-
Notifications
You must be signed in to change notification settings - Fork 2
181 lines (168 loc) · 7.04 KB
/
Copy pathdependency-security.yml
File metadata and controls
181 lines (168 loc) · 7.04 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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
name: "Dependency Security Scan"
# Runs on pushes/PRs so a bad upgrade is caught immediately, and on a schedule because a
# dependency can become vulnerable without this repo changing at all.
on:
push:
branches:
- master
- staging
pull_request:
branches:
- master
- staging
schedule:
# Mondays 06:00 UTC
- cron: '0 6 * * 1'
workflow_dispatch:
permissions:
contents: read
env:
# Modules published to Maven Central. Their runtime dependencies are what every
# integrator inherits, so they are scanned as `published` and always block.
# NOTE: sdk-java only applies the publish plugin when a publish task is requested, so the
# report step cannot auto-detect it -- this list is the only signal.
PUBLISHED_MODULES: ":sdk-java"
jobs:
osv-scan:
name: OSV scan (all modules)
runs-on: ubuntu-latest
permissions:
contents: read
# Needed to post the scan result as a comment on the pull request.
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v4
# NOTE: JDK 17, not the JDK 8 used by gradle.yml. settings.gradle only includes
# :app-javafx on Java 11+, so a JDK 8 run would silently skip that module's
# dependencies -- exactly the blind spot that let a known org.json CVE sit in the demo
# modules after sdk-java had been fixed.
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'corretto'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Resolve dependencies for every module
run: |
set -o pipefail
./gradlew -q --init-script .github/scripts/dependency-report.init.gradle \
"-DpublishedModules=$PUBLISHED_MODULES" \
printResolvedDependencies | tee resolved-dependencies.txt
count=$(grep -c '^COORD' resolved-dependencies.txt || true)
echo "Resolved $count coordinate lines."
if [ "$count" -eq 0 ]; then
echo "::error::Gradle produced no dependency coordinates"
exit 1
fi
# Blocks on `published` and `sample` findings -- everything we declare ourselves,
# including the demo modules. `buildscript` is reported only: it is Gradle plugin
# internals, which cannot be upgraded independently of the plugins themselves.
- name: Check resolved dependencies against OSV
id: osv
env:
OSV_FAIL_ON: HIGH
OSV_BLOCKING_SCOPES: published,sample
run: python3 .github/scripts/osv_scan.py < resolved-dependencies.txt
# The job summary written above only shows on the workflow run page. This is what
# actually puts the result on the pull request. It updates one sticky comment
# instead of adding a new one on every push.
- name: Comment scan result on the pull request
if: always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
uses: actions/github-script@v9
with:
script: |
const fs = require('fs');
const marker = '<!-- countly-dependency-security-scan -->';
const outcome = '${{ steps.osv.outcome }}';
// The report body already carries its own heading.
const status = outcome === 'success'
? '**Result: passed**'
: '**Result: FAILED — a dependency has a known vulnerability**';
let report = '';
try {
report = fs.readFileSync('osv-report.md', 'utf8');
} catch (e) {
report = `The scan step did not produce a report (outcome: ${outcome}). See the workflow logs.`;
}
const body = [
marker,
report,
status,
'',
`[Full run log](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`,
].join('\n');
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
per_page: 100,
});
const existing = comments.find(c => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- name: Upload dependency list
if: always()
uses: actions/upload-artifact@v4
with:
name: resolved-dependencies
path: |
resolved-dependencies.txt
osv-report.md
if-no-files-found: warn
dependency-submission:
name: Submit dependency graph
# Runs on pushes to the long-lived branches, on the weekly cron, on manual dispatch,
# AND on same-repo pull requests -- the last one is what gives dependency-review a head
# snapshot to diff against.
# Fork PRs are skipped on purpose: `contents: write` is not granted to a workflow
# triggered by a PR from a public fork, so the submit would fail. Covering forks needs
# the two-workflow generate-and-upload + workflow_run pattern from the gradle/actions docs.
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'corretto'
- name: Submit resolved dependency graph to GitHub
uses: gradle/actions/dependency-submission@v4
dependency-review:
name: Review dependency changes
# Needs the submission job so the head snapshot exists before the diff.
# `always()` keeps this running on fork PRs, where submission is skipped -- without it,
# a skipped dependency-submission would skip this job too.
# SCOPE: this can only diff Gradle dependencies once BOTH the base branch and the head
# have a submitted snapshot, so expect Actions-only output until master has been through
# dependency-submission at least once. osv-scan is the job that covers Gradle
# dependencies unconditionally.
if: always() && github.event_name == 'pull_request'
needs: dependency-submission
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Fail the PR on newly introduced vulnerable dependencies
uses: actions/dependency-review-action@v5
with:
fail-on-severity: low
comment-summary-in-pr: on-failure