Skip to content

ci: add nightly OSV-Scanner and Trivy vulnerability scans - #584

Draft
reitblatt wants to merge 3 commits into
mainfrom
reitblatt/nightly-vuln-scans
Draft

reitblatt wants to merge 3 commits into
mainfrom
reitblatt/nightly-vuln-scans

Conversation

@reitblatt

@reitblatt reitblatt commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Every night, this checks the third-party software Osprey depends on against public databases of known security vulnerabilities. Maintainers then hear about a vulnerable dependency without waiting for someone to report it.

It checks two things, for both the current main and the latest release:

  • The libraries Osprey uses. OSV-Scanner (from Google) reads the lockfiles for the Python worker, the UI and the Rust coordinator. It looks up each pinned version in OSV.dev, the open-source vulnerability database.
  • The coordinator container image we publish. Trivy (from Aqua Security) scans ghcr.io/roostorg/osprey/osprey-coordinator. That includes the operating-system packages inside the image, which no lockfile lists.

Only maintainers can see the results, in the repo's Security tab (GitHub code scanning). Nothing is posted publicly, because a report of an unfixed vulnerability can help an attacker. The workflow only reports: it doesn't fail builds or change code. It is part of the vulnerability-response process proposed in roostorg/community#119.

Details

The workflow is .github/workflows/nightly-vulnerability-scan.yml. It runs daily at 06:47 UTC and on workflow_dispatch.

Job Tool Target Code scanning category
OSV-Scanner (main) osv-scanner 2.7.0 uv.lock, osprey_ui/pnpm-lock.yaml, osprey_coordinator/Cargo.lock on the triggering ref (main for the schedule) osv-main
OSV-Scanner (release) osv-scanner 2.7.0 the same lockfiles at the latest release tag osv-release
Trivy (edge) trivy 0.76.1 ghcr.io/roostorg/osprey/osprey-coordinator:main trivy-osprey-coordinator-edge
Trivy (release) trivy 0.76.1 ghcr.io/roostorg/osprey/osprey-coordinator:<latest release> trivy-osprey-coordinator-release

A small resolve job looks up the latest release with gh release view and rejects anything that isn't X.Y.Z.

Where results go (privacy)

  • Results go only to GitHub code scanning as SARIF. Code scanning alerts are visible only to people with write access. Scheduled runs have no PR, so there are no read-visible PR annotations.
  • No workflow artifacts, because anyone can download artifacts on a public repo. No issues and no comments either.
  • Run logs are public, so the scanners write only to the SARIF file. Trivy runs with --quiet, and OSV prints only package counts. In the validation run below, the logs contain no CVE, GHSA, RUSTSEC or PYSEC IDs.
  • All four analyses upload against the default branch and are told apart by category, so release-tag findings show up in the normal alert list. Their file locations point at main's copy of each lockfile.

Permissions

The top level is permissions: {}. resolve gets contents: read. The scan jobs get contents: read and security-events: write, which the SARIF upload needs. The images are public, so the jobs don't need packages: read. Checkouts use persist-credentials: false.

New third-party dependencies (approved per AGENTS.md)

Dependency How it's pinned License
github/codeql-action/upload-sarif v4.39.1 9b3254085494b55a0f7c4c2b3d2d52cc712ce370 MIT
OSV-Scanner v2.7.0 (google/osv-scanner release binary osv-scanner_linux_amd64) sha256 160c6253e2922e9e0a6a9771c5c4c40a4b3c6090b34a3cdd5e80c96cc2e4218b, checked in-step Apache-2.0
Trivy v0.76.1 (aquasecurity/trivy release trivy_0.76.1_Linux-64bit.tar.gz) sha256 c7cbe3137fb8a48a17574bede3dd6beb16742d1e9772929940fc90082c39d9c0, checked in-step Apache-2.0

The workflow also downloads Trivy's vulnerability DB at runtime from mirror.gcr.io/aquasec/trivy-db:2, falling back to ghcr.io/aquasecurity/trivy-db:2. actions/checkout is already used in this repo.

Why the scanners are binaries rather than actions:

  • aquasecurity/trivy-action and setup-trivy had their tags force-pushed to malicious commits in March 2026 (GHSA-69fq-xp46-6x23, CVE-2026-33634), together with a malicious Trivy v0.69.4. v0.76.1 is well after that incident. Trivy versions before it, including the 0.70.0 default of trivy-action, also have GHSA-mcj4-mphf-j9ff and GHSA-8rc5-4fr6-64pw.
  • google/osv-scanner-action is a Docker action. Its action.yml runs docker://ghcr.io/google/osv-scanner-action:v2.7.0, a mutable tag, so pinning the action by SHA doesn't pin the code that runs.

Both hashes were checked against the projects' published checksum files (trivy_0.76.1_checksums.txt, osv-scanner_SHA256SUMS).

The Trivy install and flags match the image-scanning/SBOM work for this repo (--scanners vuln --pkg-types os,library, all severities, no --ignore-unfixed, same DB repositories). The Trivy categories are deliberately the same as the publish-time scan in #583 (trivy-osprey-coordinator-edge / -release). Trivy puts image alerts at the same location whether it scans a tag or a digest, so the nightly upload refreshes those alerts against a fresh DB instead of duplicating them. Keep the flags identical in both workflows, or the two uploads will churn the alerts. The coop nightly scans use the same tools, versions and design, scheduled at 06:17 UTC.

Dependabot won't bump the two binaries, since they are hard-coded URLs and hashes rather than uses: refs. Someone has to update the version and hash together by hand. Dependabot's github-actions ecosystem does cover upload-sarif.

Known gaps

  • osprey_coordinator/Cargo.lock is gitignored on main until ci(dependabot): Add Dependabot coverage for npm, cargo and Docker; track Cargo.lock #552 merges. The step warns and skips any lockfile that's missing, so Rust crates are covered on main once ci(dependabot): Add Dependabot coverage for npm, cargo and Docker; track Cargo.lock #552 lands, with no change here. Release tags up to and including 1.2.1 will never have a Cargo.lock. The coordinator image doesn't help either: its Rust findings come from crate sources left in /usr/local/cargo/registry, not from the coordinator's own dependency graph (it doesn't ship Cargo.lock and the binary isn't built with cargo-auditable). Scanning Cargo.lock with OSV is the accurate view.
  • Trivy result volume: the coordinator image is single-stage FROM rust:1.91, so it ships a full Debian userland and toolchain. Each image scan produces roughly 13k results. Code scanning keeps the top 5,000 by severity, which covers every critical and high result, so part of the medium/low tail isn't shown. A slim runtime stage would fix this, but that's a production Dockerfile change and out of scope here.

Stacked-PR CI (#578)

This workflow has only schedule and workflow_dispatch triggers, so #578's change to pull_request base branches doesn't affect it either way. Scheduled runs always use the default branch.

Testing

  • zizmor 1.25.2 (online and --offline): no findings.
  • actionlint 1.7.12 with shellcheck: clean.
  • pre-commit on the file: passes.
  • Ran OSV-Scanner 2.7.0 and Trivy 0.76.1 locally against main (with ci(dependabot): Add Dependabot coverage for npm, cargo and Docker; track Cargo.lock #552's Cargo.lock), the 1.2.1 tag, and the main and 1.2.1 coordinator images. Findings were shared privately with maintainers and are not in this PR.
  • A workflow_dispatch can't start a workflow that isn't on the default branch yet. The branch instead carried a temporary push trigger, which was removed in the last commit. Run 40784059496: all five jobs passed, all four SARIF analyses were processed by code scanning, and the public log has no advisory IDs. Those branch-ref analyses can be deleted from code scanning after review.

No CHANGELOG entry: this is CI plumbing.

Refs roostorg/community#119.

🤖 Generated with Claude Code

claude-agent and others added 3 commits October 28, 2026 22:59
Scan uv.lock, osprey_ui/pnpm-lock.yaml and osprey_coordinator/Cargo.lock
with OSV-Scanner, and the published coordinator image with Trivy, for
main and the latest release. Results go to code scanning only.

Refs roostorg/community#119.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
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