Context
0370 makes a service refuse to start on a pack whose signature does not verify against a trusted key, so whoever holds the private key can change tax, fiscal and legal behaviour in every tenant. Two different things were called “signing”: a person vouching that a value is legally right, and the cryptographic signature that proves the bytes came from the release. Alternatives weighed: counsel or each local reviewer holding a key (rejected: many keys, held on laptops, and a reviewer’s approval is per value, not per file), a key per product for its sections (rejected for now: every service would trust several keys and a product could ship a section the platform never saw), and a CI secret variable (rejected: anyone who can change a workflow can read it).Decision
- Two acts, two records. A reviewer’s approval is a sign-off per entry key in the pack version (
reviews, 0370 decision 8): who, on what date. The Ed25519 signature is the release’s proof that the bytes are the reviewed ones. A reviewer never holds a signing key. - One holder. The platform release service (OS) holds the private key in a managed key store (a cloud KMS or HSM
with an Ed25519 key that cannot be exported). No person, repository, CI variable or tenant holds it.
signPackruns inside that service with a non-exportableCryptoKey. - What may be signed. The release service signs a pack version only when
unreviewedlists no key and its status isbetaorlive. Drafts are never signed. Product sections are signed by the same service after the product’s own reviewers sign off their keys. - Key ids and rotation. Each key has an id (
packs-2026). Deployments list trusted public keys by id (0370 decision 2); during a rotation two ids are trusted, and the old one is removed once every live pack is re-signed. A compromised key is removed from every deployment at once; packs it signed stop loading. - Who may promote. Moving a signed version to
live, and pinning a tenant, remain operator actions with their own permissions and audit; holding the key gives no right to promote.
Consequences
- The blast radius of a leaked reviewer account is one unsigned draft; a forged pack needs the release service.
- A pack change always needs both a reviewer sign-off and a release run; there is no “quick fix” path that skips either.
- Rotation is routine data work (a new trusted id, re-signing), not a code change.
- A product that wants to ship sections without the platform’s release service needs a new ADR.
Enforcement
planned — the release service’s sign step refuses a draft or a version with unreviewed keys; deployments read trusted keys from configuration only. Nothing checks either yet.Supersedes and sources
Supersedes: none. Settles 0363 open question 2; fills 0370 decisions 2 and 8. Sources:notes/handover/stackra-package-needs.md (market-pack loader row); notes/handover/answers-as-config.md
(CAP-pack-review, CAP-pack-launch-gate); STA-666.