ADR: Package trust v1
Status
Accepted (2026-07-12)
Context
Pre-CRM3 readiness requires verifiable package identity beyond deterministic hashes (R18). Host publication and tamper-evidence need a signing model that remains backward compatible with unsigned dev packages.
Decision
-
Manifest-level detached signatures — Sign the canonical package identity JSON (
manifestwithoutsignatures+ sorted artifact hashes, including the optionaltempliqx.lock), not individual files. -
Development algorithm —
sha256-keyedwithTEMPLIQX_PACKAGE_SIGNING_KEYexists only for local development and CI conformance. It is a keyed digest, not a public-key signature, must not be described as production signing, and must not be used as an OCI trust root. Production OCI publication uses Sigstore/Cosign keyless OIDC and verifies the image digest separately. -
Schema — Optional
signaturesarray ontempliqx.yaml:signatures: - key_id: ci-test algorithm: sha256-keyed value: <hex digest> -
Validation behavior
- Unsigned packages: pass default validation.
- Explicit strict verification (or
TEMPLIQX_PACKAGE_STRICT=1during package validation): reject unsigned packages withTQX_PACKAGE_UNSIGNEDerror. - Signatures present + key set: verify or emit
TQX_PACKAGE_SIGNATURE_INVALID. - Signatures present + key unset:
TQX_PACKAGE_SIGNATURE_UNVERIFIEDerror. - Duplicate signature identities and unsupported algorithms fail closed.
- The digest binds the canonical identity,
key_id, andalgorithm; changing signature metadata invalidates it. If any supported signature is invalid, the complete signature set is rejected (no partial acceptance).
Operator flow
- Run
export-package-identity <package>and retain itspackage_identityfingerprint as review evidence. Use the returnedmanifestfingerprint as the signing CAS value. - Set
TEMPLIQX_PACKAGE_SIGNING_KEYfrom a local/CI secret store. Never pass the key as a CLI or MCP argument. - Run
sign-package <package> --key-id <id> --expected-fingerprint <manifest-fingerprint>. The store rechecks both the manifest CAS value and full package-identity fingerprint while holding its package lock. This prevents attachment after an unseen manifest or artifact mutation; an existing signature for the same key and algorithm is replaced. - Run
verify-package-trust <package> --strict. Artifact tampering, wrong keys, cross-package replay, unsigned packages, duplicates and unsupported algorithms all produce error diagnostics. - For a release, independently sign and verify the OCI digest with Cosign. Manifest trust and OCI distribution trust are deliberately separate gates.
Consequences
- Dev workflows unchanged for unsigned packages.
- CI can round-trip sign/verify synthetic packages without cosign registry push.
- Cosign image attestation remains separate (BuildKit provenance in
scripts/supply-chain-smoke.sh).
Alternatives considered
- Per-file signatures — Rejected; inventory hash already covers artifact set.
- Mandatory signing in dev — Rejected; blocks local iteration.