diff --git a/.circleci/config.yml b/.circleci/config.yml
index 990c6caf..fd42402a 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -15,13 +15,26 @@
version: 2.1
executors:
- python:
+ python36:
+ docker:
+ - image: circleci/python:3.6
+ python37:
docker:
- image: circleci/python:3.7
+ python38:
+ docker:
+ - image: circleci/python:3.8
+ python39:
+ docker:
+ - image: circleci/python:3.9
jobs:
publish:
- executor: python
+ parameters:
+ executor:
+ type: executor
+ default: python39
+ executor: << parameters.executor >>
environment:
PIPENV_VENV_IN_PROJECT: true
steps:
@@ -39,42 +52,52 @@ jobs:
# TODO: perform publish steps, maybe using python-semantic-release
build:
- executor: python
+ parameters:
+ executor:
+ type: executor
+ default: python39
+ executor: << parameters.executor >>
environment:
PIPENV_VENV_IN_PROJECT: true
steps:
- checkout
- run:
- name: Setup Python environment
+ name: Install Tox & Coverage
+ command: |
+ pip install tox coverage
+ - run:
+ name: Run tox
command: |
- # TODO: do stuff, like setup .venv, poetry, pip etc.
+ tox --result-json=.tox/results.json
- run:
- name: Run tests
+ name: Generate Coverage Reports
command: |
- # TODO: maybe run pylint and run those tests
+ coverage report && coverage xml -o test-reports/coverage.xml && coverage html -d test-reports
- run:
name: Run self scan
command: |
# TODO: audit with jake maybe?
- - store_test_results: # Upload test results for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
- path: test-results
- - store_artifacts: # Upload test summary for display in Artifacts: https://circleci.com/docs/2.0/artifacts/
- path: test-results
- destination: tr1
+ - store_artifacts:
+ path: .tox/results.json
+ destination: tox-logs
+ - store_artifacts:
+ path: test-reports
+ destination: test-reports
+ - store_test_results:
+ path: test-reports
workflows:
version: 2
build_and_test_and_publish:
jobs:
- - build
-# TODO: enable to publish after successful build
-# - publish:
-# filters:
-# branches:
-# only: main
-# context: pypi
-# requires:
-# - build
+ - build:
+ executor: python36
+ - build:
+ executor: python37
+ - build:
+ executor: python38
+ - build:
+ executor: python39
build_nightly:
triggers:
@@ -84,4 +107,11 @@ workflows:
branches:
only: main
jobs:
- - build
+ - build:
+ executor: python36
+ - build:
+ executor: python37
+ - build:
+ executor: python38
+ - build:
+ executor: python39
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..8b2226c1
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,29 @@
+# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: 'pip'
+ directory: '/'
+ schedule:
+ interval: 'weekly'
+ day: 'saturday'
+ allow:
+ - dependency-type: 'all'
+ versioning-strategy: 'auto'
+ labels: [ 'dependencies' ]
+ commit-message:
+ ## prefix maximum string length of 15
+ prefix: 'poetry'
+ include: 'scope'
+ open-pull-requests-limit: 999
+ - package-ecosystem: 'github-actions'
+ directory: '/'
+ schedule:
+ interval: 'weekly'
+ day: 'saturday'
+ labels: [ 'dependencies' ]
+ commit-message:
+ ## prefix maximum string length of 15
+ prefix: 'gh-actions'
+ include: 'scope'
+ open-pull-requests-limit: 999
\ No newline at end of file
diff --git a/.github/workflows/poetry.yml b/.github/workflows/poetry.yml
new file mode 100644
index 00000000..8990a985
--- /dev/null
+++ b/.github/workflows/poetry.yml
@@ -0,0 +1,99 @@
+# For details of what checks are run for PRs please refer below
+# docs: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
+name: Python CI
+
+on:
+ push:
+ branches: ["master"]
+ pull_request:
+ workflow_dispatch:
+ schedule:
+ # schedule weekly tests, since dependencies are not intended to be pinned
+ # this means: at 23:42 on Fridays
+ - cron: '42 23 * * 5'
+
+env:
+ REPORTS_DIR: CI_reports
+
+jobs:
+ coding-standards:
+ name: Linting & Coding Standards
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ # see https://github.com/actions/checkout
+ uses: actions/checkout@v2
+ - name: Setup Python Environment
+ # see https://github.com/actions/setup-python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.9
+ architecture: 'x64'
+ - name: Install poetry
+ # see https://github.com/marketplace/actions/setup-poetry
+ uses: Gr1N/setup-poetry@v7
+ with:
+ poetry-version: 1.1.8
+ - uses: actions/cache@v2
+ with:
+ path: ~/.cache/pypoetry/virtualenvs
+ key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
+ - name: Install dependencies
+ run: poetry install
+ - name: Run tox
+ run: poetry run tox -e flake8
+
+ build-and-test:
+ name: Build & Test (Python ${{ matrix.python-version }}
+ runs-on: ubuntu-latest
+ env:
+ REPORTS_ARTIFACT: tests-reports
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version:
+ - "3.9" # highest supported
+ - "3.8"
+ - "3.7"
+ - "3.6" # lowest supported
+ timeout-minutes: 30
+ steps:
+ - name: Checkout
+ # see https://github.com/actions/checkout
+ uses: actions/checkout@v2
+ - name: Create reports directory
+ run: mkdir ${{ env.REPORTS_DIR }}
+ - name: Setup Python Environment
+ # see https://github.com/actions/setup-python
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ architecture: 'x64'
+ - name: Install poetry
+ # see https://github.com/marketplace/actions/setup-poetry
+ uses: Gr1N/setup-poetry@v7
+ with:
+ poetry-version: 1.1.8
+ - uses: actions/cache@v2
+ with:
+ path: ~/.cache/pypoetry/virtualenvs
+ key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
+ - name: Install dependencies
+ run: poetry install
+ - name: Ensure build successful
+ run: poetry build
+ - name: Run tox
+ run: poetry run tox -e py${{ matrix.python-version }}
+ - name: Generate coverage reports
+ run: >
+ poetry run coverage report &&
+ poetry run coverage xml -o ${{ env.REPORTS_DIR }}/coverage.xml &&
+ poetry run coverage html -d ${{ env.REPORTS_DIR }}
+ - name: Artifact reports
+ if: ${{ ! cancelled() }}
+ # see https://github.com/actions/upload-artifact
+ uses: actions/upload-artifact@v2
+ with:
+ name: ${{ env.REPORTS_ARTIFACT }}
+ path: ${{ env.REPORTS_DIR }}
+ if-no-files-found: error
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 25a2e3f0..a414d201 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,24 @@
+# Exlude python build & distribution directories
+build/
+dist/
+*.egg-info*
+
+# Exlude *.pyc
+*.pyc
+
+# Exclude test-related items
+.tox/*
+
+# Exclude coverage
+.coverage
+test-reports
+
+# Exclude Python Virtual Environment
+venv/*
+
+# Exlude IDE related files
+.idea/*
+.vscode/*
+
# ci config for local ci build
-/.circleci/local-config.yml
+/.circleci/local-config.yml
\ No newline at end of file
diff --git a/MAINFEST.in b/MAINFEST.in
new file mode 100644
index 00000000..d922f707
--- /dev/null
+++ b/MAINFEST.in
@@ -0,0 +1,3 @@
+include README.md
+include VERSION
+include cyclonedx/schema/*
\ No newline at end of file
diff --git a/README.md b/README.md
index af047542..c7f366df 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,183 @@
# Python Library for generating CycloneDX
[![CircleCI](https://circleci.com/gh/sonatype-nexus-community/cyclonedx-python-lib.svg?style=shield)](https://circleci.com/gh/sonatype-nexus-community/cyclonedx-python-lib)
+![GitHub Workflow Status](https://img.shields.io/github/workflow/status/sonatype-nexus-community/cyclonedx-python-lib/Python%20CI)
+![Python Version Support](https://img.shields.io/badge/python-3.7%20%7C%203.8%20%7C%203.9-blue)
+[![GitHub license](https://img.shields.io/github/license/sonatype-nexus-community/cyclonedx-python-lib)](https://github.com/sonatype-nexus-community/cyclonedx-python-lib/blob/main/LICENSE)
+[![GitHub issues](https://img.shields.io/github/issues/sonatype-nexus-community/cyclonedx-python-lib)](https://github.com/sonatype-nexus-community/cyclonedx-python-lib/issues)
+[![GitHub forks](https://img.shields.io/github/forks/sonatype-nexus-community/cyclonedx-python-lib)](https://github.com/sonatype-nexus-community/cyclonedx-python-lib/network)
+[![GitHub stars](https://img.shields.io/github/stars/sonatype-nexus-community/cyclonedx-python-lib)](https://github.com/sonatype-nexus-community/cyclonedx-python-lib/stargazers)
-_Coming soon!_
+----
+
+This CycloneDX module for Python can generate valid CycloneDX bill-of-material document containing an aggregate of all
+project dependencies.
+
+This module is not designed for standalone use. If you're looking for a tool to run to generate CycloneDX software
+bill-of-materials documents, why not checkout:
+
+- [Jake](https://github.com/sonatype-nexus-community/jake)
+
+Or you can use this module yourself in your application to generate SBOMs.
+
+CycloneDX is a lightweight BOM specification that is easily created, human-readable, and simple to parse.
+
+## Installation
+
+Install from pypi.org as you would any other Python module:
+
+```
+pip install cyclonedx-python-lib
+```
+
+## Architecture
+
+This module break out into three key areas:
+
+1. **Parser**: Use a parser that suits your needs to automatically gather information about your environment or
+ application
+2. **Model**: Internal models used to unify data from different parsers
+3. **Output**: Choose and configure an output which allows you to define output format as well as the CycloneDX schema
+ version
+
+### Parsing
+
+You can use one of the parsers to obtain information about your project or environment. Available parsers:
+
+| Parser | Class / Import | Description |
+| ------- | ------ | ------ |
+| Environment | `from cyclonedx.parser.environment import EnvironmentParser` | Looks at the packaged installed in your current Python environment. |
+| RequirementsParser | `from cyclonedx.parser.requirements import RequirementsParser` | Parses a multiline string that you provide that conforms to the `requirements.txt` [PEP-508](https://www.python.org/dev/peps/pep-0508/) standard. |
+| RequirementsFileParser | `from cyclonedx.parser.requirements import RequirementsFileParser` | Parses a file that you provide the path to that conforms to the `requirements.txt` [PEP-508](https://www.python.org/dev/peps/pep-0508/) standard. |
+
+#### Example
+
+```
+from cyclonedx.parser.environment import EnvironmentParser
+
+parser = EnvironmentParser()
+```
+
+### Modelling
+
+You can create a BOM Model from either an Parser instance or manually using the methods avaialbel directly on the `Bom` class.
+
+#### Example from a Parser
+
+```
+from cyclonedx.model.bom import Bom
+from cyclonedx.parser.environment import EnvironmentParser
+
+parser = EnvironmentParser()
+bom = Bom.from_parser(parser=parser)
+```
+
+### Generating Output
+
+Once you have an instance of a `Bom` you can produce output in either `JSON` or `XML` against any of the supporting CycloneDX schema versions as you require.
+
+We provide two helper methods:
+1. Output to string (for you to do with as you require)
+2. Output directly to a filename you provide
+
+##### Example as JSON
+
+```
+from cyclonedx.output import get_instance, OutputFormat
+
+outputter = get_instance(bom=bom, output_format=OutputFormat.JSON)
+outputter.output_as_string()
+```
+
+##### Example as XML
+```
+from cyclonedx.output import get_instance, SchemaVersion
+
+outputter = get_instance(bom=bom, schema_version=SchemaVersion.V1_2)
+outputter.output_to_file(filename='/tmp/sbom-v1.2.xml')
+```
+
+## Schema Support
+
+This library is a work in progress and complete support for all parts of the CycloneDX schema will come in future releases.
+
+Here is a summary of the parts of the schema supported by this library:
+
+_Note: We refer throughout using XPath, but the same is true for both XML and JSON output formats._
+
+
+
+
+ XPath |
+ Support v1.3 |
+ Support v1.2 |
+ Support v1.1 |
+ Support v1.0 |
+ Notes |
+
+
+
+
+ /bom |
+ Y | Y | Y | Y |
+
+ This is the root element and is supported with all it's defined attributes.
+ |
+
+
+ /bom/metadata |
+ Y | Y | N/A | N/A |
+
+ Only timestamp is currently supported
+ |
+
+
+ /bom/components |
+ Y | Y | Y | Y |
+ |
+
+
+ /bom/components/component |
+
+
+ ./author |
+ Y | Y | N/A | N/A |
+ |
+
+
+ ./name |
+ Y | Y | Y | Y |
+ |
+
+
+ ./version |
+ Y | Y | Y | Y |
+ |
+
+
+ ./purl |
+ Y | Y | Y | Y |
+ |
+
+
+
+
+### Notes on Schema Support
+
+1. N/A is where the CycloneDX standard does not include this
+2. If the table above does not refer to an element, it is not currently supported
+
+## Python Support
+
+We endeavour to support all functionality for all [current actively supported Python versions](https://www.python.org/downloads/).
+However, some features may not be possible/present in older Python versions due to their lack of support.
## The Fine Print
Remember:
-It is worth noting that this is **NOT SUPPORTED** by Sonatype, and is a contribution of ours
-to the open source community (read: you!)
+It is worth noting that this is **NOT SUPPORTED** by Sonatype, and is a contribution of ours to the open source
+community (read: you!)
* Use this contribution at the risk tolerance that you have
* Do NOT file Sonatype support tickets related to `cyclonedx-python-lib` support in regard to this project
diff --git a/VERSION b/VERSION
new file mode 100644
index 00000000..8a9ecc2e
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.0.1
\ No newline at end of file
diff --git a/cyclonedx/__init__.py b/cyclonedx/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/cyclonedx/model/__init__.py b/cyclonedx/model/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py
new file mode 100644
index 00000000..d7a4ac07
--- /dev/null
+++ b/cyclonedx/model/bom.py
@@ -0,0 +1,83 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import datetime
+from typing import List
+from uuid import uuid4
+
+from .component import Component
+from ..parser import BaseParser
+
+
+class BomMetaData:
+ """
+ Our internal representation of the metadata complex type within the CycloneDX standard.
+
+ See https://cyclonedx.org/docs/1.3/#type_metadata
+ """
+
+ _timestamp: datetime.datetime
+
+ def __init__(self):
+ self._timestamp = datetime.datetime.now(tz=datetime.timezone.utc)
+
+ def get_timestamp(self) -> datetime.datetime:
+ return self._timestamp
+
+
+class Bom:
+ """
+ This is our internal representation of the BOM.
+
+ We can pass a BOM instance to a Generator to produce CycloneDX in the required format and according
+ to the requested schema version.
+ """
+
+ _uuid: str
+ _metadata: BomMetaData = None
+ _components: List[Component] = []
+
+ @staticmethod
+ def from_parser(parser: BaseParser):
+ bom = Bom()
+ bom.add_components(parser.get_components())
+ return bom
+
+ def __init__(self):
+ self._uuid = uuid4()
+ self._metadata = BomMetaData()
+ self._components.clear()
+
+ def add_component(self, component: Component):
+ self._components.append(component)
+
+ def add_components(self, components: List[Component]):
+ self._components = self._components + components
+
+ def component_count(self) -> int:
+ return len(self._components)
+
+ def get_components(self) -> List[Component]:
+ return self._components
+
+ def get_metadata(self) -> BomMetaData:
+ return self._metadata
+
+ def get_urn_uuid(self) -> str:
+ return 'urn:uuid:{}'.format(self._uuid)
+
+ def has_component(self, component: Component) -> bool:
+ return component in self._components
diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py
new file mode 100644
index 00000000..5cfed9b3
--- /dev/null
+++ b/cyclonedx/model/component.py
@@ -0,0 +1,94 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from enum import Enum
+
+PURL_TYPE_PREFIX = 'pypi'
+
+
+class ComponentType(Enum):
+ """
+ Enum object that defines the permissible 'types' for a Component according to the CycloneDX
+ schemas.
+ """
+ APPLICATION = 'application'
+ CONTAINER = 'container'
+ DEVICE = 'device'
+ FILE = 'file'
+ FIRMWARE = 'firmware'
+ FRAMEWORK = 'framework'
+ LIBRARY = 'library'
+ OPERATING_SYSTEM = 'operating-system'
+
+
+class Component:
+ """
+ An object that mirrors the Component type in the CycloneDX schema.
+ """
+ _type: ComponentType
+ _name: str
+ _version: str
+ _qualifiers: str
+
+ _author: str = None
+ _description: str = None
+ _license: str = None
+
+ def __init__(self, name: str, version: str, qualifiers: str = None,
+ component_type: ComponentType = ComponentType.LIBRARY):
+ self._name = name
+ self._version = version
+ self._type = component_type
+ self._qualifiers = qualifiers
+
+ def get_author(self) -> str:
+ return self._author
+
+ def get_description(self) -> str:
+ return self._description
+
+ def get_license(self) -> str:
+ return self._license
+
+ def get_name(self) -> str:
+ return self._name
+
+ def get_purl(self) -> str:
+ base_purl = 'pkg:{}/{}@{}'.format(PURL_TYPE_PREFIX, self._name, self._version)
+ if self._qualifiers:
+ base_purl = '{}?{}'.format(base_purl, self._qualifiers)
+ return base_purl
+
+ def get_type(self) -> ComponentType:
+ return self._type
+
+ def get_version(self) -> str:
+ return self._version
+
+ def set_author(self, author: str):
+ self._author = author
+
+ def set_description(self, description: str):
+ self._description = description
+
+ def set_license(self, license_str: str):
+ self._license = license_str
+
+ def __eq__(self, other):
+ return other.get_purl() == self.get_purl()
+
+ def __repr__(self):
+ return ''.format(self._name, self._version)
diff --git a/cyclonedx/output/__init__.py b/cyclonedx/output/__init__.py
new file mode 100644
index 00000000..a83e1618
--- /dev/null
+++ b/cyclonedx/output/__init__.py
@@ -0,0 +1,78 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import importlib
+from abc import ABC, abstractmethod
+from enum import Enum
+
+from ..model.bom import Bom
+
+
+class OutputFormat(Enum):
+ JSON: str = 'Json'
+ XML: str = 'Xml'
+
+
+class SchemaVersion(Enum):
+ V1_0: str = 'V1Dot0'
+ V1_1: str = 'V1Dot1'
+ V1_2: str = 'V1Dot2'
+ V1_3: str = 'V1Dot3'
+
+
+DEFAULT_SCHEMA_VERSION = SchemaVersion.V1_3
+
+
+class BaseOutput(ABC):
+ _bom: Bom
+
+ def __init__(self, bom: Bom = None):
+ self._bom = bom
+
+ def get_bom(self) -> Bom:
+ return self._bom
+
+ def set_bom(self, bom: Bom):
+ self._bom = bom
+
+ @abstractmethod
+ def output_as_string(self) -> str:
+ pass
+
+ @abstractmethod
+ def output_to_file(self, filename: str):
+ pass
+
+
+def get_instance(bom: Bom = None, output_format: OutputFormat = OutputFormat.XML,
+ schema_version: SchemaVersion = DEFAULT_SCHEMA_VERSION) -> BaseOutput:
+ """
+ Helper method to quickly get the correct output class/formatter.
+
+ Pass in your BOM and optionally an output format and schema version (defaults to XML and latest schema version).
+
+ :param bom: Bom
+ :param output_format: OutputFormat
+ :param schema_version: SchemaVersion
+ :return:
+ """
+ try:
+ module = importlib.import_module(f"cyclonedx.output.{output_format.value.lower()}")
+ output_klass = getattr(module, f"{output_format.value}{schema_version.value}")
+ except (ImportError, AttributeError):
+ raise ValueError(f"Unknown format {output_format.value.lower()!r}") from None
+
+ return output_klass(bom=bom)
diff --git a/cyclonedx/output/json.py b/cyclonedx/output/json.py
new file mode 100644
index 00000000..99bda479
--- /dev/null
+++ b/cyclonedx/output/json.py
@@ -0,0 +1,81 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import json
+
+from . import BaseOutput
+from .schema import BaseSchemaVersion, SchemaVersion1Dot0, SchemaVersion1Dot1, SchemaVersion1Dot2, SchemaVersion1Dot3
+from ..model.component import Component
+
+
+class Json(BaseOutput, BaseSchemaVersion):
+
+ def output_as_string(self) -> str:
+ return json.dumps(self._get_json())
+
+ def output_to_file(self, filename: str):
+ raise NotImplementedError
+
+ def _get_json(self) -> dict:
+ components = list(map(self._get_component_as_dict, self.get_bom().get_components()))
+
+ response = {
+ "bomFormat": "CycloneDX",
+ "specVersion": str(self.get_schema_version()),
+ "serialNumber": self.get_bom().get_urn_uuid(),
+ "version": 1,
+ "components": components
+ }
+
+ if self.bom_supports_metadata():
+ response['metadata'] = self._get_metadata_as_dict()
+
+ return response
+
+ def _get_component_as_dict(self, component: Component) -> dict:
+ c = {
+ "type": component.get_type().value,
+ "name": component.get_name(),
+ "version": component.get_version(),
+ "purl": component.get_purl()
+ }
+
+ if self.component_supports_author() and component.get_author() is not None:
+ c['author'] = component.get_author()
+
+ return c
+
+ def _get_metadata_as_dict(self) -> dict:
+ metadata = self.get_bom().get_metadata()
+ return {
+ "timestamp": metadata.get_timestamp().isoformat()
+ }
+
+
+class JsonV1Dot0(Json, SchemaVersion1Dot0):
+ pass
+
+
+class JsonV1Dot1(Json, SchemaVersion1Dot1):
+ pass
+
+
+class JsonV1Dot2(Json, SchemaVersion1Dot2):
+ pass
+
+
+class JsonV1Dot3(Json, SchemaVersion1Dot3):
+ pass
diff --git a/cyclonedx/output/schema.py b/cyclonedx/output/schema.py
new file mode 100644
index 00000000..03f637ab
--- /dev/null
+++ b/cyclonedx/output/schema.py
@@ -0,0 +1,71 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from abc import ABC
+
+
+class BaseSchemaVersion(ABC):
+
+ def bom_supports_metadata(self) -> bool:
+ return True
+
+ def component_supports_author(self) -> bool:
+ return True
+
+ def component_supports_bom_ref(self) -> bool:
+ return True
+
+ def get_schema_version(self) -> str:
+ pass
+
+
+class SchemaVersion1Dot3(BaseSchemaVersion):
+
+ def get_schema_version(self) -> str:
+ return '1.3'
+
+
+class SchemaVersion1Dot2(BaseSchemaVersion):
+
+ def get_schema_version(self) -> str:
+ return '1.2'
+
+
+class SchemaVersion1Dot1(BaseSchemaVersion):
+
+ def bom_supports_metadata(self) -> bool:
+ return False
+
+ def component_supports_author(self) -> bool:
+ return False
+
+ def get_schema_version(self) -> str:
+ return '1.1'
+
+
+class SchemaVersion1Dot0(BaseSchemaVersion):
+
+ def bom_supports_metadata(self) -> bool:
+ return False
+
+ def component_supports_author(self) -> bool:
+ return False
+
+ def component_supports_bom_ref(self) -> bool:
+ return False
+
+ def get_schema_version(self) -> str:
+ return '1.0'
diff --git a/cyclonedx/output/xml.py b/cyclonedx/output/xml.py
new file mode 100644
index 00000000..734e0e11
--- /dev/null
+++ b/cyclonedx/output/xml.py
@@ -0,0 +1,115 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from xml.etree import ElementTree
+
+from . import BaseOutput
+from .schema import BaseSchemaVersion, SchemaVersion1Dot0, SchemaVersion1Dot1, SchemaVersion1Dot2, SchemaVersion1Dot3
+from ..model.component import Component
+
+
+class Xml(BaseOutput, BaseSchemaVersion):
+ XML_VERSION_DECLARATION: str = ''
+
+ def get_target_namespace(self) -> str:
+ return 'http://cyclonedx.org/schema/bom/{}'.format(self.get_schema_version())
+
+ def output_as_string(self) -> str:
+ bom = self._get_bom_root_element()
+
+ if self.bom_supports_metadata():
+ bom = self._add_metadata(bom=bom)
+
+ components = ElementTree.SubElement(bom, 'components')
+ for component in self.get_bom().get_components():
+ components.append(self._get_component_as_xml_element(component=component))
+
+ return Xml.XML_VERSION_DECLARATION + ElementTree.tostring(bom, 'unicode')
+
+ def output_to_file(self, filename: str):
+ raise NotImplementedError
+
+ def _component_supports_bom_ref_attribute(self) -> bool:
+ return True
+
+ def _get_bom_root_element(self) -> ElementTree.Element:
+ return ElementTree.Element('bom', {'xmlns': self.get_target_namespace(), 'version': '1',
+ 'serialNumber': self.get_bom().get_urn_uuid()})
+
+ def _get_component_as_xml_element(self, component: Component) -> ElementTree.Element:
+ element_attributes = {'type': component.get_type().value}
+ if self.component_supports_bom_ref():
+ element_attributes['bom-ref'] = component.get_purl()
+
+ component_element = ElementTree.Element('component', element_attributes)
+
+ if self.component_supports_author() and component.get_author() is not None:
+ ElementTree.SubElement(component_element, 'author').text = component.get_author()
+
+ # if publisher and publisher != "UNKNOWN":
+ # ElementTree.SubElement(component, "publisher").text = re.sub(RE_XML_ILLEGAL, "?", publisher)
+
+ # if name and name != "UNKNOWN":
+ ElementTree.SubElement(component_element, 'name').text = component.get_name()
+
+ # if version and version != "UNKNOWN":
+ ElementTree.SubElement(component_element, 'version').text = component.get_version()
+
+ # if description and description != "UNKNOWN":
+ # ElementTree.SubElement(component, "description").text = re.sub(RE_XML_ILLEGAL, "?", description)
+ #
+ # if hashes:
+ # hashes_elm = ElementTree.SubElement(component, "hashes")
+ # for h in hashes:
+ # ElementTree.SubElement(hashes_elm, "hash", alg=h.alg).text = h.content
+ #
+ # if len(licenses):
+ # licenses_elm = ElementTree.SubElement(component, "licenses")
+ # for component_license in licenses:
+ # if component_license.license is not None:
+ # license_elm = ElementTree.SubElement(licenses_elm, "license")
+ # ElementTree.SubElement(license_elm, "name").text = re.sub(RE_XML_ILLEGAL, "?",
+ # component_license.license.name)
+
+ # if purl:
+ ElementTree.SubElement(component_element, 'purl').text = component.get_purl()
+
+ # ElementTree.SubElement(component, "modified").text = modified if modified else "false"
+
+ return component_element
+
+ def _add_metadata(self, bom: ElementTree.Element) -> ElementTree.Element:
+ metadata_e = ElementTree.SubElement(bom, 'metadata')
+ ElementTree.SubElement(metadata_e, 'timestamp').text = self.get_bom().get_metadata().get_timestamp().isoformat()
+ return bom
+
+
+class XmlV1Dot0(Xml, SchemaVersion1Dot0):
+
+ def _get_bom_root_element(self) -> ElementTree.Element:
+ return ElementTree.Element('bom', {'xmlns': self.get_target_namespace(), 'version': '1'})
+
+
+class XmlV1Dot1(Xml, SchemaVersion1Dot1):
+ pass
+
+
+class XmlV1Dot2(Xml, SchemaVersion1Dot2):
+ pass
+
+
+class XmlV1Dot3(Xml, SchemaVersion1Dot3):
+ pass
diff --git a/cyclonedx/parser/__init__.py b/cyclonedx/parser/__init__.py
new file mode 100644
index 00000000..27b65a09
--- /dev/null
+++ b/cyclonedx/parser/__init__.py
@@ -0,0 +1,30 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from abc import ABC
+from typing import List
+
+from ..model.component import Component
+
+
+class BaseParser(ABC):
+ _components: List[Component] = []
+
+ def component_count(self) -> int:
+ return len(self._components)
+
+ def get_components(self) -> List[Component]:
+ return self._components
diff --git a/cyclonedx/parser/environment.py b/cyclonedx/parser/environment.py
new file mode 100644
index 00000000..8cea45d7
--- /dev/null
+++ b/cyclonedx/parser/environment.py
@@ -0,0 +1,58 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import sys
+
+if sys.version_info >= (3, 8, 0):
+ from importlib.metadata import metadata
+else:
+ from importlib_metadata import metadata
+
+from . import BaseParser
+
+from ..model.component import Component
+
+
+class EnvironmentParser(BaseParser):
+ """
+ This will look at the current Python environment and list out all installed packages.
+
+ Best used when you have virtual Python environments per project.
+ """
+
+ def __init__(self):
+ import pkg_resources
+
+ i: pkg_resources.DistInfoDistribution
+ for i in iter(pkg_resources.working_set):
+ c = Component(name=i.project_name, version=i.version)
+
+ i_metadata = self._get_metadata_for_package(i.project_name)
+ print(i_metadata.keys())
+ if 'Author' in i_metadata.keys():
+ c.set_author(author=i_metadata.get('Author'))
+
+ if 'License' in i_metadata.keys():
+ c.set_license(license_str=i_metadata.get('License'))
+
+ self._components.append(c)
+
+ @staticmethod
+ def _get_metadata_for_package(package_name: str):
+ if sys.version_info >= (3, 8, 0):
+ return metadata(package_name)
+ else:
+ return metadata(package_name)
diff --git a/cyclonedx/parser/requirements.py b/cyclonedx/parser/requirements.py
new file mode 100644
index 00000000..8950942e
--- /dev/null
+++ b/cyclonedx/parser/requirements.py
@@ -0,0 +1,47 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import pkg_resources
+
+from . import BaseParser
+from ..model.component import Component
+
+
+class RequirementsParser(BaseParser):
+
+ def __init__(self, requirements_content: str):
+ requirements = pkg_resources.parse_requirements(requirements_content)
+ for requirement in requirements:
+ """
+ @todo
+ Note that the below line will get the first (lowest) version specified in the Requirement and
+ ignore the operator (it might not be ==). This is passed to the Component.
+
+ For example if a requirement was listed as: "PickyThing>1.6,<=1.9,!=1.8.6", we'll be interpretting this
+ as if it were written "PickyThing==1.6"
+ """
+ (op, version) = requirement.specs[0]
+ self._components.append(Component(
+ name=requirement.project_name, version=version
+ ))
+
+
+class RequirementsFileParser(RequirementsParser):
+
+ def __init__(self, requirements_file: str):
+ with open(requirements_file) as r:
+ super(RequirementsFileParser, self).__init__(requirements_content=r.read())
+ r.close()
diff --git a/cyclonedx/schema/bom-1.0.xsd b/cyclonedx/schema/bom-1.0.xsd
new file mode 100644
index 00000000..9cf88149
--- /dev/null
+++ b/cyclonedx/schema/bom-1.0.xsd
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+ The person(s) or organization(s) that published the component
+
+
+
+
+ The grouping name or identifier. This will often be a shortened, single
+ name of the company or project that produced the component, or the source package or
+ domain name. Whitespace and special characters should be avoided. Examples include:
+ apache, org.apache.commons, and apache.org.
+
+
+
+
+ The name of the component. This will often be a shortened, single name
+ of the component. Examples: commons-lang3 and jquery
+
+
+
+
+ The component version. The version should ideally comply with semantic versioning
+ but is not enforced.
+
+
+
+
+ Specifies a description for the component
+
+
+
+
+ Specifies the scope of the component. If scope is not specified, 'runtime'
+ scope will be assumed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A valid SPDX license ID
+
+
+
+
+ If SPDX does not define the license used, this field may be used to provide the license name
+
+
+
+
+
+
+
+
+
+
+
+ An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.
+
+
+
+
+ Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe
+
+
+
+
+
+ Specifies the package-url (PURL). The purl, if specified, must be valid and conform
+ to the specification defined at: https://github.com/package-url/purl-spec
+
+
+
+
+
+
+ A boolean value indicating is the component has been modified from the original.
+ A value of true indicates the component is a derivative of the original.
+ A value of false indicates the component has not been modified from the original.
+
+
+
+
+
+
+ Specifies optional sub-components. This is not a dependency tree. It simply provides
+ an optional way to group large sets of components together.
+
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the type of component. Software applications, libraries, frameworks, and
+ other dependencies should be classified as 'application'.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Specifies the file hash of the component
+
+
+
+
+
+ Specifies the algorithm used to create hash
+
+
+
+
+
+
+
+
+
+
+ The component is required for runtime
+
+
+
+
+ The component is optional at runtime. Optional components are components that
+ are not capable of being called due to them not be installed or otherwise accessible by any means.
+ Components that are installed but due to configuration or other restrictions are prohibited from
+ being called must be scoped as 'required'.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Define the format for acceptable CPE URIs. Supports CPE 2.2 and CPE 2.3 formats. Refer to https://nvd.nist.gov/products/cpe for official specification.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+ The version allows component publishers/authors to make changes to existing
+ BOMs to update various aspects of the document such as description or licenses. When a system
+ is presented with multiiple BOMs for the same component, the system should use the most recent
+ version of the BOM. The default version is '1' and should be incremented for each version of the
+ BOM that is published. Each version of a component should have a unique BOM and if no changes are
+ made to the BOMs, then each BOM will have a version of '1'.
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
\ No newline at end of file
diff --git a/cyclonedx/schema/bom-1.1.xsd b/cyclonedx/schema/bom-1.1.xsd
new file mode 100644
index 00000000..833e1691
--- /dev/null
+++ b/cyclonedx/schema/bom-1.1.xsd
@@ -0,0 +1,731 @@
+
+
+
+
+
+
+
+
+ CycloneDX Software Bill-of-Material Specification
+ https://cyclonedx.org/
+ Apache License, Version 2.0
+
+ Steve Springett
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The person(s) or organization(s) that published the component
+
+
+
+
+ The grouping name or identifier. This will often be a shortened, single
+ name of the company or project that produced the component, or the source package or
+ domain name. Whitespace and special characters should be avoided. Examples include:
+ apache, org.apache.commons, and apache.org.
+
+
+
+
+ The name of the component. This will often be a shortened, single name
+ of the component. Examples: commons-lang3 and jquery
+
+
+
+
+ The component version. The version should ideally comply with semantic versioning
+ but is not enforced.
+
+
+
+
+ Specifies a description for the component
+
+
+
+
+ Specifies the scope of the component. If scope is not specified, 'runtime'
+ scope should be assumed by the consumer of the BOM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A valid SPDX license expression.
+ Refer to https://spdx.org/specifications for syntax requirements
+
+
+
+
+
+
+
+ An optional copyright notice informing users of the underlying claims to
+ copyright ownership in a published work.
+
+
+
+
+
+ DEPRECATED - DO NOT USE. This will be removed in a future version.
+ Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe
+
+
+
+
+
+
+ Specifies the package-url (PURL). The purl, if specified, must be valid and conform
+ to the specification defined at: https://github.com/package-url/purl-spec
+
+
+
+
+
+
+ DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree
+ element instead to supply information on exactly how the component was modified.
+ A boolean value indicating is the component has been modified from the original.
+ A value of true indicates the component is a derivative of the original.
+ A value of false indicates the component has not been modified from the original.
+
+
+
+
+
+
+ Component pedigree is a way to document complex supply chain scenarios where components are
+ created, distributed, modified, redistributed, combined with other components, etc.
+
+
+
+
+
+ Provides the ability to document external references related to the
+ component or to the project the component describes.
+
+
+
+
+
+ Specifies optional sub-components. This is not a dependency tree. It provides a way
+ to specify a hierarchical representation of component assemblies, similar to
+ system -> subsystem -> parts assembly in physical supply chains.
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+ Specifies the type of component. For software components, classify as application if no more
+ specific appropriate classification is available or cannot be determined for the component.
+ Valid choices are: application, framework, library, operating-system, device, or file
+ Refer to the bom:classification documentation for information describing each one
+
+
+
+
+
+
+ An optional identifier which can be used to reference the component elsewhere in the BOM.
+ Uniqueness is enforced within all elements and children of the root-level bom element.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
+ A valid SPDX license ID
+
+
+
+
+ If SPDX does not define the license used, this field may be used to provide the license name
+
+
+
+
+
+ Specifies the optional full text of the license
+
+
+
+
+ The URL to the license file. If specified, a 'license'
+ externalReference should also be specified for completeness.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ Specifies attributes of the license text
+
+
+
+ Specifies the content type of the license text. Defaults to text/plain
+ if not specified.
+
+
+
+
+
+ Specifies the optional encoding the license text is represented in
+
+
+
+
+
+
+
+
+
+ Specifies the file hash of the component
+
+
+
+
+
+ Specifies the algorithm used to create the hash
+
+
+
+
+
+
+
+
+
+
+ The component is required for runtime
+
+
+
+
+ The component is optional at runtime. Optional components are components that
+ are not capable of being called due to them not be installed or otherwise accessible by any means.
+ Components that are installed but due to configuration or other restrictions are prohibited from
+ being called must be scoped as 'required'.
+
+
+
+
+ Components that are excluded provide the ability to document component usage
+ for test and other non-runtime purposes. Excluded components are not reachable within a call
+ graph at runtime.
+
+
+
+
+
+
+
+
+
+ A software application. Refer to https://en.wikipedia.org/wiki/Application_software
+ for information about applications.
+
+
+
+
+ A software framework. Refer to https://en.wikipedia.org/wiki/Software_framework
+ for information on how frameworks vary slightly from libraries.
+
+
+
+
+ A software library. Refer to https://en.wikipedia.org/wiki/Library_(computing)
+ for information about libraries. All third-party and open source reusable components will likely
+ be a library. If the library also has key features of a framework, then it should be classified
+ as a framework. If not, or is unknown, then specifying library is recommended.
+
+
+
+
+ A software operating system without regard to deployment model
+ (i.e. installed on physical hardware, virtual machine, container image, etc) Refer to
+ https://en.wikipedia.org/wiki/Operating_system
+
+
+
+
+ A hardware device such as a processor, or chip-set. A hardware device
+ containing firmware should include a component for the physical hardware itself, and another
+ component of type 'application' or 'operating-system' (whichever is relevant), describing
+ information about the firmware.
+
+
+
+
+ A computer file. Refer to https://en.wikipedia.org/wiki/Computer_file
+ for information about files.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Define the format for acceptable CPE URIs. Supports CPE 2.2 and CPE 2.3 formats.
+ Refer to https://nvd.nist.gov/products/cpe for official specification.
+
+
+
+
+
+
+
+
+
+
+ Defines a string representation of a UUID conforming to RFC 4122.
+
+
+
+
+
+
+
+
+
+
+
+ Version Control System
+
+
+
+
+ Issue or defect tracking system, or an Application Lifecycle Management (ALM) system
+
+
+
+
+ Website
+
+
+
+
+ Security advisories
+
+
+
+
+ Bill-of-material document (CycloneDX, SPDX, SWID, etc)
+
+
+
+
+ Mailing list or discussion group
+
+
+
+
+ Social media account
+
+
+
+
+ Real-time chat platform
+
+
+
+
+ Documentation, guides, or how-to instructions
+
+
+
+
+ Community or commercial support
+
+
+
+
+ Direct or repository download location
+
+
+
+
+ The URL to the license file. If a license URL has been defined in the license
+ node, it should also be defined as an external reference for completeness
+
+
+
+
+ Build-system specific meta file (i.e. pom.xml, package.json, .nuspec, etc)
+
+
+
+
+ URL to an automated build system
+
+
+
+
+ Use this if no other types accurately describe the purpose of the external reference
+
+
+
+
+
+
+
+
+ External references provide a way to document systems, sites, and information that may be relevant
+ but which are not included with the BOM.
+
+
+
+
+
+ Zero or more external references can be defined
+
+
+
+
+
+
+
+
+
+ The URL to the external reference
+
+
+
+
+ An optional comment describing the external reference
+
+
+
+
+
+ Specifies the type of external reference. There are built-in types to describe common
+ references. If a type does not exist for the reference being referred to, use the "other" type.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Zero or more commits can be specified.
+
+
+
+
+ Specifies an individual commit.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ A unique identifier of the commit. This may be version control
+ specific. For example, Subversion uses revision numbers whereas git uses commit hashes.
+
+
+
+
+
+ The URL to the commit. This URL will typically point to a commit
+ in a version control system.
+
+
+
+
+
+ The author who created the changes in the commit
+
+
+
+
+ The person who committed or pushed the commit
+
+
+
+
+ The text description of the contents of the commit
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ The timestamp in which the action occurred
+
+
+
+
+ The name of the individual who performed the action
+
+
+
+
+ The email address of the individual who performed the action
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+ Component pedigree is a way to document complex supply chain scenarios where components are created,
+ distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing
+ this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to
+ document variants where the exact relation may not be known.
+
+
+
+
+
+ Describes zero or more components in which a component is derived
+ from. This is commonly used to describe forks from existing projects where the forked version
+ contains a ancestor node containing the original component it was forked from. For example,
+ Component A is the original component. Component B is the component being used and documented
+ in the BOM. However, Component B contains a pedigree node with a single ancestor documenting
+ Component A - the original component from which Component B is derived from.
+
+
+
+
+
+ Descendants are the exact opposite of ancestors. This provides a
+ way to document all forks (and their forks) of an original or root component.
+
+
+
+
+
+ Variants describe relations where the relationship between the
+ components are not known. For example, if Component A contains nearly identical code to
+ Component B. They are both related, but it is unclear if one is derived from the other,
+ or if they share a common ancestor.
+
+
+
+
+
+ A list of zero or more commits which provide a trail describing
+ how the component deviates from an ancestor, descendant, or variant.
+
+
+
+
+ Notes, observations, and other non-structured commentary
+ describing the components pedigree.
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+
+
+ Provides the ability to document external references related to the BOM or
+ to the project the BOM describes.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ The version allows component publishers/authors to make changes to existing
+ BOMs to update various aspects of the document such as description or licenses. When a system
+ is presented with multiple BOMs for the same component, the system should use the most recent
+ version of the BOM. The default version is '1' and should be incremented for each version of the
+ BOM that is published. Each version of a component should have a unique BOM and if no changes are
+ made to the BOMs, then each BOM will have a version of '1'.
+
+
+
+
+ Every BOM generated should have a unique serial number, even if the contents
+ of the BOM being generated have not changed over time. The process or tool responsible for
+ creating the BOM should create random UUID's for every BOM generated.
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cyclonedx/schema/bom-1.2-strict.schema.json b/cyclonedx/schema/bom-1.2-strict.schema.json
new file mode 100644
index 00000000..30dad527
--- /dev/null
+++ b/cyclonedx/schema/bom-1.2-strict.schema.json
@@ -0,0 +1,1020 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "http://cyclonedx.org/schema/bom-1.2a.schema.json",
+ "type": "object",
+ "title": "CycloneDX Software Bill-of-Material Specification",
+ "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
+ "required": [
+ "bomFormat",
+ "specVersion",
+ "version"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "bomFormat": {
+ "$id": "#/properties/bomFormat",
+ "type": "string",
+ "title": "BOM Format",
+ "description": "Specifies the format of the BOM. This helps to identify the file as CycloneDX since BOMs do not have a filename convention nor does JSON schema support namespaces.",
+ "enum": [
+ "CycloneDX"
+ ]
+ },
+ "specVersion": {
+ "$id": "#/properties/specVersion",
+ "type": "string",
+ "title": "CycloneDX Specification Version",
+ "description": "The version of the CycloneDX specification a BOM is written to (starting at version 1.2)",
+ "examples": ["1.2"]
+ },
+ "serialNumber": {
+ "$id": "#/properties/serialNumber",
+ "type": "string",
+ "title": "BOM Serial Number",
+ "description": "Every BOM generated should have a unique serial number, even if the contents of the BOM being generated have not changed over time. The process or tool responsible for creating the BOM should create random UUID's for every BOM generated.",
+ "default": "",
+ "examples": ["urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"],
+ "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ },
+ "version": {
+ "$id": "#/properties/version",
+ "type": "integer",
+ "title": "BOM Version",
+ "description": "The version allows component publishers/authors to make changes to existing BOMs to update various aspects of the document such as description or licenses. When a system is presented with multiple BOMs for the same component, the system should use the most recent version of the BOM. The default version is '1' and should be incremented for each version of the BOM that is published. Each version of a component should have a unique BOM and if no changes are made to the BOMs, then each BOM will have a version of '1'.",
+ "default": 1,
+ "examples": [1]
+ },
+ "metadata": {
+ "$id": "#/properties/metadata",
+ "$ref": "#/definitions/metadata",
+ "title": "BOM Metadata",
+ "description": "Provides additional information about a BOM."
+ },
+ "components": {
+ "$id": "#/properties/components",
+ "type": "array",
+ "items": {"$ref": "#/definitions/component"},
+ "uniqueItems": true,
+ "title": "Components"
+ },
+ "services": {
+ "$id": "#/properties/services",
+ "type": "array",
+ "items": {"$ref": "#/definitions/service"},
+ "uniqueItems": true,
+ "title": "Services"
+ },
+ "externalReferences": {
+ "$id": "#/properties/externalReferences",
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References",
+ "description": "External references provide a way to document systems, sites, and information that may be relevant but which are not included with the BOM."
+ },
+ "dependencies": {
+ "$id": "#/properties/dependencies",
+ "type": "array",
+ "items": {"$ref": "#/definitions/dependency"},
+ "uniqueItems": true,
+ "title": "Dependencies",
+ "description": "Provides the ability to document dependency relationships."
+ }
+ },
+ "definitions": {
+ "metadata": {
+ "type": "object",
+ "title": "BOM Metadata Object",
+ "additionalProperties": false,
+ "properties": {
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Timestamp",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "tools": {
+ "type": "array",
+ "title": "Creation Tools",
+ "description": "The tool(s) used in the creation of the BOM.",
+ "items": {"$ref": "#/definitions/tool"}
+ },
+ "authors" :{
+ "type": "array",
+ "title": "Authors",
+ "description": "The person(s) who created the BOM. Authors are common in BOMs created through manual processes. BOMs created through automated means may not have authors.",
+ "items": {"$ref": "#/definitions/organizationalContact"}
+ },
+ "component": {
+ "title": "Component",
+ "description": "The component that the BOM describes.",
+ "$ref": "#/definitions/component"
+ },
+ "manufacture": {
+ "title": "Manufacture",
+ "description": "The organization that manufactured the component that the BOM describes.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "supplier": {
+ "title": "Supplier",
+ "description": " The organization that supplied the component that the BOM describes. The supplier may often be the manufacture, but may also be a distributor or repackager.",
+ "$ref": "#/definitions/organizationalEntity"
+ }
+ }
+ },
+ "tool": {
+ "type": "object",
+ "title": "Tool",
+ "description": "The tool used to create the BOM.",
+ "additionalProperties": false,
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "format": "string",
+ "title": "Tool Vendor",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "name": {
+ "type": "string",
+ "format": "string",
+ "title": "Tool Name",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "version": {
+ "type": "string",
+ "format": "string",
+ "title": "Tool Version",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "hashes": {
+ "$id": "#/properties/hashes",
+ "type": "array",
+ "items": {"$ref": "#/definitions/hash"},
+ "title": "Hashes",
+ "description": "The hashes of the tool (if applicable)."
+ }
+ }
+ },
+ "organizationalEntity": {
+ "type": "object",
+ "title": "Organizational Entity Object",
+ "description": "",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the organization",
+ "default": "",
+ "examples": [
+ "Example Inc."
+ ],
+ "pattern": "^(.*)$"
+ },
+ "url": {
+ "type": "array",
+ "title": "URL",
+ "description": "The URL of the organization. Multiple URLs are allowed.",
+ "default": "",
+ "examples": ["https://example.com"],
+ "pattern": "^(.*)$"
+ },
+ "contact": {
+ "type": "array",
+ "title": "Contact",
+ "description": "A contact at the organization. Multiple contacts are allowed.",
+ "items": {"$ref": "#/definitions/organizationalContact"}
+ }
+ }
+ },
+ "organizationalContact": {
+ "type": "object",
+ "title": "Organizational Contact Object",
+ "description": "",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of a contact",
+ "default": "",
+ "examples": ["Contact name"],
+ "pattern": "^(.*)$"
+ },
+ "email": {
+ "type": "string",
+ "title": "Email Address",
+ "description": "The email address of the contact. Multiple email addresses are allowed.",
+ "default": "",
+ "examples": ["firstname.lastname@example.com"],
+ "pattern": "^(.*)$"
+ },
+ "phone": {
+ "type": "string",
+ "title": "Phone",
+ "description": "The phone number of the contact. Multiple phone numbers are allowed.",
+ "default": "",
+ "examples": ["800-555-1212"],
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "component": {
+ "type": "object",
+ "title": "Component Object",
+ "required": [
+ "type",
+ "name",
+ "version"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "application",
+ "framework",
+ "library",
+ "container",
+ "operating-system",
+ "device",
+ "firmware",
+ "file"
+ ],
+ "title": "Component Type",
+ "description": "Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component.",
+ "default": "",
+ "examples": ["library"],
+ "pattern": "^(.*)$"
+ },
+ "mime-type": {
+ "type": "string",
+ "title": "Mime-Type",
+ "description": "The optional mime-type of the component. When used on file components, the mime-type can provide additional context about the kind of file being represented such as an image, font, or executable. Some library or framework components may also have an associated mime-type.",
+ "default": "",
+ "examples": ["image/jpeg"],
+ "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
+ },
+ "bom-ref": {
+ "type": "string",
+ "title": "BOM Reference",
+ "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique.",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "supplier": {
+ "title": "Component Supplier",
+ "description": " The organization that supplied the component. The supplier may often be the manufacture, but may also be a distributor or repackager.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "author": {
+ "type": "string",
+ "title": "Component Author",
+ "description": "The person(s) or organization(s) that authored the component",
+ "default": "",
+ "examples": ["Acme Inc"],
+ "pattern": "^(.*)$"
+ },
+ "publisher": {
+ "type": "string",
+ "title": "Component Publisher",
+ "description": "The person(s) or organization(s) that published the component",
+ "default": "",
+ "examples": ["Acme Inc"],
+ "pattern": "^(.*)$"
+ },
+ "group": {
+ "type": "string",
+ "title": "Component Group",
+ "description": "The grouping name or identifier. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. Whitespace and special characters should be avoided. Examples include: apache, org.apache.commons, and apache.org.",
+ "default": "",
+ "examples": ["com.acme"],
+ "pattern": "^(.*)$"
+ },
+ "name": {
+ "type": "string",
+ "title": "Component Name",
+ "description": "The name of the component. This will often be a shortened, single name of the component. Examples: commons-lang3 and jquery",
+ "default": "",
+ "examples": ["tomcat-catalina"],
+ "pattern": "^(.*)$"
+ },
+ "version": {
+ "type": "string",
+ "title": "Component Version",
+ "description": "The component version. The version should ideally comply with semantic versioning but is not enforced.",
+ "default": "",
+ "examples": ["9.0.14"],
+ "pattern": "^(.*)$"
+ },
+ "description": {
+ "type": "string",
+ "title": "Component Description",
+ "description": "Specifies a description for the component",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "scope": {
+ "type": "string",
+ "enum": [
+ "required",
+ "optional",
+ "excluded"
+ ],
+ "title": "Component Scope",
+ "description": "Specifies the scope of the component. If scope is not specified, 'required' scope should be assumed by the consumer of the BOM",
+ "default": "required",
+ "pattern": "^(.*)$"
+ },
+ "hashes": {
+ "type": "array",
+ "title": "Component Hashes",
+ "items": {"$ref": "#/definitions/hash"}
+ },
+ "licenses": {
+ "type": "array",
+ "title": "Component License(s)",
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "license": {
+ "$ref": "#/definitions/license"
+ },
+ "expression": {
+ "type": "string",
+ "title": "SPDX License Expression",
+ "examples": [
+ "Apache-2.0 AND (MIT OR GPL-2.0-only)",
+ "GPL-3.0-only WITH Classpath-exception-2.0"
+ ],
+ "pattern": "^(.*)$"
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["license"]
+ },
+ {
+ "required": ["expression"]
+ }
+ ]
+ }
+ },
+ "copyright": {
+ "type": "string",
+ "title": "Component Copyright",
+ "description": "An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.",
+ "examples": ["Acme Inc"],
+ "pattern": "^(.*)$"
+ },
+ "cpe": {
+ "type": "string",
+ "title": "Component Common Platform Enumeration (CPE)",
+ "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe",
+ "examples": ["cpe:2.3:a:acme:component_framework:-:*:*:*:*:*:*:*"],
+ "pattern": "^(.*)$"
+ },
+ "purl": {
+ "type": "string",
+ "title": "Component Package URL (purl)",
+ "default": "",
+ "examples": ["pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar"],
+ "pattern": "^(.*)$"
+ },
+ "swid": {
+ "$ref": "#/definitions/swid",
+ "title": "SWID Tag",
+ "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags."
+ },
+ "modified": {
+ "type": "boolean",
+ "title": "Component Modified From Original",
+ "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree element instead to supply information on exactly how the component was modified. A boolean value indicating is the component has been modified from the original. A value of true indicates the component is a derivative of the original. A value of false indicates the component has not been modified from the original."
+ },
+ "pedigree": {
+ "type": "object",
+ "title": "Component Pedigree",
+ "description": "Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to document variants where the exact relation may not be known.",
+ "additionalProperties": false,
+ "properties": {
+ "ancestors": {
+ "type": "array",
+ "title": "Ancestors",
+ "description": "Describes zero or more components in which a component is derived from. This is commonly used to describe forks from existing projects where the forked version contains a ancestor node containing the original component it was forked from. For example, Component A is the original component. Component B is the component being used and documented in the BOM. However, Component B contains a pedigree node with a single ancestor documenting Component A - the original component from which Component B is derived from.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "descendants": {
+ "type": "array",
+ "title": "Descendants",
+ "description": "Descendants are the exact opposite of ancestors. This provides a way to document all forks (and their forks) of an original or root component.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "variants": {
+ "type": "array",
+ "title": "Variants",
+ "description": "Variants describe relations where the relationship between the components are not known. For example, if Component A contains nearly identical code to Component B. They are both related, but it is unclear if one is derived from the other, or if they share a common ancestor.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "commits": {
+ "type": "array",
+ "title": "Commits",
+ "description": "A list of zero or more commits which provide a trail describing how the component deviates from an ancestor, descendant, or variant.",
+ "items": {"$ref": "#/definitions/commit"}
+ },
+ "patches": {
+ "type": "array",
+ "title": "Patches",
+ "description": ">A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits or may be used in place of commits.",
+ "items": {"$ref": "#/definitions/patch"}
+ },
+ "notes": {
+ "type": "string",
+ "title": "Notes",
+ "description": "Notes, observations, and other non-structured commentary describing the components pedigree.",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "externalReferences": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References"
+ },
+ "components": {
+ "$id": "#/properties/components",
+ "type": "array",
+ "items": {"$ref": "#/definitions/component"},
+ "uniqueItems": true,
+ "title": "Components"
+ }
+ }
+ },
+ "swid": {
+ "type": "object",
+ "title": "SWID Tag",
+ "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.",
+ "required": [
+ "tagId",
+ "name"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "tagId": {
+ "type": "string",
+ "title": "Tag ID",
+ "description": "Maps to the tagId of a SoftwareIdentity."
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "Maps to the name of a SoftwareIdentity."
+ },
+ "version": {
+ "type": "string",
+ "title": "Version",
+ "default": "0.0",
+ "description": "Maps to the version of a SoftwareIdentity."
+ },
+ "tagVersion": {
+ "type": "integer",
+ "title": "Tag Version",
+ "default": 0,
+ "description": "Maps to the tagVersion of a SoftwareIdentity."
+ },
+ "patch": {
+ "type": "boolean",
+ "title": "Patch",
+ "default": false,
+ "description": "Maps to the patch of a SoftwareIdentity."
+ },
+ "text": {
+ "title": "Attachment text",
+ "description": "Specifies the metadata and content of the SWID tag.",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "default": "The URL to the SWID file.",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "attachment": {
+ "type": "object",
+ "title": "Attachment",
+ "description": "Specifies the metadata and content for an attachment.",
+ "required": [
+ "content"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "contentType": {
+ "type": "string",
+ "title": "Content-Type",
+ "description": "Specifies the content type of the text. Defaults to text/plain if not specified.",
+ "default": "text/plain"
+ },
+ "encoding": {
+ "type": "string",
+ "title": "Encoding",
+ "description": "Specifies the optional encoding the text is represented in.",
+ "enum": [
+ "base64"
+ ],
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "content": {
+ "type": "string",
+ "title": "Attachment Text",
+ "description": "The attachment data"
+ }
+ }
+ },
+ "hash": {
+ "type": "object",
+ "title": "Hash Objects",
+ "required": [
+ "alg",
+ "content"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "alg": {
+ "$ref": "#/definitions/hash-alg"
+ },
+ "content": {
+ "$ref": "#/definitions/hash-content"
+ }
+ }
+ },
+ "hash-alg": {
+ "type": "string",
+ "enum": [
+ "MD5",
+ "SHA-1",
+ "SHA-256",
+ "SHA-384",
+ "SHA-512",
+ "SHA3-256",
+ "SHA3-384",
+ "SHA3-512",
+ "BLAKE2b-256",
+ "BLAKE2b-384",
+ "BLAKE2b-512",
+ "BLAKE3"
+ ],
+ "title": "Hash Algorithm",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "hash-content": {
+ "type": "string",
+ "title": "Hash Content (value)",
+ "default": "",
+ "examples": ["3942447fac867ae5cdb3229b658f4d48"],
+ "pattern": "^([a-fA-F0-9]{32}|[a-fA-F0-9]{40}|[a-fA-F0-9]{64}|[a-fA-F0-9]{96}|[a-fA-F0-9]{128})$"
+ },
+ "license": {
+ "type": "object",
+ "title": "License Object",
+ "oneOf": [
+ {
+ "required": ["id"]
+ },
+ {
+ "required": ["name"]
+ }
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "$ref": "spdx.schema.json",
+ "title": "License ID (SPDX)",
+ "description": "A valid SPDX license ID",
+ "examples": ["Apache-2.0"]
+ },
+ "name": {
+ "type": "string",
+ "title": "License Name",
+ "description": "If SPDX does not define the license used, this field may be used to provide the license name",
+ "default": "",
+ "examples": ["Acme Software License"],
+ "pattern": "^(.*)$"
+ },
+ "text": {
+ "title": "License text",
+ "description": "An optional way to include the textual content of a license.",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "License URL",
+ "description": "The URL to the license file. If specified, a 'license' externalReference should also be specified for completeness",
+ "examples": ["https://www.apache.org/licenses/LICENSE-2.0.txt"],
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "title": "Commit",
+ "description": "Specifies an individual commit",
+ "additionalProperties": false,
+ "properties": {
+ "uid": {
+ "type": "string",
+ "title": "UID",
+ "description": "A unique identifier of the commit. This may be version control specific. For example, Subversion uses revision numbers whereas git uses commit hashes.",
+ "pattern": "^(.*)$"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the commit. This URL will typically point to a commit in a version control system.",
+ "format": "iri-reference"
+ },
+ "author": {
+ "title": "Author",
+ "description": "The author who created the changes in the commit",
+ "$ref": "#/definitions/identifiableAction"
+ },
+ "committer": {
+ "title": "Committer",
+ "description": "The person who committed or pushed the commit",
+ "$ref": "#/definitions/identifiableAction"
+ },
+ "message": {
+ "type": "string",
+ "title": "Message",
+ "description": "The text description of the contents of the commit",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "patch": {
+ "type": "object",
+ "title": "Patch",
+ "description": "Specifies an individual patch",
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "unofficial",
+ "monkey",
+ "backport",
+ "cherry-pick"
+ ],
+ "title": "Type",
+ "description": "Specifies the purpose for the patch including the resolution of defects, security issues, or new behavior or functionality"
+ },
+ "diff": {
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "$ref": "#/definitions/diff"
+ },
+ "resolves": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/issue"},
+ "title": "Resolves",
+ "description": "A collection of issues the patch resolves"
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "additionalProperties": false,
+ "properties": {
+ "text": {
+ "title": "Diff text",
+ "description": "Specifies the optional text of the diff",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "Specifies the URL to the diff",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "issue": {
+ "type": "object",
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "defect",
+ "enhancement",
+ "security"
+ ],
+ "title": "Type",
+ "description": "Specifies the type of issue"
+ },
+ "id": {
+ "type": "string",
+ "title": "ID",
+ "description": "The identifier of the issue assigned by the source of the issue",
+ "pattern": "^(.*)$"
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the issue",
+ "pattern": "^(.*)$"
+ },
+ "description": {
+ "type": "string",
+ "title": "Description",
+ "description": "A description of the issue",
+ "pattern": "^(.*)$"
+ },
+ "source": {
+ "type": "object",
+ "title": "Source",
+ "description": "The source of the issue where it is documented",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the source. For example 'National Vulnerability Database', 'NVD', and 'Apache'",
+ "pattern": "^(.*)$"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The url of the issue documentation as provided by the source",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "references": {
+ "type": "array",
+ "title": "References",
+ "description": "A collection of URL's for reference. Multiple URLs are allowed.",
+ "default": "",
+ "examples": ["https://example.com"],
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "identifiableAction": {
+ "type": "object",
+ "title": "Identifiable Action",
+ "description": "Specifies an individual commit",
+ "additionalProperties": false,
+ "properties": {
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Timestamp",
+ "description": "The timestamp in which the action occurred"
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the individual who performed the action",
+ "pattern": "^(.*)$"
+ },
+ "email": {
+ "type": "string",
+ "format": "idn-email",
+ "title": "E-mail",
+ "description": "The email address of the individual who performed the action"
+ }
+ }
+ },
+ "externalReference": {
+ "type": "object",
+ "title": "External Reference",
+ "description": "Specifies an individual external reference",
+ "required": [
+ "url",
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the external reference",
+ "pattern": "^(.*)$"
+ },
+ "comment": {
+ "type": "string",
+ "title": "Comment",
+ "description": "An optional comment describing the external reference",
+ "pattern": "^(.*)$"
+ },
+ "type": {
+ "type": "string",
+ "title": "Type",
+ "description": "Specifies the type of external reference. There are built-in types to describe common references. If a type does not exist for the reference being referred to, use the \"other\" type.",
+ "enum": [
+ "vcs",
+ "issue-tracker",
+ "website",
+ "advisories",
+ "bom",
+ "mailing-list",
+ "social",
+ "chat",
+ "documentation",
+ "support",
+ "distribution",
+ "license",
+ "build-meta",
+ "build-system",
+ "other"
+ ]
+ }
+ }
+ },
+ "dependency": {
+ "type": "object",
+ "title": "Dependency",
+ "description": "Defines the direct dependencies of a component. Components that do not have their own dependencies MUST be declared as empty elements within the graph. Components that are not represented in the dependency graph MAY have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque and not an indicator of a component being dependency-free.",
+ "required": [
+ "ref"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "ref": {
+ "type": "string",
+ "format": "string",
+ "title": "Reference",
+ "description": "References a component by the components bom-ref attribute"
+ },
+ "dependsOn": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ },
+ "title": "Depends On",
+ "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
+ }
+ }
+ },
+ "service": {
+ "type": "object",
+ "title": "Service Object",
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "bom-ref": {
+ "type": "string",
+ "title": "BOM Reference",
+ "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique.",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "provider": {
+ "title": "Provider",
+ "description": "The organization that provides the service.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "group": {
+ "type": "string",
+ "title": "Service Group",
+ "description": "The grouping name, namespace, or identifier. This will often be a shortened, single name of the company or project that produced the service or domain name. Whitespace and special characters should be avoided.",
+ "default": "",
+ "examples": ["com.acme"],
+ "pattern": "^(.*)$"
+ },
+ "name": {
+ "type": "string",
+ "title": "Service Name",
+ "description": "The name of the service. This will often be a shortened, single name of the service.",
+ "default": "",
+ "examples": ["ticker-service"],
+ "pattern": "^(.*)$"
+ },
+ "version": {
+ "type": "string",
+ "title": "Service Version",
+ "description": "The service version.",
+ "default": "",
+ "examples": ["1.0.0"],
+ "pattern": "^(.*)$"
+ },
+ "description": {
+ "type": "string",
+ "title": "Service Description",
+ "description": "Specifies a description for the service",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "endpoints": {
+ "type": "array",
+ "title": "Endpoints",
+ "description": "The endpoint URIs of the service. Multiple endpoints are allowed.",
+ "default": "",
+ "examples": ["https://example.com/api/v1/ticker"],
+ "pattern": "^(.*)$"
+ },
+ "authenticated": {
+ "type": "boolean",
+ "title": "Authentication Required",
+ "description": "A boolean value indicating if the service requires authentication. A value of true indicates the service requires authentication prior to use. A value of false indicates the service does not require authentication."
+ },
+ "x-trust-boundary": {
+ "type": "boolean",
+ "title": "Crosses Trust Boundary",
+ "description": "A boolean value indicating if use of the service crosses a trust zone or boundary. A value of true indicates that by using the service, a trust boundary is crossed. A value of false indicates that by using the service, a trust boundary is not crossed."
+ },
+ "data": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/dataClassification"},
+ "title": "Data Classification",
+ "description": "Specifies the data classification."
+ },
+ "licenses": {
+ "type": "array",
+ "title": "Component License(s)",
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "license": {
+ "$ref": "#/definitions/license"
+ },
+ "expression": {
+ "type": "string",
+ "title": "SPDX License Expression",
+ "examples": [
+ "Apache-2.0 AND (MIT OR GPL-2.0-only)",
+ "GPL-3.0-only WITH Classpath-exception-2.0"
+ ],
+ "pattern": "^(.*)$"
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["license"]
+ },
+ {
+ "required": ["expression"]
+ }
+ ]
+ }
+ },
+ "externalReferences": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References"
+ },
+ "services": {
+ "$id": "#/properties/services",
+ "type": "array",
+ "items": {"$ref": "#/definitions/service"},
+ "uniqueItems": true,
+ "title": "Services"
+ }
+ }
+ },
+ "dataClassification": {
+ "type": "object",
+ "title": "Hash Objects",
+ "required": [
+ "flow",
+ "classification"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "flow": {
+ "$ref": "#/definitions/dataFlow"
+ },
+ "classification": {
+ "type": "string"
+ }
+ }
+ },
+ "dataFlow": {
+ "type": "string",
+ "enum": [
+ "inbound",
+ "outbound",
+ "bi-directional",
+ "unknown"
+ ],
+ "title": "Data flow direction",
+ "default": "",
+ "pattern": "^(.*)$"
+ }
+ }
+}
diff --git a/cyclonedx/schema/bom-1.2.schema.json b/cyclonedx/schema/bom-1.2.schema.json
new file mode 100644
index 00000000..2e44d942
--- /dev/null
+++ b/cyclonedx/schema/bom-1.2.schema.json
@@ -0,0 +1,997 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "http://cyclonedx.org/schema/bom-1.2a.schema.json",
+ "type": "object",
+ "title": "CycloneDX Software Bill-of-Material Specification",
+ "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
+ "required": [
+ "bomFormat",
+ "specVersion",
+ "version"
+ ],
+ "properties": {
+ "bomFormat": {
+ "$id": "#/properties/bomFormat",
+ "type": "string",
+ "title": "BOM Format",
+ "description": "Specifies the format of the BOM. This helps to identify the file as CycloneDX since BOMs do not have a filename convention nor does JSON schema support namespaces.",
+ "enum": [
+ "CycloneDX"
+ ]
+ },
+ "specVersion": {
+ "$id": "#/properties/specVersion",
+ "type": "string",
+ "title": "CycloneDX Specification Version",
+ "description": "The version of the CycloneDX specification a BOM is written to (starting at version 1.2)",
+ "examples": ["1.2"]
+ },
+ "serialNumber": {
+ "$id": "#/properties/serialNumber",
+ "type": "string",
+ "title": "BOM Serial Number",
+ "description": "Every BOM generated should have a unique serial number, even if the contents of the BOM being generated have not changed over time. The process or tool responsible for creating the BOM should create random UUID's for every BOM generated.",
+ "default": "",
+ "examples": ["urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"],
+ "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ },
+ "version": {
+ "$id": "#/properties/version",
+ "type": "integer",
+ "title": "BOM Version",
+ "description": "The version allows component publishers/authors to make changes to existing BOMs to update various aspects of the document such as description or licenses. When a system is presented with multiple BOMs for the same component, the system should use the most recent version of the BOM. The default version is '1' and should be incremented for each version of the BOM that is published. Each version of a component should have a unique BOM and if no changes are made to the BOMs, then each BOM will have a version of '1'.",
+ "default": 1,
+ "examples": [1]
+ },
+ "metadata": {
+ "$id": "#/properties/metadata",
+ "$ref": "#/definitions/metadata",
+ "title": "BOM Metadata",
+ "description": "Provides additional information about a BOM."
+ },
+ "components": {
+ "$id": "#/properties/components",
+ "type": "array",
+ "items": {"$ref": "#/definitions/component"},
+ "uniqueItems": true,
+ "title": "Components"
+ },
+ "services": {
+ "$id": "#/properties/services",
+ "type": "array",
+ "items": {"$ref": "#/definitions/service"},
+ "uniqueItems": true,
+ "title": "Services"
+ },
+ "externalReferences": {
+ "$id": "#/properties/externalReferences",
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References",
+ "description": "External references provide a way to document systems, sites, and information that may be relevant but which are not included with the BOM."
+ },
+ "dependencies": {
+ "$id": "#/properties/dependencies",
+ "type": "array",
+ "items": {"$ref": "#/definitions/dependency"},
+ "uniqueItems": true,
+ "title": "Dependencies",
+ "description": "Provides the ability to document dependency relationships."
+ }
+ },
+ "definitions": {
+ "metadata": {
+ "type": "object",
+ "title": "BOM Metadata Object",
+ "properties": {
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Timestamp",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "tools": {
+ "type": "array",
+ "title": "Creation Tools",
+ "description": "The tool(s) used in the creation of the BOM.",
+ "items": {"$ref": "#/definitions/tool"}
+ },
+ "authors" :{
+ "type": "array",
+ "title": "Authors",
+ "description": "The person(s) who created the BOM. Authors are common in BOMs created through manual processes. BOMs created through automated means may not have authors.",
+ "items": {"$ref": "#/definitions/organizationalContact"}
+ },
+ "component": {
+ "title": "Component",
+ "description": "The component that the BOM describes.",
+ "$ref": "#/definitions/component"
+ },
+ "manufacture": {
+ "title": "Manufacture",
+ "description": "The organization that manufactured the component that the BOM describes.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "supplier": {
+ "title": "Supplier",
+ "description": " The organization that supplied the component that the BOM describes. The supplier may often be the manufacture, but may also be a distributor or repackager.",
+ "$ref": "#/definitions/organizationalEntity"
+ }
+ }
+ },
+ "tool": {
+ "type": "object",
+ "title": "Tool",
+ "description": "The tool used to create the BOM.",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "format": "string",
+ "title": "Tool Vendor",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "name": {
+ "type": "string",
+ "format": "string",
+ "title": "Tool Name",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "version": {
+ "type": "string",
+ "format": "string",
+ "title": "Tool Version",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "hashes": {
+ "$id": "#/properties/hashes",
+ "type": "array",
+ "items": {"$ref": "#/definitions/hash"},
+ "title": "Hashes",
+ "description": "The hashes of the tool (if applicable)."
+ }
+ }
+ },
+ "organizationalEntity": {
+ "type": "object",
+ "title": "Organizational Entity Object",
+ "description": "",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the organization",
+ "default": "",
+ "examples": [
+ "Example Inc."
+ ],
+ "pattern": "^(.*)$"
+ },
+ "url": {
+ "type": "array",
+ "title": "URL",
+ "description": "The URL of the organization. Multiple URLs are allowed.",
+ "default": "",
+ "examples": ["https://example.com"],
+ "pattern": "^(.*)$"
+ },
+ "contact": {
+ "type": "array",
+ "title": "Contact",
+ "description": "A contact at the organization. Multiple contacts are allowed.",
+ "items": {"$ref": "#/definitions/organizationalContact"}
+ }
+ }
+ },
+ "organizationalContact": {
+ "type": "object",
+ "title": "Organizational Contact Object",
+ "description": "",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of a contact",
+ "default": "",
+ "examples": ["Contact name"],
+ "pattern": "^(.*)$"
+ },
+ "email": {
+ "type": "string",
+ "title": "Email Address",
+ "description": "The email address of the contact. Multiple email addresses are allowed.",
+ "default": "",
+ "examples": ["firstname.lastname@example.com"],
+ "pattern": "^(.*)$"
+ },
+ "phone": {
+ "type": "string",
+ "title": "Phone",
+ "description": "The phone number of the contact. Multiple phone numbers are allowed.",
+ "default": "",
+ "examples": ["800-555-1212"],
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "component": {
+ "type": "object",
+ "title": "Component Object",
+ "required": [
+ "type",
+ "name",
+ "version"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "application",
+ "framework",
+ "library",
+ "container",
+ "operating-system",
+ "device",
+ "firmware",
+ "file"
+ ],
+ "title": "Component Type",
+ "description": "Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component.",
+ "default": "",
+ "examples": ["library"],
+ "pattern": "^(.*)$"
+ },
+ "mime-type": {
+ "type": "string",
+ "title": "Mime-Type",
+ "description": "The optional mime-type of the component. When used on file components, the mime-type can provide additional context about the kind of file being represented such as an image, font, or executable. Some library or framework components may also have an associated mime-type.",
+ "default": "",
+ "examples": ["image/jpeg"],
+ "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
+ },
+ "bom-ref": {
+ "type": "string",
+ "title": "BOM Reference",
+ "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique.",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "supplier": {
+ "title": "Component Supplier",
+ "description": " The organization that supplied the component. The supplier may often be the manufacture, but may also be a distributor or repackager.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "author": {
+ "type": "string",
+ "title": "Component Author",
+ "description": "The person(s) or organization(s) that authored the component",
+ "default": "",
+ "examples": ["Acme Inc"],
+ "pattern": "^(.*)$"
+ },
+ "publisher": {
+ "type": "string",
+ "title": "Component Publisher",
+ "description": "The person(s) or organization(s) that published the component",
+ "default": "",
+ "examples": ["Acme Inc"],
+ "pattern": "^(.*)$"
+ },
+ "group": {
+ "type": "string",
+ "title": "Component Group",
+ "description": "The grouping name or identifier. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. Whitespace and special characters should be avoided. Examples include: apache, org.apache.commons, and apache.org.",
+ "default": "",
+ "examples": ["com.acme"],
+ "pattern": "^(.*)$"
+ },
+ "name": {
+ "type": "string",
+ "title": "Component Name",
+ "description": "The name of the component. This will often be a shortened, single name of the component. Examples: commons-lang3 and jquery",
+ "default": "",
+ "examples": ["tomcat-catalina"],
+ "pattern": "^(.*)$"
+ },
+ "version": {
+ "type": "string",
+ "title": "Component Version",
+ "description": "The component version. The version should ideally comply with semantic versioning but is not enforced.",
+ "default": "",
+ "examples": ["9.0.14"],
+ "pattern": "^(.*)$"
+ },
+ "description": {
+ "type": "string",
+ "title": "Component Description",
+ "description": "Specifies a description for the component",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "scope": {
+ "type": "string",
+ "enum": [
+ "required",
+ "optional",
+ "excluded"
+ ],
+ "title": "Component Scope",
+ "description": "Specifies the scope of the component. If scope is not specified, 'required' scope should be assumed by the consumer of the BOM",
+ "default": "required",
+ "pattern": "^(.*)$"
+ },
+ "hashes": {
+ "type": "array",
+ "title": "Component Hashes",
+ "items": {"$ref": "#/definitions/hash"}
+ },
+ "licenses": {
+ "type": "array",
+ "title": "Component License(s)",
+ "items": {
+ "properties": {
+ "license": {
+ "$ref": "#/definitions/license"
+ },
+ "expression": {
+ "type": "string",
+ "title": "SPDX License Expression",
+ "examples": [
+ "Apache-2.0 AND (MIT OR GPL-2.0-only)",
+ "GPL-3.0-only WITH Classpath-exception-2.0"
+ ],
+ "pattern": "^(.*)$"
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["license"]
+ },
+ {
+ "required": ["expression"]
+ }
+ ]
+ }
+ },
+ "copyright": {
+ "type": "string",
+ "title": "Component Copyright",
+ "description": "An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.",
+ "examples": ["Acme Inc"],
+ "pattern": "^(.*)$"
+ },
+ "cpe": {
+ "type": "string",
+ "title": "Component Common Platform Enumeration (CPE)",
+ "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe",
+ "examples": ["cpe:2.3:a:acme:component_framework:-:*:*:*:*:*:*:*"],
+ "pattern": "^(.*)$"
+ },
+ "purl": {
+ "type": "string",
+ "title": "Component Package URL (purl)",
+ "default": "",
+ "examples": ["pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar"],
+ "pattern": "^(.*)$"
+ },
+ "swid": {
+ "$ref": "#/definitions/swid",
+ "title": "SWID Tag",
+ "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags."
+ },
+ "modified": {
+ "type": "boolean",
+ "title": "Component Modified From Original",
+ "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree element instead to supply information on exactly how the component was modified. A boolean value indicating is the component has been modified from the original. A value of true indicates the component is a derivative of the original. A value of false indicates the component has not been modified from the original."
+ },
+ "pedigree": {
+ "type": "object",
+ "title": "Component Pedigree",
+ "description": "Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to document variants where the exact relation may not be known.",
+ "properties": {
+ "ancestors": {
+ "type": "array",
+ "title": "Ancestors",
+ "description": "Describes zero or more components in which a component is derived from. This is commonly used to describe forks from existing projects where the forked version contains a ancestor node containing the original component it was forked from. For example, Component A is the original component. Component B is the component being used and documented in the BOM. However, Component B contains a pedigree node with a single ancestor documenting Component A - the original component from which Component B is derived from.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "descendants": {
+ "type": "array",
+ "title": "Descendants",
+ "description": "Descendants are the exact opposite of ancestors. This provides a way to document all forks (and their forks) of an original or root component.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "variants": {
+ "type": "array",
+ "title": "Variants",
+ "description": "Variants describe relations where the relationship between the components are not known. For example, if Component A contains nearly identical code to Component B. They are both related, but it is unclear if one is derived from the other, or if they share a common ancestor.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "commits": {
+ "type": "array",
+ "title": "Commits",
+ "description": "A list of zero or more commits which provide a trail describing how the component deviates from an ancestor, descendant, or variant.",
+ "items": {"$ref": "#/definitions/commit"}
+ },
+ "patches": {
+ "type": "array",
+ "title": "Patches",
+ "description": ">A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits or may be used in place of commits.",
+ "items": {"$ref": "#/definitions/patch"}
+ },
+ "notes": {
+ "type": "string",
+ "title": "Notes",
+ "description": "Notes, observations, and other non-structured commentary describing the components pedigree.",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "externalReferences": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References"
+ },
+ "components": {
+ "$id": "#/properties/components",
+ "type": "array",
+ "items": {"$ref": "#/definitions/component"},
+ "uniqueItems": true,
+ "title": "Components"
+ }
+ }
+ },
+ "swid": {
+ "type": "object",
+ "title": "SWID Tag",
+ "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.",
+ "required": [
+ "tagId",
+ "name"
+ ],
+ "properties": {
+ "tagId": {
+ "type": "string",
+ "title": "Tag ID",
+ "description": "Maps to the tagId of a SoftwareIdentity."
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "Maps to the name of a SoftwareIdentity."
+ },
+ "version": {
+ "type": "string",
+ "title": "Version",
+ "default": "0.0",
+ "description": "Maps to the version of a SoftwareIdentity."
+ },
+ "tagVersion": {
+ "type": "integer",
+ "title": "Tag Version",
+ "default": 0,
+ "description": "Maps to the tagVersion of a SoftwareIdentity."
+ },
+ "patch": {
+ "type": "boolean",
+ "title": "Patch",
+ "default": false,
+ "description": "Maps to the patch of a SoftwareIdentity."
+ },
+ "text": {
+ "title": "Attachment text",
+ "description": "Specifies the metadata and content of the SWID tag.",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "default": "The URL to the SWID file.",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "attachment": {
+ "type": "object",
+ "title": "Attachment",
+ "description": "Specifies the metadata and content for an attachment.",
+ "required": [
+ "content"
+ ],
+ "properties": {
+ "contentType": {
+ "type": "string",
+ "title": "Content-Type",
+ "description": "Specifies the content type of the text. Defaults to text/plain if not specified.",
+ "default": "text/plain"
+ },
+ "encoding": {
+ "type": "string",
+ "title": "Encoding",
+ "description": "Specifies the optional encoding the text is represented in.",
+ "enum": [
+ "base64"
+ ],
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "content": {
+ "type": "string",
+ "title": "Attachment Text",
+ "description": "The attachment data"
+ }
+ }
+ },
+ "hash": {
+ "type": "object",
+ "title": "Hash Objects",
+ "required": [
+ "alg",
+ "content"
+ ],
+ "properties": {
+ "alg": {
+ "$ref": "#/definitions/hash-alg"
+ },
+ "content": {
+ "$ref": "#/definitions/hash-content"
+ }
+ }
+ },
+ "hash-alg": {
+ "type": "string",
+ "enum": [
+ "MD5",
+ "SHA-1",
+ "SHA-256",
+ "SHA-384",
+ "SHA-512",
+ "SHA3-256",
+ "SHA3-384",
+ "SHA3-512",
+ "BLAKE2b-256",
+ "BLAKE2b-384",
+ "BLAKE2b-512",
+ "BLAKE3"
+ ],
+ "title": "Hash Algorithm",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "hash-content": {
+ "type": "string",
+ "title": "Hash Content (value)",
+ "default": "",
+ "examples": ["3942447fac867ae5cdb3229b658f4d48"],
+ "pattern": "^([a-fA-F0-9]{32}|[a-fA-F0-9]{40}|[a-fA-F0-9]{64}|[a-fA-F0-9]{96}|[a-fA-F0-9]{128})$"
+ },
+ "license": {
+ "type": "object",
+ "title": "License Object",
+ "oneOf": [
+ {
+ "required": ["id"]
+ },
+ {
+ "required": ["name"]
+ }
+ ],
+ "properties": {
+ "id": {
+ "$ref": "spdx.schema.json",
+ "title": "License ID (SPDX)",
+ "description": "A valid SPDX license ID",
+ "examples": ["Apache-2.0"]
+ },
+ "name": {
+ "type": "string",
+ "title": "License Name",
+ "description": "If SPDX does not define the license used, this field may be used to provide the license name",
+ "default": "",
+ "examples": ["Acme Software License"],
+ "pattern": "^(.*)$"
+ },
+ "text": {
+ "title": "License text",
+ "description": "An optional way to include the textual content of a license.",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "License URL",
+ "description": "The URL to the license file. If specified, a 'license' externalReference should also be specified for completeness",
+ "examples": ["https://www.apache.org/licenses/LICENSE-2.0.txt"],
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "title": "Commit",
+ "description": "Specifies an individual commit",
+ "properties": {
+ "uid": {
+ "type": "string",
+ "title": "UID",
+ "description": "A unique identifier of the commit. This may be version control specific. For example, Subversion uses revision numbers whereas git uses commit hashes.",
+ "pattern": "^(.*)$"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the commit. This URL will typically point to a commit in a version control system.",
+ "format": "iri-reference"
+ },
+ "author": {
+ "title": "Author",
+ "description": "The author who created the changes in the commit",
+ "$ref": "#/definitions/identifiableAction"
+ },
+ "committer": {
+ "title": "Committer",
+ "description": "The person who committed or pushed the commit",
+ "$ref": "#/definitions/identifiableAction"
+ },
+ "message": {
+ "type": "string",
+ "title": "Message",
+ "description": "The text description of the contents of the commit",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "patch": {
+ "type": "object",
+ "title": "Patch",
+ "description": "Specifies an individual patch",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "unofficial",
+ "monkey",
+ "backport",
+ "cherry-pick"
+ ],
+ "title": "Type",
+ "description": "Specifies the purpose for the patch including the resolution of defects, security issues, or new behavior or functionality"
+ },
+ "diff": {
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "$ref": "#/definitions/diff"
+ },
+ "resolves": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/issue"},
+ "title": "Resolves",
+ "description": "A collection of issues the patch resolves"
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "properties": {
+ "text": {
+ "title": "Diff text",
+ "description": "Specifies the optional text of the diff",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "Specifies the URL to the diff",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "issue": {
+ "type": "object",
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "defect",
+ "enhancement",
+ "security"
+ ],
+ "title": "Type",
+ "description": "Specifies the type of issue"
+ },
+ "id": {
+ "type": "string",
+ "title": "ID",
+ "description": "The identifier of the issue assigned by the source of the issue",
+ "pattern": "^(.*)$"
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the issue",
+ "pattern": "^(.*)$"
+ },
+ "description": {
+ "type": "string",
+ "title": "Description",
+ "description": "A description of the issue",
+ "pattern": "^(.*)$"
+ },
+ "source": {
+ "type": "object",
+ "title": "Source",
+ "description": "The source of the issue where it is documented",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the source. For example 'National Vulnerability Database', 'NVD', and 'Apache'",
+ "pattern": "^(.*)$"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The url of the issue documentation as provided by the source",
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "references": {
+ "type": "array",
+ "title": "References",
+ "description": "A collection of URL's for reference. Multiple URLs are allowed.",
+ "default": "",
+ "examples": ["https://example.com"],
+ "pattern": "^(.*)$"
+ }
+ }
+ },
+ "identifiableAction": {
+ "type": "object",
+ "title": "Identifiable Action",
+ "description": "Specifies an individual commit",
+ "properties": {
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Timestamp",
+ "description": "The timestamp in which the action occurred"
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the individual who performed the action",
+ "pattern": "^(.*)$"
+ },
+ "email": {
+ "type": "string",
+ "format": "idn-email",
+ "title": "E-mail",
+ "description": "The email address of the individual who performed the action"
+ }
+ }
+ },
+ "externalReference": {
+ "type": "object",
+ "title": "External Reference",
+ "description": "Specifies an individual external reference",
+ "required": [
+ "url",
+ "type"
+ ],
+ "properties": {
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the external reference",
+ "pattern": "^(.*)$"
+ },
+ "comment": {
+ "type": "string",
+ "title": "Comment",
+ "description": "An optional comment describing the external reference",
+ "pattern": "^(.*)$"
+ },
+ "type": {
+ "type": "string",
+ "title": "Type",
+ "description": "Specifies the type of external reference. There are built-in types to describe common references. If a type does not exist for the reference being referred to, use the \"other\" type.",
+ "enum": [
+ "vcs",
+ "issue-tracker",
+ "website",
+ "advisories",
+ "bom",
+ "mailing-list",
+ "social",
+ "chat",
+ "documentation",
+ "support",
+ "distribution",
+ "license",
+ "build-meta",
+ "build-system",
+ "other"
+ ]
+ }
+ }
+ },
+ "dependency": {
+ "type": "object",
+ "title": "Dependency",
+ "description": "Defines the direct dependencies of a component. Components that do not have their own dependencies MUST be declared as empty elements within the graph. Components that are not represented in the dependency graph MAY have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque and not an indicator of a component being dependency-free.",
+ "required": [
+ "ref"
+ ],
+ "properties": {
+ "ref": {
+ "type": "string",
+ "format": "string",
+ "title": "Reference",
+ "description": "References a component by the components bom-ref attribute"
+ },
+ "dependsOn": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ },
+ "title": "Depends On",
+ "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
+ }
+ }
+ },
+ "service": {
+ "type": "object",
+ "title": "Service Object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "bom-ref": {
+ "type": "string",
+ "title": "BOM Reference",
+ "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique.",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "provider": {
+ "title": "Provider",
+ "description": "The organization that provides the service.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "group": {
+ "type": "string",
+ "title": "Service Group",
+ "description": "The grouping name, namespace, or identifier. This will often be a shortened, single name of the company or project that produced the service or domain name. Whitespace and special characters should be avoided.",
+ "default": "",
+ "examples": ["com.acme"],
+ "pattern": "^(.*)$"
+ },
+ "name": {
+ "type": "string",
+ "title": "Service Name",
+ "description": "The name of the service. This will often be a shortened, single name of the service.",
+ "default": "",
+ "examples": ["ticker-service"],
+ "pattern": "^(.*)$"
+ },
+ "version": {
+ "type": "string",
+ "title": "Service Version",
+ "description": "The service version.",
+ "default": "",
+ "examples": ["1.0.0"],
+ "pattern": "^(.*)$"
+ },
+ "description": {
+ "type": "string",
+ "title": "Service Description",
+ "description": "Specifies a description for the service",
+ "default": "",
+ "pattern": "^(.*)$"
+ },
+ "endpoints": {
+ "type": "array",
+ "title": "Endpoints",
+ "description": "The endpoint URIs of the service. Multiple endpoints are allowed.",
+ "default": "",
+ "examples": ["https://example.com/api/v1/ticker"],
+ "pattern": "^(.*)$"
+ },
+ "authenticated": {
+ "type": "boolean",
+ "title": "Authentication Required",
+ "description": "A boolean value indicating if the service requires authentication. A value of true indicates the service requires authentication prior to use. A value of false indicates the service does not require authentication."
+ },
+ "x-trust-boundary": {
+ "type": "boolean",
+ "title": "Crosses Trust Boundary",
+ "description": "A boolean value indicating if use of the service crosses a trust zone or boundary. A value of true indicates that by using the service, a trust boundary is crossed. A value of false indicates that by using the service, a trust boundary is not crossed."
+ },
+ "data": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/dataClassification"},
+ "title": "Data Classification",
+ "description": "Specifies the data classification."
+ },
+ "licenses": {
+ "type": "array",
+ "title": "Component License(s)",
+ "items": {
+ "properties": {
+ "license": {
+ "$ref": "#/definitions/license"
+ },
+ "expression": {
+ "type": "string",
+ "title": "SPDX License Expression",
+ "examples": [
+ "Apache-2.0 AND (MIT OR GPL-2.0-only)",
+ "GPL-3.0-only WITH Classpath-exception-2.0"
+ ],
+ "pattern": "^(.*)$"
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["license"]
+ },
+ {
+ "required": ["expression"]
+ }
+ ]
+ }
+ },
+ "externalReferences": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References"
+ },
+ "services": {
+ "$id": "#/properties/services",
+ "type": "array",
+ "items": {"$ref": "#/definitions/service"},
+ "uniqueItems": true,
+ "title": "Services"
+ }
+ }
+ },
+ "dataClassification": {
+ "type": "object",
+ "title": "Hash Objects",
+ "required": [
+ "flow",
+ "classification"
+ ],
+ "properties": {
+ "flow": {
+ "$ref": "#/definitions/dataFlow"
+ },
+ "classification": {
+ "type": "string"
+ }
+ }
+ },
+ "dataFlow": {
+ "type": "string",
+ "enum": [
+ "inbound",
+ "outbound",
+ "bi-directional",
+ "unknown"
+ ],
+ "title": "Data flow direction",
+ "default": "",
+ "pattern": "^(.*)$"
+ }
+ }
+}
diff --git a/cyclonedx/schema/bom-1.2.xsd b/cyclonedx/schema/bom-1.2.xsd
new file mode 100644
index 00000000..d30ff62e
--- /dev/null
+++ b/cyclonedx/schema/bom-1.2.xsd
@@ -0,0 +1,1418 @@
+
+
+
+
+
+
+
+
+ CycloneDX Software Bill-of-Material Specification
+ https://cyclonedx.org/
+ Apache License, Version 2.0
+
+ Steve Springett
+
+
+
+
+
+
+
+
+ The date and time (timestamp) when the document was created.
+
+
+
+
+ The tool(s) used in the creation of the BOM.
+
+
+
+
+
+
+
+
+
+ The person(s) who created the BOM. Authors are common in BOMs created through
+ manual processes. BOMs created through automated means may not have authors.
+
+
+
+
+
+
+
+
+
+ The component that the BOM describes.
+
+
+
+
+ The organization that manufactured the component that the BOM describes.
+
+
+
+
+ The organization that supplied the component that the BOM describes. The
+ supplier may often be the manufacture, but may also be a distributor or repackager.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The name of the organization
+
+
+
+
+ The URL of the organization. Multiple URLs are allowed.
+
+
+
+
+ A contact person at the organization. Multiple contacts are allowed.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Specifies a tool (manual or automated).
+
+
+
+
+ The vendor of the tool used to create the BOM.
+
+
+
+
+ The name of the tool used to create the BOM.
+
+
+
+
+ The version of the tool used to create the BOM.
+
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The name of the contact
+
+
+
+
+ The email address of the contact. Multiple email addresses are allowed.
+
+
+
+
+ The phone number of the contact. Multiple phone numbers are allowed.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The organization that supplied the component. The supplier may often
+ be the manufacture, but may also be a distributor or repackager.
+
+
+
+
+ The person(s) or organization(s) that authored the component
+
+
+
+
+ The person(s) or organization(s) that published the component
+
+
+
+
+ The grouping name or identifier. This will often be a shortened, single
+ name of the company or project that produced the component, or the source package or
+ domain name. Whitespace and special characters should be avoided. Examples include:
+ apache, org.apache.commons, and apache.org.
+
+
+
+
+ The name of the component. This will often be a shortened, single name
+ of the component. Examples: commons-lang3 and jquery
+
+
+
+
+ The component version. The version should ideally comply with semantic versioning
+ but is not enforced.
+
+
+
+
+ Specifies a description for the component
+
+
+
+
+ Specifies the scope of the component. If scope is not specified, 'runtime'
+ scope should be assumed by the consumer of the BOM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A valid SPDX license expression.
+ Refer to https://spdx.org/specifications for syntax requirements
+
+
+
+
+
+
+
+ An optional copyright notice informing users of the underlying claims to
+ copyright ownership in a published work.
+
+
+
+
+
+ DEPRECATED - DO NOT USE. This will be removed in a future version.
+ Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe
+
+
+
+
+
+
+ Specifies the package-url (PURL). The purl, if specified, must be valid and conform
+ to the specification defined at: https://github.com/package-url/purl-spec
+
+
+
+
+
+
+ Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.
+
+
+
+
+
+
+ DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree
+ element instead to supply information on exactly how the component was modified.
+ A boolean value indicating is the component has been modified from the original.
+ A value of true indicates the component is a derivative of the original.
+ A value of false indicates the component has not been modified from the original.
+
+
+
+
+
+
+ Component pedigree is a way to document complex supply chain scenarios where components are
+ created, distributed, modified, redistributed, combined with other components, etc.
+
+
+
+
+
+ Provides the ability to document external references related to the
+ component or to the project the component describes.
+
+
+
+
+
+ Specifies optional sub-components. This is not a dependency tree. It provides a way
+ to specify a hierarchical representation of component assemblies, similar to
+ system -> subsystem -> parts assembly in physical supply chains.
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+ Specifies the type of component. For software components, classify as application if no more
+ specific appropriate classification is available or cannot be determined for the component.
+
+
+
+
+
+
+ The optional mime-type of the component. When used on file components, the mime-type
+ can provide additional context about the kind of file being represented such as an image,
+ font, or executable. Some library or framework components may also have an associated mime-type.
+
+
+
+
+
+
+ An optional identifier which can be used to reference the component elsewhere in the BOM.
+ Uniqueness is enforced within all elements and children of the root-level bom element.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
+ A valid SPDX license ID
+
+
+
+
+ If SPDX does not define the license used, this field may be used to provide the license name
+
+
+
+
+
+ Specifies the optional full text of the attachment
+
+
+
+
+ The URL to the attachment file. If the attachment is a license or BOM,
+ an externalReference should also be specified for completeness.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ Specifies attributes of the text
+
+
+
+ Specifies the content type of the text. Defaults to text/plain
+ if not specified.
+
+
+
+
+
+ Specifies the optional encoding the text is represented in
+
+
+
+
+
+
+
+
+
+ Specifies the file hash of the component
+
+
+
+
+
+ Specifies the algorithm used to create the hash
+
+
+
+
+
+
+
+
+
+
+ The component is required for runtime
+
+
+
+
+ The component is optional at runtime. Optional components are components that
+ are not capable of being called due to them not be installed or otherwise accessible by any means.
+ Components that are installed but due to configuration or other restrictions are prohibited from
+ being called must be scoped as 'required'.
+
+
+
+
+ Components that are excluded provide the ability to document component usage
+ for test and other non-runtime purposes. Excluded components are not reachable within a call
+ graph at runtime.
+
+
+
+
+
+
+
+
+
+ A software application. Refer to https://en.wikipedia.org/wiki/Application_software
+ for information about applications.
+
+
+
+
+ A software framework. Refer to https://en.wikipedia.org/wiki/Software_framework
+ for information on how frameworks vary slightly from libraries.
+
+
+
+
+ A software library. Refer to https://en.wikipedia.org/wiki/Library_(computing)
+ for information about libraries. All third-party and open source reusable components will likely
+ be a library. If the library also has key features of a framework, then it should be classified
+ as a framework. If not, or is unknown, then specifying library is recommended.
+
+
+
+
+ A packaging and/or runtime format, not specific to any particular technology,
+ which isolates software inside the container from software outside of a container through
+ virtualization technology. Refer to https://en.wikipedia.org/wiki/OS-level_virtualization
+
+
+
+
+ A software operating system without regard to deployment model
+ (i.e. installed on physical hardware, virtual machine, image, etc) Refer to
+ https://en.wikipedia.org/wiki/Operating_system
+
+
+
+
+ A hardware device such as a processor, or chip-set. A hardware device
+ containing firmware should include a component for the physical hardware itself, and another
+ component of type 'firmware' or 'operating-system' (whichever is relevant), describing
+ information about the software running on the device.
+
+
+
+
+ A special type of software that provides low-level control over a devices
+ hardware. Refer to https://en.wikipedia.org/wiki/Firmware
+
+
+
+
+ A computer file. Refer to https://en.wikipedia.org/wiki/Computer_file
+ for information about files.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Define the format for acceptable CPE URIs. Supports CPE 2.2 and CPE 2.3 formats.
+ Refer to https://nvd.nist.gov/products/cpe for official specification.
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the full content of the SWID tag.
+
+
+
+
+ The URL to the SWID file.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ Maps to the tagId of a SoftwareIdentity.
+
+
+
+
+ Maps to the name of a SoftwareIdentity.
+
+
+
+
+ Maps to the version of a SoftwareIdentity.
+
+
+
+
+ Maps to the tagVersion of a SoftwareIdentity.
+
+
+
+
+ Maps to the patch of a SoftwareIdentity.
+
+
+
+
+
+
+
+ Defines a string representation of a UUID conforming to RFC 4122.
+
+
+
+
+
+
+
+
+
+
+
+ Version Control System
+
+
+
+
+ Issue or defect tracking system, or an Application Lifecycle Management (ALM) system
+
+
+
+
+ Website
+
+
+
+
+ Security advisories
+
+
+
+
+ Bill-of-material document (CycloneDX, SPDX, SWID, etc)
+
+
+
+
+ Mailing list or discussion group
+
+
+
+
+ Social media account
+
+
+
+
+ Real-time chat platform
+
+
+
+
+ Documentation, guides, or how-to instructions
+
+
+
+
+ Community or commercial support
+
+
+
+
+ Direct or repository download location
+
+
+
+
+ The URL to the license file. If a license URL has been defined in the license
+ node, it should also be defined as an external reference for completeness
+
+
+
+
+ Build-system specific meta file (i.e. pom.xml, package.json, .nuspec, etc)
+
+
+
+
+ URL to an automated build system
+
+
+
+
+ Use this if no other types accurately describe the purpose of the external reference
+
+
+
+
+
+
+
+
+ External references provide a way to document systems, sites, and information that may be relevant
+ but which are not included with the BOM.
+
+
+
+
+
+ Zero or more external references can be defined
+
+
+
+
+
+
+
+
+
+ The URL to the external reference
+
+
+
+
+ An optional comment describing the external reference
+
+
+
+
+
+ Specifies the type of external reference. There are built-in types to describe common
+ references. If a type does not exist for the reference being referred to, use the "other" type.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Zero or more commits can be specified.
+
+
+
+
+ Specifies an individual commit.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ A unique identifier of the commit. This may be version control
+ specific. For example, Subversion uses revision numbers whereas git uses commit hashes.
+
+
+
+
+
+ The URL to the commit. This URL will typically point to a commit
+ in a version control system.
+
+
+
+
+
+ The author who created the changes in the commit
+
+
+
+
+ The person who committed or pushed the commit
+
+
+
+
+ The text description of the contents of the commit
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+ Zero or more patches can be specified.
+
+
+
+
+ Specifies an individual patch.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ The patch file (or diff) that show changes.
+ Refer to https://en.wikipedia.org/wiki/Diff
+
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ Specifies the purpose for the patch including the resolution of defects,
+ security issues, or new behavior or functionality
+
+
+
+
+
+
+
+
+ A patch which is not developed by the creators or maintainers of the software
+ being patched. Refer to https://en.wikipedia.org/wiki/Unofficial_patch
+
+
+
+
+ A patch which dynamically modifies runtime behavior.
+ Refer to https://en.wikipedia.org/wiki/Monkey_patch
+
+
+
+
+ A patch which takes code from a newer version of software and applies
+ it to older versions of the same software. Refer to https://en.wikipedia.org/wiki/Backporting
+
+
+
+
+ A patch created by selectively applying commits from other versions or
+ branches of the same software.
+
+
+
+
+
+
+
+
+
+ A fault, flaw, or bug in software
+
+
+
+
+ A new feature or behavior in software
+
+
+
+
+ A special type of defect which impacts security
+
+
+
+
+
+
+
+
+
+ Specifies the optional text of the diff
+
+
+
+
+ Specifies the URL to the diff
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ The identifier of the issue assigned by the source of the issue
+
+
+
+
+ The name of the issue
+
+
+
+
+ A description of the issue
+
+
+
+
+
+
+ The source of the issue where it is documented.
+
+
+
+
+
+
+ The name of the source. For example "National Vulnerability Database",
+ "NVD", and "Apache"
+
+
+
+
+
+
+ The url of the issue documentation as provided by the source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ Specifies the type of issue
+
+
+
+
+
+
+
+
+ The timestamp in which the action occurred
+
+
+
+
+ The name of the individual who performed the action
+
+
+
+
+ The email address of the individual who performed the action
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+ Component pedigree is a way to document complex supply chain scenarios where components are created,
+ distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing
+ this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to
+ document variants where the exact relation may not be known.
+
+
+
+
+
+ Describes zero or more components in which a component is derived
+ from. This is commonly used to describe forks from existing projects where the forked version
+ contains a ancestor node containing the original component it was forked from. For example,
+ Component A is the original component. Component B is the component being used and documented
+ in the BOM. However, Component B contains a pedigree node with a single ancestor documenting
+ Component A - the original component from which Component B is derived from.
+
+
+
+
+
+ Descendants are the exact opposite of ancestors. This provides a
+ way to document all forks (and their forks) of an original or root component.
+
+
+
+
+
+ Variants describe relations where the relationship between the
+ components are not known. For example, if Component A contains nearly identical code to
+ Component B. They are both related, but it is unclear if one is derived from the other,
+ or if they share a common ancestor.
+
+
+
+
+
+ A list of zero or more commits which provide a trail describing
+ how the component deviates from an ancestor, descendant, or variant.
+
+
+
+
+ A list of zero or more patches describing how the component
+ deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits
+ or may be used in place of commits.
+
+
+
+
+ Notes, observations, and other non-structured commentary
+ describing the components pedigree.
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+
+
+ References a component or service by the its bom-ref attribute
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ Components that do not have their own dependencies MUST be declared as empty
+ elements within the graph. Components that are not represented in the dependency graph MAY
+ have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque
+ and not an indicator of a component being dependency-free.
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The organization that provides the service.
+
+
+
+
+ The grouping name, namespace, or identifier. This will often be a shortened,
+ single name of the company or project that produced the service or domain name.
+ Whitespace and special characters should be avoided.
+
+
+
+
+ The name of the service. This will often be a shortened, single name
+ of the service.
+
+
+
+
+ The service version.
+
+
+
+
+ Specifies a description for the service.
+
+
+
+
+
+
+
+ A service endpoint URI.
+
+
+
+
+
+
+
+ A boolean value indicating if the service requires authentication.
+ A value of true indicates the service requires authentication prior to use.
+ A value of false indicates the service does not require authentication.
+
+
+
+
+ A boolean value indicating if use of the service crosses a trust zone or boundary.
+ A value of true indicates that by using the service, a trust boundary is crossed.
+ A value of false indicates that by using the service, a trust boundary is not crossed.
+
+
+
+
+
+
+
+ Specifies the data classification.
+
+
+
+
+
+
+
+
+
+
+
+ A valid SPDX license expression.
+ Refer to https://spdx.org/specifications for syntax requirements
+
+
+
+
+
+
+
+ Provides the ability to document external references related to the service.
+
+
+
+
+
+ Specifies optional sub-service. This is not a dependency tree. It provides a way
+ to specify a hierarchical representation of service assemblies, similar to
+ system -> subsystem -> parts assembly in physical supply chains.
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+ An optional identifier which can be used to reference the service elsewhere in the BOM.
+ Uniqueness is enforced within all elements and children of the root-level bom element.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Specifies the data classification.
+
+
+
+
+
+ Specifies the flow direction of the data.
+
+
+
+
+
+
+
+
+ Specifies the flow direction of the data. Valid values are:
+ inbound, outbound, bi-directional, and unknown. Direction is relative to the service.
+ Inbound flow states that data enters the service. Outbound flow states that data
+ leaves the service. Bi-directional states that data flows both ways, and unknown
+ states that the direction is not known.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Provides additional information about a BOM.
+
+
+
+
+ Provides the ability to document a list of components.
+
+
+
+
+ Provides the ability to document a list of external services.
+
+
+
+
+ Provides the ability to document external references related to the BOM or
+ to the project the BOM describes.
+
+
+
+
+ Provides the ability to document dependency relationships.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ The version allows component publishers/authors to make changes to existing
+ BOMs to update various aspects of the document such as description or licenses. When a system
+ is presented with multiple BOMs for the same component, the system should use the most recent
+ version of the BOM. The default version is '1' and should be incremented for each version of the
+ BOM that is published. Each version of a component should have a unique BOM and if no changes are
+ made to the BOMs, then each BOM will have a version of '1'.
+
+
+
+
+ Every BOM generated should have a unique serial number, even if the contents
+ of the BOM being generated have not changed over time. The process or tool responsible for
+ creating the BOM should create random UUID's for every BOM generated.
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
diff --git a/cyclonedx/schema/bom-1.3-strict.schema.json b/cyclonedx/schema/bom-1.3-strict.schema.json
new file mode 100644
index 00000000..cecf325e
--- /dev/null
+++ b/cyclonedx/schema/bom-1.3-strict.schema.json
@@ -0,0 +1,1079 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "http://cyclonedx.org/schema/bom-1.3.schema.json",
+ "type": "object",
+ "title": "CycloneDX Software Bill-of-Material Specification",
+ "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
+ "required": [
+ "bomFormat",
+ "specVersion",
+ "version"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "bomFormat": {
+ "$id": "#/properties/bomFormat",
+ "type": "string",
+ "title": "BOM Format",
+ "description": "Specifies the format of the BOM. This helps to identify the file as CycloneDX since BOMs do not have a filename convention nor does JSON schema support namespaces.",
+ "enum": [
+ "CycloneDX"
+ ]
+ },
+ "specVersion": {
+ "$id": "#/properties/specVersion",
+ "type": "string",
+ "title": "CycloneDX Specification Version",
+ "description": "The version of the CycloneDX specification a BOM is written to (starting at version 1.2)",
+ "examples": ["1.3"]
+ },
+ "serialNumber": {
+ "$id": "#/properties/serialNumber",
+ "type": "string",
+ "title": "BOM Serial Number",
+ "description": "Every BOM generated should have a unique serial number, even if the contents of the BOM being generated have not changed over time. The process or tool responsible for creating the BOM should create random UUID's for every BOM generated.",
+ "examples": ["urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"],
+ "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ },
+ "version": {
+ "$id": "#/properties/version",
+ "type": "integer",
+ "title": "BOM Version",
+ "description": "The version allows component publishers/authors to make changes to existing BOMs to update various aspects of the document such as description or licenses. When a system is presented with multiple BOMs for the same component, the system should use the most recent version of the BOM. The default version is '1' and should be incremented for each version of the BOM that is published. Each version of a component should have a unique BOM and if no changes are made to the BOMs, then each BOM will have a version of '1'.",
+ "default": 1,
+ "examples": [1]
+ },
+ "metadata": {
+ "$id": "#/properties/metadata",
+ "$ref": "#/definitions/metadata",
+ "title": "BOM Metadata",
+ "description": "Provides additional information about a BOM."
+ },
+ "components": {
+ "$id": "#/properties/components",
+ "type": "array",
+ "items": {"$ref": "#/definitions/component"},
+ "uniqueItems": true,
+ "title": "Components"
+ },
+ "services": {
+ "$id": "#/properties/services",
+ "type": "array",
+ "items": {"$ref": "#/definitions/service"},
+ "uniqueItems": true,
+ "title": "Services"
+ },
+ "externalReferences": {
+ "$id": "#/properties/externalReferences",
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References",
+ "description": "External references provide a way to document systems, sites, and information that may be relevant but which are not included with the BOM."
+ },
+ "dependencies": {
+ "$id": "#/properties/dependencies",
+ "type": "array",
+ "items": {"$ref": "#/definitions/dependency"},
+ "uniqueItems": true,
+ "title": "Dependencies",
+ "description": "Provides the ability to document dependency relationships."
+ },
+ "compositions": {
+ "$id": "#/properties/compositions",
+ "type": "array",
+ "items": {"$ref": "#/definitions/compositions"},
+ "uniqueItems": true,
+ "title": "Compositions",
+ "description": "Compositions describe constituent parts (including components, services, and dependency relationships) and their completeness."
+ }
+ },
+ "definitions": {
+ "metadata": {
+ "type": "object",
+ "title": "BOM Metadata Object",
+ "additionalProperties": false,
+ "properties": {
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Timestamp",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "tools": {
+ "type": "array",
+ "title": "Creation Tools",
+ "description": "The tool(s) used in the creation of the BOM.",
+ "items": {"$ref": "#/definitions/tool"}
+ },
+ "authors" :{
+ "type": "array",
+ "title": "Authors",
+ "description": "The person(s) who created the BOM. Authors are common in BOMs created through manual processes. BOMs created through automated means may not have authors.",
+ "items": {"$ref": "#/definitions/organizationalContact"}
+ },
+ "component": {
+ "title": "Component",
+ "description": "The component that the BOM describes.",
+ "$ref": "#/definitions/component"
+ },
+ "manufacture": {
+ "title": "Manufacture",
+ "description": "The organization that manufactured the component that the BOM describes.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "supplier": {
+ "title": "Supplier",
+ "description": " The organization that supplied the component that the BOM describes. The supplier may often be the manufacturer, but may also be a distributor or repackager.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "licenses": {
+ "type": "array",
+ "title": "BOM License(s)",
+ "items": {"$ref": "#/definitions/licenseChoice"}
+ },
+ "properties": {
+ "type": "array",
+ "title": "Properties",
+ "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
+ "items": {"$ref": "#/definitions/property"}
+ }
+ }
+ },
+ "tool": {
+ "type": "object",
+ "title": "Tool",
+ "description": "The tool used to create the BOM.",
+ "additionalProperties": false,
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "title": "Tool Vendor",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "name": {
+ "type": "string",
+ "title": "Tool Name",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "version": {
+ "type": "string",
+ "title": "Tool Version",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "hashes": {
+ "$id": "#/properties/hashes",
+ "type": "array",
+ "items": {"$ref": "#/definitions/hash"},
+ "title": "Hashes",
+ "description": "The hashes of the tool (if applicable)."
+ }
+ }
+ },
+ "organizationalEntity": {
+ "type": "object",
+ "title": "Organizational Entity Object",
+ "description": "",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the organization",
+ "examples": [
+ "Example Inc."
+ ]
+ },
+ "url": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "iri-reference"
+ },
+ "title": "URL",
+ "description": "The URL of the organization. Multiple URLs are allowed.",
+ "examples": ["https://example.com"]
+ },
+ "contact": {
+ "type": "array",
+ "title": "Contact",
+ "description": "A contact at the organization. Multiple contacts are allowed.",
+ "items": {"$ref": "#/definitions/organizationalContact"}
+ }
+ }
+ },
+ "organizationalContact": {
+ "type": "object",
+ "title": "Organizational Contact Object",
+ "description": "",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of a contact",
+ "examples": ["Contact name"]
+ },
+ "email": {
+ "type": "string",
+ "title": "Email Address",
+ "description": "The email address of the contact.",
+ "examples": ["firstname.lastname@example.com"]
+ },
+ "phone": {
+ "type": "string",
+ "title": "Phone",
+ "description": "The phone number of the contact.",
+ "examples": ["800-555-1212"]
+ }
+ }
+ },
+ "component": {
+ "type": "object",
+ "title": "Component Object",
+ "required": [
+ "type",
+ "name",
+ "version"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "application",
+ "framework",
+ "library",
+ "container",
+ "operating-system",
+ "device",
+ "firmware",
+ "file"
+ ],
+ "title": "Component Type",
+ "description": "Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component.",
+ "examples": ["library"]
+ },
+ "mime-type": {
+ "type": "string",
+ "title": "Mime-Type",
+ "description": "The optional mime-type of the component. When used on file components, the mime-type can provide additional context about the kind of file being represented such as an image, font, or executable. Some library or framework components may also have an associated mime-type.",
+ "examples": ["image/jpeg"],
+ "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
+ },
+ "bom-ref": {
+ "type": "string",
+ "title": "BOM Reference",
+ "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique."
+ },
+ "supplier": {
+ "title": "Component Supplier",
+ "description": " The organization that supplied the component. The supplier may often be the manufacturer, but may also be a distributor or repackager.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "author": {
+ "type": "string",
+ "title": "Component Author",
+ "description": "The person(s) or organization(s) that authored the component",
+ "examples": ["Acme Inc"]
+ },
+ "publisher": {
+ "type": "string",
+ "title": "Component Publisher",
+ "description": "The person(s) or organization(s) that published the component",
+ "examples": ["Acme Inc"]
+ },
+ "group": {
+ "type": "string",
+ "title": "Component Group",
+ "description": "The grouping name or identifier. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. Whitespace and special characters should be avoided. Examples include: apache, org.apache.commons, and apache.org.",
+ "examples": ["com.acme"]
+ },
+ "name": {
+ "type": "string",
+ "title": "Component Name",
+ "description": "The name of the component. This will often be a shortened, single name of the component. Examples: commons-lang3 and jquery",
+ "examples": ["tomcat-catalina"]
+ },
+ "version": {
+ "type": "string",
+ "title": "Component Version",
+ "description": "The component version. The version should ideally comply with semantic versioning but is not enforced.",
+ "examples": ["9.0.14"]
+ },
+ "description": {
+ "type": "string",
+ "title": "Component Description",
+ "description": "Specifies a description for the component"
+ },
+ "scope": {
+ "type": "string",
+ "enum": [
+ "required",
+ "optional",
+ "excluded"
+ ],
+ "title": "Component Scope",
+ "description": "Specifies the scope of the component. If scope is not specified, 'required' scope should be assumed by the consumer of the BOM",
+ "default": "required"
+ },
+ "hashes": {
+ "type": "array",
+ "title": "Component Hashes",
+ "items": {"$ref": "#/definitions/hash"}
+ },
+ "licenses": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/licenseChoice"},
+ "title": "Component License(s)"
+ },
+ "copyright": {
+ "type": "string",
+ "title": "Component Copyright",
+ "description": "An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.",
+ "examples": ["Acme Inc"]
+ },
+ "cpe": {
+ "type": "string",
+ "title": "Component Common Platform Enumeration (CPE)",
+ "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe",
+ "examples": ["cpe:2.3:a:acme:component_framework:-:*:*:*:*:*:*:*"]
+ },
+ "purl": {
+ "type": "string",
+ "title": "Component Package URL (purl)",
+ "examples": ["pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar"]
+ },
+ "swid": {
+ "$ref": "#/definitions/swid",
+ "title": "SWID Tag",
+ "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags."
+ },
+ "modified": {
+ "type": "boolean",
+ "title": "Component Modified From Original",
+ "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree element instead to supply information on exactly how the component was modified. A boolean value indicating is the component has been modified from the original. A value of true indicates the component is a derivative of the original. A value of false indicates the component has not been modified from the original."
+ },
+ "pedigree": {
+ "type": "object",
+ "title": "Component Pedigree",
+ "description": "Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to document variants where the exact relation may not be known.",
+ "additionalProperties": false,
+ "properties": {
+ "ancestors": {
+ "type": "array",
+ "title": "Ancestors",
+ "description": "Describes zero or more components in which a component is derived from. This is commonly used to describe forks from existing projects where the forked version contains a ancestor node containing the original component it was forked from. For example, Component A is the original component. Component B is the component being used and documented in the BOM. However, Component B contains a pedigree node with a single ancestor documenting Component A - the original component from which Component B is derived from.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "descendants": {
+ "type": "array",
+ "title": "Descendants",
+ "description": "Descendants are the exact opposite of ancestors. This provides a way to document all forks (and their forks) of an original or root component.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "variants": {
+ "type": "array",
+ "title": "Variants",
+ "description": "Variants describe relations where the relationship between the components are not known. For example, if Component A contains nearly identical code to Component B. They are both related, but it is unclear if one is derived from the other, or if they share a common ancestor.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "commits": {
+ "type": "array",
+ "title": "Commits",
+ "description": "A list of zero or more commits which provide a trail describing how the component deviates from an ancestor, descendant, or variant.",
+ "items": {"$ref": "#/definitions/commit"}
+ },
+ "patches": {
+ "type": "array",
+ "title": "Patches",
+ "description": ">A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits or may be used in place of commits.",
+ "items": {"$ref": "#/definitions/patch"}
+ },
+ "notes": {
+ "type": "string",
+ "title": "Notes",
+ "description": "Notes, observations, and other non-structured commentary describing the components pedigree."
+ }
+ }
+ },
+ "externalReferences": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References"
+ },
+ "components": {
+ "$id": "#/properties/components",
+ "type": "array",
+ "items": {"$ref": "#/definitions/component"},
+ "uniqueItems": true,
+ "title": "Components"
+ },
+ "evidence": {
+ "$ref": "#/definitions/componentEvidence",
+ "title": "Evidence",
+ "description": "Provides the ability to document evidence collected through various forms of extraction or analysis."
+ },
+ "properties": {
+ "type": "array",
+ "title": "Properties",
+ "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
+ "items": {"$ref": "#/definitions/property"}
+ }
+ }
+ },
+ "swid": {
+ "type": "object",
+ "title": "SWID Tag",
+ "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.",
+ "required": [
+ "tagId",
+ "name"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "tagId": {
+ "type": "string",
+ "title": "Tag ID",
+ "description": "Maps to the tagId of a SoftwareIdentity."
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "Maps to the name of a SoftwareIdentity."
+ },
+ "version": {
+ "type": "string",
+ "title": "Version",
+ "default": "0.0",
+ "description": "Maps to the version of a SoftwareIdentity."
+ },
+ "tagVersion": {
+ "type": "integer",
+ "title": "Tag Version",
+ "default": 0,
+ "description": "Maps to the tagVersion of a SoftwareIdentity."
+ },
+ "patch": {
+ "type": "boolean",
+ "title": "Patch",
+ "default": false,
+ "description": "Maps to the patch of a SoftwareIdentity."
+ },
+ "text": {
+ "title": "Attachment text",
+ "description": "Specifies the metadata and content of the SWID tag.",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the SWID file.",
+ "format": "iri-reference"
+ }
+ }
+ },
+ "attachment": {
+ "type": "object",
+ "title": "Attachment",
+ "description": "Specifies the metadata and content for an attachment.",
+ "required": [
+ "content"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "contentType": {
+ "type": "string",
+ "title": "Content-Type",
+ "description": "Specifies the content type of the text. Defaults to text/plain if not specified.",
+ "default": "text/plain"
+ },
+ "encoding": {
+ "type": "string",
+ "title": "Encoding",
+ "description": "Specifies the optional encoding the text is represented in.",
+ "enum": [
+ "base64"
+ ]
+ },
+ "content": {
+ "type": "string",
+ "title": "Attachment Text",
+ "description": "The attachment data"
+ }
+ }
+ },
+ "hash": {
+ "type": "object",
+ "title": "Hash Objects",
+ "required": [
+ "alg",
+ "content"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "alg": {
+ "$ref": "#/definitions/hash-alg"
+ },
+ "content": {
+ "$ref": "#/definitions/hash-content"
+ }
+ }
+ },
+ "hash-alg": {
+ "type": "string",
+ "enum": [
+ "MD5",
+ "SHA-1",
+ "SHA-256",
+ "SHA-384",
+ "SHA-512",
+ "SHA3-256",
+ "SHA3-384",
+ "SHA3-512",
+ "BLAKE2b-256",
+ "BLAKE2b-384",
+ "BLAKE2b-512",
+ "BLAKE3"
+ ],
+ "title": "Hash Algorithm"
+ },
+ "hash-content": {
+ "type": "string",
+ "title": "Hash Content (value)",
+ "examples": ["3942447fac867ae5cdb3229b658f4d48"],
+ "pattern": "^([a-fA-F0-9]{32}|[a-fA-F0-9]{40}|[a-fA-F0-9]{64}|[a-fA-F0-9]{96}|[a-fA-F0-9]{128})$"
+ },
+ "license": {
+ "type": "object",
+ "title": "License Object",
+ "oneOf": [
+ {
+ "required": ["id"]
+ },
+ {
+ "required": ["name"]
+ }
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "$ref": "spdx.schema.json",
+ "title": "License ID (SPDX)",
+ "description": "A valid SPDX license ID",
+ "examples": ["Apache-2.0"]
+ },
+ "name": {
+ "type": "string",
+ "title": "License Name",
+ "description": "If SPDX does not define the license used, this field may be used to provide the license name",
+ "examples": ["Acme Software License"]
+ },
+ "text": {
+ "title": "License text",
+ "description": "An optional way to include the textual content of a license.",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "License URL",
+ "description": "The URL to the license file. If specified, a 'license' externalReference should also be specified for completeness",
+ "examples": ["https://www.apache.org/licenses/LICENSE-2.0.txt"],
+ "format": "iri-reference"
+ }
+ }
+ },
+ "licenseChoice": {
+ "type": "object",
+ "title": "License(s)",
+ "additionalProperties": false,
+ "properties": {
+ "license": {
+ "$ref": "#/definitions/license"
+ },
+ "expression": {
+ "type": "string",
+ "title": "SPDX License Expression",
+ "examples": [
+ "Apache-2.0 AND (MIT OR GPL-2.0-only)",
+ "GPL-3.0-only WITH Classpath-exception-2.0"
+ ]
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["license"]
+ },
+ {
+ "required": ["expression"]
+ }
+ ]
+ },
+ "commit": {
+ "type": "object",
+ "title": "Commit",
+ "description": "Specifies an individual commit",
+ "additionalProperties": false,
+ "properties": {
+ "uid": {
+ "type": "string",
+ "title": "UID",
+ "description": "A unique identifier of the commit. This may be version control specific. For example, Subversion uses revision numbers whereas git uses commit hashes."
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the commit. This URL will typically point to a commit in a version control system.",
+ "format": "iri-reference"
+ },
+ "author": {
+ "title": "Author",
+ "description": "The author who created the changes in the commit",
+ "$ref": "#/definitions/identifiableAction"
+ },
+ "committer": {
+ "title": "Committer",
+ "description": "The person who committed or pushed the commit",
+ "$ref": "#/definitions/identifiableAction"
+ },
+ "message": {
+ "type": "string",
+ "title": "Message",
+ "description": "The text description of the contents of the commit"
+ }
+ }
+ },
+ "patch": {
+ "type": "object",
+ "title": "Patch",
+ "description": "Specifies an individual patch",
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "unofficial",
+ "monkey",
+ "backport",
+ "cherry-pick"
+ ],
+ "title": "Type",
+ "description": "Specifies the purpose for the patch including the resolution of defects, security issues, or new behavior or functionality"
+ },
+ "diff": {
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "$ref": "#/definitions/diff"
+ },
+ "resolves": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/issue"},
+ "title": "Resolves",
+ "description": "A collection of issues the patch resolves"
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "additionalProperties": false,
+ "properties": {
+ "text": {
+ "title": "Diff text",
+ "description": "Specifies the optional text of the diff",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "Specifies the URL to the diff",
+ "format": "iri-reference"
+ }
+ }
+ },
+ "issue": {
+ "type": "object",
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "defect",
+ "enhancement",
+ "security"
+ ],
+ "title": "Type",
+ "description": "Specifies the type of issue"
+ },
+ "id": {
+ "type": "string",
+ "title": "ID",
+ "description": "The identifier of the issue assigned by the source of the issue"
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the issue"
+ },
+ "description": {
+ "type": "string",
+ "title": "Description",
+ "description": "A description of the issue"
+ },
+ "source": {
+ "type": "object",
+ "title": "Source",
+ "description": "The source of the issue where it is documented",
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the source. For example 'National Vulnerability Database', 'NVD', and 'Apache'"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The url of the issue documentation as provided by the source",
+ "format": "iri-reference"
+ }
+ }
+ },
+ "references": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "iri-reference"
+ },
+ "title": "References",
+ "description": "A collection of URL's for reference. Multiple URLs are allowed.",
+ "examples": ["https://example.com"]
+ }
+ }
+ },
+ "identifiableAction": {
+ "type": "object",
+ "title": "Identifiable Action",
+ "description": "Specifies an individual commit",
+ "additionalProperties": false,
+ "properties": {
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Timestamp",
+ "description": "The timestamp in which the action occurred"
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the individual who performed the action"
+ },
+ "email": {
+ "type": "string",
+ "format": "idn-email",
+ "title": "E-mail",
+ "description": "The email address of the individual who performed the action"
+ }
+ }
+ },
+ "externalReference": {
+ "type": "object",
+ "title": "External Reference",
+ "description": "Specifies an individual external reference",
+ "required": [
+ "url",
+ "type"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the external reference",
+ "format": "iri-reference"
+ },
+ "comment": {
+ "type": "string",
+ "title": "Comment",
+ "description": "An optional comment describing the external reference"
+ },
+ "type": {
+ "type": "string",
+ "title": "Type",
+ "description": "Specifies the type of external reference. There are built-in types to describe common references. If a type does not exist for the reference being referred to, use the \"other\" type.",
+ "enum": [
+ "vcs",
+ "issue-tracker",
+ "website",
+ "advisories",
+ "bom",
+ "mailing-list",
+ "social",
+ "chat",
+ "documentation",
+ "support",
+ "distribution",
+ "license",
+ "build-meta",
+ "build-system",
+ "other"
+ ]
+ },
+ "hashes": {
+ "$id": "#/properties/hashes",
+ "type": "array",
+ "items": {"$ref": "#/definitions/hash"},
+ "title": "Hashes",
+ "description": "The hashes of the external reference (if applicable)."
+ }
+ }
+ },
+ "dependency": {
+ "type": "object",
+ "title": "Dependency",
+ "description": "Defines the direct dependencies of a component. Components that do not have their own dependencies MUST be declared as empty elements within the graph. Components that are not represented in the dependency graph MAY have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque and not an indicator of a component being dependency-free.",
+ "required": [
+ "ref"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "ref": {
+ "type": "string",
+ "title": "Reference",
+ "description": "References a component by the components bom-ref attribute"
+ },
+ "dependsOn": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ },
+ "title": "Depends On",
+ "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
+ }
+ }
+ },
+ "service": {
+ "type": "object",
+ "title": "Service Object",
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "bom-ref": {
+ "type": "string",
+ "title": "BOM Reference",
+ "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique."
+ },
+ "provider": {
+ "title": "Provider",
+ "description": "The organization that provides the service.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "group": {
+ "type": "string",
+ "title": "Service Group",
+ "description": "The grouping name, namespace, or identifier. This will often be a shortened, single name of the company or project that produced the service or domain name. Whitespace and special characters should be avoided.",
+ "examples": ["com.acme"]
+ },
+ "name": {
+ "type": "string",
+ "title": "Service Name",
+ "description": "The name of the service. This will often be a shortened, single name of the service.",
+ "examples": ["ticker-service"]
+ },
+ "version": {
+ "type": "string",
+ "title": "Service Version",
+ "description": "The service version.",
+ "examples": ["1.0.0"]
+ },
+ "description": {
+ "type": "string",
+ "title": "Service Description",
+ "description": "Specifies a description for the service"
+ },
+ "endpoints": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "iri-reference"
+ },
+ "title": "Endpoints",
+ "description": "The endpoint URIs of the service. Multiple endpoints are allowed.",
+ "examples": ["https://example.com/api/v1/ticker"]
+ },
+ "authenticated": {
+ "type": "boolean",
+ "title": "Authentication Required",
+ "description": "A boolean value indicating if the service requires authentication. A value of true indicates the service requires authentication prior to use. A value of false indicates the service does not require authentication."
+ },
+ "x-trust-boundary": {
+ "type": "boolean",
+ "title": "Crosses Trust Boundary",
+ "description": "A boolean value indicating if use of the service crosses a trust zone or boundary. A value of true indicates that by using the service, a trust boundary is crossed. A value of false indicates that by using the service, a trust boundary is not crossed."
+ },
+ "data": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/dataClassification"},
+ "title": "Data Classification",
+ "description": "Specifies the data classification."
+ },
+ "licenses": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/licenseChoice"},
+ "title": "Component License(s)"
+ },
+ "externalReferences": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References"
+ },
+ "services": {
+ "$id": "#/properties/services",
+ "type": "array",
+ "items": {"$ref": "#/definitions/service"},
+ "uniqueItems": true,
+ "title": "Services"
+ },
+ "properties": {
+ "type": "array",
+ "title": "Properties",
+ "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
+ "items": {"$ref": "#/definitions/property"}
+ }
+ }
+ },
+ "dataClassification": {
+ "type": "object",
+ "title": "Hash Objects",
+ "required": [
+ "flow",
+ "classification"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "flow": {
+ "$ref": "#/definitions/dataFlow"
+ },
+ "classification": {
+ "type": "string"
+ }
+ }
+ },
+ "dataFlow": {
+ "type": "string",
+ "enum": [
+ "inbound",
+ "outbound",
+ "bi-directional",
+ "unknown"
+ ],
+ "title": "Data flow direction"
+ },
+
+ "copyright": {
+ "type": "object",
+ "title": "Copyright",
+ "required": [
+ "text"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "text": {
+ "type": "string",
+ "title": "Copyright Text"
+ }
+ }
+ },
+
+ "componentEvidence": {
+ "type": "object",
+ "title": "Evidence",
+ "description": "Provides the ability to document evidence collected through various forms of extraction or analysis.",
+ "additionalProperties": false,
+ "properties": {
+ "licenses": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/licenseChoice"},
+ "title": "Component License(s)"
+ },
+ "copyright": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/copyright"},
+ "title": "Copyright"
+ }
+ }
+ },
+ "compositions": {
+ "type": "object",
+ "title": "Compositions",
+ "required": [
+ "aggregate"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "aggregate": {
+ "$ref": "#/definitions/aggregateType",
+ "title": "Aggregate",
+ "description": "Specifies an aggregate type that describe how complete a relationship is."
+ },
+ "assemblies": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ },
+ "title": "BOM references",
+ "description": "The bom-ref identifiers of the components or services being described. Assemblies refer to nested relationships whereby a constituent part may include other constituent parts. References do not cascade to child parts. References are explicit for the specified constituent part only."
+ },
+ "dependencies": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ },
+ "title": "BOM references",
+ "description": "The bom-ref identifiers of the components or services being described. Dependencies refer to a relationship whereby an independent constituent part requires another independent constituent part. References do not cascade to transitive dependencies. References are explicit for the specified dependency only."
+ }
+ }
+ },
+ "aggregateType": {
+ "type": "string",
+ "default": "not_specified",
+ "enum": [
+ "complete",
+ "incomplete",
+ "incomplete_first_party_only",
+ "incomplete_third_party_only",
+ "unknown",
+ "not_specified"
+ ]
+ },
+ "property": {
+ "type": "object",
+ "title": "Lightweight name-value pair",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the property. Duplicate names are allowed, each potentially having a different value."
+ },
+ "value": {
+ "type": "string",
+ "title": "Value",
+ "description": "The value of the property."
+ }
+ }
+ }
+ }
+}
diff --git a/cyclonedx/schema/bom-1.3.proto b/cyclonedx/schema/bom-1.3.proto
new file mode 100644
index 00000000..5c9926b2
--- /dev/null
+++ b/cyclonedx/schema/bom-1.3.proto
@@ -0,0 +1,452 @@
+syntax = "proto3";
+package cyclonedx.v1_3;
+import "google/protobuf/timestamp.proto";
+
+// Specifies attributes of the text
+message AttachedText {
+ // Specifies the content type of the text. Defaults to text/plain if not specified.
+ optional string content_type = 1;
+ // Specifies the optional encoding the text is represented in
+ optional string encoding = 2;
+ // SimpleContent value of element
+ string value = 3;
+}
+
+message Bom {
+ // The version of the CycloneDX specification a BOM is written to (starting at version 1.3)
+ string spec_version = 1;
+ // The version allows component publishers/authors to make changes to existing BOMs to update various aspects of the document such as description or licenses. When a system is presented with multiple BOMs for the same component, the system should use the most recent version of the BOM. The default version is '1' and should be incremented for each version of the BOM that is published. Each version of a component should have a unique BOM and if no changes are made to the BOMs, then each BOM will have a version of '1'.
+ optional int32 version = 2;
+ // Every BOM generated should have a unique serial number, even if the contents of the BOM being generated have not changed over time. The process or tool responsible for creating the BOM should create random UUID's for every BOM generated.
+ optional string serial_number = 3;
+ // Provides additional information about a BOM.
+ optional Metadata metadata = 4;
+ // Provides the ability to document a list of components.
+ repeated Component components = 5;
+ // Provides the ability to document a list of external services.
+ repeated Service services = 6;
+ // Provides the ability to document external references related to the BOM or to the project the BOM describes.
+ repeated ExternalReference external_references = 7;
+ // Provides the ability to document dependency relationships.
+ repeated Dependency dependencies = 8;
+ // Provides the ability to document aggregate completeness
+ repeated Composition compositions = 9;
+}
+
+enum Classification {
+ CLASSIFICATION_NULL = 0;
+ // A software application. Refer to https://en.wikipedia.org/wiki/Application_software for information about applications.
+ CLASSIFICATION_APPLICATION = 1;
+ // A software framework. Refer to https://en.wikipedia.org/wiki/Software_framework for information on how frameworks vary slightly from libraries.
+ CLASSIFICATION_FRAMEWORK = 2;
+ // A software library. Refer to https://en.wikipedia.org/wiki/Library_(computing) for information about libraries. All third-party and open source reusable components will likely be a library. If the library also has key features of a framework, then it should be classified as a framework. If not, or is unknown, then specifying library is recommended.
+ CLASSIFICATION_LIBRARY = 3;
+ // A software operating system without regard to deployment model (i.e. installed on physical hardware, virtual machine, image, etc) Refer to https://en.wikipedia.org/wiki/Operating_system
+ CLASSIFICATION_OPERATING_SYSTEM = 4;
+ // A hardware device such as a processor, or chip-set. A hardware device containing firmware should include a component for the physical hardware itself, and another component of type 'firmware' or 'operating-system' (whichever is relevant), describing information about the software running on the device.
+ CLASSIFICATION_DEVICE = 5;
+ // A computer file. Refer to https://en.wikipedia.org/wiki/Computer_file for information about files.
+ CLASSIFICATION_FILE = 6;
+ // A packaging and/or runtime format, not specific to any particular technology, which isolates software inside the container from software outside of a container through virtualization technology. Refer to https://en.wikipedia.org/wiki/OS-level_virtualization
+ CLASSIFICATION_CONTAINER = 7;
+ // A special type of software that provides low-level control over a devices hardware. Refer to https://en.wikipedia.org/wiki/Firmware
+ CLASSIFICATION_FIRMWARE = 8;
+}
+
+message Commit {
+ // A unique identifier of the commit. This may be version control specific. For example, Subversion uses revision numbers whereas git uses commit hashes.
+ optional string uid = 1;
+ // The URL to the commit. This URL will typically point to a commit in a version control system.
+ optional string url = 2;
+ // The author who created the changes in the commit
+ optional IdentifiableAction author = 3;
+ // The person who committed or pushed the commit
+ optional IdentifiableAction committer = 4;
+ // The text description of the contents of the commit
+ optional string message = 5;
+}
+
+message Component {
+ // Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component.
+ Classification type = 1;
+ // The optional mime-type of the component. When used on file components, the mime-type can provide additional context about the kind of file being represented such as an image, font, or executable. Some library or framework components may also have an associated mime-type.
+ optional string mime_type = 2;
+ // An optional identifier which can be used to reference the component elsewhere in the BOM. Uniqueness is enforced within all elements and children of the root-level bom element.
+ optional string bom_ref = 3;
+ // The organization that supplied the component. The supplier may often be the manufacture, but may also be a distributor or repackager.
+ optional OrganizationalEntity supplier = 4;
+ // The person(s) or organization(s) that authored the component
+ optional string author = 5;
+ // The person(s) or organization(s) that published the component
+ optional string publisher = 6;
+ // The grouping name or identifier. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. Whitespace and special characters should be avoided. Examples include: apache, org.apache.commons, and apache.org.
+ optional string group = 7;
+ // The name of the component. This will often be a shortened, single name of the component. Examples: commons-lang3 and jquery
+ string name = 8;
+ // The component version. The version should ideally comply with semantic versioning but is not enforced.
+ string version = 9;
+ // Specifies a description for the component
+ optional string description = 10;
+ // Specifies the scope of the component. If scope is not specified, 'runtime' scope should be assumed by the consumer of the BOM
+ optional Scope scope = 11;
+ repeated Hash hashes = 12;
+ repeated LicenseChoice licenses = 13;
+ // An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.
+ optional string copyright = 14;
+ // DEPRECATED - DO NOT USE. This will be removed in a future version. Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe
+ optional string cpe = 15;
+ // Specifies the package-url (PURL). The purl, if specified, must be valid and conform to the specification defined at: https://github.com/package-url/purl-spec
+ optional string purl = 16;
+ // Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.
+ optional Swid swid = 17;
+ // DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree element instead to supply information on exactly how the component was modified. A boolean value indicating is the component has been modified from the original. A value of true indicates the component is a derivative of the original. A value of false indicates the component has not been modified from the original.
+ optional bool modified = 18;
+ // Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc.
+ optional Pedigree pedigree = 19;
+ // Provides the ability to document external references related to the component or to the project the component describes.
+ repeated ExternalReference external_references = 20;
+ // Specifies optional sub-components. This is not a dependency tree. It provides a way to specify a hierarchical representation of component assemblies, similar to system -> subsystem -> parts assembly in physical supply chains.
+ repeated Component components = 21;
+ // Specifies optional, custom, properties
+ repeated Property properties = 22;
+ // Specifies optional license and copyright evidence
+ repeated Evidence evidence = 23;
+}
+
+// Specifies the data classification.
+message DataClassification {
+ // Specifies the flow direction of the data.
+ DataFlow flow = 1;
+ // SimpleContent value of element
+ string value = 2;
+}
+
+// Specifies the flow direction of the data. Valid values are: inbound, outbound, bi-directional, and unknown. Direction is relative to the service. Inbound flow states that data enters the service. Outbound flow states that data leaves the service. Bi-directional states that data flows both ways, and unknown states that the direction is not known.
+enum DataFlow {
+ DATA_FLOW_NULL = 0;
+ DATA_FLOW_INBOUND = 1;
+ DATA_FLOW_OUTBOUND = 2;
+ DATA_FLOW_BI_DIRECTIONAL = 3;
+ DATA_FLOW_UNKNOWN = 4;
+}
+
+message Dependency {
+ // References a component or service by the its bom-ref attribute
+ string ref = 1;
+ repeated Dependency dependencies = 2;
+}
+
+message Diff {
+ // Specifies the optional text of the diff
+ optional AttachedText text = 1;
+ // Specifies the URL to the diff
+ optional string url = 2;
+}
+
+message ExternalReference {
+ // Specifies the type of external reference. There are built-in types to describe common references. If a type does not exist for the reference being referred to, use the "other" type.
+ ExternalReferenceType type = 1;
+ // The URL to the external reference
+ string url = 2;
+ // An optional comment describing the external reference
+ optional string comment = 3;
+ // Optional integrity hashes for the external resource content
+ repeated Hash hashes = 4;
+}
+
+enum ExternalReferenceType {
+ // Use this if no other types accurately describe the purpose of the external reference
+ EXTERNAL_REFERENCE_TYPE_OTHER = 0;
+ // Version Control System
+ EXTERNAL_REFERENCE_TYPE_VCS = 1;
+ // Issue or defect tracking system, or an Application Lifecycle Management (ALM) system
+ EXTERNAL_REFERENCE_TYPE_ISSUE_TRACKER = 2;
+ // Website
+ EXTERNAL_REFERENCE_TYPE_WEBSITE = 3;
+ // Security advisories
+ EXTERNAL_REFERENCE_TYPE_ADVISORIES = 4;
+ // Bill-of-material document (CycloneDX, SPDX, SWID, etc)
+ EXTERNAL_REFERENCE_TYPE_BOM = 5;
+ // Mailing list or discussion group
+ EXTERNAL_REFERENCE_TYPE_MAILING_LIST = 6;
+ // Social media account
+ EXTERNAL_REFERENCE_TYPE_SOCIAL = 7;
+ // Real-time chat platform
+ EXTERNAL_REFERENCE_TYPE_CHAT = 8;
+ // Documentation, guides, or how-to instructions
+ EXTERNAL_REFERENCE_TYPE_DOCUMENTATION = 9;
+ // Community or commercial support
+ EXTERNAL_REFERENCE_TYPE_SUPPORT = 10;
+ // Direct or repository download location
+ EXTERNAL_REFERENCE_TYPE_DISTRIBUTION = 11;
+ // The URL to the license file. If a license URL has been defined in the license node, it should also be defined as an external reference for completeness
+ EXTERNAL_REFERENCE_TYPE_LICENSE = 12;
+ // Build-system specific meta file (i.e. pom.xml, package.json, .nuspec, etc)
+ EXTERNAL_REFERENCE_TYPE_BUILD_META = 13;
+ // URL to an automated build system
+ EXTERNAL_REFERENCE_TYPE_BUILD_SYSTEM = 14;
+}
+
+enum HashAlg {
+ HASH_ALG_NULL = 0;
+ HASH_ALG_MD_5 = 1;
+ HASH_ALG_SHA_1 = 2;
+ HASH_ALG_SHA_256 = 3;
+ HASH_ALG_SHA_384 = 4;
+ HASH_ALG_SHA_512 = 5;
+ HASH_ALG_SHA_3_256 = 6;
+ HASH_ALG_SHA_3_384 = 7;
+ HASH_ALG_SHA_3_512 = 8;
+ HASH_ALG_BLAKE_2_B_256 = 9;
+ HASH_ALG_BLAKE_2_B_384 = 10;
+ HASH_ALG_BLAKE_2_B_512 = 11;
+ HASH_ALG_BLAKE_3 = 12;
+}
+
+// Specifies the file hash of the component
+message Hash {
+ // Specifies the algorithm used to create the hash
+ HashAlg alg = 1;
+ // SimpleContent value of element
+ string value = 2;
+}
+
+message IdentifiableAction {
+ // The timestamp in which the action occurred
+ optional google.protobuf.Timestamp timestamp = 1;
+ // The name of the individual who performed the action
+ optional string name = 2;
+ // The email address of the individual who performed the action
+ optional string email = 3;
+}
+
+enum IssueClassification {
+ ISSUE_CLASSIFICATION_NULL = 0;
+ // A fault, flaw, or bug in software
+ ISSUE_CLASSIFICATION_DEFECT = 1;
+ // A new feature or behavior in software
+ ISSUE_CLASSIFICATION_ENHANCEMENT = 2;
+ // A special type of defect which impacts security
+ ISSUE_CLASSIFICATION_SECURITY = 3;
+}
+
+message Issue {
+ // Specifies the type of issue
+ IssueClassification type = 1;
+ // The identifier of the issue assigned by the source of the issue
+ optional string id = 2;
+ // The name of the issue
+ optional string name = 3;
+ // A description of the issue
+ optional string description = 4;
+ optional Source source = 5;
+ repeated string references = 6;
+}
+
+// The source of the issue where it is documented.
+message Source {
+ // The name of the source. For example "National Vulnerability Database", "NVD", and "Apache"
+ optional string name = 1;
+ // The url of the issue documentation as provided by the source
+ optional string url = 2;
+}
+
+message LicenseChoice {
+ oneof choice {
+ License license = 1;
+ string expression = 2;
+ }
+}
+
+message License {
+ oneof license {
+ // A valid SPDX license ID
+ string id = 1;
+ // If SPDX does not define the license used, this field may be used to provide the license name
+ string name = 2;
+ }
+ // Specifies the optional full text of the attachment
+ optional AttachedText text = 3;
+ // The URL to the attachment file. If the attachment is a license or BOM, an externalReference should also be specified for completeness.
+ optional string url = 4;
+}
+
+message Metadata {
+ // The date and time (timestamp) when the document was created.
+ optional google.protobuf.Timestamp timestamp = 1;
+ // The tool(s) used in the creation of the BOM.
+ repeated Tool tools = 2;
+ // The person(s) who created the BOM. Authors are common in BOMs created through manual processes. BOMs created through automated means may not have authors.
+ repeated OrganizationalContact authors = 3;
+ // The component that the BOM describes.
+ optional Component component = 4;
+ // The organization that manufactured the component that the BOM describes.
+ optional OrganizationalEntity manufacture = 5;
+ // The organization that supplied the component that the BOM describes. The supplier may often be the manufacture, but may also be a distributor or repackager.
+ optional OrganizationalEntity supplier = 6;
+ // The license information for the BOM document
+ optional LicenseChoice licenses = 7;
+ // Specifies optional, custom, properties
+ repeated Property properties = 8;
+}
+
+message OrganizationalContact {
+ // The name of the contact
+ optional string name = 1;
+ // The email address of the contact.
+ optional string email = 2;
+ // The phone number of the contact.
+ optional string phone = 3;
+}
+
+message OrganizationalEntity {
+ // The name of the organization
+ optional string name = 1;
+ // The URL of the organization. Multiple URLs are allowed.
+ repeated string url = 2;
+ // A contact person at the organization. Multiple contacts are allowed.
+ repeated OrganizationalContact contact = 3;
+}
+
+enum PatchClassification {
+ PATCH_CLASSIFICATION_NULL = 0;
+ // A patch which is not developed by the creators or maintainers of the software being patched. Refer to https://en.wikipedia.org/wiki/Unofficial_patch
+ PATCH_CLASSIFICATION_UNOFFICIAL = 1;
+ // A patch which dynamically modifies runtime behavior. Refer to https://en.wikipedia.org/wiki/Monkey_patch
+ PATCH_CLASSIFICATION_MONKEY = 2;
+ // A patch which takes code from a newer version of software and applies it to older versions of the same software. Refer to https://en.wikipedia.org/wiki/Backporting
+ PATCH_CLASSIFICATION_BACKPORT = 3;
+ // A patch created by selectively applying commits from other versions or branches of the same software.
+ PATCH_CLASSIFICATION_CHERRY_PICK = 4;
+}
+
+message Patch {
+ // Specifies the purpose for the patch including the resolution of defects, security issues, or new behavior or functionality
+ PatchClassification type = 1;
+ // The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff
+ optional Diff diff = 2;
+ repeated Issue resolves = 3;
+}
+
+// Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to document variants where the exact relation may not be known.
+message Pedigree {
+ // Describes zero or more components in which a component is derived from. This is commonly used to describe forks from existing projects where the forked version contains a ancestor node containing the original component it was forked from. For example, Component A is the original component. Component B is the component being used and documented in the BOM. However, Component B contains a pedigree node with a single ancestor documenting Component A - the original component from which Component B is derived from.
+ repeated Component ancestors = 1;
+ // Descendants are the exact opposite of ancestors. This provides a way to document all forks (and their forks) of an original or root component.
+ repeated Component descendants = 2;
+ // Variants describe relations where the relationship between the components are not known. For example, if Component A contains nearly identical code to Component B. They are both related, but it is unclear if one is derived from the other, or if they share a common ancestor.
+ repeated Component variants = 3;
+ // A list of zero or more commits which provide a trail describing how the component deviates from an ancestor, descendant, or variant.
+ repeated Commit commits = 4;
+ // A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits or may be used in place of commits.
+ repeated Patch patches = 5;
+ // Notes, observations, and other non-structured commentary describing the components pedigree.
+ optional string notes = 6;
+}
+
+enum Scope {
+ // Default
+ SCOPE_UNSPECIFIED = 0;
+ // The component is required for runtime
+ SCOPE_REQUIRED = 1;
+ // The component is optional at runtime. Optional components are components that are not capable of being called due to them not be installed or otherwise accessible by any means. Components that are installed but due to configuration or other restrictions are prohibited from being called must be scoped as 'required'.
+ SCOPE_OPTIONAL = 2;
+ // Components that are excluded provide the ability to document component usage for test and other non-runtime purposes. Excluded components are not reachable within a call graph at runtime.
+ SCOPE_EXCLUDED = 3;
+}
+
+message Service {
+ // An optional identifier which can be used to reference the service elsewhere in the BOM. Uniqueness is enforced within all elements and children of the root-level bom element.
+ optional string bom_ref = 1;
+ // The organization that provides the service.
+ optional OrganizationalEntity provider = 2;
+ // The grouping name, namespace, or identifier. This will often be a shortened, single name of the company or project that produced the service or domain name. Whitespace and special characters should be avoided.
+ optional string group = 3;
+ // The name of the service. This will often be a shortened, single name of the service.
+ string name = 4;
+ // The service version.
+ optional string version = 5;
+ // Specifies a description for the service.
+ optional string description = 6;
+ repeated string endpoints = 7;
+ // A boolean value indicating if the service requires authentication. A value of true indicates the service requires authentication prior to use. A value of false indicates the service does not require authentication.
+ optional bool authenticated = 8;
+ // A boolean value indicating if use of the service crosses a trust zone or boundary. A value of true indicates that by using the service, a trust boundary is crossed. A value of false indicates that by using the service, a trust boundary is not crossed.
+ optional bool x_trust_boundary = 9;
+ repeated DataClassification data = 10;
+ repeated LicenseChoice licenses = 11;
+ // Provides the ability to document external references related to the service.
+ repeated ExternalReference external_references = 12;
+ // Specifies optional sub-service. This is not a dependency tree. It provides a way to specify a hierarchical representation of service assemblies, similar to system -> subsystem -> parts assembly in physical supply chains.
+ repeated Service services = 13;
+ // Specifies optional, custom, properties
+ repeated Property properties = 14;
+}
+
+message Swid {
+ // Maps to the tagId of a SoftwareIdentity.
+ string tag_id = 1;
+ // Maps to the name of a SoftwareIdentity.
+ string name = 2;
+ // Maps to the version of a SoftwareIdentity.
+ optional string version = 3;
+ // Maps to the tagVersion of a SoftwareIdentity.
+ optional int32 tag_version = 4;
+ // Maps to the patch of a SoftwareIdentity.
+ optional bool patch = 5;
+ // Specifies the full content of the SWID tag.
+ optional AttachedText text = 6;
+ // The URL to the SWID file.
+ optional string url = 7;
+}
+
+// Specifies a tool (manual or automated).
+message Tool {
+ // The vendor of the tool used to create the BOM.
+ optional string vendor = 1;
+ // The name of the tool used to create the BOM.
+ optional string name = 2;
+ // The version of the tool used to create the BOM.
+ optional string version = 3;
+ repeated Hash hashes = 4;
+}
+
+// Specifies a property
+message Property {
+ string name = 1;
+ optional string value = 2;
+}
+
+enum Aggregate {
+ // Default, no statement about the aggregate completeness is being made
+ AGGREGATE_NOT_SPECIFIED = 0;
+ // The aggregate composition is complete
+ AGGREGATE_COMPLETE = 1;
+ // The aggregate composition is incomplete
+ AGGREGATE_INCOMPLETE = 2;
+ // The aggregate composition is incomplete for first party components, complete for third party components
+ AGGREGATE_INCOMPLETE_FIRST_PARTY_ONLY = 3;
+ // The aggregate composition is incomplete for third party components, complete for first party components
+ AGGREGATE_INCOMPLETE_THIRD_PARTY_ONLY = 4;
+ // The aggregate composition completeness is unknown
+ AGGREGATE_UNKNOWN = 5;
+}
+
+message Composition {
+ // Indicates the aggregate completeness
+ Aggregate aggregate = 1;
+ // The assemblies the aggregate completeness applies to
+ repeated string assemblies = 2;
+ // The dependencies the aggregate completeness applies to
+ repeated string dependencies = 3;
+}
+
+message EvidenceCopyright {
+ // Copyright text
+ string text = 1;
+}
+
+message Evidence {
+ repeated LicenseChoice licenses = 1;
+ repeated EvidenceCopyright copyright = 2;
+}
diff --git a/cyclonedx/schema/bom-1.3.schema.json b/cyclonedx/schema/bom-1.3.schema.json
new file mode 100644
index 00000000..fdec9736
--- /dev/null
+++ b/cyclonedx/schema/bom-1.3.schema.json
@@ -0,0 +1,1054 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "http://cyclonedx.org/schema/bom-1.3.schema.json",
+ "type": "object",
+ "title": "CycloneDX Software Bill-of-Material Specification",
+ "$comment" : "CycloneDX JSON schema is published under the terms of the Apache License 2.0.",
+ "required": [
+ "bomFormat",
+ "specVersion",
+ "version"
+ ],
+ "properties": {
+ "bomFormat": {
+ "$id": "#/properties/bomFormat",
+ "type": "string",
+ "title": "BOM Format",
+ "description": "Specifies the format of the BOM. This helps to identify the file as CycloneDX since BOMs do not have a filename convention nor does JSON schema support namespaces.",
+ "enum": [
+ "CycloneDX"
+ ]
+ },
+ "specVersion": {
+ "$id": "#/properties/specVersion",
+ "type": "string",
+ "title": "CycloneDX Specification Version",
+ "description": "The version of the CycloneDX specification a BOM is written to (starting at version 1.2)",
+ "examples": ["1.3"]
+ },
+ "serialNumber": {
+ "$id": "#/properties/serialNumber",
+ "type": "string",
+ "title": "BOM Serial Number",
+ "description": "Every BOM generated should have a unique serial number, even if the contents of the BOM being generated have not changed over time. The process or tool responsible for creating the BOM should create random UUID's for every BOM generated.",
+ "examples": ["urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79"],
+ "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ },
+ "version": {
+ "$id": "#/properties/version",
+ "type": "integer",
+ "title": "BOM Version",
+ "description": "The version allows component publishers/authors to make changes to existing BOMs to update various aspects of the document such as description or licenses. When a system is presented with multiple BOMs for the same component, the system should use the most recent version of the BOM. The default version is '1' and should be incremented for each version of the BOM that is published. Each version of a component should have a unique BOM and if no changes are made to the BOMs, then each BOM will have a version of '1'.",
+ "default": 1,
+ "examples": [1]
+ },
+ "metadata": {
+ "$id": "#/properties/metadata",
+ "$ref": "#/definitions/metadata",
+ "title": "BOM Metadata",
+ "description": "Provides additional information about a BOM."
+ },
+ "components": {
+ "$id": "#/properties/components",
+ "type": "array",
+ "items": {"$ref": "#/definitions/component"},
+ "uniqueItems": true,
+ "title": "Components"
+ },
+ "services": {
+ "$id": "#/properties/services",
+ "type": "array",
+ "items": {"$ref": "#/definitions/service"},
+ "uniqueItems": true,
+ "title": "Services"
+ },
+ "externalReferences": {
+ "$id": "#/properties/externalReferences",
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References",
+ "description": "External references provide a way to document systems, sites, and information that may be relevant but which are not included with the BOM."
+ },
+ "dependencies": {
+ "$id": "#/properties/dependencies",
+ "type": "array",
+ "items": {"$ref": "#/definitions/dependency"},
+ "uniqueItems": true,
+ "title": "Dependencies",
+ "description": "Provides the ability to document dependency relationships."
+ },
+ "compositions": {
+ "$id": "#/properties/compositions",
+ "type": "array",
+ "items": {"$ref": "#/definitions/compositions"},
+ "uniqueItems": true,
+ "title": "Compositions",
+ "description": "Compositions describe constituent parts (including components, services, and dependency relationships) and their completeness."
+ }
+ },
+ "definitions": {
+ "metadata": {
+ "type": "object",
+ "title": "BOM Metadata Object",
+ "properties": {
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Timestamp",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "tools": {
+ "type": "array",
+ "title": "Creation Tools",
+ "description": "The tool(s) used in the creation of the BOM.",
+ "items": {"$ref": "#/definitions/tool"}
+ },
+ "authors" :{
+ "type": "array",
+ "title": "Authors",
+ "description": "The person(s) who created the BOM. Authors are common in BOMs created through manual processes. BOMs created through automated means may not have authors.",
+ "items": {"$ref": "#/definitions/organizationalContact"}
+ },
+ "component": {
+ "title": "Component",
+ "description": "The component that the BOM describes.",
+ "$ref": "#/definitions/component"
+ },
+ "manufacture": {
+ "title": "Manufacture",
+ "description": "The organization that manufactured the component that the BOM describes.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "supplier": {
+ "title": "Supplier",
+ "description": " The organization that supplied the component that the BOM describes. The supplier may often be the manufacturer, but may also be a distributor or repackager.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "licenses": {
+ "type": "array",
+ "title": "BOM License(s)",
+ "items": {"$ref": "#/definitions/licenseChoice"}
+ },
+ "properties": {
+ "type": "array",
+ "title": "Properties",
+ "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
+ "items": {"$ref": "#/definitions/property"}
+ }
+ }
+ },
+ "tool": {
+ "type": "object",
+ "title": "Tool",
+ "description": "The tool used to create the BOM.",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "title": "Tool Vendor",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "name": {
+ "type": "string",
+ "title": "Tool Name",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "version": {
+ "type": "string",
+ "title": "Tool Version",
+ "description": "The date and time (timestamp) when the document was created."
+ },
+ "hashes": {
+ "$id": "#/properties/hashes",
+ "type": "array",
+ "items": {"$ref": "#/definitions/hash"},
+ "title": "Hashes",
+ "description": "The hashes of the tool (if applicable)."
+ }
+ }
+ },
+ "organizationalEntity": {
+ "type": "object",
+ "title": "Organizational Entity Object",
+ "description": "",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the organization",
+ "examples": [
+ "Example Inc."
+ ]
+ },
+ "url": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "iri-reference"
+ },
+ "title": "URL",
+ "description": "The URL of the organization. Multiple URLs are allowed.",
+ "examples": ["https://example.com"]
+ },
+ "contact": {
+ "type": "array",
+ "title": "Contact",
+ "description": "A contact at the organization. Multiple contacts are allowed.",
+ "items": {"$ref": "#/definitions/organizationalContact"}
+ }
+ }
+ },
+ "organizationalContact": {
+ "type": "object",
+ "title": "Organizational Contact Object",
+ "description": "",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of a contact",
+ "examples": ["Contact name"]
+ },
+ "email": {
+ "type": "string",
+ "title": "Email Address",
+ "description": "The email address of the contact.",
+ "examples": ["firstname.lastname@example.com"]
+ },
+ "phone": {
+ "type": "string",
+ "title": "Phone",
+ "description": "The phone number of the contact.",
+ "examples": ["800-555-1212"]
+ }
+ }
+ },
+ "component": {
+ "type": "object",
+ "title": "Component Object",
+ "required": [
+ "type",
+ "name",
+ "version"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "application",
+ "framework",
+ "library",
+ "container",
+ "operating-system",
+ "device",
+ "firmware",
+ "file"
+ ],
+ "title": "Component Type",
+ "description": "Specifies the type of component. For software components, classify as application if no more specific appropriate classification is available or cannot be determined for the component.",
+ "examples": ["library"]
+ },
+ "mime-type": {
+ "type": "string",
+ "title": "Mime-Type",
+ "description": "The optional mime-type of the component. When used on file components, the mime-type can provide additional context about the kind of file being represented such as an image, font, or executable. Some library or framework components may also have an associated mime-type.",
+ "examples": ["image/jpeg"],
+ "pattern": "^[-+a-z0-9.]+/[-+a-z0-9.]+$"
+ },
+ "bom-ref": {
+ "type": "string",
+ "title": "BOM Reference",
+ "description": "An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref should be unique."
+ },
+ "supplier": {
+ "title": "Component Supplier",
+ "description": " The organization that supplied the component. The supplier may often be the manufacturer, but may also be a distributor or repackager.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "author": {
+ "type": "string",
+ "title": "Component Author",
+ "description": "The person(s) or organization(s) that authored the component",
+ "examples": ["Acme Inc"]
+ },
+ "publisher": {
+ "type": "string",
+ "title": "Component Publisher",
+ "description": "The person(s) or organization(s) that published the component",
+ "examples": ["Acme Inc"]
+ },
+ "group": {
+ "type": "string",
+ "title": "Component Group",
+ "description": "The grouping name or identifier. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. Whitespace and special characters should be avoided. Examples include: apache, org.apache.commons, and apache.org.",
+ "examples": ["com.acme"]
+ },
+ "name": {
+ "type": "string",
+ "title": "Component Name",
+ "description": "The name of the component. This will often be a shortened, single name of the component. Examples: commons-lang3 and jquery",
+ "examples": ["tomcat-catalina"]
+ },
+ "version": {
+ "type": "string",
+ "title": "Component Version",
+ "description": "The component version. The version should ideally comply with semantic versioning but is not enforced.",
+ "examples": ["9.0.14"]
+ },
+ "description": {
+ "type": "string",
+ "title": "Component Description",
+ "description": "Specifies a description for the component"
+ },
+ "scope": {
+ "type": "string",
+ "enum": [
+ "required",
+ "optional",
+ "excluded"
+ ],
+ "title": "Component Scope",
+ "description": "Specifies the scope of the component. If scope is not specified, 'required' scope should be assumed by the consumer of the BOM",
+ "default": "required"
+ },
+ "hashes": {
+ "type": "array",
+ "title": "Component Hashes",
+ "items": {"$ref": "#/definitions/hash"}
+ },
+ "licenses": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/licenseChoice"},
+ "title": "Component License(s)"
+ },
+ "copyright": {
+ "type": "string",
+ "title": "Component Copyright",
+ "description": "An optional copyright notice informing users of the underlying claims to copyright ownership in a published work.",
+ "examples": ["Acme Inc"]
+ },
+ "cpe": {
+ "type": "string",
+ "title": "Component Common Platform Enumeration (CPE)",
+ "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe",
+ "examples": ["cpe:2.3:a:acme:component_framework:-:*:*:*:*:*:*:*"]
+ },
+ "purl": {
+ "type": "string",
+ "title": "Component Package URL (purl)",
+ "examples": ["pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar"]
+ },
+ "swid": {
+ "$ref": "#/definitions/swid",
+ "title": "SWID Tag",
+ "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags."
+ },
+ "modified": {
+ "type": "boolean",
+ "title": "Component Modified From Original",
+ "description": "DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree element instead to supply information on exactly how the component was modified. A boolean value indicating is the component has been modified from the original. A value of true indicates the component is a derivative of the original. A value of false indicates the component has not been modified from the original."
+ },
+ "pedigree": {
+ "type": "object",
+ "title": "Component Pedigree",
+ "description": "Component pedigree is a way to document complex supply chain scenarios where components are created, distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to document variants where the exact relation may not be known.",
+ "properties": {
+ "ancestors": {
+ "type": "array",
+ "title": "Ancestors",
+ "description": "Describes zero or more components in which a component is derived from. This is commonly used to describe forks from existing projects where the forked version contains a ancestor node containing the original component it was forked from. For example, Component A is the original component. Component B is the component being used and documented in the BOM. However, Component B contains a pedigree node with a single ancestor documenting Component A - the original component from which Component B is derived from.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "descendants": {
+ "type": "array",
+ "title": "Descendants",
+ "description": "Descendants are the exact opposite of ancestors. This provides a way to document all forks (and their forks) of an original or root component.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "variants": {
+ "type": "array",
+ "title": "Variants",
+ "description": "Variants describe relations where the relationship between the components are not known. For example, if Component A contains nearly identical code to Component B. They are both related, but it is unclear if one is derived from the other, or if they share a common ancestor.",
+ "items": {"$ref": "#/definitions/component"}
+ },
+ "commits": {
+ "type": "array",
+ "title": "Commits",
+ "description": "A list of zero or more commits which provide a trail describing how the component deviates from an ancestor, descendant, or variant.",
+ "items": {"$ref": "#/definitions/commit"}
+ },
+ "patches": {
+ "type": "array",
+ "title": "Patches",
+ "description": ">A list of zero or more patches describing how the component deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits or may be used in place of commits.",
+ "items": {"$ref": "#/definitions/patch"}
+ },
+ "notes": {
+ "type": "string",
+ "title": "Notes",
+ "description": "Notes, observations, and other non-structured commentary describing the components pedigree."
+ }
+ }
+ },
+ "externalReferences": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References"
+ },
+ "components": {
+ "$id": "#/properties/components",
+ "type": "array",
+ "items": {"$ref": "#/definitions/component"},
+ "uniqueItems": true,
+ "title": "Components"
+ },
+ "evidence": {
+ "$ref": "#/definitions/componentEvidence",
+ "title": "Evidence",
+ "description": "Provides the ability to document evidence collected through various forms of extraction or analysis."
+ },
+ "properties": {
+ "type": "array",
+ "title": "Properties",
+ "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
+ "items": {"$ref": "#/definitions/property"}
+ }
+ }
+ },
+ "swid": {
+ "type": "object",
+ "title": "SWID Tag",
+ "description": "Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.",
+ "required": [
+ "tagId",
+ "name"
+ ],
+ "properties": {
+ "tagId": {
+ "type": "string",
+ "title": "Tag ID",
+ "description": "Maps to the tagId of a SoftwareIdentity."
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "Maps to the name of a SoftwareIdentity."
+ },
+ "version": {
+ "type": "string",
+ "title": "Version",
+ "default": "0.0",
+ "description": "Maps to the version of a SoftwareIdentity."
+ },
+ "tagVersion": {
+ "type": "integer",
+ "title": "Tag Version",
+ "default": 0,
+ "description": "Maps to the tagVersion of a SoftwareIdentity."
+ },
+ "patch": {
+ "type": "boolean",
+ "title": "Patch",
+ "default": false,
+ "description": "Maps to the patch of a SoftwareIdentity."
+ },
+ "text": {
+ "title": "Attachment text",
+ "description": "Specifies the metadata and content of the SWID tag.",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the SWID file.",
+ "format": "iri-reference"
+ }
+ }
+ },
+ "attachment": {
+ "type": "object",
+ "title": "Attachment",
+ "description": "Specifies the metadata and content for an attachment.",
+ "required": [
+ "content"
+ ],
+ "properties": {
+ "contentType": {
+ "type": "string",
+ "title": "Content-Type",
+ "description": "Specifies the content type of the text. Defaults to text/plain if not specified.",
+ "default": "text/plain"
+ },
+ "encoding": {
+ "type": "string",
+ "title": "Encoding",
+ "description": "Specifies the optional encoding the text is represented in.",
+ "enum": [
+ "base64"
+ ]
+ },
+ "content": {
+ "type": "string",
+ "title": "Attachment Text",
+ "description": "The attachment data"
+ }
+ }
+ },
+ "hash": {
+ "type": "object",
+ "title": "Hash Objects",
+ "required": [
+ "alg",
+ "content"
+ ],
+ "properties": {
+ "alg": {
+ "$ref": "#/definitions/hash-alg"
+ },
+ "content": {
+ "$ref": "#/definitions/hash-content"
+ }
+ }
+ },
+ "hash-alg": {
+ "type": "string",
+ "enum": [
+ "MD5",
+ "SHA-1",
+ "SHA-256",
+ "SHA-384",
+ "SHA-512",
+ "SHA3-256",
+ "SHA3-384",
+ "SHA3-512",
+ "BLAKE2b-256",
+ "BLAKE2b-384",
+ "BLAKE2b-512",
+ "BLAKE3"
+ ],
+ "title": "Hash Algorithm"
+ },
+ "hash-content": {
+ "type": "string",
+ "title": "Hash Content (value)",
+ "examples": ["3942447fac867ae5cdb3229b658f4d48"],
+ "pattern": "^([a-fA-F0-9]{32}|[a-fA-F0-9]{40}|[a-fA-F0-9]{64}|[a-fA-F0-9]{96}|[a-fA-F0-9]{128})$"
+ },
+ "license": {
+ "type": "object",
+ "title": "License Object",
+ "oneOf": [
+ {
+ "required": ["id"]
+ },
+ {
+ "required": ["name"]
+ }
+ ],
+ "properties": {
+ "id": {
+ "$ref": "spdx.schema.json",
+ "title": "License ID (SPDX)",
+ "description": "A valid SPDX license ID",
+ "examples": ["Apache-2.0"]
+ },
+ "name": {
+ "type": "string",
+ "title": "License Name",
+ "description": "If SPDX does not define the license used, this field may be used to provide the license name",
+ "examples": ["Acme Software License"]
+ },
+ "text": {
+ "title": "License text",
+ "description": "An optional way to include the textual content of a license.",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "License URL",
+ "description": "The URL to the license file. If specified, a 'license' externalReference should also be specified for completeness",
+ "examples": ["https://www.apache.org/licenses/LICENSE-2.0.txt"],
+ "format": "iri-reference"
+ }
+ }
+ },
+ "licenseChoice": {
+ "type": "object",
+ "title": "License(s)",
+ "properties": {
+ "license": {
+ "$ref": "#/definitions/license"
+ },
+ "expression": {
+ "type": "string",
+ "title": "SPDX License Expression",
+ "examples": [
+ "Apache-2.0 AND (MIT OR GPL-2.0-only)",
+ "GPL-3.0-only WITH Classpath-exception-2.0"
+ ]
+ }
+ },
+ "oneOf":[
+ {
+ "required": ["license"]
+ },
+ {
+ "required": ["expression"]
+ }
+ ]
+ },
+ "commit": {
+ "type": "object",
+ "title": "Commit",
+ "description": "Specifies an individual commit",
+ "properties": {
+ "uid": {
+ "type": "string",
+ "title": "UID",
+ "description": "A unique identifier of the commit. This may be version control specific. For example, Subversion uses revision numbers whereas git uses commit hashes."
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the commit. This URL will typically point to a commit in a version control system.",
+ "format": "iri-reference"
+ },
+ "author": {
+ "title": "Author",
+ "description": "The author who created the changes in the commit",
+ "$ref": "#/definitions/identifiableAction"
+ },
+ "committer": {
+ "title": "Committer",
+ "description": "The person who committed or pushed the commit",
+ "$ref": "#/definitions/identifiableAction"
+ },
+ "message": {
+ "type": "string",
+ "title": "Message",
+ "description": "The text description of the contents of the commit"
+ }
+ }
+ },
+ "patch": {
+ "type": "object",
+ "title": "Patch",
+ "description": "Specifies an individual patch",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "unofficial",
+ "monkey",
+ "backport",
+ "cherry-pick"
+ ],
+ "title": "Type",
+ "description": "Specifies the purpose for the patch including the resolution of defects, security issues, or new behavior or functionality"
+ },
+ "diff": {
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "$ref": "#/definitions/diff"
+ },
+ "resolves": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/issue"},
+ "title": "Resolves",
+ "description": "A collection of issues the patch resolves"
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "properties": {
+ "text": {
+ "title": "Diff text",
+ "description": "Specifies the optional text of the diff",
+ "$ref": "#/definitions/attachment"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "Specifies the URL to the diff",
+ "format": "iri-reference"
+ }
+ }
+ },
+ "issue": {
+ "type": "object",
+ "title": "Diff",
+ "description": "The patch file (or diff) that show changes. Refer to https://en.wikipedia.org/wiki/Diff",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "defect",
+ "enhancement",
+ "security"
+ ],
+ "title": "Type",
+ "description": "Specifies the type of issue"
+ },
+ "id": {
+ "type": "string",
+ "title": "ID",
+ "description": "The identifier of the issue assigned by the source of the issue"
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the issue"
+ },
+ "description": {
+ "type": "string",
+ "title": "Description",
+ "description": "A description of the issue"
+ },
+ "source": {
+ "type": "object",
+ "title": "Source",
+ "description": "The source of the issue where it is documented",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the source. For example 'National Vulnerability Database', 'NVD', and 'Apache'"
+ },
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The url of the issue documentation as provided by the source",
+ "format": "iri-reference"
+ }
+ }
+ },
+ "references": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "iri-reference"
+ },
+ "title": "References",
+ "description": "A collection of URL's for reference. Multiple URLs are allowed.",
+ "examples": ["https://example.com"]
+ }
+ }
+ },
+ "identifiableAction": {
+ "type": "object",
+ "title": "Identifiable Action",
+ "description": "Specifies an individual commit",
+ "properties": {
+ "timestamp": {
+ "type": "string",
+ "format": "date-time",
+ "title": "Timestamp",
+ "description": "The timestamp in which the action occurred"
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the individual who performed the action"
+ },
+ "email": {
+ "type": "string",
+ "format": "idn-email",
+ "title": "E-mail",
+ "description": "The email address of the individual who performed the action"
+ }
+ }
+ },
+ "externalReference": {
+ "type": "object",
+ "title": "External Reference",
+ "description": "Specifies an individual external reference",
+ "required": [
+ "url",
+ "type"
+ ],
+ "properties": {
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The URL to the external reference",
+ "format": "iri-reference"
+ },
+ "comment": {
+ "type": "string",
+ "title": "Comment",
+ "description": "An optional comment describing the external reference"
+ },
+ "type": {
+ "type": "string",
+ "title": "Type",
+ "description": "Specifies the type of external reference. There are built-in types to describe common references. If a type does not exist for the reference being referred to, use the \"other\" type.",
+ "enum": [
+ "vcs",
+ "issue-tracker",
+ "website",
+ "advisories",
+ "bom",
+ "mailing-list",
+ "social",
+ "chat",
+ "documentation",
+ "support",
+ "distribution",
+ "license",
+ "build-meta",
+ "build-system",
+ "other"
+ ]
+ },
+ "hashes": {
+ "$id": "#/properties/hashes",
+ "type": "array",
+ "items": {"$ref": "#/definitions/hash"},
+ "title": "Hashes",
+ "description": "The hashes of the external reference (if applicable)."
+ }
+ }
+ },
+ "dependency": {
+ "type": "object",
+ "title": "Dependency",
+ "description": "Defines the direct dependencies of a component. Components that do not have their own dependencies MUST be declared as empty elements within the graph. Components that are not represented in the dependency graph MAY have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque and not an indicator of a component being dependency-free.",
+ "required": [
+ "ref"
+ ],
+ "properties": {
+ "ref": {
+ "type": "string",
+ "title": "Reference",
+ "description": "References a component by the components bom-ref attribute"
+ },
+ "dependsOn": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ },
+ "title": "Depends On",
+ "description": "The bom-ref identifiers of the components that are dependencies of this dependency object."
+ }
+ }
+ },
+ "service": {
+ "type": "object",
+ "title": "Service Object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "bom-ref": {
+ "type": "string",
+ "title": "BOM Reference",
+ "description": "An optional identifier which can be used to reference the service elsewhere in the BOM. Every bom-ref should be unique."
+ },
+ "provider": {
+ "title": "Provider",
+ "description": "The organization that provides the service.",
+ "$ref": "#/definitions/organizationalEntity"
+ },
+ "group": {
+ "type": "string",
+ "title": "Service Group",
+ "description": "The grouping name, namespace, or identifier. This will often be a shortened, single name of the company or project that produced the service or domain name. Whitespace and special characters should be avoided.",
+ "examples": ["com.acme"]
+ },
+ "name": {
+ "type": "string",
+ "title": "Service Name",
+ "description": "The name of the service. This will often be a shortened, single name of the service.",
+ "examples": ["ticker-service"]
+ },
+ "version": {
+ "type": "string",
+ "title": "Service Version",
+ "description": "The service version.",
+ "examples": ["1.0.0"]
+ },
+ "description": {
+ "type": "string",
+ "title": "Service Description",
+ "description": "Specifies a description for the service"
+ },
+ "endpoints": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "format": "iri-reference"
+ },
+ "title": "Endpoints",
+ "description": "The endpoint URIs of the service. Multiple endpoints are allowed.",
+ "examples": ["https://example.com/api/v1/ticker"]
+ },
+ "authenticated": {
+ "type": "boolean",
+ "title": "Authentication Required",
+ "description": "A boolean value indicating if the service requires authentication. A value of true indicates the service requires authentication prior to use. A value of false indicates the service does not require authentication."
+ },
+ "x-trust-boundary": {
+ "type": "boolean",
+ "title": "Crosses Trust Boundary",
+ "description": "A boolean value indicating if use of the service crosses a trust zone or boundary. A value of true indicates that by using the service, a trust boundary is crossed. A value of false indicates that by using the service, a trust boundary is not crossed."
+ },
+ "data": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/dataClassification"},
+ "title": "Data Classification",
+ "description": "Specifies the data classification."
+ },
+ "licenses": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/licenseChoice"},
+ "title": "Component License(s)"
+ },
+ "externalReferences": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/externalReference"},
+ "title": "External References"
+ },
+ "services": {
+ "$id": "#/properties/services",
+ "type": "array",
+ "items": {"$ref": "#/definitions/service"},
+ "uniqueItems": true,
+ "title": "Services"
+ },
+ "properties": {
+ "type": "array",
+ "title": "Properties",
+ "description": "Provides the ability to document properties in a name-value store. This provides flexibility to include data not officially supported in the standard without having to use additional namespaces or create extensions. Unlike key-value stores, properties support duplicate names, each potentially having different values.",
+ "items": {"$ref": "#/definitions/property"}
+ }
+ }
+ },
+ "dataClassification": {
+ "type": "object",
+ "title": "Hash Objects",
+ "required": [
+ "flow",
+ "classification"
+ ],
+ "properties": {
+ "flow": {
+ "$ref": "#/definitions/dataFlow"
+ },
+ "classification": {
+ "type": "string"
+ }
+ }
+ },
+ "dataFlow": {
+ "type": "string",
+ "enum": [
+ "inbound",
+ "outbound",
+ "bi-directional",
+ "unknown"
+ ],
+ "title": "Data flow direction"
+ },
+
+ "copyright": {
+ "type": "object",
+ "title": "Copyright",
+ "required": [
+ "text"
+ ],
+ "properties": {
+ "text": {
+ "type": "string",
+ "title": "Copyright Text"
+ }
+ }
+ },
+
+ "componentEvidence": {
+ "type": "object",
+ "title": "Evidence",
+ "description": "Provides the ability to document evidence collected through various forms of extraction or analysis.",
+ "properties": {
+ "licenses": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/licenseChoice"},
+ "title": "Component License(s)"
+ },
+ "copyright": {
+ "type": "array",
+ "items": {"$ref": "#/definitions/copyright"},
+ "title": "Copyright"
+ }
+ }
+ },
+ "compositions": {
+ "type": "object",
+ "title": "Compositions",
+ "required": [
+ "aggregate"
+ ],
+ "properties": {
+ "aggregate": {
+ "$ref": "#/definitions/aggregateType",
+ "title": "Aggregate",
+ "description": "Specifies an aggregate type that describe how complete a relationship is."
+ },
+ "assemblies": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ },
+ "title": "BOM references",
+ "description": "The bom-ref identifiers of the components or services being described. Assemblies refer to nested relationships whereby a constituent part may include other constituent parts. References do not cascade to child parts. References are explicit for the specified constituent part only."
+ },
+ "dependencies": {
+ "type": "array",
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ },
+ "title": "BOM references",
+ "description": "The bom-ref identifiers of the components or services being described. Dependencies refer to a relationship whereby an independent constituent part requires another independent constituent part. References do not cascade to transitive dependencies. References are explicit for the specified dependency only."
+ }
+ }
+ },
+ "aggregateType": {
+ "type": "string",
+ "default": "not_specified",
+ "enum": [
+ "complete",
+ "incomplete",
+ "incomplete_first_party_only",
+ "incomplete_third_party_only",
+ "unknown",
+ "not_specified"
+ ]
+ },
+ "property": {
+ "type": "object",
+ "title": "Lightweight name-value pair",
+ "properties": {
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the property. Duplicate names are allowed, each potentially having a different value."
+ },
+ "value": {
+ "type": "string",
+ "title": "Value",
+ "description": "The value of the property."
+ }
+ }
+ }
+ }
+}
diff --git a/cyclonedx/schema/bom-1.3.xsd b/cyclonedx/schema/bom-1.3.xsd
new file mode 100644
index 00000000..53b37ffa
--- /dev/null
+++ b/cyclonedx/schema/bom-1.3.xsd
@@ -0,0 +1,1631 @@
+
+
+
+
+
+
+
+
+ CycloneDX Software Bill-of-Material Specification
+ https://cyclonedx.org/
+ Apache License, Version 2.0
+
+
+
+
+
+
+
+ The date and time (timestamp) when the document was created.
+
+
+
+
+ The tool(s) used in the creation of the BOM.
+
+
+
+
+
+
+
+
+
+ The person(s) who created the BOM. Authors are common in BOMs created through
+ manual processes. BOMs created through automated means may not have authors.
+
+
+
+
+
+
+
+
+
+ The component that the BOM describes.
+
+
+
+
+ The organization that manufactured the component that the BOM describes.
+
+
+
+
+ The organization that supplied the component that the BOM describes. The
+ supplier may often be the manufacturer, but may also be a distributor or repackager.
+
+
+
+
+
+ Provides the ability to document properties in a key/value store.
+ This provides flexibility to include data not officially supported in the standard
+ without having to use additional namespaces or create extensions.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The name of the organization
+
+
+
+
+ The URL of the organization. Multiple URLs are allowed.
+
+
+
+
+ A contact person at the organization. Multiple contacts are allowed.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Specifies a tool (manual or automated).
+
+
+
+
+ The vendor of the tool used to create the BOM.
+
+
+
+
+ The name of the tool used to create the BOM.
+
+
+
+
+ The version of the tool used to create the BOM.
+
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The name of the contact
+
+
+
+
+ The email address of the contact.
+
+
+
+
+ The phone number of the contact.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The organization that supplied the component. The supplier may often
+ be the manufacturer, but may also be a distributor or repackager.
+
+
+
+
+ The person(s) or organization(s) that authored the component
+
+
+
+
+ The person(s) or organization(s) that published the component
+
+
+
+
+ The grouping name or identifier. This will often be a shortened, single
+ name of the company or project that produced the component, or the source package or
+ domain name. Whitespace and special characters should be avoided. Examples include:
+ apache, org.apache.commons, and apache.org.
+
+
+
+
+ The name of the component. This will often be a shortened, single name
+ of the component. Examples: commons-lang3 and jquery
+
+
+
+
+ The component version. The version should ideally comply with semantic versioning
+ but is not enforced.
+
+
+
+
+ Specifies a description for the component
+
+
+
+
+ Specifies the scope of the component. If scope is not specified, 'runtime'
+ scope should be assumed by the consumer of the BOM
+
+
+
+
+
+
+
+
+
+
+
+
+ An optional copyright notice informing users of the underlying claims to
+ copyright ownership in a published work.
+
+
+
+
+
+ DEPRECATED - DO NOT USE. This will be removed in a future version.
+ Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe
+
+
+
+
+
+
+ Specifies the package-url (PURL). The purl, if specified, must be valid and conform
+ to the specification defined at: https://github.com/package-url/purl-spec
+
+
+
+
+
+
+ Specifies metadata and content for ISO-IEC 19770-2 Software Identification (SWID) Tags.
+
+
+
+
+
+
+ DEPRECATED - DO NOT USE. This will be removed in a future version. Use the pedigree
+ element instead to supply information on exactly how the component was modified.
+ A boolean value indicating is the component has been modified from the original.
+ A value of true indicates the component is a derivative of the original.
+ A value of false indicates the component has not been modified from the original.
+
+
+
+
+
+
+ Component pedigree is a way to document complex supply chain scenarios where components are
+ created, distributed, modified, redistributed, combined with other components, etc.
+
+
+
+
+
+ Provides the ability to document external references related to the
+ component or to the project the component describes.
+
+
+
+
+ Provides the ability to document properties in a key/value store.
+ This provides flexibility to include data not officially supported in the standard
+ without having to use additional namespaces or create extensions.
+
+
+
+
+
+ Specifies optional sub-components. This is not a dependency tree. It provides a way
+ to specify a hierarchical representation of component assemblies, similar to
+ system -> subsystem -> parts assembly in physical supply chains.
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+ Provides the ability to document evidence collected through various forms of extraction or analysis.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+ Specifies the type of component. For software components, classify as application if no more
+ specific appropriate classification is available or cannot be determined for the component.
+
+
+
+
+
+
+ The optional mime-type of the component. When used on file components, the mime-type
+ can provide additional context about the kind of file being represented such as an image,
+ font, or executable. Some library or framework components may also have an associated mime-type.
+
+
+
+
+
+
+ An optional identifier which can be used to reference the component elsewhere in the BOM.
+ Uniqueness is enforced within all elements and children of the root-level bom element.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
+ A valid SPDX license ID
+
+
+
+
+ If SPDX does not define the license used, this field may be used to provide the license name
+
+
+
+
+
+ Specifies the optional full text of the attachment
+
+
+
+
+ The URL to the attachment file. If the attachment is a license or BOM,
+ an externalReference should also be specified for completeness.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ Specifies attributes of the text
+
+
+
+ Specifies the content type of the text. Defaults to text/plain
+ if not specified.
+
+
+
+
+
+ Specifies the optional encoding the text is represented in
+
+
+
+
+
+
+
+
+
+ Specifies the file hash of the component
+
+
+
+
+
+ Specifies the algorithm used to create the hash
+
+
+
+
+
+
+
+
+
+
+ The component is required for runtime
+
+
+
+
+ The component is optional at runtime. Optional components are components that
+ are not capable of being called due to them not be installed or otherwise accessible by any means.
+ Components that are installed but due to configuration or other restrictions are prohibited from
+ being called must be scoped as 'required'.
+
+
+
+
+ Components that are excluded provide the ability to document component usage
+ for test and other non-runtime purposes. Excluded components are not reachable within a call
+ graph at runtime.
+
+
+
+
+
+
+
+
+
+ A software application. Refer to https://en.wikipedia.org/wiki/Application_software
+ for information about applications.
+
+
+
+
+ A software framework. Refer to https://en.wikipedia.org/wiki/Software_framework
+ for information on how frameworks vary slightly from libraries.
+
+
+
+
+ A software library. Refer to https://en.wikipedia.org/wiki/Library_(computing)
+ for information about libraries. All third-party and open source reusable components will likely
+ be a library. If the library also has key features of a framework, then it should be classified
+ as a framework. If not, or is unknown, then specifying library is recommended.
+
+
+
+
+ A packaging and/or runtime format, not specific to any particular technology,
+ which isolates software inside the container from software outside of a container through
+ virtualization technology. Refer to https://en.wikipedia.org/wiki/OS-level_virtualization
+
+
+
+
+ A software operating system without regard to deployment model
+ (i.e. installed on physical hardware, virtual machine, image, etc) Refer to
+ https://en.wikipedia.org/wiki/Operating_system
+
+
+
+
+ A hardware device such as a processor, or chip-set. A hardware device
+ containing firmware should include a component for the physical hardware itself, and another
+ component of type 'firmware' or 'operating-system' (whichever is relevant), describing
+ information about the software running on the device.
+
+
+
+
+ A special type of software that provides low-level control over a devices
+ hardware. Refer to https://en.wikipedia.org/wiki/Firmware
+
+
+
+
+ A computer file. Refer to https://en.wikipedia.org/wiki/Computer_file
+ for information about files.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Define the format for acceptable CPE URIs. Supports CPE 2.2 and CPE 2.3 formats.
+ Refer to https://nvd.nist.gov/products/cpe for official specification.
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the full content of the SWID tag.
+
+
+
+
+ The URL to the SWID file.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ Maps to the tagId of a SoftwareIdentity.
+
+
+
+
+ Maps to the name of a SoftwareIdentity.
+
+
+
+
+ Maps to the version of a SoftwareIdentity.
+
+
+
+
+ Maps to the tagVersion of a SoftwareIdentity.
+
+
+
+
+ Maps to the patch of a SoftwareIdentity.
+
+
+
+
+
+
+
+ Defines a string representation of a UUID conforming to RFC 4122.
+
+
+
+
+
+
+
+
+
+
+
+ Version Control System
+
+
+
+
+ Issue or defect tracking system, or an Application Lifecycle Management (ALM) system
+
+
+
+
+ Website
+
+
+
+
+ Security advisories
+
+
+
+
+ Bill-of-material document (CycloneDX, SPDX, SWID, etc)
+
+
+
+
+ Mailing list or discussion group
+
+
+
+
+ Social media account
+
+
+
+
+ Real-time chat platform
+
+
+
+
+ Documentation, guides, or how-to instructions
+
+
+
+
+ Community or commercial support
+
+
+
+
+ Direct or repository download location
+
+
+
+
+ The URL to the license file. If a license URL has been defined in the license
+ node, it should also be defined as an external reference for completeness
+
+
+
+
+ Build-system specific meta file (i.e. pom.xml, package.json, .nuspec, etc)
+
+
+
+
+ URL to an automated build system
+
+
+
+
+ Use this if no other types accurately describe the purpose of the external reference
+
+
+
+
+
+
+
+
+ External references provide a way to document systems, sites, and information that may be relevant
+ but which are not included with the BOM.
+
+
+
+
+
+ Zero or more external references can be defined
+
+
+
+
+
+
+
+
+
+ The URL to the external reference
+
+
+
+
+ An optional comment describing the external reference
+
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the type of external reference. There are built-in types to describe common
+ references. If a type does not exist for the reference being referred to, use the "other" type.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Zero or more commits can be specified.
+
+
+
+
+ Specifies an individual commit.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ A unique identifier of the commit. This may be version control
+ specific. For example, Subversion uses revision numbers whereas git uses commit hashes.
+
+
+
+
+
+ The URL to the commit. This URL will typically point to a commit
+ in a version control system.
+
+
+
+
+
+ The author who created the changes in the commit
+
+
+
+
+ The person who committed or pushed the commit
+
+
+
+
+ The text description of the contents of the commit
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+ Zero or more patches can be specified.
+
+
+
+
+ Specifies an individual patch.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ The patch file (or diff) that show changes.
+ Refer to https://en.wikipedia.org/wiki/Diff
+
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ Specifies the purpose for the patch including the resolution of defects,
+ security issues, or new behavior or functionality
+
+
+
+
+
+
+
+
+ A patch which is not developed by the creators or maintainers of the software
+ being patched. Refer to https://en.wikipedia.org/wiki/Unofficial_patch
+
+
+
+
+ A patch which dynamically modifies runtime behavior.
+ Refer to https://en.wikipedia.org/wiki/Monkey_patch
+
+
+
+
+ A patch which takes code from a newer version of software and applies
+ it to older versions of the same software. Refer to https://en.wikipedia.org/wiki/Backporting
+
+
+
+
+ A patch created by selectively applying commits from other versions or
+ branches of the same software.
+
+
+
+
+
+
+
+
+
+ A fault, flaw, or bug in software
+
+
+
+
+ A new feature or behavior in software
+
+
+
+
+ A special type of defect which impacts security
+
+
+
+
+
+
+
+
+
+ Specifies the optional text of the diff
+
+
+
+
+ Specifies the URL to the diff
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+ The identifier of the issue assigned by the source of the issue
+
+
+
+
+ The name of the issue
+
+
+
+
+ A description of the issue
+
+
+
+
+
+
+ The source of the issue where it is documented.
+
+
+
+
+
+
+ The name of the source. For example "National Vulnerability Database",
+ "NVD", and "Apache"
+
+
+
+
+
+
+ The url of the issue documentation as provided by the source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ Specifies the type of issue
+
+
+
+
+
+
+
+
+ The timestamp in which the action occurred
+
+
+
+
+ The name of the individual who performed the action
+
+
+
+
+ The email address of the individual who performed the action
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+ Component pedigree is a way to document complex supply chain scenarios where components are created,
+ distributed, modified, redistributed, combined with other components, etc. Pedigree supports viewing
+ this complex chain from the beginning, the end, or anywhere in the middle. It also provides a way to
+ document variants where the exact relation may not be known.
+
+
+
+
+
+ Describes zero or more components in which a component is derived
+ from. This is commonly used to describe forks from existing projects where the forked version
+ contains a ancestor node containing the original component it was forked from. For example,
+ Component A is the original component. Component B is the component being used and documented
+ in the BOM. However, Component B contains a pedigree node with a single ancestor documenting
+ Component A - the original component from which Component B is derived from.
+
+
+
+
+
+ Descendants are the exact opposite of ancestors. This provides a
+ way to document all forks (and their forks) of an original or root component.
+
+
+
+
+
+ Variants describe relations where the relationship between the
+ components are not known. For example, if Component A contains nearly identical code to
+ Component B. They are both related, but it is unclear if one is derived from the other,
+ or if they share a common ancestor.
+
+
+
+
+
+ A list of zero or more commits which provide a trail describing
+ how the component deviates from an ancestor, descendant, or variant.
+
+
+
+
+ A list of zero or more patches describing how the component
+ deviates from an ancestor, descendant, or variant. Patches may be complimentary to commits
+ or may be used in place of commits.
+
+
+
+
+ Notes, observations, and other non-structured commentary
+ describing the components pedigree.
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+
+
+ References a component or service by the its bom-ref attribute
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ Components that do not have their own dependencies MUST be declared as empty
+ elements within the graph. Components that are not represented in the dependency graph MAY
+ have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque
+ and not an indicator of a component being dependency-free.
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The organization that provides the service.
+
+
+
+
+ The grouping name, namespace, or identifier. This will often be a shortened,
+ single name of the company or project that produced the service or domain name.
+ Whitespace and special characters should be avoided.
+
+
+
+
+ The name of the service. This will often be a shortened, single name
+ of the service.
+
+
+
+
+ The service version.
+
+
+
+
+ Specifies a description for the service.
+
+
+
+
+
+
+
+ A service endpoint URI.
+
+
+
+
+
+
+
+ A boolean value indicating if the service requires authentication.
+ A value of true indicates the service requires authentication prior to use.
+ A value of false indicates the service does not require authentication.
+
+
+
+
+ A boolean value indicating if use of the service crosses a trust zone or boundary.
+ A value of true indicates that by using the service, a trust boundary is crossed.
+ A value of false indicates that by using the service, a trust boundary is not crossed.
+
+
+
+
+
+
+
+ Specifies the data classification.
+
+
+
+
+
+
+
+
+ Provides the ability to document external references related to the service.
+
+
+
+
+ Provides the ability to document properties in a key/value store.
+ This provides flexibility to include data not officially supported in the standard
+ without having to use additional namespaces or create extensions.
+
+
+
+
+
+ Specifies optional sub-service. This is not a dependency tree. It provides a way
+ to specify a hierarchical representation of service assemblies, similar to
+ system -> subsystem -> parts assembly in physical supply chains.
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+ An optional identifier which can be used to reference the service elsewhere in the BOM.
+ Uniqueness is enforced within all elements and children of the root-level bom element.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Specifies the data classification.
+
+
+
+
+
+ Specifies the flow direction of the data.
+
+
+
+
+
+
+
+
+ Specifies the flow direction of the data. Valid values are:
+ inbound, outbound, bi-directional, and unknown. Direction is relative to the service.
+ Inbound flow states that data enters the service. Outbound flow states that data
+ leaves the service. Bi-directional states that data flows both ways, and unknown
+ states that the direction is not known.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A valid SPDX license expression.
+ Refer to https://spdx.org/specifications for syntax requirements
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ Specifies an aggregate type that describe how complete a relationship is.
+
+
+
+
+
+ The bom-ref identifiers of the components or services being described. Assemblies refer to
+ nested relationships whereby a constituent part may include other constituent parts. References
+ do not cascade to child parts. References are explicit for the specified constituent part only.
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+ The bom-ref identifiers of the components or services being described. Dependencies refer to a
+ relationship whereby an independent constituent part requires another independent constituent
+ part. References do not cascade to transitive dependencies. References are explicit for the
+ specified dependency only.
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The relationship is complete. No further relationships including constituent components, services, or dependencies exist.
+
+
+
+
+ The relationship is incomplete. Additional relationships exist and may include constituent components, services, or dependencies.
+
+
+
+
+ The relationship is incomplete. Only relationships for first-party components, services, or their dependencies are represented.
+
+
+
+
+ The relationship is incomplete. Only relationships for third-party components, services, or their dependencies are represented.
+
+
+
+
+ The relationship may be complete or incomplete. This usually signifies a 'best-effort' to obtain constituent components, services, or dependencies but the completeness is inconclusive.
+
+
+
+
+ The relationship completeness is not specified.
+
+
+
+
+
+
+
+
+ References a component or service by the its bom-ref attribute
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Specifies an individual property with a name and value.
+
+
+
+
+
+ The name of the property. Duplicate names are allowed, each potentially having a different value.
+
+
+
+
+
+
+
+
+
+
+
+ Provides additional information about a BOM.
+
+
+
+
+ Provides the ability to document a list of components.
+
+
+
+
+ Provides the ability to document a list of external services.
+
+
+
+
+ Provides the ability to document external references related to the BOM or
+ to the project the BOM describes.
+
+
+
+
+ Provides the ability to document dependency relationships.
+
+
+
+
+ Compositions describe constituent parts (including components, services, and dependency relationships) and their completeness.
+
+
+
+
+ Provides the ability to document properties in a name-value store.
+ This provides flexibility to include data not officially supported in the standard
+ without having to use additional namespaces or create extensions. Unlike key-value
+ stores, properties support duplicate names, each potentially having different values.
+
+
+
+
+
+ Allows any undeclared elements as long as the elements are placed in a different namespace.
+
+
+
+
+
+
+ The version allows component publishers/authors to make changes to existing
+ BOMs to update various aspects of the document such as description or licenses. When a system
+ is presented with multiple BOMs for the same component, the system should use the most recent
+ version of the BOM. The default version is '1' and should be incremented for each version of the
+ BOM that is published. Each version of a component should have a unique BOM and if no changes are
+ made to the BOMs, then each BOM will have a version of '1'.
+
+
+
+
+ Every BOM generated should have a unique serial number, even if the contents
+ of the BOM being generated have not changed over time. The process or tool responsible for
+ creating the BOM should create random UUID's for every BOM generated.
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
diff --git a/cyclonedx/schema/ext/bom-descriptor-0.9.xsd b/cyclonedx/schema/ext/bom-descriptor-0.9.xsd
new file mode 100644
index 00000000..605df12f
--- /dev/null
+++ b/cyclonedx/schema/ext/bom-descriptor-0.9.xsd
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+ CycloneDX BOM Descriptor Extension
+ https://cyclonedx.org/ext/bom-descriptor
+ Apache License, Version 2.0
+
+ Steve Springett
+
+
+
+
+
+
+
+
+ Specifies the name of the software the BOM describes.
+
+
+
+
+ Specifies the version of the software the BOM describes.
+
+
+
+
+ Specifies the edition of the software the BOM describes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A valid SPDX license expression.
+ Refer to https://spdx.org/specifications for syntax requirements
+
+
+
+
+
+
+
+ An optional copyright notice informing users of the underlying claims to
+ copyright ownership in a published work.
+
+
+
+
+
+ Specifies a well-formed CPE name. See https://nvd.nist.gov/products/cpe
+
+
+
+
+
+
+ Specifies the package-url (PURL). The purl, if specified, must be valid and conform
+ to the specification defined at: https://github.com/package-url/purl-spec
+
+
+
+
+
+ The organization that manufactured the software for which the BOM describes.
+
+
+
+
+ The organization that supplied the software for which the BOM describes. The
+ supplier may often be the manufacture, but may also be a distributor or repackager.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The name of the organization
+
+
+
+
+ The URL of the organization. Multiple URLs are allowed.
+
+
+
+
+ A contact person at the organization. Multiple contacts are allowed.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The name of the person
+
+
+
+
+ The email address of the person. Multiple email addresses are allowed.
+
+
+
+
+ The phone number of the person. Multiple phone numbers are allowed.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Provides additional information about a BOM.
+
+
+
+
diff --git a/cyclonedx/schema/ext/bom-descriptor-1.0.xsd b/cyclonedx/schema/ext/bom-descriptor-1.0.xsd
new file mode 100644
index 00000000..013f550e
--- /dev/null
+++ b/cyclonedx/schema/ext/bom-descriptor-1.0.xsd
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+ CycloneDX BOM Descriptor Extension
+ https://cyclonedx.org/ext/bom-descriptor
+ Apache License, Version 2.0
+
+ Steve Springett
+
+
+
+
+
+
+
+
+
+
+ The date and time (timestamp) when the document was created.
+
+
+
+
+ The tool used to create the BOM.
+
+
+
+
+ The person(s) who created the BOM. Authors are common in BOMs created through
+ manual processes. BOMs created through automated means may not have authors.
+
+
+
+
+
+
+
+
+
+ The component that the BOM describes.
+
+
+
+
+ The organization that manufactured the component that the BOM describes.
+
+
+
+
+ The organization that supplied the component that the BOM describes. The
+ supplier may often be the manufacture, but may also be a distributor or repackager.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The name of the organization
+
+
+
+
+ The URL of the organization. Multiple URLs are allowed.
+
+
+
+
+ A contact person at the organization. Multiple contacts are allowed.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Specifies a tool (manual or automated).
+
+
+
+
+ The vendor of the tool used to create the BOM.
+
+
+
+
+ The name of the tool used to create the BOM.
+
+
+
+
+ The version of the tool used to create the BOM.
+
+
+
+
+
+
+
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+ The name of the person
+
+
+
+
+ The email address of the person. Multiple email addresses are allowed.
+
+
+
+
+ The phone number of the person. Multiple phone numbers are allowed.
+
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+ Provides additional information about a BOM.
+
+
+
+
diff --git a/cyclonedx/schema/ext/dependency-graph-1.0.xsd b/cyclonedx/schema/ext/dependency-graph-1.0.xsd
new file mode 100644
index 00000000..ddcb5365
--- /dev/null
+++ b/cyclonedx/schema/ext/dependency-graph-1.0.xsd
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+ CycloneDX Dependency Graph Extension
+ https://cyclonedx.org/ext/dependency-graph
+ Apache License, Version 2.0
+
+ Steve Springett
+
+
+
+
+
+
+
+
+
+
+ References a component by the components bom-ref attribute
+
+
+
+
+ User-defined attributes may be used on this element as long as they
+ do not have the same name as an existing attribute used by the schema.
+
+
+
+
+
+
+
+
+
+ Components that do not have their own dependencies MUST be declared as empty
+ elements within the graph. Components that are not represented in the dependency graph MAY
+ have unknown dependencies. It is RECOMMENDED that implementations assume this to be opaque
+ and not an indicator of a component being dependency-free.
+
+
+
+
+
+
+
diff --git a/cyclonedx/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json b/cyclonedx/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json
new file mode 100644
index 00000000..378bd498
--- /dev/null
+++ b/cyclonedx/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json
@@ -0,0 +1,182 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "http://cyclonedx.org/schema/ext/vulnerability-1.0-SNAPSHOT.schema.json",
+ "type": "object",
+ "title": "CycloneDX Vulnerability Extension",
+ "$comment" : "CycloneDX Vulnerability Extension for JSON Schema is published under the terms of the Apache License 2.0.",
+ "properties": {
+ "vulnerabilities": {
+ "$id": "#/properties/vulnerabilities",
+ "type": "array",
+ "items": {"$ref": "#/definitions/vulnerability"},
+ "title": "Vulnerabilities",
+ "description": "Defines a list of vulnerabilities."
+ }
+ },
+ "definitions": {
+ "cwe": {
+ "type": "integer",
+ "minimum": 1,
+ "title": "CWE",
+ "description": "Integer representation of a Common Weaknesses Enumerations (CWE). For example 399 (of https://cwe.mitre.org/data/definitions/399.html)"
+ },
+ "severity": {
+ "type": "string",
+ "title": "Severity",
+ "description": "Textual representation of the severity of the vulnerability adopted by the risk analysis method. If an other risk analysis method is used other than whats defined in scoreSourceType, the user is expected to translate appropriately to match with an element value below.",
+ "enum": [
+ "None",
+ "Low",
+ "Medium",
+ "High",
+ "Critical",
+ "Unknown"
+ ]
+ },
+ "scoreValue": {
+ "type": "number",
+ "title": "Score",
+ "description": "Numerical representation of the vulnerability score. Must be a number between 0 - 10 (maps to lowest severity - highest severity)",
+ "multipleOf": 0.1,
+ "examples": [7.9, 10.0]
+ },
+ "scoreSource": {
+ "type": "string",
+ "title": "Source",
+ "description": "Specifies the risk scoring methodology/standard used.",
+ "enum": [
+ "CVSSv2",
+ "CVSSv3",
+ "OWASP Risk",
+ "Open FAIR",
+ "Other"
+ ]
+ },
+ "score": {
+ "type": "object",
+ "title": "Score",
+ "description": "Defines the numerical risk score of a vulnerability",
+ "properties": {
+ "base": {
+ "type": "number",
+ "title": "Base Score",
+ "description": "The base score of the security vulnerability (Refer CVSS standard for example)",
+ "multipleOf": 0.1,
+ "examples": [2.9, 7.2]
+ },
+ "impact": {
+ "type": "number",
+ "title": "Impact Score",
+ "description": "The impact subscore of the security vulnerability (Refer CVSS standard for example)",
+ "multipleOf": 0.1,
+ "examples": [2.9, 7.2]
+ },
+ "exploitability": {
+ "type": "number",
+ "title": "Exploitability Score",
+ "description": "The exploitability subscore of the security vulnerability (Refer CVSS standard for example)",
+ "multipleOf": 0.1,
+ "examples": [2.9, 7.2]
+ }
+ }
+ },
+ "rating": {
+ "type": "object",
+ "title": "Rating",
+ "description": "Defines the risk rating of a vulnerability.",
+ "properties": {
+ "score": {
+ "$ref": "#/definitions/score"
+ },
+ "severity": {
+ "$ref": "#/definitions/severity"
+ },
+ "method": {
+ "$ref": "#/definitions/scoreSource"
+ },
+ "vector": {
+ "type": "string",
+ "title": "Vector",
+ "description": "Textual representation of the metric values used to score the vulnerability see attack vector in https://www.first.org/cvss/v3.1/specification-document"
+ }
+ }
+ },
+ "source": {
+ "type": "object",
+ "title": "Source",
+ "description": "The source of the vulnerability where it is documented. Usually the name of the organization publishing vulnerability information",
+ "properties": {
+ "url": {
+ "type": "string",
+ "title": "URL",
+ "description": "The url of the vulnerability documentation as provided by the source.",
+ "examples": [
+ "https://nvd.nist.gov/vuln/detail/CVE-2019-15842"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "title": "Name",
+ "description": "The name of the source.",
+ "examples": [
+ "NVD", "National Vulnerability Database", "OSS Index", "VulnDB", "NPM Advisories"
+ ]
+ }
+ }
+ },
+ "vulnerability": {
+ "type": "object",
+ "title": "Vulnerability",
+ "description": "Defines the structure of a vulnerability.",
+ "properties": {
+ "ref": {
+ "type": "string",
+ "format": "string",
+ "title": "Reference",
+ "description": "References a component by the components bom-ref attribute"
+ },
+ "id": {
+ "type": "string",
+ "title": "ID",
+ "description": "The id of the vulnerability as defined by the risk scoring methodology. For example CVE-2019-15842 (of https://nvd.nist.gov/vuln/detail/CVE-2019-15842)"
+ },
+ "source": {
+ "$ref": "#/definitions/source"
+ },
+ "ratings": {
+ "type": "array",
+ "title": "Ratings",
+ "description": "List of the vulnerability ratings as defined by various risk rating methodologies.",
+ "items": {"$ref": "#/definitions/rating"}
+ },
+ "cwes": {
+ "type": "array",
+ "title": "CWEs",
+ "description": "List of Common Weaknesses Enumerations (CWEs) codes that describes this vulnerability. For example 399 (of https://cwe.mitre.org/data/definitions/399.html)",
+ "items": {"$ref": "#/definitions/cwe"}
+ },
+ "description": {
+ "type": "string",
+ "title": "Description",
+ "description": "Description of the vulnerability as provided by the source organization"
+ },
+ "recommendations": {
+ "type": "array",
+ "title": "Recommendations",
+ "description": "List of recommendations of how the particular vulnerability can be avoided/mitigated.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "advisories": {
+ "type": "array",
+ "title": "Advisories",
+ "description": "Published advisories of the vulnerability if provided.",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/cyclonedx/schema/ext/vulnerability-1.0.xsd b/cyclonedx/schema/ext/vulnerability-1.0.xsd
new file mode 100644
index 00000000..2d684745
--- /dev/null
+++ b/cyclonedx/schema/ext/vulnerability-1.0.xsd
@@ -0,0 +1,291 @@
+
+
+
+
+
+
+ CycloneDX Vulnerability Extension
+ https://cyclonedx.org/ext/vulnerability
+ Apache License, Version 2.0
+
+
+
+
+
+
+ Textual representation of the severity of the vulnerability adopted by the risk analysis method.
+ If an other risk analysis method is used other than whats defined in scoreSourceType,
+ the user is expected to translate appropriately to match with an element value below.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Numerical representation of the vulnerability score.
+ Must be a number between 0 - 10 (maps to lowest severity - highest severity)
+
+
+
+
+
+
+
+
+
+
+
+
+ Specifies the risk scoring methodology/standard used.
+
+
+
+
+
+
+ The rating is based on CVSS v2 standard
+ https://www.first.org/cvss/v2/guide
+
+
+
+
+
+
+ The rating is based on CVSS v3 standard
+ https://www.first.org/cvss/v3.1/specification-document
+
+
+
+
+
+
+ The rating is based on OWASP Risk Rating
+ https://www.owasp.org/index.php/OWASP_Risk_Rating_Methodology
+
+
+
+
+
+
+ The rating is based on Open FAIR specification
+ http://www.opengroup.org/subjectareas/security/risk
+
+
+
+
+
+
+ Use this if the risk scoring methodology is not based on any of the options above
+
+
+
+
+
+
+
+
+
+ Defines the numerical risk score of a vulnerability
+
+
+
+
+
+
+
+
+
+ The base score of the security vulnerability (Refer CVSS standard for example)
+
+
+
+
+
+
+ The impact subscore of the security vulnerability (Refer CVSS standard for example)
+
+
+
+
+
+
+ The exploitability subscore of the security vulnerability (Refer CVSS standard for
+ example)
+
+
+
+
+
+
+
+
+
+
+
+ Textual representation of the metric values used to score the vulnerability
+ see attack vector in https://www.first.org/cvss/v3.1/specification-document
+
+
+
+
+
+
+
+
+
+ Defines the structure of a vulnerability.
+
+
+
+
+
+
+ The id of the vulnerability as defined by the risk scoring methodology
+ For example CVE-2019-15842 (of https://nvd.nist.gov/vuln/detail/CVE-2019-15842)
+
+
+
+
+
+
+
+ The source of the vulnerability where it is documented.
+ Usually the name of the organization publishing vulnerability information
+
+
+
+
+
+
+ The url of the vulnerability documentation as provided by the source
+ For example https://nvd.nist.gov/vuln/detail/CVE-2019-15842
+
+
+
+
+
+
+
+ The name of the source. For example "National Vulnerability Database"
+
+
+
+
+
+
+
+
+ List of the vulnerability ratings as defined by various risk rating methodologies.
+
+
+
+
+
+
+
+
+
+
+
+
+ List of Common Weaknesses Enumerations (CWEs) codes that describes this vulnerability.
+ For example 399 (of https://cwe.mitre.org/data/definitions/399.html)
+
+
+
+
+
+
+
+
+
+
+ Description of the vulnerability as provided by the source organization
+
+
+
+
+
+
+
+ The remediation options for the vulnerability if available
+
+
+
+
+
+
+ A recommendation of how the particular vulnerability can be avoided/mitigated.
+
+
+
+
+
+
+
+
+
+
+ Published advisories of the vulnerability if provided
+
+
+
+
+
+
+
+
+
+
+ References a component by the components bom-ref attribute
+
+
+
+
+
+
+
+ Defines a list of vulnerabilities.
+ Vulnerabilities are intended to be used inside the BOM component element.
+ Extending a component ability to declare associated vulnerability information.
+ Each component element optionally can add a vulnerabilities element.
+
+
+
+
+
+
+
+
+
diff --git a/cyclonedx/schema/spdx.schema.json b/cyclonedx/schema/spdx.schema.json
new file mode 100644
index 00000000..049708a4
--- /dev/null
+++ b/cyclonedx/schema/spdx.schema.json
@@ -0,0 +1,491 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "http://cyclonedx.org/schema/spdx.schema.json",
+ "$comment": "v1.0-3.10",
+ "type": "string",
+ "enum": [
+ "0BSD",
+ "AAL",
+ "ADSL",
+ "AFL-1.1",
+ "AFL-1.2",
+ "AFL-2.0",
+ "AFL-2.1",
+ "AFL-3.0",
+ "AGPL-1.0",
+ "AGPL-1.0-only",
+ "AGPL-1.0-or-later",
+ "AGPL-3.0",
+ "AGPL-3.0-only",
+ "AGPL-3.0-or-later",
+ "AMDPLPA",
+ "AML",
+ "AMPAS",
+ "ANTLR-PD",
+ "APAFML",
+ "APL-1.0",
+ "APSL-1.0",
+ "APSL-1.1",
+ "APSL-1.2",
+ "APSL-2.0",
+ "Abstyles",
+ "Adobe-2006",
+ "Adobe-Glyph",
+ "Afmparse",
+ "Aladdin",
+ "Apache-1.0",
+ "Apache-1.1",
+ "Apache-2.0",
+ "Artistic-1.0",
+ "Artistic-1.0-Perl",
+ "Artistic-1.0-cl8",
+ "Artistic-2.0",
+ "BSD-1-Clause",
+ "BSD-2-Clause",
+ "BSD-2-Clause-FreeBSD",
+ "BSD-2-Clause-NetBSD",
+ "BSD-2-Clause-Patent",
+ "BSD-2-Clause-Views",
+ "BSD-3-Clause",
+ "BSD-3-Clause-Attribution",
+ "BSD-3-Clause-Clear",
+ "BSD-3-Clause-LBNL",
+ "BSD-3-Clause-No-Nuclear-License",
+ "BSD-3-Clause-No-Nuclear-License-2014",
+ "BSD-3-Clause-No-Nuclear-Warranty",
+ "BSD-3-Clause-Open-MPI",
+ "BSD-4-Clause",
+ "BSD-4-Clause-UC",
+ "BSD-Protection",
+ "BSD-Source-Code",
+ "BSL-1.0",
+ "Bahyph",
+ "Barr",
+ "Beerware",
+ "BitTorrent-1.0",
+ "BitTorrent-1.1",
+ "BlueOak-1.0.0",
+ "Borceux",
+ "CAL-1.0",
+ "CAL-1.0-Combined-Work-Exception",
+ "CATOSL-1.1",
+ "CC-BY-1.0",
+ "CC-BY-2.0",
+ "CC-BY-2.5",
+ "CC-BY-3.0",
+ "CC-BY-3.0-AT",
+ "CC-BY-4.0",
+ "CC-BY-NC-1.0",
+ "CC-BY-NC-2.0",
+ "CC-BY-NC-2.5",
+ "CC-BY-NC-3.0",
+ "CC-BY-NC-4.0",
+ "CC-BY-NC-ND-1.0",
+ "CC-BY-NC-ND-2.0",
+ "CC-BY-NC-ND-2.5",
+ "CC-BY-NC-ND-3.0",
+ "CC-BY-NC-ND-3.0-IGO",
+ "CC-BY-NC-ND-4.0",
+ "CC-BY-NC-SA-1.0",
+ "CC-BY-NC-SA-2.0",
+ "CC-BY-NC-SA-2.5",
+ "CC-BY-NC-SA-3.0",
+ "CC-BY-NC-SA-4.0",
+ "CC-BY-ND-1.0",
+ "CC-BY-ND-2.0",
+ "CC-BY-ND-2.5",
+ "CC-BY-ND-3.0",
+ "CC-BY-ND-4.0",
+ "CC-BY-SA-1.0",
+ "CC-BY-SA-2.0",
+ "CC-BY-SA-2.5",
+ "CC-BY-SA-3.0",
+ "CC-BY-SA-3.0-AT",
+ "CC-BY-SA-4.0",
+ "CC-PDDC",
+ "CC0-1.0",
+ "CDDL-1.0",
+ "CDDL-1.1",
+ "CDLA-Permissive-1.0",
+ "CDLA-Sharing-1.0",
+ "CECILL-1.0",
+ "CECILL-1.1",
+ "CECILL-2.0",
+ "CECILL-2.1",
+ "CECILL-B",
+ "CECILL-C",
+ "CERN-OHL-1.1",
+ "CERN-OHL-1.2",
+ "CERN-OHL-P-2.0",
+ "CERN-OHL-S-2.0",
+ "CERN-OHL-W-2.0",
+ "CNRI-Jython",
+ "CNRI-Python",
+ "CNRI-Python-GPL-Compatible",
+ "CPAL-1.0",
+ "CPL-1.0",
+ "CPOL-1.02",
+ "CUA-OPL-1.0",
+ "Caldera",
+ "ClArtistic",
+ "Condor-1.1",
+ "Crossword",
+ "CrystalStacker",
+ "Cube",
+ "D-FSL-1.0",
+ "DOC",
+ "DSDP",
+ "Dotseqn",
+ "ECL-1.0",
+ "ECL-2.0",
+ "EFL-1.0",
+ "EFL-2.0",
+ "EPICS",
+ "EPL-1.0",
+ "EPL-2.0",
+ "EUDatagrid",
+ "EUPL-1.0",
+ "EUPL-1.1",
+ "EUPL-1.2",
+ "Entessa",
+ "ErlPL-1.1",
+ "Eurosym",
+ "FSFAP",
+ "FSFUL",
+ "FSFULLR",
+ "FTL",
+ "Fair",
+ "Frameworx-1.0",
+ "FreeImage",
+ "GFDL-1.1",
+ "GFDL-1.1-invariants-only",
+ "GFDL-1.1-invariants-or-later",
+ "GFDL-1.1-no-invariants-only",
+ "GFDL-1.1-no-invariants-or-later",
+ "GFDL-1.1-only",
+ "GFDL-1.1-or-later",
+ "GFDL-1.2",
+ "GFDL-1.2-invariants-only",
+ "GFDL-1.2-invariants-or-later",
+ "GFDL-1.2-no-invariants-only",
+ "GFDL-1.2-no-invariants-or-later",
+ "GFDL-1.2-only",
+ "GFDL-1.2-or-later",
+ "GFDL-1.3",
+ "GFDL-1.3-invariants-only",
+ "GFDL-1.3-invariants-or-later",
+ "GFDL-1.3-no-invariants-only",
+ "GFDL-1.3-no-invariants-or-later",
+ "GFDL-1.3-only",
+ "GFDL-1.3-or-later",
+ "GL2PS",
+ "GLWTPL",
+ "GPL-1.0",
+ "GPL-1.0+",
+ "GPL-1.0-only",
+ "GPL-1.0-or-later",
+ "GPL-2.0",
+ "GPL-2.0+",
+ "GPL-2.0-only",
+ "GPL-2.0-or-later",
+ "GPL-2.0-with-GCC-exception",
+ "GPL-2.0-with-autoconf-exception",
+ "GPL-2.0-with-bison-exception",
+ "GPL-2.0-with-classpath-exception",
+ "GPL-2.0-with-font-exception",
+ "GPL-3.0",
+ "GPL-3.0+",
+ "GPL-3.0-only",
+ "GPL-3.0-or-later",
+ "GPL-3.0-with-GCC-exception",
+ "GPL-3.0-with-autoconf-exception",
+ "Giftware",
+ "Glide",
+ "Glulxe",
+ "HPND",
+ "HPND-sell-variant",
+ "HaskellReport",
+ "Hippocratic-2.1",
+ "IBM-pibs",
+ "ICU",
+ "IJG",
+ "IPA",
+ "IPL-1.0",
+ "ISC",
+ "ImageMagick",
+ "Imlib2",
+ "Info-ZIP",
+ "Intel",
+ "Intel-ACPI",
+ "Interbase-1.0",
+ "JPNIC",
+ "JSON",
+ "JasPer-2.0",
+ "LAL-1.2",
+ "LAL-1.3",
+ "LGPL-2.0",
+ "LGPL-2.0+",
+ "LGPL-2.0-only",
+ "LGPL-2.0-or-later",
+ "LGPL-2.1",
+ "LGPL-2.1+",
+ "LGPL-2.1-only",
+ "LGPL-2.1-or-later",
+ "LGPL-3.0",
+ "LGPL-3.0+",
+ "LGPL-3.0-only",
+ "LGPL-3.0-or-later",
+ "LGPLLR",
+ "LPL-1.0",
+ "LPL-1.02",
+ "LPPL-1.0",
+ "LPPL-1.1",
+ "LPPL-1.2",
+ "LPPL-1.3a",
+ "LPPL-1.3c",
+ "Latex2e",
+ "Leptonica",
+ "LiLiQ-P-1.1",
+ "LiLiQ-R-1.1",
+ "LiLiQ-Rplus-1.1",
+ "Libpng",
+ "Linux-OpenIB",
+ "MIT",
+ "MIT-0",
+ "MIT-CMU",
+ "MIT-advertising",
+ "MIT-enna",
+ "MIT-feh",
+ "MITNFA",
+ "MPL-1.0",
+ "MPL-1.1",
+ "MPL-2.0",
+ "MPL-2.0-no-copyleft-exception",
+ "MS-PL",
+ "MS-RL",
+ "MTLL",
+ "MakeIndex",
+ "MirOS",
+ "Motosoto",
+ "MulanPSL-1.0",
+ "MulanPSL-2.0",
+ "Multics",
+ "Mup",
+ "NASA-1.3",
+ "NBPL-1.0",
+ "NCGL-UK-2.0",
+ "NCSA",
+ "NGPL",
+ "NIST-PD",
+ "NIST-PD-fallback",
+ "NLOD-1.0",
+ "NLPL",
+ "NOSL",
+ "NPL-1.0",
+ "NPL-1.1",
+ "NPOSL-3.0",
+ "NRL",
+ "NTP",
+ "NTP-0",
+ "Naumen",
+ "Net-SNMP",
+ "NetCDF",
+ "Newsletr",
+ "Nokia",
+ "Noweb",
+ "Nunit",
+ "O-UDA-1.0",
+ "OCCT-PL",
+ "OCLC-2.0",
+ "ODC-By-1.0",
+ "ODbL-1.0",
+ "OFL-1.0",
+ "OFL-1.0-RFN",
+ "OFL-1.0-no-RFN",
+ "OFL-1.1",
+ "OFL-1.1-RFN",
+ "OFL-1.1-no-RFN",
+ "OGC-1.0",
+ "OGL-Canada-2.0",
+ "OGL-UK-1.0",
+ "OGL-UK-2.0",
+ "OGL-UK-3.0",
+ "OGTSL",
+ "OLDAP-1.1",
+ "OLDAP-1.2",
+ "OLDAP-1.3",
+ "OLDAP-1.4",
+ "OLDAP-2.0",
+ "OLDAP-2.0.1",
+ "OLDAP-2.1",
+ "OLDAP-2.2",
+ "OLDAP-2.2.1",
+ "OLDAP-2.2.2",
+ "OLDAP-2.3",
+ "OLDAP-2.4",
+ "OLDAP-2.5",
+ "OLDAP-2.6",
+ "OLDAP-2.7",
+ "OLDAP-2.8",
+ "OML",
+ "OPL-1.0",
+ "OSET-PL-2.1",
+ "OSL-1.0",
+ "OSL-1.1",
+ "OSL-2.0",
+ "OSL-2.1",
+ "OSL-3.0",
+ "OpenSSL",
+ "PDDL-1.0",
+ "PHP-3.0",
+ "PHP-3.01",
+ "PSF-2.0",
+ "Parity-6.0.0",
+ "Parity-7.0.0",
+ "Plexus",
+ "PolyForm-Noncommercial-1.0.0",
+ "PolyForm-Small-Business-1.0.0",
+ "PostgreSQL",
+ "Python-2.0",
+ "QPL-1.0",
+ "Qhull",
+ "RHeCos-1.1",
+ "RPL-1.1",
+ "RPL-1.5",
+ "RPSL-1.0",
+ "RSA-MD",
+ "RSCPL",
+ "Rdisc",
+ "Ruby",
+ "SAX-PD",
+ "SCEA",
+ "SGI-B-1.0",
+ "SGI-B-1.1",
+ "SGI-B-2.0",
+ "SHL-0.5",
+ "SHL-0.51",
+ "SISSL",
+ "SISSL-1.2",
+ "SMLNJ",
+ "SMPPL",
+ "SNIA",
+ "SPL-1.0",
+ "SSH-OpenSSH",
+ "SSH-short",
+ "SSPL-1.0",
+ "SWL",
+ "Saxpath",
+ "Sendmail",
+ "Sendmail-8.23",
+ "SimPL-2.0",
+ "Sleepycat",
+ "Spencer-86",
+ "Spencer-94",
+ "Spencer-99",
+ "StandardML-NJ",
+ "SugarCRM-1.1.3",
+ "TAPR-OHL-1.0",
+ "TCL",
+ "TCP-wrappers",
+ "TMate",
+ "TORQUE-1.1",
+ "TOSL",
+ "TU-Berlin-1.0",
+ "TU-Berlin-2.0",
+ "UCL-1.0",
+ "UPL-1.0",
+ "Unicode-DFS-2015",
+ "Unicode-DFS-2016",
+ "Unicode-TOU",
+ "Unlicense",
+ "VOSTROM",
+ "VSL-1.0",
+ "Vim",
+ "W3C",
+ "W3C-19980720",
+ "W3C-20150513",
+ "WTFPL",
+ "Watcom-1.0",
+ "Wsuipa",
+ "X11",
+ "XFree86-1.1",
+ "XSkat",
+ "Xerox",
+ "Xnet",
+ "YPL-1.0",
+ "YPL-1.1",
+ "ZPL-1.1",
+ "ZPL-2.0",
+ "ZPL-2.1",
+ "Zed",
+ "Zend-2.0",
+ "Zimbra-1.3",
+ "Zimbra-1.4",
+ "Zlib",
+ "blessing",
+ "bzip2-1.0.5",
+ "bzip2-1.0.6",
+ "copyleft-next-0.3.0",
+ "copyleft-next-0.3.1",
+ "curl",
+ "diffmark",
+ "dvipdfm",
+ "eCos-2.0",
+ "eGenix",
+ "etalab-2.0",
+ "gSOAP-1.3b",
+ "gnuplot",
+ "iMatix",
+ "libpng-2.0",
+ "libselinux-1.0",
+ "libtiff",
+ "mpich2",
+ "psfrag",
+ "psutils",
+ "wxWindows",
+ "xinetd",
+ "xpp",
+ "zlib-acknowledgement",
+ "GCC-exception-2.0",
+ "openvpn-openssl-exception",
+ "Nokia-Qt-exception-1.1",
+ "GPL-3.0-linking-exception",
+ "Fawkes-Runtime-exception",
+ "u-boot-exception-2.0",
+ "PS-or-PDF-font-exception-20170817",
+ "gnu-javamail-exception",
+ "LGPL-3.0-linking-exception",
+ "DigiRule-FOSS-exception",
+ "LLVM-exception",
+ "Linux-syscall-note",
+ "GPL-3.0-linking-source-exception",
+ "Qwt-exception-1.0",
+ "389-exception",
+ "mif-exception",
+ "eCos-exception-2.0",
+ "CLISP-exception-2.0",
+ "Bison-exception-2.2",
+ "Libtool-exception",
+ "LZMA-exception",
+ "OpenJDK-assembly-exception-1.0",
+ "Font-exception-2.0",
+ "OCaml-LGPL-linking-exception",
+ "GCC-exception-3.1",
+ "Bootloader-exception",
+ "SHL-2.0",
+ "Classpath-exception-2.0",
+ "Swift-exception",
+ "Autoconf-exception-2.0",
+ "FLTK-exception",
+ "freertos-exception-2.0",
+ "Universal-FOSS-exception-1.0",
+ "WxWindows-exception-3.1",
+ "OCCT-exception-1.0",
+ "Autoconf-exception-3.0",
+ "i2p-gpl-java-exception",
+ "GPL-CC-1.0",
+ "Qt-LGPL-exception-1.1",
+ "SHL-2.1",
+ "Qt-GPL-exception-1.0"
+ ]
+}
diff --git a/cyclonedx/schema/spdx.xsd b/cyclonedx/schema/spdx.xsd
new file mode 100644
index 00000000..dbd61b16
--- /dev/null
+++ b/cyclonedx/schema/spdx.xsd
@@ -0,0 +1,2429 @@
+
+
+
+
+
+
+
+
+ BSD Zero Clause License
+
+
+
+
+ Attribution Assurance License
+
+
+
+
+ Amazon Digital Services License
+
+
+
+
+ Academic Free License v1.1
+
+
+
+
+ Academic Free License v1.2
+
+
+
+
+ Academic Free License v2.0
+
+
+
+
+ Academic Free License v2.1
+
+
+
+
+ Academic Free License v3.0
+
+
+
+
+ Affero General Public License v1.0
+
+
+
+
+ Affero General Public License v1.0 only
+
+
+
+
+ Affero General Public License v1.0 or later
+
+
+
+
+ GNU Affero General Public License v3.0
+
+
+
+
+ GNU Affero General Public License v3.0 only
+
+
+
+
+ GNU Affero General Public License v3.0 or later
+
+
+
+
+ AMD's plpa_map.c License
+
+
+
+
+ Apple MIT License
+
+
+
+
+ Academy of Motion Picture Arts and Sciences BSD
+
+
+
+
+ ANTLR Software Rights Notice
+
+
+
+
+ Adobe Postscript AFM License
+
+
+
+
+ Adaptive Public License 1.0
+
+
+
+
+ Apple Public Source License 1.0
+
+
+
+
+ Apple Public Source License 1.1
+
+
+
+
+ Apple Public Source License 1.2
+
+
+
+
+ Apple Public Source License 2.0
+
+
+
+
+ Abstyles License
+
+
+
+
+ Adobe Systems Incorporated Source Code License Agreement
+
+
+
+
+ Adobe Glyph List License
+
+
+
+
+ Afmparse License
+
+
+
+
+ Aladdin Free Public License
+
+
+
+
+ Apache License 1.0
+
+
+
+
+ Apache License 1.1
+
+
+
+
+ Apache License 2.0
+
+
+
+
+ Artistic License 1.0
+
+
+
+
+ Artistic License 1.0 (Perl)
+
+
+
+
+ Artistic License 1.0 w/clause 8
+
+
+
+
+ Artistic License 2.0
+
+
+
+
+ BSD 1-Clause License
+
+
+
+
+ BSD 2-Clause "Simplified" License
+
+
+
+
+ BSD 2-Clause FreeBSD License
+
+
+
+
+ BSD 2-Clause NetBSD License
+
+
+
+
+ BSD-2-Clause Plus Patent License
+
+
+
+
+ BSD 2-Clause with views sentence
+
+
+
+
+ BSD 3-Clause "New" or "Revised" License
+
+
+
+
+ BSD with attribution
+
+
+
+
+ BSD 3-Clause Clear License
+
+
+
+
+ Lawrence Berkeley National Labs BSD variant license
+
+
+
+
+ BSD 3-Clause No Nuclear License
+
+
+
+
+ BSD 3-Clause No Nuclear License 2014
+
+
+
+
+ BSD 3-Clause No Nuclear Warranty
+
+
+
+
+ BSD 3-Clause Open MPI variant
+
+
+
+
+ BSD 4-Clause "Original" or "Old" License
+
+
+
+
+ BSD-4-Clause (University of California-Specific)
+
+
+
+
+ BSD Protection License
+
+
+
+
+ BSD Source Code Attribution
+
+
+
+
+ Boost Software License 1.0
+
+
+
+
+ Bahyph License
+
+
+
+
+ Barr License
+
+
+
+
+ Beerware License
+
+
+
+
+ BitTorrent Open Source License v1.0
+
+
+
+
+ BitTorrent Open Source License v1.1
+
+
+
+
+ Blue Oak Model License 1.0.0
+
+
+
+
+ Borceux license
+
+
+
+
+ Cryptographic Autonomy License 1.0
+
+
+
+
+ Cryptographic Autonomy License 1.0 (Combined Work Exception)
+
+
+
+
+ Computer Associates Trusted Open Source License 1.1
+
+
+
+
+ Creative Commons Attribution 1.0 Generic
+
+
+
+
+ Creative Commons Attribution 2.0 Generic
+
+
+
+
+ Creative Commons Attribution 2.5 Generic
+
+
+
+
+ Creative Commons Attribution 3.0 Unported
+
+
+
+
+ Creative Commons Attribution 3.0 Austria
+
+
+
+
+ Creative Commons Attribution 4.0 International
+
+
+
+
+ Creative Commons Attribution Non Commercial 1.0 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial 2.0 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial 2.5 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial 3.0 Unported
+
+
+
+
+ Creative Commons Attribution Non Commercial 4.0 International
+
+
+
+
+ Creative Commons Attribution Non Commercial No Derivatives 1.0 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial No Derivatives 2.0 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial No Derivatives 2.5 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial No Derivatives 3.0 Unported
+
+
+
+
+ Creative Commons Attribution Non Commercial No Derivatives 3.0 IGO
+
+
+
+
+ Creative Commons Attribution Non Commercial No Derivatives 4.0 International
+
+
+
+
+ Creative Commons Attribution Non Commercial Share Alike 1.0 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial Share Alike 2.0 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial Share Alike 2.5 Generic
+
+
+
+
+ Creative Commons Attribution Non Commercial Share Alike 3.0 Unported
+
+
+
+
+ Creative Commons Attribution Non Commercial Share Alike 4.0 International
+
+
+
+
+ Creative Commons Attribution No Derivatives 1.0 Generic
+
+
+
+
+ Creative Commons Attribution No Derivatives 2.0 Generic
+
+
+
+
+ Creative Commons Attribution No Derivatives 2.5 Generic
+
+
+
+
+ Creative Commons Attribution No Derivatives 3.0 Unported
+
+
+
+
+ Creative Commons Attribution No Derivatives 4.0 International
+
+
+
+
+ Creative Commons Attribution Share Alike 1.0 Generic
+
+
+
+
+ Creative Commons Attribution Share Alike 2.0 Generic
+
+
+
+
+ Creative Commons Attribution Share Alike 2.5 Generic
+
+
+
+
+ Creative Commons Attribution Share Alike 3.0 Unported
+
+
+
+
+ Creative Commons Attribution-Share Alike 3.0 Austria
+
+
+
+
+ Creative Commons Attribution Share Alike 4.0 International
+
+
+
+
+ Creative Commons Public Domain Dedication and Certification
+
+
+
+
+ Creative Commons Zero v1.0 Universal
+
+
+
+
+ Common Development and Distribution License 1.0
+
+
+
+
+ Common Development and Distribution License 1.1
+
+
+
+
+ Community Data License Agreement Permissive 1.0
+
+
+
+
+ Community Data License Agreement Sharing 1.0
+
+
+
+
+ CeCILL Free Software License Agreement v1.0
+
+
+
+
+ CeCILL Free Software License Agreement v1.1
+
+
+
+
+ CeCILL Free Software License Agreement v2.0
+
+
+
+
+ CeCILL Free Software License Agreement v2.1
+
+
+
+
+ CeCILL-B Free Software License Agreement
+
+
+
+
+ CeCILL-C Free Software License Agreement
+
+
+
+
+ CERN Open Hardware Licence v1.1
+
+
+
+
+ CERN Open Hardware Licence v1.2
+
+
+
+
+ CERN Open Hardware Licence Version 2 - Permissive
+
+
+
+
+ CERN Open Hardware Licence Version 2 - Strongly Reciprocal
+
+
+
+
+ CERN Open Hardware Licence Version 2 - Weakly Reciprocal
+
+
+
+
+ CNRI Jython License
+
+
+
+
+ CNRI Python License
+
+
+
+
+ CNRI Python Open Source GPL Compatible License Agreement
+
+
+
+
+ Common Public Attribution License 1.0
+
+
+
+
+ Common Public License 1.0
+
+
+
+
+ Code Project Open License 1.02
+
+
+
+
+ CUA Office Public License v1.0
+
+
+
+
+ Caldera License
+
+
+
+
+ Clarified Artistic License
+
+
+
+
+ Condor Public License v1.1
+
+
+
+
+ Crossword License
+
+
+
+
+ CrystalStacker License
+
+
+
+
+ Cube License
+
+
+
+
+ Deutsche Freie Software Lizenz
+
+
+
+
+ DOC License
+
+
+
+
+ DSDP License
+
+
+
+
+ Dotseqn License
+
+
+
+
+ Educational Community License v1.0
+
+
+
+
+ Educational Community License v2.0
+
+
+
+
+ Eiffel Forum License v1.0
+
+
+
+
+ Eiffel Forum License v2.0
+
+
+
+
+ EPICS Open License
+
+
+
+
+ Eclipse Public License 1.0
+
+
+
+
+ Eclipse Public License 2.0
+
+
+
+
+ EU DataGrid Software License
+
+
+
+
+ European Union Public License 1.0
+
+
+
+
+ European Union Public License 1.1
+
+
+
+
+ European Union Public License 1.2
+
+
+
+
+ Entessa Public License v1.0
+
+
+
+
+ Erlang Public License v1.1
+
+
+
+
+ Eurosym License
+
+
+
+
+ FSF All Permissive License
+
+
+
+
+ FSF Unlimited License
+
+
+
+
+ FSF Unlimited License (with License Retention)
+
+
+
+
+ Freetype Project License
+
+
+
+
+ Fair License
+
+
+
+
+ Frameworx Open License 1.0
+
+
+
+
+ FreeImage Public License v1.0
+
+
+
+
+ GNU Free Documentation License v1.1
+
+
+
+
+ GNU Free Documentation License v1.1 only - invariants
+
+
+
+
+ GNU Free Documentation License v1.1 or later - invariants
+
+
+
+
+ GNU Free Documentation License v1.1 only - no invariants
+
+
+
+
+ GNU Free Documentation License v1.1 or later - no invariants
+
+
+
+
+ GNU Free Documentation License v1.1 only
+
+
+
+
+ GNU Free Documentation License v1.1 or later
+
+
+
+
+ GNU Free Documentation License v1.2
+
+
+
+
+ GNU Free Documentation License v1.2 only - invariants
+
+
+
+
+ GNU Free Documentation License v1.2 or later - invariants
+
+
+
+
+ GNU Free Documentation License v1.2 only - no invariants
+
+
+
+
+ GNU Free Documentation License v1.2 or later - no invariants
+
+
+
+
+ GNU Free Documentation License v1.2 only
+
+
+
+
+ GNU Free Documentation License v1.2 or later
+
+
+
+
+ GNU Free Documentation License v1.3
+
+
+
+
+ GNU Free Documentation License v1.3 only - invariants
+
+
+
+
+ GNU Free Documentation License v1.3 or later - invariants
+
+
+
+
+ GNU Free Documentation License v1.3 only - no invariants
+
+
+
+
+ GNU Free Documentation License v1.3 or later - no invariants
+
+
+
+
+ GNU Free Documentation License v1.3 only
+
+
+
+
+ GNU Free Documentation License v1.3 or later
+
+
+
+
+ GL2PS License
+
+
+
+
+ Good Luck With That Public License
+
+
+
+
+ GNU General Public License v1.0 only
+
+
+
+
+ GNU General Public License v1.0 or later
+
+
+
+
+ GNU General Public License v1.0 only
+
+
+
+
+ GNU General Public License v1.0 or later
+
+
+
+
+ GNU General Public License v2.0 only
+
+
+
+
+ GNU General Public License v2.0 or later
+
+
+
+
+ GNU General Public License v2.0 only
+
+
+
+
+ GNU General Public License v2.0 or later
+
+
+
+
+ GNU General Public License v2.0 w/GCC Runtime Library exception
+
+
+
+
+ GNU General Public License v2.0 w/Autoconf exception
+
+
+
+
+ GNU General Public License v2.0 w/Bison exception
+
+
+
+
+ GNU General Public License v2.0 w/Classpath exception
+
+
+
+
+ GNU General Public License v2.0 w/Font exception
+
+
+
+
+ GNU General Public License v3.0 only
+
+
+
+
+ GNU General Public License v3.0 or later
+
+
+
+
+ GNU General Public License v3.0 only
+
+
+
+
+ GNU General Public License v3.0 or later
+
+
+
+
+ GNU General Public License v3.0 w/GCC Runtime Library exception
+
+
+
+
+ GNU General Public License v3.0 w/Autoconf exception
+
+
+
+
+ Giftware License
+
+
+
+
+ 3dfx Glide License
+
+
+
+
+ Glulxe License
+
+
+
+
+ Historical Permission Notice and Disclaimer
+
+
+
+
+ Historical Permission Notice and Disclaimer - sell variant
+
+
+
+
+ Haskell Language Report License
+
+
+
+
+ Hippocratic License 2.1
+
+
+
+
+ IBM PowerPC Initialization and Boot Software
+
+
+
+
+ ICU License
+
+
+
+
+ Independent JPEG Group License
+
+
+
+
+ IPA Font License
+
+
+
+
+ IBM Public License v1.0
+
+
+
+
+ ISC License
+
+
+
+
+ ImageMagick License
+
+
+
+
+ Imlib2 License
+
+
+
+
+ Info-ZIP License
+
+
+
+
+ Intel Open Source License
+
+
+
+
+ Intel ACPI Software License Agreement
+
+
+
+
+ Interbase Public License v1.0
+
+
+
+
+ Japan Network Information Center License
+
+
+
+
+ JSON License
+
+
+
+
+ JasPer License
+
+
+
+
+ Licence Art Libre 1.2
+
+
+
+
+ Licence Art Libre 1.3
+
+
+
+
+ GNU Library General Public License v2 only
+
+
+
+
+ GNU Library General Public License v2 or later
+
+
+
+
+ GNU Library General Public License v2 only
+
+
+
+
+ GNU Library General Public License v2 or later
+
+
+
+
+ GNU Lesser General Public License v2.1 only
+
+
+
+
+ GNU Library General Public License v2.1 or later
+
+
+
+
+ GNU Lesser General Public License v2.1 only
+
+
+
+
+ GNU Lesser General Public License v2.1 or later
+
+
+
+
+ GNU Lesser General Public License v3.0 only
+
+
+
+
+ GNU Lesser General Public License v3.0 or later
+
+
+
+
+ GNU Lesser General Public License v3.0 only
+
+
+
+
+ GNU Lesser General Public License v3.0 or later
+
+
+
+
+ Lesser General Public License For Linguistic Resources
+
+
+
+
+ Lucent Public License Version 1.0
+
+
+
+
+ Lucent Public License v1.02
+
+
+
+
+ LaTeX Project Public License v1.0
+
+
+
+
+ LaTeX Project Public License v1.1
+
+
+
+
+ LaTeX Project Public License v1.2
+
+
+
+
+ LaTeX Project Public License v1.3a
+
+
+
+
+ LaTeX Project Public License v1.3c
+
+
+
+
+ Latex2e License
+
+
+
+
+ Leptonica License
+
+
+
+
+ Licence Libre du Québec – Permissive version 1.1
+
+
+
+
+ Licence Libre du Québec – Réciprocité version 1.1
+
+
+
+
+ Licence Libre du Québec – Réciprocité forte version 1.1
+
+
+
+
+ libpng License
+
+
+
+
+ Linux Kernel Variant of OpenIB.org license
+
+
+
+
+ MIT License
+
+
+
+
+ MIT No Attribution
+
+
+
+
+ CMU License
+
+
+
+
+ Enlightenment License (e16)
+
+
+
+
+ enna License
+
+
+
+
+ feh License
+
+
+
+
+ MIT +no-false-attribs license
+
+
+
+
+ Mozilla Public License 1.0
+
+
+
+
+ Mozilla Public License 1.1
+
+
+
+
+ Mozilla Public License 2.0
+
+
+
+
+ Mozilla Public License 2.0 (no copyleft exception)
+
+
+
+
+ Microsoft Public License
+
+
+
+
+ Microsoft Reciprocal License
+
+
+
+
+ Matrix Template Library License
+
+
+
+
+ MakeIndex License
+
+
+
+
+ The MirOS Licence
+
+
+
+
+ Motosoto License
+
+
+
+
+ Mulan Permissive Software License, Version 1
+
+
+
+
+ Mulan Permissive Software License, Version 2
+
+
+
+
+ Multics License
+
+
+
+
+ Mup License
+
+
+
+
+ NASA Open Source Agreement 1.3
+
+
+
+
+ Net Boolean Public License v1
+
+
+
+
+ Non-Commercial Government Licence
+
+
+
+
+ University of Illinois/NCSA Open Source License
+
+
+
+
+ Nethack General Public License
+
+
+
+
+ NIST Public Domain Notice
+
+
+
+
+ NIST Public Domain Notice with license fallback
+
+
+
+
+ Norwegian Licence for Open Government Data
+
+
+
+
+ No Limit Public License
+
+
+
+
+ Netizen Open Source License
+
+
+
+
+ Netscape Public License v1.0
+
+
+
+
+ Netscape Public License v1.1
+
+
+
+
+ Non-Profit Open Software License 3.0
+
+
+
+
+ NRL License
+
+
+
+
+ NTP License
+
+
+
+
+ NTP No Attribution
+
+
+
+
+ Naumen Public License
+
+
+
+
+ Net-SNMP License
+
+
+
+
+ NetCDF license
+
+
+
+
+ Newsletr License
+
+
+
+
+ Nokia Open Source License
+
+
+
+
+ Noweb License
+
+
+
+
+ Nunit License
+
+
+
+
+ Open Use of Data Agreement v1.0
+
+
+
+
+ Open CASCADE Technology Public License
+
+
+
+
+ OCLC Research Public License 2.0
+
+
+
+
+ Open Data Commons Attribution License v1.0
+
+
+
+
+ ODC Open Database License v1.0
+
+
+
+
+ SIL Open Font License 1.0
+
+
+
+
+ SIL Open Font License 1.0 with Reserved Font Name
+
+
+
+
+ SIL Open Font License 1.0 with no Reserved Font Name
+
+
+
+
+ SIL Open Font License 1.1
+
+
+
+
+ SIL Open Font License 1.1 with Reserved Font Name
+
+
+
+
+ SIL Open Font License 1.1 with no Reserved Font Name
+
+
+
+
+ OGC Software License, Version 1.0
+
+
+
+
+ Open Government Licence - Canada
+
+
+
+
+ Open Government Licence v1.0
+
+
+
+
+ Open Government Licence v2.0
+
+
+
+
+ Open Government Licence v3.0
+
+
+
+
+ Open Group Test Suite License
+
+
+
+
+ Open LDAP Public License v1.1
+
+
+
+
+ Open LDAP Public License v1.2
+
+
+
+
+ Open LDAP Public License v1.3
+
+
+
+
+ Open LDAP Public License v1.4
+
+
+
+
+ Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)
+
+
+
+
+ Open LDAP Public License v2.0.1
+
+
+
+
+ Open LDAP Public License v2.1
+
+
+
+
+ Open LDAP Public License v2.2
+
+
+
+
+ Open LDAP Public License v2.2.1
+
+
+
+
+ Open LDAP Public License 2.2.2
+
+
+
+
+ Open LDAP Public License v2.3
+
+
+
+
+ Open LDAP Public License v2.4
+
+
+
+
+ Open LDAP Public License v2.5
+
+
+
+
+ Open LDAP Public License v2.6
+
+
+
+
+ Open LDAP Public License v2.7
+
+
+
+
+ Open LDAP Public License v2.8
+
+
+
+
+ Open Market License
+
+
+
+
+ Open Public License v1.0
+
+
+
+
+ OSET Public License version 2.1
+
+
+
+
+ Open Software License 1.0
+
+
+
+
+ Open Software License 1.1
+
+
+
+
+ Open Software License 2.0
+
+
+
+
+ Open Software License 2.1
+
+
+
+
+ Open Software License 3.0
+
+
+
+
+ OpenSSL License
+
+
+
+
+ ODC Public Domain Dedication & License 1.0
+
+
+
+
+ PHP License v3.0
+
+
+
+
+ PHP License v3.01
+
+
+
+
+ Python Software Foundation License 2.0
+
+
+
+
+ The Parity Public License 6.0.0
+
+
+
+
+ The Parity Public License 7.0.0
+
+
+
+
+ Plexus Classworlds License
+
+
+
+
+ PolyForm Noncommercial License 1.0.0
+
+
+
+
+ PolyForm Small Business License 1.0.0
+
+
+
+
+ PostgreSQL License
+
+
+
+
+ Python License 2.0
+
+
+
+
+ Q Public License 1.0
+
+
+
+
+ Qhull License
+
+
+
+
+ Red Hat eCos Public License v1.1
+
+
+
+
+ Reciprocal Public License 1.1
+
+
+
+
+ Reciprocal Public License 1.5
+
+
+
+
+ RealNetworks Public Source License v1.0
+
+
+
+
+ RSA Message-Digest License
+
+
+
+
+ Ricoh Source Code Public License
+
+
+
+
+ Rdisc License
+
+
+
+
+ Ruby License
+
+
+
+
+ Sax Public Domain Notice
+
+
+
+
+ SCEA Shared Source License
+
+
+
+
+ SGI Free Software License B v1.0
+
+
+
+
+ SGI Free Software License B v1.1
+
+
+
+
+ SGI Free Software License B v2.0
+
+
+
+
+ Solderpad Hardware License v0.5
+
+
+
+
+ Solderpad Hardware License, Version 0.51
+
+
+
+
+ Sun Industry Standards Source License v1.1
+
+
+
+
+ Sun Industry Standards Source License v1.2
+
+
+
+
+ Standard ML of New Jersey License
+
+
+
+
+ Secure Messaging Protocol Public License
+
+
+
+
+ SNIA Public License 1.1
+
+
+
+
+ Sun Public License v1.0
+
+
+
+
+ SSH OpenSSH license
+
+
+
+
+ SSH short notice
+
+
+
+
+ Server Side Public License, v 1
+
+
+
+
+ Scheme Widget Library (SWL) Software License Agreement
+
+
+
+
+ Saxpath License
+
+
+
+
+ Sendmail License
+
+
+
+
+ Sendmail License 8.23
+
+
+
+
+ Simple Public License 2.0
+
+
+
+
+ Sleepycat License
+
+
+
+
+ Spencer License 86
+
+
+
+
+ Spencer License 94
+
+
+
+
+ Spencer License 99
+
+
+
+
+ Standard ML of New Jersey License
+
+
+
+
+ SugarCRM Public License v1.1.3
+
+
+
+
+ TAPR Open Hardware License v1.0
+
+
+
+
+ TCL/TK License
+
+
+
+
+ TCP Wrappers License
+
+
+
+
+ TMate Open Source License
+
+
+
+
+ TORQUE v2.5+ Software License v1.1
+
+
+
+
+ Trusster Open Source License
+
+
+
+
+ Technische Universitaet Berlin License 1.0
+
+
+
+
+ Technische Universitaet Berlin License 2.0
+
+
+
+
+ Upstream Compatibility License v1.0
+
+
+
+
+ Universal Permissive License v1.0
+
+
+
+
+ Unicode License Agreement - Data Files and Software (2015)
+
+
+
+
+ Unicode License Agreement - Data Files and Software (2016)
+
+
+
+
+ Unicode Terms of Use
+
+
+
+
+ The Unlicense
+
+
+
+
+ VOSTROM Public License for Open Source
+
+
+
+
+ Vovida Software License v1.0
+
+
+
+
+ Vim License
+
+
+
+
+ W3C Software Notice and License (2002-12-31)
+
+
+
+
+ W3C Software Notice and License (1998-07-20)
+
+
+
+
+ W3C Software Notice and Document License (2015-05-13)
+
+
+
+
+ Do What The F*ck You Want To Public License
+
+
+
+
+ Sybase Open Watcom Public License 1.0
+
+
+
+
+ Wsuipa License
+
+
+
+
+ X11 License
+
+
+
+
+ XFree86 License 1.1
+
+
+
+
+ XSkat License
+
+
+
+
+ Xerox License
+
+
+
+
+ X.Net License
+
+
+
+
+ Yahoo! Public License v1.0
+
+
+
+
+ Yahoo! Public License v1.1
+
+
+
+
+ Zope Public License 1.1
+
+
+
+
+ Zope Public License 2.0
+
+
+
+
+ Zope Public License 2.1
+
+
+
+
+ Zed License
+
+
+
+
+ Zend License v2.0
+
+
+
+
+ Zimbra Public License v1.3
+
+
+
+
+ Zimbra Public License v1.4
+
+
+
+
+ zlib License
+
+
+
+
+ SQLite Blessing
+
+
+
+
+ bzip2 and libbzip2 License v1.0.5
+
+
+
+
+ bzip2 and libbzip2 License v1.0.6
+
+
+
+
+ copyleft-next 0.3.0
+
+
+
+
+ copyleft-next 0.3.1
+
+
+
+
+ curl License
+
+
+
+
+ diffmark license
+
+
+
+
+ dvipdfm License
+
+
+
+
+ eCos license version 2.0
+
+
+
+
+ eGenix.com Public License 1.1.0
+
+
+
+
+ Etalab Open License 2.0
+
+
+
+
+ gSOAP Public License v1.3b
+
+
+
+
+ gnuplot License
+
+
+
+
+ iMatix Standard Function Library Agreement
+
+
+
+
+ PNG Reference Library version 2
+
+
+
+
+ libselinux public domain notice
+
+
+
+
+ libtiff License
+
+
+
+
+ mpich2 License
+
+
+
+
+ psfrag License
+
+
+
+
+ psutils License
+
+
+
+
+ wxWindows Library License
+
+
+
+
+ xinetd License
+
+
+
+
+ XPP License
+
+
+
+
+ zlib/libpng License with Acknowledgement
+
+
+
+
+
+ GCC Runtime Library exception 2.0
+
+
+
+
+ OpenVPN OpenSSL Exception
+
+
+
+
+ Nokia Qt LGPL exception 1.1
+
+
+
+
+ GPL-3.0 Linking Exception
+
+
+
+
+ Fawkes Runtime Exception
+
+
+
+
+ U-Boot exception 2.0
+
+
+
+
+ PS/PDF font exception (2017-08-17)
+
+
+
+
+ GNU JavaMail exception
+
+
+
+
+ LGPL-3.0 Linking Exception
+
+
+
+
+ DigiRule FOSS License Exception
+
+
+
+
+ LLVM Exception
+
+
+
+
+ Linux Syscall Note
+
+
+
+
+ GPL-3.0 Linking Exception (with Corresponding Source)
+
+
+
+
+ Qwt exception 1.0
+
+
+
+
+ 389 Directory Server Exception
+
+
+
+
+ Macros and Inline Functions Exception
+
+
+
+
+ eCos exception 2.0
+
+
+
+
+ CLISP exception 2.0
+
+
+
+
+ Bison exception 2.2
+
+
+
+
+ Libtool Exception
+
+
+
+
+ LZMA exception
+
+
+
+
+ OpenJDK Assembly exception 1.0
+
+
+
+
+ Font exception 2.0
+
+
+
+
+ OCaml LGPL Linking Exception
+
+
+
+
+ GCC Runtime Library exception 3.1
+
+
+
+
+ Bootloader Distribution Exception
+
+
+
+
+ Solderpad Hardware License v2.0
+
+
+
+
+ Classpath exception 2.0
+
+
+
+
+ Swift Exception
+
+
+
+
+ Autoconf exception 2.0
+
+
+
+
+ FLTK exception
+
+
+
+
+ FreeRTOS Exception 2.0
+
+
+
+
+ Universal FOSS Exception, Version 1.0
+
+
+
+
+ WxWindows Library Exception 3.1
+
+
+
+
+ Open CASCADE Exception 1.0
+
+
+
+
+ Autoconf exception 3.0
+
+
+
+
+ i2p GPL+Java Exception
+
+
+
+
+ GPL Cooperation Commitment 1.0
+
+
+
+
+ Qt LGPL exception 1.1
+
+
+
+
+ Solderpad Hardware License v2.1
+
+
+
+
+ Qt GPL exception 1.0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/poetry.lock b/poetry.lock
new file mode 100644
index 00000000..c63968a1
--- /dev/null
+++ b/poetry.lock
@@ -0,0 +1,369 @@
+[[package]]
+name = "backports.entry-points-selectable"
+version = "1.1.0"
+description = "Compatibility shim providing selectable entry points for older implementations"
+category = "dev"
+optional = false
+python-versions = ">=2.7"
+
+[package.dependencies]
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=4.6)", "pytest-flake8", "pytest-cov", "pytest-black (>=0.3.7)", "pytest-mypy", "pytest-checkdocs (>=2.4)", "pytest-enabler (>=1.0.1)"]
+
+[[package]]
+name = "colorama"
+version = "0.4.4"
+description = "Cross-platform colored terminal text."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[[package]]
+name = "coverage"
+version = "5.5"
+description = "Code coverage measurement for Python"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
+
+[package.extras]
+toml = ["toml"]
+
+[[package]]
+name = "distlib"
+version = "0.3.2"
+description = "Distribution utilities"
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "filelock"
+version = "3.0.12"
+description = "A platform independent file lock."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "importlib-metadata"
+version = "4.8.1"
+description = "Read metadata from Python packages"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
+zipp = ">=0.5"
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+perf = ["ipython"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+
+[[package]]
+name = "importlib-resources"
+version = "5.2.2"
+description = "Read resources from Python packages"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"]
+
+[[package]]
+name = "packageurl-python"
+version = "0.9.4"
+description = "A \"purl\" aka. Package URL parser and builder"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "packaging"
+version = "21.0"
+description = "Core utilities for Python packages"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+pyparsing = ">=2.0.2"
+
+[[package]]
+name = "platformdirs"
+version = "2.3.0"
+description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
+test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
+
+[[package]]
+name = "pluggy"
+version = "1.0.0"
+description = "plugin and hook calling mechanisms for python"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "py"
+version = "1.10.0"
+description = "library with cross-python path, ini-parsing, io, code, log facilities"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pyparsing"
+version = "2.4.7"
+description = "Python parsing module"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "requirements-parser"
+version = "0.2.0"
+description = "Parses Pip requirement files"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "toml"
+version = "0.10.2"
+description = "Python Library for Tom's Obvious, Minimal Language"
+category = "dev"
+optional = false
+python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+
+[[package]]
+name = "tox"
+version = "3.24.3"
+description = "tox is a generic virtualenv management and test command line tool"
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+
+[package.dependencies]
+colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""}
+filelock = ">=3.0.0"
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+packaging = ">=14"
+pluggy = ">=0.12.0"
+py = ">=1.4.17"
+six = ">=1.14.0"
+toml = ">=0.9.4"
+virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7"
+
+[package.extras]
+docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"]
+testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)", "pytest-xdist (>=1.22.2)", "pathlib2 (>=2.3.3)"]
+
+[[package]]
+name = "typing-extensions"
+version = "3.10.0.2"
+description = "Backported and Experimental Type Hints for Python 3.5+"
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "virtualenv"
+version = "20.7.2"
+description = "Virtual Python Environment builder"
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+
+[package.dependencies]
+"backports.entry-points-selectable" = ">=1.0.4"
+distlib = ">=0.3.1,<1"
+filelock = ">=3.0.0,<4"
+importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
+importlib-resources = {version = ">=1.0", markers = "python_version < \"3.7\""}
+platformdirs = ">=2,<3"
+six = ">=1.9.0,<2"
+
+[package.extras]
+docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)"]
+testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
+
+[[package]]
+name = "zipp"
+version = "3.5.0"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+
+[metadata]
+lock-version = "1.1"
+python-versions = "^3.6"
+content-hash = "bc05fb928d057f1640afadcd1413625114bbe97b215619acefa9f715295d1a1a"
+
+[metadata.files]
+"backports.entry-points-selectable" = [
+ {file = "backports.entry_points_selectable-1.1.0-py2.py3-none-any.whl", hash = "sha256:a6d9a871cde5e15b4c4a53e3d43ba890cc6861ec1332c9c2428c92f977192acc"},
+ {file = "backports.entry_points_selectable-1.1.0.tar.gz", hash = "sha256:988468260ec1c196dab6ae1149260e2f5472c9110334e5d51adcb77867361f6a"},
+]
+colorama = [
+ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
+ {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
+]
+coverage = [
+ {file = "coverage-5.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf"},
+ {file = "coverage-5.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b"},
+ {file = "coverage-5.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669"},
+ {file = "coverage-5.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90"},
+ {file = "coverage-5.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c"},
+ {file = "coverage-5.5-cp27-cp27m-win32.whl", hash = "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a"},
+ {file = "coverage-5.5-cp27-cp27m-win_amd64.whl", hash = "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82"},
+ {file = "coverage-5.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905"},
+ {file = "coverage-5.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083"},
+ {file = "coverage-5.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5"},
+ {file = "coverage-5.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81"},
+ {file = "coverage-5.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6"},
+ {file = "coverage-5.5-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0"},
+ {file = "coverage-5.5-cp310-cp310-win_amd64.whl", hash = "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae"},
+ {file = "coverage-5.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb"},
+ {file = "coverage-5.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160"},
+ {file = "coverage-5.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6"},
+ {file = "coverage-5.5-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701"},
+ {file = "coverage-5.5-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793"},
+ {file = "coverage-5.5-cp35-cp35m-win32.whl", hash = "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e"},
+ {file = "coverage-5.5-cp35-cp35m-win_amd64.whl", hash = "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3"},
+ {file = "coverage-5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066"},
+ {file = "coverage-5.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a"},
+ {file = "coverage-5.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465"},
+ {file = "coverage-5.5-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb"},
+ {file = "coverage-5.5-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821"},
+ {file = "coverage-5.5-cp36-cp36m-win32.whl", hash = "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45"},
+ {file = "coverage-5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184"},
+ {file = "coverage-5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a"},
+ {file = "coverage-5.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53"},
+ {file = "coverage-5.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d"},
+ {file = "coverage-5.5-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638"},
+ {file = "coverage-5.5-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3"},
+ {file = "coverage-5.5-cp37-cp37m-win32.whl", hash = "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a"},
+ {file = "coverage-5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a"},
+ {file = "coverage-5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6"},
+ {file = "coverage-5.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2"},
+ {file = "coverage-5.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759"},
+ {file = "coverage-5.5-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873"},
+ {file = "coverage-5.5-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a"},
+ {file = "coverage-5.5-cp38-cp38-win32.whl", hash = "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6"},
+ {file = "coverage-5.5-cp38-cp38-win_amd64.whl", hash = "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502"},
+ {file = "coverage-5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b"},
+ {file = "coverage-5.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529"},
+ {file = "coverage-5.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b"},
+ {file = "coverage-5.5-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff"},
+ {file = "coverage-5.5-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b"},
+ {file = "coverage-5.5-cp39-cp39-win32.whl", hash = "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6"},
+ {file = "coverage-5.5-cp39-cp39-win_amd64.whl", hash = "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03"},
+ {file = "coverage-5.5-pp36-none-any.whl", hash = "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079"},
+ {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"},
+ {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"},
+]
+distlib = [
+ {file = "distlib-0.3.2-py2.py3-none-any.whl", hash = "sha256:23e223426b28491b1ced97dc3bbe183027419dfc7982b4fa2f05d5f3ff10711c"},
+ {file = "distlib-0.3.2.zip", hash = "sha256:106fef6dc37dd8c0e2c0a60d3fca3e77460a48907f335fa28420463a6f799736"},
+]
+filelock = [
+ {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
+ {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
+]
+importlib-metadata = [
+ {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"},
+ {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"},
+]
+importlib-resources = [
+ {file = "importlib_resources-5.2.2-py3-none-any.whl", hash = "sha256:2480d8e07d1890056cb53c96e3de44fead9c62f2ba949b0f2e4c4345f4afa977"},
+ {file = "importlib_resources-5.2.2.tar.gz", hash = "sha256:a65882a4d0fe5fbf702273456ba2ce74fe44892c25e42e057aca526b702a6d4b"},
+]
+packageurl-python = [
+ {file = "packageurl-python-0.9.4.tar.gz", hash = "sha256:bd0e829260baff12055c47e1898e0f4014469d09bdb380ddcb102b5d2392fb56"},
+ {file = "packageurl_python-0.9.4-py2.py3-none-any.whl", hash = "sha256:65f1eade0f3f412bdc77401e76725e9fc21d0c742ba0f2d066113cb19ccd8b61"},
+]
+packaging = [
+ {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
+ {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
+]
+platformdirs = [
+ {file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"},
+ {file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"},
+]
+pluggy = [
+ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
+ {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
+]
+py = [
+ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
+ {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
+]
+pyparsing = [
+ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
+ {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
+]
+requirements-parser = [
+ {file = "requirements-parser-0.2.0.tar.gz", hash = "sha256:5963ee895c2d05ae9f58d3fc641082fb38021618979d6a152b6b1398bd7d4ed4"},
+ {file = "requirements_parser-0.2.0-py2-none-any.whl", hash = "sha256:76650b4a9d98fc65edf008a7920c076bb2a76c08eaae230ce4cfc6f51ea6a773"},
+]
+six = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+toml = [
+ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
+ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
+]
+tox = [
+ {file = "tox-3.24.3-py2.py3-none-any.whl", hash = "sha256:9fbf8e2ab758b2a5e7cb2c72945e4728089934853076f67ef18d7575c8ab6b88"},
+ {file = "tox-3.24.3.tar.gz", hash = "sha256:c6c4e77705ada004283610fd6d9ba4f77bc85d235447f875df9f0ba1bc23b634"},
+]
+typing-extensions = [
+ {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"},
+ {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"},
+ {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},
+]
+virtualenv = [
+ {file = "virtualenv-20.7.2-py2.py3-none-any.whl", hash = "sha256:e4670891b3a03eb071748c569a87cceaefbf643c5bac46d996c5a45c34aa0f06"},
+ {file = "virtualenv-20.7.2.tar.gz", hash = "sha256:9ef4e8ee4710826e98ff3075c9a4739e2cb1040de6a2a8d35db0055840dc96a0"},
+]
+zipp = [
+ {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"},
+ {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"},
+]
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..ce570c06
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,21 @@
+[tool.poetry]
+name = "cyclonedx"
+version = "0.0.1"
+description = "A library for producing CycloneDX SBOM (Software Bill of Materials) files."
+authors = ["Paul Horton "]
+license = "Apache-2.0"
+
+[tool.poetry.dependencies]
+python = "^3.6"
+packageurl-python = "^0.9.4"
+requirements_parser = "^0.2.0"
+setuptools = "^50.3.2"
+importlib-metadata = "^4.8.1"
+
+[tool.poetry.dev-dependencies]
+tox = "^3.24.3"
+coverage = "^5.5"
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
\ No newline at end of file
diff --git a/requirements-test.txt b/requirements-test.txt
new file mode 100644
index 00000000..48c07777
--- /dev/null
+++ b/requirements-test.txt
@@ -0,0 +1,15 @@
+backports.entry-points-selectable==1.1.0
+coverage==5.5
+distlib==0.3.2
+filelock==3.0.12
+packageurl-python==0.9.4
+packaging==21.0
+platformdirs==2.2.0
+pluggy==1.0.0
+py==1.10.0
+pyparsing==2.4.7
+requirements-parser==0.2.0
+six==1.16.0
+toml==0.10.2
+tox==3.24.3
+virtualenv==20.7.2
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..ea71d69b
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+packageurl-python>=0.9.4
+requirements_parser>=0.2.0
+setuptools>=50.3.2
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 00000000..3480374b
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal=1
\ No newline at end of file
diff --git a/setup.py b/setup.py
index e69de29b..6f0d79a3 100644
--- a/setup.py
+++ b/setup.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8 -*-
+
+import os.path
+from setuptools import setup, find_packages
+
+script_path = os.path.dirname(__file__)
+
+setup(
+ name='cyclonedx-python-lib',
+ version=open(os.path.join(script_path, 'VERSION')).read(),
+ url="https://github.com/sonatype-nexus-community/cyclonedx-python-lib",
+ author="Sonatype Community",
+ author_email="community-group@sonatype.com",
+ description="A library for producing CycloneDX SBOM (Software Bill of Materials) files.",
+ long_description=open(os.path.join(script_path, 'README.md')).read(),
+ long_description_content_type="text/markdown",
+ keywords=["BOM", "SBOM", "SCA", "OWASP"],
+ license="Apache-2.0",
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: Information Technology',
+ 'Intended Audience :: Legal Industry',
+ 'Intended Audience :: System Administrators',
+ 'Topic :: Security',
+ 'Topic :: Software Development',
+ 'Topic :: System :: Software Distribution',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9'
+ ],
+ packages=find_packages(),
+ python_requires='>=3.6',
+ package_data={
+ 'cyclonedx': ['schema/*.json', 'schema/*.xsd', 'schema/ext/*.json', 'schema/ext/*.xsd']
+ },
+ data_files=[('', ['README.md', 'requirements.txt', 'requirements-test.txt', 'VERSION'])],
+ include_package_data=True,
+ install_requires=open(os.path.join(script_path, 'requirements.txt')).read()
+)
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/base.py b/tests/base.py
new file mode 100644
index 00000000..880fc6d7
--- /dev/null
+++ b/tests/base.py
@@ -0,0 +1,112 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import json
+import xml.etree.ElementTree
+from datetime import datetime, timezone
+from unittest import TestCase
+from uuid import uuid4
+from xml.dom import minidom
+
+single_uuid: str = 'urn:uuid:{}'.format(uuid4())
+
+
+class BaseJsonTestCase(TestCase):
+
+ def assertEqualJson(self, a: str, b: str):
+ self.assertEqual(
+ json.dumps(json.loads(a), sort_keys=True),
+ json.dumps(json.loads(b), sort_keys=True)
+ )
+
+ def assertEqualJsonBom(self, a: str, b: str):
+ """
+ Remove UUID before comparison as this will be unique to each generation
+ """
+ ab, bb = json.loads(a), json.loads(b)
+
+ # Null serialNumbers
+ ab['serialNumber'] = single_uuid
+ bb['serialNumber'] = single_uuid
+
+ # Unify timestamps to ensure they will compare
+ now = datetime.now(tz=timezone.utc)
+ ab['metadata']['timestamp'] = now.isoformat()
+ bb['metadata']['timestamp'] = now.isoformat()
+
+ self.assertEqualJson(json.dumps(ab), json.dumps(bb))
+
+
+class BaseXmlTestCase(TestCase):
+
+ def assertEqualXml(self, a: str, b: str):
+ da, db = minidom.parseString(a), minidom.parseString(b)
+ self.assertTrue(self._is_equal_xml_element(da.documentElement, db.documentElement),
+ 'XML Documents are not equal: \n{}\n{}'.format(da.toxml(), db.toxml()))
+
+ def assertEqualXmlBom(self, a: str, b: str, namespace: str):
+ """
+ Sanitise some fields such as timestamps which cannot have their values directly compared for equality.
+ """
+ ba, bb = xml.etree.ElementTree.fromstring(a), xml.etree.ElementTree.fromstring(b)
+
+ # Align serialNumbers
+ ba.set('serialNumber', single_uuid)
+ bb.set('serialNumber', single_uuid)
+
+ # Align timestamps in metadata
+ now = datetime.now(tz=timezone.utc)
+ metadata_ts_a = ba.find('./{{{}}}metadata/{{{}}}timestamp'.format(namespace, namespace))
+ if metadata_ts_a is not None:
+ metadata_ts_a.text = now.isoformat()
+
+ metadata_ts_b = bb.find('./{{{}}}metadata/{{{}}}timestamp'.format(namespace, namespace))
+ if metadata_ts_b is not None:
+ metadata_ts_b.text = now.isoformat()
+
+ self.assertEqualXml(
+ xml.etree.ElementTree.tostring(ba, 'unicode'),
+ xml.etree.ElementTree.tostring(bb, 'unicode')
+ )
+
+ def _is_equal_xml_element(self, a, b):
+ if a.tagName != b.tagName:
+ return False
+ if sorted(a.attributes.items()) != sorted(b.attributes.items()):
+ return False
+
+ """
+ Remove any pure whitespace Dom Text Nodes before we compare
+
+ See: https://xml-sig.python.narkive.com/8o0UIicu
+ """
+ for n in a.childNodes:
+ if n.nodeType == n.TEXT_NODE and n.data.strip() == '':
+ a.removeChild(n)
+ for n in b.childNodes:
+ if n.nodeType == n.TEXT_NODE and n.data.strip() == '':
+ b.removeChild(n)
+
+ if len(a.childNodes) != len(b.childNodes):
+ return False
+ for ac, bc in zip(a.childNodes, b.childNodes):
+ if ac.nodeType != bc.nodeType:
+ return False
+ if ac.nodeType == ac.TEXT_NODE and ac.data != bc.data:
+ return False
+ if ac.nodeType == ac.ELEMENT_NODE and not self._is_equal_xml_element(ac, bc):
+ return False
+ return True
diff --git a/tests/fixtures/bom_v1.0_setuptools.xml b/tests/fixtures/bom_v1.0_setuptools.xml
new file mode 100644
index 00000000..0a837f10
--- /dev/null
+++ b/tests/fixtures/bom_v1.0_setuptools.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ setuptools
+ 50.3.2
+ pkg:pypi/setuptools@50.3.2?extension=tar.gz
+
+
+
\ No newline at end of file
diff --git a/tests/fixtures/bom_v1.1_setuptools.xml b/tests/fixtures/bom_v1.1_setuptools.xml
new file mode 100644
index 00000000..d051ce6b
--- /dev/null
+++ b/tests/fixtures/bom_v1.1_setuptools.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ setuptools
+ 50.3.2
+ pkg:pypi/setuptools@50.3.2?extension=tar.gz
+
+
+
\ No newline at end of file
diff --git a/tests/fixtures/bom_v1.2_setuptools.json b/tests/fixtures/bom_v1.2_setuptools.json
new file mode 100644
index 00000000..b01e52c0
--- /dev/null
+++ b/tests/fixtures/bom_v1.2_setuptools.json
@@ -0,0 +1,17 @@
+{
+ "bomFormat": "CycloneDX",
+ "specVersion": "1.2",
+ "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+ "version": 1,
+ "metadata": {
+ "timestamp": "2021-09-01T10:50:42.051979+00:00"
+ },
+ "components": [
+ {
+ "type": "library",
+ "name": "setuptools",
+ "version": "50.3.2",
+ "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/fixtures/bom_v1.2_setuptools.xml b/tests/fixtures/bom_v1.2_setuptools.xml
new file mode 100644
index 00000000..9030abd7
--- /dev/null
+++ b/tests/fixtures/bom_v1.2_setuptools.xml
@@ -0,0 +1,13 @@
+
+
+
+ 2021-09-01T10:50:42.051979+00:00
+
+
+
+ setuptools
+ 50.3.2
+ pkg:pypi/setuptools@50.3.2?extension=tar.gz
+
+
+
\ No newline at end of file
diff --git a/tests/fixtures/bom_v1.3_setuptools.json b/tests/fixtures/bom_v1.3_setuptools.json
new file mode 100644
index 00000000..2c51c26e
--- /dev/null
+++ b/tests/fixtures/bom_v1.3_setuptools.json
@@ -0,0 +1,17 @@
+{
+ "bomFormat": "CycloneDX",
+ "specVersion": "1.3",
+ "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
+ "version": 1,
+ "metadata": {
+ "timestamp": "2021-09-01T10:50:42.051979+00:00"
+ },
+ "components": [
+ {
+ "type": "library",
+ "name": "setuptools",
+ "version": "50.3.2",
+ "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/fixtures/bom_v1.3_setuptools.xml b/tests/fixtures/bom_v1.3_setuptools.xml
new file mode 100644
index 00000000..420b8dbe
--- /dev/null
+++ b/tests/fixtures/bom_v1.3_setuptools.xml
@@ -0,0 +1,13 @@
+
+
+
+ 2021-09-01T10:50:42.051979+00:00
+
+
+
+ setuptools
+ 50.3.2
+ pkg:pypi/setuptools@50.3.2?extension=tar.gz
+
+
+
\ No newline at end of file
diff --git a/tests/fixtures/requirements-example-1.txt b/tests/fixtures/requirements-example-1.txt
new file mode 100644
index 00000000..ea71d69b
--- /dev/null
+++ b/tests/fixtures/requirements-example-1.txt
@@ -0,0 +1,3 @@
+packageurl-python>=0.9.4
+requirements_parser>=0.2.0
+setuptools>=50.3.2
\ No newline at end of file
diff --git a/tests/fixtures/requirements-simple.txt b/tests/fixtures/requirements-simple.txt
new file mode 100644
index 00000000..890d7da2
--- /dev/null
+++ b/tests/fixtures/requirements-simple.txt
@@ -0,0 +1 @@
+setuptools==50.3.2
\ No newline at end of file
diff --git a/tests/test_bom.py b/tests/test_bom.py
new file mode 100644
index 00000000..7c7695da
--- /dev/null
+++ b/tests/test_bom.py
@@ -0,0 +1,36 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import os
+from unittest import TestCase
+
+from cyclonedx.model.bom import Bom
+from cyclonedx.model.component import Component
+from cyclonedx.parser.requirements import RequirementsFileParser
+
+
+class TestBom(TestCase):
+
+ def test_bom_simple(self):
+ parser = RequirementsFileParser(
+ requirements_file=os.path.join(os.path.dirname(__file__), 'fixtures/requirements-simple.txt')
+ )
+ bom = Bom.from_parser(parser=parser)
+
+ self.assertEqual(bom.component_count(), 1)
+ self.assertTrue(bom.has_component(
+ Component(name='setuptools', version='50.3.2')
+ ))
diff --git a/tests/test_component.py b/tests/test_component.py
new file mode 100644
index 00000000..99d1f4c5
--- /dev/null
+++ b/tests/test_component.py
@@ -0,0 +1,77 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from unittest import TestCase
+
+from packageurl import PackageURL
+
+from cyclonedx.model.component import Component
+
+
+class TestComponent(TestCase):
+ _component: Component
+
+ @classmethod
+ def setUpClass(cls) -> None:
+ cls._component = Component(name='setuptools', version='50.3.2').get_purl()
+ cls._component_with_qualifiers = Component(name='setuptools', version='50.3.2',
+ qualifiers='extension=tar.gz').get_purl()
+
+ def test_purl_correct(self):
+ self.assertEqual(
+ str(PackageURL(
+ type='pypi', name='setuptools', version='50.3.2'
+ )),
+ TestComponent._component
+ )
+
+ def test_purl_incorrect_version(self):
+ purl = PackageURL(
+ type='pypi', name='setuptools', version='50.3.1'
+ )
+ self.assertNotEqual(
+ str(purl),
+ TestComponent._component
+ )
+ self.assertEqual(purl.type, 'pypi')
+ self.assertEqual(purl.name, 'setuptools')
+ self.assertEqual(purl.version, '50.3.1')
+
+ def test_purl_incorrect_name(self):
+ purl = PackageURL(
+ type='pypi', name='setuptoolz', version='50.3.2'
+ )
+ self.assertNotEqual(
+ str(purl),
+ TestComponent._component
+ )
+ self.assertEqual(purl.type, 'pypi')
+ self.assertEqual(purl.name, 'setuptoolz')
+ self.assertEqual(purl.version, '50.3.2')
+
+ def test_purl_with_qualifiers(self):
+ purl = PackageURL(
+ type='pypi', name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'
+ )
+ self.assertEqual(
+ str(purl),
+ TestComponent._component_with_qualifiers
+ )
+ self.assertNotEqual(
+ str(purl),
+ TestComponent._component
+ )
+ self.assertEqual(purl.qualifiers, {'extension': 'tar.gz'})
diff --git a/tests/test_e2e_environment.py b/tests/test_e2e_environment.py
new file mode 100644
index 00000000..1b7904b8
--- /dev/null
+++ b/tests/test_e2e_environment.py
@@ -0,0 +1,61 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import json
+from unittest import TestCase
+from xml.etree import ElementTree
+
+from cyclonedx.model.bom import Bom
+from cyclonedx.output import get_instance, OutputFormat
+from cyclonedx.output.json import Json
+from cyclonedx.output.xml import Xml
+from cyclonedx.parser.environment import EnvironmentParser
+
+
+class TestE2EEnvironment(TestCase):
+
+ def test_json_defaults(self):
+ outputter: Json = get_instance(bom=Bom.from_parser(EnvironmentParser()), output_format=OutputFormat.JSON)
+ bom_json = json.loads(outputter.output_as_string())
+ component_this_library = next(
+ (x for x in bom_json['components'] if x['purl'] == 'pkg:pypi/cyclonedx-python-lib@0.0.1'), None
+ )
+
+ self.assertTrue('author' in component_this_library.keys(), 'author is missing from JSON BOM')
+ self.assertEqual(component_this_library['author'], 'Sonatype Community')
+ self.assertEqual(component_this_library['name'], 'cyclonedx-python-lib')
+ self.assertEqual(component_this_library['version'], '0.0.1')
+
+ def test_xml_defaults(self):
+ outputter: Xml = get_instance(bom=Bom.from_parser(EnvironmentParser()))
+
+ # Check we have cyclonedx-python-lib version 0.0.1 with Author, Name and Version
+ bom_xml_e = ElementTree.fromstring(outputter.output_as_string())
+ component_this_library = bom_xml_e.find('./{{{}}}components/{{{}}}component[@bom-ref=\'pkg:pypi/{}\']'.format(
+ outputter.get_target_namespace(), outputter.get_target_namespace(), 'cyclonedx-python-lib@0.0.1'
+ ))
+
+ author = component_this_library.find('./{{{}}}author'.format(outputter.get_target_namespace()))
+ self.assertIsNotNone(author, 'No author element but one was expected.')
+ self.assertEqual(author.text, 'Sonatype Community')
+
+ name = component_this_library.find('./{{{}}}name'.format(outputter.get_target_namespace()))
+ self.assertIsNotNone(name, 'No name element but one was expected.')
+ self.assertEqual(name.text, 'cyclonedx-python-lib')
+
+ version = component_this_library.find('./{{{}}}version'.format(outputter.get_target_namespace()))
+ self.assertIsNotNone(version, 'No version element but one was expected.')
+ self.assertEqual(version.text, '0.0.1')
diff --git a/tests/test_output_generic.py b/tests/test_output_generic.py
new file mode 100644
index 00000000..74eb671b
--- /dev/null
+++ b/tests/test_output_generic.py
@@ -0,0 +1,35 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from unittest import TestCase
+
+from cyclonedx.output import get_instance, OutputFormat, SchemaVersion
+from cyclonedx.output.xml import XmlV1Dot3
+
+
+class TestOutputGeneric(TestCase):
+
+ def test_get_instance_default(self):
+ i = get_instance()
+ self.assertIsInstance(i, XmlV1Dot3)
+
+ def test_get_instance_xml(self):
+ i = get_instance(output_format=OutputFormat.XML)
+ self.assertIsInstance(i, XmlV1Dot3)
+
+ def test_get_instance_xml_v1_3(self):
+ i = get_instance(output_format=OutputFormat.XML, schema_version=SchemaVersion.V1_3)
+ self.assertIsInstance(i, XmlV1Dot3)
diff --git a/tests/test_output_json.py b/tests/test_output_json.py
new file mode 100644
index 00000000..7feb0bdb
--- /dev/null
+++ b/tests/test_output_json.py
@@ -0,0 +1,44 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from os.path import dirname, join
+
+from cyclonedx.model.bom import Bom
+from cyclonedx.model.component import Component
+from cyclonedx.output import get_instance, OutputFormat, SchemaVersion
+from cyclonedx.output.json import JsonV1Dot3, JsonV1Dot2
+from tests.base import BaseJsonTestCase
+
+
+class TestOutputJson(BaseJsonTestCase):
+
+ def test_simple_bom_v1_3(self):
+ bom = Bom()
+ bom.add_component(Component(name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'))
+ outputter = get_instance(bom=bom, output_format=OutputFormat.JSON)
+ self.assertIsInstance(outputter, JsonV1Dot3)
+ with open(join(dirname(__file__), 'fixtures/bom_v1.3_setuptools.json')) as expected_json:
+ self.assertEqualJsonBom(outputter.output_as_string(), expected_json.read())
+ expected_json.close()
+
+ def test_simple_bom_v1_2(self):
+ bom = Bom()
+ bom.add_component(Component(name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'))
+ outputter = get_instance(bom=bom, output_format=OutputFormat.JSON, schema_version=SchemaVersion.V1_2)
+ self.assertIsInstance(outputter, JsonV1Dot2)
+ with open(join(dirname(__file__), 'fixtures/bom_v1.2_setuptools.json')) as expected_json:
+ self.assertEqualJsonBom(outputter.output_as_string(), expected_json.read())
+ expected_json.close()
diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py
new file mode 100644
index 00000000..663639df
--- /dev/null
+++ b/tests/test_output_xml.py
@@ -0,0 +1,66 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from os.path import dirname, join
+
+from cyclonedx.model.bom import Bom
+from cyclonedx.model.component import Component
+from cyclonedx.output import get_instance, SchemaVersion
+from cyclonedx.output.xml import XmlV1Dot3, XmlV1Dot2, XmlV1Dot1, XmlV1Dot0, Xml
+from tests.base import BaseXmlTestCase
+
+
+class TestOutputXml(BaseXmlTestCase):
+
+ def test_simple_bom_v1_3(self):
+ bom = Bom()
+ bom.add_component(Component(name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'))
+ outputter: Xml = get_instance(bom=bom)
+ self.assertIsInstance(outputter, XmlV1Dot3)
+ with open(join(dirname(__file__), 'fixtures/bom_v1.3_setuptools.xml')) as expected_xml:
+ self.assertEqualXmlBom(a=outputter.output_as_string(), b=expected_xml.read(),
+ namespace=outputter.get_target_namespace())
+ expected_xml.close()
+
+ def test_simple_bom_v1_2(self):
+ bom = Bom()
+ bom.add_component(Component(name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'))
+ outputter = get_instance(bom=bom, schema_version=SchemaVersion.V1_2)
+ self.assertIsInstance(outputter, XmlV1Dot2)
+ with open(join(dirname(__file__), 'fixtures/bom_v1.2_setuptools.xml')) as expected_xml:
+ self.assertEqualXmlBom(outputter.output_as_string(), expected_xml.read(),
+ namespace=outputter.get_target_namespace())
+ expected_xml.close()
+
+ def test_simple_bom_v1_1(self):
+ bom = Bom()
+ bom.add_component(Component(name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'))
+ outputter = get_instance(bom=bom, schema_version=SchemaVersion.V1_1)
+ self.assertIsInstance(outputter, XmlV1Dot1)
+ with open(join(dirname(__file__), 'fixtures/bom_v1.1_setuptools.xml')) as expected_xml:
+ self.assertEqualXmlBom(outputter.output_as_string(), expected_xml.read(),
+ namespace=outputter.get_target_namespace())
+ expected_xml.close()
+
+ def test_simple_bom_v1_0(self):
+ bom = Bom()
+ bom.add_component(Component(name='setuptools', version='50.3.2', qualifiers='extension=tar.gz'))
+ outputter = get_instance(bom=bom, schema_version=SchemaVersion.V1_0)
+ self.assertIsInstance(outputter, XmlV1Dot0)
+ with open(join(dirname(__file__), 'fixtures/bom_v1.0_setuptools.xml')) as expected_xml:
+ self.assertEqualXmlBom(outputter.output_as_string(), expected_xml.read(),
+ namespace=outputter.get_target_namespace())
+ expected_xml.close()
diff --git a/tests/test_parser_environment.py b/tests/test_parser_environment.py
new file mode 100644
index 00000000..02c210e0
--- /dev/null
+++ b/tests/test_parser_environment.py
@@ -0,0 +1,32 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+from unittest import TestCase
+
+from cyclonedx.parser.environment import EnvironmentParser
+
+
+class TestRequirementsParser(TestCase):
+
+ def test_simple(self):
+ """
+ @todo This test is a vague as it will detect the unique environment where tests are being executed -
+ so is this valid?
+
+ :return:
+ """
+ parser = EnvironmentParser()
+ self.assertGreater(parser.component_count(), 1)
diff --git a/tests/test_parser_requirements.py b/tests/test_parser_requirements.py
new file mode 100644
index 00000000..dfb67fad
--- /dev/null
+++ b/tests/test_parser_requirements.py
@@ -0,0 +1,39 @@
+# encoding: utf-8
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import os
+from unittest import TestCase
+
+from cyclonedx.parser.requirements import RequirementsParser
+
+
+class TestRequirementsParser(TestCase):
+
+ def test_simple(self):
+ with open(os.path.join(os.path.dirname(__file__), 'fixtures/requirements-simple.txt')) as r:
+ parser = RequirementsParser(
+ requirements_content=r.read()
+ )
+ r.close()
+ self.assertTrue(1, parser.component_count())
+
+ def test_example_1(self):
+ with open(os.path.join(os.path.dirname(__file__), 'fixtures/requirements-example-1.txt')) as r:
+ parser = RequirementsParser(
+ requirements_content=r.read()
+ )
+ r.close()
+ self.assertTrue(3, parser.component_count())
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 00000000..36c5ba44
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,21 @@
+[tox]
+minversion=3.9.0
+envlist = flake8,py3.9,py3.8,py3.7,py3.6
+
+[testenv]
+deps =
+ -r{toxinidir}/requirements-test.txt
+commands = coverage run --source=cyclonedx -m unittest discover -s tests
+
+[testenv:flake8]
+basepython = python3
+skip_install = true
+deps =
+ flake8
+ -r{toxinidir}/requirements-test.txt
+commands = flake8 cyclonedx/ tests/ setup.py
+
+[flake8]
+ignore = E305
+exclude = .git,__pycache__
+max-line-length = 120
\ No newline at end of file