





























@@ -110,6 +110,165 @@ describe("pi tool definition adapter logging", () => {
110110);
111111});
112112113+it("omits raw exec commands and env values from failure logs", async () => {
114+const commandSecret = "issue85049-xai-cleartext-token-ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
115+const envSecret = "issue85049-env-cleartext-token-ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
116+const baseTool = {
117+name: "exec",
118+label: "exec",
119+description: "runs commands",
120+parameters: Type.Object({
121+command: Type.String(),
122+env: Type.Optional(Type.Record(Type.String(), Type.String())),
123+timeout: Type.Optional(Type.Number()),
124+}),
125+execute: async () => {
126+throw new Error("exec denied: allowlist miss");
127+},
128+} satisfies AgentTool;
129+const [def] = toToolDefinitions([baseTool]);
130+if (!def) {
131+throw new Error("missing tool definition");
132+}
133+134+await def.execute(
135+"call-exec-denied",
136+{
137+command: `export XAI_API_KEY=\\"${commandSecret}\\" && echo blocked`,
138+env: {
139+OPENAI_API_KEY: envSecret,
140+},
141+timeout: 5,
142+},
143+undefined,
144+undefined,
145+extensionContext,
146+);
147+148+const message = String(firstLogErrorMessage());
149+expect(message).toContain("[tools] exec failed: exec denied: allowlist miss");
150+expect(message).toContain('"command":{"omitted":true');
151+expect(message).toContain('"reason":"exec command may contain credentials"');
152+expect(message).toContain('"chars":');
153+expect(message).toMatch(/"sha256":"[a-f0-9]{16}"/u);
154+expect(message).toContain('"env":{"OPENAI_API_KEY":"[omitted exec env value]"}');
155+expect(message).toContain('"timeout":5');
156+expect(message).not.toContain(commandSecret);
157+expect(message).not.toContain(envSecret);
158+expect(message).not.toContain("export XAI_API_KEY");
159+});
160+161+it("omits raw exec commands from JSON-string failure params", async () => {
162+const commandSecret = "issue85049-json-cleartext-token-ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
163+const baseTool = {
164+name: "exec",
165+label: "exec",
166+description: "runs commands",
167+parameters: Type.Any(),
168+execute: async () => {
169+throw new Error("exec denied: allowlist miss");
170+},
171+} satisfies AgentTool;
172+const [def] = toToolDefinitions([baseTool]);
173+if (!def) {
174+throw new Error("missing tool definition");
175+}
176+177+await def.execute(
178+"call-exec-denied-json-string",
179+JSON.stringify({
180+command: `export XAI_API_KEY=\\"${commandSecret}\\" && echo blocked`,
181+timeout: 5,
182+}),
183+undefined,
184+undefined,
185+extensionContext,
186+);
187+188+const message = String(firstLogErrorMessage());
189+expect(message).toContain('"command":{"omitted":true');
190+expect(message).toContain('"reason":"exec command may contain credentials"');
191+expect(message).toContain('"timeout":5');
192+expect(message).not.toContain(commandSecret);
193+expect(message).not.toContain("export XAI_API_KEY");
194+});
195+196+it("omits malformed exec command and env values from failure logs", async () => {
197+const commandSecret =
198+"issue85049-malformed-command-cleartext-token-ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
199+const envSecret =
200+"issue85049-malformed-env-cleartext-token-ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
201+const baseTool = {
202+name: "exec",
203+label: "exec",
204+description: "runs commands",
205+parameters: Type.Any(),
206+execute: async () => {
207+throw new Error("exec denied: allowlist miss");
208+},
209+} satisfies AgentTool;
210+const [def] = toToolDefinitions([baseTool]);
211+if (!def) {
212+throw new Error("missing tool definition");
213+}
214+215+await def.execute(
216+"call-exec-denied-malformed",
217+{
218+command: [`export XAI_API_KEY=\\"${commandSecret}\\" && echo blocked`],
219+env: `OPENAI_API_KEY=${envSecret}`,
220+},
221+undefined,
222+undefined,
223+extensionContext,
224+);
225+226+const message = String(firstLogErrorMessage());
227+expect(message).toContain('"command":{"omitted":true');
228+expect(message).toContain('"type":"array"');
229+expect(message).toContain('"env":"[omitted exec env]"');
230+expect(message).not.toContain(commandSecret);
231+expect(message).not.toContain(envSecret);
232+expect(message).not.toContain("export XAI_API_KEY");
233+});
234+235+it("omits cmd-style exec payloads from normalized bash failure logs", async () => {
236+const commandSecret =
237+"issue85049-cmd-alias-cleartext-token-ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
238+const baseTool = {
239+name: "bash",
240+label: "Bash",
241+description: "runs commands",
242+parameters: Type.Any(),
243+execute: async () => {
244+throw new Error("exec denied: allowlist miss");
245+},
246+} satisfies AgentTool;
247+const [def] = toToolDefinitions([baseTool]);
248+if (!def) {
249+throw new Error("missing tool definition");
250+}
251+252+await def.execute(
253+"call-bash-denied-cmd-alias",
254+{
255+cmd: `export XAI_API_KEY=\\"${commandSecret}\\" && echo blocked`,
256+timeout: 5,
257+},
258+undefined,
259+undefined,
260+extensionContext,
261+);
262+263+const message = String(firstLogErrorMessage());
264+expect(message).toContain("[tools] exec failed: exec denied: allowlist miss");
265+expect(message).toContain('"cmd":{"omitted":true');
266+expect(message).toContain('"reason":"exec command may contain credentials"');
267+expect(message).toContain('"timeout":5');
268+expect(message).not.toContain(commandSecret);
269+expect(message).not.toContain("export XAI_API_KEY");
270+});
271+113272it("logs provider AbortError failures when the agent run was not aborted", async () => {
114273const baseTool = {
115274name: "web_search",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。