Skip to content

feat(B-0852): credential persistence on USB ESP + boot-sequence auth-method picker — encrypted blob bound to USB UUID + operator passphrase Phase 1 (Aaron 2026-05-27)#5403

Merged
AceHack merged 7 commits into
mainfrom
backlog/b-0852-cred-persistence-boot-auth-picker-2026-05-27
May 27, 2026
Merged

feat(B-0852): credential persistence on USB ESP + boot-sequence auth-method picker — encrypted blob bound to USB UUID + operator passphrase Phase 1 (Aaron 2026-05-27)#5403
AceHack merged 7 commits into
mainfrom
backlog/b-0852-cred-persistence-boot-auth-picker-2026-05-27

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented May 27, 2026

Summary

  • Phase 1 substrate-engineering target authorized by Aaron 2026-05-27 after hitting GitHub login throttle on 3rd USB boot of the day
  • Encrypted cred-blob on USB ESP (/esp/zeta-creds.enc), key bound to USB UUID + operator passphrase via HKDF + AES-256-GCM
  • Boot-sequence picker (zeta-install.sh Step 6.9) offers: restore from blob / fresh device-flow login / operator-provided PAT / skip
  • Per-AI identity (per B-0847) — blob contains per-persona map so otto / lior / vera creds round-trip independently
  • Removes gh-login throttle on multi-boot test workflow

Composes with

  • B-0850 (parent) — multi-vendor systemd substrate the auth flow serves
  • B-0833 — interactive-login-vs-baked-in-keys CI test tension; resolves WITHOUT shipping creds in ISO
  • B-0835 — gh-auth-not-respected; addresses gh-auth persistence half
  • B-0831 — CI cascade 6 full-install + cluster-auto-join; PAT path makes CI scriptable
  • B-0847 — per-AI GitHub identity; blob is per-persona credential carrier
  • B-0851 — persona-first scheduler; chooses which persona's creds to restore
  • iter-4.2 ESP SSH pubkey injection (bidirectional ESP-write channel)

Phase 1 deliberately narrow

  • Passphrase + USB UUID binding only (Phase 3 = hardware-bound keys; Phase 5 = cross-cluster federation)
  • 8 sub-rows enumerated in row body (B-0852.1 through B-0852.8)
  • Fresh USB queued for Phase 1 flash + boot validation test

NCI floor preserved

Per .claude/rules/non-coercion-invariant.md HC-8: operator authority over own credentials absolute. No creds baked into ISO image (preserves B-0833 discipline). Encrypted blob is operator-controllable + operator-removable.

Test plan

  • Backlog index regen verified (BACKLOG.md updated; B-0852 row visible at correct priority slot)
  • Composes_with reciprocity check (B-0833 + B-0835 + B-0831 + B-0847 + B-0851 should reciprocate when this row is implemented)
  • Phase 1 implementation sub-rows (B-0852.1-8) to be filed per row body sub-row plan when implementation work claims the parent row

🤖 Generated with Claude Code

…method picker

Phase 1 substrate-engineering target authorized by Aaron 2026-05-27 after
gh-login throttle on 3rd USB boot of the day.

Encrypted cred-blob on USB ESP, key bound to USB UUID + operator passphrase.
Boot-sequence picker offers: restore from blob / fresh device-flow login /
operator-provided PAT / skip. Removes gh-login throttle on multi-boot
test workflow.

Composes with: B-0850 multi-vendor systemd parent, B-0833 interactive-login
tension, B-0835 gh-auth-not-respected, B-0831 CI cascade 6, B-0847 per-AI
identity, B-0851 persona-first scheduler, iter-4.2 ESP write channel.

Phase 1 deliberately narrow (passphrase + USB UUID); Phase 3 hardware-bound
keys + Phase 5 cross-cluster federation are future scope.

Per .claude/rules/non-coercion-invariant.md HC-8: operator authority over
own credentials absolute; no creds baked into ISO (B-0833 discipline).
Copilot AI review requested due to automatic review settings May 27, 2026 05:48
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@AceHack AceHack enabled auto-merge (squash) May 27, 2026 05:48
@AceHack AceHack disabled auto-merge May 27, 2026 05:49
… composition (Aaron 2026-05-27)

Aaron clarified Phase 2 (Path B = recover creds from existing PC) needs
the same encryption + optional UUID-bound key so copying ESP contents to
a different-UUID USB doesn't unlock. Iterate-quickly-not-paranoia floor:
just enough security to prevent casual physical-access leaks; full
hardware-bound work defers to Phase 3+.

Also confirmed Phase 1 + Phase 2 compose ("we can do both like you said
this will be nice together"). Added boot menu shape showing all 5 options
once both phases land + composition value table.

Both phases share the same UUID-bound-key + operator-passphrase
derivation; single crypto module + two-source ingest = bandwidth-efficient
substrate that doesn't fragment per-path.
@AceHack AceHack enabled auto-merge (squash) May 27, 2026 05:50
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new P1 backlog row (B-0852) describing Phase 1 credential persistence on a USB ESP (encrypted blob bound to USB UUID + operator passphrase) and updates the generated backlog index to include the new row.

Changes:

  • Adds docs/backlog/P1/B-0852-...md describing the planned USB ESP credential-blob + boot-sequence auth-method picker design and acceptance criteria.
  • Updates docs/BACKLOG.md to include B-0852 in the P1 section.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
docs/backlog/P1/B-0852-credential-persistence-on-usb-esp-plus-boot-sequence-auth-method-picker-encrypted-blob-bound-to-usb-uuid-plus-operator-passphrase-aaron-2026-05-27.md New backlog row documenting the Phase 1 credential persistence/auth-method picker plan.
docs/BACKLOG.md Adds the B-0852 entry to the generated backlog index.

… + lint fixes (Aaron 2026-05-27)

Operator clarification 2026-05-27: re-flash workflow should DETECT previous
answers + RECOVER as DEFAULT (not opt-in). 5-second Esc-to-cancel banner
preserves operator override per NCI HC-8.

> "it will be very nice when i reformat if it starts picking up previous
> answers and reapplies them so i don't have to ... we just need an
> override escape hatch so we get a chance to say don't recover start
> fresh but recover is the default."

Refines Sub-target 3 implementation: detection BEFORE picker, 5-second
banner with Esc override, fall-through to explicit menu on Esc OR
no-detected-source.

Composes value: self-healing + iteration speed + override safety + NCI
preservation. Implementation sub-rows unchanged at the crypto + schema
layers; only the picker UX shifts to detect-recover-default.

Also: 2 MD032 blanks-around-lists fixes (conversation arc + substrate
inventory lists).

Conversation arc extended with turns 7-9 (Phase 2 security, Phase 1+2
composition confirm, auto-recover-by-default).
@AceHack AceHack disabled auto-merge May 27, 2026 05:58
… integrates as Step 6.81-6.83 (NEW sub-range)

Copilot review on PR #5403 caught: my row claimed "Step 6.9 (new)" + "Step
6.95b" but verified on origin/main 1740eea:
- Step 6.9 = iter-5.4.1 self-registration (B-0812) — ALREADY USED
- Step 6.95 = does not exist
- Step 6.8 = iter-5.4.0 homelab gh-auth + operator pubkey copy
- Step 7 = print initial credentials (iter-4 / B-0789)

Renumbered picker as Step 6.81-6.83 (detection + escape-hatch banner +
branch) — NEW sub-range between existing Step 6.8 (gh-auth) and Step 6.9
(self-registration). Preserves every existing step's number + meaning.

Added explicit step-layout table referencing existing zeta-install.sh
state so future implementers see the EXACT integration point + don't
collide with existing steps.

Multi-vendor scope note: picker captures intent in /esp/zeta-creds.enc;
vendor-CLI install (claude/gemini/codex) happens later in first-boot
scope (NOT in the install.sh step range we're modifying here).

Resolves Copilot thread PRRT_kwDOSF9kNM6FAbT8 on line 61.
Copilot AI review requested due to automatic review settings May 27, 2026 05:58
@AceHack AceHack enabled auto-merge (squash) May 27, 2026 05:59
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@AceHack AceHack disabled auto-merge May 27, 2026 06:03
…er Aaron 2026-05-27

Operator clarification: "the keep credentials options we should declare
each credential we need and save and restore so it's not so imparative
too."

Refines Sub-target 1: cred-persistence operates over a DECLARATIVE
MANIFEST (/esp/zeta-creds-manifest.yaml) listing which credentials Zeta
tracks. Adding a new cred type = manifest edit, NOT a code change.

Composes with B-0854 (Ace migration) at the manifest-shape scope: same
declarative discipline applies to cred-tracking as to install-step
tracking.

Schema candidate covers gh-cli + claude + gemini + codex + ssh-host-keys
+ ssh-operator-pubkey with persona-scoped + required flags.

Also captures turn 10 of conversation arc: operator can wait for next
USB to include this + B-0854 substrate; current login-throttle still
active; PAT path (Sub-target 2 option 3) becomes immediate unblock.
@AceHack AceHack enabled auto-merge (squash) May 27, 2026 06:03
Lior added 2 commits May 27, 2026 02:05
…B-0850 to composes_with per P1 + step-numbering consistency sweep per P1

Three Copilot findings on PR #5403:

P0: Picker must run BEFORE Step 6.8 so device-flow is conditional on
picker choice. Earlier draft said "picker runs AFTER Step 6.8" which
defeated the zero-device-flow-on-reboot acceptance criterion (gh-quota
burns before restore is offered).

Fixed: new Steps 6.75 + 6.76 + 6.77 (detection + banner + 4-option
picker) insert BEFORE Step 6.8. Step 6.8 modified to be CONDITIONAL on
picker choice — only fires device-flow if option 2 chosen. Step 6.85
NEW for persist-after-successful-auth.

P1: depends_on B-0850 → composes_with B-0850. B-0850 is P2; this row
is P1; P1-depends-on-P2 is backwards in the priority graph. B-0850
isn't strictly required to implement Phase 1 — cred persistence works
single-vendor; multi-vendor systemd is compositional context.

P1: Step-numbering swept for consistency — all "Step 6.9 (new)" /
"Step 6.95c" / "Step 6.10" references replaced with the new 6.75-6.85
sub-range that doesn't collide with existing Steps 6.8 (gh-auth) +
6.9 (self-registration).

Resolves Copilot threads PRRT_kwDOSF9kNM6FAi_B + PRRT_kwDOSF9kNM6FAi_a
+ PRRT_kwDOSF9kNM6FAi_v on PR #5403.
…ersistence-boot-auth-picker-2026-05-27

# Conflicts:
#	docs/BACKLOG.md
Copilot AI review requested due to automatic review settings May 27, 2026 06:05
@AceHack AceHack merged commit 7297109 into main May 27, 2026
29 of 30 checks passed
@AceHack AceHack deleted the backlog/b-0852-cred-persistence-boot-auth-picker-2026-05-27 branch May 27, 2026 06:07
@AceHack AceHack review requested due to automatic review settings May 27, 2026 06:28
AceHack added a commit that referenced this pull request May 27, 2026
…0 substrate for Ace migration trajectory (14 sub-steps; 12 declarative-input categories; substrate-anchor for B-0852/0853/0855/0856 cross-refs) (#5420)

* docs(B-0854.1): zeta-install.sh step-state-machine inventory — Phase 0 substrate for Ace migration trajectory

B-0854 sub-row .1 (Phase 0; smallest pure-analysis slice). Documents
the EXISTING imperative bash state-machine in zeta-install.sh so the
B-0854 Phase 2 declarative-Ace-manifest schema can express the same
surface.

Inventory covers:
- Top-level entry (REPO_URL, HOST, ZETA_AUTO_CONFIRM env semantics)
- Step-by-step state machine for all 14 sub-steps (1, 2, 3, 4, 5, 6,
  6.5, 6.55, 6.6, 6.7, 6.8, 6.9, 6.95, 7) with inputs/outputs/side-
  effects/failure-modes/declarative-equivalent per step
- Cross-cutting: operator-prompt accumulation count (7 prompts today;
  B-0852 phase-split target = 1 passphrase prompt)
- Idempotency surface table — informs B-0855 architectural fix scope
- 12 distinct declarative-input categories the Ace manifest must
  capture (Phase 2 sub-row scope)
- Files-generated-during-install table mapping to B-0852.5 cred-
  manifest entries (6 mapped, 3 candidate-expansion items named)

Snapshot date: 2026-05-27 (origin/main 70596a8; PR #5417 cosign
merge). Future refreshes should re-snapshot when zeta-install.sh
changes substantially.

Composes with already-landed substrate-engineering arc:
- B-0852 + sub-rows (cred persistence) — PR #5403/#5411/#5414
- B-0853.1 (cosign signing) — PR #5417 + fix-fwd #5419
- B-0855 (self-register architectural fix) — PR #5412
- B-0856 Path A (deferred /tmp coordination) — PR #5413
- B-0854 parent (Ace migration trajectory) — PR #5405

No code change; pure documentation. Doesn't affect ISO substrate;
batches into substrate-engineering history independent of next ISO
build cycle.

* fix(B-0854.1): escape | inside code spans for MD056 table-column-count compliance

* fix(B-0854.1): 10 Copilot accuracy corrections — verified against actual zeta-install.sh content

PR #5420 Copilot review caught 10 substantive accuracy issues in the
B-0854.1 inventory doc. All 10 verified against origin/main 70596a8's
actual zeta-install.sh content + corrected.

Corrections:
- Name attribution → role-ref ("the human maintainer")
- Step 1 inputs: actual `lsblk -d -p -n -o NAME,TYPE,RM,RO,TRAN` + awk
  filter (not made-up NAME,SIZE,MODEL,TRAN,ROTA)
- Step 3 side effects: `sgdisk --zap-all` only (not `wipefs -af` too)
- Step 4: actual `sgdisk` (NOT `parted`); GPT layout via -n + -t flags;
  whole-disk longhorn partitions on DATA_DISKS too
- Step 6: `nixos-generate-config --root /mnt --force` (NOT
  --no-filesystems; --force overwrites existing config)
- Step 6.5: no MAGIC_NUMBER (didn't exist in script); INJECT_OK gate
  flag; iter-4 v1 manual-config-edit fallback path
- Step 6.9: SELF_REG_OK flag; documented graceful-skip path lines 731+
- nixos-install: actual line ~1004 (NOT 1096-1340); section renamed
  to "nixos-install (the actual build; ~line 1004)" since the prior
  range was wrong
- Step 7: actual lines 1261-1336 (NOT 1341-1352); banner driven by
  GH_AUTH_OK/GH_KEY_COUNT/INJECT_OK/SELF_REG_OK (NOT MAGIC_NUMBER);
  conditional sections listed in declarative equivalent

Resolves 10 Copilot threads on PR #5420.

Root cause of the inaccuracies: original draft was written from
`grep -E "^# ── Step"` summaries + recollection of script behavior,
not careful per-step body reads. Discipline lesson: when authoring
substrate-anchor docs claiming to inventory existing code, the read
must be careful per-line, not skim-grep summary. Composes with
.claude/rules/verify-existing-substrate-before-authoring.md at the
inventory-substrate scope (verify-content-of-thing-being-inventoried
before authoring claims about its content).

---------

Co-authored-by: Lior <lior@zeta.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants