Skip to content

🤖 tests: bug-bash sandbox self-check and CI job (D2) - #6085

Merged
ThomasK33 merged 6 commits into
mainfrom
tests/5714-d2-selfcheck-ci
Oct 11, 2026
Merged

ThomasK33 merged 6 commits into
mainfrom
tests/5714-d2-selfcheck-ci

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Summary

The bug-bash sandbox gets a self-check that costs nothing (make bug-bash-sandbox-check), a target that runs the repros of fixed bugs through the sandbox launcher (make test-bugbash-repros-sandbox), and a new required CI job with no secrets that runs both. This is PR D2 of the #5714 plan, stacked on D1 (#6082). It closes the sandbox CI job (#5931) and the runner docs (#5932).

Refs #5714 #5931 #5932

Implementation

  1. Self-check (sandbox/selfCheck.ts in the container, sandbox/selfCheckRun.ts on the host). It runs three jobs through the real launcher against a fake upstream, with no key. It prints one line per check and exits 0 only when every check passes:
    • The process runs as the host uid, which is not 0. CapEff is 0, NoNewPrivs is 1, Seccomp is 2, and the boot ID is the host's.
    • /, /repo/src, /repo/node_modules and /repo/dist are read-only (EROFS). The home is empty and writable. /home holds no host home, and no docker.sock or ~/.docker exists.
    • The only interface is lo, and no IPv4 route exists. In Node probes, loopback gives ECONNREFUSED, 172.17.0.1 and 1.1.1.1 give ENETUNREACH, and DNS fails (EAI_AGAIN or ENOTFOUND). No credential env name is set.
    • The proxy is a unix socket on a read-only mount. One allowed call passes, and the P1–P5 cases refuse. On the host, for each of the three jobs, the fake upstream must see exactly that job's allowed call and no key.
    • A model-driven app started by startApp.ts has all three XUM_DISABLE_* switches.
    • The host requires all 31 container checks by name, once each (CONTAINER_CHECKS), and fails with the missing and unexpected names. A partial report never passes.
    • A stopped job ends the run with exit 130 or 143 and starts no other job. A job whose container state is unknown after cleanup ends it with exit 3, which outranks a stop. The in-container /health probe has a 2 s timeout.
    • Two more jobs export a path-traversal frame and an oversized frame. Each must refuse with its own message, exit 4, clean up, and leave no file outside the output folder.
  2. Launcher (launch.ts, entry.ts): a fourth job kind, self-check [--export-fixture traversal|oversize] --output .e2e/<dir>. It has a fixed command and is model-driven, so it gets the proxy and the guard. entry.ts accepts --export-fixture only for that command.
  3. procShowsAll() (follow-up from the D1 readiness review): when /proc is mounted more than once, it reads the last /proc line of mountinfo, which is the mount in effect, not the first.
  4. Makefile: bug-bash-sandbox-check and test-bugbash-repros-sandbox. The second runs every repro of a fixed bug (known-failure excluded) through the launcher, on the mock app AI.
  5. CI (.github/workflows/pr.yml): the new job Test / Bug-bash sandbox (bugbash-sandbox) runs both targets without secrets, and Required needs it. The launcher pulls the pinned image by digest without credentials. E2E shard 1 keeps its host repros until this job proves stable.
  6. Docs (docs/AGENTS.md, regenerated builtInSkillContent.generated.ts): the two targets, the CI job, and what the launcher refuses with exit 2.

CI cost

The bugbash-sandbox job runs its own full build (build-main build-renderer build-static) on every PR where the tests filter is true. That costs CI minutes. It adds nothing to the app's perf path.

Size

The diff is 584 lines, over the 500-line target, because selfCheck.ts alone is 291 lines.

Validation

Items 1–3 ran on the pushed head. Item 4 ran on 6fb6315ff1: the later commits change only the self-check, which the repro run does not use.

  1. make static-check passes.
  2. bun test ./tests/bugbash/: 255 pass, 0 fail. The procShowsAll test fails when the change reverts to the first line.
  3. make bug-bash-sandbox-check: 54 passed, 0 failed. All three job containers were removed.
  4. make test-bugbash-repros-sandbox: 26 files and 50 tests passed, and the container was removed.
  5. On an earlier D2 commit, I ran the self-check with no-new-privileges removed from the container flags: 2 checks failed and it exited 1.
  6. With the container's DNS check skipped, the container exited 0 and reported 30 of 31 checks. The self-check failed with missing: no DNS.

Follow-ups

These are tracked, not fixed in this PR.

  1. Only e2e's exit 3 is remapped (to 6). A job's own exits 2, 4 and 5 still collide with the launcher's codes. Map every e2e code into its own range, or document the overlap.
  2. Optional: a socket-path test that runs under Node. Bun 1.3.12 binds unix socket paths over the 107-byte limit, so a test that runs under Bun cannot catch a path that is too long.
  3. The bridge probe tries only 172.17.0.1, so a daemon with a custom bip is not probed. The "no IPv4 route" check (routes.length === 0) already proves the claim.
  4. A change to the Makefile alone skips every test job. This paths-filter gap is older than this PR, and 🤖 ci: fail PRs that grow first-load JS over the recorded budget #6084 changes the filter.
  5. Remove the duplicate host repro run on E2E shard 1 once the sandbox repros run stably in CI.
  6. The docs/AGENTS.md bullet says the check "launches one self-check job". It launches three (the self-check and two export fixtures). Fix the count and regenerate builtInSkillContent.generated.ts with the next docs change to this section.

Risks

Test and CI code only. The new required job depends on Docker on the Linux runner and on an anonymous pull of the pinned image from ghcr.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $160.50

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T21:53:29.428526Z 2fc08c2 New commits
🔒 Security Review ✅ Completed 2026-10-10T21:52:58.510339Z 2fc08c2 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThomasK33
ThomasK33 added this pull request to stack #6070 October 10, 2026 20:16

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6fb6315ff1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/bugbash/sandbox/selfCheck.ts Outdated
ThomasK33 added a commit that referenced this pull request Oct 10, 2026
The app check subscribed to the app's exit only after it sent SIGTERM. An app
that had already exited during startup never fires that event again, so the
check hung until the CI job's timeout (Codex review on #6085). It now
subscribes at spawn, stops polling /health once the app is gone, and reports
the app's exit code.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Round 2: the self-check no longer hangs on an app that exits during startup (189de75).

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 189de75aa9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 189de75aa9

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Base automatically changed from tests/5714-d1-runtime-fixes to main October 10, 2026 21:05
- sandbox/selfCheck.ts (in the container) and selfCheckRun.ts (host, `make
  bug-bash-sandbox-check`, $0 against a fake upstream, no key): one line per
  check. The container runs as the host uid (nonzero), with CapEff 0,
  NoNewPrivs 1, seccomp 2 and the host's boot ID. /, /repo/src,
  /repo/node_modules and /repo/dist are read-only (EROFS), the home is empty,
  /home holds no host home, and no docker.sock or ~/.docker exists. Only lo
  exists, with no IPv4 route. Loopback gives ECONNREFUSED, 172.17.0.1 and
  1.1.1.1 give ENETUNREACH, and DNS fails (EAI_AGAIN or ENOTFOUND). No
  credential env name is set. The proxy socket is a unix socket on a read-only
  mount. One allowed proxy call passes, and the P1-P5 cases refuse. A
  model-driven app started by startApp has all three XUM_DISABLE_* switches.
- The host side checks that the fake upstream saw exactly the allowed call and
  no key. Two more jobs export a path-traversal frame and an oversized frame:
  each must refuse with its own message, exit 4, clean up, and leave no file
  outside the output folder.
- launch.ts: a fourth job kind, `self-check [--export-fixture traversal|oversize]
  --output .e2e/<dir>`, with a fixed command and the model-driven guard.
  entry.ts accepts --export-fixture only for that command.
- launch.ts procShowsAll(): the last /proc line of mountinfo is the mount in
  effect, so it reads that one, not the first (D1 readiness review).
- Makefile: `test-bugbash-repros-sandbox` runs the repros of fixed bugs through
  the launcher on the mock app AI.
- pr.yml: new `Test / Bug-bash sandbox` job (no secrets) runs both targets;
  Required needs it. E2E shard 1 keeps its host repros for now.
- docs/AGENTS.md: the sandbox checks, the CI job and what the launcher refuses.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
The app check subscribed to the app's exit only after it sent SIGTERM. An app
that had already exited during startup never fires that event again, so the
check hung until the CI job's timeout (Codex review on #6085). It now
subscribes at spawn, stops polling /health once the app is gone, and reports
the app's exit code.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
@mintlify

mintlify Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
Mux 🟢 Ready View Preview Oct 10, 2026, 9:05 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

selfCheckRun.ts accepted any non-empty checks.jsonl from the container, so a
self-check that stopped early, or lost a check, still passed (D2 readiness
review). It now requires every one of the 31 container checks by name, once
each, and fails with the missing and unexpected names.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d09d4e6888

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/bugbash/sandbox/selfCheck.ts Outdated
Comment thread tests/bugbash/sandbox/selfCheckRun.ts Outdated
Comment thread tests/bugbash/sandbox/selfCheckRun.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Round 3: the host now requires all 31 container checks by name and fails on a partial report (5dc92dd, on the restacked head).

…s every job's upstream

From the Codex review on #6085:
- A stopped job now ends the self-check with Stopped (exit 130 or 143) and
  starts no other job, as for any launcher job. An unknown cleanup still
  outranks the stop.
- Each export-fixture job runs the whole selfCheck.ts too, so it makes its own
  allowed call and P1-P5 probes. The upstream is now checked per job (exactly
  one allowed call, no forbidden one, nothing else, no key), not only after
  the first job.
- The in-container /health probe has a 2 s timeout, so a server that accepts
  and never answers cannot hang the check.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 5dc92dd746

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 5dc92dd746

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Round 4: per-job upstream checks, a stopped job ends the self-check, and the health probe is bounded (2d8a3a7).

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 2d8a3a7e26

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2d8a3a7e26

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/bugbash/sandbox/selfCheckRun.ts Outdated
Comment thread docs/AGENTS.md
…r a stop

The round-3 change skipped the stop when a job's cleanup was unknown, so the
self-check went on to the next job with the aborted signal and exited 130 or
143 instead of 3 (Codex review on #6085). exitFor()'s rule now applies: an
unknown cleanup ends the run at once with exit 3, and outranks a stop.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Round 5: an unknown cleanup now ends the self-check with exit 3 and outranks a stop (545ddea).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 545ddea634

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/bugbash/sandbox/selfCheckRun.ts
Comment thread tests/bugbash/sandbox/selfCheck.ts Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 545ddea634

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33

Copy link
Copy Markdown
Member Author

Review loop stopped: this PR is at its 6-round Codex cap and waits for a waiver.

Head 545ddea634 has no Codex approval. Round 6 found 2 P2s. Both threads have a reply and are resolved, but the code is not fixed yet:

  1. Capability check fails open. The self-check's "no capabilities" check reads only CapEff. A container that keeps permitted, inheritable, bounding or ambient capabilities would still pass. Today's launcher config is not affected: with its real flags, all five sets measured 0000000000000000. The defect is that the check cannot catch a regression, so this is the finding that blocks merge.
  2. Wrong exit code. A Session refusal after the preflight exits 1 instead of the documented 2. It still fails closed.

The proposed fix: one small patch with both fixes, plus a test where CapEff is 0 and another set is nonzero. Then all D2 gates and one more Codex round. Merge only on approval of the final head and a passing Required. Nothing gets pushed until the maintainer grants the extra round.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high

…on a refusal

From the last Codex review round on #6085:
- F1: "no capabilities" read only CapEff, so a container that kept a
  capability in its permitted, inheritable, bounding or ambient set still
  passed, and a permitted capability can be made effective again. The check now
  requires CapInh, CapPrm, CapEff, CapBnd and CapAmb all to be zero, and names
  any nonzero or missing set. With the launcher's flags all five are zero.
- F2: a Refusal that Session raises after the preflight (root, rootless Docker,
  Docker Desktop) came back in the job outcome, so the self-check recorded
  failed checks, started the other jobs and exited 1. It now re-throws the
  outcome's error after the unknown-cleanup and stop checks: a Refusal exits
  2 and no further job starts.

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Round 7 (user-granted, final): all five capability sets must be 0; a Refusal exits 2 (2fc08c2).

@chatgpt-codex-connector

This comment has been minimized.

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 2fc08c26c3

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 10, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 10, 2026
@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 11, 2026
Merged via the queue into main with commit 9224e24 Oct 11, 2026
63 of 65 checks passed
@ThomasK33
ThomasK33 deleted the tests/5714-d2-selfcheck-ci branch October 11, 2026 00:18
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