Castle Wall macOS boot-survival drill, 2026-06-14/15

Purpose. This document is the in-repo trace target for the F1 boot-service capability (PR #450). Sanctuary’s standard for capability claims is drill evidence on the platform that matters, not a release tag. This drill is the first clean demonstration that an armed Castle Wall survives a reboot without bricking the box: the safe-mode boot daemon comes up before login on the boot token alone, the machine stays reachable while the filter is armed, and the persisted policy keeps enforcing. It is the companion to the 2026-06-11 allow/deny drill (castle-wall-macos-allow-deny-drill-2026-06-11.md); this run re-confirmed the per-uid allow/deny enforcement demo on the boot-service candidate as well.

The earlier boot-service work was held because, as first shipped, the boot daemon could not even start (it crash-looped and the installer wrongly reported success), and two further gaps had to close before a clean reboot drill was meaningful. Those must-fixes landed and were codex-gated before this drill (see “Mid-drill bug caught and fixed” and the must-fix summary below).

Claim proven

On macOS Tahoe 26.5.1, with the Castle Wall system extension armed and a persisted signed manifest in force:

The drilled candidate was signed build v774 (CFBundleVersion 774), git_sha 8c8efe68, extension binary SHA-256 5fae8f4b..., on Mini1 (Agents-Mac-mini), Erik present at the console, 2026-06-15.

The honest upper bound on this claim is “enforces a signed operator policy with a clean per-uid allow/deny demo and reboot-survival.” It is not “audited per-rule per-flow” (see “What this does not prove, the C4 gap”).

Platform and builds

Item Value
Host Mini1 (Agents-Mac-mini), macOS Tahoe 26.5.1
System extension ai.sanctuaryprotocol.macos.castle-wall, CFBundleVersion 774, activated and enabled
Extension binary SHA-256 5fae8f4b... (verified changed from prior candidates 9f89cfff (v771) and badef967 (v773); the stale-extension trap was closed each rebuild)
Host app / CLI commit git_sha 8c8efe68 (the drilled source; see “Rebase nuance” for how this relates to main)
Fortress / pin drill fortress .sanctuary-drill-0611b, global pin c3f22755; real ~/.sanctuary never touched
Roles MBA subthread orchestrated over SSH; Erik present at the Mini1 console for the signed build, deploy, and reboots

A1, F1 boot-survival, 5/5 reboot reps

Criteria were pre-declared. Each rep was a real reboot of the armed machine; the table records the safe-mode daemon coming up before login and the box staying reachable.

Rep SSH down then up Safe-mode daemon PID (before login) Reachable, not bricked Armed (ext SHA)
1 ~79s up yes 5fae8f4b
2 ~141s up yes 5fae8f4b
3 ~57s up yes 5fae8f4b
4 ~61s up yes 5fae8f4b
5 ~72s up yes 5fae8f4b

Per-criterion verdict (one line each):

A2, per-uid allow/deny enforcement demo, N=3

In an armed window enforcing the drill manifest, egress was probed as the agent and as the operator. The same destination is blocked for the agent but reachable for the operator, proving the enforcement is uid-scoped agent classification, not a blanket block.

Probe Result Reps
agent (uid 502) to allowlisted host (allow-anthropic) connected (HTTP 404, reachable) 3/3
agent (uid 502) to non-allowlisted IP 1.1.1.1 (deny-exfil) blocked (curl exit 7) 3/3
operator (uid 501) to the same 1.1.1.1 reachable (HTTP 301) 1/1
operator SSH during the armed window alive throughout full session

What this does not prove, the C4 gap

Rebase nuance, drilled source versus the merged tree

The behavior proven above was captured on the drilled source at git_sha 8c8efe68 (branch drill/f1-lean-2026-06-14). That source was rebased onto main and merged as PR #450 (7732f4d5). The rebase was verified behavior-preserving: it passed the codex review and the frozen-surface guard, and the two core boot files (server/src/castle-wall/boot/boot-token.ts and server/src/castle-wall/runtime/macos-daemon.ts) are byte-identical (SHA-256 match) between the drilled commit 8c8efe68 and the merged commit 7732f4d5.

What this drill does not establish: a fresh signed build produced from main’s exact tree was not independently reboot-drilled. The reboot evidence is from the v774 binary built at 8c8efe68. The byte-identity of the core boot files plus the clean codex and frozen-surface checks are the basis for treating the merged tree as behavior-equivalent; that is an inference from the rebase verification, not a second on-hardware drill of main’s exact binary.

Mid-drill bug caught and fixed

A real F1 daemon-start bug was caught on the A1 second rep of an earlier candidate (v773): a stale active-config entry plus PID reuse made the safe-mode daemon refuse to start after a reboot (the box was not bricked, the extension fail-safe held). It was fixed mid-drill in 8c8efe68: an active-config collision now requires a live listener, not a bare PID. The fix was codex-clean and was validated live and across all five v774 reboots above.

Must-fixes that preceded this drill

The boot-service work was held until five must-fixes closed, each code plus regression test, codex-gated (a refute-by-default codex pass caught two HIGH plus one MED that the build and diff-read both missed, all fixed before the signed rebuild):

  1. Boot-daemon PATH plus stable-PID false-PASS (the original crash-loop and false install success).
  2. Boot-daemon PATH durability (also prepend the stable Homebrew symlink bin dir so a brew upgrade node does not re-brick).
  3. Safe-mode daemon socket re-owned to the operator (the programmatic dead-man lever), with a non-following lstat + isSocket() + lchown guard against the symlink-redirect escalation.
  4. The full-daemon “supersede safe mode” behavior, which existed only in doc comments, honestly de-scoped (a root KeepAlive boot daemon cannot be stood down by the unprivileged operator daemon), with the docs corrected and an actionable stand-down handoff message added.
  5. An install-boot composition guard so arming the filter refuses unless a verified boot service plist is installed (closing the path where arming with no boot daemon re-bricks the next reboot).

Non-blocking residuals, tracked in issue #567

Two residuals were ruled non-blocking and are tracked in issue #567 (Castle Wall safe-mode hardening):

These do not block the not-bricked or the allow/deny results, and the GUI VPN and Filters toggle remains the ultimate dead-man lever throughout.

End state, box restored safe

The filter was disarmed (functionally verified), the global pin c3f22755 was intact, the real ~/.sanctuary was never touched, the boot service was left installed (harmless with the filter off), and the scratch state was cleared.

Evidence retention

Raw captures (pre-state hashes, per-rep reboot transcripts, armed-window probe transcripts, daemon and extension logs) are retained in the maintainer’s drill-evidence archive under the 2026-06-14 Mini1 drill reference, alongside the full drill report. This document summarizes that evidence for in-repo traceability; the numbers above are transcribed from the captured transcripts and summaries.