StellaOps Attestor
Attestor converts signed DSSE evidence from the Signer into transparency-log proofs and verifiable reports for every downstream surface (Policy Engine, Export Center, CLI, Console, Scheduler). It is the trust backbone that proves SBOM, scan, VEX, and policy artefacts were signed, witnessed, and preserved without tampering.
Notable capabilities & posture
- Repro Bundle profile: the Repro Bundle profile contract combines SLSA v1 + in-toto + DSSE + optional Rekor, with offline parity and fail-closed policy gates.
- PostgreSQL-backed runtime: canonical attestation entries, identity-watchlist state, and bulk-verification jobs are persisted in PostgreSQL; the non-testing host runs the durable bulk worker (see Storage and API sections).
- Canonical event:
attestor.logged@1is the current Platform Events payload — keep verification workflows aligned to it. - Observability assets: an observability runbook and dashboard ship under
operations/for offline import.
Why it exists
- Evidence first: organisations need portable, verifiable attestations that prove build provenance, SBOM availability, policy verdicts, and VEX statements.
- Policy enforcement: verification policies ensure only approved issuers, key types, witnesses, and freshness windows are accepted.
- Sovereign/offline-ready: Attestor archives envelopes, signatures, and proofs so air-gapped deployments can replay verification without contacting external services.
Roles & surfaces
- Subjects: immutable digests for container images, SBOMs, reports, and policy bundles.
- Issuers: builders, scanners, policy engines, or operators signing DSSE envelopes using keyless (Fulcio), KMS/HSM, or FIDO2 keys.
- Consumers: CLI/SDK, Console, Export Center, Scanner, Policy Engine, and Notify retrieving verification bundles or triggering policy checks.
- Scopes: WebService authorization policies (
AttestorWebServiceComposition.cs) keep the internal namesattestor:read,attestor:verify, andattestor:write. Their canonical Authority claim values areattest:readfor read/verify andattest:createfor writes (create also satisfies reads), or a configured StellaOps service-to-service bypass. Identity-watchlist endpoints use separatewatchlist:*policy names backed primarily by canonicaltrust:*claims. Every call may additionally require mTLS (security.mtls.requireClientCertificate, defaulttrue).
Supported payloads
StellaOps.BuildProvenance@1,StellaOps.SBOMAttestation@1StellaOps.ScanResults@1,StellaOps.VEXAttestation@1StellaOps.PolicyEvaluation@1,StellaOps.RiskProfileEvidence@1These versioned schema identifiers are generated byStellaOps.Attestor.Types(see the generator’squalifiedVersionregistrations) and several are also referenced as constants inAttestationChain.cs. All predicates capture subjects, issuer metadata, policy context, materials, optional witnesses, and versioned schemas.- In-toto predicate URIs are tracked separately in the predicate type registry (
proofchain.predicate_type_registry, seeded by migration002_add_predicate_type_registry.sql), spanningstella-core,stella-proof,stella-delta,ecosystem(SPDX/CycloneDX/SLSA), andintotocategories. Discover them viaGET /api/v1/attestor/predicates(and/{uri}). - Routing/validation is handled by
PredicateTypeRouter; an unregistered predicate yields a validation error (“Unsupported predicate type: …”). (There is no422 predicate_unsupportedresponse in the WebService; submission validation failures surface as400 Bad Requestwith acodeextension.)
API surface (WebService)
Minimal-API endpoints (AttestorWebServiceEndpoints.cs, PredicateRegistryEndpoints.cs, WatchlistEndpoints.cs) and MVC controllers (Controllers/). Scope shown is the policy required; verify/read are satisfied by higher scopes (see Security hardening).
- Submission & signing (
attestor:write):POST /api/v1/rekor/entries,POST /api/v1/attestations:sign,POST /api/v1/attestor/links(in-toto),POST /api/v1/attestations:export-build(SPDX 3.0.1 Build Profile). - Retrieval & listing (
attestor:read):GET /api/v1/attestations,GET /api/v1/attestations/{uuid},GET /api/v1/rekor/entries/{uuid}(both support?refresh=true),GET /api/v1/attestor/predicatesand/{uri}. - Verification:
POST /api/v1/rekor/verify(attestor:verify); bulkPOST /api/v1/rekor/verify:bulk+GET /api/v1/rekor/verify:bulk/{jobId}(attestor:write). OutsideTesting,AddAttestorRuntimePersistencereplaces the in-memory default withPostgresBulkVerificationJobStoreand the host runsBulkVerificationWorker. - Bundle export/import (
attestor:read/attestor:write):POST /api/v1/attestations:export,POST /api/v1/attestations:import. - External transparency (
attestor:read/attestor:write):GET/POST /api/v1/transparency/targets,…/{targetId},…:enable/…:disable,POST /api/v1/transparency/external-sync:run,GET /api/v1/transparency/external-sync/reports[/{batchId}], and the controlled-media…/exchange/schedules,…/exchange/relay-imports,…/exchange/imports:validate,…/exchange/imports:apply,GET …/exchange/batches[/{batchId}]. - Identity watchlist (
watchlist:read/watchlist:write):WatchlistEndpoints.cs. - Controllers:
api/v1/bundles,api/v1/chains, andinternal/api/v1/exceptions/*remain excluded prototypes because their required durable services are not production-composed.api/v1/proofsis active and backed by the Attestor-owned, tenant-partitioned PostgreSQL proof projection; its subject-chain route returns a deterministic graph or a typed RFC 7807 404 for an honest empty subject. Bareproofsandverifyremain explicit 501 responses.anchorsis also an explicit 501 management stub.internal/api/v1/attestations/verdictis implemented and flag-gated.
Trust & envelope model
- DSSE envelopes are canonicalised, hashed, and stored alongside the Rekor UUID, index, and proof.
- Signature modes span keyless (Fulcio), keyful (KMS/HSM), and hardware-backed (FIDO2). Multiple signatures are supported per envelope.
- Proofs include Merkle inclusion path, checkpoint metadata, optional witness endorsements, and cached verification verdicts.
- Canonical envelope/provenance custody and replay use the implemented PostgreSQL/archive/EvidenceLocker paths. A separate filesystem-backed ProofChain CAS is registered as partial infrastructure, but no production SBOM/VEX/attestation producer currently calls it; do not treat it as a live unified artifact service.
Security hardening
attestor:write,attestor:verify, andattestor:readpolicies are enforced per endpoint. The colon-named policies require canonicalattest:createorattest:readclaims; submissions remain create-only, while create also satisfies read/verify (AttestorWebServiceComposition.cs).- JSON content-type is mandatory on mutating endpoints; non-JSON bodies return
415withcode = unsupported_media_type(IsJsonContentType/UnsupportedMediaTypeResult). - DSSE payloads are capped at 2 MiB (
submissionLimits.maxPayloadBytes, default2 * 1024 * 1024), certificate chains at six entries (maxCertificateChainEntries = 6), and each envelope may carry up to six signatures (maxSignatures = 6) to contain parsing abuse (AttestorOptions.SubmissionLimitOptions). - Rate limiting uses per-policy token buckets keyed off
quotas.perCaller:attestor-submissions,attestor-verifications,attestor-reads, and a dedicatedattestor-bulklimiter for bulk verification (AttestorWebServiceComposition.cs).
UI, CLI, and SDK workflows
- Console: Evidence browser, verification reports, chain-of-custody graph, issuer/key management, attestation workbench, and bulk verification surfaces. The non-testing bulk path uses the PostgreSQL job store and hosted worker.
- CLI / SDK:
stella attest build|attach|verify|verify-offline|list|fetch|predicates(plusfix-chainand patch-attestation subcommands) for OCI artifact attestations, and a separatestella attestor transparency …group (targets,sync,receipts,exchange) for external transparency mirror management (AttestCommandGroup.cs,AttestorTransparencyCommandGroup.cs). There is noattest signorattest keysubcommand; signing happens via the WebService/api/v1/attestations:signendpoint and key management is administered elsewhere. Bundle export usesstella attest fetch … attestation-bundleplus language SDKs for build-pipeline and offline verification scripts. - Policy Studio: Verification policies author required predicate types, issuers, witness requirements, and freshness windows; simulations show enforcement impact. Reference:
guides/timestamp-policy.mdfor RFC-3161 policy assertions.
Storage, offline & air-gap posture
- PostgreSQL stores canonical attestation entries in
attestor.entries, legacy-drain compatibility rows inattestor.rekor_submission_queue, watchlist state inattestor.identity_watchlist/attestor.identity_alert_dedup, local/external transparency state inattestor.local_transparency_entries,attestor.external_transparency_targets,attestor.external_transparency_mirror_receipts, andattestor.transparency_exchange_batches, and proof-chain evidence in theproofchainschema (trust_anchors,sbom_entries,dsse_envelopes,spines,rekor_entries,predicate_type_registry); startup migrations (StellaOps.Attestor.Persistence/Migrations/,001–006) are the runtime authority. New publication does not enqueue the legacy queue: it commits locally and optionally mirrors through durable external receipts. Audit events flow through the shared audit-emission pipeline (StellaOps.Audit.Emission.Audited(AuditModules.Attestor, …)), routed to the Timeline unified audit sink, not a module-local audit table — the legacyproofchain.audit_logtable was created in001_initial_schema.sqlthen dropped in migration004_drop_deprecated_audit_log.sql. - Production composition must call
AddAttestorRuntimePersistence(...)after infrastructure registration soIAttestorEntryRepositoryresolves toPostgresAttestorEntryRepository.AddAttestorInfrastructure()intentionally does not provide an in-memory entry repository default; test/dev harnesses must opt into in-memory repositories explicitly. - Attestation bundles are exported/imported through the WebService (
POST /api/v1/attestations:exportand:import, bothattestor:read/attestor:writeandIAttestorBundleService) for Offline Kit delivery. (There is nostella export attestation-bundleCLI subcommand; thestella exportgroup exposesaudit,lineage,risk, andevidence-pack.) - Transparency logs can be mirrored to operator-approved external targets and exchanged across air-gaps via the controlled-media schedule/relay-import/import flows (
/api/v1/transparency/exchange/*); offline mode records gaps and provides compensating controls.
Observability & performance
- Metrics (Meter
StellaOps.Attestor, dotted instrument names —AttestorMetrics.cs):attestor.submit_total/attestor.submit_latency_seconds,attestor.sign_total/attestor.sign_latency_seconds,attestor.verify_total/attestor.verify_latency_seconds,attestor.verify_cache_lookup_total/attestor.verify_cache_hit_total,attestor.dedupe_hits_total,attestor.bulk_jobs_total/attestor.bulk_items_total/attestor.bulk_job_duration_seconds, theattestor.rekor_*family (e.g.attestor.rekor_inclusion_verify_total,attestor.rekor_checkpoint_verify_latency_seconds,attestor.rekor_queue_wait_seconds,attestor.rekor_dead_letter_total),attestor.external_transparency_sync_runs_total,attestor.time_skew_seconds, andattestor.errors_total. (The olderattestor_submission_total/attestor_verify_seconds/attestor_cache_hit_ratio/attestor_rekor_latency_secondsnames are not emitted.) - Logs capture tenant, issuer, subject digests, Rekor UUID, proof status, and policy verdict.
- Performance target: ≥1 000 envelopes/minute per worker with cached verification, batched operations, and concurrency controls.
- Observability assets:
operations/observability.mdandoperations/dashboards/attestor-observability.json(offline import).
Key integrations
- Signer (DSSE source), Authority (scopes & tenancy), Export Center (attestation bundles), Policy Engine (verification policies), Scanner/Excititor (subject evidence), Notify (key rotation & verification alerts), Observability stack (dashboards/alerts).
Backlog references
- DOCS-ATTEST-73-001 … DOCS-ATTEST-75-002 (Attestor console, key management, air-gap bundles) — see
implementation_plan.md. - EXPORT-ATTEST-75-002 (Export Center attestation packaging) — tracked under the Export Center module.
Epic alignment
- Epic 19 – Attestor Console: console experience, verification APIs, issuer/key governance, transparency integration, and offline bundles.
- Epic 10 – Export Center: provenance alignment so exports carry signed manifests and attestation bundles.
Implementation Status
Delivery Phases:
- Phase 1 (Foundations) – Complete: service skeleton, DSSE ingestion, Rekor client, and cache layer operational
- Phase 2 (Policies & UI) – Blocked: Policy Studio integration and CLI commands awaiting upstream dependencies
- Phase 3 (Scan & VEX support) – Complete: SBOM, VEX, and scan result predicates integrated
- Phase 4 (Transparency & keys) – In progress: key event notifications, witness endorsements, and rotation workflows
- Phase 5 (Bulk & air gap) – Blocked: Export Center contract required for attestation bundle workflows
- Phase 6 (Performance & hardening) – Not started: benchmarks and incident playbooks pending
Acceptance Criteria:
- Service ingests DSSE envelopes, logs to transparency, returns proofs with deterministic hashes
- Verification APIs/CLI/UI validate signatures, inclusion proofs, policy compliance with caching
- Performance target: ≥1k envelopes/minute per worker with horizontal scaling
- Export Center and Offline Kit workflows bundle attestations for offline replay
- Observability coverage: metrics, traces, logs, audit events, and alerts
Key Risks & Mitigations:
- Key compromise: enforce hardware-backed keys, rotation procedures, revocation checks, incident runbooks
- Parser bugs: fuzz DSSE/predicate schemas, strict validation, fail closed
- Transparency outage: mirror logs, witness endorsements, queue submissions with exponential backoff
- Policy complexity: ship starter policies, simulation tooling, documented scenarios
- Offline gaps: archive bundles and proof material, surface gaps to operators, document compensating controls
