Skip to content

fix(runtime): bound run_command with ctx + 2-minute per-command timeout#63

Merged
tzone85 merged 1 commit into
mainfrom
fix/run-command-context-and-timeout
Jun 11, 2026
Merged

fix(runtime): bound run_command with ctx + 2-minute per-command timeout#63
tzone85 merged 1 commit into
mainfrom
fix/run-command-context-and-timeout

Conversation

@tzone85

@tzone85 tzone85 commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

execRunCommand built its child process with shellexec.Command — no context. cmd.CombinedOutput() then blocked until the child exited regardless of parent cancellation. A small model that asked the runtime to run a slow or runaway command (e.g. go test ./... -run TestSlow against a test it just wrote with an infinite loop) would pin the iteration goroutine for the full 5-minute outer budget. On a single-GPU Ollama config (concurrency: 1) every other story in the wave queued behind it.

Changes

  • Thread ctx from ExecuteexecuteToolexecRunCommand. File ops (read/write/edit) stay context-free — they're fast.
  • Wrap with context.WithTimeout(ctx, runCommandTimeout). 2 minutes ceiling — comfortable for go build ./... / go test ./... on a modest repo.
  • A hung child now receives SIGKILL via Go's os/exec context handling.
  • On DeadlineExceeded, return actionable text to the model ("command timed out after 2m0s — split into smaller commands or fix the slow path") so the agent can self-correct.

Test plan

  • New TestExecRunCommand_CancelledContextKillsCommand asserts a pre-cancelled ctx surfaces as IsError without blocking.
  • Test files updated to pass context.Background() for the existing surface.
  • go build ./..., go vet ./..., go test ./... -count=1 -timeout 240s all green locally.

Audit traceability

Security finding SEC-H1 (2026-06-11 sweep).

execRunCommand built its child process with shellexec.Command — no
context. cmd.CombinedOutput() then blocked until the child exited
regardless of parent cancellation. A small model that asked the runtime
to run a slow or runaway command (e.g. `go test ./... -run TestSlow`
against a test it just wrote with an infinite loop) would pin the
iteration goroutine for the full 5-minute outer budget — and on a
single-GPU Ollama config (concurrency: 1) every other story in the
wave queued behind it.

- Thread ctx from Execute → executeTool → execRunCommand. File ops
  (read/write/edit) stay context-free; they're fast.
- Wrap with context.WithTimeout(ctx, runCommandTimeout). 2 minutes is a
  comfortable ceiling for `go build ./...` / `go test ./...` on a
  modest repo. A hung child now receives SIGKILL via Go's os/exec
  context handling.
- On DeadlineExceeded, return actionable text to the model
  ("command timed out after 2m0s — split into smaller commands or
  fix the slow path") instead of a generic exec error so the agent can
  self-correct.
- Test files updated to pass context.Background() — the existing test
  surface is unchanged in intent, just receives ctx.
- New test TestExecRunCommand_CancelledContextKillsCommand asserts a
  pre-cancelled ctx surfaces as IsError without blocking.

Surfaced by the 2026-06-11 security audit (SEC-H1).
@tzone85 tzone85 merged commit 94c7161 into main Jun 11, 2026
9 of 10 checks passed
@tzone85 tzone85 deleted the fix/run-command-context-and-timeout branch June 11, 2026 10:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant