Files
ThothII/.artifacts/reviews/task9-quality-audit-final5.md
T
marcopan c7338969d7 fix: bind complete P1 manual dist graph and snapshot identity
prepare records an immutable manifest of every regular backend/dist file
(path/size/sha256/dev/ino) in the owned root and binds its record identity
in ownership; serve revalidates record and every file before spawn, passes
the manifest to the child on fd 4, and the immutable preload hash-verifies
all files at startup and serves only cached verified bytes for any import
below backend/dist, so imported dependency replacement is refused before
RUNNING or never executes. The render command validates the commit
snapshot.json manifest, binds snapshot bytes to the manifest digest and the
installed Git blob, and passes the expected digest to the renderer, which
revalidates head/files digest with bounded no-follow reads and renders only
verified bytes with lease release on refusal.
2026-08-10 17:36:24 +02:00

4.2 KiB

Task 9 quality audit — final 5

Scope: the two blocking findings from task9-quality-audit-final4.md — unbound production module graph at manual serve, and commit-addressed snapshots accepted without content identity at render. Manual acceptance remains PENDING; no VERDICT.md was created.

Verdict: APPROVED for the two final integrity blockers

1. Manual serve binds the complete backend/dist module graph, not only server.js

prepare now builds a post-build manifest of every regular backend/dist file (relative path, size, SHA-256, device, inode) and writes it as an exclusive 0600 record (installation/runtime/backend-dist.manifest.json) inside the owned root; ownership.json records that record's path/device/inode/size/SHA-256. serve revalidates the manifest record identity and bytes, revalidates every distribution file against it (no-follow, single inode, size and digest), and refuses before spawning. The manifest descriptor is passed to the child on fd 4 together with the entrypoint on fd 3. The immutable preload parses the manifest, verifies the entrypoint cross-digest, reads and hash-verifies every file at startup, caches the verified bytes, and its load hook serves only those cached bytes for any import below backend/dist (entry URL still served from the bound fd-3 bytes). A same-path regular replacement of any imported dependency is therefore refused before RUNNING (serve-time validation), refused at child startup (startup verification), or rendered harmless (cached bytes), and the parent revalidates the full manifest at RUNNING publication and at stop.

2. Renderer binds snapshot content to its commit identity

The generated render command validates the bounded saved read/publish revisions, the commit-addressed owned snapshot path, the installed Git HEAD, and the bounded snapshot.json manifest of that commit: head equals the commit, files[<id>.yaml] is the SHA-256 of the snapshot bytes, the manifest revision binds commit/blob/snapshot path, the saved revision blob equals the manifest blob, and git rev-parse <commit>:workspaces/<id>.yaml plus git hash-object of the snapshot bytes both equal that blob. It passes the expected digest as --snapshot-sha256. The renderer re-reads the bounded snapshot.json (head, files[<id>.yaml] must equal the carried digest), opens the snapshot once with no-follow semantics and bounded reads, renders only the digest-verified bytes, re-verifies around lease publication, releases the lease in finally, and publishes no output on any refusal.

Deterministic regressions added

  • static regular replacement of an imported production dependency after prepare is refused, no marker, no accepted PID record, no orphan;
  • deterministic dependency check/load swap (beforeSpawn rename) is refused by the child's startup verification, no marker, no PID record, no orphan;
  • after RUNNING, a same-path regular dependency replacement is never executed: the loader serves the verified cached bytes (health-visible source stays the original) and the marker is absent;
  • renderer refuses a same-path regular snapshot byte replacement against the carried digest and manifest, with lease release and no output;
  • renderer refuses manifest head, files digest, expected-digest, missing, and malformed cases, with lease release and no output;
  • wrapper refuses missing manifest, manifest head/digest/revision tampering, saved-revision blob mismatch, Git blob mismatch, and snapshot-vs-Git-bytes mismatch, and passes the exact --snapshot-sha256 on the valid path (stub renderer records arguments).

Verification

  • bash scripts/test-p1-manual-acceptance.sh (backend build + both suites): 59 tests, 59 pass, 0 fail; no 8791/8792 listener and no --p1-manual-nonce process remain.
  • npx tsc --noEmit -p . (backend): PASS.
  • Real-repository prepare + cleanup cycle: 39 distribution files bound, entrypoint cross-digest verified, owned root fully removed afterwards.
  • Diff check: only the seven Task 9 paths are touched; no Task 8 file was modified.
  • This report and the implementation contain no fixture secret or canary values.

Manual acceptance remains PENDING by design; the walkthrough and human verdict are unchanged.