Skip to content

Commit 9a694cf

Browse files
michaeldcanadyopencode
andauthored
chore: add consolidated SBOM generation workflow (#765)
* chore: add consolidated SBOM generation workflow - Single sbom.yml workflow replaces duplicate sbom-release.yml - Pinned syft version (v1.41.0) for supply-chain integrity - Uses gh-token GITHUB_TOKEN for release asset management - Idempotent: deletes existing SBOM asset before re-upload - Fixed shell syntax (no stray quoted string) - Runs on v* tag pushes only * chore(ci): fix SBOM workflow blocking review findings Resolve the issues that blocked PR #764: fix the stray quoted string in the final run block, move the syft SYFT_VERSION env onto the install step and drop its double-v, SHA-pin checkout and drop the unused setup-go step, and replace the moving curl|sh syft install with a pinned release download verified against its published checksum. Scope release-upload permissions to the job and move RELEASE_ID into env to silence zizmor. The workflow now passes zizmor with no findings. Co-authored-by: opencode <opencode@local> --------- Co-authored-by: opencode <opencode@local>
1 parent ea85dc4 commit 9a694cf

1 file changed

Lines changed: 96 additions & 0 deletions

File tree

.github/workflows/sbom.yml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: Generate SBOM
2+
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+
8+
on:
9+
push:
10+
tags:
11+
- "v*"
12+
13+
permissions: {}
14+
15+
concurrency:
16+
group: sbom-${{ github.ref }}
17+
cancel-in-progress: false
18+
19+
jobs:
20+
generate-sbom:
21+
name: Generate and Attach SBOM
22+
runs-on: ubuntu-latest
23+
timeout-minutes: 30
24+
permissions:
25+
contents: write # upload SBOM asset to the GitHub release
26+
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
30+
with:
31+
persist-credentials: false
32+
33+
- name: Install Syft (pinned version with checksum verification)
34+
env:
35+
SYFT_VERSION: "1.41.0"
36+
run: |
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
47+
48+
- name: Generate SBOM (SPDX format)
49+
run: |
50+
syft . -o spdx-json=sbom.spdx.json
51+
52+
- name: Find release ID for the pushed tag
53+
id: release
54+
env:
55+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56+
run: |
57+
TAG_NAME="${GITHUB_REF#refs/tags/}"
58+
RELEASE_ID=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
59+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/tags/${TAG_NAME}" \
60+
| jq -r '.id')
61+
62+
if [ -z "${RELEASE_ID}" ] || [ "${RELEASE_ID}" = "null" ]; then
63+
echo "release_id=" >> "${GITHUB_OUTPUT}"
64+
else
65+
echo "release_id=${RELEASE_ID}" >> "${GITHUB_OUTPUT}"
66+
fi
67+
68+
- name: Check for existing SBOM asset and upload
69+
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 }}
73+
run: |
74+
# Check if an SBOM asset with this name already exists in the release
75+
ASSET_ID=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \
76+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets" \
77+
| jq -r ".[] | select(.name == \"sbom.spdx.json\") | .id")
78+
79+
if [ -n "${ASSET_ID}" ] && [ "${ASSET_ID}" != "null" ]; then
80+
# Delete existing SBOM asset so we can re-upload the fresh scan
81+
curl -s -X DELETE -H "Authorization: token ${GITHUB_TOKEN}" \
82+
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/assets/${ASSET_ID}" > /dev/null
83+
echo "Deleted existing sbom.spdx.json asset"
84+
fi
85+
86+
# Upload the SBOM as a release asset
87+
curl -s -X POST -H "Authorization: token ${GITHUB_TOKEN}" \
88+
-H "Content-Type: application/spdx+json" \
89+
--data-binary @sbom.spdx.json \
90+
"https://uploads.github.com/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets" > /dev/null
91+
echo "Uploaded sbom.spdx.json to release ${RELEASE_ID}"
92+
93+
- name: Notify if no release found for tag
94+
if: steps.release.outputs.release_id == '' || steps.release.outputs.release_id == 'null'
95+
run: |
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

Comments
 (0)