Skip to content

revisit later if this is determined to bea useful way to deploy and worth the time to understand it - [infra] - Add a throwaway Ubuntu 26.04 bwrap AppArmor canary - #1628

Closed
cgfixit wants to merge 1 commit into
mainfrom
agent/ubuntu-26-04-bwrap-canary-e284
Closed

cgfixit wants to merge 1 commit into
mainfrom
agent/ubuntu-26-04-bwrap-canary-e284

Conversation

@cgfixit

@cgfixit cgfixit commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Proposed changes

Adds a throwaway, non-required Ubuntu 26.04 canary for the three bwrap AppArmor steps that the required ubuntu-latest test leg runs on 24.04. Linked issue: #1626.

GitHub's ubuntu-26.04 label is generally available for public repositories (runs-on: ubuntu-26.04, changelog 2026-09-17). ubuntu-latest moves from 24.04 to 26.04 gradually between 2026-10-19 and 2026-11-19. This PR runs the same probes on 26.04 before that window, without changing any check that gates merges.

The new job is ubuntu-26-04-bwrap-canary in .github/workflows/ci.yml. It uses runs-on: ubuntu-26.04, continue-on-error: true, and a 15 minute timeout. It checks out the repo, installs bubblewrap, then runs the three probes copied from the ubuntu-latest leg:

  1. Prove stock AppArmor refuses bwrap (sysctl must read 1, and bwrap must fail with a userns/permission denial).
  2. Load deploy/apparmor/cyclaw-bwrap with apparmor_parser -r.
  3. Prove bwrap confinement.

The refusal script is byte-for-byte the same as the 24.04 leg. It is not loosened. The job does not write kernel.apparmor_restrict_unprivileged_userns. The noble apt pin bubblewrap=0.9.0-1ubuntu0.3 is used when that version is in the image cache, and the version string must then match bubblewrap 0.9.0. If the pin is absent, the job installs the distro package, prints bwrap --version, and continues. The required 24.04 leg still hard-fails on a pin miss.

actionlint 1.7.12 (the workflow-lint pin, actionlint-py==1.7.12.24) does not know ubuntu-26.04 and has no ignore-comment syntax. .github/actionlint.yaml allowlists that one label so workflow-lint stays green. The label is a GitHub-hosted runner, not a self-hosted machine. CI workflow-lint (actionlint + zizmor) passed on this head.

The test matrix, the ubuntu-latest and ubuntu-22.04 legs, required check names, and the six invariants are unchanged.

First canary run (do not retune from this): the 26.04 image ran. Stock refusal failed even though the sysctl was 1, because bwrap succeeded. Profile load passed. Confinement then failed with RTM_NEWADDR: Operation not permitted. Details are in Further comments.

Workflow changes need the Advisor's pass on the exact head SHA before merge. This PR is a draft and must not be merged or auto-merged. The canary is throwaway and non-required.

Invariant / Governance Impact

  • None of the six security invariants or I6 module isolation. No change to gate.py, graph.py, soul handling, the sanitizer, auth, or retrieval.
  • Evidence: python3 .claude/skills/invariant-guard/check_invariants.py reported 46 passed, 0 failed on this head. doc-sync reported 0 drift, so no doc or registry update was required for the new job. tests/test_repo_hygiene.py still requires a timeout on every job; this job sets timeout-minutes: 15.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Security (auth, privacy, injection, egress, redaction, or secrets)
  • Invariant / Governance refinement (use this for changes that strengthen or evolve the 6 invariants, I6 isolation, or harness phases)
  • Dependencies (added, removed, or bumped)
  • CI / infrastructure (workflows, hooks, templates, or checkers)
  • Refactor or tests (behavior-preserving, no new capability)
  • Documentation update
  • Other (none of the boxes above fit)

Optional free-text scope note (recommended):
Infrastructure / CI only

Benefits / why

Risks to monitor

  • The canary spends a small amount of Actions time on every pull request and on pushes to main. It is not a release gate. Delete the job after the migration window answers the question.
  • If the refusal step fails, that is the finding. Do not retune the grep or re-add the global sysctl write to make it green. This first run failed that way, and the script was left as copied.
  • When ubuntu-latest starts landing on 26.04, the required refusal step will fail the same way this canary did, unless the image or the check changes first. That is the point of running this before 2026-10-19.
  • .github/actionlint.yaml allowlists ubuntu-26.04 for actionlint only. It does not provision a runner. A future actionlint release that knows the label can drop the file.
  • No new shortcut around audit convergence, RAG-first, soul writes, or subprocess isolation. The product runtime is unchanged.
  • Drift signal: the canary step log's kernel.apparmor_restrict_unprivileged_userns= line and the three step conclusions. This run's signal is sysctl 1 plus bwrap succeeded under stock AppArmor.

Checklist

  • I have read docs/THREAT_MODEL.md, INVARIANTS.md and SECURITY.md (and any relevant Phase docs)
  • This change preserves all 6 security invariants and I6 module isolation (explicit evidence or invariant matrix included for core changes)
  • Full sandbox validation has been run (GROK_API_KEY=dummy pytest tests/ -q --tb=short, and bash .claude/skills/CyClaw-Sandbox/verify.sh for core RAG/agentic paths) and passes with no regressions
  • No new external network dependencies or mandatory online LLM assumptions were introduced without explicit justification + offline fallback path
  • For any agentic/fsconnect change: two-phase audit, quota enforcement, governed delete/trash, and write guards have been verified
  • Relevant architecture docs or threat model notes have been updated if core behavior or topology changed
  • Commit messages follow the title prefix convention above
  • For large or complex changes: before/after invariant matrix + sandbox evidence is included in "Further comments" or linked

Further comments

Head SHA for Advisor review: b84eb6820e43900c73e161c655342f4d78a7401e. Workflow changes need the Advisor's pass on that exact head SHA before merge. This PR is a draft and must not be merged or auto-merged. The canary is throwaway and non-required.

Human review note: this diff touches .github/workflows/ci.yml and adds .github/actionlint.yaml. Both are CI control files. The checkout action pin is the existing SHA actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 (v7.0.1) with persist-credentials: false. No new third-party action.

Local checks on this head, not the full suite:

  • actionlint 1.7.12 (actionlint-py==1.7.12.24) on .github/workflows/*.yml, with ShellCheck 0.9.0: exit 0. Without .github/actionlint.yaml the same binary reports label "ubuntu-26.04" is unknown.
  • zizmor 1.28.0 --gh-token --min-severity=high .github/workflows/: no high findings.
  • python3 .claude/skills/invariant-guard/check_invariants.py: 46 passed, 0 failed.
  • python3 .claude/skills/doc-sync/doc_sync.py: 0 drift. No doc update.
  • pytest tests/test_repo_hygiene.py for the timeout, SHA-pin, and workflow-permission tests only, with --noconftest: passed. The full pytest tests/ suite was not run.

The three run: scripts in the canary match the ubuntu-latest copies. The matrix if: lines are omitted so the probes are not skipped on a non-matrix job. Later probes use if: ${{ !cancelled() }} so a failed refusal still attempts the profile load and the confinement probe. That does not change the refusal check.

First CI run of ubuntu-26-04-bwrap-canary on head b84eb6820e43900c73e161c655342f4d78a7401e:

  • Run: https://github.com/cgfixit/CyClaw/actions/runs/38077837149
  • Job: https://github.com/cgfixit/CyClaw/actions/runs/38077837149/job/114288431049
  • Runner label ubuntu-26.04 did run. Image ubuntu-26.04 version 20260927.149.1, OS Ubuntu 26.04.1 LTS.
  • Install bubblewrap: pass. Apt candidate is 0.11.1-1ubuntu0.3 (already installed). Warning: noble pin bubblewrap=0.9.0-1ubuntu0.3 is not in this image apt cache. bwrap_version=bubblewrap 0.11.1, path /usr/bin/bwrap.
  • Prove stock AppArmor refuses bwrap: fail. Log: kernel.apparmor_restrict_unprivileged_userns=1 then bwrap succeeded under stock AppArmor; expected a refusal before the cyclaw-bwrap profile loads. The sysctl matched the 24.04 requirement. The probe was not refused. The check was not changed.
  • Load the bwrap-scoped AppArmor profile: pass. apparmor_parser -r printed no error.
  • Prove bwrap confinement: fail. The same bwrap command, after the profile load, exited 1 with bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted.

Suggested merge order of open PRs

Trial merges verified (git merge --no-commit --no-ff + abort) against main @ b9573b0 on 2026-10-10.

#1628 · Blocked ⛔
Impact: Throwaway non-required ubuntu-26.04 bwrap canary. No file overlap with #1617, #1618, #1619, #1625, or #1627.
Action: Do not merge and do not auto-merge. Draft until the Advisor passes the exact head SHA. Trial merge of this branch onto main was clean.

ELI5

The required Ubuntu test still runs on today's 24.04 image and still has to prove that stock AppArmor blocks bubblewrap, then load our small AppArmor profile, then prove bubblewrap can run. GitHub will start moving that "latest" image to Ubuntu 26.04 on October 19, 2026. This PR adds a separate practice run on the Ubuntu 26.04 image and does not change the required jobs. That practice run already happened. Ubuntu 26.04 has bubblewrap 0.11.1, not the 24.04 package pin. The kernel switch is still 1, but bubblewrap was allowed to run anyway, so the "stock refuses bubblewrap" step failed. Loading the profile succeeded. The confinement command then failed with "Operation not permitted" while adding a network address. That failure is the finding. The refusal check was not loosened to hide it. The practice job is continue-on-error, so it is not supposed to block a merge by itself. Do not merge this draft.

Last updated: 2026-10-10 14:59 ET

Open in Web Open in Cursor 

Co-authored-by: Chris Grady <cgfixit@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

PR template check (blocking)

This PR is not a complete fill of .github/PULL_REQUEST_TEMPLATE.md:

  • [stamp] Last non-blank line must be Last updated: YYYY-MM-DD HH:MM ET
  • [title] Title must read [prefix] - Short sentence with prefix one of invariant|governance|fsconnect|agentic|rag|harness|security|docs|infra|fix|feat

This check fails the job. Copy .github/PULL_REQUEST_TEMPLATE.md, fill every section, and edit the PR. Check locally first with scripts/check-pr-template.sh --title ... --branch ... body.md. Verify / Base are optional here (Grok-local push extras).

@cgfixit

cgfixit commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@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-10T19:36:39.777870Z b84eb68 Manual request
ℹ️ 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.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: b84eb6820e

ℹ️ 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".

@cgfixit cgfixit changed the title [infra] - Add a throwaway Ubuntu 26.04 bwrap AppArmor canary revisit later if this is determined to bea useful way to deploy and worth the time to understand it - [infra] - Add a throwaway Ubuntu 26.04 bwrap AppArmor canary Oct 10, 2026
@cgfixit cgfixit closed this Oct 10, 2026
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