11name : Generate SBOM
22
3- # Runs on tag pushes matching the vX.Y.Z pattern.
4- # This generates and attaches the SPDX SBOM asset to the GitHub release.
5- # It is idempotent: if the SBOM asset already exists for the tag, it is
6- # overwritten with the fresh scan output.
3+ # Generates and attaches an SPDX SBOM to the GitHub release for the pushed
4+ # version tag. Runs only on vX.Y.Z tag pushes; the SBOM asset is uploaded
5+ # (or replaced) via the GitHub Releases API. Idempotent: if the asset
6+ # already exists it is deleted and re-uploaded with fresh scan output.
7+
78on :
89 push :
910 tags :
1011 - " v*"
1112
12- permissions :
13- contents : read
14- pull-requests : read
13+ permissions : {}
1514
1615concurrency :
1716 group : sbom-${{ github.ref }}
@@ -22,72 +21,76 @@ jobs:
2221 name : Generate and Attach SBOM
2322 runs-on : ubuntu-latest
2423 timeout-minutes : 30
24+ permissions :
25+ contents : write # upload SBOM asset to the GitHub release
2526
2627 steps :
2728 - name : Checkout code
28- uses : actions/checkout@v4
29+ uses : actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
2930 with :
3031 persist-credentials : false
3132
32- - name : Set up Go
33- uses : actions/setup-go@v5
34- with :
35- go-version-file : go.mod
36-
37- - name : Install Syft (pinned version)
33+ - name : Install Syft (pinned version with checksum verification)
34+ env :
35+ SYFT_VERSION : " 1.41.0"
3836 run : |
39- curl -sSfL https://raw.githubusercontent.com/anchore/syft/v$SYFT_VERSION/install.sh | sh -s -- -b /usr/local/bin
37+ curl -sSfL -o syft.tar.gz \
38+ "https://github.com/anchore/syft/releases/download/v${SYFT_VERSION}/syft_${SYFT_VERSION}_linux_amd64.tar.gz"
39+ curl -sSfL -o syft_checksums.txt \
40+ "https://github.com/anchore/syft/releases/download/v${SYFT_VERSION}/syft_${SYFT_VERSION}_checksums.txt"
41+ # Verify the downloaded archive against the published checksum for this exact asset.
42+ EXPECTED=$(awk '$2 == "syft_'${SYFT_VERSION}'_linux_amd64.tar.gz" {print $1}' syft_checksums.txt)
43+ echo "${EXPECTED} syft.tar.gz" | sha256sum -c -
44+ tar -xzf syft.tar.gz syft
45+ sudo mv syft /usr/local/bin/syft
46+ rm -f syft.tar.gz syft_checksums.txt
4047
4148 - name : Generate SBOM (SPDX format)
42- # Scan the project directory and output an SPDX SBOM file.
43- env :
44- SYFT_VERSION : ' v1.41.0'
4549 run : |
4650 syft . -o spdx-json=sbom.spdx.json
4751
4852 - name : Find release ID for the pushed tag
4953 id : release
54+ env :
55+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
5056 run : |
5157 TAG_NAME="${GITHUB_REF#refs/tags/}"
52- # Query the GitHub API for a release with this tag name
53- RELEASE_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
54- "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/tags/$TAG_NAME" \
58+ RELEASE_ID=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
59+ "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG_NAME}" \
5560 | jq -r '.id')
5661
57- if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then
58- echo "release_id=" >> "$GITHUB_OUTPUT"
62+ if [ -z "${ RELEASE_ID} " ] || [ "${ RELEASE_ID} " = "null" ]; then
63+ echo "release_id=" >> "${ GITHUB_OUTPUT} "
5964 else
60- echo "release_id=$RELEASE_ID" >> "$GITHUB_OUTPUT"
65+ echo "release_id=${ RELEASE_ID} " >> "${ GITHUB_OUTPUT} "
6166 fi
6267
6368 - name : Check for existing SBOM asset and upload
6469 if : steps.release.outputs.release_id != '' && steps.release.outputs.release_id != 'null'
70+ env :
71+ GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
72+ RELEASE_ID : ${{ steps.release.outputs.release_id }}
6573 run : |
66- RELEASE_ID="${{ steps.release.outputs.release_id }}"
67-
6874 # Check if an SBOM asset with this name already exists in the release
69- ASSET_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
75+ ASSET_ID=$(curl -s -H "Authorization: token ${ GITHUB_TOKEN} " \
7076 "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets" \
7177 | jq -r ".[] | select(.name == \"sbom.spdx.json\") | .id")
7278
73- if [ -n "$ASSET_ID" ] && [ "$ASSET_ID" != "null" ]; then
79+ if [ -n "${ ASSET_ID} " ] && [ "${ ASSET_ID} " != "null" ]; then
7480 # Delete existing SBOM asset so we can re-upload the fresh scan
75- curl -s -X DELETE -H "Authorization: token $GITHUB_TOKEN" \
76- "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/$ASSET_ID" > /dev/null
81+ curl -s -X DELETE -H "Authorization: token ${ GITHUB_TOKEN} " \
82+ "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${ ASSET_ID} " > /dev/null
7783 echo "Deleted existing sbom.spdx.json asset"
7884 fi
7985
8086 # Upload the SBOM as a release asset
81- curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \
87+ curl -s -X POST -H "Authorization: token ${ GITHUB_TOKEN} " \
8288 -H "Content-Type: application/spdx+json" \
8389 --data-binary @sbom.spdx.json \
8490 "https://uploads.github.com/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets" > /dev/null
85- echo "Uploaded sbom.spdx.json to release $RELEASE_ID"
91+ echo "Uploaded sbom.spdx.json to release ${ RELEASE_ID} "
8692
8793 - name : Notify if no release found for tag
8894 if : steps.release.outputs.release_id == '' || steps.release.outputs.release_id == 'null'
8995 run : |
90- echo "::notice::No GitHub Release found for tag ${GITHUB_REF#refs/tags/}. "
91- echo "The SBOM was generated at ./sbom.spdx.json but was not attached to a release."
92- echo "Ensure the tag was created by the release-please process "
93- "or manually create a release draft."
96+ echo "::notice::No GitHub Release found for tag ${GITHUB_REF#refs/tags/}. The SBOM was generated at ./sbom.spdx.json but was not attached to a release. Ensure the tag was created by the release-please process or manually create a release draft."
0 commit comments