Skip to content

Commit 3a794c8

Browse files
authored
ci: make cargo-deny advisory checks non-blocking (#2957)
Advisory checks run against a live RUSTSEC database. A new advisory instantly breaks CI on every branch even though no code changed -- this is what happened with RUSTSEC-2026-0104. Split cargo-deny into two CI jobs: - lint-rust-deny: bans, licenses, sources (blocking) - lint-rust-advisories: advisories only (informational, continue-on-error) Add a weekly cron workflow (rust-advisories.yaml) that checks for new advisories and opens an issue when one appears.
1 parent 83f94e4 commit 3a794c8

3 files changed

Lines changed: 79 additions & 4 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,25 @@ jobs:
330330
- uses: jdx/mise-action@v4
331331
with:
332332
cache_key_prefix: mise-ci-${{ github.job }}
333-
- name: Check licenses and advisories
334-
run: mise run lint:rust:deny
333+
- name: Check licenses, bans, and sources
334+
run: cargo deny --manifest-path crates/Cargo.toml check bans licenses sources
335+
336+
# Advisory checks run against a live database that can change at any time.
337+
# A new RUSTSEC entry would break CI on every branch even though no code
338+
# changed, so this job is informational only (continue-on-error).
339+
# A weekly cron workflow (rust-advisories.yaml) opens issues for new advisories.
340+
lint-rust-advisories:
341+
name: Lint Rust (advisories)
342+
runs-on: ubuntu-latest
343+
timeout-minutes: 10
344+
continue-on-error: true
345+
steps:
346+
- uses: actions/checkout@v6
347+
- uses: jdx/mise-action@v4
348+
with:
349+
cache_key_prefix: mise-ci-${{ github.job }}
350+
- name: Check advisories (informational)
351+
run: cargo deny --manifest-path crates/Cargo.toml check advisories
335352

336353
lint-python:
337354
name: Lint Python
@@ -668,6 +685,7 @@ jobs:
668685
- lint-go
669686
- lint-rust
670687
- lint-rust-deny
688+
- lint-rust-advisories
671689
- lint-python
672690
- lint-docs
673691
- test-go
@@ -696,6 +714,7 @@ jobs:
696714
echo " lint-go: ${{ needs.lint-go.result }}"
697715
echo " lint-rust: ${{ needs.lint-rust.result }}"
698716
echo " lint-rust-deny: ${{ needs.lint-rust-deny.result }}"
717+
echo " lint-rust-advisories: ${{ needs.lint-rust-advisories.result }} (informational)"
699718
echo " lint-python: ${{ needs.lint-python.result }}"
700719
echo " lint-docs: ${{ needs.lint-docs.result }}"
701720
echo " test-go: ${{ needs.test-go.result }}"
@@ -706,7 +725,9 @@ jobs:
706725
echo " integration-shards: ${{ needs.integration-shards.result }}"
707726
echo " test-integration: ${{ needs.test-integration.result }}"
708727
709-
# Fail if any job failed
728+
# Fail if any required job failed.
729+
# lint-rust-advisories is excluded: it uses continue-on-error because
730+
# advisory DB updates shouldn't block unrelated PRs.
710731
FAILED=false
711732
for result in \
712733
"${{ needs.setup.result }}" \
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Rust Advisory Check
2+
3+
on:
4+
schedule:
5+
# Monday 9am UTC
6+
- cron: "0 9 * * 1"
7+
workflow_dispatch:
8+
9+
permissions:
10+
issues: write
11+
12+
jobs:
13+
check-advisories:
14+
name: Check Rust advisories
15+
runs-on: ubuntu-latest
16+
timeout-minutes: 10
17+
steps:
18+
- uses: actions/checkout@v6
19+
- uses: jdx/mise-action@v4
20+
with:
21+
cache_key_prefix: mise-ci-${{ github.job }}
22+
- name: Check advisories
23+
id: advisories
24+
continue-on-error: true
25+
run: cargo deny --manifest-path crates/Cargo.toml check advisories 2>&1 | tee /tmp/deny-output.txt
26+
- name: Open issue on failure
27+
if: steps.advisories.outcome == 'failure'
28+
env:
29+
GH_TOKEN: ${{ github.token }}
30+
run: |
31+
# Don't open a duplicate if one already exists
32+
EXISTING=$(gh issue list --label "security" --search "Rust security advisory" --state open --json number --jq '.[0].number')
33+
if [ -n "$EXISTING" ]; then
34+
echo "Issue #$EXISTING already open, skipping"
35+
exit 0
36+
fi
37+
38+
SNIPPET=$(grep -A5 'error\[vulnerability\]' /tmp/deny-output.txt | head -30 || echo "See CI logs for details")
39+
40+
gh issue create \
41+
--title "Rust security advisory detected" \
42+
--label "security" \
43+
--body "\`cargo deny check advisories\` found new security advisories in Rust dependencies.
44+
45+
\`\`\`
46+
$SNIPPET
47+
\`\`\`
48+
49+
Run \`cargo deny --manifest-path crates/Cargo.toml check advisories\` locally for full details.
50+
Typically fixed with \`cargo update -p <crate>\` in \`crates/\`."

mise.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,13 @@ description = "Lint Rust code (clippy)"
437437
run = "cargo clippy --manifest-path crates/Cargo.toml --workspace -- -D warnings"
438438

439439
[tasks."lint:rust:deny"]
440-
description = "Check Rust licenses and advisories"
440+
description = "Check Rust licenses, bans, sources, and advisories"
441441
run = "cargo deny --manifest-path crates/Cargo.toml check"
442442

443+
[tasks."lint:rust:deny:advisories"]
444+
description = "Check Rust advisory database (RUSTSEC)"
445+
run = "cargo deny --manifest-path crates/Cargo.toml check advisories"
446+
443447
[tasks."lint:rust:fix"]
444448
description = "Fix Rust lint issues"
445449
run = "cargo clippy --manifest-path crates/Cargo.toml --workspace --fix --allow-dirty -- -D warnings"

0 commit comments

Comments
 (0)