
























@@ -1,14 +1,16 @@
11import { describe, expect, it, vi } from "vitest";
2+import { REDACTED_SENTINEL } from "../../config/redact-snapshot.js";
2334let writtenConfig: unknown = null;
5+let loadedConfig: unknown = {
6+skills: {
7+entries: {},
8+},
9+};
410511vi.mock("../../config/config.js", () => {
612return {
7-loadConfig: () => ({
8-skills: {
9-entries: {},
10-},
11-}),
13+loadConfig: () => loadedConfig,
1214writeConfigFile: async (cfg: unknown) => {
1315writtenConfig = cfg;
1416},
@@ -20,6 +22,11 @@ const { skillsHandlers } = await import("./skills.js");
2022describe("skills.update", () => {
2123it("strips embedded CR/LF from apiKey", async () => {
2224writtenConfig = null;
25+loadedConfig = {
26+skills: {
27+entries: {},
28+},
29+};
23302431let ok: boolean | null = null;
2532let error: unknown = null;
@@ -50,4 +57,102 @@ describe("skills.update", () => {
5057},
5158});
5259});
60+61+it("redacts apiKey and secret env values from the response but writes full values to config", async () => {
62+writtenConfig = null;
63+loadedConfig = {
64+skills: {
65+entries: {},
66+},
67+};
68+69+let responseResult: unknown = null;
70+await skillsHandlers["skills.update"]({
71+params: {
72+skillKey: "demo-skill",
73+apiKey: "secret-api-key-123",
74+env: {
75+GEMINI_API_KEY: "secret-env-key-456",
76+BRAVE_REGION: "us",
77+},
78+},
79+req: {} as never,
80+client: null as never,
81+isWebchatConnect: () => false,
82+context: {} as never,
83+respond: (_success, result, _err) => {
84+responseResult = result;
85+},
86+});
87+88+// Full values must be persisted to config
89+expect(writtenConfig).toMatchObject({
90+skills: {
91+entries: {
92+"demo-skill": {
93+apiKey: "secret-api-key-123",
94+env: {
95+GEMINI_API_KEY: "secret-env-key-456",
96+BRAVE_REGION: "us",
97+},
98+},
99+},
100+},
101+});
102+103+// Response must not expose plaintext secrets
104+const config = (responseResult as { config: Record<string, unknown> }).config;
105+expect(config.apiKey).toBe(REDACTED_SENTINEL);
106+const env = config.env as Record<string, string>;
107+expect(env.GEMINI_API_KEY).toBe(REDACTED_SENTINEL);
108+// Non-secret env values should still be present
109+expect(env.BRAVE_REGION).toBe("us");
110+});
111+112+it("keeps existing secrets when clients submit redacted sentinel values", async () => {
113+writtenConfig = null;
114+loadedConfig = {
115+skills: {
116+entries: {
117+"demo-skill": {
118+apiKey: "secret-api-key-123",
119+env: {
120+GEMINI_API_KEY: "secret-env-key-456",
121+BRAVE_REGION: "us",
122+},
123+},
124+},
125+},
126+};
127+128+await skillsHandlers["skills.update"]({
129+params: {
130+skillKey: "demo-skill",
131+apiKey: REDACTED_SENTINEL,
132+env: {
133+GEMINI_API_KEY: REDACTED_SENTINEL,
134+BRAVE_REGION: "eu",
135+},
136+},
137+req: {} as never,
138+client: null as never,
139+isWebchatConnect: () => false,
140+context: {} as never,
141+respond: () => {},
142+});
143+144+expect(writtenConfig).toMatchObject({
145+skills: {
146+entries: {
147+"demo-skill": {
148+apiKey: "secret-api-key-123",
149+env: {
150+GEMINI_API_KEY: "secret-env-key-456",
151+BRAVE_REGION: "eu",
152+},
153+},
154+},
155+},
156+});
157+});
53158});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。