-
Notifications
You must be signed in to change notification settings - Fork 0
202 lines (181 loc) · 7.93 KB
/
Copy pathrefresh-data.yml
File metadata and controls
202 lines (181 loc) · 7.93 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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
name: Refresh data
# Keeps published data fresh: pull all upstream sources, rebuild the graph,
# package dist/, verify it, and publish a data-YYYYMMDD release when — and
# only when — the snapshot_id actually changed (publish.sh enforces that).
#
# Trigger rationale (04:17 UTC daily):
# - EPSS posts epss_scores-current.csv.gz shortly after 00:00 UTC, so the
# daily scores have landed and settled by 04:00.
# - CISA KEV is updated on US business days, typically 18:00-22:00 UTC, so
# this run picks up the previous business day's additions in full.
# - CVEList V5, OSV, nuclei-templates and PoC-in-GitHub push continuously;
# any time of day is equally fresh for them.
# - :17 rather than :00 avoids the top-of-hour scheduled-job queue on
# GitHub-hosted runners, which can delay a :00 cron by 10-30 minutes.
on:
schedule:
- cron: '17 4 * * *'
workflow_dispatch:
inputs:
publish:
description: 'Publish a data-YYYYMMDD release if the snapshot changed'
type: boolean
default: true
permissions:
contents: write
# Never let two refreshes race: they share dist/ semantics and the release tag.
concurrency:
group: refresh-data
cancel-in-progress: false
jobs:
refresh:
runs-on: ubuntu-latest
timeout-minutes: 300
env:
# cargo's built-in libgit2 transport ignores url.insteadOf and the SSH
# config below; shelling out to the git CLI honors both.
CARGO_NET_GIT_FETCH_WITH_CLI: true
steps:
- uses: actions/checkout@v4
# The raw source tree is ~17 GB (OSV extracts to ~9 GB, cvelistV5 is
# ~3.5 GB). A stock runner does not have room for that, so reclaim the
# preinstalled toolchains we do not use (~30 GB).
- name: Free disk space
run: |
df -h /
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/usr/local/share/boost /usr/local/share/powershell \
/usr/share/swift /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force >/dev/null 2>&1 || true
df -h /
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: cargo-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
restore-keys: cargo-${{ runner.os }}-
# The deps.dev cache is expensive to build (two rate-limited API calls
# per package) and cheap to store, so it persists across runs and is
# topped up incrementally below.
- name: Restore deps.dev cache
id: deps-dev-cache
uses: actions/cache/restore@v4
with:
path: research/downloads/deps-dev
key: deps-dev-
restore-keys: deps-dev-
# vulngraph-engine is a git dependency on the private copyleftdev/vulngraph
# repo. A job's GITHUB_TOKEN is scoped to its own repo and cannot read it,
# so cargo authenticates with a read-only deploy key over SSH instead.
- name: Authenticate cargo to the private engine repo
env:
ENGINE_SSH_KEY: ${{ secrets.ENGINE_SSH_KEY }}
run: |
mkdir -p ~/.ssh
printf '%s\n' "$ENGINE_SSH_KEY" > ~/.ssh/engine_ed25519
chmod 600 ~/.ssh/engine_ed25519
ssh-keyscan -t ed25519 github.com >> ~/.ssh/known_hosts 2>/dev/null
printf '%s\n' \
'Host github.com' \
' IdentityFile ~/.ssh/engine_ed25519' \
' IdentitiesOnly yes' >> ~/.ssh/config
# insteadOf matches on longest prefix, and ".../vulngraph" is a prefix
# of ".../vulngraph-data" — the first rule alone would also rewrite this
# repo's own remote to SSH and break the badge push in publish.sh. The
# longer identity-mapped rule below pins vulngraph-data back to HTTPS.
git config --global url."git@github.com:copyleftdev/vulngraph".insteadOf \
"https://github.com/copyleftdev/vulngraph"
git config --global url."https://github.com/copyleftdev/vulngraph-data".insteadOf \
"https://github.com/copyleftdev/vulngraph-data"
git ls-remote --get-url https://github.com/copyleftdev/vulngraph
git ls-remote --get-url https://github.com/copyleftdev/vulngraph-data.git
- name: Build pipeline binary
run: cargo build --release
# fetch-deps-dev.sh enumerates packages out of the *previous* graph, so
# seed one from the last release. Without it the deps.dev step is a
# no-op and the build silently loses its dependency edges.
- name: Seed previous graph from latest release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p builds/vulngraph.db
if gh release download --repo "$GITHUB_REPOSITORY" \
--pattern vulngraph-db.tar.gz --output /tmp/prev-db.tar.gz 2>/dev/null; then
tar -xzf /tmp/prev-db.tar.gz -C builds/vulngraph.db
rm -f /tmp/prev-db.tar.gz
echo "Seeded previous graph: $(du -sh builds/vulngraph.db | cut -f1)"
else
echo "No previous release to seed from — deps.dev enumeration will be skipped."
fi
- name: Download sources
run: ./scripts/download_sources.sh
# The 1.2 GB archive is dead weight once extracted, and refresh.sh runs
# with --rebuild-only so it will not be re-read.
- name: Drop OSV archive
run: |
rm -f research/downloads/osv/all.zip
du -sh research/downloads/* | sort -h
df -h /
# Time-boxed: a cold cache is ~20k packages at ~3/sec. Each run extends
# the cache; a failure or timeout here is non-fatal by design.
- name: Top up deps.dev cache
continue-on-error: true
run: |
mkdir -p research/downloads/deps-dev
timeout 25m ./scripts/fetch-deps-dev.sh \
research/downloads/deps-dev builds/vulngraph.db || \
echo "deps.dev top-up ended early (time-boxed) — cache retained."
- name: Save deps.dev cache
if: always()
uses: actions/cache/save@v4
with:
path: research/downloads/deps-dev
key: deps-dev-${{ github.run_id }}
- name: Configure git identity
run: |
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
# Sources are already current from the steps above, so --rebuild-only:
# build -> export-demo -> package -> verify -> promote -> publish.
# publish.sh no-ops when snapshot_id matches the latest release.
- name: Build, package, verify and publish
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p logs
ARGS="--rebuild-only"
if [ "${{ github.event_name }}" = "schedule" ] || [ "${{ inputs.publish }}" = "true" ]; then
ARGS="$ARGS --publish"
fi
set -o pipefail
./scripts/refresh.sh $ARGS 2>&1 | tee logs/refresh.log
- name: Summarize
if: always()
run: |
{
echo '## VulnGraph data refresh'
if [ -f dist/manifest.json ]; then
python3 - <<'PY'
import json
m = json.load(open('dist/manifest.json'))
print(f"- snapshot: `{m['snapshot_id']}`")
print(f"- graph: {m['node_count']:,} nodes / {m['edge_count']:,} edges")
print(f"- engine: `{m['engine_rev']}` (format {m['format_version']})")
print(f"- sources: {len(m.get('sources') or {})}")
PY
else
echo '- no dist/manifest.json produced'
fi
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload manifest and log
if: always()
uses: actions/upload-artifact@v4
with:
name: refresh-${{ github.run_id }}
path: |
dist/manifest.json
logs/refresh.log
if-no-files-found: warn
retention-days: 14