5.10.2.3 Signing
The Signing domain of releases. The trust chain clients verify: the public keys of the TUF roles, whose private halves live in Cloud KMS, and the signed metadata documents with their signatures. Staff register, rotate and revoke keys but never sign: the system signs when a release becomes active. Clients fetch metadata by role. It is one API, with its own contract and its own version.
5.10.2.3.1 Versions¶
| Version | Status | Prod URL | Contract |
|---|---|---|---|
v1 |
Proposed | https://releases.moonitoring.com/signing/v1 |
signing/v1/openapi.yaml |
The resources follow the data model. Adds the client reads of the TUF documents by role, which carry the signed and signatures JSON as the client verifies it.
5.10.2.3.2 Operations¶
Every operation names who calls it and the capability it checks (x-moonitoring-audience, x-moonitoring-capability in the contract); every capability is in the catalog of the data model (req 1002, 1006). Lists are paged by cursor, writes that create something carry an Idempotency-Key, errors are Problem Details.
| Operation | Request | Who | Capability |
|---|---|---|---|
| List signing keys | GET /signing-keys |
Staff | releases.releases.read |
| Register a signing key | POST /signing-keys |
Staff | releases.release_keys.manage |
| Rotate a signing key | POST /signing-keys/{key_id}/rotate |
Staff | releases.release_keys.manage |
| Revoke a signing key | POST /signing-keys/{key_id}/revoke |
Staff | releases.release_keys.manage |
| List encryption keys | GET /encryption-keys |
Staff | releases.releases.read |
| Register an encryption key | POST /encryption-keys |
Staff | releases.release_keys.manage |
| Rotate an encryption key | POST /encryption-keys/{key_id}/rotate |
Staff | releases.release_keys.manage |
| List signed metadata | GET /signed-metadata |
Staff | releases.releases.read |
| List a document's signatures | GET /signed-metadata/{metadata_id}/signatures |
Staff | releases.releases.read |
| Fetch the current metadata of a role | GET /applications/{application_id}/channels/{channel_id}/metadata/{role} |
Installed clients | none |
| Fetch a root version | GET /applications/{application_id}/channels/{channel_id}/metadata/root/{version} |
Installed clients | none |
5.10.2.3.3 Contract v1¶
Proposed version
v1 is a proposal for review: its endpoints, errors and capabilities were designed from the requirements and the flows and are not confirmed. It leaves proposal with its first release; from then on it changes only as described in Every API Is Versioned.
5.10.2.3.4 Rules Confirmed with the Implementation¶
Decided on 2026-11-05, from the choices made while building releases:
- Lifetimes: root 365 days, targets 90, snapshot 30, timestamp 7. The sweeper renews each document two days before it expires, every hour, and alerts when a renewal fails: a timestamp that lapses stops every update.
- The first root of a channel is signed by the sweeper as soon as the channel has registered keys, before its first release (decided 2026-11-10), so an installer can pin it from the start; it is root version 1, read by
GET /applications/{application_id}/channels/{channel_id}/metadata/root/1. - Formats: a key id is the SHA-256 of the canonical JSON of the key object; a signature is hex DER ECDSA over the canonical JSON of
signed; the targets document names<depot>/<manifest content hash>.manifestwith the blob's length and SHA-256, and the release incustom. - Rotating an encryption key creates the new key from the input and marks the old one
rotated_at; content encrypted with the old key stays readable.