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:
nis2-soa-v1dora-major-incident-report-v1dora-roi-v1dora-info-sharing-event-v1tlpt-evidence-pack-v1cra-tech-file-v1conformity-dossier-v1
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.
| Method | Route | Returns | Notes |
|---|---|---|---|
| GET | /v1/exports/assurance/profiles | AssuranceExportProfileListResponse | Optional ?frameworkId= filter (case-insensitive). Response wraps items[] and totalCount. |
| GET | /v1/exports/assurance/profiles/{profileId} | AssuranceExportProfileResponse | Single profile by id. |
| GET | /v1/exports/assurance/profiles/{profileId}/readiness | AssuranceExportReadinessResponse | Fail-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.
| Field | Type | Required | Notes |
|---|---|---|---|
schemaVersion | string | yes | MUST be assurance-evidence-export-v1. |
profileId | string | yes | Stable export profile id. |
frameworkId | string | yes | Framework id such as nis2, dora, or cra. |
packId | string | yes | Pack id from assurance-pack-v1. |
exportType | string | yes | Export kind such as statement-of-applicability or technical-file. |
displayName | string | yes | Operator-visible profile name. |
adapterId | string | yes | ExportCenter adapter id or typed endpoint owner. |
schemaId | string | yes | Payload contract id. |
signingRequired | boolean | yes | True when a successful production export must be signed. (All current built-in profiles set this to true.) |
supportsOfflineVerification | boolean | yes | True 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 array | yes | Required stable input refs. |
readinessPrerequisites[] | string array | yes | Setup/readiness ids from assurance-setup-prerequisites-v1. |
outputArtifacts[] | object array | yes | Bundle, archive, or signature outputs. Each entry is { kind, mediaType?, payloadType? } (AssuranceExportArtifactDescriptor); mediaType and payloadType are both nullable. |
offlineVerifier | object | yes | { mode, payloadTypeId } (AssuranceExportOfflineVerifier). mode is the verifier mode string (for example signer-eu-offline-verifier or hmac-dsse-offline-verifier). |
compatibilityRoutes[] | string array | yes | Existing API/CLI routes retained for compatibility. (Non-empty for every built-in profile.) |
Proposed (not in the current
AssuranceExportProfileResponseDTO):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:
| Field | Type | Notes |
|---|---|---|
schemaVersion | string | Always assurance-evidence-export-v1. |
profileId | string | Echoes the requested profile. |
tenantId | string | Tenant the readiness was computed for. |
frameworkId | string | From the profile. |
packId | string | From the profile. |
exportType | string | From the profile. |
state | string | export-ready or blocked (see below). |
signedExportReady | boolean | True when all signed-export prerequisites are met. |
livePublicationReady | boolean | null | Separate 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 array | Distinct, ordinally sorted reason codes (convenience projection of reasons[].code). |
reasons[] | object array | { code, category, summary, ownerModule, blocking } (AssuranceExportReadinessReason), ordinally sorted by code. |
secretValuesExposed | boolean | Always 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:
| State | Meaning |
|---|---|
export-ready | All blocking signed-export reasons are cleared (signedExportReady == true). |
blocked | At 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, andconfiguredas first-class states. The implementation does not emit those asstatevalues;unavailable/disabledsemantics surface as a 404 or as blocking reason codes, andconfiguredis 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
AssuranceExportProfileResponsenorAssuranceExportReadinessResponsecurrently carries anevidenceCoverage[]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 id | Framework | Pack | Export type | adapterId | schemaId | offlineVerifier.mode | Compatibility routes |
|---|---|---|---|---|---|---|---|
cra.conformity-dossier | cra | cra.technical-documentation | conformity-dossier | cra:conformity-dossier | conformity-dossier-v1 | signer-eu-offline-verifier | stella export conformity-dossier |
cra.technical-file | cra | cra.technical-documentation | technical-file | cra:tech-file | cra-tech-file-v1 | signer-eu-offline-verifier | stella export cra-tech-file |
dora.info-sharing | dora | dora | info-sharing | exportcenter.dora.info-sharing | dora-info-sharing-event-v1 | signer-eu-offline-verifier | stella export dora-info-sharing; stella verify dora-info-sharing |
dora.major-incident-report | dora | dora | major-incident-report | exportcenter.dora.major-incident-report | dora-major-incident-report.v1 | signer-eu-offline-verifier | stella export dora-incident-report; stella verify dora-incident-report |
dora.roi | dora | dora | register-of-information | exportcenter.dora.roi | dora-roi-v1 | signer-eu-offline-verifier | stella export dora-roi; stella verify dora-roi |
dora.tlpt-evidence-pack | dora | dora | tlpt-evidence-pack | exportcenter.dora.tlpt-evidence-pack | tlpt-evidence-pack.v1 | signer-eu-offline-verifier | stella tlpt pack; stella verify tlpt-pack |
nis2.effectiveness-report | nis2 | nis2 | effectiveness-report | exportcenter.nis2.effectiveness-report | nis2-effectiveness-report-v1 | hmac-dsse-offline-verifier | stella export nis2-effectiveness-report |
nis2.statement-of-applicability | nis2 | nis2 | statement-of-applicability | exportcenter.nis2.soa | nis2-soa-v1 | signer-eu-offline-verifier | 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 |
Notes grounded in source:
- The DORA profiles are built-in (not route-owned placeholders): they are emitted by
AssuranceExportProfileRegistrywithexportcenter.dora.*adapter ids. Each fails closed via blockingsource-datareason codes until the owning workflow supplies inputs (see DORA readiness reasons below). dora.tlpt-evidence-packis materialized over HTTP only by delegating thetlptEvidencePackrequest body to EvidenceLockerPOST /api/v1/evidence/capsules/tlpt-packsand persisting the sealed response JSON. ExportCenter does not assemble or sign TLPT evidence locally.dora.major-incident-reportanddora.info-sharingremain non-materializing over HTTP and return422 assurance_export_produce_not_expressiblewhen readiness is otherwise satisfied.dora.major-incident-reportanddora.tlpt-evidence-packcarry aschemaIdwith a dotted suffix (dora-major-incident-report.v1,tlpt-evidence-pack.v1) while theirofflineVerifier.payloadTypeIduses the hyphenated contract id (dora-major-incident-report-v1,tlpt-evidence-pack-v1).nis2.effectiveness-reportuses thehmac-dsse-offline-verifiermode; all other built-in profiles usesigner-eu-offline-verifier.
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:
| Profile | Blocking reason codes (source-data, plus live-publication where noted) |
|---|---|
dora.roi | dora-roi-register-source-missing, dora-roi-owner-approval-missing, dora-roi-schema-mapping-missing |
dora.major-incident-report | dora-major-incident-report-source-missing, dora-major-incident-report-owner-approval-missing, dora-major-incident-report-schema-mapping-missing |
dora.info-sharing | dora-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-pack | dora-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.
- NIS2 SoA: export readiness means ExportCenter can generate and sign the tenant bundle. There is no public publication requirement in this profile.
- DORA major incident and RoI: local signed handoff readiness means Stella can produce and verify deterministic operator artifacts. Competent-authority filing and live auto-submit remain separate operator-controlled posture.
- DORA information sharing: a signed batch can be export-ready while subscriber delivery remains blocked by channel enablement, endpoint allowlist, subscriber approval, or trust material.
- CRA Product Security Pack: local signed feed or metadata rendering can be export-ready while public publication is still blocked by mailbox/key preflight.
- CRA Technical Documentation Pack: technical-file export readiness means the bundle can be generated and verified. Regulator submission remains outside this export profile unless a separate handoff profile is enabled.
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
- Authorization: all discovery routes require the
export.viewerscope (StellaOpsScopes.ExportViewer=export.viewer). The owning ExportCenter run endpoints (for example NIS2 SoA runs) require their own scopes (export.operator/export.admin) and are documented with those routes. - Configuration: assurance readiness reads
AssuranceExportOptionsbound from theExport:Assuranceconfiguration section (AddAssuranceExportProfiles). Relevant keys:Export:Assurance:StorageRoot— signed bundle storage root (CRA/DORA signed-export prerequisite).Export:Assurance:SigningKeyId— export signing key reference.Export:Assurance:SigningProviderHint— preferred crypto provider hint.Export:Assurance:TrustRoots[]—{ TrustRootId, KeyId, PublicKeyPem, Fingerprint, NotBeforeUtc, NotAfterUtc, SignerProfiles[] }used for offline signature verification.Export:Assurance:CraPublication— CRA live-publication preflight (SecurityMailbox,SecurityMailboxVerified,IntakeKeyFingerprint,IntakeKeyExpiresAtUtc,RotationRolesConfigured,SupportLifecycleMetadataConfigured).- NIS2 SoA readiness reads a separate
Nis2SoaExportOptions(AuthorityBaseUrl,StorageRoot,SigningKeyId,TrustRoots[]).
Determinism Rules
- Profile lists are sorted by
profileId(ordinal) — seeAssuranceExportProfileRegistryconstructor andBuildProfiles(). - Readiness
reasonCodes[]andreasons[]are deduplicated and ordinally sorted by code so responses are byte-stable for a given configuration. - Export runs must derive bundle hashes from canonical payload bytes, not local file paths or wall-clock time.
- Readiness reason codes are stable strings; messages may be localized later but codes must remain deterministic.
- Readiness responses never serialize secret configuration values (
secretValuesExposedis alwaysfalse; storage roots and signing key ids are not echoed).
Related Contracts
assurance-pack-v1— the pack catalogue that lists which export profile ids each framework registers.assurance-setup-prerequisites-v1— the readiness/prerequisite vocabulary referenced byreadinessPrerequisites[].assurance-reporting-timeline-v1— the companion Notify-owned reporting-timeline surface.
