Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ version: 2
# It does NOT delay security fixes. Cooldown applies to version updates, and
# Dependabot security updates are a separate mechanism.
#
# Two things about this repository that a reviewer needs to know before merging
# any of these, and neither is obvious from the diff:
# Three things about this repository that a reviewer needs to know before
# merging any of these, and none is obvious from the diff:
#
# 1. A dependency bump can change the bytes of a generated file, and this
# project promises those bytes inside a major version (D11). The byte
Expand All @@ -33,6 +33,14 @@ version: 2
# every one of them, and GPL-3.0 makes that a real question rather than
# a formality.
#
# 3. An update of google/osv-scanner-action goes red too, in the job
# "new vulnerabilities (OSV)", until the digest of its new Docker image
# is written to .github/osv-scanner-digest in the same pull request. The
# action is pinned by commit but runs an image named by a tag, so the
# digest is what holds the image still (O281). Read what the release
# changed, then take the digest from the "Pull down action image" lines
# of that red run and check it against the release before writing it.
#
# None of these are merged on a green tick alone. Every one is read before it
# is accepted: which files of the module changed between the two versions
# (diff the two copies in the module cache, not the release notes), whether
Expand Down
1 change: 1 addition & 0 deletions .github/osv-scanner-digest
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sha256:71ad04ab2f8798be47870f9b18817ad317c2f8f2f97aa6726ba10d5578bc174a
59 changes: 59 additions & 0 deletions .github/scripts/osv_scanner_image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
#
# Is the scanner image on this runner the one this repository recorded.
#
# The OSV actions are pinned by commit, and each of them names its Docker image
# by a tag, ghcr.io/google/osv-scanner-action:vX.Y.Z, which whoever owns it can
# push again. Pinning the action does not stop that. The runner pulls the image
# while it sets the job up, before the first step, so by the time this runs the
# image is here and has not run yet. If its digest is not the one recorded in
# the file, this fails, and the scan steps after it do not start. Measured on
# the runner 2026-10-15, docs/OSV-2-2026-10-15.md.
#
# Fails rather than passes when there is no image of the scanner at all. That
# would mean the runner stopped pulling it during set-up, and a check that found
# nothing to check has not checked anything.
#
# A Dependabot update of google/osv-scanner-action brings a new image and stops
# here until its digest is written to the file. That is on purpose: it is the
# moment somebody reads what the new release changed.
#
# Usage: osv_scanner_image.sh [file with the digest]
set -euo pipefail

file="${1:-.github/osv-scanner-digest}"
repository="ghcr.io/google/osv-scanner-action"

# One digest and nothing else, white space allowed around it and none inside
# it - the shape TestTheScannerImageIsCheckedBeforeItRuns asks of the file.
# Taking every space out first, as this once did, joined a digest split in two
# into one that passed (review of #187).
raw=$(cat -- "$file" 2>/dev/null || true)
if [[ "$raw" =~ ^[[:space:]]*(sha256:[0-9a-f]{64})[[:space:]]*$ ]]; then
expected="${BASH_REMATCH[1]}"
else
echo "::error::$file does not hold one sha256 digest, so there is nothing to compare the scanner image with. Write one line to it: sha256: and the 64 lowercase hexadecimal characters of the image the OSV actions run, which the Set up job section of a run prints after Digest."
exit 1
fi

ids=$(docker image ls --no-trunc --quiet "$repository")
if [ -z "$ids" ]; then
echo "::error::No image of $repository is on this runner. The runner used to pull it while setting the job up, before any step, and this check relies on that. Read the Set up job section of this run."
exit 1
fi

status=0
for id in $(printf '%s\n' "$ids" | sort -u); do
digests=$(docker image inspect --format '{{range .RepoDigests}}{{println .}}{{end}}' "$id")
if printf '%s\n' "$digests" | grep -qxF "$repository@$expected"; then
echo "osv_scanner_image: $id is $repository@$expected"
continue
fi
echo "::error::The scanner image $id is not the one recorded in $file."
echo "It was pulled as:"
printf '%s\n' "$digests" | sed 's/^/ /'
echo "If google/osv-scanner-action was just updated, read what its new release changed and write the new digest to $file."
echo "If it was not, the image behind the tag has changed, and nothing should run it."
status=1
done
exit "$status"
24 changes: 20 additions & 4 deletions .github/workflows/osv-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ jobs:
fetch-depth: 2
persist-credentials: false

# The two OSV actions below are pinned by commit, but they run a Docker
# image named by a tag, and a tag can be pushed again. The runner has
# already pulled that image while setting this job up, so this compares
# it with the digest in .github/osv-scanner-digest before anything runs
# it (O281). Here, before the checkout of the branch this merges into,
# so the digest read is the pull request's own: a Dependabot update that
# writes the new one would otherwise be held to the old one for ever.
- name: the scanner image is the one recorded
run: bash .github/scripts/osv_scanner_image.sh

# Asserted rather than assumed, from the review of #181: with a commit
# of one parent here, HEAD^1 would be the pull request's own previous
# commit, and the comparison would find nothing new for the wrong reason.
Expand Down Expand Up @@ -77,7 +87,7 @@ jobs:
with:
scan-args: |-
--format=json
--output=osv-old.json
--output-file=osv-old.json
--no-call-analysis=go
--recursive
./
Expand All @@ -94,7 +104,7 @@ jobs:
with:
scan-args: |-
--format=json
--output=osv-new.json
--output-file=osv-new.json
--no-call-analysis=go
--recursive
./
Expand All @@ -120,12 +130,18 @@ jobs:
# advisory and the version that fixes it. The annotations on the pull
# request are not - measured 2026-10-14 with findings in two files, one
# annotation came out, for one of them.
#
# table:#stdout is that list, and it has to be named. Once anything else
# goes to a terminal stream - the annotations here - the reporter stops
# printing the table on its own, measured 2026-10-15 on v2.6.0 (3100
# bytes of log down to none). Named, the SARIF, the annotations and the
# table come out byte for byte as they did under the deprecated
# --output and --gh-annotations (docs/OSV-2-2026-10-15.md).
- name: what this pull request adds
uses: google/osv-scanner-action/osv-reporter-action@a345acffa64b0eaede81a3d9aae6141214d9c8fc # v2.6.0
with:
scan-args: |-
--old=osv-old.json
--new=osv-new.json
--output=osv-new.sarif
--gh-annotations=true
--output-files=sarif:osv-new.sarif,gh-annotations:#stderr,table:#stdout
--fail-on-vuln=true
17 changes: 13 additions & 4 deletions .github/workflows/osv-weekly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,22 @@ jobs:
with:
persist-credentials: false

# The image the OSV actions run, against the digest recorded in
# .github/osv-scanner-digest, before anything runs it. The reasons are
# written beside the same step in osv-pull-request.yml (O281). When it
# fails, nothing is scanned and no SARIF is written, so the upload below
# finds no file and the alerts of the week before stay as they were.
- name: the scanner image is the one recorded
run: bash .github/scripts/osv_scanner_image.sh

- name: scan
id: scan
uses: google/osv-scanner-action/osv-scanner-action@a345acffa64b0eaede81a3d9aae6141214d9c8fc # v2.6.0
continue-on-error: true
with:
scan-args: |-
--format=json
--output=osv-results.json
--output-file=osv-results.json
--no-call-analysis=go
--recursive
./
Expand All @@ -81,14 +89,15 @@ jobs:

# Writes the results for the Security tab and fails the job when there
# is any, which is after the file is written - the upload below runs
# either way.
# either way. table:#stdout keeps the list in the log of this step, the
# way the deprecated --output printed it, measured byte for byte
# 2026-10-15 (docs/OSV-2-2026-10-15.md).
- name: results for the Security tab
uses: google/osv-scanner-action/osv-reporter-action@a345acffa64b0eaede81a3d9aae6141214d9c8fc # v2.6.0
with:
scan-args: |-
--new=osv-results.json
--output=osv-results.sarif
--gh-annotations=false
--output-files=sarif:osv-results.sarif,table:#stdout
--fail-on-vuln=true

- name: upload to the Security tab
Expand Down
Loading
Loading