


























@@ -6,6 +6,12 @@ import { resolveUserPath } from "../utils.js";
66import { createCacheTrace } from "./cache-trace.js";
7788describe("createCacheTrace", () => {
9+const bareAnthropicKey = "sk-ant-api03-AbCdEfGhIjKlMnOpQrStUvWx"; // pragma: allowlist secret
10+const bareAwsKey = "AKIAIOSFODNN7EXAMPLE"; // pragma: allowlist secret
11+const bareGithubKey = "ghp_AbCdEfGhIjKlMnOpQrStUvWxYz1234567890"; // pragma: allowlist secret
12+const bareGoogleKey = "AIzaSyA1bC2dE3fG4hI5jK6lM7nO8pQrStUvW"; // pragma: allowlist secret
13+const barePerplexityKey = "pplx-AbCdEfGhIjKlMnOpQrStUvWx"; // pragma: allowlist secret
14+915function createMemoryTraceForTest() {
1016const lines: string[] = [];
1117// In-memory writer keeps cache trace assertions deterministic without
@@ -179,15 +185,21 @@ describe("createCacheTrace", () => {
179185180186trace?.recordStage("stream:context", {
181187system: {
182-provider: { apiKey: "sk-system-secret", baseUrl: "https://api.example.com" },
188+provider: {
189+apiKey: "sk-system-secret",
190+baseUrl: "https://api.example.com",
191+diagnosticText: bareAwsKey,
192+},
183193},
184194model: {
185195id: "test-model",
186196apiKey: "sk-model-secret",
187197tokenCount: 8192,
198+diagnosticText: bareGoogleKey,
188199},
189200options: {
190201apiKey: "sk-options-secret",
202+diagnosticText: bareGithubKey,
191203nested: {
192204password: "super-secret-password",
193205safe: "keep-me",
@@ -204,6 +216,10 @@ describe("createCacheTrace", () => {
204216label: "preserve-me",
205217},
206218content: [
219+{
220+type: "text",
221+text: barePerplexityKey,
222+},
207223{
208224type: "image",
209225source: { type: "base64", media_type: "image/jpeg", data: "U0VDUkVU" },
@@ -214,16 +230,25 @@ describe("createCacheTrace", () => {
214230});
215231216232const event = JSON.parse(lines[0]?.trim() ?? "{}") as Record<string, unknown>;
217-expect(event.system).toEqual({
218-provider: {
219- baseUrl: "https://api.example.com",
220-},
233+const systemProvider =
234+(event.system as { provider?: Record<string, unknown> } | undefined)?.provider ?? {};
235+expect(systemProvider).toMatchObject({
236+baseUrl: "https://api.example.com",
221237});
238+expect(systemProvider.diagnosticText).toBeTypeOf("string");
239+expect(systemProvider.diagnosticText).not.toBe(bareAwsKey);
240+expect(systemProvider.diagnosticText).not.toContain(bareAwsKey);
222241expect(event.model).toEqual({
223242id: "test-model",
224243tokenCount: 8192,
244+diagnosticText: expect.any(String),
225245});
246+expect((event.model as { diagnosticText?: string }).diagnosticText).not.toBe(bareGoogleKey);
247+expect((event.model as { diagnosticText?: string }).diagnosticText).not.toContain(
248+bareGoogleKey,
249+);
226250expect(event.options).toEqual({
251+diagnosticText: expect.any(String),
227252nested: {
228253safe: "keep-me",
229254tokenCount: 42,
@@ -238,6 +263,10 @@ describe("createCacheTrace", () => {
238263},
239264],
240265});
266+expect((event.options as { diagnosticText?: string }).diagnosticText).not.toBe(bareGithubKey);
267+expect((event.options as { diagnosticText?: string }).diagnosticText).not.toContain(
268+bareGithubKey,
269+);
241270242271const optionsImages = (
243272((event.options as { images?: unknown[] } | undefined)?.images ?? []) as Array<
@@ -257,11 +286,44 @@ describe("createCacheTrace", () => {
257286expect(firstMessage?.metadata).toEqual({
258287label: "preserve-me",
259288});
260-const source = (((firstMessage?.content as Array<Record<string, unknown>> | undefined) ?? [])[0]
261-?.source ?? {}) as Record<string, unknown>;
289+const content = (firstMessage?.content as Array<Record<string, unknown>> | undefined) ?? [];
290+expect(content[0]).toEqual({
291+type: "text",
292+text: expect.any(String),
293+});
294+expect(content[0]?.text).not.toBe(barePerplexityKey);
295+expect(content[0]?.text).not.toContain(barePerplexityKey);
296+const source = (content[1]?.source ?? {}) as Record<string, unknown>;
262297expect(source.data).toBe("<redacted>");
263298expect(source.bytes).toBe(6);
264299expect(source.sha256).toBe(crypto.createHash("sha256").update("U0VDUkVU").digest("hex"));
300+const serialized = JSON.stringify(event);
301+expect(serialized).not.toContain(bareAwsKey);
302+expect(serialized).not.toContain(bareGoogleKey);
303+expect(serialized).not.toContain(bareGithubKey);
304+expect(serialized).not.toContain(barePerplexityKey);
305+});
306+307+it("redacts bare vendor keys from cache-trace prompt, note, and error fields", () => {
308+const { lines, trace } = createMemoryTraceForTest();
309+310+trace?.recordStage("prompt:before", {
311+prompt: `prompt ${bareAnthropicKey}`,
312+note: `note ${bareGithubKey}`,
313+error: `error ${bareGoogleKey}`,
314+});
315+316+const event = JSON.parse(lines[0]?.trim() ?? "{}") as Record<string, unknown>;
317+expect(event.prompt).toBeTypeOf("string");
318+expect(event.note).toBeTypeOf("string");
319+expect(event.error).toBeTypeOf("string");
320+expect(event.prompt).not.toBe(`prompt ${bareAnthropicKey}`);
321+expect(event.note).not.toBe(`note ${bareGithubKey}`);
322+expect(event.error).not.toBe(`error ${bareGoogleKey}`);
323+const serialized = JSON.stringify(event);
324+expect(serialized).not.toContain(bareAnthropicKey);
325+expect(serialized).not.toContain(bareGithubKey);
326+expect(serialized).not.toContain(bareGoogleKey);
265327});
266328267329it("handles circular references in messages without stack overflow", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。