Skip to content

feat: add reusable SBOM publish and Trivy security scan workflows - #23

Merged
TheMeinerLP merged 1 commit into
mainfrom
feat/supply-chain-workflows
Aug 8, 2026
Merged

feat: add reusable SBOM publish and Trivy security scan workflows#23
TheMeinerLP merged 1 commit into
mainfrom
feat/supply-chain-workflows

Conversation

@TheMeinerLP

Copy link
Copy Markdown
Contributor

Makes Dependency-Track and Trivy org-wide mechanics instead of per-repo copy-paste. Prompted by the AntiRedstoneClock-Remastered 2.9.0 release, where the SBOM upload lived inside the release job and one rejected platform version cost the JAR, both platform releases and the SBOM in one go.

Preconditions are already in place: DEPENDENCYTRACK_HOSTNAME and DEPENDENCYTRACK_APIKEY are organisation secrets, so secrets: inherit covers every repo with no per-repo setup.

sbom-publish.yml

Publishes a CycloneDX SBOM to Dependency-Track. The SBOM comes from one of two places:

artifact-name Source When
set artifact from an upstream job the project already emits an SBOM (e.g. the CycloneDX Gradle plugin) — a build tool resolves the dependency graph better than any external scanner
empty Trivy filesystem scan the project has no SBOM generator; zero setup

Runs as its own job by design. Dependency-Track being unreachable or rejecting a key must not take down the release that produced the artifact.

security-scan.yml

Trivy scan with findings pushed to GitHub code scanning.

  • Report-only by default. Adopting this should make vulnerabilities visible, not turn a repo's CI red on day one. fail-on-findings: true gates once a repo is clean enough to keep it that way.
  • limit-severities-for-sarif: true. Without it Trivy ignores severity for SARIF output and uploads every severity, so code scanning would show a different set than the gate fails on.
  • Two passes when gating. The report pass always exits 0 — a non-zero exit would skip the SARIF upload and the findings would never reach code scanning. The gate pass runs afterwards with skip-setup-trivy.

Conventions followed

Every input has a description, explicit type and a default unless genuinely required; secrets: inherit friendly; concurrency follows the publish-vs-validation split (cancel-in-progress: false for the SBOM publish, true for the scan); required caller permissions documented at the top of each file. Action inputs were verified against the actual action.yml of aquasecurity/trivy-action@v0.36.0 and DependencyTrack/gh-upload-sbom@v4 rather than assumed.

Two things worth knowing before adopting

  • autocreate needs PROJECT_CREATION_UPLOAD. It defaults to true, and the Dependency-Track API key's team needs that permission on top of BOM_UPLOAD — otherwise the server answers 403 the first time any new version is uploaded. This is exactly what is currently failing for AntiRedstoneClock-Remastered 2.9.0, and it is a server-side key permission, not something this workflow can fix.
  • SARIF upload on private repos needs Advanced Security. The organisation is on the Free plan, so public repos are fine and private ones must set upload-sarif: false.

Follow-up

A companion PR migrates AntiRedstoneClock-Remastered onto both workflows as the first consumer, so this is exercised for real rather than only in theory.

The README examples pin @v2.6.0, assuming this feat: lands as 2.6.0. Worth a glance if release-please picks something else.

Supply-chain CI was per-repo copy-paste, and in practice that meant it
mostly did not exist. Two additions so every project gets it by
referencing a tag instead of maintaining its own YAML.

sbom-publish.yml
----------------
Publishes a CycloneDX SBOM to Dependency-Track. The SBOM comes from
either an artifact an upstream job produced - preferred, since a build
tool resolves the dependency graph better than any external scanner -
or from Trivy, which generates one from the checked-out repository when
the project has no generator of its own.

It is a standalone job on purpose. AntiRedstoneClock-Remastered 2.9.0
showed the alternative: the SBOM upload sat in the same job as the
release publish, so one failing platform upload cost the JAR, both
platform releases and the SBOM at once.

security-scan.yml
-----------------
Trivy scan with findings uploaded to GitHub code scanning. Report-only
by default - onboarding a repo should make its vulnerabilities visible,
not turn its CI red on day one - with fail-on-findings to gate once a
repo is clean.

It can scan an artifact from an upstream job instead of the repository,
which is what makes a pre-publish gate possible: build, gate on the
artifact, and only then publish.

Two details that were measured rather than assumed:

- limit-severities-for-sarif is on. Without it Trivy ignores `severity`
  for SARIF output, so code scanning would show a different set than
  the gate fails on.
- rootfs, not fs, is the mode for built JVM artifacts. On the
  AntiRedstoneClock-Remastered shaded jar, fs reported 0 packages and 0
  findings while rootfs reported 12 packages and a HIGH finding. fs on
  a Gradle source tree without a lockfile finds nothing either - a gate
  on that looks green because it checked nothing.
@TheMeinerLP
TheMeinerLP force-pushed the feat/supply-chain-workflows branch from 6bdaf7d to d1d4cf2 Compare August 8, 2026 14:39
@TheMeinerLP
TheMeinerLP merged commit e5c73b3 into main Aug 8, 2026
4 checks passed
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