Skip to content

Add sample PQC readiness perspective for CBOM - #960

Open
bhess wants to merge 3 commits into
CycloneDX:2.0-devfrom
bhess:bhe-pqc-perspective
Open

Add sample PQC readiness perspective for CBOM#960
bhess wants to merge 3 commits into
CycloneDX:2.0-devfrom
bhess:bhe-pqc-perspective

Conversation

@bhess

@bhess bhess commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Adds a sample perspective demonstrating how the perspective model can apply in a CBOM context, using PQC readiness as the example. It lives in a new perspectives/ folder, as discussed in the last Cryptography WG meeting.

The mappings also exercise a proposed expectation field (values are present or absent) on perspective mappings that turns a descriptive mapping into a machine-checkable assertion. That field is not yet in the 2.0 schema, so the sample is illustrative pending that discussion.

@bhess
bhess requested a review from a team as a code owner June 25, 2026 12:29
@bhess
bhess changed the base branch from master to 2.0-dev June 29, 2026 12:05
Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
@bhess
bhess force-pushed the bhe-pqc-perspective branch from bca039c to 68d3377 Compare June 29, 2026 12:08
@Mehrn0ush

Copy link
Copy Markdown
Contributor

Hi,
I was reading this PR against #947.

Since changeMechanism is now an array, would “includes runtime-config” fit the rationale better than “runtime-config or restart-required”? Multiple values now mean required steps rather than alternatives.

And if #947 lands first, I assume the path should move from cryptoProperties.agility to component.agility — is that right?

The inventory/algorithm/agility split makes sense to me. One thing I wondered: should primitive: "unknown" / "other" be treated like missing primitive for the inventory check? And whether protocol cipher suites or cert->signing-algorithm linkage are in scope for a later revision.

I also couldn't find perspective-expectation-rationale.md in this PR — is it planned elsewhere, or should the reference in the description come out for now?

Signed-off-by: Basil Hess <bhe@zurich.ibm.com>
@bhess
bhess force-pushed the bhe-pqc-perspective branch from 7750dd2 to bebabfd Compare July 16, 2026 11:37
@bhess

bhess commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the good feedback @Mehrn0ush .

Since changeMechanism is now an array, would “includes runtime-config” fit the rationale better than “runtime-config or restart-required”? Multiple values now mean required steps rather than alternatives.

Changed the wording accordingly.

And if #947 lands first, I assume the path should move from cryptoProperties.agility to component.agility — is that right?

I agree, Changed the path accordingly to component.agility.

The inventory/algorithm/agility split makes sense to me. One thing I wondered: should primitive: "unknown" / "other" be treated like missing primitive for the inventory check? And whether protocol cipher suites or cert->signing-algorithm linkage are in scope for a later revision.

I agree, modified the rule to exclude "unknown". I think cert algorithms could be valuable as well, need to brainstorm a bit how to implement this as a JSON path expression since this needs bom-ref matching.

I also couldn't find perspective-expectation-rationale.md in this PR — is it planned elsewhere, or should the reference in the description come out for now?

Right, the reference is removed now.

@taleodor

Copy link
Copy Markdown

@bhess I'd appreciate if you can take a look at #1067 - if this aligns with your vision here.

@jkowalleck jkowalleck added this to the 2.0 milestone Aug 31, 2026
taleodor-claude pushed a commit to relizaio/cyclonedx-specification that referenced this pull request Sep 3, 2026
…ract in CI

The registry data file is hand-maintained (no generator), so until now
nothing asserted that it actually conforms to its governing schema or that
the hand-kept enum stays in step with the entries. Add a registry test to
the schema-v2 suite (picked up by `npm test` via the `test:*` glob, so the
existing JavaScript CI workflow runs it on every pull request):

- schema/perspectives-defs.json validates against
  schema/perspectives-defs.schema.json (strict ajv, draft-07 meta-schema,
  formats enabled).
- preDefinedPerspectivesEnum and the entries' `predefined` values are the
  same set, with no duplicates on either side; the message names which
  file to fix.
- every entry's `file` points under perspectives/. A missing document only
  warns, so an identity can be reserved ahead of its catalog document
  (pqc-readiness, CycloneDX#960). An existing document must
  be JSON, declare an integer `version` >= 1 (the value a reference's
  `predefinedVersion` selects), define at least one perspective, and define
  it inline (no `predefined`/`predefinedVersion`), since catalog entries are
  the published definitions, not references.

The test is not versioned (`-v`) because the registry lives at the schema
root and is shared across specification versions.

Verified: suite green; each check fails on a tampered input (unknown
identity/missing file in data, enum drift, catalog document in reference
form, catalog document without version).
taleodor pushed a commit to relizaio/cyclonedx-specification that referenced this pull request Sep 4, 2026
…d references, standalone registry

* feat(perspective): namespace pre-defined perspective identities under cdx:perspectives:

Per review on CycloneDX#1067: prefix the pre-defined
perspective enum values with the reserved cdx: namespace and a
cdx:perspectives: path, so 'model-card' becomes
'cdx:perspectives:model-card' and 'pqc-readiness' becomes
'cdx:perspectives:pqc-readiness'. This aligns the identities with the
reserved CycloneDX property taxonomy and keeps them collision-free with
author-chosen names.

Updates the enum, its meta:enum keys, the field description, and the
valid/invalid test fixtures accordingly.

* feat(perspective): version pre-defined perspective references (registry model)

Per Steve's review on CycloneDX#1067: adopt a registry model
for pre-defined perspectives, referenced by identity plus version.

- Add a required sibling 'predefinedVersion' (integer, minimum 1) on the
  reference form. It selects the published revision of the perspective and
  is the 'version' of the catalog document that defines it; like other
  CycloneDX version fields it increments by 1 per revision. Pinning it
  keeps a reference stable as the catalog perspective evolves.
- The reference form now requires both predefined and predefinedVersion
  (and still forbids all inline content but bom-ref); the inline form
  forbids both.
- The 'predefined' enum stays ids-only, hand-maintained inline (the
  registry is this id list plus the versioned catalog files) -- no
  separate data file or generator, unlike the crypto family registry,
  since the set is small and curated and version is not schema-enumerated
  per id (mirroring how crypto validates the family but not the parameter
  set).

Fixtures: valid reference form gains the version; the unknown-id,
annotated and mixed invalid cases gain it so each isolates its intended
violation; new invalid fixture covers a reference missing the required
version.

* feat(perspective): move pre-defined perspective registry into a standalone defs file

Decouples the pre-defined perspective lifecycle from the specification
release cycle, the same way the cryptography algorithm registry is
handled: perspectives can be added or revised, and new catalog document
versions published, by editing the registry alone -- no change to the
versioned specification schemas.

- New schema/perspectives-defs.schema.json: a single registry file
  holding the reserved identity enum (definitions.preDefinedPerspectivesEnum)
  and the identity-to-catalog-document map (definitions.catalog, id ->
  document path under perspectives/). Kept to one file, no separate data
  file or generator (the set is small and curated, unlike the ~100-entry
  crypto family registry that justifies generation).
- cyclonedx-perspective-2.0.schema.json: 'predefined' now  the
  external enum (../../perspectives-defs.schema.json#/definitions/
  preDefinedPerspectivesEnum) instead of an inline enum; the inline
  preDefinedPerspective def is removed.
- bundler: perspectives-defs.schema.json added to the external ref
  exceptions so it stays external in the bundle (like cryptography-defs).
- schema-v2 validate + functional harnesses: load and register the new
  external schema so refs resolve.

The registry data is expressed with schema keywords (const-valued map
entries) so the single file remains a valid JSON Schema under the
harness's ajv strict mode. Bundled schemas left to the post-merge
workflow.

* refactor(perspective): split pre-defined registry into data file + governing schema

Follows the crypto registry's file split so the registry data has a real,
checkable contract (the previous single file invented an unvalidated
const-map convention).

- schema/perspectives-defs.json: the registry DATA, hand-edited (no
  generator). Each entry is a proper object: predefined (the reserved
  identity, matching the CycloneDX perspective 'predefined' field),
  file (catalog document path), and description. Declares its governing
  schema via $schema.
- schema/perspectives-defs.schema.json: now a governing meta-schema that
  defines the data file's shape (perspectives[] of {predefined, file,
  description}, predefined constrained to preDefinedPerspectivesEnum) and
  still exposes preDefinedPerspectivesEnum for the specification schema to
  $ref. Identities are entry values, not object keys.

Data edits stay manual, matching how the crypto data file is maintained;
the enum in the governing schema is kept in sync by hand (the set is
small and curated). Verified the data file validates against the
governing schema, and the schema-v2 suite passes.

* test(perspective): enforce the pre-defined perspectives registry contract in CI

The registry data file is hand-maintained (no generator), so until now
nothing asserted that it actually conforms to its governing schema or that
the hand-kept enum stays in step with the entries. Add a registry test to
the schema-v2 suite (picked up by `npm test` via the `test:*` glob, so the
existing JavaScript CI workflow runs it on every pull request):

- schema/perspectives-defs.json validates against
  schema/perspectives-defs.schema.json (strict ajv, draft-07 meta-schema,
  formats enabled).
- preDefinedPerspectivesEnum and the entries' `predefined` values are the
  same set, with no duplicates on either side; the message names which
  file to fix.
- every entry's `file` points under perspectives/. A missing document only
  warns, so an identity can be reserved ahead of its catalog document
  (pqc-readiness, CycloneDX#960). An existing document must
  be JSON, declare an integer `version` >= 1 (the value a reference's
  `predefinedVersion` selects), define at least one perspective, and define
  it inline (no `predefined`/`predefinedVersion`), since catalog entries are
  the published definitions, not references.

The test is not versioned (`-v`) because the registry lives at the schema
root and is shared across specification versions.

Verified: suite green; each check fails on a tampered input (unknown
identity/missing file in data, enum drift, catalog document in reference
form, catalog document without version).

* test(perspective): register the perspectives registry schema in the Java 2.x harness

The Java schema-v2 verification harness resolves external schema URIs
through an explicit classpath mapping and disallows anything else, so the
perspective schema's $ref to perspectives-defs.schema.json failed to load
("Schema from 'https://cyclonedx.org/schema/perspectives-defs.schema.json'
is not allowed to be loaded"), erroring the five perspective fixtures.

Map the http/https URIs of perspectives-defs.schema.json to the classpath
copy (schema/ is already a test resource root), alongside the existing
cryptography-defs and behavior-taxonomy mappings.

Verified: `mvn clean test -Pschema-v2-tests` green locally (229 tests,
0 errors).

* feat(perspective): generate the pre-defined perspectives registry and enforce immutable published versions

The registry data (schema/perspectives-defs.json) is now GENERATED, in the
spirit of the crypto registry's generator, and published perspective
versions become immutable:

- Naming convention replaces any mapping: the catalog document defining
  `cdx:perspectives:<name>` is `perspectives/<name>-perspective.json`.
  Identities are lowercase-kebab-case. The identity enum in the governing
  schema stays hand-maintained (now with meta:enum descriptions, so a
  reserved identity without a document still has one).
- Registry entries are objects {predefined, file, name, description,
  versions[]}; each version record is {version, sha256, commit, date}:
  sha256 of the catalog document's canonical JSON (keys sorted, no
  whitespace, so formatting-only edits do not count as changes), the last
  commit touching the document, and that commit's UTC date. `name` and
  `description` are copied from the document at the latest version.
  lastUpdated is the newest registered date (deterministic).
- tools/src/main/js/perspectives-registry/: shared module (convention,
  canonical hash, structural checks, version-state assessment) used by both
  the generator and the test, plus generate-perspectives-registry.js. The
  generator only appends unregistered versions (a new perspective at
  version 1, or registered latest + 1); it refuses content changed at a
  registered version, regressed or skipped versions, removed registered
  documents, documents not defining exactly one inline perspective, and
  identities violating the convention. Idempotent when nothing changed.
- .github/workflows/generate_perspectives_registry.yml: on push to
  master/main/2.0-dev touching perspectives/**, the governing schema, or
  the generator, runs the generator and commits the registry directly
  (with a skip-ci marker), mirroring bundle_2.0_schemas.yml. A failing generator (change
  without bump merged over a red check) fails the workflow.
- The schema-v2 registry test now shares that logic and checks every
  identity in the enum: reserved, new, unchanged and pending (latest + 1)
  pass; modified, regressed, skipped and removed fail. It also checks
  registered entries follow the convention and list contiguous versions
  from 1, and that every registered identity is in the enum.
- Governing schema rewritten for the generated shape (patterns for file,
  sha256, commit; date-time dates; versions minItems 1).
- Perspective schema: `predefined` description now states the naming
  convention instead of a mapping.

Initial registry generated from this branch: model-card version 1 at
ebb5184 (the commit is fork-side provenance; the hash is the check key).

Verified: JS schema-v2 suite green; Java schema-v2 suite green (229 tests);
bundler unchanged (registry ref stays external); no new lint findings on
the perspective schema. Test and generator both reject each tampered
input: content change at a registered version, skipped/regressed version,
removed document, non-contiguous registry versions, non-convention
identity, document with two perspectives; a version bump registers cleanly
and formatting-only edits are accepted.

* feat: create generate_perspectives_registry.yml to generate perspectives defs PR

Signed-off-by: Pavel Shukhman <taleodor@users.noreply.github.com>

* fix: switch generate_perspectives_registry.yml to perspectives code

Signed-off-by: Pavel Shukhman <taleodor@users.noreply.github.com>

---------

Co-authored-by: Claude Code (ReARM Agent) <rearm-agent-claude@reliza.io>
Co-authored-by: Pavel Shukhman <taleodor@users.noreply.github.com>

Signed-off-by: Pavel Shukhman <taleodor@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants