@@ -439,13 +439,21 @@ jobs:
439439 path : pywry/dist/*.whl
440440 retention-days : 30
441441
442+ generate-sbom :
443+ name : Generate release SBOM
444+ needs : [test]
445+ if : ${{ !cancelled() && (needs.test.result == 'success' || needs.test.result == 'skipped') }}
446+ permissions :
447+ contents : read
448+ uses : ./.github/workflows/sbom.yml
449+
442450 # =============================================================================
443451 # Step 3: Merge all artifacts into single dist
444452 # =============================================================================
445453 merge-artifacts :
446454 name : Merge artifacts
447- needs : [build-linux-x86_64, build-linux-aarch64, build-macos-x86_64, build-macos-arm64, build-windows-amd64, build-windows-arm64]
448- if : ${{ !cancelled() && needs.build-linux-x86_64.result == 'success' }}
455+ needs : [build-linux-x86_64, build-linux-aarch64, build-macos-x86_64, build-macos-arm64, build-windows-amd64, build-windows-arm64, generate-sbom ]
456+ if : ${{ !cancelled() && needs.build-linux-x86_64.result == 'success' && needs.generate-sbom.result == 'success' }}
449457 runs-on : ubuntu-24.04
450458 defaults :
451459 run :
@@ -469,6 +477,15 @@ jobs:
469477 name : sdist
470478 path : artifacts/sdist/
471479
480+ - name : Download SBOM artifacts
481+ uses : actions/download-artifact@v8.0.1
482+ with :
483+ name : sbom
484+ path : artifacts/sbom/
485+
486+ - name : Ensure output directories exist
487+ run : mkdir -p dist
488+
472489 - name : Consolidate artifacts and fail on duplicate wheel names
473490 shell : bash
474491 run : |
@@ -522,6 +539,34 @@ jobs:
522539 print(f"Skipped {skipped_identical} identical duplicate wheel artifact(s)")
523540 PY
524541
542+ - name : Add distributed artifacts to merged SBOM
543+ shell : bash
544+ run : |
545+ test -f artifacts/sbom/sbom.cdx.json
546+ docker run --rm \
547+ -v "$PWD:/work" \
548+ -w /work \
549+ cyclonedx/cyclonedx-cli:latest \
550+ add files \
551+ --input-file artifacts/sbom/sbom.cdx.json \
552+ --input-format json \
553+ --output-format json \
554+ --output-file dist/sbom.cdx.json \
555+ --base-path dist \
556+ --include "**/*.whl" "**/*.tar.gz"
557+
558+ - name : Validate release SBOM
559+ shell : bash
560+ run : |
561+ docker run --rm \
562+ -v "$PWD:/work" \
563+ -w /work \
564+ cyclonedx/cyclonedx-cli:latest \
565+ validate \
566+ --input-file dist/sbom.cdx.json \
567+ --input-format json \
568+ --fail-on-errors
569+
525570 - name : Validate wheel archives for duplicate ZIP members
526571 shell : bash
527572 run : |
@@ -834,6 +879,12 @@ jobs:
834879 contents : write
835880
836881 steps :
882+ - name : Download dist artifacts
883+ uses : actions/download-artifact@v8.0.1
884+ with :
885+ name : dist
886+ path : dist/
887+
837888 - name : Create draft release
838889 uses : softprops/action-gh-release@v2
839890 with :
@@ -866,8 +917,14 @@ jobs:
866917
867918 - Python 3.10, 3.11, 3.12, 3.13, 3.14
868919
920+ ### SBOM
921+
922+ - CycloneDX SBOM is included in this release as `sbom.cdx.json`.
923+
869924 ---
870925 *This is a draft release. Wheels are published to PyPI separately.*
926+ files : |
927+ dist/*
871928
872929 # =============================================================================
873930 # Step 6: Publish to PyPI - Trusted Publisher (workflow_dispatch only)
0 commit comments