Skip to content

OCI backend: honour writable_scratch=False; tell a parser's exit 125–127 from the engine's (#38) - #52

Draft
Deep-Sixed wants to merge 2 commits into
mainfrom
claude/sweet-bardeen-bi3jez
Draft

Deep-Sixed wants to merge 2 commits into
mainfrom
claude/sweet-bardeen-bi3jez

Conversation

@Deep-Sixed

Copy link
Copy Markdown
Owner

Closes #38.

writable_scratch=False was ignored

The OCI backend always mounted /tmp, /home, /mnt, /root, /run and /var as writable tmpfs. With writable_scratch=False they are now mounted read-only (still empty), on top of the existing --read-only root filesystem, so /stele/output is the only writable path, as under bubblewrap with Landlock.

Exit statuses 125–127

These were always reported as engine_error, even when the parser itself exited with one of them. A status is now an engine_error only when stderr ends with the engine's or OCI runtime's own message:

  • a failed exec of the command (OCI runtime ..., executable file not found in $PATH, unable to start container process, OCI permission denied);
  • Error response from daemon;
  • the Error: (Podman) or docker: prefix at 125, for unknown images or runtimes and the like.

Otherwise it is the parser's own exit_status. I captured Podman's real messages for each case locally.

Limit (documented in docs/containment.md): a parser that prints the engine's exact wording and exits 125 is still taken for an engine error. The alternative, a start marker written by an entrypoint wrapper, would change what runs inside every container, so I left it out.

Tests

  • Unit: the argv for both scratch modes, and the classification of six engine messages and four parser exits.
  • Live, on every OCI lane (runc, gVisor, Podman, Docker): a parser exiting 125, 126 and 127 is exit_status; with writable_scratch=False, writes to /tmp /var /run /home /root /mnt /etc / all fail and /stele/output works.
  • Locally (Podman): the new live tests pass. The Docker and gVisor lanes run only in CI.
  • Full suite: 879 passed, 97 skipped. ruff is clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_013p3FU6gUJ1MGinnmEgvHsm


Generated by Claude Code

…127 from the engine's (#38)

- writable_scratch=False now mounts the /tmp, /home, /mnt, /root, /run and
  /var tmpfs read-only (they stay empty), so /stele/output is the only
  writable path in a container, as under bubblewrap+Landlock. It was ignored.
- Exit statuses 125-127 were always an engine_error. They are now one only
  when stderr ends with the engine's or OCI runtime's own message (failed
  exec of the command, unknown image or runtime, "Error response from
  daemon", podman "Error: " / docker "docker: " at 125); otherwise the
  parser's own exit_status. A parser that prints the engine's exact wording
  at 125 is still misread; documented.

Unit tests cover the argv and both classifications; live proofs run on every
OCI lane (a parser exiting 125/126/127; writes refused everywhere but
/stele/output).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013p3FU6gUJ1MGinnmEgvHsm
…errors

Docker ends a failed `docker run` with "Run 'docker run --help' for more
information" after the error itself, so a missing parser command (127) was
not recognised as an engine error on the Docker lanes (CI,
test_container_engine_error[oci-runc-docker / oci-runsc-docker]). Podman's
messages are a single line, which is all the first version was checked
against. Look at the last three non-empty lines; a line far from the end
(parser noise) still does not count. Unit tests use Docker's two-line form.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013p3FU6gUJ1MGinnmEgvHsm

Copy link
Copy Markdown
Owner Author

linux-containment failed on the first push, and it was a real bug in this PR. I fixed it in d18ae27.

The failure: test_container_engine_error on oci-runc-docker and oci-runsc-docker. A missing parser command (exit 127) came back as exit_status, not engine_error.

Why: I matched the engine's message against the last line of stderr. Podman's errors are a single line, which is all I could check locally. Docker ends its error with a second line, Run 'docker run --help' for more information, so the marker was never on the last line.

Fix: look at the last three non-empty lines. A marker far from the end (a parser's own noise) still doesn't count. The unit tests now include Docker's two-line form, plus a case with an engine-looking line earlier in the output. The full suite passes locally (882 passed, 97 skipped). The Docker lanes run only in CI, so I'm watching the new run.


Generated by Claude Code


Generated by Claude Code

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.

OCI backend: honour writable_scratch=False and disambiguate exit codes 125–127

2 participants