Verify manifest.integrity at the os plugin publish preflight (framework leg of #11331) - #13502
Verify manifest.integrity at the os plugin publish preflight (framework leg of #11331)#13502os-project-manager wants to merge 2 commits into
Conversation
📓 Docs Drift CheckThis PR changes 3 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 138 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e25b7cf3076f40a212b1e9eb2dbb1ac4db5198cd && git checkout e25b7cf3076f40a212b1e9eb2dbb1ac4db5198cd
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e7191ce71da1a8cc25c05e3d372eb4f63be5517a 4f3eda771ce43129d0208f90e1f53c7df5b6009e && git checkout -B drift-repro e7191ce71da1a8cc25c05e3d372eb4f63be5517a && git merge --no-ff 4f3eda771ce43129d0208f90e1f53c7df5b6009e
node scripts/docs-audit/affected-docs.mjs --json e7191ce71da1a8cc25c05e3d372eb4f63be5517a
|
…#13464) Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KX8wnyjStaZcuMyAMNsy3N
f26fef2 to
5ead860
Compare
…blish-integrity-preflight
Fixes #13464
Part-of #11331
Scope framing (verbatim obligation from the card)
This PR does NOT discharge the #11331 unpack ruling. The ruled enforce leg — re-verification of
manifest.integrityat install/load-time unpack (ADR-0025 §3.5 step 5) — has no landing surface in this repo and remains the cloud control plane's obligation, tracked on #11331. This PR lands only the framework leg: the publisher now self-checks its own artifact before upload. #11331 remains open and its spec promise remains outstanding.What landed
verifyIntegrity(files, integrity, options)inpackages/core/src/security/plugin-artifact-integrity.ts, beside the artifact-signature contract and with the same portability property (pure, node:crypto only, byte-mirrorable to cloud). Returns a structured envelope: ok / skipped / checked count / one violation per finding, with kindsdigest_mismatch,missing_file,extra_file. SRI-style digests (sha256 by declared algorithm; sha384/sha512 honoured; an unrecognized digest shape compares as sha256 and therefore fails loudly, never silently passes).formatIntegrityViolationrenders the actionable line the CLI prints. Exported from@objectstack/core.os plugin publishpreflight (packages/cli/src/commands/plugin/publish.ts, step 2b): the already-in-memory unpacked tree is checked against the manifest's own declared digests before any network call; refusal exits 1 pre-upload with per-file findings and the remedy (rebuild withos plugin build, re-sign, publish fresh). The compiled manifest and SIGNATURE placeholder are exempt paths, mirroring whatcomputeIntegrityexcludes at build.packages/spec/src/kernel/manifest.zod.ts(regions 100-109 and 611-616 only — measured disjoint from in-flight [text correction · ruled B] manifest.runtime tombstone/describe reads truthfully: publish-gate enforced (cloud), load-side NOT enforced #11330's regions; no shape change, no describe-text change): the comments no longer claim the runtime re-verifies at unpack; they now state the truth — computed at build, self-checked at publish preflight, unpack-time verification is the cloud control plane's unimplemented obligation (manifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331).packages/spec/liveness/manifest.json, integrity row): corrected census — the map IS computed at build and now has one non-test in-repo reader (the publish preflight).statusleftdeadper the card's mandate;check:livenesspasses on the row as written, and the note records explicitly that any flip tolivebelongs to themanifest.integritydeclares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331 resolution / review chain, not to a rider here..changeset/plugin-publish-integrity-preflight.md): patch for@objectstack/cliand@objectstack/core.Decision mandate (pre-answered on the card, carried here)
.optional(); strict-by-default would be a contract change needing its own ruling.packages/runtime/src/artifact-reference.ts, lines 68-73 at base).packages/spec/src/api/error-code-ledger.zod.tsis untouched.Declared bounded in-place fix (same defect class, same files)
packages/cli/src/utils/osplugin.tscarried the identical false claim the card corrects in the spec ("re-verifies … when the runtime unpacks", header and the sriDigest docblock). Comment-only correction to the same truthful wording, in a file this card already reads at its call site; no behavior change. Evidence: the card's own ruling text pins the correct prose; the PM claim measured no other in-flight card touchingosplugin.ts.Clause ② parking
Both limbs fire (diff touches
packages/spec/src/kernel/manifest.zod.ts; publish gains an accept/reject change). This PR is parked as DRAFT withneeds:contract-reviewon both carriers (PR + card #13464). The review chain owns enqueue; #13464 stays open until then and #11331 remains open regardless.Gates
All measured at branch head
f26fef2a(basec38b7eff= origin/main at dispatch; upstream moved since, but touched none of this PR's files — in particularmanifest.zod.tsis unchanged upstream, so in-flight #11330 has not merged and no base merge was owed).pnpm --filter @objectstack/cli testvitest run test/plugin-publish.test.ts(direct)pnpm --filter @objectstack/core testvitest run src/security/plugin-artifact-integrity.test.ts(direct)pnpm --filter @objectstack/spec check:livenessstatus: deadkept per mandatepnpm --filter @objectstack/spec check:authorable-surfacepnpm --filter @objectstack/spec check:generatedpnpm --filter @objectstack/spec typecheckpnpm --filter @objectstack/cli typechecksrconly, so the edited test file is exercised by vitest, not tsc (pre-existing repo shape)pnpm lint(repo eslint,--no-inline-config)check:type-check-coverage+check:type-check-debt --re-measure(full package closure built first)check:i18n/check:i18n-coveragescripts/pm/dispatch-gates.mjs, derived atf26fef2a)Generated by Claude Code
Generated by Claude Code