The language-neutral contract for OSCAL data bindings: OpenSpec capability specs, the vendored NIST OSCAL JSON Schema, the naming manifest, and the conformance corpus. Each language binding implements the contract and passes the corpus.
This repo is an OpenSpec store.
openspec/: the capability specs (specs/), the changes (changes/), the config, the identifier ledgerspec-ids.yaml, and the requirement indexrequirements.json.npm run requirements:writegenerates the index from the main specs. It lists the identifier, capability, and title of each requirement.traceability.schema.jsonis the JSON Schema of the traceability record that each binding keeps (see binding-surface).schemas/<release>/: the NIST OSCAL JSON Schema files of one release, byte-for-byte, withsha256sums.manifest/<release>/: the naming manifest.names.jsonis generated and holds the canonical name, kind, and schema pointers of each type.overrides.jsonis the hand-edited naming input.manifest/*.schema.jsonare the JSON Schemas of both files (see manifest/1.2.3/README.md).corpus/<release>/: the conformance corpus.docs/: shared documents that the specs cite, such as canonical JSON for conformance comparison.scripts/: the store tooling.
-
Clone this repo.
-
Register it:
openspec store register <path>. -
In a binding repo, add the store to
openspec/config.yaml:references: - { id: oscal-bindings-specs, remote: "https://github.com/cairn-proofs/oscal-bindings-specs.git" }
A reference is planning context only. Builds and conformance runs use the tagged archive, pinned by its sha256.
oscal-bindings-python, in Python: repository, issue tracker.oscal-bindings-typescript, in TypeScript: repository, issue tracker.
Each binding keeps its own expected conformance failures, in its own repository. This store holds no data about the
state of a binding (see schema-versioning). npm run binding-links:check
reads this list.
CONTRIBUTING.md describes how to change a requirement and how a binding adds or promotes an operation.
mise pins Node and the OpenSpec CLI. package-lock.json pins the npm dependencies.
mise installnpm cinpm run check
npm run check runs these checks. CI runs the same command on each pull request.
- The TypeScript typecheck.
- The identifier checker and its self-test.
- The requirement index generator self-test, which also checks the traceability record JSON Schema on sample
records, and
npm run requirements:check: it fails whenopenspec/requirements.jsondiffers from the generator output. - The
VERSIONcheck and its self-test. - The schema
sha256check. - The canonical JSON self-test.
- The YAML reader self-test.
scripts/yaml-reader.tsis the reference reader that the corpus check uses for YAML inputs. - The corpus check (see corpus/1.2.3/README.md).
- The binding link check and its self-test,
npm run binding-links:check. It fails when a tracked file outsideopenspec/changes/links an individual issue or pull request in a binding repository. The binding repositories are the repositories in Known implementations and eachoscal-bindings-*repository other than this store. - The names generator self-test, and
npm run names:check: it validates each manifest file and fails whennames.jsondiffers from the generator output. - The release checks and their self-test,
npm run releases:check. A released name that changes needs a breakingVERSIONincrement, and a releasedschemas/<release>/file must not change. These checks read git tags and history, so they fail in a shallow clone or a clone without tags. They also list each name change against the base ref (SPEC_IDS_BASE, defaultHEAD), and CI writes that list to the job summary. openspec validate --all --strict.
To change a canonical name, edit manifest/<release>/overrides.json, run npm run names:write, and commit both
files.
To add, rename, or remove a requirement in the main specs, run npm run requirements:write, and commit the index with
the specs.
VERSION holds the spec artifact version: a Semantic Version with the OSCAL release as build metadata, for example
0.1.0+oscal.1.2.3.
This repo's threat model is a Threat Composer .tc.json file, kept in
a separate private repo, oscal-bindings-specs-threat-models, rather than in this repo. Access to it is optional: you
do not need it to build, test or contribute.
If you have access, clone it beside this repo, not inside it:
gh repo clone cairn-proofs/oscal-bindings-specs-threat-models ../oscal-bindings-specs-threat-models
Open the .tc.json file there with the Threat Composer VS Code extension or web app.
- Set the new version in
VERSION, and merge the pull request. - Push the tag
v<VERSION>on that commit ofmain, for examplev0.1.0+oscal.1.2.3. - CI runs
npm run check, builds the archive withnpm run archive, and attaches the archive andSHA256SUMSto a draft GitHub release. CI fails when the tag is not onmainor does not matchVERSION. - Review the draft and publish it.
Pin the archive by the sha256 in SHA256SUMS, not by the tag. Before you pin or update a pin, check the archive you
downloaded. In the commands below, <version> is the release version, for example 0.8.0+oscal.1.2.3.
-
The archive matches
SHA256SUMS:shasum -a 256 -c SHA256SUMS -
This repo's CI built the archive from the tag (SLSA build provenance, logged in the public Sigstore transparency log):
gh attestation verify oscal-bindings-specs-<version>.tar.gz --repo cairn-proofs/oscal-bindings-specs \ --cert-identity "https://github.com/cairn-proofs/oscal-bindings-specs/.github/workflows/build.yml@refs/tags/v<version>" -
The archive is the asset published in the release (GitHub release attestation):
gh release verify-asset v<version> oscal-bindings-specs-<version>.tar.gz --repo cairn-proofs/oscal-bindings-specs -
The archive holds exactly the tagged files. In a clone of this repo with its tags, run
scripts/verify-release.sh v<version>. It rebuilds the archive withgit archivefrom the tag, compares it with the published archive, and runs checks 1 to 3, skipping a check the release cannot pass (see below). It runs no code from the tag. It needsghsigned in.
Older releases cannot pass every check. Releases up to and including v0.7.0+oscal.1.2.3 were built before CI
attested provenance, so check 2 fails for them. v0.1.0+oscal.1.2.3 and v0.2.0+oscal.1.2.3 are not immutable
releases, so check 3 fails for them. Checks 1 and 4 pass for every release.
These checks show that the archive matches the tagged commit. They do not show that the tagged commit is free of unwanted changes.