Skip to content

feat: Implement JSF (JSON Signature Format) signature support - #994

Open
wiebe-vandendriessche wants to merge 9 commits into
CycloneDX:mainfrom
wiebe-vandendriessche:feat/sig
Open

feat: Implement JSF (JSON Signature Format) signature support#994
wiebe-vandendriessche wants to merge 9 commits into
CycloneDX:mainfrom
wiebe-vandendriessche:feat/sig

Conversation

@wiebe-vandendriessche

@wiebe-vandendriessche wiebe-vandendriessche commented Jun 9, 2026

Copy link
Copy Markdown

Description

Implements comprehensive JSF (JSON Signature Format) signature support for CycloneDX Python library.

Summary of Changes:

  • Created JsfAlgorithm enum with 14 JWA/RFC8037 algorithms (RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, ED25519, ED448, HS256, HS384, HS512)
  • Created JsfKeyType enum for key types (EC, OKP, RSA)
  • Implemented JsfPublicKey class with conditional RFC-compliant validation per key type
  • Designed abstract JsfSignature base class with three concrete implementations:
    • JsfSimpleSignature: Simple signature mode (algorithm + value + optional fields)
    • JsfSignatureSigners: Multisignature mode (array of simple signatures under signers)
    • JsfSignatureChain: Chain mode (array of simple signatures under chain)
  • Implemented _JsfSignatureSerializationHelper for JSON serialization/deserialization (ignoring xml serialization/deserialization)
  • Added Optional[JsfSignature] property to Bom, Component, and Service model classes (compositions, annotation, declarations also support sigantures but are not yet implemented in the Python library)
  • Created unit tests covering all classes
  • Updated models.py for snapshots of boms with signatures

Difficulties encountered:

  • Type-safe design prevents invalid nesting at compile time (signers/chain lists only accept JsfSimpleSignature)
  • Three mutually exclusive signature modes properly modeled per JSF specification
  • JSON-only serialization (XML methods return None through a helper _JsfSignatureSerializationHelper)
  • Proper public key validation (EC: crv/x/y, OKP: crv/x, RSA: n/e)

Resolves or fixes issue:
#122
#978

AI Tool Disclosure

  • My contribution includes AI-generated content, as disclosed below:
    • AI Tools: GitHub Copilot
    • LLMs and versions: Claude: Haiku 4.5, Sonnet 4.6
    • Prompts: Architecture design for type-safe JSF signature implementation; test case generation for all signature modes; import optimization and linting fixes

Affirmation

Signed-off-by: Wiebe Vandendriessche <wiebe.vandendriessche@gmail.com>
@wiebe-vandendriessche
wiebe-vandendriessche requested a review from a team as a code owner June 9, 2026 12:47
@codacy-production

codacy-production Bot commented Jun 9, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 95 complexity · 5 duplication

Metric Results
Complexity 95
Duplication 5

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.

wiebe-vandendriessche and others added 2 commits June 12, 2026 10:45
Signed-off-by: Wiebe Vandendriessche <146532897+wiebe-vandendriessche@users.noreply.github.com>
Comment thread tests/test_deserialize_xml.py Outdated
Comment thread cyclonedx/model/signature.py
wiebe-vandendriessche and others added 2 commits June 17, 2026 17:30
Signed-off-by: Wiebe Vandendriessche <wiebe.vandendriessche@gmail.com>
@wiebe-vandendriessche
wiebe-vandendriessche marked this pull request as draft June 26, 2026 14:21
wiebe-vandendriessche and others added 2 commits July 13, 2026 15:44
Signed-off-by: Wiebe Vandendriessche <wiebe.vandendriessche@gmail.com>
Signed-off-by: Wiebe Vandendriessche <146532897+wiebe-vandendriessche@users.noreply.github.com>
@wiebe-vandendriessche
wiebe-vandendriessche marked this pull request as ready for review September 3, 2026 08:28
@wiebe-vandendriessche

Copy link
Copy Markdown
Author

@jkowalleck this should be ready

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new JSF signature models allow construction/deserialization of invalid JSF structures (ambiguous modes, invalid nesting, and post-init invalid mutation) and one unit test currently encodes an invalid algorithm assignment.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Implements JSF (JSON Signature Format) signature support in the CycloneDX Python models, enabling signatures to be represented and serialized in JSON for CycloneDX schema versions >= 1.4.

Changes:

  • Added cyclonedx.model.signature module with JSF enums, public key model, three signature modes, and a JSON-only serialization helper.
  • Extended Bom, Component, and Service models with an optional signature field (JSON-only; omitted in XML).
  • Added unit tests and updated/added snapshot fixtures to cover signatures and enum/schema alignment.
File summaries
File Description
tests/test_model_signature.py New unit tests for JSF signature/key models and polymorphic behavior.
tests/test_enums.py Adds enum-vs-schema validation and JSON rendering cases exercising signatures.
tests/test_deserialize_xml.py Adds XML deserialization-only test for BOMs containing JSON-only fields (signatures).
tests/_data/models.py Adds a snapshot BOM generator including signatures and excludes it from XML roundtrip deep-compare tests.
cyclonedx/model/signature.py Introduces JSF signature domain model + JSON-only (de)serialization helper.
cyclonedx/model/service.py Adds signature: Optional[JsfSignature] to Service with JSON-only serialization mapping.
cyclonedx/model/component.py Adds signature: Optional[JsfSignature] to Component with JSON-only serialization mapping.
cyclonedx/model/bom.py Adds signature: Optional[JsfSignature] to Bom with JSON-only serialization mapping.
tests/_data/snapshots/get_bom_with_signatures-1.7.xml.bin XML snapshot for BOM containing signatures (signatures dropped in XML).
tests/_data/snapshots/get_bom_with_signatures-1.7.json.bin JSON snapshot for BOM containing signatures (signatures present).
tests/_data/snapshots/get_bom_with_signatures-1.6.xml.bin XML snapshot for BOM containing signatures (signatures dropped in XML).
tests/_data/snapshots/get_bom_with_signatures-1.6.json.bin JSON snapshot for BOM containing signatures (signatures present).
tests/_data/snapshots/get_bom_with_signatures-1.5.xml.bin XML snapshot for BOM containing signatures (signatures dropped in XML).
tests/_data/snapshots/get_bom_with_signatures-1.5.json.bin JSON snapshot for BOM containing signatures (signatures present).
tests/_data/snapshots/get_bom_with_signatures-1.4.xml.bin XML snapshot for BOM containing signatures (signatures dropped in XML).
tests/_data/snapshots/get_bom_with_signatures-1.4.json.bin JSON snapshot for BOM containing signatures (signatures present).
tests/_data/snapshots/get_bom_with_signatures-1.3.xml.bin XML snapshot for older schema BOM (no signatures).
tests/_data/snapshots/get_bom_with_signatures-1.3.json.bin JSON snapshot for older schema BOM (no signatures).
tests/_data/snapshots/get_bom_with_signatures-1.2.xml.bin XML snapshot for older schema BOM (no signatures).
tests/_data/snapshots/get_bom_with_signatures-1.2.json.bin JSON snapshot for older schema BOM (no signatures).
tests/_data/snapshots/get_bom_with_signatures-1.1.xml.bin XML snapshot for schema 1.1 (no JSON signatures).
tests/_data/snapshots/get_bom_with_signatures-1.0.xml.bin XML snapshot for schema 1.0 (no JSON signatures).
tests/_data/snapshots/enum_JsfOkpCurve-1.7.json.bin JSON snapshot covering OKP curve enum rendering for schema 1.7.
tests/_data/snapshots/enum_JsfOkpCurve-1.6.json.bin JSON snapshot covering OKP curve enum rendering for schema 1.6.
tests/_data/snapshots/enum_JsfOkpCurve-1.5.json.bin JSON snapshot covering OKP curve enum rendering for schema 1.5.
tests/_data/snapshots/enum_JsfOkpCurve-1.4.json.bin JSON snapshot covering OKP curve enum rendering for schema 1.4.
tests/_data/snapshots/enum_JsfKeyType-1.7.json.bin JSON snapshot covering key type enum rendering for schema 1.7.
tests/_data/snapshots/enum_JsfKeyType-1.6.json.bin JSON snapshot covering key type enum rendering for schema 1.6.
tests/_data/snapshots/enum_JsfKeyType-1.5.json.bin JSON snapshot covering key type enum rendering for schema 1.5.
tests/_data/snapshots/enum_JsfKeyType-1.4.json.bin JSON snapshot covering key type enum rendering for schema 1.4.
tests/_data/snapshots/enum_JsfEcCurve-1.7.json.bin JSON snapshot covering EC curve enum rendering for schema 1.7.
tests/_data/snapshots/enum_JsfEcCurve-1.6.json.bin JSON snapshot covering EC curve enum rendering for schema 1.6.
tests/_data/snapshots/enum_JsfEcCurve-1.5.json.bin JSON snapshot covering EC curve enum rendering for schema 1.5.
tests/_data/snapshots/enum_JsfEcCurve-1.4.json.bin JSON snapshot covering EC curve enum rendering for schema 1.4.
tests/_data/snapshots/enum_JsfAlgorithm-1.7.json.bin JSON snapshot covering algorithm enum rendering for schema 1.7.
tests/_data/snapshots/enum_JsfAlgorithm-1.6.json.bin JSON snapshot covering algorithm enum rendering for schema 1.6.
tests/_data/snapshots/enum_JsfAlgorithm-1.5.json.bin JSON snapshot covering algorithm enum rendering for schema 1.5.
tests/_data/snapshots/enum_JsfAlgorithm-1.4.json.bin JSON snapshot covering algorithm enum rendering for schema 1.4.
Review details
  • Files reviewed: 38/38 changed files
  • Comments generated: 5
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cyclonedx/model/signature.py
Comment thread cyclonedx/model/signature.py
Comment thread cyclonedx/model/signature.py
Comment thread cyclonedx/model/signature.py
Comment thread tests/test_model_signature.py
@wiebe-vandendriessche

Copy link
Copy Markdown
Author

Not an easy one to implement, I'll take a look at Copilots comments

@jkowalleck

Copy link
Copy Markdown
Member

Not an easy one to implement, I'll take a look at Copilots comments

please take your time.
I did not even have time to manually review your valuable contribution, nor copilots review.
As usual - AI is non-authoritative and may make mistakes - since it scans your changes only, not the entirety of this repo - it does not know about previous design decisions and such ...

Even without looking into the details of the PR or AI review, I'd like to say:
It would be okay if the proposed data models would allow creation of invalid data due to not implementing some business logic.
We have a schema-based validator that should take care of formal invalids, and we would not implement a 3rd party (defacto?) standard, since the library users shall take care of this (garbage-in/garbage-out)

Signed-off-by: Wiebe Vandendriessche <wiebe.vandendriessche@gmail.com>
@wiebe-vandendriessche

Copy link
Copy Markdown
Author

Even without looking into the details of the PR or AI review, I'd like to say: It would be okay if the proposed data models would allow creation of invalid data due to not implementing some business logic. We have a schema-based validator that should take care of formal invalids, and we would not implement a 3rd party (defacto?) standard, since the library users shall take care of this (garbage-in/garbage-out)

Thanks for clarifying. I’ve kept the model relatively lightweight, while keeping stricter validation around JsfPublicKey because its fields are conditional on the key type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants