Promotion-Time Attestations for Stella Ops

Destination currency (source-verified 2026-10-07 at f9dbf896333339ed6ed3e655d4e8e3a793cc38fe): Evidence hosts attestation, canonical-record, capsule, and signing-key reads under /api/evidence/v1; OfflineKit hosts the standard export API under /api/offlinekit/v1/exports. The owner handler suffix determines the complete path. See Evidence architecture. This documentation update does not verify a live signing, promotion, or export operation.

Status: Stable (2025-11)
Owners: Signing Guild · Provenance Guild · DevEx/CLI Guild · Export Center Guild

1. Purpose

Capture the full promotion-time evidence – image digest, SBOM/VEX artifacts, Rekor proof – in a single DSSE-wrapped statement so that air-gapped auditors can verify releases without talking to external services. This document explains the data shape, producer responsibilities, and downstream consumers that rely on the promotion attestation.

2. Predicate schema – stella.ops/promotion@v1

{
  "_type": "stella.ops/promotion@v1",
  "subject": [
    { "name": "registry.example.com/acme/api", "digest": { "sha256": "…" } }
  ],
  "materials": [
    { "role": "sbom", "algo": "sha256", "digest": "…", "format": "CycloneDX-1.6", "uri": "oci://…/sbom@sha256:…" },
    { "role": "vex",  "algo": "sha256", "digest": "…", "format": "OpenVEX-1.0",   "uri": "oci://…/vex@sha256:…" }
  ],
  "promotion": {
    "from": "staging",
    "to": "prod",
    "actor": "ci/gitlab-runner",
    "timestamp": "2025-11-10T12:34:56Z",
    "pipeline": "https://git.example.com/acme/api/-/pipelines/12345",
    "ticket": "JIRA-1234",
    "notes": "risk accepted by ops"
  },
  "rekor": {
    "uuid": "REKOR_ENTRY_UUID",
    "logIndex": 1234567,
    "inclusionProof": {
      "rootHash": "MERKLE_ROOT",
      "hashes": ["…path…"],
      "treeSize": 9876543,
      "checkpoint": {
        "origin": "rekor.sigstore.dev - transparency log",
        "size": 9876543,
        "hash": "CHECKPOINT_HASH",
        "signedNote": "BASE64_NOTE"
      }
    }
  },
  "attestation": {
    "bundle_sha256": "sha256:…",   
    "witness": "optional-transparency-witness-signature"
  }
}

The Provenance Guild implements the predicate builder (task PROV-OBS-53-003). The signer pipeline accepts the predicate as a raw JSON payload and wraps it inside a DSSE envelope (SIGN-CORE-186-005). Rekor metadata is pulled from Attestor after DSSE submission.

3. Producer workflow

3.1 CLI orchestration (CLI-PROMO-70-001/002)

  1. Resolve and freeze the image digest (cosign triangulate/crane digest).
  2. Hash SBOM and VEX artifacts, optionally publish them to an OCI registry.
  3. Upload the SBOM (or dummy artifact) to Rekor to obtain {uuid, logIndex}.
  4. Retrieve inclusion proof + checkpoint (rekor-cli get, rekor-cli loginfo).
  5. Build attestation.json using the template above and current promotion metadata.
  6. Call Signer to produce a DSSE bundle (cosign attest or stella promotion attest).
  7. Store the bundle alongside attestation.json and add both to Offline/Replay kits.
  8. Emit Timeline + Evidence Locker entries with bundle digest.

3.2 Signer responsibilities (SIGN-CORE-186-004/005/006)

3.3 Export Center integration (EXPORT-OBS-54-002)

4. Verification flow

Auditors can validate the promotion attestation offline:

  1. Verify the DSSE signature using the provided bundle and trusted key/cert chain.
  2. Recompute Merkle inclusion using the embedded proof + checkpoint. The checkpoint’s signed note ties the inclusion to a known Rekor tree size.
  3. Hash SBOM/VEX artifacts and compare to the materials digests.
  4. Confirm the promotion metadata in release notes/CI evidence.

Authority exposes helper APIs (AUTH-VERIFY-186-007) to replay both DSSE and Merkle validations.

5. APIs & storage

ComponentEndpoint / ArtifactNotes
SignerPOST /api/v1/signer/sign/dsseAccepts promotion predicate, returns DSSE bundle + auditId.
AttestorPOST /api/evidence/v1/rekor/entriesPersists DSSE, returns {uuid, index, proof}.
OfflineKitPromotion assembly reads under /api/offlinekit/v1/promotionsCurrent source contract listed below; no deployed acceptance is implied.
Evidence LockerStore DSSE + Rekor proof for long-term retention.

Current promotion assembly reads (source-verified 2026-10-07)

OfflineKit’s host mounts PromotionAttestationEndpoints on /api/offlinekit; the endpoint group adds /v1/promotions. Its current read contracts are:

The group requires ExportOperator, the catalog export.operator policy, including for these reads. These source-mapped operations do not establish a current deployment, generated artifact or verified promotion attestation. Re-verify src/OfflineKit/__Libraries/StellaOps.ExportCenter.Application/Attestation/PromotionAttestationEndpoints.cs and the host’s Program.cs together.

Historical 2025-11 export proposal

The former planned GET /api/v1/exports/{id}/promotion described a proposed promotion export. It does not identify a current mapped owner contract and is withdrawn as an implementation instruction. Use the distinct source-mapped promotion assembly reads above rather than replacing the proposal’s prefix.

Artifacts are content-addressed via CAS and mirrored into Offline kits (docs/replay/DETERMINISTIC_REPLAY.md).

6. Security considerations

7. Implementation checklist

AreaSprint taskStatus
Predicate builderPROV-OBS-53-003Planned
Signer supportSIGN-CORE-186-004/005/006Planned
CLI commandsCLI-PROMO-70-001/002Planned
Authority verifierAUTH-VERIFY-186-007Planned
Export packagingEXPORT-OBS-54-002Planned
DocumentationDOCS-PROMO-70-001DONE (2025-11-26)

When all tasks are completed this document should be updated with status links and sample payloads.