Skip to content

Commit 68e622a

Browse files
committed
fix(bash): reject malformed timeout_secs
- codex would occasionally omit this parameter leading the script to hang indefinitely
1 parent 5bff20c commit 68e622a

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

src/services/tools/bash.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,4 +597,80 @@ describe("bash tool", () => {
597597
expect(result.wall_duration_ms).toBe(0);
598598
}
599599
});
600+
601+
it("should fail immediately when timeout_secs is undefined", async () => {
602+
const tool = createBashTool({ cwd: process.cwd() });
603+
const args = {
604+
script: "echo hello",
605+
timeout_secs: undefined,
606+
max_lines: 100,
607+
};
608+
609+
const result = (await tool.execute!(args, mockToolCallOptions)) as BashToolResult;
610+
611+
expect(result.success).toBe(false);
612+
if (!result.success) {
613+
expect(result.error).toContain("timeout_secs parameter is missing or invalid");
614+
expect(result.error).toContain("malformed tool call");
615+
expect(result.exitCode).toBe(-1);
616+
expect(result.wall_duration_ms).toBe(0);
617+
}
618+
});
619+
620+
it("should fail immediately when timeout_secs is null", async () => {
621+
const tool = createBashTool({ cwd: process.cwd() });
622+
const args = {
623+
script: "echo hello",
624+
timeout_secs: null as unknown as number,
625+
max_lines: 100,
626+
};
627+
628+
const result = (await tool.execute!(args, mockToolCallOptions)) as BashToolResult;
629+
630+
expect(result.success).toBe(false);
631+
if (!result.success) {
632+
expect(result.error).toContain("timeout_secs parameter is missing or invalid");
633+
expect(result.error).toContain("malformed tool call");
634+
expect(result.exitCode).toBe(-1);
635+
expect(result.wall_duration_ms).toBe(0);
636+
}
637+
});
638+
639+
it("should fail immediately when timeout_secs is zero", async () => {
640+
const tool = createBashTool({ cwd: process.cwd() });
641+
const args: BashToolArgs = {
642+
script: "echo hello",
643+
timeout_secs: 0,
644+
max_lines: 100,
645+
};
646+
647+
const result = (await tool.execute!(args, mockToolCallOptions)) as BashToolResult;
648+
649+
expect(result.success).toBe(false);
650+
if (!result.success) {
651+
expect(result.error).toContain("timeout_secs parameter is missing or invalid");
652+
expect(result.error).toContain("malformed tool call");
653+
expect(result.exitCode).toBe(-1);
654+
expect(result.wall_duration_ms).toBe(0);
655+
}
656+
});
657+
658+
it("should fail immediately when timeout_secs is negative", async () => {
659+
const tool = createBashTool({ cwd: process.cwd() });
660+
const args: BashToolArgs = {
661+
script: "echo hello",
662+
timeout_secs: -5,
663+
max_lines: 100,
664+
};
665+
666+
const result = (await tool.execute!(args, mockToolCallOptions)) as BashToolResult;
667+
668+
expect(result.success).toBe(false);
669+
if (!result.success) {
670+
expect(result.error).toContain("timeout_secs parameter is missing or invalid");
671+
expect(result.error).toContain("malformed tool call");
672+
expect(result.exitCode).toBe(-1);
673+
expect(result.wall_duration_ms).toBe(0);
674+
}
675+
});
600676
});

src/services/tools/bash.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ export const createBashTool: ToolFactory = (config: ToolConfiguration) => {
5656
};
5757
}
5858

59+
// Validate timeout_secs is present and valid
60+
if (timeout_secs === undefined || timeout_secs === null || timeout_secs <= 0) {
61+
return {
62+
success: false,
63+
error:
64+
"timeout_secs parameter is missing or invalid. This likely indicates a malformed tool call.",
65+
exitCode: -1,
66+
wall_duration_ms: 0,
67+
};
68+
}
69+
5970
const startTime = performance.now();
6071
const normalizedMaxLines = Math.max(1, Math.floor(max_lines));
6172
const effectiveMaxLines = Math.min(normalizedMaxLines, BASH_HARD_MAX_LINES);

0 commit comments

Comments
 (0)