From 4b983a05696fcd1db34040e764188cd7eb833541 Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 3 Oct 2026 21:17:03 +0000 Subject: [PATCH] E5: watchdog stdin test feeds the wrapper through a redirect Callers run '_gstack_codex_timeout_wrapper ... codex exec - < file'. Bash keeps stdin for a backgrounded command inside a pipeline but not behind a redirect, so the pipe form passed on the old watchdog; the redirect form reproduces the lost prompt. --- test/codex-hardening.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/codex-hardening.test.ts b/test/codex-hardening.test.ts index 52d252b1f..bb345a4a5 100644 --- a/test/codex-hardening.test.ts +++ b/test/codex-hardening.test.ts @@ -383,7 +383,11 @@ describe('gstack-codex-probe: timeout wrapper + namespace hygiene', () => { const target = resolved.stdout.toString().trim(); if (target.startsWith('/')) fs.symlinkSync(target, path.join(dir, tool)); } - const r = runProbe({ snippet: `printf 'prompt on stdin' | _gstack_codex_timeout_wrapper 5 cat; echo " rc=$?"`, env: native ? { PATH: dir } : {} }); + // A redirect onto the wrapper is how callers feed `codex exec -`; a + // backgrounded command without job control would otherwise read /dev/null. + const input = path.join(dir, 'prompt.txt'); + fs.writeFileSync(input, 'prompt on stdin'); + const r = runProbe({ snippet: `_gstack_codex_timeout_wrapper 5 cat < "${input}"; echo " rc=$?"`, env: native ? { PATH: dir } : {} }); expect(r.stdout).toBe('prompt on stdin rc=0\n'); } finally { fs.rmSync(dir, { recursive: true, force: true });