Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline (Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/* packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
109 lines
3.9 KiB
TypeScript
109 lines
3.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { redactBindings, redactSensitiveText } from "./redaction.js";
|
|
|
|
describe("redaction", () => {
|
|
it("redacts secrets, credentials, and message bodies", () => {
|
|
const redacted = redactBindings({
|
|
"user.id": "user-1",
|
|
email: "person@example.com",
|
|
authorization: "Bearer secret",
|
|
cookie: "session=abc",
|
|
prompt: "do not log",
|
|
messages: [{ role: "user", content: "hi" }],
|
|
body: { text: "payload" },
|
|
query: { q: "search" },
|
|
apiKey: "sk-live",
|
|
nested: { password: "hunter2", token: "abc", safe: true },
|
|
});
|
|
expect(redacted["user.id"]).toBe("user-1");
|
|
expect(redacted.email).toBe("[Redacted]");
|
|
expect(redacted.authorization).toBe("[Redacted]");
|
|
expect(redacted.cookie).toBe("[Redacted]");
|
|
expect(redacted.prompt).toBe("[Redacted]");
|
|
expect(redacted.messages).toBe("[Redacted]");
|
|
expect(redacted.body).toBe("[Redacted]");
|
|
expect(redacted.query).toBe("[Redacted]");
|
|
expect(redacted.apiKey).toBe("[Redacted]");
|
|
expect(redacted.nested).toEqual({ password: "[Redacted]", token: "[Redacted]", safe: true });
|
|
});
|
|
|
|
it("replaces circular values", () => {
|
|
const cycle: Record<string, unknown> = { "request.id": "r1" };
|
|
cycle.self = cycle;
|
|
const redacted = redactBindings(cycle);
|
|
expect(redacted["request.id"]).toBe("r1");
|
|
expect(redacted.self).toBe("[Circular]");
|
|
});
|
|
|
|
it("redacts Error values nested in bindings", () => {
|
|
const cause = new Error("password=inner-secret");
|
|
const error = new Error("request failed with token=outer-secret", { cause });
|
|
|
|
const redacted = redactBindings({ detail: error });
|
|
|
|
expect(redacted.detail).toMatchObject({
|
|
name: "Error",
|
|
message: "request failed with token=[Redacted]",
|
|
cause: { name: "Error", message: "password=[Redacted]" },
|
|
});
|
|
expect(JSON.stringify(redacted.detail)).not.toMatch(/inner-secret|outer-secret/);
|
|
});
|
|
|
|
it("redacts string Error causes", () => {
|
|
const error = new Error("request failed", { cause: "token=cause-secret" });
|
|
|
|
const redacted = redactBindings({ detail: error });
|
|
|
|
expect(redacted.detail).toMatchObject({
|
|
name: "Error",
|
|
message: "request failed",
|
|
cause: "token=[Redacted]",
|
|
});
|
|
expect(JSON.stringify(redacted.detail)).not.toContain("cause-secret");
|
|
});
|
|
|
|
it("redacts secrets embedded in string binding values", () => {
|
|
const redacted = redactBindings({
|
|
detail: "token=binding-secret",
|
|
nested: { note: "Bearer nested-secret" },
|
|
});
|
|
|
|
expect(redacted).toEqual({
|
|
detail: "token=[Redacted]",
|
|
nested: { note: "Bearer [Redacted]" },
|
|
});
|
|
});
|
|
|
|
it("redacts secrets embedded in free text", () => {
|
|
const redacted = redactSensitiveText(
|
|
"user person@example.com used Bearer supersecret and token=abc123",
|
|
);
|
|
expect(redacted).toContain("[Redacted]");
|
|
expect(redacted).not.toContain("person@example.com");
|
|
expect(redacted).not.toContain("supersecret");
|
|
expect(redacted).not.toContain("abc123");
|
|
});
|
|
|
|
it("redacts bare API keys and JWTs in free text", () => {
|
|
const redacted = redactSensitiveText(
|
|
"key sk-or-v1-abc123456789 and sk-live-secret99 jwt eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.sig ak_secretvaluehere",
|
|
);
|
|
expect(redacted).not.toMatch(
|
|
/sk-or-v1-abc123456789|sk-live-secret99|eyJhbGciOiJIUzI1NiJ9|ak_secretvaluehere/,
|
|
);
|
|
expect(redacted).toContain("[Redacted]");
|
|
});
|
|
|
|
it("redacts quoted JSON credential fields", () => {
|
|
const redacted = redactSensitiveText(
|
|
'{"password":"hunter2","token":"abc","authorization":"Bearer secret"}',
|
|
);
|
|
expect(redacted).not.toContain("hunter2");
|
|
expect(redacted).not.toContain('"token":"abc"');
|
|
expect(redacted).not.toContain("Bearer secret");
|
|
expect(redacted).toContain('"password":"[Redacted]"');
|
|
expect(redacted).toContain('"token":"[Redacted]"');
|
|
expect(redacted).toContain('"authorization":"[Redacted]"');
|
|
});
|
|
});
|