Skip to content

Commit

Permalink
feat: add basic support for CDX 1.5
Browse files Browse the repository at this point in the history
Signed-off-by: Johannes Feichtner <[email protected]>
  • Loading branch information
Churro committed Nov 26, 2023
1 parent 3189e59 commit da14f74
Show file tree
Hide file tree
Showing 63 changed files with 14,294 additions and 21 deletions.
27 changes: 26 additions & 1 deletion cyclonedx/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
NoPropertiesProvidedException,
UnknownHashTypeException,
)
from ..schema.schema import SchemaVersion1Dot3, SchemaVersion1Dot4
from ..schema.schema import SchemaVersion1Dot3, SchemaVersion1Dot4, SchemaVersion1Dot5

"""
Uniform set of models to represent objects within a CycloneDX software bill-of-materials.
Expand Down Expand Up @@ -395,22 +395,45 @@ class ExternalReferenceType(str, Enum):
See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.3/#type_externalReferenceType
"""

ADVERSARY_MODEL = 'adversary-model' # Only supported in >= 1.5
ADVISORIES = 'advisories'
ATTESTATION = 'attestation' # Only supported in >= 1.5
BOM = 'bom'
BUILD_META = 'build-meta'
BUILD_SYSTEM = 'build-system'
CERTIFICATION_REPORT = 'certification-report' # Only supported in >= 1.5
CHAT = 'chat'
CODIFIED_INFRASTRUCTURE = 'codified-infrastructure' # Only supported in >= 1.5
COMPONENT_ANALYSIS_REPORT = 'component-analysis-report' # Only supported in >= 1.5
CONFIGURATION = 'configuration' # Only supported in >= 1.5
DISTRIBUTION = 'distribution'
DISTRIBUTION_INTAKE = 'distribution-intake' # Only supported in >= 1.5
DOCUMENTATION = 'documentation'
DYNAMIC_ANALYSIS_REPORT = 'dynamic-analysis-report' # Only supported in >= 1.5
EVIDENCE = 'evidence' # Only supported in >= 1.5
EXPLOITABILITY_STATEMENT = 'exploitability-statement' # Only supported in >= 1.5
FORMULATION = 'formulation' # Only supported in >= 1.5
ISSUE_TRACKER = 'issue-tracker'
LICENSE = 'license'
LOG = 'log' # Only supported in >= 1.5
MAILING_LIST = 'mailing-list'
MATURITY_REPORT = 'maturity-report' # Only supported in >= 1.5
MODEL_CARD = 'model-card' # Only supported in >= 1.5
OTHER = 'other'
PENTEST_REPORT = 'pentest-report' # Only supported in >= 1.5
POAM = 'poam' # Only supported in >= 1.5
QUALITY_METRICS = 'quality-metrics' # Only supported in >= 1.5
RELEASE_NOTES = 'release-notes' # Only supported in >= 1.4
RISK_ASSESSMENT = 'risk-assessment' # Only supported in >= 1.5
RUNTIME_ANALYSIS_REPORT = 'runtime-analysis-report' # Only supported in >= 1.5
SECURITY_CONTACT = 'security-contact' # Only supported in >= 1.5
STATIC_ANALYSIS_REPORT = 'static-analysis-report' # Only supported in >= 1.5
SOCIAL = 'social'
SCM = 'vcs'
SUPPORT = 'support'
THREAT_MODEL = 'threat-model' # Only supported in >= 1.5
VCS = 'vcs'
VULNERABILITY_ASSERTION = 'vulnerability-assertion' # Only supported in >= 1.5
WEBSITE = 'website'


Expand Down Expand Up @@ -541,6 +564,7 @@ def type(self, type: ExternalReferenceType) -> None:
@property
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'hash')
def hashes(self) -> 'SortedSet[HashType]':
"""
Expand Down Expand Up @@ -1052,6 +1076,7 @@ def hashes(self, hashes: Iterable[HashType]) -> None:

@property
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
@serializable.xml_sequence(5)
def external_references(self) -> 'SortedSet[ExternalReference]':
Expand Down
11 changes: 10 additions & 1 deletion cyclonedx/model/bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
SchemaVersion1Dot2,
SchemaVersion1Dot3,
SchemaVersion1Dot4,
SchemaVersion1Dot5,
)
from ..serialization import LicenseRepositoryHelper, UrnUuidHelper
from . import ExternalReference, OrganizationalContact, OrganizationalEntity, Property, ThisTool, Tool, get_now_utc
Expand All @@ -53,7 +54,7 @@ class BomMetaData:
This is our internal representation of the metadata complex type within the CycloneDX standard.
.. note::
See the CycloneDX Schema for Bom metadata: https://cyclonedx.org/docs/1.4/#type_metadata
See the CycloneDX Schema for Bom metadata: https://cyclonedx.org/docs/1.5/#type_metadata
"""

def __init__(self, *, tools: Optional[Iterable[Tool]] = None,
Expand Down Expand Up @@ -187,6 +188,7 @@ def supplier(self, supplier: Optional[OrganizationalEntity]) -> None:
@property
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.type_mapping(LicenseRepositoryHelper)
@serializable.xml_sequence(7)
def licenses(self) -> LicenseRepository:
Expand All @@ -205,6 +207,7 @@ def licenses(self, licenses: Iterable[License]) -> None:
@property
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
@serializable.xml_sequence(8)
def properties(self) -> 'SortedSet[Property]':
Expand Down Expand Up @@ -294,6 +297,7 @@ def __init__(self, *, components: Optional[Iterable[Component]] = None,
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_attribute()
def serial_number(self) -> UUID:
"""
Expand All @@ -313,6 +317,7 @@ def serial_number(self, serial_number: UUID) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_sequence(1)
def metadata(self) -> BomMetaData:
"""
Expand Down Expand Up @@ -392,6 +397,7 @@ def has_component(self, component: Component) -> bool:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'service')
@serializable.xml_sequence(3)
def services(self) -> 'SortedSet[Service]':
Expand All @@ -412,6 +418,7 @@ def services(self, services: Iterable[Service]) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
@serializable.xml_sequence(4)
def external_references(self) -> 'SortedSet[ExternalReference]':
Expand Down Expand Up @@ -462,6 +469,7 @@ def has_vulnerabilities(self) -> bool:

@property
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'vulnerability')
@serializable.xml_sequence(8)
def vulnerabilities(self) -> 'SortedSet[Vulnerability]':
Expand Down Expand Up @@ -490,6 +498,7 @@ def version(self, version: int) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'dependency')
@serializable.xml_sequence(5)
def dependencies(self) -> 'SortedSet[Dependency]':
Expand Down
16 changes: 16 additions & 0 deletions cyclonedx/model/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
SchemaVersion1Dot2,
SchemaVersion1Dot3,
SchemaVersion1Dot4,
SchemaVersion1Dot5,
)
from ..serialization import BomRefHelper, LicenseRepositoryHelper, PackageUrl
from . import (
Expand Down Expand Up @@ -255,12 +256,16 @@ class ComponentType(str, Enum):
"""
APPLICATION = 'application'
CONTAINER = 'container'
DATA = 'data'
DEVICE = 'device'
DEVICE_DRIVER = 'device-driver'
FILE = 'file'
FIRMWARE = 'firmware'
FRAMEWORK = 'framework'
LIBRARY = 'library'
MACHINE_LEARNING_MODEL = 'machine-learning-model'
OPERATING_SYSTEM = 'operating-system'
PLATFORM = 'platform'


class Diff:
Expand Down Expand Up @@ -528,6 +533,7 @@ def commits(self, commits: Iterable[Commit]) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'patch')
@serializable.xml_sequence(5)
def patches(self) -> 'SortedSet[Patch]':
Expand Down Expand Up @@ -849,6 +855,7 @@ def mime_type(self, mime_type: Optional[str]) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_attribute()
@serializable.xml_name('bom-ref')
def bom_ref(self) -> BomRef:
Expand All @@ -867,6 +874,7 @@ def bom_ref(self) -> BomRef:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_sequence(1)
def supplier(self) -> Optional[OrganizationalEntity]:
"""
Expand All @@ -886,6 +894,7 @@ def supplier(self, supplier: Optional[OrganizationalEntity]) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_sequence(2)
def author(self) -> Optional[str]:
"""
Expand Down Expand Up @@ -1028,6 +1037,7 @@ def hashes(self, hashes: Iterable[HashType]) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.type_mapping(LicenseRepositoryHelper)
@serializable.xml_sequence(10)
def licenses(self) -> LicenseRepository:
Expand Down Expand Up @@ -1098,6 +1108,7 @@ def purl(self, purl: Optional[PackageURL]) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_sequence(14)
def swid(self) -> Optional[Swid]:
"""
Expand Down Expand Up @@ -1127,6 +1138,7 @@ def modified(self, modified: bool) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_sequence(16)
def pedigree(self) -> Optional[Pedigree]:
"""
Expand All @@ -1147,6 +1159,7 @@ def pedigree(self, pedigree: Optional[Pedigree]) -> None:
@serializable.view(SchemaVersion1Dot2)
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'reference')
@serializable.xml_sequence(17)
def external_references(self) -> 'SortedSet[ExternalReference]':
Expand All @@ -1166,6 +1179,7 @@ def external_references(self, external_references: Iterable[ExternalReference])
@property
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
@serializable.xml_sequence(18)
def properties(self) -> 'SortedSet[Property]':
Expand Down Expand Up @@ -1203,6 +1217,7 @@ def components(self, components: Iterable['Component']) -> None:
@property
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_sequence(20)
def evidence(self) -> Optional[ComponentEvidence]:
"""
Expand All @@ -1219,6 +1234,7 @@ def evidence(self, evidence: Optional[ComponentEvidence]) -> None:

@property
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_sequence(21)
def release_notes(self) -> Optional[ReleaseNotes]:
"""
Expand Down
4 changes: 3 additions & 1 deletion cyclonedx/model/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from cyclonedx.serialization import BomRefHelper, LicenseRepositoryHelper

from ..schema.schema import SchemaVersion1Dot3, SchemaVersion1Dot4
from ..schema.schema import SchemaVersion1Dot3, SchemaVersion1Dot4, SchemaVersion1Dot5
from . import ComparableTuple, DataClassification, ExternalReference, OrganizationalEntity, Property, XsUri
from .bom_ref import BomRef
from .dependency import Dependable
Expand Down Expand Up @@ -291,6 +291,7 @@ def services(self, services: Iterable['Service']) -> None:

@property
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_sequence(14)
def release_notes(self) -> Optional[ReleaseNotes]:
"""
Expand All @@ -308,6 +309,7 @@ def release_notes(self, release_notes: Optional[ReleaseNotes]) -> None:
@property
@serializable.view(SchemaVersion1Dot3)
@serializable.view(SchemaVersion1Dot4)
@serializable.view(SchemaVersion1Dot5)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'property')
@serializable.xml_sequence(12)
def properties(self) -> 'SortedSet[Property]':
Expand Down
2 changes: 1 addition & 1 deletion cyclonedx/output/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from .json import Json as JsonOutputter
from .xml import Xml as XmlOutputter

LATEST_SUPPORTED_SCHEMA_VERSION = SchemaVersion.V1_4
LATEST_SUPPORTED_SCHEMA_VERSION = SchemaVersion.V1_5


class BaseOutput(ABC):
Expand Down
8 changes: 8 additions & 0 deletions cyclonedx/output/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
SchemaVersion1Dot2,
SchemaVersion1Dot3,
SchemaVersion1Dot4,
SchemaVersion1Dot5,
)
from . import BaseOutput, BomRefDiscriminator

Expand Down Expand Up @@ -117,7 +118,14 @@ def _get_schema_uri(self) -> str:
return 'http://cyclonedx.org/schema/bom-1.4.schema.json'


class JsonV1Dot5(Json, SchemaVersion1Dot5):

def _get_schema_uri(self) -> str:
return 'http://cyclonedx.org/schema/bom-1.5.schema.json'


BY_SCHEMA_VERSION: Dict[SchemaVersion, Type[Json]] = {
SchemaVersion.V1_5: JsonV1Dot5,
SchemaVersion.V1_4: JsonV1Dot4,
SchemaVersion.V1_3: JsonV1Dot3,
SchemaVersion.V1_2: JsonV1Dot2,
Expand Down
6 changes: 6 additions & 0 deletions cyclonedx/output/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
SchemaVersion1Dot2,
SchemaVersion1Dot3,
SchemaVersion1Dot4,
SchemaVersion1Dot5,
)
from . import BaseOutput, BomRefDiscriminator

Expand Down Expand Up @@ -114,7 +115,12 @@ class XmlV1Dot4(Xml, SchemaVersion1Dot4):
pass


class XmlV1Dot5(Xml, SchemaVersion1Dot5):
pass


BY_SCHEMA_VERSION: Dict[SchemaVersion, Type[Xml]] = {
SchemaVersion.V1_5: XmlV1Dot5,
SchemaVersion.V1_4: XmlV1Dot4,
SchemaVersion.V1_3: XmlV1Dot3,
SchemaVersion.V1_2: XmlV1Dot2,
Expand Down
1 change: 1 addition & 0 deletions cyclonedx/schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class SchemaVersion(Enum):
my_sv = SchemaVersion.V1_3
"""

V1_5 = (1, 5)
V1_4 = (1, 4)
V1_3 = (1, 3)
V1_2 = (1, 2)
Expand Down
2 changes: 2 additions & 0 deletions cyclonedx/schema/_res/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ Currently using version
| [`bom-1.2.SNAPSHOT.xsd`](bom-1.2.SNAPSHOT.xsd) | applied changes: 1 |
| [`bom-1.3.SNAPSHOT.xsd`](bom-1.3.SNAPSHOT.xsd) | applied changes: 1 |
| [`bom-1.4.SNAPSHOT.xsd`](bom-1.4.SNAPSHOT.xsd) | applied changes: 1 |
| [`bom-1.5.SNAPSHOT.xsd`](bom-1.5.SNAPSHOT.xsd) | applied changes: 1 |
| [`bom-1.2.SNAPSHOT.schema.json`](bom-1.2.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
| [`bom-1.3.SNAPSHOT.schema.json`](bom-1.3.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
| [`bom-1.4.SNAPSHOT.schema.json`](bom-1.4.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
| [`bom-1.5.SNAPSHOT.schema.json`](bom-1.5.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
| [`bom-1.2-strict.SNAPSHOT.schema.json`](bom-1.2-strict.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
| [`bom-1.3-strict.SNAPSHOT.schema.json`](bom-1.3-strict.SNAPSHOT.schema.json) | applied changes: 2,3,4,5 |
| [`spdx.SNAPSHOT.xsd`](spdx.SNAPSHOT.xsd) | |
Expand Down
3 changes: 3 additions & 0 deletions cyclonedx/schema/_res/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
__DIR = dirname(__file__)

BOM_XML: Dict[SchemaVersion, Optional[str]] = {
SchemaVersion.V1_5: join(__DIR, 'bom-1.5.SNAPSHOT.xsd'),
SchemaVersion.V1_4: join(__DIR, 'bom-1.4.SNAPSHOT.xsd'),
SchemaVersion.V1_3: join(__DIR, 'bom-1.3.SNAPSHOT.xsd'),
SchemaVersion.V1_2: join(__DIR, 'bom-1.2.SNAPSHOT.xsd'),
Expand All @@ -36,6 +37,7 @@
}

BOM_JSON: Dict[SchemaVersion, Optional[str]] = {
SchemaVersion.V1_5: join(__DIR, 'bom-1.5.SNAPSHOT.schema.json'),
SchemaVersion.V1_4: join(__DIR, 'bom-1.4.SNAPSHOT.schema.json'),
SchemaVersion.V1_3: join(__DIR, 'bom-1.3.SNAPSHOT.schema.json'),
SchemaVersion.V1_2: join(__DIR, 'bom-1.2.SNAPSHOT.schema.json'),
Expand All @@ -46,6 +48,7 @@

BOM_JSON_STRICT: Dict[SchemaVersion, Optional[str]] = {
# >= v1.4 is already strict - no special file here
SchemaVersion.V1_5: join(__DIR, 'bom-1.5.SNAPSHOT.schema.json'),
SchemaVersion.V1_4: join(__DIR, 'bom-1.4.SNAPSHOT.schema.json'),
# <= 1.3 need special files
SchemaVersion.V1_3: join(__DIR, 'bom-1.3-strict.SNAPSHOT.schema.json'),
Expand Down
Loading

0 comments on commit da14f74

Please sign in to comment.