22 KiB
I’m sharing this because it closely aligns with your strategy for building strong supply‑chain and attestation moats — these are emerging standards you’ll want to embed into your architecture now.
DSSE + in‑toto: The event‑spine
- The Dead Simple Signing Envelope (DSSE) spec defines a minimal JSON envelope for signing arbitrary data — “transparent transport for signed statements”. (GitHub)
- The in‑toto Attestation model builds on DSSE as the envelope, with a statement + predicate about the artifact (e.g., build/cohort metadata). (Legit Security)
- In your architecture: using DSSE‑signed in‑toto attestations across Scanner → Sbomer → Vexer → Scorer → Attestor gives you a unified “event spine” of provenance and attestations.
- That means every step emits a signed statement, verifiable, linking tooling. Helps achieve deterministic replayability and audit‑integrity.
CycloneDX v1.7: SBOM + cryptography assurance
- Version 1.7 of CycloneDX was released October 21, 2025 and introduces advanced cryptography, data‑provenance transparency, and IP visibility for the software supply chain. (CycloneDX)
- It introduces a “Cryptography Registry” to standardize naming / classification of crypto algorithms in BOMs — relevant for PQC readiness, global cryptographic standards like GOST/SM, etc. (CycloneDX)
- If you emit SBOMs in CycloneDX v1.7 format (and include CBOM/crypto details), you’re aligning with modern supply‑chain trust expectations — satisfying your moat #1 (crypto‑sovereign readiness) and #2 (deterministic manifests).
Sigstore Rekor v2: Logging the provenance chain
- Rekor v2 reached GA on October 10 2025; the redesign introduces a “tile‑backed transparency log implementation” to simplify ops and reduce costs. (Sigstore Blog)
- Rekor supports auditing of signing events, monitors to verify append‑only consistency, and log inclusion proofs. (Sigstore)
- By bundling your provenance/SBOM/VEX/scores and recording those in Rekor v2, you’re closing your chain of custody with immutable log entries — supports your “Proof‑of‑Integrity Graph” moat (point #4).
Why this matters for your architecture
- With each scan or stage (Scanner → Sbomer → Vexer → Scorer → Attestor) producing a DSSE‑signed in‑toto statement, you have a canonical spine of events.
- Emitting SBOMs in CycloneDX v1.7 ensures you not only list components but crypto metadata, attestation pointers, and versions ready for future‑proofing.
- Recording all artifacts (attestations, SBOM, VEX, scores) into Rekor v2 gives you external public verifiability and auditability — minimal trust surface, maximal transparency.
- These standards map directly to several of your moats: crypto‑sovereign readiness, deterministic replayable scans, provenance graphs, trust‑ledger.
If you like, I can pull together mappings of your internal modules (Scanner, Sbomer, Vexer, etc) to these standards and provide a reference implementation skeleton in .NET 10 (you indicated you’re working with that).
Got it — let’s turn your vision into something devs can actually build against.
Below is a concrete implementation plan you can paste into an internal doc / ticketing system and refine into epics & stories.
0. Assumptions & Target End‑State
Assumptions
-
Services:
Scanner → Sbomer → Vexer → Scorer → Attestor(plus shared infra). -
Language: .NET (8/10) for your services.
-
You want:
- DSSE‑signed in‑toto attestations as the event “spine”. (GitHub)
- CycloneDX 1.7 SBOM + VEX for inventory + exploitability. (CycloneDX)
- Rekor v2 as the transparency log, with Sigstore bundles for offline verification. (Sigstore Blog)
Target picture
For every artifact A (image / binary / model):
-
Each stage emits a DSSE‑signed in‑toto attestation:
- Scanner → scan predicate
- Sbomer → CycloneDX 1.7 SBOM predicate
- Vexer → VEX predicate
- Scorer → score predicate
- Attestor → final decision predicate
-
Each attestation is:
- Signed with your keys or Sigstore keyless.
- Logged to Rekor (v2) and optionally packaged into a Sigstore bundle.
-
A consumer can:
- Fetch all attestations for A, verify signatures + Rekor proofs, read SBOM/VEX, and understand the score.
The rest of this plan is: how to get there step‑by‑step.
1. Core Data Contracts (Must Be Done First)
1.1 Define the canonical envelope and statement
Standards to follow
- DSSE Envelope from secure‑systems‑lab (
envelope.proto). (GitHub) - In‑toto Attestation “Statement” model (subject + predicateType + predicate). (SLSA)
Deliverable: internal spec
Create a short internal spec (Markdown) for developers:
-
ArtifactIdentityalgorithm:sha256|sha512| etc.digest: hex string.- Optional:
name,version,buildPipelineId.
-
InTotoStatement<TPredicate>type: fixed:https://in-toto.io/Statement/v1subject: list ofArtifactIdentity.predicateType: string (URL-ish).predicate: generic JSON (stage‑specific payload).
-
DsseEnvelopepayloadType: e.g.application/vnd.in-toto+jsonpayload: base64 of the JSONInTotoStatement.signatures[]:{ keyid, sig }.
1.2 Implement the .NET representation
Tasks
-
Generate DSSE envelope types
- Use
envelope.protofrom DSSE repo and generate C# types; or reuse the GrafeasEnvelopeclass which is explicitly aligned with DSSE. (Google Cloud) - Project:
Attestations.Core.
- Use
-
Define generic Statement & Predicate types
In
Attestations.Core:public record ArtifactIdentity(string Algorithm, string Digest, string? Name = null, string? Version = null); public record InTotoStatement<TPredicate>( string _Type, IReadOnlyList<ArtifactIdentity> Subject, string PredicateType, TPredicate Predicate ); public record DsseSignature(string KeyId, byte[] Sig); public record DsseEnvelope( string PayloadType, byte[] Payload, IReadOnlyList<DsseSignature> Signatures ); -
Define predicate contracts for each stage
Example:
public static class PredicateTypes { public const string ScanV1 = "https://example.com/attestations/scan/v1"; public const string SbomV1 = "https://example.com/attestations/sbom/cyclonedx-1.7"; public const string VexV1 = "https://example.com/attestations/vex/cyclonedx"; public const string ScoreV1 = "https://example.com/attestations/score/v1"; public const string VerdictV1= "https://example.com/attestations/verdict/v1"; }Then define concrete predicates:
ScanPredicateV1SbomPredicateV1(likely mostly a pointer to a CycloneDX doc)VexPredicateV1(pointer to VEX doc + summary)ScorePredicateV1VerdictPredicateV1(attest/deny + reasoning)
Definition of done
- All services share a single
Attestations.Corelibrary. - There is a test that serializes + deserializes
InTotoStatementandDsseEnvelopeand matches the JSON format expected by in‑toto tooling.
2. Signing & Key Management Layer
2.1 Abstraction: decouple from crypto choice
Create an internal package: Attestations.Signing.
public interface IArtifactSigner
{
Task<DsseEnvelope> SignStatementAsync<TPredicate>(
InTotoStatement<TPredicate> statement,
CancellationToken ct = default);
}
public interface IArtifactVerifier
{
Task VerifyAsync(DsseEnvelope envelope, CancellationToken ct = default);
}
Backends to implement:
-
KMS‑backed signer (e.g., AWS KMS, GCP KMS, Azure Key Vault).
-
Sigstore keyless / cosign integration:
- For now you can wrap the cosign CLI, which already understands in‑toto attestations and Rekor. (Sigstore)
- Later, replace with a native HTTP client against Sigstore services.
2.2 Key & algorithm strategy
- Default: ECDSA P‑256 or Ed25519 keys, stored in KMS.
- Wrap all usage via
IArtifactSigner/IArtifactVerifier. - Keep room for PQC migration by never letting services call crypto APIs directly; only use the abstraction.
Definition of done
-
CLI or small test harness that:
- Creates a dummy
InTotoStatement, - Signs it via
IArtifactSigner, - Verifies via
IArtifactVerifier, - Fails verification if payload is tampered.
- Creates a dummy
3. Service‑by‑Service Integration
For each component we’ll define inputs → behavior → attestation output.
3.1 Scanner
Goal For each artifact, emit a scan attestation with normalized findings.
Tasks
-
Extend Scanner to normalize findings to a canonical model:
- Vulnerability id (CVE / GHSA / etc).
- Affected package (
purl, version). - Severity, source (NVD, OSV, etc).
-
Define
ScanPredicateV1:public record ScanPredicateV1( string ScannerName, string ScannerVersion, DateTimeOffset ScanTime, string ScanConfigurationId, IReadOnlyList<ScanFinding> Findings ); -
After each scan completes:
- Build
ArtifactIdentityfrom the artifact digest. - Build
InTotoStatement<ScanPredicateV1>withPredicateTypes.ScanV1. - Call
IArtifactSigner.SignStatementAsync. - Save
DsseEnvelopeto an Attestation Store (see section 5). - Publish an event
scan.attestation.createdon your message bus with the attestation id.
- Build
Definition of done
- Every scan results in a stored DSSE envelope with
ScanV1predicate. - A consumer service can query by artifact digest and get all scan attestations.
3.2 Sbomer (CycloneDX 1.7)
Goal Generate CycloneDX 1.7 SBOMs and attest to them.
CycloneDX provides a .NET library and tools for producing and consuming SBOMs. (GitHub) CycloneDX 1.7 adds cryptography registry, data‑provenance and IP transparency. (CycloneDX)
Tasks
-
Add CycloneDX .NET library
- NuGet:
CycloneDX.Core(and optionalCycloneDX.Utils). (NuGet)
- NuGet:
-
SBOM generation process
-
Input: artifact digest + build metadata (e.g., manifest, lock file).
-
Generate a CycloneDX 1.7 SBOM:
- Fill
metadata.component,bomRef, and dependency graph. - Include crypto material using the Cryptography Registry (algorithms, key sizes, modes) when relevant. (CycloneDX)
- Include data provenance (tool name/version, timestamp).
- Fill
-
-
Storage
- Store SBOM documents (JSON) in object storage:
sboms/{artifactDigest}/cyclonedx-1.7.json. - Index them in the Attestation DB (see 5).
- Store SBOM documents (JSON) in object storage:
-
SbomPredicateV1public record SbomPredicateV1( string Format, // "CycloneDX" string Version, // "1.7" Uri Location, // URL to the SBOM blob string? HashAlgorithm, string? HashDigest // hash of the SBOM document itself ); -
After SBOM generation:
- Create statement with
PredicateTypes.SbomV1. - Sign via
IArtifactSigner. - Store DSSE envelope + publish
sbom.attestation.created.
- Create statement with
Definition of done
-
For any scanned artifact, you can fetch:
- A CycloneDX 1.7 SBOM, and
- A DSSE‑signed in‑toto SBOM attestation pointing to it.
3.3 Vexer (CycloneDX VEX / CSAF)
Goal Turn “raw vulnerability findings” into VEX documents that say whether each vulnerability is exploitable, using CycloneDX VEX representation. (CycloneDX)
Tasks
-
Model VEX status mapping
-
Example statuses:
affected,not_affected,fixed,under_investigation. -
Derive rules from:
- Reachability analysis, config, feature usage.
- Business logic (e.g., vulnerability only affects optional module not shipped).
-
-
Generate VEX docs
- Use the same CycloneDX .NET library to emit CycloneDX VEX documents.
- Store them:
vex/{artifactDigest}/cyclonedx-vex.json.
-
VexPredicateV1public record VexPredicateV1( string Format, // "CycloneDX-VEX" string Version, Uri Location, string? HashAlgorithm, string? HashDigest, int TotalVulnerabilities, int ExploitableVulnerabilities ); -
After VEX generation:
- Build statement with
PredicateTypes.VexV1. - Sign, store, publish
vex.attestation.created.
- Build statement with
Definition of done
-
For an artifact with scan results, there is a VEX doc and attestation that:
- Marks each vulnerability with exploitability status.
- Can be consumed by
Scorerto prioritize risk.
3.4 Scorer
Goal Compute a trust/risk score based on SBOM + VEX + other signals, and attest to it.
Tasks
-
Scoring model v1
-
Inputs:
- Count of exploitable vulns by severity.
- Presence/absence of required attestations (scan, sbom, vex).
- Age of last scan.
-
Output:
RiskScore(0–100 or letter grade).RiskTier(“low”, “medium”, “high”).- Reasons (top 3 contributors).
-
-
ScorePredicateV1public record ScorePredicateV1( double Score, string Tier, DateTimeOffset CalculatedAt, IReadOnlyList<string> Reasons ); -
When triggered (new VEX or SBOM):
- Recompute score for the artifact.
- Create attestation, sign, store, publish
score.attestation.created.
Definition of done
-
A consumer can call “/artifacts/{digest}/score” and:
- Verify the DSSE envelope,
- Read a deterministic
ScorePredicateV1.
3.5 Attestor (Final Verdict + Rekor integration)
Goal Emit the final verdict attestation and push evidences to Rekor / Sigstore bundle.
Tasks
-
VerdictPredicateV1public record VerdictPredicateV1( string Decision, // "allow" | "deny" | "quarantine" string PolicyVersion, DateTimeOffset DecidedAt, IReadOnlyList<string> Reasons, string? RequestedBy, string? Environment // "prod", "staging", etc. ); -
Policy evaluation:
- Input: all attestations for artifact (scan, sbom, vex, score).
- Apply policy (e.g., “no critical exploitable vulns”, “score ≥ 70”).
- Produce
allow/deny.
-
Rekor integration (v2‑ready)
- Rekor provides an HTTP API and CLI for recording signed metadata. (Sigstore)
- Rekor v2 uses a modern tile‑backed log for better cost/ops (you don’t need details, just that the API remains similar). (Sigstore Blog)
Implementation options:
-
Option A: CLI wrapper
- Use
rekor-clivia a sidecar container. - Call
rekor-cli uploadwith the DSSE payload or Sigstore bundle.
- Use
-
Option B: Native HTTP client
-
Generate client from Rekor OpenAPI in .NET.
-
Implement:
public interface IRekorClient { Task<RekorEntryRef> UploadDsseAsync(DsseEnvelope envelope, CancellationToken ct); } public record RekorEntryRef( string Uuid, long LogIndex, byte[] SignedEntryTimestamp);
-
-
Sigstore bundle support
-
A Sigstore bundle packages:
- Verification material (cert, Rekor SET, timestamps),
- Signature content (DSSE envelope). (Sigstore)
-
You can:
- Store bundles alongside DSSE envelopes:
bundles/{artifactDigest}/{stage}.json. - Expose them in an API for offline verification.
- Store bundles alongside DSSE envelopes:
-
-
After producing final verdict:
- Sign verdict statement.
- Upload verdict attestation (and optionally previous key attestations) to Rekor.
- Store Rekor entry ref (
uuid,index,SET) in DB. - Publish
verdict.attestation.created.
Definition of done
-
For a given artifact, you can:
- Retrieve a verdict DSSE envelope.
- Verify its signature and Rekor inclusion.
- Optionally retrieve a Sigstore bundle for fully offline verification.
4. Attestation Store & Data Model
Create an “Attestation Service” that all others depend on for reading/writing.
4.1 Database schema (simplified)
Relational schema example:
-
artifactsid(PK)algorithmdigestnameversion
-
attestationsid(PK)artifact_id(FK)stage(scan,sbom,vex,score,verdict)predicate_typedsse_envelope_jsoncreated_atsigner_key_id
-
rekor_entriesid(PK)attestation_id(FK)uuidlog_indexsigned_entry_timestamp(bytea)
-
sbomsidartifact_idformat(CycloneDX)version(1.7)locationhash_algorithmhash_digest
-
vex_documentsidartifact_idformatversionlocationhash_algorithmhash_digest
4.2 Attestation Service API
Provide a REST/gRPC API:
GET /artifacts/{algo}:{digest}/attestationsGET /artestations/{id}GET /artifacts/{algo}:{digest}/sbomGET /artifacts/{algo}:{digest}/vexGET /artifacts/{algo}:{digest}/scoreGET /artifacts/{algo}:{digest}/bundle(optional, Sigstore bundle)
Definition of done
- All other services call Attestation Service instead of touching the DB directly.
- You can fetch the full “attestation chain” for a given artifact from one place.
5. Observability & QA
5.1 Metrics
For each service:
attestations_emitted_total{stage}attestation_sign_errors_total{stage}rekor_upload_errors_totalattestation_verification_failures_total
5.2 Tests
-
Contract tests
-
JSON produced for
InTotoStatementandDsseEnvelopeis validated by:- in‑toto reference tooling.
- DSSE reference implementations. (GitHub)
-
-
End‑to‑end flow
-
Seed a mini pipeline with a test artifact:
- Build → Scan → SBOM → VEX → Score → Verdict.
-
Use an external verifier (e.g., cosign, in‑toto attestation verifier) to:
- Verify DSSE signatures.
- Verify Rekor entries and/or Sigstore bundles. (Sigstore)
-
-
Failure scenarios
- Corrupt payload (verification must fail).
- Missing VEX (policy should deny or fall back to stricter rules).
- Rekor offline (system should continue but mark entries as “not logged”).
6. Phased Rollout Plan (High‑Level)
You can translate this into epics:
-
Epic 1 – Core Attestation Platform
- Implement
Attestations.Core&Attestations.Signing. - Implement Attestation Service + DB schema.
- Build small CLI / test harness.
- Implement
-
Epic 2 – Scanner Integration
- Normalize findings.
- Emit scan attestations only (no SBOM/VEX yet).
-
Epic 3 – CycloneDX SBOMs
- Integrate CycloneDX .NET library.
- Generate 1.7 SBOMs for each artifact.
- Emit SBOM attestations.
-
Epic 4 – VEXer
- Implement VEX derivation logic + CycloneDX VEX docs.
- Emit VEX attestations.
-
Epic 5 – Scorer & Policy
- Implement scoring model v1.
- Implement policy engine.
- Emit Score + Verdict attestations.
-
Epic 6 – Rekor & Bundles
- Stand up Rekor (or integrate with public instance).
- Implement Rekor client and Sigstore bundle support.
- Wire Attestor to log final (and optionally intermediate) attestations.
-
Epic 7 – UX & Docs
-
Build UI (or CLI) to visualize:
- Artifact → SBOM → VEX → Score → Verdict.
-
Document how other teams integrate (what events to listen to, which APIs to call).
-
If you’d like, I can next:
- Turn this into Jira‑style epics & stories with acceptance criteria; or
- Draft the actual C# interfaces and a project structure (
src/Attestations.Core,src/Attestations.Signing, services, etc.).







