From 06e2507ce4bb7499239aa8667601c6c47c37e78a Mon Sep 17 00:00:00 2001 From: Robert Allan James Date: Wed, 16 Sep 2026 03:41:10 -0400 Subject: [PATCH] =?UTF-8?q?Stage=20E=20ratified:=20unattended=20identity?= =?UTF-8?q?=20is=20cert+personality=20only,=20no=20seed=20(FABRIC-3.md=20?= =?UTF-8?q?=C2=A7XXXII.2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settles all 4 open questions on paper, no code: - No seed baked into capsules for this pass (Bob's call); runtime-minted seed documented as a future, separately-scoped possibility - Birth via capsule_birth_baby() (unmodified, already generic), not capsule_runcap_birth() -- that path requires a real blkio_dev*+ homeblocks_sig_t* an unattended identity can't provide, and its own header says build-time-baked content is exactly the wrong case for it - Identity population is the same post-birth struct-assignment pattern capsule_wirebind.c already uses live (vm->identity = identity) - §XXIV's block-collision machinery already covers a cert-carrying capsule -- no new risk, no change needed there - ACL gate lives on the attaching human's credentials, since an unattended instance holds no secret to prove anything about itself - xHCI/live-table machinery confirmed irrelevant, independent of the seed question One real wrinkle flagged, not resolved: vm_identity_from_cert()'s serial-number check binds to a physical drive_uuid an unattended identity doesn't have -- needs Bob's call before implementation. Punch list recorded; implementation not started per standing "plan approval is not a start signal" rule. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K --- FABRIC-3.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/FABRIC-3.md b/FABRIC-3.md index a7efd7e1..c8dd3b44 100644 --- a/FABRIC-3.md +++ b/FABRIC-3.md @@ -4297,6 +4297,81 @@ whatever code implements unattended birth. unattended identity's own lifecycle (no `blkio_dev`, no device to attach/detach) before assuming the two paths share no state. +**Ratified, 2026-09-16 -- all four questions settled on paper, no code written.** Traced, +not assumed: `vm_identity.h`'s own header comment says outright "no seed/private material +belongs here at all" (line 29), and `user_identity_seed.h:25` states the running system's own +verify path checks "these two alone" -- cert + pubkey, never the seed. Confirmed live: +`capsule_wirebind_verify_cert()` only ever reads and verifies (§XXVIII's BINDSTEP re-check is +the same function, same direction); nothing in the attach/verify path signs as the identity +being checked. **Decision (Captain Bob, 2026-09-16): unattended identities carry cert + +personality only, never a seed, for this pass.** A future runtime-minted-seed path (an +instance that signs as itself) is a documented possibility, explicitly out of scope here -- +if it's ever built, it must mint at runtime into a non-persisted/fenced location, never bake a +seed into a git-committed capsule. + +This collapses all four questions: + +1. **Packaging -- a new capsule content convention, not a new `mkcapsule` mode or MINT + variant.** No seed means no secret-handling in the build tool at all: the DER cert + (produced offline by the existing `MINT`/`capsule_mint_identity()` path, Zuse-signed, same + as today) becomes part of a normal `(p)` PRODUCTION capsule's own payload, following the + same `Block NNNN` convention every capsule already uses for its personality source. + §XXIV's collision machinery (`check_block_conflicts()`, `mkcapsule --resolve`, + `capsule-reserved.txt`) already covers this -- it's blind to *content*, only to block + numbers, so a cert-carrying capsule is just another capsule to it. No new collision risk, + no change needed to §XXIV's machinery. +2. **Birth -- `capsule_birth_baby()`, unmodified, not `capsule_runcap_birth()`.** + `capsule_runcap_birth()` was the wrong tool: its own header says a user's identity source + "never exists at build time" (`capsule_runcap.h:19-20`) -- exactly backwards for a + build-time-baked unattended capsule, and it hard-requires a real `blkio_dev*` + + `homeblocks_sig_t*` it would have no way to obtain. `capsule_birth_baby()` is already the + generic, capsule-directory-sourced birth path every `(p)` capsule uses (confirmed at 4 + existing call sites across `mama_forth_words.c`/`capsule_console.c`); an unattended + identity is just another named capsule going through it, `skip_pki_sig = 0` like any normal + build-time capsule. Identity population is a proven, already-live pattern, not new + invention: `capsule_wirebind.c:272-274` does exactly this today -- + `((VM *)user_ctx)->identity = identity;`, a plain post-birth struct assignment once + `vm_identity_from_cert()` has verified the cert. The unattended path calls + `vm_identity_from_cert()` on the capsule's own embedded DER cert immediately after + `capsule_birth_baby()` returns, then assigns the result the same way. + **One real wrinkle, not silently resolved:** `vm_identity_from_cert()`'s serial-number + check binds the cert to a physical `drive_uuid` (`homeblocks_sig_t`, 16 bytes) -- a + capsule-embedded identity has no physical drive and thus no `drive_uuid` to bind against. + Either the cert-issuing step needs a different binding value for this identity origin (e.g. + the capsule's own content hash, already the system's universal identity primitive) or + `vm_identity_from_cert()` needs a origin-aware variant. **Not designed here -- flagged for + the punch list, needs Bob's call on what an unattended identity's cert should bind to + before implementation.** +3. **ACL-gated console attachment -- checks the attaching human's own credentials, not the + instance's.** Falls directly out of the no-seed decision: an unattended instance can never + prove anything about itself at attach time (it holds no secret to challenge), so the gate + necessarily lives on the human side -- almost certainly a capability bit + (`VMIdentity.acl_caps`, still unassigned per this header's own "real bits get names only + once the operation gets built" precedent) checked on the attaching human's own verified + identity before the console-birth + `VM-NAME-REG` pairing (§XXXII.2 above) is allowed to + run. Concrete bit value: punch-list item, not decided here. +4. **§VII's xHCI/live-table machinery -- confirmed irrelevant, independently of the seed + question.** An unattended identity is born from a capsule directory entry, never from a + `blkio_dev*`; it has no physical device to attach/detach and never enters the xHCI + per-device registry at all. This holds regardless of how Q1/Q2 were answered, so it was + never actually contingent on the seed decision above. + +**Punch list for implementation (not started, needs explicit authorization per this project's +standing "plan approval is not a start signal" rule):** +- Decide what an unattended identity's cert binds to instead of `drive_uuid` (item 2's + wrinkle) -- Bob's call. +- Define the new capsule content convention for an embedded cert (which block(s), what + format) and add build-time production of it (offline `MINT`-equivalent step, not new + runtime code). +- Add the unattended-birth call site: `capsule_birth_baby()` + `vm_identity_from_cert()` + + post-birth `identity` assignment, gated by the explicit invariant already stated above + (never touch `g_wirebind_attached_username`/console-pairing). +- Assign a real `acl_caps` bit for "may attach a console to an unattended instance" and wire + the check into the console-birth + `VM-NAME-REG` path. +- Acceptance: 3-arch clean boot with at least one unattended instance born at boot, no console + attached, verified un-promptable (§VIII.1 gate holds), then a human console attached to it + after the fact via the existing `VM-NAME-REG` pairing mechanism. + ### XXXII.3 -- Primitive error-handling audit: kernel-only scope, real surface counted **Scope, decided explicitly:** this audit covers kernel-side primitives only --