Add apple-container sandbox runtime contract and fail-closed validation - #56122
Add apple-container sandbox runtime contract and fail-closed validation#56122lpcox wants to merge 1 commit into
Conversation
Introduce `sandbox.agent.runtime: apple-container` as a recognised runtime profile for AWF's Apple Virtualization.framework workload preview (gh-aw-firewall#7764). This is the contract/validation layer only: it defines the declarative surface, emits the AWF config selectors, and fails closed on everything the compiler can know statically. Generated runtime setup, image provisioning, and MCP transport rewiring are deliberately left out. Runtime model and profile: - Add `AgentRuntimeAppleContainer` and its profile: network isolation on, rootless AWF invocation, no host access, no compiler-generated runtime installation. Docker is still required — AWF keeps Squid, the API proxy, the CLI proxy, and the MCP gateway in Docker Compose on the host, and only the agent workload moves to Apple Container. - Add the value to the frontmatter schema, regenerate autocomplete data and the generated frontmatter reference, and update the internal agent-runtime instructions so tools do not emit an invalid configuration. AWF config generation: - Emit BOTH required selectors as a unit: `container.containerRuntime: "apple-container"` and `appleContainer.previewEnabled: true`. Neither is ever emitted without the other. - Suppress `network.topologyAttach`, which AWF rejects for this runtime because externally owned peers are not published to macOS loopback and cannot be bridged into the NIC-less guest. - Suppress `--tty`, matching the docker-sbx and cloud-hypervisor handling. - Mirror the AWF source schema in the embedded `awf-config.schema.json`: the `apple-container` enum value, the `appleContainer` section (previewEnabled, cpus, memory, initImage, cliPath with AWF's exact types, defaults, and patterns), and the `container.images.appleInit` role. Version gating: - Add `AWFAppleContainerMinVersion` (v0.28.9) and `awfSupportsAppleContainer`. The constant is deliberately above `DefaultFirewallVersion` because gh-aw-firewall#7764 is not in any published release yet (v0.28.8 still has no `apple-container` enum value and no `appleContainer` section), so the runtime fails closed until a workflow explicitly pins a supporting AWF version. Runner validation: - Accept only an explicitly self-hosted bare-metal Apple Silicon label set: `runs-on: [self-hosted, macOS, ARM64]` (extra pool labels allowed). - Reject every GitHub-hosted `macos-*` label, including the `-xlarge` Apple Silicon images, because those runners are virtual machines without nested virtualization. - Reject runner groups without labels, GitHub Actions expressions, contradicting OS/arch labels, and an omitted runner, rather than guessing. Every rejection names the exact accepted syntax. - Keep the blanket macOS rejection for every other runner field (`runs-on-slim`, safe-output job runners) and for every other runtime. The exemption applies only to the agent job's own `runs-on` when this workflow's frontmatter selects apple-container, and `validateSandboxConfig` re-validates the merged runner so imports cannot bypass the host requirement. Feature compatibility: - Reject arc-dind topology, enclaves, `sandbox.agent.mounts`, `filesystem.allowWrite`, `ssl_bump`, Vertex AI credential isolation, and the raw AWF arguments AWF refuses under this runtime (`--legacy-security`, `--enable-host-access`, `--allow-host-ports`, `--dns-over-https`, `--topology-attach`, `--dind`, `--docker-host-path-prefix`, `--build-local`, `--agent-image`, `--sysroot-image`, `--chroot-binaries-source-path`, `--volume`, `--tty`, `--ssl-bump`, `--google-api-key`, and `--no-network-isolation`). - `allow-host-ports`, GitHub Actions `services:` port mappings, and `runtime-install` are already rejected by the shared profile rules. - Require the `appleInit` image role whenever a `sandbox.agent.images` manifest is present, add it to the image-tag digest contract, and exclude it from Docker predownload because Apple Container uses a separate image store. All existing runtimes and Linux-only behaviour are unchanged; `make recompile` produces no lock file drift. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Hey @lpcox 👋 — thanks for shipping layer 1 of the Apple Container stack! This looks great: ✅ Focused scope — contract and validation only, with clear deferred items (setup, provisioning, transport rewiring) for layer 2. The PR is ready for review and looks well-aligned with the project's standards for safety and correctness.
|
Apple Container stack — layer 1 (contract & validation)
This is layer 1 of the gh-aw Apple Container stack. It adds the compiler/runtime contract and fail-closed validation for AWF's Apple Virtualization.framework workload preview. It does not yet generate runnable Apple Container setup.
Depends functionally on github/gh-aw-firewall#7764 (stacked on #7760 and #7762), which is not merged or released yet. Nothing in this PR can produce a working run until that lands and ships.
Runtime model
sandbox.agent.runtime: apple-containeris now a recognised runtime profile:NetworkIsolationtrue--network-isolation; the guest has no NICLegacySecurityfalseRootlesstruecontainerCLI is unprivilegedSupportsRuntimeInstallfalseSupportsHostAccessfalseDocker is not removed: AWF keeps Squid, the API proxy, the CLI proxy, and the MCP gateway in Docker Compose on the host. Only the agent workload moves to Apple Container.
AWF config generation
container.containerRuntime: "apple-container"andappleContainer.previewEnabled: true. Neither is ever emitted without the other.network.topologyAttach. AWF fails closed on any non-empty value here for this runtime (config.topologyAttach && config.topologyAttach.length > 0), because externally owned peers are not published to macOS loopback.--tty, matching docker-sbx and cloud-hypervisor.awf-config.schema.jsonmirrors the AWF source schema: theapple-containerenum value, theappleContainersection (previewEnabled,cpusint ≥1 default 4,memorystring^[1-9][0-9]*[KMGTP]?$default8G,initImagedigest-pinned,cliPath), and thecontainer.images.appleInitrole.Sizing/init-image/CLI-path are intentionally not exposed as gh-aw frontmatter yet — the compiler emits only the two selectors and lets AWF apply its documented defaults. Adding user-facing knobs before there is a runnable path would be speculative surface area.
Version gating
New
AWFAppleContainerMinVersion = v0.28.9, deliberately aboveDefaultFirewallVersion(v0.28.7).The latest published AWF release (v0.28.8) still ships a
containerRuntimeenum of["gvisor", "sbx", "cloud-hypervisor"]and has noappleContainersection, so v0.28.9 is the earliest release that can contain #7764. The runtime therefore fails closed by default: a workflow must explicitly pinsandbox.agent.version(orfirewall.version). Bump the constant if #7764 lands later; never lower it.Runner acceptance
Accepted syntax, exactly:
Extra pool labels are allowed (e.g.
[self-hosted, macOS, ARM64, apple-container]). Matching is case-insensitive and order-independent.Rejected, each with an actionable error naming the accepted syntax:
macos-*label, including-xlargeApple Silicon images — those runners are VMs without nested virtualization (kern.hv_support != 1)x64,x86,x86_64,amd64) — Rosetta is refusedlinux,windows)ubuntu-latest)The blanket macOS rejection stays fully intact for
runs-on-slim, safe-output job runners, and every other runtime. The exemption applies only to the agent job's ownruns-onwhen this workflow's own frontmatter selects apple-container, andvalidateSandboxConfigindependently re-validates the merged runner, so imports cannot bypass the host requirement.Feature compatibility
Rejected at compile time: arc-dind topology, enclaves,
sandbox.agent.mounts,filesystem.allowWrite,ssl_bump, Vertex AI credential isolation, plus the raw AWF arguments AWF refuses (--legacy-security,--enable-host-access,--allow-host-ports,--dns-over-https,--topology-attach,--dind,--docker-host-path-prefix,--build-local,--agent-image,--sysroot-image,--chroot-binaries-source-path,--volume,--tty,--ssl-bump,--google-api-key,--no-network-isolation).allow-host-ports,services:port mappings, andruntime-installare already rejected by the shared profile rules.The AWF CLI proxy (
--difc-proxy-host/tools.github.mode: gh-proxy) is supported under apple-container — it is in AWF's capability-socket allowlist — so unlike cloud-hypervisor it is deliberately not rejected.Images
appleInitis added to the closedcontainer.imagesrole set and required whenever the runtime is selected. It is added to the image-tag digest contract alongsideagent, and excluded from Docker predownload: Apple Container maintains a separate image store thatdocker pullcannot populate.Explicitly deferred to layer 2
Apple Container CLI/runtime install steps, runtime-aware image pulling into the Apple image store, MCP gateway transport rewiring onto capability sockets, public documentation, the live smoke workflow, and any broad golden-fixture regeneration.
Validation
go test ./pkg/workflow ./pkg/parser ./pkg/constants— pass (86 new subtests)make lint— cleanmake recompile— 294/294 workflows, no lock file drift[self-hosted, macOS, ARM64], framework jobs still onubuntu-slim, both selectors present,topologyAttachabsentmacos-26,macos-15-xlarge, runner group only, omittedruns-on, and default AWF version all fail closedPre-existing unrelated failures on this machine (
/privatesymlink and chi-square tests inpkg/cli/pkg/fileutil) reproduce on the base commit.