Skip to content

fix(runtime): report unstartable exec programs as exit 127/126 on every backend (RIG-5121) - #2225

Merged
mattwilkinsonn merged 2 commits into
mainfrom
compass-runner/rig-5121-exec-exit-parity
Oct 12, 2026
Merged

mattwilkinsonn merged 2 commits into
mainfrom
compass-runner/rig-5121-exec-exit-parity

Conversation

@rigel-mintaka

@rigel-mintaka rigel-mintaka commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements Matt's ruling B' on RIG-5121. Every WorkloadRuntime.Exec backend now reports a program it cannot start as an exit code, the way podman already does.

Case Result (all backends)
Program not found ExitCode 127, err == nil, reason on stderr
Program present but cannot be invoked: no exec bit, not a regular file, ENOEXEC, or execve EACCES/EPERM after the pre-check ExitCode 126, err == nil, reason on stderr
Missing or non-directory workdir, missing script interpreter Go error (unchanged)
Timeout, transport failure, dead VM, engine binary missing Go error (unchanged)
  • podman: no change. It already passes 127/126 through.
  • microVM guestd (go/internal/guestd/supervisor.go): a pre-check before spawn. One-shot returns an ExecResponse. Streaming sends ExecStarted, stderr, then ExecExit. A PATH search skips unusable entries, as a shell does.
  • host (go/internal/runtime/host_backend.go): the same pre-check and classification. A synthetic exited stream serves its output from memory. A done ctx is returned before the pre-check.
  • microVM client: rejects an empty ExecStarted.exec_id, because guestd reads an empty id as a whole-guest stop.
  • Contract suite: one-shot and streaming rows on every backend, plus TestExitCodeOf.
  • Docs: proto comments are updated, and the V2b and V8 records get dated amendments. The V8 W2 harness asserts err == nil, then rejects 126/127.

Verification

  • go test for runtime/..., guestd, runner/..., and cmd/compass-stack: all pass.
  • go test -tags podman -run TestContractSuite_Podman against live podman: passes. This caught, and the PR fixes, a streaming row that assumed ExitStatusError on podman.
  • golangci-lint for runtime/..., guestd, and runner/... (untagged, podman, microvm): 0 issues. nilaway (CI flags): 0. go vet -tags microvm and darwin vet: clean.
  • moon run compass-proto:gen: no drift. Design-ledger gate OK. rumdl clean.
  • Red→green: new regressions were seen failing first, including the unsearchable PATH entry → 127, a canceled ctx before the pre-check, dot PATH with a workdir, and EACCES/EPERM classification.
  • The KVM-gated microVM tests did not run locally (no /dev/kvm). The microVM-tagged code is vetted and linted, and CI's microvm job covers it.
  • Review: 6 rounds. Round 1 found 2 high and 6 medium findings, and all were folded. The last round's single finding (an untested exitCodeOf gate) is fixed by TestExitCodeOf.

Spec-impact: proto/compass/v1/guest_control.proto Exec contract comments; V2b and V8 record amendments.
Ledger-impact: none.

Refs RIG-5121, RIG-2922

…ry backend (RIG-5121)

guestd and the host backend now match podman. A missing program is exit 127
and a present program that cannot be invoked (no exec bit, not a regular file,
ENOEXEC, execve EACCES/EPERM after the pre-check) is exit 126, with a reason on
stderr. A missing or non-directory workdir, a missing script interpreter, and
runtime faults stay Go errors. Adds one-shot and streaming contract-suite rows,
rejects an empty guest exec_id, and amends the V2b and V8 records.

Refs RIG-5121, RIG-2922

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@trunk-io

trunk-io Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

😎 This pull request was merged.

@linear-code

linear-code Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

RIG-2922

RIG-5121

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

…contract row (RIG-5121)

microVM stdio is an unbuffered io.Pipe, so reading stdout to EOF before stderr
deadlocked the response pump on the stderr frame and timed out the microvm job.

Refs RIG-5121

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@rigel-mintaka

Copy link
Copy Markdown
Contributor Author

Merge-ready at head 41e9c264.

Review: high 0 / medium 0 / low 0 after 6 rounds. The final round's one finding (the untested exitCodeOf gate) is fixed by TestExitCodeOf. The follow-up commit is test-only: the streaming contract row now drains stdout and stderr together, fixing a microVM CI timeout on the first head.

CI: all required checks are green on 41e9c264, microvm included.

@rigel-mintaka
rigel-mintaka marked this pull request as ready for review October 12, 2026 04:02
@mattwilkinsonn
mattwilkinsonn merged commit 34863c1 into main Oct 12, 2026
17 checks passed
@mattwilkinsonn
mattwilkinsonn deleted the compass-runner/rig-5121-exec-exit-parity branch October 12, 2026 19:15
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.

2 participants