@@ -259,6 +259,85 @@ jobs:
259259 print('simple SPDX override: ok')
260260 PY
261261
262+ # ---- liboqs / Falcon dep entry ---------------------------------------
263+ # Without this, every code path that emits a dep package - pkg-config
264+ # lookup, supplier/purl/license construction, deterministic UUID
265+ # derivation for deps - is uncovered by CI. A future rename or shape
266+ # break in DEP_META['liboqs'] would silently land.
267+
268+ - name : Install liboqs (provides liboqs.pc for --with-liboqs)
269+ run : sudo apt-get update && sudo apt-get install -y liboqs-dev
270+
271+ - name : Configure with --with-liboqs --enable-falcon
272+ run : |
273+ make distclean
274+ autoreconf -ivf
275+ ./configure --enable-shared --enable-experimental \
276+ --with-liboqs --enable-falcon
277+
278+ - name : Build + generate SBOM with liboqs enabled
279+ run : make sbom
280+
281+ - name : liboqs dep entry resolves to a CVE-trackable identifier
282+ # The point of recording liboqs (rather than `falcon`) is that
283+ # OSV / Grype / Trivy / Dependency-Track key vulnerability
284+ # records off purl + name. These assertions guard the contract
285+ # that pulled the entry away from the algorithm name.
286+ run : |
287+ python3 - <<'PY'
288+ import glob, json, re, sys
289+ with open(glob.glob('wolfssl-*.spdx.json')[0]) as f:
290+ d = json.load(f)
291+ pkgs = {p['name']: p for p in d['packages']}
292+ assert 'liboqs' in pkgs, list(pkgs)
293+ assert 'falcon' not in pkgs, "algorithm name leaked as a dep package"
294+ liboqs = pkgs['liboqs']
295+ assert liboqs['supplier'] == 'Organization: Open Quantum Safe', \
296+ liboqs['supplier']
297+ refs = {r['referenceType']: r['referenceLocator']
298+ for r in liboqs.get('externalRefs', [])}
299+ assert 'purl' in refs, refs
300+ assert re.match(r'pkg:github/open-quantum-safe/liboqs@', refs['purl']), \
301+ refs['purl']
302+ # Algorithm enablement must still be visible via build_props
303+ # (parsed from options.h), not via the dep entry.
304+ props = {p['name']: p['value']
305+ for p in d['packages'][0].get('annotations', [])
306+ if p.get('annotationType') == 'OTHER'}
307+ # CycloneDX side: same package + version present.
308+ with open(glob.glob('wolfssl-*.cdx.json')[0]) as f:
309+ cdx = json.load(f)
310+ deps = {c['name']: c for c in cdx.get('components', [])}
311+ assert 'liboqs' in deps, list(deps)
312+ print('liboqs dep entry: ok ->', refs['purl'])
313+ PY
314+
315+ - name : HAVE_FALCON algorithm flag is captured as a build property
316+ # Algorithm visibility moved out of the dep entry; this verifies
317+ # it is still preserved (just somewhere honest).
318+ run : |
319+ python3 - <<'PY'
320+ import glob, json
321+ with open(glob.glob('wolfssl-*.spdx.json')[0]) as f:
322+ d = json.load(f)
323+ wolf = [p for p in d['packages'] if p['name'] == 'wolfssl'][0]
324+ props = {p['name']: p['value']
325+ for p in wolf.get('annotations', [])
326+ if p.get('annotationType') == 'OTHER'}
327+ # Build props can land as annotations or as a 'attributionTexts'
328+ # block depending on SPDX version; check both.
329+ combined = json.dumps(d)
330+ assert 'HAVE_FALCON' in combined, \
331+ "HAVE_FALCON missing from SBOM build properties"
332+ print('HAVE_FALCON build prop: present')
333+ PY
334+
335+ - name : Restore default build for remaining steps
336+ run : |
337+ make distclean
338+ autoreconf -ivf
339+ ./configure --enable-shared --enable-static
340+
262341 # ---- Distribution + install hooks -----------------------------------
263342
264343 - name : Tarball roundtrip (make dist -> ./configure -> make sbom)
@@ -310,13 +389,14 @@ jobs:
310389 brew install autoconf automake libtool
311390 python3 -m pip install --user --break-system-packages \
312391 'spdx-tools==0.8.*'
313- echo "$HOME/.local/bin" >> "$GITHUB_PATH"
314- # On some macOS runners pyspdxtools lands in
315- # Library/Python/<ver>/bin; symlink to a known-on-PATH location.
316- for d in "$HOME/Library/Python"/*/bin; do
317- [ -x "$d/pyspdxtools" ] && \
318- echo "$d" >> "$GITHUB_PATH"
319- done
392+ # Resolve the actual scripts dir for the python that ran pip,
393+ # rather than guessing a glob like `~/Library/Python/*/bin`.
394+ # `posix_user` is the install scheme `pip install --user` wrote
395+ # to, so this matches even when the runner's selected python
396+ # changes between minor versions / homebrew vs system.
397+ python3 -c \
398+ 'import sysconfig; print(sysconfig.get_path("scripts","posix_user"))' \
399+ >> "$GITHUB_PATH"
320400
321401 - name : Configure wolfSSL (shared)
322402 run : autoreconf -ivf && ./configure --enable-shared
@@ -334,3 +414,102 @@ jobs:
334414 assert re.fullmatch(r'[0-9a-f]{64}', checksum), checksum
335415 print('macOS SBOM checksum well-formed:', checksum)
336416 PY
417+
418+ # Tier 2 (bomsh) - exercises the `make bomsh` target which traces a
419+ # full clean rebuild under bomtrace3 (patched strace, Linux-only) and
420+ # produces an OmniBOR artifact dependency graph. Without this job
421+ # the entire bomsh recipe and its SPDX enrichment step would only be
422+ # exercised by hand; a regression in either would silently land.
423+ bomsh :
424+ name : bomsh integration (linux)
425+ if : github.repository_owner == 'wolfssl'
426+ runs-on : ubuntu-24.04
427+ needs : unit
428+ timeout-minutes : 30
429+ steps :
430+ - uses : actions/checkout@v4
431+
432+ - name : Install build deps + SBOM validators
433+ run : |
434+ sudo apt-get update
435+ sudo apt-get install -y build-essential autoconf automake libtool \
436+ python3 python3-pip git
437+ python3 -m pip install --user --upgrade pip
438+ python3 -m pip install --user 'spdx-tools==0.8.*'
439+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
440+
441+ - name : Install bomsh toolchain (bomtrace3 + helper scripts)
442+ # Bomsh is not packaged; build bomtrace3 (patched strace) from
443+ # source and install the python helpers system-wide so configure's
444+ # AC_PATH_PROG can find them.
445+ run : |
446+ git clone --depth=1 https://github.com/omnibor/bomsh /tmp/bomsh
447+ # bomtrace3 build: docker/devcontainer-only Makefile in upstream;
448+ # use the embedded build script if present, else fall back to
449+ # the strace patch path.
450+ cd /tmp/bomsh
451+ if [ -d .devcontainer/bomtrace3 ]; then
452+ make -C .devcontainer/bomtrace3
453+ sudo install -m 755 .devcontainer/bomtrace3/bomtrace3 \
454+ /usr/local/bin/
455+ else
456+ echo "bomsh repo layout changed; please update CI"
457+ exit 1
458+ fi
459+ sudo install -m 755 scripts/bomsh_create_bom.py /usr/local/bin/
460+ sudo install -m 755 scripts/bomsh_sbom.py /usr/local/bin/
461+ bomtrace3 --version || true
462+ which bomsh_create_bom.py bomsh_sbom.py
463+
464+ - name : Configure wolfSSL
465+ run : autoreconf -ivf && ./configure --enable-shared
466+
467+ - name : Generate SPDX (input to bomsh enrichment)
468+ run : make sbom
469+
470+ - name : Run make bomsh
471+ run : make bomsh
472+
473+ - name : OmniBOR artifact graph produced
474+ # bomsh writes the artifact dependency graph under omnibor/.
475+ # Empty/missing graph means bomtrace3 silently failed to trace.
476+ run : |
477+ test -d omnibor
478+ test "$(find omnibor -type f | wc -l)" -gt 0
479+ echo "omnibor/ contents:"
480+ find omnibor -maxdepth 3 -type f | head -20
481+
482+ - name : Enriched SPDX has PERSISTENT-ID gitoid externalRef
483+ # The whole point of `make bomsh` over `make sbom` is the
484+ # bridge between component identity (SPDX package) and build
485+ # provenance (OmniBOR gitoid). If the enrichment step ran but
486+ # produced an SPDX without the gitoid ref, the bridge is broken.
487+ run : |
488+ ls omnibor.wolfssl-*.spdx.json
489+ python3 - <<'PY'
490+ import glob, json, sys
491+ path = glob.glob('omnibor.wolfssl-*.spdx.json')[0]
492+ with open(path) as f:
493+ d = json.load(f)
494+ gitoid_refs = []
495+ for pkg in d.get('packages', []):
496+ for ref in pkg.get('externalRefs', []):
497+ if (ref.get('referenceCategory') == 'PERSISTENT-ID'
498+ or ref.get('referenceType') == 'gitoid'):
499+ gitoid_refs.append(ref)
500+ assert gitoid_refs, \
501+ f'no PERSISTENT-ID gitoid externalRef in {path}'
502+ print(f'bomsh enrichment ok: {len(gitoid_refs)} gitoid refs')
503+ PY
504+
505+ - name : make clean removes all bomsh + sbom artefacts
506+ # Regression guard: if a future change adds an output to either
507+ # recipe but forgets CLEANFILES, this will catch it.
508+ run : |
509+ make clean
510+ if ls wolfssl-*.spdx.json wolfssl-*.cdx.json \
511+ omnibor.wolfssl-*.spdx.json 2>/dev/null; then
512+ echo "make clean did not remove SBOM/bomsh artefacts"
513+ exit 1
514+ fi
515+ test ! -d omnibor || (echo "omnibor/ not cleaned"; exit 1)
0 commit comments