Skip to content

Initial Model for CDX 1.7#786

Open
mr-zepol wants to merge 8 commits intodev_1.7from
dev_1.7_model
Open

Initial Model for CDX 1.7#786
mr-zepol wants to merge 8 commits intodev_1.7from
dev_1.7_model

Conversation

@mr-zepol
Copy link
Copy Markdown
Contributor

@mr-zepol mr-zepol commented Feb 7, 2026

This PR adds the new model classes, schema definition and test files for initial support for CDX 1.7 spec, this is to merge to one feature branch until implementation is done.

NOTE: Test are failing because some serializers need to be updated, this will done in different PRs

@sebtiem
Copy link
Copy Markdown

sebtiem commented Mar 24, 2026

Hey @mr-zepol ,
I am currently looking through your changes, in general they look great!
There is one thing I could find: I think the 'signature' is missing as part of the citations-section.

@sebtiem
Copy link
Copy Markdown

sebtiem commented Apr 8, 2026

I have provided a pr for this change.
Please have a look at #814.

@wkoot
Copy link
Copy Markdown

wkoot commented Apr 21, 2026

@nscuro is this something that only you can merge, or is that just the default assignment? It would be nice to unblock DependencyTrack/dependency-track#5818
Perhaps both #786 and #814 can be combined in a single merge, seems like progress has stagnated now

@Nihlus
Copy link
Copy Markdown

Nihlus commented May 3, 2026

I would also love to see this merged soon - CDX 1.7 in DependencyTrack is a pretty sharp need for me. If there's anything I can do to support or help, I'd be happy to pitch in.

@stevespringett
Copy link
Copy Markdown
Member

CycloneDX 1.7 coverage audit

Audited against: CycloneDX 1.7 (ECMA-424 2nd Edition, December 2025), JSON Schema and XSD published by CycloneDX/specification using the CycloneDX Skill for Claude Code (Opus 4.7 used).

The PR description acknowledges that test failures will be addressed in follow-up PRs because some serializers still need to be wired up. This audit therefore focuses on (1) whether the bundled schemas match the published 1.7 spec, (2) whether the Java model classes faithfully model the 1.7 schema, and (3) gaps that will block conformant 1.7 round-tripping regardless of serializer work.


TL;DR

The bundled JSON Schema, XSD, and protobuf are essentially identical to the upstream CycloneDX 1.7 spec (only three pre-existing doc-only differences). The Java model has good coverage of the headline 1.7 features (citations, patents, distribution constraints, version range, isExternal, license restructuring), but contains several conformance bugs that will produce non-validating output or fail to deserialize the PR's own test fixtures. Most are addressable with focused, mechanical edits before merging the next PR in this series.

Severity legend. P0 = blocks 1.7 conformance; P1 = correctness bug visible to users; P2 = polish or maintenance.

# Severity Area Issue
1 P0 Schema bundling cryptography-defs.schema.json not bundled or registered in CycloneDxSchema.offlineMappings; 1.7 $ref cannot be resolved offline
2 P0 Patents Definition splits patents and patentFamilies into two fields, but the schema (and the PR's own test fixture) keeps them in a single mixed patents array
3 P0 Patents PatentAssertion.asserter is OrganizationalChoice, which has no refLinkType (string) branch — fails to deserialize "asserter": "org-acme-inc" from valid-patent-1.7.json
4 P0 Cryptography AlgorithmProperties, CertificateProperties, RelatedCryptoMaterialProperties, ProtocolProperties are missing the new 1.7 fields algorithmFamily, ellipticCurve, and relatedCryptographicAssets — fields used in the PR's own crypto fixtures
5 P0 Licenses LicenseChoice still models 1.6's mutually-exclusive oneOf; 1.7 redefines licenseChoice as a flat array where each item is independently a license or a license-expression. Mixed-item arrays cannot be represented
6 P1 Citations Citation is missing the signature field defined by the JSON schema
7 P1 External references ExternalReference.Type.MODEL_CARD serialises as model_card but the 1.7 enum is model-card (hyphen). Pre-existing typo, now blocking under 1.7's strict enum
8 P1 License expression XML ExpressionDetailed wraps expressionDetails and item localName expressionDetail, but the XSD uses an unwrapped, repeating <details> element
9 P1 License expression XML ExpressionDetail.licenseIdentifier is a JSON property in 1.7 schema and an XML attribute license-identifier in the XSD; the Java field is mapped only as a JSON/XML element, not as an XML attribute
10 P2 Bundled schemas PR's bom-1.7.schema.json, bom-1.7.xsd, and bom-1.7.proto lag the upstream spec by three description-only edits (two typo fixes — "starting"/"plain text" — and an expanded vulnerability ratings description). Resync recommended
11 P2 Dead code Classifications.java is a duplicate of DistributionConstraints.java and is referenced nowhere
12 P2 Property ordering Component.@JsonPropertyOrder and Service.@JsonPropertyOrder do not include the new 1.7 fields (isExternal, versionRange, patentAssertions, tags); Citation.@JsonPropertyOrder uses bomRef while the JSON property is bom-ref
13 P2 Equality Component, Bom, Metadata, Citation equals/hashCode do not include the new 1.7 fields

Findings in detail

1. (P0) cryptography-defs.schema.json not bundled and not mapped

The PR's bom-1.7.schema.json references the cryptography registry via relative $ref:

schema/bom-1.7.schema.json:5283   "$ref": "cryptography-defs.schema.json#/definitions/algorithmFamiliesEnum"
schema/bom-1.7.schema.json:5300   "$ref": "cryptography-defs.schema.json#/definitions/ellipticCurvesEnum"

CycloneDxSchema.getJsonSchema() registers offline mappings for SPDX, JSF, and every bom-1.x.schema.json from 1.2 to 1.7, but not for cryptography-defs.schema.json. The src/main/resources/ listing for the PR head SHA confirms the file is also not added as a classpath resource.

Result: any 1.7 BOM that uses algorithmFamily or ellipticCurve cannot be validated offline; the validator will either fail to resolve the $ref or fall back to network lookup, defeating the offline-validation guarantee that exists for every other version.

Fix. Add src/main/resources/cryptography-defs.schema.json (1.7 spec ships it at https://github.com/CycloneDX/specification/blob/master/schema/cryptography-defs.schema.json) and add an offline mapping entry in CycloneDxSchema.java:

offlineMappings.put("http://cyclonedx.org/schema/cryptography-defs.schema.json",
    getClass().getClassLoader().getResource("cryptography-defs.schema.json").toExternalForm());

The XSD does not need a parallel; the spec deliberately leaves algorithmFamily/ellipticCurve typed as xs:string for XML.

2. (P0) Definition splits patents and patentFamilies into separate fields

The 1.7 schema models bom.definitions.patents as a single array whose items are anyOf [patent, patentFamily]:

"patents": {
  "type": "array",
  "items": { "anyOf": [
    { "$ref": "#/definitions/patent" },
    { "$ref": "#/definitions/patentFamily" }
  ]}
}

The XSD models the same element as <xs:choice maxOccurs="unbounded"> of <patent> or <patentFamily> inside a single <patents> wrapper. The PR's own valid-patent-1.7.json fixture demonstrates this — definitions.patents contains 3 patents and 1 patent family in the same array.

Definition.java instead declares two separate fields:

private List<Patent> patents;
private List<PatentFamily> patentFamilies;

Serialisation will emit a patentFamilies property that is rejected by additionalProperties: false, and deserialisation cannot read the canonical mixed array.

Fix. Replace with a single polymorphic field, e.g. List<Object> patents plus a JsonDeserializer that selects between Patent and PatentFamily based on the discriminating fields (patentNumberPatent, familyIdPatentFamily). For XML, use Jackson's @JsonSubTypes with JsonTypeInfo.As.WRAPPER_OBJECT or a custom Jackson XML deserializer.

3. (P0) PatentAssertion.asserter cannot accept a refLinkType string

Schema:

"asserter": { "oneOf": [
  { "$ref": "#/definitions/organizationalEntity", "title": "Organizational Entity" },
  { "$ref": "#/definitions/organizationalContact", "title": "Person" },
  { "$ref": "#/definitions/refLinkType",          "title": "Reference" }
]}

XSD:

<xs:choice>
  <xs:element name="organization" type="bom:organizationalEntity"/>
  <xs:element name="contact"      type="bom:organizationalContact"/>
  <xs:element name="ref"          type="bom:refLinkType"/>
</xs:choice>

PatentAssertion.java types this as OrganizationalChoice, which only has individual (contact) and organization (entity) branches. There is no third branch for the bare bom-ref string, and the PR's own valid-patent-1.7.json uses exactly that:

"asserter": "org-acme-inc"

Jackson will fail to bind a JSON string to OrganizationalChoice's object shape.

Fix. Either widen OrganizationalChoice to add a String ref branch (making it match the new oneOf), or introduce a PatentAssertionAsserter type with three branches and a custom deserializer. The XML mapping must emit <ref> for the string-only case.

4. (P0) Cryptography Java models are missing 1.7 fields

The 1.7 cryptography subschema adds, on every relevant inline type:

  • algorithmProperties.algorithmFamily (new — refs cryptography-defs.schema.json#/definitions/algorithmFamiliesEnum)
  • algorithmProperties.ellipticCurve (new — refs cryptography-defs.schema.json#/definitions/ellipticCurvesEnum; replaces deprecated curve)
  • algorithmProperties.relatedCryptographicAssets (new)
  • certificateProperties.relatedCryptographicAssets (new)
  • relatedCryptoMaterialProperties.relatedCryptographicAssets (new)
  • protocolProperties.relatedCryptographicAssets (new — and cipherSuites is deprecated in favour of it)

The PR adds tlsGroups and tlsSignatureSchemes to CipherSuite.java but no other crypto class is touched. The PR's own fixtures (valid-cryptography-full-1.7.json, valid-cryptography-certificate-1.7.json, valid-cryptography-implementation-1.7.json, etc.) all use algorithmFamily, ellipticCurve, and relatedCryptographicAssets, so round-tripping any of them will silently drop data thanks to @JsonIgnoreProperties(ignoreUnknown = true).

Fix. Add the missing fields with @VersionFilter(Version.VERSION_17) to the four crypto property classes; introduce a RelatedCryptographicAsset model class to back the new array; mark AlgorithmProperties.curve @Deprecated and add a meta:enum-aware enum or String for algorithmFamily/ellipticCurve.

5. (P0) LicenseChoice does not model the 1.7 unified array

In 1.6 the licenseChoice definition was a oneOf between two siblings — a single array of License or a single expression object. In 1.7 it becomes a type: array whose items are independently a license or an expression-with-details. The shape of each expression item also gained expressionDetails, acknowledgement, bom-ref, licensing, and properties.

LicenseChoice.java retains the 1.6 model:

private List<License> license;          // exclusive
private Expression expression;          // exclusive
private ExpressionDetailed expressionDetailed;  // exclusive

Each setter nulls the other two. Under 1.7 a BOM can legitimately contain a mix of licenses and expressions in the same licenses array — see valid-license-declared-concluded-mix-1.7.json in the PR — and the PR's class cannot represent that.

The new ExpressionDetailed class itself is also redundant with the existing Expression class for the most part; the only true addition is expressionDetails: List<ExpressionDetail>. Folding expressionDetails into Expression and dropping ExpressionDetailed would be cleaner and avoid the schema field name confusion (expressionDetailed singular vs expressionDetails plural).

Fix. Re-model LicenseChoice as List<LicenseChoiceItem> (or List<Object> plus a custom deserializer) where each item is oneOf {License, Expression}. Update LicenseDeserializer accordingly. Mark the old setters @Deprecated.

6. (P1) Citation is missing the signature field

The 1.7 JSON schema declares:

"signature": {
  "$ref": "#/definitions/signature",
  "title": "Signature",
  "description": "A digital signature verifying the authenticity or integrity of the attribution."
}

Citation.java declares no signature field. The XSD does not have a <signature> element on <citation>, so the JSON-only side is what is affected — but for JSON round-tripping the field must exist. The PR's Bom.@JsonPropertyOrder already names signature as the final property; the same should be added at the citation level.

7. (P1) ExternalReference.Type.MODEL_CARD JSON value mismatch

@JsonProperty("model_card")
MODEL_CARD("model_card"),

The 1.7 schema enum is model-card (hyphen, like every other reference type). This is a pre-existing bug that the 1.7 schema makes worse: 1.7 keeps additionalProperties: false, so any output written by cyclonedx-core-java with MODEL_CARD will fail validation against the bundled schema. The Type enum should be @JsonProperty("model-card") and the underlying string should be updated to match.

8. (P1) expressionDetails XML structure does not match the XSD

@JacksonXmlElementWrapper(localName = "expressionDetails")
@JacksonXmlProperty(localName = "expressionDetail")
private List<ExpressionDetail> expressionDetails;

XSD:

<xs:element name="details" minOccurs="0" maxOccurs="unbounded">
   ...
</xs:element>

So the 1.7 XSD wants <details>...</details><details>...</details> (no wrapper, repeating sibling elements), not <expressionDetails><expressionDetail>...</expressionDetail></expressionDetails>. Jackson XML output therefore won't validate.

Fix. Use a Jackson XML serialiser/deserialiser that maps the field to repeated <details> elements without a wrapper, gated by Version.VERSION_17 so 1.6 output is unaffected.

9. (P1) ExpressionDetail.licenseIdentifier is an XML attribute, not an element

The XSD declares license-identifier as a required attribute on each <details> complex type (and bom-ref similarly). ExpressionDetail.java declares licenseIdentifier as a plain field with no @JacksonXmlProperty(isAttribute = true, localName = "license-identifier"), so XML output produces <licenseIdentifier>...</licenseIdentifier> instead of the attribute form expected by the XSD.

bom-ref is correctly mapped as an attribute. Only licenseIdentifier is wrong.

10. (P2) PR's bundled schemas trail upstream by three doc-only edits

The PR's bom-1.7.schema.json, bom-1.7.xsd, and bom-1.7.proto differ from the current CycloneDX/specification/master in only three places, all of them description text:

  1. definitions.refType.$comment — PR has the typo "staring", upstream fixed it to "starting".
  2. attachedText.contentType.description — PR has "plan text", upstream fixed it to "plain text".
  3. vulnerability.ratings.description — PR has the short "List of vulnerability ratings"; upstream expands it to "List of vulnerability ratings. Consumers SHOULD consider ratings in prioritization decisions; source ratings may differ and aid prioritization."

These are not v1.7 conformance issues, but bundling stale prose perpetuates the typos. Resync from the spec repo before final merge.

11. (P2) Classifications.java is dead code

Classifications.java and DistributionConstraints.java have identical bodies (one nullable TlpClassification tlp field). Only DistributionConstraints is referenced from Metadata.java. Classifications is not imported, instantiated, or referenced anywhere in the diff. Remove it before publishing.

12. (P2) @JsonPropertyOrder and JSON property name slips

  • Component.@JsonPropertyOrder does not list isExternal, versionRange, patentAssertions, or tags. Output ordering for these fields will be implementation-defined.
  • Service.@JsonPropertyOrder does not list patentAssertions.
  • Citation.@JsonPropertyOrder lists "bomRef", but the actual JSON property name is "bom-ref". Effect is benign because the field has its own @JsonProperty("bom-ref"), but the order entry is silently a no-op.
  • Patent.@JsonPropertyOrder and PatentAssertion.@JsonPropertyOrder similarly use "bomRef" instead of "bom-ref".

13. (P2) equals/hashCode not updated for 1.7 fields

Defensive only, but worth catching now while these classes are being modified:

  • Bom.equals/hashCode skip citations, definitions, declarations, formulation, signature.
  • Component.equals/hashCode skip bomRef, mimeType, isExternal, versionRange, patentAssertions, tags, authors, manufacturer, cryptoProperties, provides, omniborId (in hashCode), signature.
  • Metadata.equals/hashCode skip manufacturer and distributionConstraints.
  • Citation is fine (covers all its current fields, but will need signature once added per finding 6).

Coverage matrix — 1.7 features

Feature Schema bundled Java model Notes
Top-level citations yes partial Missing signature property (finding 6)
metadata.distributionConstraints + tlpClassification yes yes Complete; matches schema and XSD
definitions.patents (mixed patent + patentFamily) yes broken Split into two fields (finding 2)
component.patentAssertions / service.patentAssertions yes partial Asserter cannot be a string ref (finding 3)
component.versionRange yes yes @VersionFilter(Version.VERSION_17) correctly applied
component.isExternal yes yes Mapped as XML attribute, matching XSD
1.7 licenseChoice array structure yes broken Old oneOf model retained (finding 5)
Cryptography Registry (algorithmFamily, ellipticCurve) partial no Subschema not bundled (finding 1); fields not on model (finding 4)
relatedCryptographicAssets on crypto property objects yes no Missing on all four crypto property classes (finding 4)
cipherSuite.tlsGroups / tlsSignatureSchemes yes yes Implemented
External reference types patent, patent-family, patent-assertion, citation yes yes model_card regression (finding 7)
Streebog-256 / Streebog-512 hash algorithms yes (via schema) n/a The Hash enum is enforced by schema; no Java enum change needed
Formulation scope extension yes yes (no model change required) Existing Formula/Workflow/Task types are still valid
BOM Format/Version wiring (Version.VERSION_17, NS_BOM_17) n/a yes Version.fromVersionString("1.7") returns VERSION_17; getJsonSchema/getXmlSchema route to the new resources

Recommended pre-merge actions

  1. (P0) Bundle cryptography-defs.schema.json and register it in CycloneDxSchema.offlineMappings.
  2. (P0) Re-shape Definition to a single polymorphic patents collection, with a deserializer that disambiguates patent from patentFamily.
  3. (P0) Add a third (refLinkType) branch to the asserter modelling for PatentAssertion (either by widening OrganizationalChoice or introducing a new asserter type).
  4. (P0) Add the missing 1.7 cryptography fields (algorithmFamily, ellipticCurve, relatedCryptographicAssets) to AlgorithmProperties, CertificateProperties, RelatedCryptoMaterialProperties, ProtocolProperties; deprecate curve and cipherSuites.
  5. (P0) Re-shape LicenseChoice as a flat array of mixed license/expression items; deprecate the 1.6-style mutually-exclusive setters.
  6. (P1) Add signature to Citation and update equals/hashCode/@JsonPropertyOrder.
  7. (P1) Fix the MODEL_CARD @JsonProperty value to model-card.
  8. (P1) Fix ExpressionDetail.licenseIdentifier to serialise as the XML attribute license-identifier; remove the wrapper around expressionDetails so it serialises as repeating <details> siblings.
  9. (P2) Resync bom-1.7.schema.json, bom-1.7.xsd, and bom-1.7.proto with the upstream spec to pick up the three doc-only fixes.
  10. (P2) Delete the unused Classifications.java.
  11. (P2) Round out @JsonPropertyOrder and the relevant equals/hashCode methods for new 1.7 fields.

Verification notes

  • The PR's bundled bom-1.7.xsd validates the JSON-paired XML test fixtures cleanly under xmllint once an XML catalog provides the http://cyclonedx.org/schema/spdx import; representative fixtures checked: valid-bom-1.7.xml, valid-citations-1.7.xml, valid-patent-1.7.xml, valid-cryptography-full-1.7.xml.
  • The PR's bundled bom-1.7.schema.json validates the JSON test fixtures under Python jsonschema (Draft-07) once cryptography-defs.schema.json, spdx.schema.json, and jsf-0.82.schema.json are supplied to the RefResolver. Representative fixtures checked: valid-bom-1.7.json, valid-citations-1.7.json, valid-patent-1.7.json, valid-cryptography-full-1.7.json, valid-cryptography-certificate-1.7.json, valid-license-expression-with-text-1.7.json, valid-license-declared-concluded-mix-1.7.json, valid-component-external-with-versionRange.json, valid-metadata-distribution-1.7.json, valid-saasbom-1.7.json — all pass.
  • The corresponding invalid-*.json fixtures are correctly rejected for the expected reasons (citations xor pointers/expressions and the attributedTo/process requirement, version vs versionRange exclusivity, and additionalProperties on metadata).

So the schemas themselves are conformant. The defects are all on the Java-model side of the line.

@mr-zepol mr-zepol added spec/1.7 Changes for Spec 1.7 breaking change labels May 9, 2026
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 9, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 690 complexity

Metric Results
Complexity 690

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

mr-zepol added 5 commits May 9, 2026 09:03
* Fix License issue serialization

* Add Ike2 Proper Support

* Add headers
Add polymorphic patent support and make serialization version-aware. Introduces PatentItem model plus PatentItemDeserializer, PatentsDeserializer and PatentAssertionDeserializer/Serializer to handle mixed Patent/PatentFamily entries and XML/JSON differences; updates Definition to use the polymorphic list and provides helpers for legacy access. Refactors many serializers (EnvironmentVars, InputType, ExternalReference, Hash, IkeV2Transform, etc.) and CustomSerializerModifier to honor @VersionFilter and a Version parameter, filters enum/field serialization by target BOM version, and normalizes date formatting. Also enhances OrganizationalChoice deserialization, adds properties handling to ExternalReferencesDeserializer, and small model tweaks (Component, Composition, Service, LicenseItem, PriorityApplication, FormulationCommon, Level) to align with newer schema versions.
* Use 'model-card' for MODEL_CARD external reference

Update ExternalReference.MODEL_CARD to use kebab-case: change @JsonProperty and enum value from "model_card" to "model-card". This aligns the serialized name with the expected CycloneDX 1.5 naming while retaining the VersionFilter(Version.VERSION_15) annotation.

* Adjust Citation & Component; delete Classifications

Fix serialization and equality logic in model classes: change Citation @JsonPropertyOrder to use "bom-ref" to match the XML attribute, remove the now-unused Classifications class, and update Component.equals()/hashCode() to include newly added fields (isExternal, versionRange, patentAssertions, tags) so equality and hashing account for them.
Introduce support for related cryptographic assets across crypto models and add a cryptography definitions schema. Changes include:

- Add new RelatedCryptographicAsset model with type and ref, equals/hashCode.
- Extend AlgorithmProperties, CertificateProperties, ProtocolProperties, and RelatedCryptoMaterialProperties to include List<RelatedCryptographicAsset> relatedCryptographicAssets with XML wrapper annotations, getters/setters, and include in equals/hashCode.
- Annotate new fields with @VersionFilter(Version.VERSION_17) and add necessary imports.
- Add cryptography-defs.schema.json resource containing algorithm family and elliptic curve metadata.
- Register the new schema in CycloneDxSchema offlineMappings so it can be resolved at runtime.

These changes enable expressing relationships between crypto objects and external cryptographic assets and provide a formal schema for algorithm/curve definitions.
Add comprehensive CycloneDX 1.7 cryptography unit tests for both JSON and XML generators (updates to BomJsonGeneratorTest and BomXmlGeneratorTest). Update schema verification to recognize -1.7 fixtures in JsonSchemaVerificationTest and XmlSchemaVerificationTest. Adjust AlgorithmProperties@JsonPropertyOrder to change the ordering of parameterSetIdentifier, curve, and ellipticCurve to match the 1.7 schema expectations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change spec/1.7 Changes for Spec 1.7

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants