From a3dd671c55293677913ab57aee7efb7bd0c2d126 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Thu, 17 Jul 2025 12:23:14 +0200 Subject: [PATCH 1/5] tests: regression for issue #850 Signed-off-by: Jan Kowalleck --- .../_data/own/xml/1.6/regression_issue850.xml | 30 +++++++++++++++++++ tests/test_real_world_examples.py | 4 +++ 2 files changed, 34 insertions(+) create mode 100644 tests/_data/own/xml/1.6/regression_issue850.xml diff --git a/tests/_data/own/xml/1.6/regression_issue850.xml b/tests/_data/own/xml/1.6/regression_issue850.xml new file mode 100644 index 00000000..04bfab07 --- /dev/null +++ b/tests/_data/own/xml/1.6/regression_issue850.xml @@ -0,0 +1,30 @@ + + + + + example + 15.8.0 + + + + + + + + + + + + + tSHVo7UgCxvvmFusf+2UzjhxXa2PyvLHaIvyNlB/yp8= + + + + gep3n58O7GLUk/jwmOda8HlwkiqA40CRhJYgoJbMJ6xZphfn7s/JHDByeptXvbolB6nVw5qAQ/mKCAkh0x7NGzWwSWypmpysK3zuUZuMihTSizd+kclwCJYamQ0l4Lqqp13Ii/6C8N56vlbci9P3NwOVC910Jj6GAFj2Ci4zCNz0tstpu7cDE2/okRR4jBzisOpr2FCaHWUfkZUiGm7ueCg/T+v2Z0HM8qcG//+iMlvHcb5yXKUObDvW8CYsMzNW0Zdhs/qf6WkPpp6QBeWxVB+5QUfMZ+F0fP3fRaerjwh6mGkOVl7QODHcIcp153yX8JxU+c0ndRacNywPBGmxTQ== + + + diff --git a/tests/test_real_world_examples.py b/tests/test_real_world_examples.py index 0fe3e480..8b95f5a1 100644 --- a/tests/test_real_world_examples.py +++ b/tests/test_real_world_examples.py @@ -38,6 +38,10 @@ def test_regression_issue_630(self, *_: Any, **__: Any) -> None: with open(join(OWN_DATA_DIRECTORY, 'xml', '1.6', 'regression_issue630.xml')) as input_xml: Bom.from_xml(input_xml) + def test_regression_issue_850(self, *_: Any, **__: Any) -> None: + with open(join(OWN_DATA_DIRECTORY, 'xml', '1.6', 'regression_issue850.xml')) as input_xml: + Bom.from_xml(input_xml) + def test_regression_issue677(self, *_: Any, **__: Any) -> None: # tests https://github.com/CycloneDX/cyclonedx-python-lib/issues/677 with open(join(OWN_DATA_DIRECTORY, 'json', '1.5', 'issue677.json')) as input_json: From 415e002520296c9b497b9091712e06bedfcbe8b2 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Fri, 18 Jul 2025 11:21:37 +0200 Subject: [PATCH 2/5] fix! ignore unknown properties when deserializing Signed-off-by: Jan Kowalleck --- cyclonedx/model/__init__.py | 14 +++++++------- cyclonedx/model/bom.py | 4 ++-- cyclonedx/model/bom_ref.py | 2 +- cyclonedx/model/component.py | 16 ++++++++-------- cyclonedx/model/component_evidence.py | 12 ++++++------ cyclonedx/model/contact.py | 6 +++--- cyclonedx/model/crypto.py | 16 ++++++++-------- cyclonedx/model/definition.py | 13 ++++++++----- cyclonedx/model/dependency.py | 2 +- cyclonedx/model/issue.py | 4 ++-- cyclonedx/model/license.py | 10 ++++++++-- cyclonedx/model/lifecycle.py | 4 ++-- cyclonedx/model/release_note.py | 2 +- cyclonedx/model/service.py | 2 +- cyclonedx/model/tool.py | 2 +- cyclonedx/model/vulnerability.py | 18 +++++++++--------- pyproject.toml | 2 +- 17 files changed, 69 insertions(+), 60 deletions(-) diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py index 19e2de36..ba3a79a3 100644 --- a/cyclonedx/model/__init__.py +++ b/cyclonedx/model/__init__.py @@ -676,7 +676,7 @@ def deserialize(cls, o: Any) -> ExternalReferenceType: return ExternalReferenceType(o) -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class XsUri(serializable.helpers.BaseHelper): """ Helper class that allows us to perform validation on data strings that are defined as xs:anyURI @@ -802,7 +802,7 @@ def is_bom_link(self) -> bool: return self._uri.startswith(_BOM_LINK_PREFIX) -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class ExternalReference: """ This is our internal representation of an ExternalReference complex type that can be used in multiple places within @@ -914,7 +914,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Property: """ This is our internal representation of `propertyType` complex type that can be used in multiple places within @@ -989,7 +989,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class NoteText: """ This is our internal representation of the Note.text complex type that can be used in multiple places within @@ -1081,7 +1081,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Note: """ This is our internal representation of the Note complex type that can be used in multiple places within @@ -1166,7 +1166,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class IdentifiableAction: """ This is our internal representation of the `identifiableActionType` complex type. @@ -1252,7 +1252,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Copyright: """ This is our internal representation of the `copyrightsType` complex type. diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py index 4d030169..c3f20116 100644 --- a/cyclonedx/model/bom.py +++ b/cyclonedx/model/bom.py @@ -55,7 +55,7 @@ from packageurl import PackageURL -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class BomMetaData: """ This is our internal representation of the metadata complex type within the CycloneDX standard. @@ -314,7 +314,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class(ignore_during_deserialization=['$schema', 'bom_format', 'spec_version']) +@serializable.serializable_class( ignore_unknown_during_deserialization=True) class Bom: """ This is our internal representation of a bill-of-materials (BOM). diff --git a/cyclonedx/model/bom_ref.py b/cyclonedx/model/bom_ref.py index a1895d3e..edde98ef 100644 --- a/cyclonedx/model/bom_ref.py +++ b/cyclonedx/model/bom_ref.py @@ -28,7 +28,7 @@ _T_BR = TypeVar('_T_BR', bound='BomRef') -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class BomRef(serializable.helpers.BaseHelper): """ An identifier that can be used to reference objects elsewhere in the BOM. diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py index 6737b39e..2b350f7d 100644 --- a/cyclonedx/model/component.py +++ b/cyclonedx/model/component.py @@ -66,7 +66,7 @@ from .release_note import ReleaseNotes -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Commit: """ Our internal representation of the `commitType` complex type. @@ -326,7 +326,7 @@ def deserialize(cls, o: Any) -> ComponentType: return ComponentType(o) -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Diff: """ Our internal representation of the `diffType` complex type. @@ -408,7 +408,7 @@ class PatchClassification(str, Enum): UNOFFICIAL = 'unofficial' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Patch: """ Our internal representation of the `patchType` complex type. @@ -498,7 +498,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Pedigree: """ Our internal representation of the `pedigreeType` complex type. @@ -661,7 +661,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Swid: """ Our internal representation of the `swidType` complex type. @@ -813,7 +813,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class OmniborId(serializable.helpers.BaseHelper): """ Helper class that allows us to perform validation on data strings that must conform to @@ -872,7 +872,7 @@ def __str__(self) -> str: return self._id -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Swhid(serializable.helpers.BaseHelper): """ Helper class that allows us to perform validation on data strings that must conform to @@ -931,7 +931,7 @@ def __str__(self) -> str: return self._id -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Component(Dependable): """ This is our internal representation of a Component within a Bom. diff --git a/cyclonedx/model/component_evidence.py b/cyclonedx/model/component_evidence.py index 2b5f1240..395f93e2 100644 --- a/cyclonedx/model/component_evidence.py +++ b/cyclonedx/model/component_evidence.py @@ -75,7 +75,7 @@ class AnalysisTechnique(str, Enum): OTHER = 'other' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Method: """ Represents a method used to extract and/or analyze evidence. @@ -181,7 +181,7 @@ def xml_denormalize(cls, o: 'XmlElement', *, return [BomRef(value=t.get('ref')) for t in o] -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Identity: """ Our internal representation of the `identityType` complex type. @@ -288,7 +288,7 @@ def __repr__(self) -> str: f' methods={self.methods}, tools={self.tools}>' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Occurrence: """ Our internal representation of the `occurrenceType` complex type. @@ -423,7 +423,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class CallStackFrame: """ Represents an individual frame in a call stack. @@ -567,7 +567,7 @@ def __repr__(self) -> str: f' line={self.line}, column={self.column}, full_filename={self.full_filename}>' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class CallStack: """ Our internal representation of the `callStackType` complex type. @@ -622,7 +622,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class ComponentEvidence: """ Our internal representation of the `componentEvidenceType` complex type. diff --git a/cyclonedx/model/contact.py b/cyclonedx/model/contact.py index 8bc19114..8ee7898d 100644 --- a/cyclonedx/model/contact.py +++ b/cyclonedx/model/contact.py @@ -29,7 +29,7 @@ from .bom_ref import BomRef -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class PostalAddress: """ This is our internal representation of the `postalAddressType` complex type that can be used in multiple places @@ -187,7 +187,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class OrganizationalContact: """ This is our internal representation of the `organizationalContact` complex type that can be used in multiple places @@ -277,7 +277,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class OrganizationalEntity: """ This is our internal representation of the `organizationalEntity` complex type that can be used in multiple places diff --git a/cyclonedx/model/crypto.py b/cyclonedx/model/crypto.py index 6bed0283..d2ccc6c2 100644 --- a/cyclonedx/model/crypto.py +++ b/cyclonedx/model/crypto.py @@ -263,7 +263,7 @@ class CryptoFunction(str, Enum): UNKNOWN = 'unknown' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class AlgorithmProperties: """ This is our internal representation of the cryptoPropertiesType.algorithmProperties ENUM type within the CycloneDX @@ -514,7 +514,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class CertificateProperties: """ This is our internal representation of the `cryptoPropertiesType.certificateProperties` complex type within @@ -746,7 +746,7 @@ class RelatedCryptoMaterialState(str, Enum): SUSPENDED = 'suspended' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class RelatedCryptoMaterialSecuredBy: """ This is our internal representation of the `cryptoPropertiesType.relatedCryptoMaterialProperties.securedBy` complex @@ -817,7 +817,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class RelatedCryptoMaterialProperties: """ This is our internal representation of the `cryptoPropertiesType.relatedCryptoMaterialProperties` complex type @@ -1086,7 +1086,7 @@ class ProtocolPropertiesType(str, Enum): UNKNOWN = 'unknown' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class ProtocolPropertiesCipherSuite: """ This is our internal representation of the `cryptoPropertiesType.protocolProperties.cipherSuites.cipherSuite` @@ -1179,7 +1179,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Ikev2TransformTypes: """ This is our internal representation of the `cryptoPropertiesType.protocolProperties.ikev2TransformTypes` @@ -1321,7 +1321,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class ProtocolProperties: """ This is our internal representation of the `cryptoPropertiesType.protocolProperties` complex type within @@ -1447,7 +1447,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class CryptoProperties: """ This is our internal representation of the `cryptoPropertiesType` complex type within CycloneDX standard. diff --git a/cyclonedx/model/definition.py b/cyclonedx/model/definition.py index 1665cbf8..e773b5db 100644 --- a/cyclonedx/model/definition.py +++ b/cyclonedx/model/definition.py @@ -35,7 +35,7 @@ _T_CreId = TypeVar('_T_CreId', bound='CreId') -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class CreId(serializable.helpers.BaseHelper): """ Helper class that allows us to perform validation on data strings that must conform to @@ -89,7 +89,7 @@ def __str__(self) -> str: return self._id -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Requirement: """ A requirement comprising a standard. @@ -282,7 +282,7 @@ def __repr__(self) -> str: f'title={self.title}, text={self.text}, parent={self.parent}>' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Level: """ Level of compliance for a standard. @@ -397,7 +397,7 @@ def __repr__(self) -> str: f'title={self.title}, description={self.description}>' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Standard: """ A standard of regulations, industry or organizational-specific standards, maturity models, best practices, @@ -574,7 +574,10 @@ def __repr__(self) -> str: f'description={self.description}, owner={self.owner}>' -@serializable.serializable_class(name='definitions') +@serializable.serializable_class( + name='definitions', + ignore_unknown_during_deserialization=True +) class Definitions: """ The repository for definitions diff --git a/cyclonedx/model/dependency.py b/cyclonedx/model/dependency.py index eea79955..b9220570 100644 --- a/cyclonedx/model/dependency.py +++ b/cyclonedx/model/dependency.py @@ -47,7 +47,7 @@ def deserialize(cls, o: Any) -> set['Dependency']: return dependencies -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Dependency: """ Models a Dependency within a BOM. diff --git a/cyclonedx/model/issue.py b/cyclonedx/model/issue.py index 3d9f30de..762dcfa4 100644 --- a/cyclonedx/model/issue.py +++ b/cyclonedx/model/issue.py @@ -39,7 +39,7 @@ class IssueClassification(str, Enum): SECURITY = 'security' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class IssueTypeSource: """ This is our internal representation ofa source within the IssueType complex type that can be used in multiple @@ -108,7 +108,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class IssueType: """ This is our internal representation of an IssueType complex type that can be used in multiple places within diff --git a/cyclonedx/model/license.py b/cyclonedx/model/license.py index 86f08dbe..123de552 100644 --- a/cyclonedx/model/license.py +++ b/cyclonedx/model/license.py @@ -60,7 +60,10 @@ class LicenseAcknowledgement(str, Enum): """Deprecated alias for :class:`LicenseAcknowledgement`""" -@serializable.serializable_class(name='license') +@serializable.serializable_class( + name='license', + ignore_unknown_during_deserialization=True +) class DisjunctiveLicense: """ This is our internal representation of `licenseType` complex type that can be used in multiple places within @@ -245,7 +248,10 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class(name='expression') +@serializable.serializable_class( + name='expression', + ignore_unknown_during_deserialization=True +) class LicenseExpression: """ This is our internal representation of `licenseType`'s expression type that can be used in multiple places within diff --git a/cyclonedx/model/lifecycle.py b/cyclonedx/model/lifecycle.py index d8f1db52..c64e3b37 100644 --- a/cyclonedx/model/lifecycle.py +++ b/cyclonedx/model/lifecycle.py @@ -58,7 +58,7 @@ class LifecyclePhase(str, Enum): DECOMMISSION = 'decommission' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class PredefinedLifecycle: """ Object that defines pre-defined phases in the product lifecycle. @@ -97,7 +97,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class NamedLifecycle: """ Object that defines custom state in the product lifecycle. diff --git a/cyclonedx/model/release_note.py b/cyclonedx/model/release_note.py index 51b704d6..77745edf 100644 --- a/cyclonedx/model/release_note.py +++ b/cyclonedx/model/release_note.py @@ -27,7 +27,7 @@ from ..model.issue import IssueType -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class ReleaseNotes: """ This is our internal representation of a `releaseNotesType` for a Component in a BOM. diff --git a/cyclonedx/model/service.py b/cyclonedx/model/service.py index c50bcb25..443db05b 100644 --- a/cyclonedx/model/service.py +++ b/cyclonedx/model/service.py @@ -41,7 +41,7 @@ from .release_note import ReleaseNotes -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Service(Dependable): """ Class that models the `service` complex type in the CycloneDX schema. diff --git a/cyclonedx/model/tool.py b/cyclonedx/model/tool.py index 904cd78b..c8cfeab0 100644 --- a/cyclonedx/model/tool.py +++ b/cyclonedx/model/tool.py @@ -37,7 +37,7 @@ from py_serializable import ObjectMetadataLibrary, ViewType -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Tool: """ This is our internal representation of the `toolType` complex type within the CycloneDX standard. diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index b217583a..4ce767b3 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -55,7 +55,7 @@ from .tool import Tool, ToolRepository, _ToolRepositoryHelper -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class BomTargetVersionRange: """ Class that represents either a version or version range and its affected status. @@ -148,7 +148,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class BomTarget: """ Class that represents referencing a Component or Service in a BOM. @@ -221,7 +221,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class VulnerabilityAnalysis: """ Class that models the `analysis` sub-element of the `vulnerabilityType` complex type. @@ -361,7 +361,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class VulnerabilityAdvisory: """ Class that models the `advisoryType` complex type. @@ -425,7 +425,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class VulnerabilitySource: """ Class that models the `vulnerabilitySourceType` complex type. @@ -491,7 +491,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class VulnerabilityReference: """ Class that models the nested `reference` within the `vulnerabilityType` complex type. @@ -753,7 +753,7 @@ def get_from_cvss_scores(scores: Union[tuple[float, ...], float, None]) -> 'Vuln return VulnerabilitySeverity.NONE -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class VulnerabilityRating: """ Class that models the `ratingType` complex element CycloneDX core schema. @@ -891,7 +891,7 @@ def __repr__(self) -> str: f'justification={self.justification}>' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class VulnerabilityCredits: """ Class that models the `credits` of `vulnerabilityType` complex type in the CycloneDX schema (version >= 1.4). @@ -966,7 +966,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Vulnerability: """ Class that models the `vulnerabilityType` complex type in the CycloneDX schema (version >= 1.4). diff --git a/pyproject.toml b/pyproject.toml index 33fe0bde..2d4eb679 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,7 @@ keywords = [ [tool.poetry.dependencies] python = "^3.9" packageurl-python = ">=0.11, <2" -py-serializable = "^2.0.0" +py-serializable = "^2.1.0" sortedcontainers = "^2.4.0" license-expression = "^30" jsonschema = { version = "^4.25", extras=['format-nongpl'], optional=true } From 42d7ccaf73de94dbedf9a6c2da4b34f18dc46157 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 21 Jul 2025 12:03:47 +0200 Subject: [PATCH 3/5] wip Signed-off-by: Jan Kowalleck --- cyclonedx/model/bom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py index c3f20116..1719bcf5 100644 --- a/cyclonedx/model/bom.py +++ b/cyclonedx/model/bom.py @@ -314,7 +314,7 @@ def __repr__(self) -> str: return f'' -@serializable.serializable_class( ignore_unknown_during_deserialization=True) +@serializable.serializable_class(ignore_unknown_during_deserialization=True) class Bom: """ This is our internal representation of a bill-of-materials (BOM). From 51d15ce09c646cf3689bece65f57b4ce45c01033 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 21 Jul 2025 12:10:00 +0200 Subject: [PATCH 4/5] tests Signed-off-by: Jan Kowalleck --- tests/test_real_world_examples.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_real_world_examples.py b/tests/test_real_world_examples.py index 8b95f5a1..e764b563 100644 --- a/tests/test_real_world_examples.py +++ b/tests/test_real_world_examples.py @@ -39,6 +39,7 @@ def test_regression_issue_630(self, *_: Any, **__: Any) -> None: Bom.from_xml(input_xml) def test_regression_issue_850(self, *_: Any, **__: Any) -> None: + # tests https://github.com/CycloneDX/cyclonedx-python-lib/issues/850 with open(join(OWN_DATA_DIRECTORY, 'xml', '1.6', 'regression_issue850.xml')) as input_xml: Bom.from_xml(input_xml) From 27e4945eb46a3337c48f2a88d5a6f00720253f1b Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 21 Jul 2025 12:12:30 +0200 Subject: [PATCH 5/5] tests Signed-off-by: Jan Kowalleck --- tests/test_real_world_examples.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_real_world_examples.py b/tests/test_real_world_examples.py index e764b563..3170e730 100644 --- a/tests/test_real_world_examples.py +++ b/tests/test_real_world_examples.py @@ -38,11 +38,6 @@ def test_regression_issue_630(self, *_: Any, **__: Any) -> None: with open(join(OWN_DATA_DIRECTORY, 'xml', '1.6', 'regression_issue630.xml')) as input_xml: Bom.from_xml(input_xml) - def test_regression_issue_850(self, *_: Any, **__: Any) -> None: - # tests https://github.com/CycloneDX/cyclonedx-python-lib/issues/850 - with open(join(OWN_DATA_DIRECTORY, 'xml', '1.6', 'regression_issue850.xml')) as input_xml: - Bom.from_xml(input_xml) - def test_regression_issue677(self, *_: Any, **__: Any) -> None: # tests https://github.com/CycloneDX/cyclonedx-python-lib/issues/677 with open(join(OWN_DATA_DIRECTORY, 'json', '1.5', 'issue677.json')) as input_json: @@ -58,3 +53,8 @@ def test_regression_issue753(self, *_: Any, **__: Any) -> None: bom = Bom.from_json(json) self.assertEqual(2, len(bom.components)) bom.validate() + + def test_regression_issue_850(self, *_: Any, **__: Any) -> None: + # tests https://github.com/CycloneDX/cyclonedx-python-lib/issues/850 + with open(join(OWN_DATA_DIRECTORY, 'xml', '1.6', 'regression_issue850.xml')) as input_xml: + Bom.from_xml(input_xml)