PRD prd-new: macOS (Apple Container) CI runner #479

Merged
didericis-claude merged 4 commits from prd-macos-container-ci-runner into main 2026-07-25 22:34:50 -04:00
Collaborator

Closes #426.

PRD: docs/prds/prd-new-macos-container-ci-runner.md

Summary

CI had no runner for the macos-container (Apple Container) backend — Docker and Firecracker are exercised, macOS is not — which is how the gateway_init.py supervisor regression survived on main for that backend. Builds on #470 (#414), whose is_backend_ready preflight and backend-agnostic guards this job plugs into.

Adds integration-macos (.gitea/workflows/test.yml): runs tests/integration against BOT_BOTTLE_BACKEND=macos-container on a self-hosted host-mode macOS runner (label macos; Apple Container can't run in a Linux container, so it can't reuse the kvm runner).

  • Advisory, by design: push-to-main + workflow_dispatch only, never PRs, and deliberately not in the coverage job's needs. A single laptop that sleeps/roams must not block a merge, and not gating on PRs also keeps fork PRs off the host-mode runner.
  • Fails, not skips, when the backend is absent: preflights command -v container, container system status, and ./cli.py backend status --backend=macos-container.
  • Handles the bot-bottle-mac-infra singleton (#425): a concurrency group serializes runs and an if: always() teardown removes the container on exit.

Relaxes the TestSandboxEscape CI skip guard. It skipped every backend but firecracker under GITEA_ACTIONS, so it would also skip on a host-mode macOS runner — leaving the macOS job green while skipping the one end-to-end test that actually boots a bottle (and the test whose setUpClass launch would catch a reverted infra.py supervisor fix, satisfying AC#4). The guard's real target is the containerized act_runner, so it now allows both host-mode backends (firecracker, macos-container) through.

Docs: README "macOS Apple Container" CI note (runner provisioning) and docs/ci.md. Also corrects a stale README line that claimed git-gate is "deferred" on the macOS backend — it isn't; it runs over the gateway's consolidated git-http daemon with dynamic key provisioning/revocation (only the legacy per-bottle git:// daemon is unused), so sandbox-escape attack 5 runs the same as on the other backends.

Notes

  • The macOS runner itself is operational and provisioned out-of-band; this PR is the job + guard + docs that the runner picks up.

Full unit suite (2233) green; workflow YAML validated; skip-guard truth table verified.

Closes #426. PRD: [`docs/prds/prd-new-macos-container-ci-runner.md`](https://gitea.dideric.is/didericis/bot-bottle/src/commit/152726dc8c4831258e4ad47927561041f89e60fa/docs/prds/prd-new-macos-container-ci-runner.md) ## Summary CI had no runner for the `macos-container` (Apple Container) backend — Docker and Firecracker are exercised, macOS is not — which is how the `gateway_init.py` supervisor regression survived on `main` for that backend. Builds on #470 (#414), whose `is_backend_ready` preflight and backend-agnostic guards this job plugs into. **Adds `integration-macos`** (`.gitea/workflows/test.yml`): runs `tests/integration` against `BOT_BOTTLE_BACKEND=macos-container` on a self-hosted **host-mode** macOS runner (label `macos`; Apple Container can't run in a Linux container, so it can't reuse the `kvm` runner). - **Advisory**, by design: push-to-`main` + `workflow_dispatch` only, never PRs, and deliberately **not** in the `coverage` job's `needs`. A single laptop that sleeps/roams must not block a merge, and not gating on PRs also keeps fork PRs off the host-mode runner. - **Fails, not skips**, when the backend is absent: preflights `command -v container`, `container system status`, and `./cli.py backend status --backend=macos-container`. - Handles the `bot-bottle-mac-infra` **singleton** (#425): a `concurrency` group serializes runs and an `if: always()` teardown removes the container on exit. **Relaxes the `TestSandboxEscape` CI skip guard.** It skipped every backend but `firecracker` under `GITEA_ACTIONS`, so it would also skip on a host-mode macOS runner — leaving the macOS job green while skipping the one end-to-end test that actually boots a bottle (and the test whose `setUpClass` launch would catch a reverted `infra.py` supervisor fix, satisfying AC#4). The guard's real target is the *containerized* act_runner, so it now allows both host-mode backends (`firecracker`, `macos-container`) through. **Docs:** README "macOS Apple Container" CI note (runner provisioning) and `docs/ci.md`. Also corrects a stale README line that claimed git-gate is "deferred" on the macOS backend — it isn't; it runs over the gateway's consolidated `git-http` daemon with dynamic key provisioning/revocation (only the legacy per-bottle `git://` daemon is unused), so sandbox-escape attack 5 runs the same as on the other backends. ## Notes - The macOS runner itself is operational and provisioned out-of-band; this PR is the job + guard + docs that the runner picks up. Full unit suite (2233) green; workflow YAML validated; skip-guard truth table verified.
didericis force-pushed prd-macos-container-ci-runner from 152726dc8c to a65eff45f5 2026-07-25 19:46:34 -04:00 Compare
Owner

@didericis-claude remove the push-to-main, and make it dispatch only

@didericis-claude remove the push-to-main, and make it dispatch only
Author
Collaborator

Done in 74632db. integration-macos is now dispatch-only — dropped the push trigger so its if is just github.event_name == 'workflow_dispatch'. Never runs on push (or PRs) anymore; a manual workflow_dispatch is the only way to trigger it. Updated the job comment, docs/ci.md, the README CI note, and the PRD to match.

Done in 74632db. `integration-macos` is now **dispatch-only** — dropped the `push` trigger so its `if` is just `github.event_name == 'workflow_dispatch'`. Never runs on push (or PRs) anymore; a manual `workflow_dispatch` is the only way to trigger it. Updated the job comment, `docs/ci.md`, the README CI note, and the PRD to match.
didericis added 3 commits 2026-07-25 22:05:31 -04:00
Adds an `integration-macos` job that runs the integration suite against
BOT_BOTTLE_BACKEND=macos-container on a self-hosted host-mode macOS runner
(label `macos`), plus the PRD and provisioning docs.

The job is advisory (push-to-main + workflow_dispatch only, never PRs, not
in coverage.needs) since it targets a single non-redundant laptop. It
preflights `container`/`backend status` so a misprovisioned runner fails
loudly, serializes on a concurrency group, and tears down the
`bot-bottle-mac-infra` singleton on exit (#425).

Also relaxes the TestSandboxEscape CI skip guard: it skipped every backend
but firecracker under GITEA_ACTIONS, which would also skip on a host-mode
macOS runner. The guard's real target is the containerized act_runner, so
it now allows both host-mode backends (firecracker, macos-container)
through — otherwise the macOS job would go green while skipping the one
end-to-end test that proves the backend launches.

Closes #426

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
git-gate is fully implemented on the macos-container backend via the
gateway's consolidated git-http daemon with dynamic key
provisioning/revocation; only the legacy per-bottle git:// daemon is
unused. Fixes a stale README claim that git-gate is "deferred" and
removes the PRD open-question built on that false premise (sandbox-escape
attack 5 runs the same on macOS as on the other backends).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
integration-macos: dispatch-only (drop push-to-main trigger)
test / integration-macos (pull_request) Has been skipped
tracker-policy-pr / check-pr (pull_request) Successful in 11s
test / integration-docker (pull_request) Successful in 34s
test / unit (pull_request) Successful in 44s
lint / lint (push) Successful in 1m2s
test / integration-firecracker (pull_request) Successful in 2m6s
test / coverage (pull_request) Successful in 17s
test / publish-infra (pull_request) Has been skipped
27dea58ae1
Make the advisory macOS Apple Container job run on workflow_dispatch
only, removing the push-to-`main` trigger so a single non-redundant
laptop never runs unattended on every push. Updates the job comment,
docs/ci.md, README CI note, and the PRD accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
didericis force-pushed prd-macos-container-ci-runner from 74632dbaeb to 27dea58ae1 2026-07-25 22:05:31 -04:00 Compare
didericis added 1 commit 2026-07-25 22:23:01 -04:00
ci(integration-macos): dump infra logs on failure before teardown
test / integration-macos (pull_request) Has been skipped
test / integration-docker (pull_request) Successful in 20s
tracker-policy-pr / check-pr (pull_request) Successful in 23s
test / unit (pull_request) Successful in 40s
test / integration-firecracker (pull_request) Successful in 2m8s
test / coverage (pull_request) Successful in 21s
test / publish-infra (pull_request) Has been skipped
605146d287
A control-plane failure (e.g. the orchestrator becoming unreachable at
bottle registration) is undiagnosable from CI as-is: the `if: always()`
teardown runs `MacosInfraService().stop()`, which deletes the
orchestrator and gateway containers — and their logs — on every run.

Add an `if: failure()` step that dumps `container ls`/`network ls`, plus
`inspect` and `logs` for `bot-bottle-mac-orchestrator` and
`bot-bottle-mac-infra`, ordered before the teardown so the evidence is
captured while the containers still exist. Best-effort (never fails the
job; tolerates an already-removed container).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
didericis-claude merged commit 38c13708c7 into main 2026-07-25 22:34:50 -04:00
Sign in to join this conversation.