fix: prefer Syft over cdxgen for Docker image SBOMs - #273
Conversation
cdxgen image SBOMs lack the operating-system component and distro metadata, so vulnerability scanners can't detect OS packages: Trivy bails with 'Unsupported os family=none' and scans nothing, which also breaks Dependency-Track's Trivy analyzer. Syft image SBOMs carry the OS component and distro PURL qualifiers, and survive the full augment/enrich pipeline intact — Trivy and Grype both scan them correctly. Swap the image generator priorities (lockfile generators unchanged): - syft-image: 35 -> 25 (preferred) - cdxgen-image: 20 -> 40 (fallback when Syft is unavailable, and the only generator for CycloneDX 1.7 image requests, which Syft does not support) Verified against gcr.io/distroless/cc-debian13: Trivy now detects 'debian 13' and scans all 13 packages; Grype reports the same 12 CVEs as against a raw syft SBOM. Package coverage is equal or better — cdxgen's extra entries were source-package duplicates and pkg:generic noise (shared-object filenames, license IDs). Fixes #264 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the generator registry’s Docker image selection so Syft is preferred over cdxgen, addressing missing OS/distro metadata in cdxgen image SBOMs that prevents downstream vulnerability scanners (e.g., Trivy / Dependency-Track analyzer) from scanning OS packages.
Changes:
- Reordered image generator priorities:
syft-image→ 25 (preferred),cdxgen-image→ 40 (fallback). - Updated registry documentation and README generator selection docs to reflect the new image preference and rationale.
- Adjusted unit tests to assert the new priority values and ordering for Docker image generation.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/test_generation_plugin.py | Updates tests to reflect new generator ordering/priorities for Docker images. |
| sbomify_action/_generation/generators/syft.py | Lowers SyftImageGenerator priority to prefer it for Docker images; adds rationale docs. |
| sbomify_action/_generation/generators/cdxgen.py | Raises CdxgenImageGenerator priority so it becomes the Docker image fallback; updates rationale/docs. |
| sbomify_action/_generation/generator.py | Reorders default registry registration and updates priority documentation to match new behavior. |
| README.md | Updates user-facing generator selection documentation to reflect Syft-first for Docker images. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Syft is a comprehensive SBOM generator that supports version selection. | ||
| It supports more versions than Trivy but is slightly lower priority. |
There was a problem hiding this comment.
Fixed in ff6a3b4 — reworded the module docstring so the Trivy comparison is scoped to lock files, and states that for Docker images Syft now ranks higher than both Trivy and cdxgen.
- Fix the syft.py module docstring: the "slightly lower priority than Trivy" comparison only holds for lock files now; for Docker images Syft ranks higher than both Trivy and cdxgen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| # run_command raises SBOMGenerationError on failure (uses check=True). | ||
| # log_errors=False: cdxgen image scanning is a priority-20 fallback | ||
| # ahead of syft; a benign failure here shouldn't spam ERROR when syft | ||
| # can still succeed. (Docker-image-not-found is handled separately and | ||
| # still logs at WARNING.) | ||
| # log_errors=False: cdxgen image scanning is a fallback behind syft; | ||
| # a benign failure here shouldn't spam ERROR — the orchestrator | ||
| # surfaces a real ERROR only if every generator fails. | ||
| # (Docker-image-not-found is handled separately and still logs at | ||
| # WARNING.) |
There was a problem hiding this comment.
Fixed in 2b97439 — reworded to say the pipeline raises SBOMGenerationError when every generator fails, rather than claiming the orchestrator logs an ERROR (the registry logs failures at INFO, as you noted).
- Fix the log_errors comment in CdxgenImageGenerator: the registry logs generator failures at INFO; what actually surfaces an all-generators failure is the SBOMGenerationError raised by the pipeline, not an ERROR log from the orchestrator. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| Priority 20 - Comprehensive Multi-Ecosystem (cdxgen, lock files): | ||
| - CdxgenFsGenerator: Filesystem/lock file scanning | ||
| - Input: Python, JavaScript, Java/Gradle, Go, Rust, Ruby, Dart, C++, | ||
| PHP, .NET, Swift, Elixir, Scala | ||
| - Output: CycloneDX 1.4-1.7 (no SPDX support) |
There was a problem hiding this comment.
Fixed in e6b6f87 — updated the generators/init.py docstring to the new priorities (syft-image 25, cdxgen-image 40) and reordered the list by priority. Also swept the generation module for any other stale priority references; none remain.
- Update the generators/__init__.py docstring to the new image generator priorities (syft-image 25, cdxgen-image 40), reordered by priority. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
This PR closes #232 |
Fixes #264
Problem
For Docker images, the generator registry preferred
cdxgen-image(priority 20) oversyft-image(priority 35). cdxgen image SBOMs lack theoperating-systemcomponent and distro metadata, so vulnerability scanners can't detect OS packages:Unsupported os family="none"and scans nothing — which also breaks Dependency-Track's Trivy analyzer, the workflow reported in the issue.Reproduction confirmed the pipeline itself is not the problem: a Syft-generated SBOM run through the full sbomify pipeline (augment + enrich) keeps the
operating-systemcomponent, and both Trivy and Grype scan it correctly. Only the generator choice was wrong.Fix
Swap the image generator priorities — lockfile generators are untouched:
syft-imagecdxgen-imagecdxgen remains the fallback when Syft isn't installed, and is still automatically selected for CycloneDX 1.7 image requests (Syft caps at 1.6 — the registry's version-based selection handles this, verified).
Verification
Against
gcr.io/distroless/cc-debian13:latestviasbomify-action --docker-image ... --no-upload --enrich:Before (cdxgen selected):
After (syft selected):
(Trivy showing 0 vulnerabilities on this image is expected — same result as the issue author's raw-syft test; the CVEs Grype lists are Debian no-advisory/"won't fix" entries Trivy filters.)
Package coverage check (steelman): compared Syft vs cdxgen image SBOMs on distroless and
python:3.13-alpine. Language-package coverage is at parity (identicalpypipurls); cdxgen's "extra" entries were source-package duplicates of installed binaries (glibcvslibc6,opensslvslibssl3) plus hundreds ofpkg:generic/*noise components (shared-object filenames, even license IDs likepkg:generic/Apache-2.0). Syft additionally catalogs the interpreter binary cdxgen misses. Nothing of value is lost.uv run pytest: 2413 passed, 4 skippedruff check/ruff format --check: clean🤖 Generated with Claude Code