diff --git a/.github/workflows/test-sbom.yml b/.github/workflows/test-sbom.yml index a601c06c..95bf5999 100644 --- a/.github/workflows/test-sbom.yml +++ b/.github/workflows/test-sbom.yml @@ -31,6 +31,9 @@ name: Wolfboot SBOM Canary # spread of architectures (Arm-M, Arm-A, PowerPC, Renesas RX and RISC-V). The # driver never calls the cross compiler, so the SBOM is produced for a target # whose toolchain is absent. +# +# The wolfglass_drift job holds tools/sbom/ to the revision it claims, so the +# vendored copy cannot drift from wolfGlass unnoticed. on: push: @@ -316,6 +319,62 @@ jobs: wolfboot-*.spdx.json if-no-files-found: warn + # tools/sbom/ is a vendored copy of the wolfGlass share/ set, pinned by + # tools/sbom/.wolfglass-rev. Nothing else proves the copy still matches the + # pin, so a stale copy, a local patch, or an unresolvable revision would all + # pass unnoticed and wolfBoot would ship a different generator from the one + # wolfSSL controls. wolfGlass owns the comparison: tools/wolfglass-sync + # --check diffs share/ against the vendored tree and compares HEAD against + # .wolfglass-rev. + wolfglass_drift: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v4 + + - name: Read the pinned wolfGlass revision + id: pin + run: | + rev="$(tr -d '[:space:]' < tools/sbom/.wolfglass-rev)" + if [ -z "$rev" ]; then + echo "ERROR: tools/sbom/.wolfglass-rev is empty." >&2 + exit 1 + fi + echo "rev=$rev" >> "$GITHUB_OUTPUT" + echo "Pinned wolfGlass revision: $rev" + + # A fork PR has no secret, so the pinned revision cannot be fetched. Skip + # rather than fail there; the run on wolfSSL/wolfBoot is the gate. + - name: Check out wolfGlass at the pinned revision + id: fetch + continue-on-error: true + uses: actions/checkout@v4 + with: + repository: wolfSSL/wolfGlass + ref: ${{ steps.pin.outputs.rev }} + token: ${{ secrets.WOLFGLASS_TOKEN }} + path: .wolfglass-src + + - name: Drift check against wolfGlass + env: + HAVE_TOKEN: ${{ secrets.WOLFGLASS_TOKEN != '' }} + PINNED_REV: ${{ steps.pin.outputs.rev }} + run: | + if [ ! -d .wolfglass-src/share ]; then + if [ "$HAVE_TOKEN" != "true" ]; then + echo "::notice::No WOLFGLASS_TOKEN available (fork PR); skipping the wolfGlass drift check." + exit 0 + fi + echo "ERROR: wolfGlass revision $PINNED_REV does not resolve." >&2 + echo "tools/sbom/.wolfglass-rev must name a commit that exists in" >&2 + echo "wolfSSL/wolfGlass. Re-run tools/wolfglass-sync to re-pin." >&2 + exit 1 + fi + git config --global --add safe.directory "$GITHUB_WORKSPACE/.wolfglass-src" + python3 .wolfglass-src/tools/wolfglass-sync \ + --check --src .wolfglass-src --dest . + windows_sbom: runs-on: windows-latest timeout-minutes: 10 diff --git a/docs/SBOM.md b/docs/SBOM.md index e7385f69..84960b83 100644 --- a/docs/SBOM.md +++ b/docs/SBOM.md @@ -353,6 +353,13 @@ sim configuration and runs a native-Windows scrub test against `tools/sbom/sbom-driver.py`. The generated SBOMs are uploaded as build artifacts. +The same workflow holds `tools/sbom/` to the revision in +`tools/sbom/.wolfglass-rev`. It checks wolfGlass out at that revision and runs +`tools/wolfglass-sync --check`, which fails if a vendored file differs from +wolfGlass `share/`, or if the pinned revision does not resolve. A local patch to +the vendored tooling therefore breaks CI instead of shipping quietly: fix +wolfGlass and re-vendor. + ## Reproducibility `gen-sbom` supports deterministic output (e.g. `SOURCE_DATE_EPOCH` and stable diff --git a/tools/sbom/.wolfglass-rev b/tools/sbom/.wolfglass-rev index c0f21c59..5d7db5d7 100644 --- a/tools/sbom/.wolfglass-rev +++ b/tools/sbom/.wolfglass-rev @@ -1 +1 @@ -1bfcf4f1a293ba09f0ff6d67904dca09ee8eb6d7 +d34a906638444b6990218a49927bcebafc5a539b