Commit Graph
11 Commits
Author SHA1 Message Date
abkslm 65623f1c34 Merge nucleic/hazy-opal-yak-cjc0 into dev 2026-07-17 23:48:59 -07:00
abkslm 608e7d0450 Merge nucleic/upbeat-slate-lemur-7euo into dev 2026-07-17 22:21:12 -07:00
abkslm 1fc4c32097 Merge nucleic/quiet-opal-gecko-ah7w into dev 2026-07-17 16:03:36 -07:00
abkslm 3168f3d8b6 Merge nucleic/tidy-north-gecko-6wqv into dev 2026-07-17 15:35:17 -07:00
abkslmandClaude Opus 4.8 9de6a6cee7 docs: add CONTAINER_ISOLATION.md — session-isolation model + build/validate workflow
Overview doc so other agents/humans understand the shared-control-container
isolation work: the failure vectors + fixes (stdio wedge, connection leak,
control-plane HOL, OOM cross-kill, CPU/fork-bomb, per-session memory.max), the
host-vs-guest shipping surfaces, the per-exec cgroup layout + graceful fallback,
and the local vminit-image build/validate workflow + -nucleicN tag invariant.
Cross-linked from the vendored PATCHES.md.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 22:03:03 -07:00
abkslmandClaude Opus 4.8 831d19c3a6 Per-exec cgroups follow-up: host-configured hard memory.max (no protobuf)
Adds an opt-in hard per-session memory ceiling on top of patch #9's scoped-OOM.
The exec already ships the full OCI Spec, so the limit rides
spec.linux.resources.memory.limit — no RPC/protobuf change:

- host framework: LinuxProcessConfiguration.memoryLimitInBytes; LinuxContainer.exec
  stamps it onto the exec spec.
- guest: Server+GRPC.createProcess reads it back and applies it as the exec
  cgroup's memory.max (new Cgroup2Manager.setMemoryMax) via createExec/ManagedProcess.
- Nucleic: ContainerServiceSettings.controlPerSessionMemoryGiB (default 0 = off),
  applied only to the shared control container (ContainerManager.exec); wired
  through ContainerEngine.exec.

So one session can't consume the whole shared container's memory before its own
(oom.group-scoped) OOM. Default off preserves #9's behavior. Compile-verified host
+ musl guest; rides the pending -nucleic2 image, still runtime-pending.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 20:12:42 -07:00
abkslmandClaude Opus 4.8 2eb563c90c Per-exec cgroups (guest patch #9): scope a session's OOM/CPU/fork-bomb to itself
Restructures the guest cgroup layout so each exec gets its OWN child cgroup
(/container/<id>/<execID>) with memory.oom.group=1, a fair cpu.weight, and a
pids.max backstop — so one control session can't OOM-kill, starve, or fork-bomb
its siblings in the shared container. The container init moves to its own leaf
so the container cgroup can delegate controllers to children (cgroup v2
no-internal-process rule). New Cgroup2Manager helpers: setOomGroup/setCpuWeight/
setPidsMax/remove.

Best-effort with graceful fallback: any failure in the per-exec setup wipes the
partial state and reverts to today's flat layout, and each exec falls back to the
container cgroup — a cgroup hiccup degrades to current behavior, never a failed
start.

COMPILE-VERIFIED via the musl cross-build; NOT yet runtime-validated. Built as
image tag -nucleic2; vminitReference stays on the validated -nucleic1 until
-nucleic2 is checked in a real container. A hard host-configured per-exec
memory.max (exec-RPC resources field) remains a follow-up.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 20:03:20 -07:00
abkslmandClaude Opus 4.8 0f9957d5e5 vminit image: add 'make vminit-image-login' for Keychain-based GHCR auth
cctl login stores the credential in the macOS Keychain, which cctl images push
reads automatically — so pushing needs no REGISTRY_* env vars after a one-time
login. Env vars remain as a fallback.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 19:37:06 -07:00
abkslmandClaude Opus 4.8 4d5a0cb42b Build the custom vminit image locally via make vminit-image; drop the CI workflow
The GitHub-hosted macos runners can't build the host framework (needs the
macOS 26+ Virtualization SDK), so publish the custom vminit guest image from a
local macOS 26/27 machine instead. Adds root-Makefile targets:
  - vminit-image-prep : one-time swiftly + musl static SDK install
  - vminit-image      : build cctl + cross-build vminitd, package the image
  - vminit-image-push : push to GHCR (REGISTRY_* env creds)
Forces WARNINGS_AS_ERRORS=false (Xcode Swift 6.4 rejects -warnings-as-errors
alongside SwiftPM's -suppress-warnings). Removes .github/workflows/vminit-image.yml
and repoints vminitReference + PATCHES.md docs at the Makefile.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 19:31:56 -07:00
abkslmandClaude Opus 4.8 4793a4b5bc containerization: guard patch #3's 'import os' behind #if canImport(os)
The swiftly toolchain used by the vminit-image CI resolves Foundation/
Virtualization but not the 'os' overlay, so 'import os' failed with
"no such module 'os'". Guarding the diagnostic logger degrades it to a
no-op under such toolchains while local (Xcode) builds keep it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 19:15:11 -07:00
abkslmandClaude Opus 4.8 7972dfb02d Container isolation: fix stdio stall + per-exec connection leak; add guest image pipeline
Host-side (ships with a normal swift build):
- LinuxProcess: non-blocking stdio relay (O_NONBLOCK + nucleicDrainNonBlocking)
  so a wedged stream can't head-of-line-block sibling execs' relays; atomic
  stdio-or-abort start (patches #5, #6).
- Vminitd: bounded deleteProcess timeout so teardown can't hang a wedged
  channel (patch #7).
- ContainerizedProcessHandle: call LinuxProcess.delete() after exit and on
  force-close — fixes a per-turn leak (per-exec vsock/gRPC connection +
  runConnections() task) in the long-lived shared control container. Likely
  the "degrades until app restart" root cause.
- ClaudeCodeBackend: map the atomic-start abort to a recoverable AgentError so
  a failed launch settles as retryable instead of locking the composer.

Guest-side (rides the custom vminitd initfs; inert until the image is built):
- ManagedProcess: offload the blocking start off the gRPC event loop (patch #8).
- Per-exec cgroups (patch #9) recorded as design only — cross-cutting.

Pipeline:
- .github/workflows/vminit-image.yml builds vminitd from the vendored source
  and pushes ghcr.io/abkslm/vminit; ContainerEngine.vminitReference repointed
  at the custom image.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-13 18:46:48 -07:00