Assurance Evidence Export v1

This contract is the catalogue of discoverable export profiles for Stella Ops Assurance packs — the read-only surface that tells operators and integrators which regulator-facing bundles (NIS2 SoA, DORA reports, CRA technical files) a tenant can export and whether that tenant is ready to do so. It is for ExportCenter integrators, Web/CLI authors building compliance surfaces, and auditors verifying export readiness. Run execution and signed-bundle output are owned by each profile’s route/adapter; this surface only describes and gates them.

Contract ID: CONTRACT-ASSURANCE-EVIDENCE-EXPORT-V1-003 Status: Implemented (profile discovery + readiness); export run execution per profile is delivered by the owning route/adapter. Owner: ExportCenter Guild Schema version: assurance-evidence-export-v1

Implementing symbols (ground truth): StellaOps.ExportCenter.WebService.AssuranceExports.AssuranceExportProfileRegistry (profile catalogue + fail-closed readiness), AssuranceExportEndpoints (REST surface), AssuranceExportModels (response DTOs), AssuranceExportOptions (config). Wired in Program.cs (AddAssuranceExportProfiles / MapAssuranceExportEndpoints).

Purpose

assurance-evidence-export-v1 describes discoverable export profiles for Assurance packs. ExportCenter owns profile discovery, export readiness, and compatibility with existing pack-specific export contracts. Run lifecycle and signed bundle output are owned by each profile’s route/adapter (for example the NIS2 SoA run endpoints under /v1/exports/nis2/soa); the assurance discovery surface itself is read-only.

This contract does not define the payload of a NIS2 SoA, DORA report, or CRA technical file. It points to payload contracts such as:

Discovery API

ExportCenter exposes the assurance discovery surface under /v1/exports/assurance. All routes are GET, return JSON, and require the export.viewer scope (StellaOpsResourceServerPolicies.ExportViewer). The tenant is resolved from the authenticated principal/request; a missing tenant returns 400 tenant_not_found, and an unknown profile returns 404 assurance_export_profile_not_found.

MethodRouteReturnsNotes
GET/v1/exports/assurance/profilesAssuranceExportProfileListResponseOptional ?frameworkId= filter (case-insensitive). Response wraps items[] and totalCount.
GET/v1/exports/assurance/profiles/{profileId}AssuranceExportProfileResponseSingle profile by id.
GET/v1/exports/assurance/profiles/{profileId}/readinessAssuranceExportReadinessResponseFail-closed readiness for the current tenant.

The list response shape:

{
  "items": [ /* AssuranceExportProfileResponse */ ],
  "totalCount": 8
}

Profile Fields

The profile object is AssuranceExportProfileResponse. The wire field names below are the [JsonPropertyName(...)] values on that record.

FieldTypeRequiredNotes
schemaVersionstringyesMUST be assurance-evidence-export-v1.
profileIdstringyesStable export profile id.
frameworkIdstringyesFramework id such as nis2, dora, or cra.
packIdstringyesPack id from assurance-pack-v1.
exportTypestringyesExport kind such as statement-of-applicability or technical-file.
displayNamestringyesOperator-visible profile name.
adapterIdstringyesExportCenter adapter id or typed endpoint owner.
schemaIdstringyesPayload contract id.
signingRequiredbooleanyesTrue when a successful production export must be signed. (All current built-in profiles set this to true.)
supportsOfflineVerificationbooleanyesTrue when the exported artifact includes verifier metadata and trust-root expectations for offline verification. (All current built-in profiles set this to true.)
deterministicInputs[]string arrayyesRequired stable input refs.
readinessPrerequisites[]string arrayyesSetup/readiness ids from assurance-setup-prerequisites-v1.
outputArtifacts[]object arrayyesBundle, archive, or signature outputs. Each entry is { kind, mediaType?, payloadType? } (AssuranceExportArtifactDescriptor); mediaType and payloadType are both nullable.
offlineVerifierobjectyes{ mode, payloadTypeId } (AssuranceExportOfflineVerifier). mode is the verifier mode string (for example signer-eu-offline-verifier or hmac-dsse-offline-verifier).
compatibilityRoutes[]string arrayyesExisting API/CLI routes retained for compatibility. (Non-empty for every built-in profile.)

Proposed (not in the current AssuranceExportProfileResponse DTO): evidenceCoverage[] per-scope coverage lines are described below but are not emitted by the implemented profile or readiness responses today. See the Evidence Coverage Lines section for the forward design.

Readiness Response

GET .../readiness returns AssuranceExportReadinessResponse:

FieldTypeNotes
schemaVersionstringAlways assurance-evidence-export-v1.
profileIdstringEchoes the requested profile.
tenantIdstringTenant the readiness was computed for.
frameworkIdstringFrom the profile.
packIdstringFrom the profile.
exportTypestringFrom the profile.
statestringexport-ready or blocked (see below).
signedExportReadybooleanTrue when all signed-export prerequisites are met.
livePublicationReadyboolean | nullSeparate live-publication lane. null when the profile has no live-publication concept (NIS2 SoA/effectiveness, all DORA profiles); populated only for CRA profiles.
reasonCodes[]string arrayDistinct, ordinally sorted reason codes (convenience projection of reasons[].code).
reasons[]object array{ code, category, summary, ownerModule, blocking } (AssuranceExportReadinessReason), ordinally sorted by code.
secretValuesExposedbooleanAlways false; asserted so readiness can never leak storage roots or signing key ids.

Each reason category is one of signed-export, live-publication, or source-data. ownerModule names the module responsible for clearing the reason (for example ExportCenter, Authority, Notify, Router, EvidenceLocker, Findings).

Readiness states

The state field has exactly two values in the current implementation:

StateMeaning
export-readyAll blocking signed-export reasons are cleared (signedExportReady == true).
blockedAt least one blocking signed-export prerequisite is missing.

A configured reason code (not a state) is appended to mark that sealed ExportCenter settings are present, and CRA live-publication preflight also emits a configured reason in the live-publication category. Unknown profiles do not produce a state — readiness for an unrecognised profile returns 404 assurance_export_profile_not_found rather than an unavailable/disabled state.

Note: earlier drafts listed unavailable, disabled, and configured as first-class states. The implementation does not emit those as state values; unavailable/disabled semantics surface as a 404 or as blocking reason codes, and configured is a non-blocking reason code.

Readiness responses MUST fail closed. Missing storage, signing, trust roots, or source snapshots cannot be treated as successful export evidence.

Example: NIS2 SoA blocked (no configuration)

{
  "schemaVersion": "assurance-evidence-export-v1",
  "profileId": "nis2.statement-of-applicability",
  "tenantId": "tenant-a",
  "frameworkId": "nis2",
  "packId": "nis2",
  "exportType": "statement-of-applicability",
  "state": "blocked",
  "signedExportReady": false,
  "livePublicationReady": null,
  "reasonCodes": [
    "authority-profile-url-missing",
    "signing-key-missing",
    "signing-provider-missing",
    "storage-root-missing",
    "tenant-export-trust-roots-missing"
  ],
  "reasons": [
    {
      "code": "authority-profile-url-missing",
      "category": "signed-export",
      "summary": "Authority tenant compliance profile access is not configured.",
      "ownerModule": "ExportCenter",
      "blocking": true
    }
  ],
  "secretValuesExposed": false
}

Evidence Coverage Lines (Proposed)

Status: Proposed / not yet implemented. Neither AssuranceExportProfileResponse nor AssuranceExportReadinessResponse currently carries an evidenceCoverage[] field. The shape below is the forward design for when ExportCenter and route-owned profiles begin emitting coverage lines.

Export profile and readiness responses may include evidenceCoverage[] lines:

{
  "scope": "operator-observed-estate",
  "status": "covered",
  "summary": "Release, asset, SBOM, VEX, policy, and evidence bundle inputs are present.",
  "reasonCodes": []
}

Allowed scope values are defined by assurance-pack-v1. The status value is one of covered, partial, operator-required, unavailable, or unknown. NIS2/DORA exports must not collapse operator-required lines into Stella-native evidence. Until ExportCenter and route-owned DORA profiles emit coverage lines, Web/CLI may show descriptor-level scope metadata and keep live coverage empty.

Built-In Export Profiles

AssuranceExportProfileRegistry.BuildProfiles() publishes these eight built-in Assurance descriptors. The list is returned sorted by profileId (ordinal). All built-in profiles set signingRequired: true and supportsOfflineVerification: true.

Profile idFrameworkPackExport typeadapterIdschemaIdofflineVerifier.modeCompatibility routes
cra.conformity-dossiercracra.technical-documentationconformity-dossiercra:conformity-dossierconformity-dossier-v1signer-eu-offline-verifierstella export conformity-dossier
cra.technical-filecracra.technical-documentationtechnical-filecra:tech-filecra-tech-file-v1signer-eu-offline-verifierstella export cra-tech-file
dora.info-sharingdoradorainfo-sharingexportcenter.dora.info-sharingdora-info-sharing-event-v1signer-eu-offline-verifierstella export dora-info-sharing; stella verify dora-info-sharing
dora.major-incident-reportdoradoramajor-incident-reportexportcenter.dora.major-incident-reportdora-major-incident-report.v1signer-eu-offline-verifierstella export dora-incident-report; stella verify dora-incident-report
dora.roidoradoraregister-of-informationexportcenter.dora.roidora-roi-v1signer-eu-offline-verifierstella export dora-roi; stella verify dora-roi
dora.tlpt-evidence-packdoradoratlpt-evidence-packexportcenter.dora.tlpt-evidence-packtlpt-evidence-pack.v1signer-eu-offline-verifierstella tlpt pack; stella verify tlpt-pack
nis2.effectiveness-reportnis2nis2effectiveness-reportexportcenter.nis2.effectiveness-reportnis2-effectiveness-report-v1hmac-dsse-offline-verifierstella export nis2-effectiveness-report
nis2.statement-of-applicabilitynis2nis2statement-of-applicabilityexportcenter.nis2.soanis2-soa-v1signer-eu-offline-verifierGET /v1/exports/nis2/soa/profile; POST /v1/exports/nis2/soa/runs; GET /v1/exports/nis2/soa/runs/{runId}; GET /v1/exports/nis2/soa/runs/{runId}/bundle

Notes grounded in source:

DORA readiness reason lanes

DORA profile readiness exposes a single state plus separate reason categories for signed-export readiness and source/live-publication blockers. Built-in DORA profiles fail closed with these blocking source-data reason codes until the owning workflow supplies inputs:

ProfileBlocking reason codes (source-data, plus live-publication where noted)
dora.roidora-roi-register-source-missing, dora-roi-owner-approval-missing, dora-roi-schema-mapping-missing
dora.major-incident-reportdora-major-incident-report-source-missing, dora-major-incident-report-owner-approval-missing, dora-major-incident-report-schema-mapping-missing
dora.info-sharingdora-info-sharing-source-missing, dora-info-sharing-subscriber-approval-missing, dora-info-sharing-schema-mapping-missing, plus dora-info-sharing-channel-disabled (live-publication)
dora.tlpt-evidence-packdora-tlpt-evidence-pack-scope-missing, dora-tlpt-evidence-pack-white-team-signoff-missing, dora-tlpt-evidence-pack-schema-mapping-missing

A missing official schema/taxonomy mapping (the *-schema-mapping-missing codes) must block any claim that the artifact validated against official XSD/XBRL packages. Note: the current implementation reports DORA readiness via the single state/signedExportReady pair with these category-tagged reason codes; livePublicationReady is null for all DORA profiles (only CRA profiles populate the live-publication boolean).

Signed Export Versus Publication

Export readiness is not the same as live public publication readiness.

Example: NIS2 Statement of Applicability

{
  "schemaVersion": "assurance-evidence-export-v1",
  "profileId": "nis2.statement-of-applicability",
  "frameworkId": "nis2",
  "packId": "nis2",
  "exportType": "statement-of-applicability",
  "displayName": "NIS2 Statement of Applicability",
  "adapterId": "exportcenter.nis2.soa",
  "schemaId": "nis2-soa-v1",
  "signingRequired": true,
  "supportsOfflineVerification": true,
  "deterministicInputs": [
    "policy.control-register.snapshot",
    "authority.tenant-compliance-profile",
    "evidence-locker.bundle-ref"
  ],
  "readinessPrerequisites": ["nis2.soa.live-export"],
  "outputArtifacts": [
    { "kind": "bundle", "mediaType": "application/vnd.stellaops.nis2.soa.bundle.v1+json" },
    { "kind": "signature", "mediaType": null, "payloadType": "application/vnd.stellaops.nis2.soa.v1+json" }
  ],
  "offlineVerifier": {
    "mode": "signer-eu-offline-verifier",
    "payloadTypeId": "nis2-soa-v1"
  },
  "compatibilityRoutes": [
    "GET /v1/exports/nis2/soa/profile",
    "POST /v1/exports/nis2/soa/runs",
    "GET /v1/exports/nis2/soa/runs/{runId}",
    "GET /v1/exports/nis2/soa/runs/{runId}/bundle"
  ]
}

Example: CRA Technical File

{
  "schemaVersion": "assurance-evidence-export-v1",
  "profileId": "cra.technical-file",
  "frameworkId": "cra",
  "packId": "cra.technical-documentation",
  "exportType": "technical-file",
  "displayName": "CRA Technical File",
  "adapterId": "cra:tech-file",
  "schemaId": "cra-tech-file-v1",
  "signingRequired": true,
  "supportsOfflineVerification": true,
  "deterministicInputs": [
    "release.product-ref",
    "release.version",
    "evidence-locker.bundle-ref",
    "policy.control-register.ref"
  ],
  "readinessPrerequisites": [
    "cra.technical-documentation.signed-export",
    "cra.product-security.publication"
  ],
  "outputArtifacts": [
    { "kind": "archive", "mediaType": "application/vnd.stellaops.cra.tech-file.v1+tar+gzip" },
    { "kind": "signature", "mediaType": "application/vnd.dsse+json", "payloadType": "application/vnd.stellaops.cra.tech-file.index.v1+json" }
  ],
  "offlineVerifier": {
    "mode": "signer-eu-offline-verifier",
    "payloadTypeId": "cra-tech-file-v1"
  },
  "compatibilityRoutes": ["stella export cra-tech-file"]
}

Configuration & Authorization

Determinism Rules