Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b19c9ab68 |
@@ -0,0 +1,60 @@
|
|||||||
|
# Phase 4 Audit — v0.8 Coverage & Trust Hardening (Final Phase)
|
||||||
|
|
||||||
|
**Milestone**: v0.8 — Coverage & Trust Hardening
|
||||||
|
**Date**: 2026-08-04
|
||||||
|
**Branch**: `phase/04-final-review-ship`
|
||||||
|
**Result**: ✅ PASS (with P1 branch-hygiene finding — pre-existing, non-blocking for v0.8)
|
||||||
|
|
||||||
|
## Step 1 — Reconstruction Test ✅
|
||||||
|
|
||||||
|
- Latest `---ci---` block (HEAD of milestone/v0.8): `project: orca, phase: 3, milestone: v0.8, status: verify, requirements: covered: [REQ-060]` — matches CHECKPOINT.json (`phase: 2, stage: verify` — note: checkpoint is one phase behind because the P03 verify commit didn't update it to phase 3; the git log `---ci---` block is authoritative and correct).
|
||||||
|
- config.json `milestone: v0.8` — matches.
|
||||||
|
- `make verify-reqs` → `✓ 60 requirements consistent with roadmap` — ROADMAP ↔ REQUIREMENTS consistent.
|
||||||
|
- All 35 v0.8 commits have `---ci---` blocks (100% commit discipline).
|
||||||
|
|
||||||
|
## Step 2 — .ciagent/ File Discipline ✅
|
||||||
|
|
||||||
|
- `config.json`: valid JSON, `milestone: v0.8`, `phase: 0` (stale — should be 3 post-P03; minor, will be corrected at milestone-complete), `milestone_type: nfr`, `active_projects: ["orca"]` — all required fields present.
|
||||||
|
- `PROJECT.md`: has v0.8 scope summary + D-043..D-047 + the vision/constraints/decisions sections — complete.
|
||||||
|
- `ROADMAP.md`: v0.8 milestone section present with 4 phases (P0-P4), phases P0-P3 marked `[x]` (shipped tags v0.7.0..v0.7.3), P4 pending — matches git branches + tags. v0.8 milestone header NOT yet marked COMPLETE (milestone ship step will add this).
|
||||||
|
- `REQUIREMENTS.md`: REQ-057..060 present, status `Pending` (milestone ship step will mark `Complete`). All 56 prior REQs (REQ-001..056) `Complete`. Traceability matrix complete.
|
||||||
|
- `ARCHITECTURE.md`: not updated for v0.8 (no new components — verify-reqs is a `cmd/` program, not an architecture component; the trust-surface changes refine existing proxmox/doctor/cli packages). Acceptable — v0.8 is NFR, no architecture changes.
|
||||||
|
- `PERSONAS.md`: v0.8 roster at top (lead/backend/data active; frontend/security/cli-engineer deactivated with reasons), v0.7 baseline preserved — complete.
|
||||||
|
- `RESEARCH_v0.8.md`, `PLAN_v0.8.md`, `GRILL_v0.8.md`, `REVIEW_v0.8.md`, `PHASE1..3_VERIFICATION_v0.8.md` — all present.
|
||||||
|
|
||||||
|
## Step 3 — Branch Hygiene ⚠️ P1 (pre-existing, non-blocking)
|
||||||
|
|
||||||
|
**Stale merged local branches** (should have been deleted by prior ship workflows — v0.6 + v0.7 milestones):
|
||||||
|
- `milestone/v0.6-node-bootstrap-proxmox` (merged to main via v0.6 ship)
|
||||||
|
- `milestone/v0.7-hardening-completion` (merged to main via v0.7 ship)
|
||||||
|
- `phase/01-cert-register`, `phase/02-config-parser`, `phase/03-coverage-uplift`, `phase/04-pprof-daemon`, `phase/05-final-review-ship` (all v0.7 phase branches, merged to v0.7 milestone)
|
||||||
|
|
||||||
|
**Stale remote branches** (same set + older v0.6-era branches): `origin/milestone/v0.6-*`, `origin/milestone/v0.7-*`, `origin/phase/01-init-bootstrap`, `origin/phase/02-proxmox-join`, `origin/phase/03-doctor-extensions`, `origin/phase/04-final-review-ship`, etc.
|
||||||
|
|
||||||
|
**v0.8 branches** (`phase/01-coverage-round2`, `phase/02-ssh-trust-hardening`, `phase/03-requirements-hygiene-gate`, `phase/04-final-review-ship`, `milestone/v0.8-coverage-trust-hardening`) are all active or just-merged — NOT stale.
|
||||||
|
|
||||||
|
**Finding**: The ship workflow's branch-cleanup step (audit.md:46-49 "Step 6.5") is not running for prior milestones. This is a P1 process gap (recurring across v0.6 + v0.7) but does NOT block v0.8 ship. **Recommendation**: after v0.8 milestone ship, delete the stale v0.6/v0.7 local + remote branches (tags preserve the history). Defer to post-ship cleanup; do NOT block the milestone release.
|
||||||
|
|
||||||
|
## Step 4 — Commit Discipline ✅
|
||||||
|
|
||||||
|
- All 35 v0.8 commits have `---ci---` blocks (100%).
|
||||||
|
- No stale decisions: D-043..D-047 are all reflected in code (T02.3 flag per D-044, T02.5 callback per D-045, T02.8 local-only per D-046, T01.6 tiered floor per D-047, T02.6 bugfix per D-043 chore classification).
|
||||||
|
- No unresolved escalations (the only escalation was P0's `release_pending` from GITEA_TOKEN unset — auto-resolved, local-only fallback, pipeline not halted).
|
||||||
|
- All 4 GRILL binding conditions satisfied (verified in REVIEW_v0.8.md).
|
||||||
|
|
||||||
|
## Step 5 — Run Audit Checks ✅
|
||||||
|
|
||||||
|
- `go build ./...` PASS
|
||||||
|
- `go vet ./...` PASS
|
||||||
|
- `go test ./...` PASS (16 packages)
|
||||||
|
- `make verify-reqs` PASS (60 consistent)
|
||||||
|
- `make build` PASS
|
||||||
|
- `gofmt -l .` clean
|
||||||
|
|
||||||
|
## Overall Verdict
|
||||||
|
|
||||||
|
✅ **PASS** — v0.8 is shippable. The P1 branch-hygiene finding (stale v0.6/v0.7 branches) is pre-existing, non-blocking, and recommended for post-ship cleanup. The checkpoint phase-staleness (config.json `phase: 0` vs actual phase 3) is a minor bookkeeping gap corrected at milestone-complete.
|
||||||
|
|
||||||
|
## Recommendation
|
||||||
|
|
||||||
|
Proceed to milestone ship: mark REQ-057..060 `Complete` in REQUIREMENTS.md, mark v0.8 `COMPLETE` in ROADMAP.md, update config.json `phase: 4`, merge `phase/04-final-review-ship` → `milestone/v0.8` → `main`, tag `v0.7.4` (= milestone release), push, then delete stale v0.6/v0.7 branches as post-ship cleanup.
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"phase": 3,
|
"phase": 4,
|
||||||
"stage": "verify",
|
"stage": "complete",
|
||||||
"milestone": "v0.8",
|
"milestone": "v0.8",
|
||||||
"milestone_slug": "coverage-trust-hardening",
|
"milestone_slug": "coverage-trust-hardening",
|
||||||
"phase_role": "execution",
|
"phase_role": "final",
|
||||||
"attempts": 0,
|
"attempts": 0,
|
||||||
"updated_at": "2026-08-04T01:20:00Z",
|
"updated_at": "2026-08-04T01:30:00Z",
|
||||||
"milestone_complete": false,
|
"milestone_complete": true,
|
||||||
"next_milestone": null
|
"next_milestone": null
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ REQ-047..052 all complete.
|
|||||||
|
|
||||||
| ID | Requirement | Priority | Phase | Status |
|
| ID | Requirement | Priority | Phase | Status |
|
||||||
|----|-------------|----------|-------|--------|
|
|----|-------------|----------|-------|--------|
|
||||||
| REQ-057 | Test coverage uplift round 2: raise `internal/engine` (8.3%), `internal/proxmox` (5.1%), `internal/cli` (27.6%), `internal/transport` (26.3%), `internal/store` (46.7%), `internal/jobspec` (47.6%) to ≥ 70%; add first tests for `internal/audit`, `internal/certpaths`, `cmd/orca` (currently 0%) to ≥ 50% (D-047 tiered floor) | High | **v0.8 P1** | Pending |
|
| REQ-057 | Test coverage uplift round 2: raise `internal/engine` (8.3%), `internal/proxmox` (5.1%), `internal/cli` (27.6%), `internal/transport` (26.3%), `internal/store` (46.7%), `internal/jobspec` (47.6%) to ≥ 70%; add first tests for `internal/audit`, `internal/certpaths`, `cmd/orca` (currently 0%) to ≥ 50% (D-047 tiered floor) | High | **v0.8 P1** | **Complete** (P1 shipped v0.7.1; all 9 packages exceeded floor) |
|
||||||
| REQ-058 | `--host-key-fingerprint <SHA256:base64>` pre-pin flag on `orca node join` (validated when `--type proxmox`): when supplied, join fails fast if the SSH host key's OpenSSH SHA-256 fingerprint does not match; supersedes TOFU (D-035) for pre-pinned deployments (D-044, D-045) | Medium | **v0.8 P2** | Pending |
|
| REQ-058 | `--host-key-fingerprint <SHA256:base64>` pre-pin flag on `orca node join` (validated when `--type proxmox`): when supplied, join fails fast if the SSH host key's OpenSSH SHA-256 fingerprint does not match; supersedes TOFU (D-035) for pre-pinned deployments (D-044, D-045) | Medium | **v0.8 P2** | **Complete** (P2 shipped v0.7.2) |
|
||||||
| REQ-059 | `orca node key-reset <node>` command: clears the persisted SSH host key entry for the node from `~/.orca/known_hosts` only (local, not remote authorized_keys — D-046); audit-logs `event=node.key_reset`; next `doctor proxmox`/dispatch re-pins via TOFU or `--host-key-fingerprint` | Low | **v0.8 P2** | Pending |
|
| REQ-059 | `orca node key-reset <node>` command: clears the persisted SSH host key entry for the node from `~/.orca/known_hosts` only (local, not remote authorized_keys — D-046); audit-logs `event=node.key_reset`; next `doctor proxmox`/dispatch re-pins via TOFU or `--host-key-fingerprint` | Low | **v0.8 P2** | **Complete** (P2 shipped v0.7.2) |
|
||||||
| REQ-060 | Requirement-status hygiene sweep: REQUIREMENTS.md v0.7 rows were stale ("Pending" after ship); add a verify-stage assertion that every REQ listed as `Complete` in ROADMAP.md has a matching `Complete` row in REQUIREMENTS.md, enforced by `make verify-reqs` | Medium | **v0.8 P3** | Pending |
|
| REQ-060 | Requirement-status hygiene sweep: REQUIREMENTS.md v0.7 rows were stale ("Pending" after ship); add a verify-stage assertion that every REQ listed as `Complete` in ROADMAP.md has a matching `Complete` row in REQUIREMENTS.md, enforced by `make verify-reqs` | Medium | **v0.8 P3** | **Complete** (P3 shipped v0.7.3) |
|
||||||
|
|||||||
@@ -0,0 +1,321 @@
|
|||||||
|
# Review: Orca v0.8 — Coverage & Trust Hardening (final-phase)
|
||||||
|
|
||||||
|
**Reviewer**: ci-code-reviewer (multi-persona: correctness, testing, security, performance, maintainability, adversarial)
|
||||||
|
**Branch**: `phase/04-final-review-ship` (review HEAD = P03 ship `70c5718`)
|
||||||
|
**Diff scope**: `main...milestone/v0.8-coverage-trust-hardening` (all v0.8 work, 59 files, +6550/-173)
|
||||||
|
**Date**: 2026-08-04
|
||||||
|
**Verdict**: **PASS-WITH-FOLLOWUPS** (0 P0, 2 P1, 2 P2)
|
||||||
|
|
||||||
|
## Methodology
|
||||||
|
|
||||||
|
Read the full diff (`internal/`, `cmd/`, `Makefile`, `.coreci.yml`), all 3 phase
|
||||||
|
verification reports, PLAN/RESEARCH/GRILL/PERSONAS, and the critical production
|
||||||
|
files directly (`internal/proxmox/bootstrap.go`, `internal/security/ca.go`,
|
||||||
|
`internal/security/sshkey.go`, `internal/doctor/doctor.go:400-454`,
|
||||||
|
`cmd/verify-reqs/main.go`). Re-ran `go build ./...`, `go vet ./...`,
|
||||||
|
`go test -race` on proxmox/security/doctor/cli/verify-reqs/cmd-orca, and
|
||||||
|
`make verify-reqs` (all PASS). Re-verified the verify-reqs regex against the
|
||||||
|
real ROADMAP.md (matches v0.1..v0.7 COMPLETE incl. v0.2 parenthetical; v0.8
|
||||||
|
correctly not matched). Confirmed all 7 T02.10 e2e cases are present and
|
||||||
|
exercised through a real in-process SSH server.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Per-Axis Findings
|
||||||
|
|
||||||
|
### 1. Correctness (lead-developer)
|
||||||
|
|
||||||
|
**C1 — `sessionRunner` seam backward-compat** ✅
|
||||||
|
`internal/proxmox/bootstrap.go:170-172,322-339`. The seam is a package-level
|
||||||
|
`var sessionRunner sessionRunnerType` (line 326) initialized lazily inside
|
||||||
|
`BootstrapProxmox` from the dialed `*ssh.Client` (`if sessionRunner == nil {
|
||||||
|
sessionRunner = &sshSessionRunner{client: conn} }`). Existing callers are
|
||||||
|
unchanged — the default `sshSessionRunner` wraps the real
|
||||||
|
`conn.NewSession().CombinedOutput(...)`. Tests reset `sessionRunner = nil`
|
||||||
|
between runs (bootstrap_test.go:910, 1010, 1035) to avoid cross-test leakage.
|
||||||
|
Backward compatible as required by P01 verification. No issue.
|
||||||
|
|
||||||
|
**C2 — `verify-reqs` parser correctness** ✅
|
||||||
|
`cmd/verify-reqs/main.go:18-26`. The `reqRowRe` uses a greedy `.*` for the
|
||||||
|
Requirement+Priority cells and anchors the Phase+Status match at the END of
|
||||||
|
the line, where those two columns always live. This correctly handles
|
||||||
|
escaped pipes inside the Requirement cell (e.g. REQ-049
|
||||||
|
`localhost\|linux\|proxmox` — verified by the passing `make verify-reqs`
|
||||||
|
which reports 60 consistent rows, matching the 60 REQ rows in
|
||||||
|
REQUIREMENTS.md). The status token is optionally bold-wrapped
|
||||||
|
(`\*{0,2}(Complete|Pending)\*{0,2}`) with `[^|]*` for trailing notes —
|
||||||
|
handles `**Complete** (P01 shipped v0.2.1)`. The milestone-complete regex
|
||||||
|
`^##\s*Milestone\s+(v0\.\d+):.*—\s*\*\*[^*]*\bCOMPLETE\b[^*]*\*\*` is
|
||||||
|
substring-tolerant (GRILL #4) — verified against the real ROADMAP: matches
|
||||||
|
v0.1..v0.7 incl. v0.2's `**COMPLETE (merged to main via v0.3)**` and v0.6's
|
||||||
|
duplicate header (line 94 matched; line 92 without COMPLETE ignored). v0.8
|
||||||
|
(line 136, not yet COMPLETE) correctly not matched — so the v0.8 REQ rows
|
||||||
|
being `Pending` is NOT flagged as drift (correct: milestone not shipped
|
||||||
|
yet). No issue.
|
||||||
|
|
||||||
|
**C3 — TOFU capture-fix logic** ✅
|
||||||
|
`internal/proxmox/bootstrap.go:275-310`. On `*knownhosts.KeyError` with
|
||||||
|
empty `Want` (host unknown), captures the key, reads existing known_hosts
|
||||||
|
(create-if-missing), ensures trailing newline, appends
|
||||||
|
`knownhosts.Line([]string{knownhosts.Normalize(addr)}, key)`, writes via
|
||||||
|
`security.WriteAtomic`, returns nil (dial proceeds). On non-empty `Want`
|
||||||
|
(mismatch) returns the error (MITM detection preserved). On `nil` (match)
|
||||||
|
records key + returns nil. Correct against x/crypto v0.54.0 `checkAddr`
|
||||||
|
semantics. No issue.
|
||||||
|
|
||||||
|
**C4 — `ResetHostKey` line matching** ✅
|
||||||
|
`internal/proxmox/bootstrap.go:479-523`. Matches a line when its first
|
||||||
|
whitespace-delimited field, normalized via `knownhosts.Normalize`, equals
|
||||||
|
the normalized target. Handles `[host]:22` vs bare `host` (Normalize
|
||||||
|
brackets ports). Preserves comments/blanks. Atomic rewrite via
|
||||||
|
`security.WriteAtomic`. Edge cases handled: empty host errors, missing
|
||||||
|
file is a no-op, no matching lines is a no-op. Test
|
||||||
|
`TestResetHostKey_RemovesTargetLines` (bootstrap_test.go:718) seeds 2 lines
|
||||||
|
for target + 1 for another host, asserts target's 2 removed + other
|
||||||
|
intact. No issue.
|
||||||
|
|
||||||
|
**C5 — `--host-key-fingerprint` non-proxmox validation** ✅
|
||||||
|
`internal/cli/node.go:79-81`. `RunE` checks `joinHostKeyFP != "" &&
|
||||||
|
joinType != "proxmox"` → clear error. Test
|
||||||
|
`TestNodeJoinHostKeyFingerprintRequiresProxmox` (node_test.go:445) asserts
|
||||||
|
the error; `TestNodeJoinHostKeyFingerprintProxmoxAccepted` (node_test.go:477)
|
||||||
|
asserts the negative-space (proxmox type accepts the flag). No issue.
|
||||||
|
|
||||||
|
### 2. Testing (all personas)
|
||||||
|
|
||||||
|
**T1 — Coverage held post-P02** ✅
|
||||||
|
PHASE2 verification: proxmox 86.5% (was 87.1%), cli 76.7% (was 76.2%),
|
||||||
|
doctor 70.4%. Marginal changes from new code paths — no coverage regression.
|
||||||
|
Re-ran `go test -race ./internal/proxmox/... ./internal/cli/...` PASS.
|
||||||
|
|
||||||
|
**T2 — Race tests pass** ✅
|
||||||
|
`go test -race -count=1 ./internal/proxmox/... ./internal/security/...
|
||||||
|
./internal/doctor/... ./cmd/verify-reqs/... ./cmd/orca/...` all PASS.
|
||||||
|
`./internal/cli/...` PASS (77s, dominated by watch tests). No races.
|
||||||
|
|
||||||
|
**T3 — 7 T02.10 integration cases** ✅
|
||||||
|
All 7 present in `internal/proxmox/bootstrap_test.go`, exercised
|
||||||
|
end-to-end through `BootstrapProxmox` with a real in-process SSH server
|
||||||
|
(`bootstrapE2ESetup`):
|
||||||
|
- Case 1: `TestBootstrapE2E_PinnedFingerprintCorrect` (815)
|
||||||
|
- Case 2: `TestBootstrapE2E_PinnedFingerprintWrong` (842)
|
||||||
|
- Case 3: `TestBootstrapE2E_TOFUFirstConnectCapturesKey` (865)
|
||||||
|
- Case 4: `TestBootstrapE2E_TOFUSecondConnectMatches` (905)
|
||||||
|
- Case 5: `TestBootstrapE2E_TOFUMismatchFails` (925)
|
||||||
|
- Case 6: `TestBootstrapE2E_KeyResetThenRePin` (1002)
|
||||||
|
- Case 7: `TestBootstrapE2E_PrePopulatedKnownHostsMatches` (966, v0.6→v0.8 migration)
|
||||||
|
|
||||||
|
**T4 — Golden tests for verify-reqs** ✅
|
||||||
|
`cmd/verify-reqs/main_test.go` has 7 tests covering: clean pair, multi-drift
|
||||||
|
(both directions), default-args subprocess, malformed (no REQ rows → error),
|
||||||
|
missing file → error, v0.2 substring-tolerant header regression guard
|
||||||
|
(`TestVerify_v02SubstringTolerantHeader`), and real-repo regression guard.
|
||||||
|
The substring-tolerant regex is explicitly exercised — the drift fixture's
|
||||||
|
ROADMAP uses `**COMPLETE (merged to main via v0.3)**` on v0.2 and the test
|
||||||
|
asserts REQ-002 (v0.2 P1, Pending) is flagged forward-drift (would be
|
||||||
|
silently skipped if the regex regressed). No issue.
|
||||||
|
|
||||||
|
**T5 — Doctor parity test** ✅
|
||||||
|
`internal/doctor/doctor_test.go` extended with 94 LOC covering
|
||||||
|
`probeProxmoxPVEVersion` paths. The doctor callback now uses the shared
|
||||||
|
`proxmox.TOFUHostKeyCallback` (doctor.go:424) — GRILL #2 parity verified by
|
||||||
|
reading both call sites. No issue.
|
||||||
|
|
||||||
|
### 3. Security (backend-engineer)
|
||||||
|
|
||||||
|
**S1 — `--host-key-fingerprint` fails closed** ✅
|
||||||
|
`internal/proxmox/bootstrap.go:141-153,245-258`. The pinned/TOFU branch is
|
||||||
|
mutually exclusive (`if opts.HostKeyFingerprint != "" { ... } else { ... }`).
|
||||||
|
The pinned callback (245-258) validates `SHA256:` prefix up front (rejects
|
||||||
|
raw hex per D-045), computes `ssh.FingerprintSHA256(key)`, returns an error
|
||||||
|
on any mismatch — no fallback to TOFU. The dial (164) aborts on callback
|
||||||
|
error before any SSH session command runs. Cannot be bypassed: the pin is
|
||||||
|
compared as a full string against the canonical fingerprint of the
|
||||||
|
server-presented key; a mismatch returns before `*capturedKey` is set. No
|
||||||
|
issue.
|
||||||
|
|
||||||
|
**S2 — `key-reset` is local-only (D-046)** ✅
|
||||||
|
`internal/proxmox/bootstrap.go:479-523` + `internal/cli/node.go:348-407`.
|
||||||
|
`ResetHostKey` only reads/writes `certpaths.KnownHostsPath()`. No SSH dial,
|
||||||
|
no remote authorized_keys touch. Audit-logs `node.key_reset` with
|
||||||
|
actor+node+host (node.go:396-400). Verified by `TestNodeKeyReset`
|
||||||
|
(node_test.go:326) which asserts the audit row. No issue.
|
||||||
|
|
||||||
|
**S3 — TOFU capture-fix doesn't weaken MITM detection** ✅
|
||||||
|
See C3 — the fix ONLY captures on `KeyError{Want:[]}` (host unknown); a
|
||||||
|
non-empty `Want` (key mismatch / MITM) returns the error. The capture path
|
||||||
|
writes the server-presented key, so a subsequent different key fails. No
|
||||||
|
issue.
|
||||||
|
|
||||||
|
**S4 — `WriteAtomic` is actually atomic** ✅
|
||||||
|
`internal/security/ca.go:308-337`. Temp file in same dir
|
||||||
|
(`os.CreateTemp(dir, ".tmp-*")`), `Write`, `Chmod`, `Sync`, `Close`, then
|
||||||
|
`os.Rename` (atomic on POSIX same-filesystem). `defer os.Remove(tmpName)`
|
||||||
|
cleans up on failure. Genuine atomic-write pattern. No issue.
|
||||||
|
|
||||||
|
### 4. Performance (all)
|
||||||
|
|
||||||
|
**P1 — ResetHostKey is O(n) in file size** ✅
|
||||||
|
`internal/proxmox/bootstrap.go:479-523`: one `os.ReadFile` (O(n)), one
|
||||||
|
`strings.Split` + linear filter loop (O(n)), one `security.WriteAtomic`
|
||||||
|
(O(n)). No nested loops, no O(n²). For a known_hosts file (typically tens
|
||||||
|
of lines), this is negligible. No issue.
|
||||||
|
|
||||||
|
**P2 — Unnecessary allocations** (P2 — nit)
|
||||||
|
`bootstrap.go:494-510`: `strings.Split(string(existing), "\n")` allocates a
|
||||||
|
slice of all lines + `append(kept, []byte(line+"\n")...)` reallocates the
|
||||||
|
kept buffer. For known_hosts (small file) this is fine; a `bufio.Scanner`
|
||||||
|
over `bytes.NewReader(existing)` with a `strings.Builder` would be leaner,
|
||||||
|
but the current shape is clear and the file is tiny. Not worth changing.
|
||||||
|
Flagged P2 (nit, no action).
|
||||||
|
|
||||||
|
### 5. Maintainability (lead-developer)
|
||||||
|
|
||||||
|
**M1 — `TOFUHostKeyCallback` extraction** ✅
|
||||||
|
`internal/proxmox/bootstrap.go:261-310` is exported and shared by bootstrap
|
||||||
|
(148) and doctor (doctor.go:424) via
|
||||||
|
`proxmox.TOFUHostKeyCallback(sshAddr, &capturedHostKey)`. Clean coupling:
|
||||||
|
doctor imports proxmox (one-way), no duplication, no circular dep. The
|
||||||
|
GRILL #2 parity requirement (both call sites use the same wrapper) is
|
||||||
|
satisfied by construction. No issue.
|
||||||
|
|
||||||
|
**M2 — `verify()` testable** ✅
|
||||||
|
`cmd/verify-reqs/main.go:98-148`: the core logic is a pure function
|
||||||
|
`verify(roadmapPath, reqsPath string) (diff []string, count int, err error)`
|
||||||
|
with `main()` as a thin wrapper. Golden-file tests call `verify()` directly
|
||||||
|
(no subprocess). Mirrors the T01.11 `main()→run()` pattern. No issue.
|
||||||
|
|
||||||
|
**M3 — cli tests follow conventions** ✅
|
||||||
|
`internal/cli/namespace_test.go:21-35` adds `resetCommandFlags()` to zero
|
||||||
|
the package-level flag-bound vars between subtests (cobra parses into
|
||||||
|
globals; without reset a prior test's value persists). Called from
|
||||||
|
`resetRootFlags`. This is a sound convention — the test isolation is
|
||||||
|
correct. No issue.
|
||||||
|
|
||||||
|
**M4 — `resetCommandFlags` completeness** (P2 — nit)
|
||||||
|
`namespace_test.go:28-34` resets the join/leave/cap/audit/run/stop flags but
|
||||||
|
NOT `joinHostKeyFP`. A test that sets `--host-key-fingerprint` without
|
||||||
|
calling `resetRootFlags` could leak the value to a later test. In practice
|
||||||
|
all node tests call `resetRootFlags` which calls `resetCommandFlags`, so
|
||||||
|
this is a latent risk only. Recommend adding `joinHostKeyFP = ""` to
|
||||||
|
`resetCommandFlags` for completeness. Flagged P2 (nit).
|
||||||
|
|
||||||
|
### 6. Adversarial (backend-engineer)
|
||||||
|
|
||||||
|
**A1 — Can `--host-key-fingerprint` be bypassed?** ✅
|
||||||
|
No. The pinned callback (bootstrap.go:249-258) returns an error before
|
||||||
|
recording the key or allowing the dial to proceed on any mismatch. There is
|
||||||
|
no code path where a supplied pin is ignored — the branch at 141-153 is
|
||||||
|
`if opts.HostKeyFingerprint != ""` (pinned) `else` (TOFU); once pinned is
|
||||||
|
chosen, TOFU is not consulted. No bypass.
|
||||||
|
|
||||||
|
**A2 — Can `key-reset` corrupt known_hosts under concurrent write?** (P1 — important, low likelihood)
|
||||||
|
`proxmox.ResetHostKey` (bootstrap.go:479-523) and `TOFUHostKeyCallback`
|
||||||
|
(bootstrap.go:290-302) both do read-modify-write on
|
||||||
|
`certpaths.KnownHostsPath()` WITHOUT a lock. Two concurrent operations
|
||||||
|
(e.g. `orca node join --type proxmox hostA` + `orca node key-reset hostB`,
|
||||||
|
or two simultaneous joins to different hosts) could interleave:
|
||||||
|
- T1 reads known_hosts (empty), T2 reads known_hosts (empty)
|
||||||
|
- T1 writes hostA line, T2 writes hostB line
|
||||||
|
- Last rename wins → one line lost.
|
||||||
|
|
||||||
|
The `security.WriteAtomic` (temp+rename) prevents corruption (the file is
|
||||||
|
always valid OpenSSH format), but a captured line can be silently lost. This
|
||||||
|
is a **last-writer-wins race on a flat file with no lock**. Severity is low
|
||||||
|
because orca is a single-operator CLI (concurrent joins are unusual) and
|
||||||
|
the lost line is recoverable (re-connect re-pins via TOFU). But it is a
|
||||||
|
real correctness gap for the trust surface. Recommend either (a) a
|
||||||
|
file-lock around the read-modify-write, or (b) documenting the
|
||||||
|
single-operator assumption explicitly. Flagged P1 (important, post-hoc).
|
||||||
|
|
||||||
|
**A3 — Can verify-reqs be fooled by a crafted markdown table?** ✅
|
||||||
|
No. The `reqRowRe` anchors on `^\|\s*(REQ-\d+)\s*\|` and the status column
|
||||||
|
at end-of-line. A crafted row with a fake status would have to match the
|
||||||
|
regex exactly. The "malformed" fixture (`requirements_malformed.md`)
|
||||||
|
exercises the no-REQ-rows path → clear error. A row like
|
||||||
|
`| REQ-999 | missing status cell | High | v0.1 |` (no final `|...|`) does
|
||||||
|
NOT match `reqRowRe` (the trailing `\|\s*$` requires the status cell) — it
|
||||||
|
is silently skipped, which `verify` reports as "no REQ rows" only if ALL
|
||||||
|
rows are malformed. If some rows are valid + one malformed, the malformed
|
||||||
|
row is skipped without error — a minor blind spot, but acceptable (the
|
||||||
|
gate catches drift, not typos). No blocking issue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## GRILL Conditions Verification
|
||||||
|
|
||||||
|
### #1 — T02.6 labeled as v0.6 ship-defect bugfix ✅
|
||||||
|
Commit `8b0cbe1` summary: "fix(proxmox): TOFU capture bug — **v0.6
|
||||||
|
ship-defect** first-connect join always failed (T02.6)". The commit message
|
||||||
|
explicitly labels it as a v0.6 ship-defect bugfix, not a v0.8 feature.
|
||||||
|
PHASE2 verification report records it as "TOFU bugfix (T02.6, v0.6
|
||||||
|
ship-defect)". **Satisfied.**
|
||||||
|
|
||||||
|
### #2 — T02.9 doctor parity (bootstrap + doctor use capture-fix wrapper) ✅
|
||||||
|
- Bootstrap: `internal/proxmox/bootstrap.go:148` calls
|
||||||
|
`TOFUHostKeyCallback(sshAddr, &capturedHostKey)`.
|
||||||
|
- Doctor: `internal/doctor/doctor.go:424` calls
|
||||||
|
`proxmox.TOFUHostKeyCallback(sshAddr, nil)`.
|
||||||
|
Both use the SAME exported wrapper (`proxmox.TOFUHostKeyCallback`,
|
||||||
|
bootstrap.go:275). No duplication. The doctor diff
|
||||||
|
(`internal/doctor/doctor.go`) removes the direct `knownhosts.New` call and
|
||||||
|
replaces it with the shared wrapper. **Satisfied.**
|
||||||
|
|
||||||
|
### #3 — T01.6 cli escape valve (was it needed?) ✅
|
||||||
|
PHASE1 verification: cli hit **76.2%** (above the 70% floor, excluding
|
||||||
|
daemon.go). The escape valve (ship at 65% if 70% not reached) was **NOT
|
||||||
|
needed**. The plan's conditional was correctly conservative; the actual
|
||||||
|
result exceeded the floor. **Satisfied (not invoked).**
|
||||||
|
|
||||||
|
### #4 — T03.1 verify-reqs regex substring-tolerant + reverse direction ✅
|
||||||
|
- **Substring-tolerant**: `cmd/verify-reqs/main.go:30`:
|
||||||
|
`^##\s*Milestone\s+(v0\.\d+):.*—\s*\*\*[^*]*\bCOMPLETE\b[^*]*\*\*`.
|
||||||
|
Verified against the real ROADMAP: matches v0.2's
|
||||||
|
`**COMPLETE (merged to main via v0.3)**` and all other COMPLETE
|
||||||
|
milestones. Golden test `TestVerify_v02SubstringTolerantHeader`
|
||||||
|
(main_test.go:140) guards against regression.
|
||||||
|
- **Reverse direction**: `cmd/verify-reqs/main.go:135-139`: a REQ marked
|
||||||
|
`Complete` whose referenced milestones are ALL not-C_COMPLETE in ROADMAP
|
||||||
|
is flagged as `direction=reverse` drift. Golden test `TestVerify_drift`
|
||||||
|
asserts REQ-003 is reverse-drift.
|
||||||
|
- **Scope note**: PLAN + commit `fc2b020` document that REQ-060 catches
|
||||||
|
doc-vs-doc drift only (code-vs-doc like the REQ-053 cert_repo_test.go
|
||||||
|
case is out of scope; P04 audit is the backstop). **Satisfied.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## P0 Fixes Applied
|
||||||
|
|
||||||
|
**None.** No P0 issues (correctness bugs, security holes, broken build/test)
|
||||||
|
were found. `go build ./...`, `go vet ./...`, `go test -race` (all key
|
||||||
|
packages), and `make verify-reqs` all PASS. The milestone is shippable as-is.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## P1+ Issues Flagged (post-hoc review)
|
||||||
|
|
||||||
|
| ID | Severity | File:line | Issue | Recommendation |
|
||||||
|
|----|----------|-----------|-------|----------------|
|
||||||
|
| A2 | P1 (important, low likelihood) | `internal/proxmox/bootstrap.go:290-302, 479-523` | `TOFUHostKeyCallback` capture path and `ResetHostKey` both do read-modify-write on `known_hosts` with no lock; concurrent operations can lose a captured line (last-writer-wins via atomic rename — no corruption, but data loss). | Add a file-lock (`flock` on a `.known_hosts.lock` sibling, or `github.com/gofrs/flock` if a dep is acceptable) around the RMW in both paths; OR document the single-operator assumption in the key-reset help text. Defer to v0.9. |
|
||||||
|
| M4 | P2 (nit) | `internal/cli/namespace_test.go:28-34` | `resetCommandFlags()` does not reset `joinHostKeyFP`; a test setting `--host-key-fingerprint` without `resetRootFlags` could leak the value. | Add `joinHostKeyFP = ""` to `resetCommandFlags`. Trivial. |
|
||||||
|
| P2 | P2 (nit) | `internal/proxmox/bootstrap.go:494-510` | `ResetHostKey` uses `strings.Split` + repeated `append` (minor allocation churn). | Optional: use `bufio.Scanner` + `strings.Builder`. Not worth changing for a small file. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overall Verdict
|
||||||
|
|
||||||
|
**PASS-WITH-FOLLOWUPS**
|
||||||
|
|
||||||
|
The v0.8 milestone is correct, secure, tested, and shippable. All 4 GRILL
|
||||||
|
binding conditions are satisfied. Zero P0 issues. The single P1 (concurrent
|
||||||
|
`known_hosts` write race, A2) is a real but low-likelihood gap appropriate
|
||||||
|
for post-hoc follow-up — it does not block the milestone ship because orca
|
||||||
|
is a single-operator CLI and the atomic-rename guarantees the file is never
|
||||||
|
corrupted (only a captured line can be lost, recoverable on re-connect).
|
||||||
|
The 2 P2 nits are cosmetic. Coverage held post-P02 (86.5%/76.7%/70.4% for
|
||||||
|
proxmox/cli/doctor), race tests pass, all 7 T02.10 e2e cases are present and
|
||||||
|
exercised through a real in-process SSH server, and `make verify-reqs`
|
||||||
|
passes on the current repo (60 consistent rows).
|
||||||
|
|
||||||
|
Recommend proceeding to P04 ship (T04.7/T04.8: mark REQ-057..060 Complete +
|
||||||
|
ROADMAP v0.8 COMPLETE, then tag v0.7.4).
|
||||||
+6
-6
@@ -133,7 +133,7 @@ Tags run on the previous minor's patch line (v0.6.x) per
|
|||||||
branch-strategy.md. The milestone branch label uses the milestone
|
branch-strategy.md. The milestone branch label uses the milestone
|
||||||
number (`milestone/v0.7-hardening-completion`); no separate minor tag.
|
number (`milestone/v0.7-hardening-completion`); no separate minor tag.
|
||||||
|
|
||||||
## Milestone v0.8: Coverage & Trust Hardening
|
## Milestone v0.8: Coverage & Trust Hardening — **COMPLETE**
|
||||||
|
|
||||||
Scope: continue the v0.7 hardening theme. v0.7 P03's ≥ 50% floor left
|
Scope: continue the v0.7 hardening theme. v0.7 P03's ≥ 50% floor left
|
||||||
six packages still under 50% (engine 8.3%, proxmox 5.1%, cli 27.6%,
|
six packages still under 50% (engine 8.3%, proxmox 5.1%, cli 27.6%,
|
||||||
@@ -144,11 +144,11 @@ in v0.6 (D-035 `--host-key-fingerprint` pre-pin, RESEARCH_v0.6 §80
|
|||||||
`orca node key-reset`) and adds a requirements-hygiene gate to prevent
|
`orca node key-reset`) and adds a requirements-hygiene gate to prevent
|
||||||
the stale-REQ-status drift seen after v0.7 ship.
|
the stale-REQ-status drift seen after v0.7 ship.
|
||||||
|
|
||||||
- [ ] Phase 0: Pre-execution (specify → clarify → research → plan → grill) — tag `v0.7.0`
|
- [x] Phase 0: Pre-execution (specify → clarify → research → plan → grill) — tag `v0.7.0` (shipped)
|
||||||
- [ ] Phase 1: Test coverage uplift round 2 — 6 packages to ≥ 70%, 3 zero-test packages to first tests (REQ-057) — tag `v0.7.1`
|
- [x] Phase 1: Test coverage uplift round 2 — 6 packages to ≥ 70%, 3 zero-test packages to first tests (REQ-057) — tag `v0.7.1` (shipped)
|
||||||
- [ ] Phase 2: SSH trust hardening — `--host-key-fingerprint` pre-pin + `orca node key-reset` + TOFU bugfix + `HostKeyFingerprint` population (REQ-058, REQ-059) — tag `v0.7.2`
|
- [x] Phase 2: SSH trust hardening — `--host-key-fingerprint` pre-pin + `orca node key-reset` + TOFU bugfix + `HostKeyFingerprint` population (REQ-058, REQ-059) — tag `v0.7.2` (shipped)
|
||||||
- [ ] Phase 3: Requirements-hygiene gate — `make verify-reqs` + verify assertion (REQ-060) — tag `v0.7.3`
|
- [x] Phase 3: Requirements-hygiene gate — `make verify-reqs` + verify assertion (REQ-060) — tag `v0.7.3` (shipped)
|
||||||
- [ ] Phase 4: Final review + ship + audit (milestone release) — tag `v0.7.4`
|
- [x] Phase 4: Final review + ship + audit (milestone release) — tag `v0.7.4` (shipped)
|
||||||
|
|
||||||
**Milestone type**: NFR (P01 test, P02 chore on trust surface per
|
**Milestone type**: NFR (P01 test, P02 chore on trust surface per
|
||||||
D-043, P03 chore, P04 docs/review). Final phase patch IS the milestone
|
D-043, P03 chore, P04 docs/review). Final phase patch IS the milestone
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"name": "Orca",
|
"name": "Orca",
|
||||||
"description": "Offline/CLI-first orchestration engine (Orca) — Nomad-inspired, far simpler than Kubernetes",
|
"description": "Offline/CLI-first orchestration engine (Orca) — Nomad-inspired, far simpler than Kubernetes",
|
||||||
"milestone": "v0.8",
|
"milestone": "v0.8",
|
||||||
"phase": 0,
|
"phase": 4,
|
||||||
"milestone_type": "nfr",
|
"milestone_type": "nfr",
|
||||||
"default_branch": "main",
|
"default_branch": "main",
|
||||||
"tech_stack": {
|
"tech_stack": {
|
||||||
|
|||||||
Reference in New Issue
Block a user