Skip to content
40 changes: 37 additions & 3 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,54 @@ jobs:
id-token: write

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Python
uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
pip install build spdx3-validate

- name: Build package
run: python -m build

- name: Embed SBOM into the wheel
id: pitloom
uses: bact/pitloom@4842922f65fb7ed1c5e51507c0fb253c62d97960 # v0.16.2
with:
embed-wheel: "dist/*.whl"
extras: "content-type"
content-type: "true"
artifact-name: "sbom"

- name: Extract and validate embedded SBOM
env:
SBOM_PATH: ${{ steps.pitloom.outputs.sbom-path }}
run: |
set -euo pipefail
whl=$(ls dist/*.whl)
sbom_basename=$(basename "${SBOM_PATH}")

entry=""
while IFS= read -r line; do
case "${line}" in
*".dist-info/sboms/${sbom_basename}") entry="${line}"; break ;;
esac
done < <(unzip -Z1 "${whl}")

if [ -z "${entry}" ]; then
echo "::error::${sbom_basename} not found under */.dist-info/sboms/ in ${whl}"
exit 1
fi
echo "Found: ${entry}"

mkdir -p extracted-sbom
unzip -p "${whl}" "${entry}" > "extracted-sbom/${sbom_basename}"
spdx3-validate --json "extracted-sbom/${sbom_basename}"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Can we run this during the normal build workflow also so there are no surprises when we publish?

@bact bact Aug 18, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes we can. Will update the test.yml for that. Or maybe a dedicated SBOM generation test workflow.

- name: Publish distribution to PyPI
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1
73 changes: 73 additions & 0 deletions .github/workflows/test-sbom.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
# Tests that the SBOM generation and embedding step works correctly on every PR.
name: Test SBOM generation

on:
push:
paths-ignore: &ignore-paths
- "docs/**"
- "**/*.md"
- "LICENSE*"
pull_request:
paths-ignore: *ignore-paths

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test-sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Setup Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.x"
cache: pip

- name: Install build tooling
run: |
python -m pip install --upgrade pip
pip install build spdx3-validate

- name: Build wheel
run: python -m build --wheel

- name: Embed SBOM into the wheel
id: pitloom
uses: bact/pitloom@4842922f65fb7ed1c5e51507c0fb253c62d97960 # v0.16.2
with:
embed-wheel: "dist/*.whl"
extras: "content-type"
content-type: "true"
artifact-name: "sbom"

- name: Extract and validate embedded SBOM
env:
SBOM_PATH: ${{ steps.pitloom.outputs.sbom-path }}
run: |
set -euo pipefail
whl=$(ls dist/*.whl)
sbom_basename=$(basename "${SBOM_PATH}")

entry=""
while IFS= read -r line; do
case "${line}" in
*".dist-info/sboms/${sbom_basename}") entry="${line}"; break ;;
esac
done < <(unzip -Z1 "${whl}")

if [ -z "${entry}" ]; then
echo "::error::${sbom_basename} not found under */.dist-info/sboms/ in ${whl}"
exit 1
fi
echo "Found: ${entry}"

mkdir -p extracted-sbom
unzip -p "${whl}" "${entry}" > "extracted-sbom/${sbom_basename}"
spdx3-validate --json "extracted-sbom/${sbom_basename}"
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ warn_redundant_casts = true
# warn_unreachable = true
# warn_unused_ignores = true

[[tool.pitloom.creator]]
name = "Joshua Watt"
email = "JPEWhacker@gmail.com"
type = "person"

[tool.pytest.ini_options]
addopts = [
"--import-mode=importlib",
Expand Down
Loading