Standards Mapping v1

Contract ID: CONTRACT-STANDARDS-MAPPING-V1-032 Status: Draft Owner: ExportCenter Last Updated: 2026-05-30

Purpose

standards-mapping-v1 defines the local YAML mapping files and the deterministic ExportCenter bundle used to link external security standards to StellaOps control-register controls and offline evidence refs.

Audience: ExportCenter adapter implementers, EU-standards reviewers who author and approve the mapping YAML, and operators producing offline standards-coverage bundles.

The adapter is evidence-pointer-first: it copies the reviewed local mapping YAML, emits a normalized summary, signs the bundle index, and records blockers for draft or incomplete mappings instead of inferring standard coverage at export time.

The export adapter id is standards:mapping (StandardsMappingConstants.AdapterId). The source mapping schema version is the literal standards-mapping-v1 (StandardsMappingConstants.SourceSchemaVersion); the emitted bundle index and summary carry their own schema versions (standards-mapping-bundle-v1, standards-mapping-summary-v1).

Source Mapping Schema

Mapping sources MUST be local files using:

schemaVersion: standards-mapping-v1
mappingVersion: 0.1.0
status: draft
targetStandard:
  id: iso27001-2022
  name: ISO/IEC 27001:2022 Annex A
  controlSet:
    unit: control
    totalControls: 93
    requirementLevelCoverageStatus: null
coverage:
  mappedControls: 93
  coveragePercent: 100.0
  thresholdPercent: 80.0
  coverageBasis: annex-a-control-count
  stellaApplicableControls: 93
  nonApplicableControls: 0
review:
  reviewStatus: pending-eu-standards-reviewer
sourceBasis: []
evidenceSets: {}
controlMappings:
  - externalControlId: A.5.1
    externalControlName: Policies for information security
    stellaControlId: NIS2-01-NIS-POLICY
    maturity: mixed
    applicability: null
    mappingNote: null
    applicabilityReason: null
    evidenceRefs:
      - ref: evidence://policy/packs/security-policy/approved
        sourceType: stella-native

The line-oriented YAML reader (StandardsMappingYamlReader.Parse) recognizes a fixed set of keys at fixed indents. Keys outside this set (for example targetStandard.sourceVersion, controlSet.families, or the richer review.* block carried in the current EU pack files) are tolerated but ignored. evidenceRefs may be inline list items or a YAML alias (*anchor) that resolves against a top-level evidenceSets anchor (&anchor); anchors are the convention used by the live mapping files.

Required source fields (validated by the reader; a missing required field throws InvalidOperationException):

FieldRequirement
schemaVersionMUST equal standards-mapping-v1 (exact ordinal match).
mappingVersionREQUIRED. Source mapping version independent from the target standard.
statusREQUIRED. Emitted as targetStandard.mappingStatus; draft/pending/blocked states are carried into bundle blockers under dependency mapping-status.
targetStandard.idREQUIRED. MUST equal the resolved target’s targetStandardId (e.g. iso27001-2022) or the build throws.
targetStandard.nameREQUIRED. Display name for the mapped standard.
targetStandard.controlSet.totalControlsREQUIRED integer. Total target controls in the mapped control set.
targetStandard.controlSet.unitOPTIONAL. Emitted as controlSetUnit.
targetStandard.controlSet.requirementLevelCoverageStatusOPTIONAL. Draft/pending/blocked values raise a requirement-level-coverage blocker.
coverage.mappedControlsREQUIRED integer. MUST equal the number of controlMappings entries or the build throws a count-mismatch error.
coverage.coveragePercentREQUIRED number. Source coverage percentage.
coverage.thresholdPercentREQUIRED number. Minimum coverage threshold; emitted on coverage.thresholdPercent.
coverage.coverageBasisOPTIONAL. Emitted as coverage.coverageBasis.
coverage.stellaApplicableControlsOPTIONAL integer. Applicability count, emitted when present.
coverage.nonApplicableControlsOPTIONAL integer. Non-applicable count, emitted when present.
review.reviewStatusOPTIONAL. The ONLY key the reader consumes from the review block. Draft/pending/blocked values raise a mapping-review blocker. Other review.* keys (e.g. requiredReviewerRole, assignedReviewerId) are present in the live pack files for human governance but are NOT parsed by the adapter.
sourceBasis[]OPTIONAL. Local docs or approved local inputs used to derive the mapping; sorted ordinally in the summary.
controlMappings[]REQUIRED array. One row per mapped external control; re-sorted by external control id during parsing.
controlMappings[].externalControlIdREQUIRED. Target control id.
controlMappings[].externalControlNameREQUIRED. Target control title.
controlMappings[].stellaControlIdREQUIRED. Stella control id from the control register.
controlMappings[].maturityREQUIRED. Free-text in the reader; the live pack convention is stella-native, mixed, or tenant-supplied (counted verbatim into maturityCounts).
controlMappings[].applicabilityOPTIONAL.
controlMappings[].mappingNoteOPTIONAL.
controlMappings[].applicabilityReasonOPTIONAL.
controlMappings[].evidenceRefs[]REQUIRED. At least one offline-replayable evidence pointer (each with ref + sourceType); a mapping with zero refs throws.

Note: coverage.coveragePercent, coverage.thresholdPercent, and the maturity set are NOT cross-validated by the adapter. The reader trusts the reviewed source values verbatim; only coverage.mappedControls vs the controlMappings count and targetStandard.id vs the resolved target are enforced.

Evidence refs MUST use immutable or replayable local evidence schemes such as evidence://.... Live SaaS, regulator, or public web endpoints are not valid source refs for deterministic bundles.

Supported Targets

StandardsMappingTargets.SupportedTargets is the canonical alias list: iso27001, iec62443-4-1, iec62443-4-2, en303645, jrc-cra. The resolver (StandardsMappingTargets.Resolve) also accepts the canonical target ids iso27001-2022 and etsi-en303645 as input aliases; both normalize to the same bundle target (iso27001 / en303645).

CLI / resolver aliasMapping target idBundle targetLocal file (relative to --mapping-dir)
iso27001 (also iso27001-2022)iso27001-2022iso27001iso27001-2022.yaml
iec62443-4-1iec62443-4-1iec62443-4-1iec62443-4-1.yaml
iec62443-4-2iec62443-4-2iec62443-4-2iec62443-4-2.yaml
en303645 (also etsi-en303645)etsi-en303645en303645etsi-en303645.yaml
jrc-crajrc-crajrc-crajrc-cra.yaml

The bundle target (third column) is the slug used in bundle entry paths (mappings/<bundle-target>.yaml) and in the output file name. The reviewed mapping files live in docs/europe/standards-mapping/, which is also the CLI default for --mapping-dir.

jrc-cra is publishable only when docs/europe/standards-mapping/jrc-cra.yaml has reviewed non-zero mapping rows, no blocked/pending/draft publication state, and no bundle blockers. This gate is enforced for the CLI path only (StandardsMappingCommandGroup.EnsureTargetPublishable); the core StandardsMappingAdapter.Build/BuildFromDirectory API will materialize a jrc-cra bundle that still carries blockers without throwing. Adapters MUST preserve local blocker states rather than fetching remote content.

CLI Surface

The bundle is produced by the stella standards-mapping command (StandardsMappingCommandGroup):

OptionBehaviour
--targetREQUIRED. One of the supported aliases above.
--mapping-dirLocal directory of reviewed YAML. Defaults to docs/europe/standards-mapping.
--output, -oOutput .tar.gz path. Defaults to <bundle-target>.standards-mapping.tar.gz.
--overwriteAllow overwriting an existing output file.
--generated-atISO-8601 UTC timestamp embedded in the index. Defaults to the sprint fixture timestamp (2026-04-30T00:00:00Z).
--signing-key-fileLocal HMAC key file. Falls back to STELLAOPS_STANDARDS_MAPPING_HMAC_KEY when omitted; if neither is set the command fails.
--signing-key-idDSSE key id. When omitted, the adapter derives hmac-sha256:<first-16-hex-of-key-sha256>.
--jsonEmit a JSON summary (output path, hashes, mapped controls, blockers).

When run inside ExportCenter (server-side export runs), authorization is the generic ExportCenter scope set from StellaOpsScopes: export.viewer (ExportViewer), export.operator (ExportOperator), export.admin (ExportAdmin). There is no standards-mapping-specific scope.

Bundle Schema

Per-entry media types embedded in index.json.entries:

Bundle entryMedia type
mappings/<bundle-target>.yamlapplication/yaml
mappings/<bundle-target>.summary.jsonapplication/vnd.stellaops.standards-mapping.summary.v1+json
signatures/index.dsse.jsonapplication/vnd.dsse+json
index.json (artifact, not self-listed in entries)application/vnd.stellaops.standards-mapping.index.v1+json
checksums.txt (artifact, not self-listed)text/plain

Bundle layout:

index.json
checksums.txt
mappings/<bundle-target>.yaml
mappings/<bundle-target>.summary.json
signatures/index.dsse.json

index.json is authoritative. index.json.entries lists only the two mappings/<bundle-target>.* files and the DSSE signature; index.json and checksums.txt are bundle members but are not self-listed in entries. checksums.txt is a deterministic convenience file for offline operators and is excluded from its own listing.

Required index.json Fields

FieldRequirement
schemaVersionMUST equal standards-mapping-bundle-v1.
generatedAtUTC timestamp supplied by the caller (request.GeneratedAt, converted to UTC), not read from wall clock inside replay paths.
targetResolved bundle target slug: iso27001, iec62443-4-1, iec62443-4-2, en303645, or jrc-cra.
targetStandardObject: id, name, mappingVersion, mappingStatus (from source status), controlSetUnit (nullable), totalControls, requirementLevelCoverageStatus (nullable).
sourceObject: path (local source path, \ normalized to /), schemaVersion, sha256 (over the LF-normalized source bytes), sizeBytes.
coverageObject: mappedControls, coveragePercent, thresholdPercent, coverageBasis (nullable), reviewStatus (nullable), stellaApplicableControls (nullable), nonApplicableControls (nullable).
entriesBundle file list (the two mappings/* files and the DSSE signature) with path, mediaType, sha256, and sizeBytes.
maturityCountsCounts keyed by mapping maturity value (ordinal-sorted).
evidenceSourceTypeCountsCounts keyed by evidence sourceType (ordinal-sorted).
blockersReview/publication/requirement-level blockers (dependency, reason, sprintRef) derived from the source mapping state; de-duplicated and ordinal-sorted by dependency.
signingObject: status (always signed), payloadType, keyId, algorithm (resolved HMAC tag, see Signing), signaturePath (signatures/index.dsse.json).

The summary.json payload carries the same targetStandard/source/coverage shape plus the full sourceBasis[] and controlMappings[] arrays, which are NOT inlined into index.json.

Signing And Verification

index.json is signed as the DSSE payload:

{
  "payloadType": "application/vnd.stellaops.standards-mapping.index.v1+json",
  "payload": "<base64 canonical index.json>",
  "signatures": [
    {
      "keyid": "hmac-sha256:<key-ref>",
      "alg": "HMAC-SHA256",
      "sig": "<base64 HMAC over DSSE PAE>"
    }
  ]
}

The HMAC DSSE envelope is the local deterministic ExportCenter signing pattern for this adapter. The MAC and the persisted alg / signing.algorithm tag are NOT hard-coded to HS256. They are resolved at sign time from the central crypto abstraction (ICryptoHmac.GetAlgorithmForPurpose(HmacPurpose.Signing), upper-cased) per the active regional compliance profile (CoC §7.4): typically HMAC-SHA256 on the world / fips / kcmvp / eidas profiles, HMAC-GOST3411 on the gost profile, and HMAC-SM3 on the sm profile. (A SignatureAlgorithm = "HS256" constant exists on StandardsMappingConstants but is unused.) Sender and verifier MUST run the same regional profile, since the verifier recomputes the expected algorithm string and the MAC bytes with the same abstraction.

keyid is the signing key id. When no key id is supplied, the adapter derives hmac-sha256:<first-16-hex-chars-of-the-key's-sha256> (CreateHmacSigningKey); an explicit --signing-key-id / KeyId is recorded verbatim and is not required to start with hmac-sha256:.

Production key sourcing remains deployment-specific; the adapter MUST fail if no signing key is configured (the ProcessAsync path returns a failed result, the Build path throws on an empty key). Offline verification (StandardsMappingBundleVerifier.Verify) re-reads the tar.gz entries, requires index.json, checks the bundle schema version, validates every entries[] row against the archive (size + sha256: hash), then verifies the DSSE envelope: payload type, base64 payload equals index.json bytes, a signature whose keyid and alg match the configured key and resolved algorithm, and a fixed-time HMAC comparison over the DSSE PAE (DSSEv1 <typelen> <type> <payloadlen> <payload>). checksums.txt is a convenience listing and is not re-validated by Verify.

Determinism Rules

Offline And Replay Expectations

Known v1 Blockers