f4192be5d1
---ci--- project: orca phase: 2 milestone: v0.8 status: verify requirements: covered: [REQ-058, REQ-059] partial: [] ---/ci---
4.2 KiB
4.2 KiB
Phase 2 Verification — v0.8 Coverage & Trust Hardening
Phase: P02 — SSH trust hardening Milestone: v0.8 REQs: REQ-058, REQ-059 (+ latent TOFU bugfix closure) Date: 2026-08-04 Result: ✅ PASS (all 4 layers)
Layer 1 — Structural ✅
go build ./...PASSgo vet ./...PASS- No TODOs/stubs in new production code
- All new exports resolve:
security.SSHFingerprintSHA256,security.WriteAtomic,proxmox.TOFUHostKeyCallback,proxmox.ResetHostKey,proxmox.pinnedHostKeyCallback,proxmox.Options.HostKeyFingerprint,cli.nodeKeyResetCmd - Backward compatible: existing
BootstrapProxmoxcallers work (the TOFU fix changed failure→success on first connect, which is the bugfix)
Layer 2 — Behavioral ✅
go test ./internal/proxmox/... ./internal/cli/... ./internal/doctor/... ./internal/security/...PASSgo test -race ./internal/proxmox/... ./internal/doctor/...PASS- Coverage held post-P02: proxmox 86.5% (was 87.1% in P01 — marginal change from new code paths), cli 76.7% (was 76.2%), doctor 70.4% (unchanged)
- T02.10: all 7 end-to-end integration cases PASS (pinned correct/wrong, TOFU first/second/mismatch, key-reset+re-pin, pre-populated migration path)
- T02.11:
--host-key-fingerprintnon-proxmox validation PASS
Layer 3 — Security ✅
- REQ-058:
--host-key-fingerprintfails closed on mismatch (pinnedHostKeyCallback returns error on any mismatch; bootstrap aborts before any SSH session command runs). SHA256: prefix validated up front. No downgrade to TOFU when pin supplied. - REQ-059:
orca node key-resetis local-only (D-046) — only rewrites~/.orca/known_hostsviasecurity.WriteAtomic(atomic temp+rename, AD-029); does NOT touch remote authorized_keys. Audit-logsnode.key_resetwith actor+node+host. - TOFU bugfix (T02.6, v0.6 ship-defect): first-connect now captures + writes the key (was silently failing). Mismatch detection preserved (MITM protection). The
TOFUHostKeyCallbackis shared between bootstrap (T02.6) and doctor (T02.9) — GRILL condition #2 parity satisfied. - STRIDE: no new spoofing surface (pin is operator-supplied, fail-closed); no tampering (atomic rewrite); no repudiation (audit log); no info disclosure (fingerprint is a hash, not the key); no DoS (no network change); no elevation (local file ops only).
- No secrets in test code (fake SSH keys generated in-test).
Layer 4 — Quality ✅
- Tests follow existing conventions (table-driven,
fakeSSHServerfixture reused,sshDialer/sessionRunnerseams injected) TOFUHostKeyCallbackextracted to a shared helper (no duplication between bootstrap + doctor) — clean coupling (proxmox doesn't import doctor)- P0 issues: none. P1+ issues: none flagged.
Requirement Coverage
| REQ | Status | Evidence |
|---|---|---|
| REQ-058 | ✅ Complete | --host-key-fingerprint flag (T02.3) + pinnedHostKeyCallback (T02.5) + Result.HostKeyFingerprint (T02.7) + e2e tests (T02.10) + validation (T02.11) |
| REQ-059 | ✅ Complete | orca node key-reset <node> (T02.8) + proxmox.ResetHostKey atomic rewrite + audit log + e2e test (T02.10 case 6) |
| (TOFU bugfix) | ✅ Complete | T02.6 fixes v0.6 ship-defect (first-connect knownhosts.New KeyError{Want:[]} treated as dial failure); T02.9 doctor parity |
GRILL Conditions Check
- #1 (T02.6 labeled v0.6 ship-defect): ✅ commit
8b0cbe1summary "TOFU capture bug — v0.6 ship-defect first-connect join always failed" - #2 (T02.9 doctor parity): ✅ both bootstrap (
8b0cbe1) and doctor (2dcb143) use the sharedproxmox.TOFUHostKeyCallbackwrapper
Lessons
- The v0.6 TOFU bug was a latent ship-defect:
knownhosts.NewreturnsKeyError{Want:[]}on first connect without writing, and the original code treated this as a dial failure. This means first-connect Proxmox join has been broken since v0.6 shipped — a strong argument for P01's coverage uplift (the 5.1% proxmox coverage hid this). v0.8 P03'sverify-reqswould not have caught this (it's code-vs-doc drift, not doc-vs-doc) — P04 audit is the backstop. - Extracting
TOFUHostKeyCallbackto a shared helper was the right call for GRILL condition #2 — duplicating the wrapper in doctor would have created drift risk.