-
Notifications
You must be signed in to change notification settings - Fork 45
feat: add make sbom / install-sbom / uninstall-sbom targets #258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
52f9a73
7a24607
ae18176
6fd9382
cdac833
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| name: SBOM Test | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ 'master', 'main', 'release/**' ] | ||
| pull_request: | ||
| branches: [ '*' ] | ||
| workflow_dispatch: | ||
| inputs: | ||
| wolfssl_ref: | ||
| description: 'wolfssl git ref that provides scripts/gen-sbom' | ||
| # TODO: switch back to 'master' once wolfSSL/wolfssl#10343 merges. | ||
| default: 'refs/pull/10343/head' | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| # This workflow only reads the repo and uploads artefacts; no API writes. | ||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| sbom: | ||
| name: wolfCLU SBOM generation (linux) | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 20 | ||
| steps: | ||
| - name: Checkout wolfclu | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| path: wolfclu | ||
|
|
||
| # wolfssl is built + installed so wolfCLU has a library to link, and its | ||
| # source tree (scripts/gen-sbom + wolfssl/version.h) is passed to | ||
| # `make sbom` via WOLFSSL_DIR. gen-sbom is not yet on wolfssl master, so | ||
| # default to the open PR head that carries it (wolfSSL/wolfssl#10343) so CI | ||
| # actually exercises `make sbom` instead of silently skipping. TODO: | ||
| # switch the fallback back to 'master' once #10343 merges. | ||
| - name: Checkout wolfssl (gen-sbom + library source) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ⚪ [Info] CI builds and executes code from an unmerged external PR ref by default · Security The workflow defaults the wolfssl checkout to Fix: Track the TODO to switch the default ref back to |
||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: wolfSSL/wolfssl | ||
| ref: ${{ github.event.inputs.wolfssl_ref || 'refs/pull/10343/head' }} | ||
| path: wolfssl | ||
|
|
||
| - name: Install SBOM validator (pyspdxtools) | ||
| run: | | ||
| python3 -m pip install --user 'spdx-tools==0.8.*' | ||
| echo "$HOME/.local/bin" >> "$GITHUB_PATH" | ||
|
|
||
| # --enable-all gives wolfCLU the OpenSSL-compat / cert-req APIs it links. | ||
| - name: Build and install wolfssl | ||
| working-directory: wolfssl | ||
| run: | | ||
| autoreconf -ivf | ||
| ./configure --enable-all --prefix="$GITHUB_WORKSPACE/wolfssl-install" | ||
| make -j"$(nproc)" | ||
| make install | ||
|
|
||
| # gen-sbom lives in wolfssl and may not be on the checked-out ref yet (the | ||
| # wolfSSL SBOM change can land separately). Gate on its presence so this | ||
| # workflow is safe even if the ref is changed to one without it. | ||
| - name: Detect gen-sbom availability and capabilities | ||
| id: gate | ||
| run: | | ||
| GS="$GITHUB_WORKSPACE/wolfssl/scripts/gen-sbom" | ||
| if [ ! -f "$GS" ]; then | ||
| echo "have=no" >> "$GITHUB_OUTPUT" | ||
| echo "::notice::wolfssl scripts/gen-sbom not present on this ref; skipping SBOM generation." | ||
| exit 0 | ||
| fi | ||
| echo "have=yes" >> "$GITHUB_OUTPUT" | ||
| if python3 "$GS" --help 2>/dev/null | grep -q -- '--dep-wolfssl'; then | ||
| echo "dep_wolfssl=yes" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "dep_wolfssl=no" >> "$GITHUB_OUTPUT" | ||
| echo "::notice::gen-sbom on this ref has no --dep-wolfssl; the wolfssl dependency + name-derived identity assertions will be skipped." | ||
| fi | ||
|
|
||
| - name: Configure and build wolfclu | ||
| if: steps.gate.outputs.have == 'yes' | ||
| working-directory: wolfclu | ||
| run: | | ||
| autoreconf -ivf | ||
| ./configure --with-wolfssl="$GITHUB_WORKSPACE/wolfssl-install" | ||
| make -j"$(nproc)" | ||
|
|
||
| - name: Generate SBOM | ||
| if: steps.gate.outputs.have == 'yes' | ||
| working-directory: wolfclu | ||
| run: make sbom WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl" | ||
|
|
||
| - name: Outputs exist and SPDX validates | ||
| if: steps.gate.outputs.have == 'yes' | ||
| working-directory: wolfclu | ||
| run: | | ||
| ls wolfclu-*.cdx.json wolfclu-*.spdx.json wolfclu-*.spdx | ||
| pyspdxtools --infile wolfclu-*.spdx.json | ||
|
|
||
| - name: CycloneDX identity and licence | ||
| if: steps.gate.outputs.have == 'yes' | ||
| working-directory: wolfclu | ||
| run: | | ||
| python3 - <<'PY' | ||
| import glob, json | ||
| cdx = json.load(open(glob.glob('wolfclu-*.cdx.json')[0])) | ||
| assert cdx['bomFormat'] == 'CycloneDX', cdx.get('bomFormat') | ||
| assert cdx['specVersion'] == '1.6', cdx.get('specVersion') | ||
| m = cdx['metadata']['component'] | ||
| assert m['name'] == 'wolfclu', m['name'] | ||
| assert m['purl'].startswith('pkg:github/wolfSSL/wolfclu@'), m['purl'] | ||
| # Default override must land as GPL-3.0-or-later (matches source headers). | ||
| ids = [l.get('license', {}).get('id') for l in m.get('licenses', [])] | ||
| assert 'GPL-3.0-or-later' in ids, ids | ||
| # Embedded identity is the hashed binary artifact. | ||
| assert {h['alg'] for h in m.get('hashes', [])}, 'no component hash' | ||
| print('CDX ok:', m['name'], m['purl'], ids) | ||
| PY | ||
|
|
||
| - name: Reproducible across two runs (SOURCE_DATE_EPOCH) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 [Low] Reproducibility CI step excludes the .spdx tag-value output from the byte-identical check · Test The reproducibility test hashes and diffs only Fix: Include |
||
| if: steps.gate.outputs.have == 'yes' | ||
| working-directory: wolfclu | ||
| run: | | ||
| rm -f wolfclu-*.cdx.json wolfclu-*.spdx.json wolfclu-*.spdx | ||
| SOURCE_DATE_EPOCH=1700000000 make sbom \ | ||
| WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl" | ||
| sha256sum wolfclu-*.cdx.json wolfclu-*.spdx.json > /tmp/a.sums | ||
| rm -f wolfclu-*.cdx.json wolfclu-*.spdx.json wolfclu-*.spdx | ||
| SOURCE_DATE_EPOCH=1700000000 make sbom \ | ||
| WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl" | ||
| sha256sum wolfclu-*.cdx.json wolfclu-*.spdx.json > /tmp/b.sums | ||
| diff /tmp/a.sums /tmp/b.sums | ||
|
|
||
| - name: wolfssl recorded as a dependency | ||
| if: steps.gate.outputs.have == 'yes' && steps.gate.outputs.dep_wolfssl == 'yes' | ||
| working-directory: wolfclu | ||
| run: | | ||
| python3 - <<'PY' | ||
| import glob, json | ||
| d = json.load(open(glob.glob('wolfclu-*.spdx.json')[0])) | ||
| assert 'wolfssl' in {p['name'] for p in d['packages']}, \ | ||
| [p['name'] for p in d['packages']] | ||
| rels = [(r['spdxElementId'], r['relationshipType'], | ||
| r['relatedSpdxElement']) for r in d['relationships']] | ||
| assert ('SPDXRef-Package-wolfclu', 'DEPENDS_ON', | ||
| 'SPDXRef-Package-wolfssl') in rels, rels | ||
| print('wolfssl dependency ok') | ||
| PY | ||
|
|
||
| - name: Upload SBOM artefacts | ||
| if: always() && steps.gate.outputs.have == 'yes' | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: wolfclu-sbom-${{ github.sha }} | ||
| path: | | ||
| wolfclu/wolfclu-*.cdx.json | ||
| wolfclu/wolfclu-*.spdx.json | ||
| wolfclu/wolfclu-*.spdx | ||
| if-no-files-found: warn | ||
| retention-days: 90 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,6 +59,13 @@ AM_PATH_PYTHON([3.6],, [:]) | |
| AC_SUBST([PYTHON]) | ||
| AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != ":"]) | ||
|
|
||
| # Tools used by the SBOM targets (see scripts/sbom.am `make sbom`). GIT is used | ||
| # only to derive SOURCE_DATE_EPOCH for reproducible SBOM output; all three are | ||
| # optional and the target reports a clear error when a required one is missing. | ||
| AC_PATH_PROG([PYTHON3], [python3]) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 [Low] AC_PATH_PROG([PYTHON3]) duplicates AM_PATH_PYTHON and requires an executable literally named 'python3' · Convention configure.ac already runs Fix: Either fall back to |
||
| AC_PATH_PROG([PYSPDXTOOLS], [pyspdxtools]) | ||
| AC_PATH_PROG([GIT], [git]) | ||
|
|
||
| # Checks for headers/libraries | ||
| AC_CHECK_HEADERS([sys/time.h string.h termios.h unistd.h]) | ||
| AC_CHECK_SIZEOF(long long, 8) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 [Low] pull_request branch filter '*' won't match base branches containing a slash · Logic
The
pushtrigger targets[ 'master', 'main', 'release/**' ], but thepull_requesttrigger filters the base branch with[ '*' ]. In GitHub Actions branch filters,*matches only single-segment branch names (no/separator), so pull requests whose base is arelease/**branch will not run the SBOM workflow, even though direct pushes to those branches do. This is a coverage inconsistency, not a security issue — SBOM regressions could merge into a release branch via PR without the check firing. Severity views differ across modes:reviewrated this Low/NIT andreview-securityrated it Info; the stricter Low is retained.Fix: Use
[ '**' ](or explicitly listmaster,main,release/**) in thepull_request.branchesfilter so PRs into release branches also run the SBOM check, matching the intent of thepushtrigger'srelease/**.