Skip to content

manifest.integrity declares per-file artifact digests the spec says the runtime re-verifies at unpack — nothing computes them and nothing checks them #11331

Description

@os-sam

Measured while seeding the plugin-manifest liveness ledger for #10728 (verdict recorded as dead in packages/spec/liveness/manifest.json). Filed, not fixed.

Measured on origin/main (b9e9227e3).

What is declared

packages/spec/src/kernel/manifest.zod.ts:107-109, 576integrity: PluginIntegritySchema.optional(), a Record of artifact-relative path → digest ("sha256-"), whose own describe/TSDoc says:

Per-file content digests of the packaged artifact (ADR-0025 §3.2), re-verified by the runtime when it unpacks the .osplugin (ADR §3.5 step 5).

What is measured

Zero reads, in either direction of the lifecycle:

  • Nothing computes the digests — os plugin build (packages/cli/src/commands/plugin/build.ts) bundles with esbuild and never hashes per-file content into a manifest.
  • Nothing verifies them — repo-wide probe for a manifest-shaped .integrity read ((manifest|pkg|package|entry|artifact)?.integrity, non-test, non-comment) returns no hits at all in objectstack, and objectui is likewise zero.

Controls

  • The same probe finds real reads of sibling manifest keys — .packaging (cli/src/commands/plugin/build.ts:126), .data (runtime/src/app-plugin.ts:946), .contributes (objectql/src/engine.ts:4504) — so it is not blind to this object.
  • objectui control: manifest.(id|name|namespace|version) → 46 hits there. The zero is about the path, not the probe.

Adjacent machinery that exists and is NOT this

packages/core/src/security/plugin-artifact-signature.ts verifies an artifact signature, and deliberately returns verified=false rather than throwing when one is absent (its header says so at :144, leaving the trust-tier decision to the caller). That is a different mechanism on a different field. Its presence is part of why this gap is easy to miss: the artifact-security story looks staffed.

Why it matters

A declared integrity check that never runs is the false-compliance shape in its most literal form: to any reader — human, AI, or an auditor reading a published manifest — the presence of an integrity block is indistinguishable from the digests having been checked. Unlike a dead display key, this one is about whether the bytes on disk are the bytes that were published.

⚠️ Scope limit — measure cloud before acting

cloud is unmeasured (carried from #10627: add_repo → "you don't have access to objectstack-ai/cloud"). The install-time unpack that ADR-0025 §3.5 describes is a control-plane path, and manifest.zod.ts:10-18 states the cloud control plane mirrors these shapes when validating a published .osplugin. Measure the cloud leg, with a control probe, before either fork. Same precondition #10724 carries.

The fork (not prejudged)

  • A — Enforce. Emit digests at os plugin build and verify them at unpack. This is what the spec already tells readers happens, so A is the option that makes the shipped documentation true.
  • B — Retire. Tombstone under ADR-0049 (ManifestSchema is not .strict(), so a plain deletion would silently strip the key — the loading precedent at manifest.zod.ts:510-514) and remove the "re-verified by the runtime" sentence with it.

A is the more defensible default here than on a typical dead key: the cost of B is deleting a supply-chain control the project has already published an intent to have. But intent is not delivery, and this is not a decision for an implementation seat.

Filed unassigned for triage.

Restart-when: git grep -n "verifyIntegrity\|readTarGz\|readTar(" origin/main -- packages/ ':!*.test.*' ':!*/CHANGELOG.md' reports a production caller outside packages/cli/src/commands/plugin/ and packages/cli/src/utils/osplugin.ts — i.e. an unpack or load path exists for the ruled step-5 re-verification to attach to
Restart-touch: packages/cli/src/utils/osplugin.ts
Restart-touch: packages/core/src/security/plugin-artifact-integrity.ts


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions