PRD: macOS Container backend #229

Merged
didericis merged 8 commits from feat/macos-container-backend into main 2026-06-10 22:33:58 -04:00
Collaborator

Summary

  • add the macos-container backend and make it the default on compatible macOS hosts
  • implement Apple container CLI wrappers for build/inspect/exec/cp, cleanup, and active enumeration
  • implement the launch path with a host-only agent network plus a dual-homed sidecar bundle on internal + egress networks
  • stamp agent HTTP(S)_PROXY and CA env vars from the discovered sidecar internal IP
  • add Apple Container builder DNS handling so BuildKit RUN steps resolve package mirrors without requiring Docker
  • add guarded real-runtime integration coverage for launch, proxy egress, direct-egress failure, and non-allowlisted proxy blocking
  • explicitly defer bottle.git / git-gate support on this backend until a safe Apple Container key-delivery path exists

Tests

  • python3 -m compileall -q bot_bottle tests/unit/test_backend_selection.py tests/unit/test_macos_container_launch.py
  • python3 -m unittest discover tests/unit
  • python3 -m unittest tests.integration.test_macos_container_launch
  • npx pyright .
  • git diff --check

The stacked Part II and Part III PRs have been merged into this branch, so this PR now represents the complete macOS Container backend MVP rather than only the initial scaffold slice.

## Summary - add the `macos-container` backend and make it the default on compatible macOS hosts - implement Apple `container` CLI wrappers for build/inspect/exec/cp, cleanup, and active enumeration - implement the launch path with a host-only agent network plus a dual-homed sidecar bundle on internal + egress networks - stamp agent HTTP(S)_PROXY and CA env vars from the discovered sidecar internal IP - add Apple Container builder DNS handling so BuildKit `RUN` steps resolve package mirrors without requiring Docker - add guarded real-runtime integration coverage for launch, proxy egress, direct-egress failure, and non-allowlisted proxy blocking - explicitly defer `bottle.git` / git-gate support on this backend until a safe Apple Container key-delivery path exists ## Tests - `python3 -m compileall -q bot_bottle tests/unit/test_backend_selection.py tests/unit/test_macos_container_launch.py` - `python3 -m unittest discover tests/unit` - `python3 -m unittest tests.integration.test_macos_container_launch` - `npx pyright .` - `git diff --check` The stacked Part II and Part III PRs have been merged into this branch, so this PR now represents the complete macOS Container backend MVP rather than only the initial scaffold slice.
didericis changed title from feat: add macOS Container backend scaffold to PRD: add macOS Container backend scaffold 2026-06-10 15:04:07 -04:00
didericis changed title from PRD: add macOS Container backend scaffold to PRD: macOS Container backend scaffold 2026-06-10 15:04:18 -04:00
didericis changed title from PRD: macOS Container backend scaffold to PRD: macOS Container backend - Part I 2026-06-10 15:08:28 -04:00
Author
Collaborator

Remaining parts I see after this PRD/scaffold slice:

  1. Apple Container networking spike

    • Verify real CLI behavior on the target macOS version for container network create --internal, repeated --network on container run, network aliases/labels, and whether one sidecar container can sit on both an internal agent network and an egress-capable network.
    • Verify published loopback ports from one Apple Container guest are reachable from another guest only through the intended per-bottle host alias.
    • Verify JSON output shapes for container list, container inspect, container image inspect, and container network inspect so cleanup/enumeration do not depend on brittle quiet-name parsing where better metadata exists.
  2. Runnable launch path

    • Build the agent image and sidecar bundle with container build.
    • Start the sidecar bundle as one managed container/VM using the existing BOT_BOTTLE_SIDECAR_DAEMONS contract, mounted route/cert/key files, and published ports where needed.
    • Start the agent container with no direct egress route around the sidecar. This is the hard gate: do not enable launch until the networking spike proves the enforcement shape.
    • Stamp HTTPS_PROXY, HTTP_PROXY, NO_PROXY, GIT_GATE_URL, and MCP_SUPERVISE_URL using the discovered sidecar endpoints, equivalent to the smolmachines flow.
  3. Provisioning parity

    • Exercise container cp recursion and ownership semantics against the provider provisioning steps, workspace copy, skills copy, prompt copy, CA installation, git identity setup, and supervise MCP registration.
    • Decide whether root/user handling should stay as container exec --user or needs backend-specific repair after copy-in.
  4. Lifecycle and cleanup hardening

    • Add labels to all Apple Container resources once confirmed supported, then enumerate by label instead of prefix where possible.
    • Dump sidecar/agent logs on teardown, matching the Docker compose log behavior.
    • Remove stale containers, networks, and state dirs without touching Docker or smolmachines resources.
  5. Integration coverage

    • Add macOS + container guarded integration tests for build, launch, exec, cp, sidecar port reachability, and cleanup.
    • Add a negative egress test that proves the agent cannot bypass the sidecar path.
  6. Follow-on Docker removal work

    • Once the macos-container launch path is trustworthy, decide whether it can replace the smolmachines sidecar Docker dependency or whether smolmachines should continue toward the bootstrap-smolmachine/buildah/zot direction from issue #220.
Remaining parts I see after this PRD/scaffold slice: 1. **Apple Container networking spike** - Verify real CLI behavior on the target macOS version for `container network create --internal`, repeated `--network` on `container run`, network aliases/labels, and whether one sidecar container can sit on both an internal agent network and an egress-capable network. - Verify published loopback ports from one Apple Container guest are reachable from another guest only through the intended per-bottle host alias. - Verify JSON output shapes for `container list`, `container inspect`, `container image inspect`, and `container network inspect` so cleanup/enumeration do not depend on brittle quiet-name parsing where better metadata exists. 2. **Runnable launch path** - Build the agent image and sidecar bundle with `container build`. - Start the sidecar bundle as one managed container/VM using the existing `BOT_BOTTLE_SIDECAR_DAEMONS` contract, mounted route/cert/key files, and published ports where needed. - Start the agent container with no direct egress route around the sidecar. This is the hard gate: do not enable launch until the networking spike proves the enforcement shape. - Stamp `HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY`, `GIT_GATE_URL`, and `MCP_SUPERVISE_URL` using the discovered sidecar endpoints, equivalent to the smolmachines flow. 3. **Provisioning parity** - Exercise `container cp` recursion and ownership semantics against the provider provisioning steps, workspace copy, skills copy, prompt copy, CA installation, git identity setup, and supervise MCP registration. - Decide whether root/user handling should stay as `container exec --user` or needs backend-specific repair after copy-in. 4. **Lifecycle and cleanup hardening** - Add labels to all Apple Container resources once confirmed supported, then enumerate by label instead of prefix where possible. - Dump sidecar/agent logs on teardown, matching the Docker compose log behavior. - Remove stale containers, networks, and state dirs without touching Docker or smolmachines resources. 5. **Integration coverage** - Add macOS + `container` guarded integration tests for build, launch, exec, cp, sidecar port reachability, and cleanup. - Add a negative egress test that proves the agent cannot bypass the sidecar path. 6. **Follow-on Docker removal work** - Once the macos-container launch path is trustworthy, decide whether it can replace the smolmachines sidecar Docker dependency or whether smolmachines should continue toward the bootstrap-smolmachine/buildah/zot direction from issue #220.
didericis reviewed 2026-06-10 21:23:10 -04:00
@@ -0,0 +25,4 @@
class MacosContainerBottleBackend(
BottleBackend["MacosContainerBottlePlan", "MacosContainerBottleCleanupPlan"]
):
"""Experimental Apple Container backend. Selected by
Owner

No longer experimental as of part III completion. We'll merge these together than merge the whole feature in. Remove this, and make macos-container the default backend when on a compatible macos system.

No longer experimental as of part III completion. We'll merge these together than merge the whole feature in. Remove this, and make macos-container the default backend when on a compatible macos system.
didericis marked this conversation as resolved
didericis reviewed 2026-06-10 21:26:12 -04:00
@@ -0,0 +2,4 @@
The backend is registered and its host primitives are implemented, but
full launch is intentionally blocked until the sidecar network
enforcement design is finished. Apple Container can publish ports and
Owner

No longer blocked/will want to update this as well.

No longer blocked/will want to update this as well.
didericis marked this conversation as resolved
didericis changed title from PRD: macOS Container backend - Part I to PRD: macOS Container backend 2026-06-10 21:32:29 -04:00
Author
Collaborator

Addressed the remaining review threads in 5498f20 and updated the PR description now that Part II and Part III are merged into this branch.

  • Re: #229 (comment) — removed the Experimental wording and made macos-container the default when the host is compatible. Explicit --backend and BOT_BOTTLE_BACKEND still win; otherwise default resolution is macos-container when available, then smolmachines.
  • Re: #229 (comment) — the launch module docstring already reflects the implemented two-network explicit-proxy topology from Part II, not the old blocked-launch scaffold state.
  • Re: #231 (comment) / #231 (comment) — renamed _SIDECAR_SLEEP_SECONDS to _AGENT_SLEEP_SECONDS; it is the long sleep used to keep the detached agent container exec-able.
  • Re: #229 (comment) — the PR body now reflects that the networking spike, runnable launch path, provisioning coverage, lifecycle cleanup, and integration coverage landed through Parts II/III. bottle.git / git-gate remains explicitly deferred for macos-container until a safe key delivery path exists.

Verification run after the changes:

  • python3 -m unittest discover tests/unit
  • python3 -m unittest tests.integration.test_macos_container_launch
  • npx pyright .
  • python3 -m compileall -q bot_bottle tests/unit/test_backend_selection.py tests/unit/test_macos_container_launch.py
  • git diff --check
Addressed the remaining review threads in `5498f20` and updated the PR description now that Part II and Part III are merged into this branch. - Re: https://gitea.dideric.is/didericis/bot-bottle/pulls/229#issuecomment-2007 — removed the `Experimental` wording and made `macos-container` the default when the host is compatible. Explicit `--backend` and `BOT_BOTTLE_BACKEND` still win; otherwise default resolution is `macos-container` when available, then `smolmachines`. - Re: https://gitea.dideric.is/didericis/bot-bottle/pulls/229#issuecomment-2009 — the launch module docstring already reflects the implemented two-network explicit-proxy topology from Part II, not the old blocked-launch scaffold state. - Re: https://gitea.dideric.is/didericis/bot-bottle/pulls/231#issuecomment-2011 / https://gitea.dideric.is/didericis/bot-bottle/pulls/231#issuecomment-2020 — renamed `_SIDECAR_SLEEP_SECONDS` to `_AGENT_SLEEP_SECONDS`; it is the long sleep used to keep the detached agent container exec-able. - Re: https://gitea.dideric.is/didericis/bot-bottle/pulls/229#issuecomment-1986 — the PR body now reflects that the networking spike, runnable launch path, provisioning coverage, lifecycle cleanup, and integration coverage landed through Parts II/III. `bottle.git` / git-gate remains explicitly deferred for macos-container until a safe key delivery path exists. Verification run after the changes: - `python3 -m unittest discover tests/unit` - `python3 -m unittest tests.integration.test_macos_container_launch` - `npx pyright .` - `python3 -m compileall -q bot_bottle tests/unit/test_backend_selection.py tests/unit/test_macos_container_launch.py` - `git diff --check`
didericis added 8 commits 2026-06-10 22:25:13 -04:00
fix(macos-container): support git-gate launch
test / unit (pull_request) Successful in 32s
test / integration (pull_request) Successful in 20s
lint / lint (push) Successful in 1m45s
prd-number / assign-numbers (push) Successful in 25s
test / unit (push) Successful in 32s
test / integration (push) Successful in 19s
Update Quality Badges / update-badges (push) Failing after 1m23s
bc9a22b46a
didericis force-pushed feat/macos-container-backend from 0e823d2aff to bc9a22b46a 2026-06-10 22:25:13 -04:00 Compare
didericis merged commit bc9a22b46a into main 2026-06-10 22:33:58 -04:00
didericis deleted branch feat/macos-container-backend 2026-06-10 22:33:58 -04:00
Sign in to join this conversation.