Skip to content

Generate CycloneDX SBOM at release time via CI#9550

Open
aclark4life wants to merge 10 commits intomainfrom
sbom
Open

Generate CycloneDX SBOM at release time via CI#9550
aclark4life wants to merge 10 commits intomainfrom
sbom

Conversation

@aclark4life
Copy link
Copy Markdown
Member

Includes all 8 C extension modules, 3 vendored thirdparty libraries (raqm 0.10.3, fribidi-shim, pythoncapi_compat), and 13 optional native library dependencies with encoded dependency relationships.

@aclark4life aclark4life changed the title Add CycloneDX SBOM Generate CycloneDX SBOM at release time via CI Apr 7, 2026
- Add .github/generate-sbom.py: reads the real version from
  src/PIL/_version.py and emits a CycloneDX 1.6 JSON SBOM covering
  the 8 C extension modules, 3 vendored thirdparty libraries, and
  13 optional native library dependencies.
- Add 'sbom' job to wheels.yml: runs on tag pushes, generates the
  SBOM, uploads it as a workflow artifact, and attaches it to the
  GitHub release via 'gh release upload'.
- Remove the static pillow.cdx.json; CI now owns the generated file.

Can also be run locally:
  python .github/generate-sbom.py

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
for name, desc in c_extensions
]

vendored_components = [
Copy link
Copy Markdown

@jkowalleck jkowalleck Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these vendored_components untouched or are they patched somehow?

If they were modified, it would be good to know in which way -- see https://cyclonedx.org/use-cases/pedigree/

},
]

native_deps = [
Copy link
Copy Markdown

@jkowalleck jkowalleck Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

},
]

native_deps = [
Copy link
Copy Markdown

@jkowalleck jkowalleck Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some of the native_deps appear to be optional. better mark them as that.
see CycloneDX' component scope - https://cyclonedx.org/docs/1.7/json/#metadata_tools_oneOf_i0_components_items_scope

@jkowalleck
Copy link
Copy Markdown

jkowalleck commented Apr 7, 2026

Once everything is flushed out, may I ask you to showcase your SBOMs in the official examples repo?
see https://github.com/CycloneDX/bom-examples/tree/master/SBOM

And when shipping the SBOM in the wheel ala PEP770, maybe give https://github.com/psf/sboms-for-python-packages a quick notice :)

]

vendored_components = [
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"description": "JPEG codec (required by default; disable with "
"-C jpeg=disable). Tested with libjpeg 6b/8/9-9d "
"and libjpeg-turbo 8.",
"externalReferences": [
Copy link
Copy Markdown

@jkowalleck jkowalleck Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


return {
"bomFormat": "CycloneDX",
"specVersion": "1.6",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just go with "1.7" - the adoption in ingesting tools should be good today

"specVersion": "1.6",
"serialNumber": f"urn:uuid:{serial}",
"version": 1,
"metadata": {
Copy link
Copy Markdown

@jkowalleck jkowalleck Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name: sbom
path: "*.cdx.json"

- name: Attach SBOM to GitHub release
Copy link
Copy Markdown

@jkowalleck jkowalleck Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better move the job condition to here:
if: github.repository_owner == 'python-pillow' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags')

this way, you would have an SBOM artifact even for tests - which might come in handy at some point. - during review of changes and such ...
and you would not have any surprises on releases, surprises that you could have seen in regular CI runs

Copy link
Copy Markdown

@jkowalleck jkowalleck Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS: if you have your SBOM artifact available, you might test it for validity and context.

There might be automated validators out there, like https://pypi.org/project/cyclonedx-python-lib/ can do this https://cyclonedx-python-library.readthedocs.io/en/latest/examples.html#complex-validation

To test the value, you might use visualizers like https://cyclonedx.studio/

The practical use of the SBOM would be, besides shipping it in PEP770 style, to feed the SBOM into some sort of tool that analyzes the SBOM and warns about new findings anachronously - like https://dependencytrack.org/ can do.
This way you would get alerts on shipped versions and might yank a vulnerable ones from package registries, and write the appropriate Security Advisory accordingly.

@aclark4life aclark4life added the Packaging Any mention of setup.py; some overlap with Install label label Apr 7, 2026
aclark4life and others added 3 commits April 7, 2026 19:31
Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com>
Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com>

sbom:
if: github.repository_owner == 'python-pillow' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
needs: count-dists
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than placing all of this after the count-dists bottleneck:

image

Let's build the SBOM beforehand, so we can inspect the results (and debug problems) without having to wait hours for all the wheels to build.

And then a job afterwards to download-artifact and attach to the release:

Image

Copy link
Copy Markdown

@jkowalleck jkowalleck Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably a very good idea to have the SBOM process isolated.

you are not using target-specific components , or do you?
Like on the windows build, you use this C library, and in the MacOS, you use a different one.
I mean, if you were having target-specific components, then you would need target-specific SBOMs generated on bdist's build-time (and additionally put the correct one in the respective wheel - if the bdist process would support PEP 770).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there are platform differences, like iOS disabling raqm and imagequant:

Pillow/pyproject.toml

Lines 108 to 110 in 7cf4dac

# Disable platform guessing on iOS, and disable raqm (since there won't be a
# vendor version, and we can't distribute it due to licensing)
ios.config-settings = "raqm=disable imagequant=disable platform-guessing=disable"

@hugovk
Copy link
Copy Markdown
Member

hugovk commented Apr 8, 2026

It would be great to get this eventually into the wheels (PEP 770) but that likely needs extra tooling, and generating and adding to the GH release is a good first step. 👍

aclark4life and others added 6 commits April 8, 2026 07:34
Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
- Fix missing datetime/hashlib imports; use datetime as dt
- Bump specVersion from 1.6 to 1.7
- Add metadata.lifecycles = [{"phase": "build"}]
- Add SHA-256 hashes to vendored components (raqm, fribidi-shim, pythoncapi_compat)
- Add pedigree notes clarifying whether vendored components are patched
- Add distribution externalReferences to vendored and native dep components
- Add SPDX license IDs to all native dependencies
- Mark optional native dependencies with scope: optional
- Split sbom job: generate early (no bottleneck), publish separately after count-dists
- Add .github/generate-sbom.py to push/PR trigger paths

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@aclark4life aclark4life marked this pull request as ready for review April 9, 2026 00:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Packaging Any mention of setup.py; some overlap with Install label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants