Files
werkrevisor/docs/prs/2026-10-18-PR#123-codex-sandbox-check.md
claude-code a6185f0949
werkator build succeeded after 00:09
werkator/werkrevisor-statistics build succeeded after 00:26
werkator/release build succeeded after 00:12
werkrevisor 0.51.0: the Codex runner checks its sandbox before it reviews (#123)
Co-authored-by: claude-code <claude-code@javagil.de>
2026-10-18 20:38:01 +02:00

91 lines
4.6 KiB
Markdown

# PR#123: The Codex Runner Checks Its Sandbox before It Reviews
Version: minor
> **WARNING:** This document describes only the change applied in this PR.
> It may already be outdated once the next PR is merged.
> Historic PR documentation is not maintained along with new PRs; treat it as a snapshot.
## Related Links
- [PR#88](2026-10-11-PR#88-codex-runner.md): the Codex runner and its `bwrap` jail.
## Problem
The Codex runner runs Codex in a `bwrap` jail, and Codex starts its own `bwrap` sandbox inside it.
On 2026-10-16 at 19:53 the AppArmor profile `bwrap` was unloaded on the workstation, while `bwrap-userns-restrict` was disabled.
Until it was loaded again on 2026-10-17 at 12:38, `bwrap` fell under `unprivileged_userns`
and failed with "bwrap: setting up uid map: Permission denied".
Each attempt for PR#115 and PR#116 failed this way and counted against `MAX_ATTEMPTS`; PR#115 waited 16.6 hours.
With `bwrap-userns-restrict` active, the nested `bwrap` fails too,
and Codex rates a PR critical because its shell sandbox failed.
A later update of the AppArmor package can bring either fault back.
## Non-Goals
- No change of the jail or of the AppArmor profiles of the workstation.
- No detection of a failed sandbox inside a Codex answer; the check before the run covers it.
## Specification
### Feature: the Codex runner reviews only with a working sandbox
#### Scenario#123.01: a broken sandbox stops the reviews of a run
&hellip; so that a fault of the workstation neither uses up the attempts of a PR nor produces a wrong verdict.
- **Given** a ready PR, and a nested `bwrap` that fails on the workstation
- **When** the runner runs
- **Then** the PR gets no review, its attempts stay unchanged, the log names the cause, and the run exits with 1
##### Verified by
- [test_codexrunner.CodexRunnerTest.test_a_broken_sandbox_stops_the_reviews](../../tests/test_codexrunner.py)
- [test_codexrunner.CodexRunnerTest.test_the_run_exits_with_1_after_a_sandbox_fault](../../tests/test_codexrunner.py)
- [test_codex.CodexTest.test_the_sandbox_check_runs_a_bwrap_inside_the_jail](../../tests/test_codex.py)
#### Scenario#123.02: a jail that fails during a review costs no attempt
&hellip; so that a fault that starts after the check does not count against the PR either.
- **Given** a ready PR, a check that passes,
and a review whose `bwrap` fails with "bwrap: setting up uid map: Permission denied"
- **When** the runner runs
- **Then** the attempts of the PR stay unchanged, and the run exits with 1
##### Verified by
- [test_codexrunner.CodexRunnerTest.test_a_jail_fault_in_a_review_costs_no_attempt](../../tests/test_codexrunner.py)
- [test_codex.CodexTest.test_only_a_failed_bwrap_is_a_jail_fault](../../tests/test_codex.py)
## Solution
- `codex.check_sandbox` runs `bwrap --ro-bind / / true` inside the jail that `codex.jail` builds for a review,
with the same environment; it returns the cause, or `None`.
- `Runner.run` calls the check first.
On a failure, it logs the cause with the next steps, reviews nothing in this run and returns `False`;
`tools/codex-runner` then exits with 1, and the systemd unit shows as failed.
- A review whose `bwrap` fails, i.e. a non-zero exit with an error that contains "bwrap: ",
counts no attempt and stops the reviews of the run in the same way.
- The runner still collects the PRs while the sandbox fails:
a PR with a Codex comment gets its gate status, the others keep `pending` "waiting for the Codex review".
- Tests inject the check; a `Runner` takes it as `sandbox_check`.
- README "Codex runner" and the plan describe the check.
- Version 0.51.0.
## Open Questions
- [x] Exit code 0 or 1 on a failed check?
1: the systemd unit then shows as failed, which `systemctl --user --failed` and the desktop show.
A failed oneshot service does not stop a timer with `OnUnitInactiveSec`;
a test with `systemd-run` fired 3 failed runs in 12 s.
- [x] Does a PR keep "waiting for the Codex review" while the sandbox fails?
Yes: the cause lies on the workstation, not in the PR, and the failed unit shows it to the human.
A gate PR stays held, as with a workstation that is off.
- [x] Does a review whose `bwrap` fails count as an attempt?
No: the jail fails before Codex starts, so the review uses no quota, and the PR is not at fault.
A PR cannot bypass the gate this way: a run that fails like this posts no comment, so the PR stays `pending`.
- [x] Does the check detect a failed sandbox inside a Codex answer, e.g. a verdict "critical" because the shell sandbox failed?
No; the check runs the nested `bwrap` before the review, which is the cause of such an answer.