# Inline DSSE Provenance > **Status:** Draft – aligns with the November 2025 advisory “store DSSE attestation refs inline on every SBOM/VEX event node.” > **Owners:** Authority Guild · Feedser Guild · Platform Guild · Docs Guild. This document defines how Stella Ops records provenance for SBOM, VEX, scan, and derived events: every event node in the PostgreSQL event store includes DSSE + Rekor references and verification metadata so audits and replay become first-class queries. --- ## 1. Event patch (PostgreSQL schema) ```jsonc { "_id": "evt_...", "kind": "SBOM|VEX|SCAN|INGEST|DERIVED", "subject": { "purl": "pkg:nuget/example@1.2.3", "digest": { "sha256": "..." }, "version": "1.2.3" }, "provenance": { "dsse": { "envelopeDigest": "sha256:...", "payloadType": "application/vnd.in-toto+json", "key": { "keyId": "cosign:SHA256-PKIX:ABC...", "issuer": "fulcio", "algo": "ECDSA" }, "rekor": { "logIndex": 1234567, "uuid": "b3f0...", "integratedTime": 1731081600, "mirrorSeq": 987654 // optional }, "chain": [ { "type": "build", "id": "att:build#...", "digest": "sha256:..." }, { "type": "sbom", "id": "att:sbom#...", "digest": "sha256:..." } ] } }, "trust": { "verified": true, "verifier": "Authority@stella", "witnesses": 1, "policyScore": 0.92 }, "ts": "2025-11-11T12:00:00Z" } ``` ### Key fields | Field | Description | |-------|-------------| | `provenance.dsse.envelopeDigest` | SHA-256 of the DSSE envelope (not payload). | | `provenance.dsse.payloadType` | Usually `application/vnd.in-toto+json`. | | `provenance.dsse.key` | Key fingerprint / issuer / algorithm. | | `provenance.dsse.rekor` | Rekor transparency log metadata (index, UUID, integrated time). | | `provenance.dsse.chain` | Optional chain of dependent attestations (build → sbom → scan). | | `trust.*` | Result of local verification (DSSE signature, Rekor proof, policy). | --- ## 2. Write path (ingest flow) 1. **Obtain provenance metadata** for each attested artifact (build, SBOM, VEX, scan). The CI script (`scripts/publish_attestation_with_provenance.sh`) captures `envelopeDigest`, Rekor `logIndex`/`uuid`, and key info. 2. **Authority/Feedser** verify the DSSE + Rekor proof (local cosign/rekor libs or the Signer service) and set `trust.verified = true`, `trust.verifier = "Authority@stella"`, `trust.witnesses = 1`. 3. **Attach** the provenance block before appending the event to PostgreSQL, using `StellaOps.Provenance.Postgres` helpers. 4. **Backfill** historical events by resolving known subjects → attestation digests and running an update script. ### 2.1 Supplying metadata from Concelier statements Concelier ingestion jobs can now inline provenance when they create advisory statements. Add an `AdvisoryProvenance` entry with `kind = "dsse"` (or `dsse-metadata` / `attestation-dsse`) and set `value` to the same JSON emitted by the CI snippet. `AdvisoryEventLog` and `AdvisoryMergeService` automatically parse that entry, hydrate `AdvisoryStatementInput.Provenance/Trust`, and persist the metadata alongside the statement. ```json { "source": "attestor", "kind": "dsse", "value": "{ \"dsse\": { \"envelopeDigest\": \"sha256:…\", \"payloadType\": \"application/vnd.in-toto+json\" }, \"trust\": { \"verified\": true, \"verifier\": \"Authority@stella\" } }", "recordedAt": "2025-11-10T00:00:00Z" } ``` Providing the metadata during ingestion keeps new statements self-contained and reduces the surface that the `/events/statements/{statementId}/provenance` endpoint needs to backfill later. Reference helper: `src/__Libraries/StellaOps.Provenance.Postgres/ProvenancePostgresExtensions.cs`. --- ### 2.2 Advisory AI structured chunk schema (GHSA/Cisco parity) Advisory AI consumes the canonical `Advisory` aggregate and emits structured chunks that mirror GHSA GraphQL and Cisco PSIRT provenance anchors. The response contract is: ```jsonc { "advisoryKey": "CVE-2025-0001", "fingerprint": "", "total": 3, "truncated": false, "entries": [ { "type": "workaround", // sorted by (type, observationPath, documentId) "chunkId": "c0ffee12", // sha256(advisory.observationId + observationPath)[:16] "content": { /* structured field */ }, "provenance": { "documentId": "tenant-a:chunk:newest", // PostgreSQL id of backing observation "observationPath": "/references/0", // JSON Pointer into the observation "source": "nvd", "kind": "workaround", "value": "tenant-a:chunk:newest", "recordedAt": "2025-01-07T00:00:00Z", "fieldMask": ["/references/0"] } } ] } ``` Determinism requirements: - Order entries by `(type, observationPath, documentId)` to keep cache keys stable across nodes. - Always include the advisory `fingerprint` in cache keys and responses. - Preserve observation-level provenance by emitting both `documentId` and `observationPath` under `provenance`. These anchors let Attestor/Console deep-link evidence and allow offline mirrors to prove origin without merging transforms. --- ## 3. CI/CD snippet See `scripts/publish_attestation_with_provenance.sh`: ```bash rekor-cli upload --rekor_server "$REKOR_URL" \ --artifact "$ATTEST_PATH" --type dsse --format json > rekor-upload.json LOG_INDEX=$(jq '.LogIndex' rekor-upload.json) UUID=$(jq -r '.UUID' rekor-upload.json) ENVELOPE_SHA256=$(sha256sum "$ATTEST_PATH" | awk '{print $1}') cat > provenance-meta.json <(r => Console.WriteLine($"{r.EventId}: {r.Status}")); var summary = await backfillService.BackfillAllAsync( kinds: new[] { "SBOM", "VEX", "SCAN" }, limit: 1000, progress: progress); Console.WriteLine($"Processed: {summary.TotalProcessed}"); Console.WriteLine($"Success: {summary.SuccessCount}"); Console.WriteLine($"Not found: {summary.NotFoundCount}"); Console.WriteLine($"Errors: {summary.ErrorCount}"); ``` ### 10.3 Implementing IAttestationResolver Implementations should query the attestation store (Rekor, CAS, or local PostgreSQL) by subject digest: ```csharp public class RekorAttestationResolver : IAttestationResolver { private readonly IRekorClient _rekor; private readonly IAttestationRepository _attestations; public async Task ResolveAsync( string subjectDigestSha256, string eventKind, CancellationToken cancellationToken) { // Look up attestation by subject digest var record = await _attestations.GetAsync(subjectDigestSha256, eventKind, cancellationToken); if (record is null) return null; // Fetch Rekor proof if available var proof = await _rekor.GetProofAsync(record.RekorUuid, RekorBackend.Sigstore, cancellationToken); return new AttestationResolution { Dsse = new DsseProvenance { /* ... */ }, Trust = new TrustInfo { Verified = true, Verifier = "Authority@stella" }, AttestationId = record.Id }; } } ``` ### 10.4 Reference files - `src/StellaOps.Events.Postgres/IAttestationResolver.cs` - `src/StellaOps.Events.Postgres/EventProvenanceBackfillService.cs` - `src/StellaOps.Events.Postgres/StubAttestationResolver.cs` This section was added as part of `PROV-BACKFILL-401-029` (completed 2025-11-27).