Repository navigation
147 lines (136 loc) · 6.82 KB
/
Copy pathosv-pull-request.yml
File metadata and controls
147 lines (136 loc) · 6.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# Blocks a pull request that brings in a vulnerability the main branch does not
# already have, by any package manifest in the tree - go.mod and the pinned
# Python packages the semgrep job installs.
#
# The owner's decision of 2026-10-14: a pull request is stopped only for what it
# adds. What main already carries is reported once a week to the Security tab by
# osv-weekly.yml, and does not hold up a change that did not cause it.
#
# How it tells the two apart. The tree is scanned twice, first as the branch it
# merges into and then as the merge itself, and the reporter compares the two
# results - the method of the action's own pull request workflow. That workflow
# is not called as it is, because it keeps the job token in the checkout to
# switch branches and asks for security-events: write to upload. Neither is
# needed: the base is the first parent of the merge commit, which a fetch depth
# of two already holds, and a pull request has nothing to upload.
#
# Next to the two gates that already read the same go.mod. "review new
# dependencies" looks only at what the diff adds and only through GitHub's
# advisories. "known vulnerabilities" is govulncheck, which counts only what our
# code can reach. This one reads OSV, which also covers the Python packages, and
# counts a vulnerable package whether or not anything calls it - see
# --no-call-analysis below.
name: OSV pull request
on:
pull_request:
permissions:
contents: read
# A push to the pull request makes the run before it pointless, and each run
# scans the tree twice. The same grouping as dev-build.yml.
concurrency:
group: osv-pull-request-${{ github.ref }}
cancel-in-progress: true
jobs:
scan:
name: new vulnerabilities (OSV)
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# The merge commit and its two parents, the first of which is the
# branch this pull request merges into.
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.
- name: the branch this merges into
run: |
parents=$(git rev-list --parents -n 1 HEAD | wc -w)
if [ "$parents" -ne 3 ]; then
echo "::error::The checkout is not the merge commit of this pull request ($((parents - 1)) parent(s)), so there is no base to compare against."
exit 1
fi
git checkout --quiet --detach HEAD^1
# The scanner exits 1 when it finds something and with another code when
# it cannot scan at all, and the step cannot tell the two apart. The
# results file can, and the check further down reads it.
#
# --no-call-analysis=go because it cannot work here and fails loudly
# when tried. It compiles the tree, and this tree refuses to compile
# without the tags in .github/build-tags and a C compiler with the
# headers of the window's toolkit, neither of which the scanner's image
# carries. Measured 2026-10-14: hundreds of compile errors in the log, and
# every Go advisory reported as if called anyway. Whether a vulnerable
# function is reachable is what the govulncheck job answers.
- name: scan the branch this merges into
id: old
uses: google/osv-scanner-action/osv-scanner-action@a345acffa64b0eaede81a3d9aae6141214d9c8fc # v2.6.0
continue-on-error: true
with:
scan-args: |-
--format=json
--output-file=osv-old.json
--no-call-analysis=go
--recursive
./
- name: the merge of this pull request
env:
MERGE: ${{ github.sha }}
run: git checkout --quiet --force --detach "$MERGE"
- name: scan the merge of this pull request
id: new
uses: google/osv-scanner-action/osv-scanner-action@a345acffa64b0eaede81a3d9aae6141214d9c8fc # v2.6.0
continue-on-error: true
with:
scan-args: |-
--format=json
--output-file=osv-new.json
--no-call-analysis=go
--recursive
./
# Both files, whatever the scan steps returned. The reporter reads a file
# it cannot parse as one with no findings - measured 2026-10-14 on
# v2.6.0, from the review of #181: thirty findings cut short came out
# "No issues found", exit 0, and so did a missing file. Only a whole
# result goes on to be compared.
- name: both scans wrote a whole result
run: |
status=0
for f in osv-old.json osv-new.json; do
if ! jq -e '.results | type == "array"' "$f" > /dev/null 2>&1; then
echo "::error::$f is missing or is not a whole scan result, so the scan did not complete. Read the scan steps above for the cause."
status=1
fi
done
exit "$status"
# Fails the job on anything in the second scan that is not in the first.
# The log of this step is the list: every finding with its package, the
# 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-files=sarif:osv-new.sarif,gh-annotations:#stderr,table:#stdout
--fail-on-vuln=true