|
| 1 | +Software Bill-of-Materials (SBOM) |
| 2 | +================================= |
| 3 | + |
| 4 | +Software Bill-of-Materials (abbreviated as "SBOM") is a document for sharing |
| 5 | +information about software and how it's been composed. This format is used |
| 6 | +most often in the security space for checking software and its dependencies |
| 7 | +for vulnerabilities using vulnerability databases like |
| 8 | +`CVE <https://www.cve.org/>`_ and `OSV <https://osv.dev/>`_. The SBOM format |
| 9 | +that the CPython project uses is `SPDX <https://spdx.github.io/spdx-spec/v2.3/>`_ |
| 10 | +which can be transformed into other formats if necessary by consumers. |
| 11 | + |
| 12 | +There are multiple sources of third-party dependencies for CPython. |
| 13 | +Some are vendored into the source code of CPython itself (like ``mpdecimal`` |
| 14 | +vendored at :cpy-file:`Modules/_decimal/libmpdec`) or they could be optionally pulled |
| 15 | +in during builds like Windows using dependencies from the |
| 16 | +`python/cpython-source-deps <https://github.com/python/cpython-source-deps>`_ |
| 17 | +repository. |
| 18 | + |
| 19 | +Whenever adding or updating a third-party dependency, an update will likely |
| 20 | +need to be done to the SBOM in order to track the version and software identifiers. |
| 21 | + |
| 22 | +Updating a dependency |
| 23 | +--------------------- |
| 24 | + |
| 25 | +The SBOM for CPython's bundled dependencies is kept at |
| 26 | +:cpy-file:`Misc/sbom.spdx.json`. When updating a dependency to a new version |
| 27 | +you'll need to edit the version and other metadata about this dependency in |
| 28 | +the SBOM. |
| 29 | + |
| 30 | +The recommended workflow is: |
| 31 | + |
| 32 | +1. Download the new dependency as an archive. Take note of the new version, download |
| 33 | + URL, and checksum of the downloaded archive. |
| 34 | +2. Update the vendored code in the CPython source tree. |
| 35 | +3. Edit :cpy-file:`Misc/sbom.spdx.json` to add the new ``versionInfo``, |
| 36 | + ``downloadLocation``, ``checksums``, and ``externalReferences`` for the |
| 37 | + corresponding ``package``. For most of these updates all that's needed is to |
| 38 | + update the embedded version within URLs and project identifiers. |
| 39 | + Don't update any information in ``files`` and ``relationships`` as this will |
| 40 | + be generated automatically by the SBOM tool. |
| 41 | +4. Run ``make regen-sbom`` or ``python Tools/build/generate_sbom.py``. |
| 42 | + Ensure that this doesn't fail with validation errors. |
| 43 | +5. Run ``git diff Misc/sbom.spdx.json`` and check the diff matches the |
| 44 | + expected changes. |
| 45 | +6. Commit the changes to :cpy-file:`Misc/sbom.spdx.json` along with the |
| 46 | + update to the dependency code. |
| 47 | + |
| 48 | +Adding a new dependency |
| 49 | +----------------------- |
| 50 | + |
| 51 | +When adding a dependency it's important to have the following information: |
| 52 | + |
| 53 | +* Name, version, and download URL of the project |
| 54 | +* License of the project as an `SPDX License Expression <https://spdx.org/licenses/>`_ |
| 55 | +* Software identifiers that match values in vulnerability databases |
| 56 | + (`CPE <https://nvd.nist.gov/products/cpe>`_ and |
| 57 | + `Package URLs <https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst>`_ |
| 58 | + or "PURLs") |
| 59 | +* Paths to include and exclude in the CPython source tree corresponding to this dependency |
| 60 | + |
| 61 | +After gathering this information: |
| 62 | + |
| 63 | +1. Add the information into a new entry in ``packages`` in the file |
| 64 | + :cpy-file:`Misc/sbom.spdx.json`. Don't worry about formatting, the tool will |
| 65 | + auto-format your manually written JSON. The fields to fill out include: |
| 66 | + |
| 67 | + * ``name`` for the project name. |
| 68 | + * ``SPDXID`` which will be ``"SPDXRef-PACKAGE-{name}"``. |
| 69 | + * ``licenseConcluded`` for the SPDX license identifier of the project license. |
| 70 | + * ``versionInfo`` for the version of the project. |
| 71 | + * ``downloadLocation`` should be an HTTPS URL for the project download as an archive. |
| 72 | + * ``checksums[0].checksumValue`` and ``.algorithm`` will be the SHA-256 |
| 73 | + checksum of the downloaded archive. |
| 74 | + * ``originator`` for the original author information, prefix with either an |
| 75 | + ``Organization:`` or ``Person:`` depending on the author/maintenance situation. |
| 76 | + * ``primaryPackagePurpose`` will likely be ``"SOURCE"``. |
| 77 | + * ``externalReferences`` is a list of one or more project identifiers, |
| 78 | + either CPE or Package URL. The value for ``referenceLocator`` must include |
| 79 | + the value in ``versionInfo`` to ensure the identifier |
| 80 | + corresponds to the correct release of the software. You can read more about |
| 81 | + external references in the `SPDX SBOM specification`_. |
| 82 | +2. If a new license ID is to be used, add the license expression to |
| 83 | + ``ALLOWED_LICENSE_EXPRESSIONS`` in the :cpy-file:`Tools/build/generate_sbom.py`. |
| 84 | +3. Add the paths to include and exclude into a ``PackageFiles`` instance |
| 85 | + with a key corresponding to the SBOM ID for the package (``SPDXID`` without the |
| 86 | + ``SPDXRef-PACKAGE-*`` prefix) in :cpy-file:`Tools/build/generate_sbom.py`. |
| 87 | +4. Run the tool with ``make regen-sbom`` or ``python Tools/build/generate_sbom.py``. |
| 88 | + Ensure that the tool doesn't fail with any validation errors. |
| 89 | +5. Compare the changes to :cpy-file:`Misc/sbom.spdx.json` with ``git diff``, check |
| 90 | + that all information appears correct. |
| 91 | +6. Commit the changes to :cpy-file:`Misc/sbom.spdx.json` and |
| 92 | + :cpy-file:`Tools/build/generate_sbom.py`. |
| 93 | + |
| 94 | +.. _SPDX SBOM specification: https://spdx.github.io/spdx-spec/v2-draft/external-repository-identifiers/ |
| 95 | + |
| 96 | +Removing a dependency |
| 97 | +--------------------- |
| 98 | + |
| 99 | +When removing a dependency: |
| 100 | + |
| 101 | +1. Remove the entry from the :cpy-file:`Misc/sbom.spdx.json` |
| 102 | + under the ``packages`` field. |
| 103 | +2. Remove the corresponding ``PackageFiles`` entry in :cpy-file:`Tools/build/generate_sbom.py` |
| 104 | +3. Run the tool with ``make regen-sbom`` or ``python Tools/build/generate_sbom.py``. |
| 105 | + Ensure that the tool doesn't fail with any validation errors. |
| 106 | +4. Compare the changes to :cpy-file:`Misc/sbom.spdx.json` with ``git diff``, check |
| 107 | + that correct package is removed from the SBOM. |
| 108 | +5. Commit the changes to :cpy-file:`Misc/sbom.spdx.json` and |
| 109 | + :cpy-file:`Tools/build/generate_sbom.py`. |
0 commit comments