| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- # Sandbox CI: the keyless real-kernel confinement proofs. This master-only
- # reference stays outside the pull-request verdict; rationale lives in
- # .agents/notes/implemented/process/2026-07-21-serial-cross-platform-ci-reference.md.
- # A separate workflow from ci.yml because the axis is different — these jobs
- # fan out over OS×runner (kernel capabilities), not node versions. The Landlock
- # launcher is built from native/landlock-run on each Landlock leg and installed
- # from the same tarballs the main-repository release workflow publishes.
- name: Sandbox
- on:
- push:
- branches: [master]
- concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
- permissions:
- contents: read
- env:
- # CI runs must never report to the production telemetry endpoint baked
- # into apps/cli/cordis.yml (AppCLIEntry disables the row when set).
- DSH_TELEMETRY_DISABLED: '1'
- jobs:
- # Keyless real-kernel sandbox proofs (sandbox Agent Note § Testing): each ladder
- # rung is only provable on a host where it enforces, so this job fans out
- # an OS×runner matrix — bwrap and Landlock on Linux (separate legs: the
- # Landlock files force the bwrap rung off, so each leg proves exactly one
- # rung; Landlock twice, once per architecture, each confining through the
- # locally built launcher), Seatbelt on macOS (sandbox-exec ships with
- # the OS). One node
- # version only: kernel confinement does not vary by node, and ci.yml's
- # node matrix already covers the node axis.
- #
- # The e2e files self-skip where their runner is absent, so a leg that lost
- # its runner (no bwrap, kernel without Landlock, macOS without
- # sandbox-exec) would otherwise pass as a false green — the same trap
- # e2e.yml's key preflight guards against. Each leg therefore asserts BOTH
- # its platform files actually ran: `Test Files 2 passed (2)`, no skips.
- sandbox-e2e:
- strategy:
- fail-fast: false
- matrix:
- include:
- - os: ubuntu-latest
- runner: bwrap
- - os: ubuntu-24.04
- runner: landlock
- - os: ubuntu-24.04-arm
- runner: landlock
- - os: macos-latest
- runner: seatbelt
- name: sandbox e2e (${{ matrix.runner }}, ${{ matrix.os }})
- runs-on: ${{ matrix.os }}
- timeout-minutes: 20
- steps:
- - uses: actions/checkout@v6
- - uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v6
- with:
- node-version: 24
- - name: Install (immutable)
- run: pnpm install --frozen-lockfile
- # The bwrap rung needs bubblewrap on PATH and unprivileged user
- # namespaces. Ubuntu 24.04 gates the latter behind an AppArmor knob;
- # lift it best-effort — on images where the knob is absent the
- # functional probe (and the run-guard below) is the arbiter anyway.
- - name: Install bubblewrap (unrestrict userns)
- if: matrix.runner == 'bwrap'
- run: |
- sudo apt-get update -q
- sudo apt-get install -yq bubblewrap
- sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 \
- || echo "apparmor userns knob absent — the functional probe decides"
- - name: Build Landlock launcher for this architecture
- if: matrix.runner == 'landlock'
- run: |
- sudo apt-get update -q
- sudo apt-get install -yq musl-tools
- pnpm --dir native/landlock-run run build:ts
- pnpm --dir native/landlock-run run build:native
- # The unit suite runs on ubuntu in `checks`; this is the one darwin leg
- # in the workflow, so run it here too — the platform-dependent unit
- # expectations (Seatbelt path canonicalization: /tmp IS /private/tmp)
- # take their darwin branch only on this runner.
- - name: Unit tests (darwin parity)
- if: matrix.runner == 'seatbelt'
- run: pnpm run test
- - name: Sandbox e2e (real kernel confinement, world-verified)
- # NO_COLOR: vitest force-enables ANSI color under GITHUB_ACTIONS even
- # without a TTY, which would thread escape codes through the summary
- # line the run-guard greps.
- env:
- NO_COLOR: 1
- run: |
- set -u +e -o pipefail
- out=$(pnpm exec vitest run --config vitest.e2e.config.ts \
- packages/sandbox/sandbox-local/tests/${{ matrix.runner }}.e2e.ts \
- packages/shell/bash-sandbox/tests/${{ matrix.runner }}.e2e.ts 2>&1); status=$?
- echo "$out"
- [ "$status" -eq 0 ]
- # Both platform files must have RUN — a self-skip (runner missing on
- # the very platform that exists to prove it) is a failure, not a pass.
- echo "$out" | grep -qE 'Test Files[[:space:]]+2 passed \(2\)'
- # Publish-path rehearsal, Landlock legs only. Build the launcher on its
- # native architecture, then install the local native and harness tarballs
- # together so registry state cannot mask source/package drift.
- - name: Build packages for the pack rehearsal
- if: matrix.runner == 'landlock'
- run: pnpm run build:official
- - name: Packed-distribution e2e (pack → install → confine)
- if: matrix.runner == 'landlock'
- env:
- NO_COLOR: 1
- run: |
- set -u +e -o pipefail
- out=$(pnpm exec vitest run --config vitest.e2e.config.ts \
- packages/sandbox/sandbox-local/tests/packed-install.e2e.ts 2>&1); status=$?
- echo "$out"
- [ "$status" -eq 0 ]
- echo "$out" | grep -qE 'Test Files[[:space:]]+1 passed \(1\)'
|