Repository navigation
[infra] - Prove bwrap AppArmor policy on Ubuntu 26.04 without weakening the checks - #1641
Conversation
… runner Co-authored-by: Chris Grady <cgfixit@users.noreply.github.com>
Co-authored-by: Chris Grady <cgfixit@users.noreply.github.com>
|
PR is a complete fill of |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2a4b369c4e
ℹ️ 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".
| if apt-cache show 'bubblewrap=0.9.0-1ubuntu0.3' >/dev/null 2>&1; then | ||
| echo "noble_pin=present" |
There was a problem hiding this comment.
Detect an absent Noble version from command output
When the pinned Noble version is absent—the expected Ubuntu 26.04 case—apt-cache show 'bubblewrap=0.9.0-1ubuntu0.3' still exits successfully with no records; this occurs with apt 2.8.3, and the commit's hosted 26.04 evidence reports the same false positive. The Ubuntu apt-cache manual defines show as displaying matching package records, so its exit status is not an existence predicate. This branch therefore emits noble_pin=present despite the version being unavailable; test for non-empty exact-version output or inspect apt-cache policy/madison instead.
AGENTS.md reference: AGENTS.md:L49-L49
Useful? React with 👍 / 👎.
Proposed changes
Adds a non-required Ubuntu 26.04 diagnosis job for the bubblewrap AppArmor checks, and does not change the required checks. Linked issue: #1626.
The diff against
mainis two files:.github/workflows/ci.ymland.github/actionlint.yaml. The new job isubuntu-26-04-bwrap-diagnose. It usesruns-on: ubuntu-26.04,continue-on-error: true, andtimeout-minutes: 15. The job name is not a required check name. It installs the distrobubblewrappackage, prints the AppArmor profiles and userns sysctls, and runs the same confinement command the 24.04 leg uses: under stock policy, afterapparmor_parser -rloadsdeploy/apparmor/cyclaw-bwrap, and after that profile is removed. It also runs a copy ofbwrapfrom the runner temp directory, so the attachment is not/usr/bin/bwrap. It does not writekernel.apparmor_restrict_unprivileged_userns..github/actionlint.yamlallowlists the labelubuntu-26.04for actionlint 1.7.12, which does not know that label. The label is a GitHub-hosted runner. The file does not provision a machine.The
testmatrix and theubuntu-latest/ubuntu-22.04bwrap steps are unchanged. This head does not make those steps pass on 26.04. It records why the canary failed.On head
2a4b369c, run https://github.com/cgfixit/CyClaw/actions/runs/38352458013 job https://github.com/cgfixit/CyClaw/actions/runs/38352458013/job/115147715257 (ubuntu-26-04-bwrap-diagnose) completed with success. The log saysPRETTY_NAME Ubuntu 26.04.1 LTS,VERSION_ID 26.04,VERSION_CODENAME=resolute. Apt policy saysInstalled: 0.11.1-1ubuntu0.3andCandidate: 0.11.1-1ubuntu0.3. The version table lists0.11.1-1ubuntu0.3and0.11.1-1only. The script still printednoble_pin=present, becauseapt-cache show 'bubblewrap=0.9.0-1ubuntu0.3'exited 0 even though that version is not in the table.kernel.apparmor_restrict_unprivileged_userns=1andkernel.apparmor_restrict_unprivileged_unconfined=1. Stock policy loads/etc/apparmor.d/bwrap-userns-restrict, whose header isprofile bwrap /usr/bin/bwrap flags=(attach_disconnected,mediate_deleted) {. Loaded profiles before any CyClaw profile:bwrap (enforce),unpriv_bwrap (enforce),unprivileged_userns (enforce). The stock confinement command exited 0. The child label waschild_apparmor=bwrap//&unpriv_bwrap (enforce).A copy at another path exited 1 with
bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted. The kernel log saysapparmor="AUDIT" operation="userns_create" ... profile="unconfined" ... comm="bwrap-unprofile" requested="userns_create" target="unprivileged_userns" execpath="/home/runner/work/_temp/bwrap-unprofiled"andapparmor="DENIED" operation="capable" class="cap" profile="unprivileged_userns" ... comm="bwrap-unprofile" capability=12 capname="net_admin".Loading
deploy/apparmor/cyclaw-bwrapexited 0 and left bothcyclaw-bwrap (unconfined)andbwrap (enforce)loaded. The same confinement command then exited 1 withbwrap: loopback: Failed RTM_NEWADDR: Operation not permitted. Removingcyclaw-bwrapmade that command exit 0 again.ubuntu-lateston this head was still queued when this description was written.invariant-guardon this head completed with success.pytest tests/was not run.Invariant / Governance Impact
gate.py,graph.py, soul handling, the sanitizer, auth, or retrieval..github/workflows/ci.ymland.github/actionlint.yamlonly. Theinvariant-guardcheck on head2a4b369ccompleted with success.Types of changes
Optional free-text scope note (recommended):
Infrastructure / CI only
Benefits / why
ubuntu-lateststeps still assume stock AppArmor refusesbwrapuntildeploy/apparmor/cyclaw-bwraploads. This run shows 26.04 already ships an enforce-modebwrapprofile for/usr/bin/bwrap, and that loadingcyclaw-bwrapbeside it makes the confinement command fail onRTM_NEWADDR. That is the evidence for a later strict check. This PR does not weaken the 24.04 refusal or confinement scripts.continue-on-error, so this diagnosis does not become a required check name.1on the runner.Risks to monitor
main. It is not a release gate.continue-on-error: truemeans a later failure of this job does not fail the workflow. The signal is the job log, not the workflow conclusion.cyclaw-bwrapon the 26.04 runner is diagnostic. The log shows that load is what turns a passing stock confinement command intobwrap: loopback: Failed RTM_NEWADDR: Operation not permitted. The runner is discarded. This is not a reason to stack that profile on a host that already has/etc/apparmor.d/bwrap-userns-restrict.apt-cache show 'bubblewrap=0.9.0-1ubuntu0.3'printednoble_pin=presentwhile the version table did not list0.9.0-1ubuntu0.3. Do not treat that line as proof the noble pin exists on 26.04..github/actionlint.yamlallowlistsubuntu-26.04for actionlint only.probe stock-fullexit 0,probe unprofiled-copywithcapname="net_admin", andprobe after-cyclaw-fullwithRTM_NEWADDR.ubuntu-latestwas still queued here, so this description does not claim the 24.04 leg passed on this head.Checklist
docs/THREAT_MODEL.md,INVARIANTS.mdandSECURITY.md(and any relevant Phase docs)GROK_API_KEY=dummy pytest tests/ -q --tb=short, andbash .claude/skills/CyClaw-Sandbox/verify.shfor core RAG/agentic paths) and passes with no regressionsFurther comments
Human review note: the diff touches
.github/workflows/ci.ymland adds.github/actionlint.yaml. The checkout action pin is the existing SHAactions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1(v7.0.1) withpersist-credentials: false. No new third-party action. This PR is a draft. Do not merge it and do not enable auto-merge.Head described here:
2a4b369c. That commit is the diagnosis job plus GitHub's merge ofmain(663a8bbd, #1639). The required bwrap steps in thetestmatrix are the ones already onmain.What the 26.04 job actually showed, and what it did not change:
/usr/bin/bwrapis confined by Ubuntu'sbwrapprofile (bwrap (enforce)stacked withunpriv_bwrap), and the confinement command exits 0.unprivileged_userns, which deniesnet_admin, and loopback setup fails withRTM_NEWADDR.cyclaw-bwrapattaches to the same/usr/bin/bwrappath. After it loads, both profiles are present and the confinement command fails the same way. Unloading it restores exit 0.kernel.apparmor_restrict_unprivileged_usernsstayed1. No sysctl write.Local checks before this description, not a full suite:
actionlint1.7.12 with ShellCheck 0.9.0 on.github/workflows/ci.ymlexited 0, andzizmor1.28.0--min-severity=highon.github/workflows/reported no high findings. Those were run on the diagnosis commit before the GitHub merge ofmain. The hostedinvariant-guardcheck on2a4b369csucceeded.workflow-lint (actionlint + zizmor)was still queued.ubuntu-latestwas still queued.pytest tests/was not run.Suggested merge order of open PRs
Trial merges verified (
git merge --no-commit --no-ff+ abort) against main @ 663a8bb on 2026-10-13.#1637 · Blocked ⛔
Impact: Telemetry egress notes for the Keychain CLI and uv. Trial merge clean. No dependency on #1641.
Action: Do not merge while
Check PR body against templateis failing. Other checks were still running.#1638 · Blocked ⛔
Impact: Ponytail audit notes. Trial merge clean. No dependency on #1641.
Action: Do not merge while
Check PR body against templateis failing. Other checks were still running.#1640 · Blocked ⛔
Impact: Dependency currency notes. Trial merge clean. No dependency on #1641.
Action: Do not merge while
Check PR body against templateis failing. Other checks were still running.#1641 · Blocked ⛔
Impact: Non-required Ubuntu 26.04 bwrap diagnosis. Trial merge clean. Draft; required bwrap steps unchanged.
Action: Do not merge and do not auto-merge.
ubuntu-latestwas still queued.ELI5
The required Ubuntu test still expects stock AppArmor to block bubblewrap until CyClaw loads
deploy/apparmor/cyclaw-bwrap. On the Ubuntu 26.04 runner that already happened in jobubuntu-26-04-bwrap-diagnose(run 38352458013), stock/usr/bin/bwrapis allowed because Ubuntu's ownbwrapprofile is loaded in enforce mode, and the confinement command exits 0. A copy of bubblewrap that is not at/usr/bin/bwrapis refused: the kernel deniesnet_adminunderunprivileged_userns, and bubblewrap printsbwrap: loopback: Failed RTM_NEWADDR: Operation not permitted. Loading CyClaw's profile next to Ubuntu's profile makes/usr/bin/bwrapfail the same way; removing CyClaw's profile makes the command exit 0 again. This pull request only adds that practice job and an actionlint allowlist for theubuntu-26.04label. It does not change the required 24.04 steps, it does not turn the kernel switch off, and it does not fix those steps for 26.04 yet. The practice job is continue-on-error.ubuntu-latestwas still queued, so this does not claim that leg passed. Do not merge this draft.Last updated: 2026-10-13 01:47 ET