mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-05 03:51:54 +01:00
test(evals): protect short multiline diagnostic credentials
This commit is contained in:
1 parent
db4c051441
commit
4e73b7bb70
2 files changed
+12
-6
No files matched your search
@@ -9,11 +9,11 @@ function registry() { const root = realpathSync(mkdtempSync(path.join(os.tmpdir(
|
||||
describe("private diagnostic output boundary", () => {
|
||||
it("redacts secret and escaped variants across chunks, multiline PEM and UTF-8 without losing ordinary failure detail", () => {
|
||||
const password = 'synthetic-credential-<&"-12345678';
|
||||
const pem = "-----BEGIN PRIVATE KEY-----\nU1lOVEhFVElDLVByaXZhdGUtS2V5LUxpbmUx\nU1lOVEhFVElDLVByaXZhdGUtS2V5LUxpbmUy\n-----END PRIVATE KEY-----";
|
||||
const outputs: string[] = []; const stream = createPrivateDiagnosticStream(() => [password, pem], value => outputs.push(value));
|
||||
const input = `HTTP503: π provider unavailable ${password}\n${pem}\nJSON ${JSON.stringify(password)}\nHTML ${password.replace(/&/g, "&").replace(/</g, "<").replace(/"/g, """)}\nURI ${encodeURIComponent(password)}\n`;
|
||||
const pem = "-----BEGIN PRIVATE KEY-----\nU1lOVEhFVElDLVByaXZhdGUtS2V5LUxpbmUx\nU1lOVEhFVElDLVByaXZhdGUtS2V5LUxpbmUy\n-----END PRIVATE KEY-----"; const short = "Ax4\nBy5\nCz6";
|
||||
const outputs: string[] = []; const stream = createPrivateDiagnosticStream(() => [password, pem, short], value => outputs.push(value));
|
||||
const input = `HTTP503: π provider unavailable ${password}\n${pem}\n${short}\nJSON ${JSON.stringify(password)}\nHTML ${password.replace(/&/g, "&").replace(/</g, "<").replace(/"/g, """)}\nURI ${encodeURIComponent(password)}\n`;
|
||||
const bytes = Buffer.from(input); for (let i = 0; i < bytes.length; i += 3) stream.write(bytes.subarray(i, i + 3)); stream.end();
|
||||
const safe = outputs.join(""); for (const value of diagnosticSecrets([password, pem])) expect(safe).not.toContain(value);
|
||||
const safe = outputs.join(""); for (const value of diagnosticSecrets([password, pem, short])) expect(safe).not.toContain(value);
|
||||
expect(safe).toContain("HTTP503: π provider unavailable"); expect(stream.redactedSecret()).toBe(true); expect(stream.failed()).toBe(false);
|
||||
});
|
||||
it("synchronously registers a generated cookie before first output and rereads at final flush", () => {
|
||||
|
||||
@@ -46,9 +46,15 @@ export function trackedPrivateSecrets(initial: string[], executionId: string, en
|
||||
} });
|
||||
}
|
||||
export function diagnosticSecrets(values: readonly string[]): string[] {
|
||||
const variants = normalizedSecrets(values).flatMap(value => [value, JSON.stringify(value).slice(1, -1), encodeURIComponent(value),
|
||||
const variants = normalizedSecrets(values).flatMap(value => {
|
||||
let structured = false; try { const parsed = JSON.parse(value); structured = parsed !== null && typeof parsed === "object"; } catch { /* Ordinary secret. */ }
|
||||
return [value, JSON.stringify(value).slice(1, -1), encodeURIComponent(value),
|
||||
value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"),
|
||||
...value.split(/\r?\n/).filter(line => line.length >= 8)]);
|
||||
// Short nonempty password/key lines are private too. JSON punctuation is
|
||||
// structural; its actual string credential values are separately indexed
|
||||
// by normalizedSecrets, and longer serialized field lines remain covered.
|
||||
...value.split(/\r?\n/).filter(line => structured ? line.length >= 8 : line.length > 0)];
|
||||
});
|
||||
return normalizedSecrets(variants);
|
||||
}
|
||||
/** No raw byte reaches a console or log. UTF-8 and secret boundaries may span
|
||||
|
||||
Reference in new issue
Block a user