Files
oh-my-pi/packages/coding-agent/test/secrets-obfuscator.test.ts
T
roboompandcan1357 2a90108893 fix(coding-agent): hid secrets in provider requests
Redacted configured secrets across provider-facing system prompts, tool definitions, developer reminders, and assistant tool-call payloads before LLM requests.

Fixes #2146
2026-06-10 08:26:01 +02:00

125 lines
4.0 KiB
TypeScript

/**
* Tests for secrets regex parsing, compilation, and obfuscation.
*/
import { describe, expect, it } from "bun:test";
import type { Message } from "@oh-my-pi/pi-ai";
import { obfuscateMessages, SecretObfuscator } from "@oh-my-pi/pi-coding-agent/secrets/obfuscator";
import { compileSecretRegex } from "@oh-my-pi/pi-coding-agent/secrets/regex";
describe("compileSecretRegex", () => {
it("adds global flag when not provided", () => {
const regex = compileSecretRegex("api[_-]?key\\s*=\\s*\\w+", "i");
expect(regex.source).toBe("api[_-]?key\\s*=\\s*\\w+");
expect(regex.flags).toBe("gi");
});
it("defaults to global flag when no flags provided", () => {
const regex = compileSecretRegex("api[_-]?key\\s*=\\s*\\w+");
expect(regex.source).toBe("api[_-]?key\\s*=\\s*\\w+");
expect(regex.flags).toBe("g");
});
it("rejects invalid regex pattern", () => {
expect(() => compileSecretRegex("(")).toThrow();
});
it("rejects invalid regex flags", () => {
expect(() => compileSecretRegex("x", "zz")).toThrow();
});
});
describe("SecretObfuscator regex behavior", () => {
it("obfuscates and deobfuscates regex matches with flags", () => {
const obfuscator = new SecretObfuscator([{ type: "regex", content: "api[_-]?key\\s*=\\s*\\w+", flags: "i" }]);
const original = "API_KEY=abc and api-key=def";
const obfuscated = obfuscator.obfuscate(original);
expect(obfuscated).not.toEqual(original);
expect(obfuscator.deobfuscate(obfuscated)).toEqual(original);
});
it("supports bare regex patterns without explicit flags", () => {
const obfuscator = new SecretObfuscator([{ type: "regex", content: "api[_-]?key\\s*=\\s*\\w+" }]);
const text = "api_key=abc and API_KEY=def";
const obfuscated = obfuscator.obfuscate(text);
expect(obfuscated).not.toEqual(text);
expect(obfuscator.deobfuscate(obfuscated)).toEqual(text);
});
it("deobfuscates placeholders through object payloads", () => {
const obfuscator = new SecretObfuscator([{ type: "regex", content: "api[_-]?key\\s*=\\s*\\w+", flags: "i" }]);
const original = {
cmd: "API_KEY=abc and api-key=def",
status: "ok",
};
const obfuscated = {
cmd: obfuscator.obfuscate(original.cmd),
status: original.status,
};
expect(obfuscator.deobfuscateObject(obfuscated)).toEqual({
cmd: original.cmd,
status: original.status,
});
});
it("obfuscates nested provider request payloads", () => {
const secret = "SUPER_SECRET_TOKEN_12345";
const obfuscator = new SecretObfuscator([{ type: "plain", content: secret }]);
const payload = {
systemPrompt: [`workspace contains ${secret}`],
tools: [
{
name: "handoff",
description: `preserve ${secret}`,
parameters: {
type: "object",
properties: { note: { type: "string", description: `write ${secret}` } },
},
},
],
};
const obfuscated = obfuscator.obfuscateObject(payload);
const serialized = JSON.stringify(obfuscated);
expect(serialized).not.toContain(secret);
expect(obfuscator.deobfuscateObject(obfuscated)).toEqual(payload);
});
it("obfuscates system reminders and assistant tool calls in messages", () => {
const secret = "SUPER_SECRET_TOKEN_12345";
const obfuscator = new SecretObfuscator([{ type: "plain", content: secret }]);
const messages: Message[] = [
{ role: "developer", content: `system reminder ${secret}`, timestamp: 1 },
{
role: "assistant",
content: [
{
type: "toolCall",
id: "call_1",
name: "handoff",
arguments: { note: secret },
intent: `handoff ${secret}`,
},
],
api: "test",
provider: "test",
model: "test",
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
},
stopReason: "toolUse",
timestamp: 1,
},
];
const obfuscated = obfuscateMessages(obfuscator, messages);
expect(JSON.stringify(obfuscated)).not.toContain(secret);
expect(obfuscator.deobfuscateObject(obfuscated)).toEqual(messages);
});
});