feat: Implement JSF (JSON Signature Format) signature support - #994
feat: Implement JSF (JSON Signature Format) signature support#994wiebe-vandendriessche wants to merge 8 commits into
Conversation
Signed-off-by: Wiebe Vandendriessche <wiebe.vandendriessche@gmail.com>
Documentation build overview
17 files changed ·
|
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 101 |
| Duplication | 5 |
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.
Signed-off-by: Wiebe Vandendriessche <146532897+wiebe-vandendriessche@users.noreply.github.com>
Signed-off-by: Wiebe Vandendriessche <wiebe.vandendriessche@gmail.com>
Signed-off-by: Wiebe Vandendriessche <wiebe.vandendriessche@gmail.com>
5c305ce to
9dc6c63
Compare
Signed-off-by: Wiebe Vandendriessche <146532897+wiebe-vandendriessche@users.noreply.github.com>
|
@jkowalleck this should be ready |
There was a problem hiding this comment.
🟡 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.signaturemodule with JSF enums, public key model, three signature modes, and a JSON-only serialization helper. - Extended
Bom,Component, andServicemodels with an optionalsignaturefield (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.
| def __init__( | ||
| self, *, | ||
| algorithm: Union[JsfAlgorithm, str], | ||
| value: str, | ||
| key_id: Optional[str] = None, | ||
| public_key: Optional[JsfPublicKey] = None, | ||
| certificate_path: Optional[list[str]] = None, | ||
| excludes: Optional[list[str]] = None, | ||
| ) -> None: | ||
| if not isinstance(algorithm, JsfAlgorithm): | ||
| # Proprietary algorithms must be expressed as URIs per JSF spec | ||
| if not _urlsplit(str(algorithm)).scheme: | ||
| raise InvalidValueException( | ||
| f'Proprietary JSF algorithm must be expressed as a URI, got {algorithm!r}' | ||
| ) | ||
| self.algorithm = algorithm | ||
| self.value = value | ||
| self.key_id = key_id | ||
| self.public_key = public_key | ||
| self.certificate_path = list(certificate_path) if certificate_path else [] | ||
| self.excludes = list(excludes) if excludes else [] | ||
|
|
| def test_update(self) -> None: | ||
| sig = JsfSimpleSignature(algorithm=JsfAlgorithm.RS256, value='val') | ||
| self.assertIs(JsfAlgorithm.RS256, sig.algorithm) | ||
| sig.algorithm = JsfOkpCurve.ED25519 | ||
| self.assertIs(JsfOkpCurve.ED25519, sig.algorithm) | ||
|
|
|
Not an easy one to implement, I'll take a look at Copilots comments |
please take your time. Even without looking into the details of the PR or AI review, I'd like to say: |
Description
Implements comprehensive JSF (JSON Signature Format) signature support for CycloneDX Python library.
Summary of Changes:
JsfAlgorithmenum with 14 JWA/RFC8037 algorithms (RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, ED25519, ED448, HS256, HS384, HS512)JsfKeyTypeenum for key types (EC, OKP, RSA)JsfPublicKeyclass with conditional RFC-compliant validation per key typeJsfSignaturebase class with three concrete implementations:JsfSimpleSignature: Simple signature mode (algorithm + value + optional fields)JsfSignatureSigners: Multisignature mode (array of simple signatures undersigners)JsfSignatureChain: Chain mode (array of simple signatures underchain)_JsfSignatureSerializationHelperfor JSON serialization/deserialization (ignoring xml serialization/deserialization)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)Difficulties encountered:
JsfSimpleSignature)_JsfSignatureSerializationHelper)Resolves or fixes issue:
#122
#978
AI Tool Disclosure
GitHub CopilotClaude: Haiku 4.5, Sonnet 4.6Architecture design for type-safe JSF signature implementation; test case generation for all signature modes; import optimization and linting fixesAffirmation