Skip to content

[scanner-registry] Emit trivy JSON + mount workdir for relationship stamping - #270

Closed
Dyc0de wants to merge 4 commits into
boost-community:mainfrom
boostsecurityio:194-trivy-json-relationship
Closed

[scanner-registry] Emit trivy JSON + mount workdir for relationship stamping#270
Dyc0de wants to merge 4 commits into
boost-community:mainfrom
boostsecurityio:194-trivy-json-relationship

Conversation

@Dyc0de

@Dyc0de Dyc0de commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Why

The trivy SBOM modules piped CycloneDX straight to stdout. CycloneDX drops trivy's native dependency graph, so the post-processor had no way to tell a direct dependency from a transitive one — the root cause of the "direct deps reported as transitive" bug.

What

boost-sca, trivy-sbom and trivy-sbom-image now run trivy once to trivy-report.json, then trivy convert --format cyclonedx that report to stdout. The CycloneDX the post-processor consumes is unchanged; the JSON graph stays behind in the scan dir, where workdir: /app makes the executor mount it into the post-processor container. The bumped post-processor image is the build that reads that report and stamps boost:relationship.

Per module:

  • scanners/boostsecurityio/boost-sca/module.yaml — scan becomes trivy fs … --format=json --output=trivy-report.json; every other flag is untouched (cache dir, --license-full, --no-progress, --scanners vuln, --skip-version-check, the 2>"$LOG" handling with both cat "$LOG" lines and exit "$ec"). On success it runs trivy convert --quiet --format cyclonedx trivy-report.json. Post-processor gains workdir: /app, image → …boost-scanner-trivy-sbom:68831d5@sha256:2b7878a7….
  • scanners/boostsecurityio/trivy-sbom/module.yaml — same three changes, keeping its ${TRIVY_ADDITIONAL_ARGS} position.
  • scanners/boostsecurityio/trivy-sbom-image/module.yamltrivy image … --format json --output trivy-report.json … && trivy convert --quiet --format cyclonedx trivy-report.json, still one folded scalar. Same workdir: /app + image bump.

Two deliberate choices:

  1. convert runs only when the scan succeeded (ec == 0 for the fs modules, && for the image module) — otherwise a failed scan surfaces as a confusing "trivy-report.json not found" instead of trivy's real error.
  2. --quiet on convert so its INFO lines don't land in $LOG and from there onto stdout, where the post-processor greps the "no language files" signal.

Output equivalence

Verified with the module's own pinned trivy 0.69.2 (binary sha256-checked against the module's MACOS_ARM64_SHA) against a real poetry.lock: old command and new --format=json + convert both emit 177627 bytes, and the documents are identical after dropping trivy's per-run serialNumber/timestamp and normalizing its random non-purl bom-ref UUIDs.

Worth knowing: two runs of the old command are not byte-identical to each other either — those random UUIDs also reorder the dependencies array. So the accurate invariant is "unchanged modulo trivy's own per-run randomness", not literal byte-equality. convert produced no stderr and needed no network or DB pull.

Relates to boostsecurityio/workspace#194

🤖 Generated with Claude Code

The trivy SBOM modules piped CycloneDX straight to stdout, which drops
trivy's native dependency graph -- the post-processor had no way to tell a
direct dependency from a transitive one.

Run trivy once to `trivy-report.json`, then `trivy convert --format cyclonedx`
that report to stdout, so the CycloneDX the post-processor consumes is
unchanged while the JSON graph stays behind in the scan dir. `workdir: /app`
makes the executor mount that dir into the post-processor container, and the
bumped image is the build that reads the report and stamps `boost:relationship`.

Relates to boostsecurityio/workspace#194

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dyc0de and others added 3 commits August 6, 2026 14:46
The executor bind-mounts the scan dir AT the workdir
(boostsec-scanner-cli executor.py:273, `mounts = {str(srcdir): definition.workdir}`),
and the post-processor image installs itself under /app -- so `workdir: /app`
mounted the scan dir over the image's own entrypoint and the container died with
`exec: "boost-convert-trivy-sbom": executable file not found in $PATH`.

/scan collides with nothing and the post-processor reads trivy-report.json
relative to cwd, so the mount still does its job.

Relates to boostsecurityio/workspace#194

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`trivy image --format cyclonedx` defaults to SBOM-only, but `--format json`
defaults to the vuln,secret scanners -- and `trivy convert` carries those
findings into the CycloneDX. The rewrite therefore made trivy-sbom-image start
reporting image vulnerabilities it never reported before (4 on alpine:3.19).

`--scanners ""` restores SBOM-only; `--list-all-pkgs` keeps every package in the
JSON report. Relationship data is independent of the scanner set, so language
packages in an image still get stamped.

Verified on alpine:3.19 with the pinned trivy 0.69.2: old and new both give 16
components / 0 vulnerabilities and are identical modulo trivy's per-run UUIDs;
without `--scanners ""` the new pipeline yields 4 vulnerabilities.

Relates to boostsecurityio/workspace#194

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The convert narration restated what the code plainly does. What's left is the
two gotchas that guard silent, CI-invisible regressions: why workdir can't be
/app, and why --scanners "" has to stay.

Relates to boostsecurityio/workspace#194

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Dyc0de

Dyc0de commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #271 — moved to a same-repo branch on boost-community/scanner-registry (now that push access exists) so scan-test actually runs instead of stalling on the fork-approval gate. Identical head commit (50318c0).

@Dyc0de Dyc0de closed this Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant