Skip to content

Supply-chain audit

Supply-chain audit #34

Workflow file for this run

name: Supply-chain audit
# Daily advisory re-scan, decoupled from PR CI. New RustSec advisories land continuously, so a tree
# that was green at merge time can go vulnerable on a quiet day. This re-runs `cargo deny check
# advisories` against the COMMITTED Cargo.lock using the same deny.toml ignore list as the PR-time
# `cargo-deny-advisories` gate — a newly published advisory that isn't already justified there turns
# this red. `workflow_dispatch` lets you run it on demand.
#
# NOTE: scheduled workflows only fire on the default branch, so this starts running once merged to
# main. Config + the per-advisory justifications live in deny.toml; the remediation backlog is #40.
on:
schedule:
- cron: "0 7 * * *" # 07:00 UTC daily
workflow_dispatch:
permissions:
contents: read
issues: write # so a failed scan can open/refresh a tracking issue (#82)
# One audit at a time: a manual workflow_dispatch overlapping the 07:00 cron must not race the
# search-then-create issue de-dup below into duplicate trackers. (#82)
concurrency:
group: supply-chain-audit
cancel-in-progress: false
jobs:
advisories:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: deny
# Pinned to the last-good release: v2.1.0 (2026-07-13) drops a positional arg in action.yml
# without updating its entrypoint, shifting --log-level into a command slot — every run dies
# with `unrecognized subcommand 'warn'`. Unpin to @v2 once upstream ships a fix.
uses: EmbarkStudios/cargo-deny-action@v2.0.20
with:
command: check advisories
# Make the daily watch LOUD (#82): if the ADVISORY SCAN itself failed (the `steps.deny.outcome`
# guard, so a checkout / action-infra error does NOT masquerade as an advisory), a new RUSTSEC
# advisory or a yanked crate was found — the nightly keeps `yanked = "deny"` even though PRs only
# warn. A red scheduled run just emails admins by default, easy to miss, so open a tracking issue
# (or comment on the open one). `gh` is preinstalled: no third-party action added.
- name: Open or refresh advisory tracking issue on failure
if: failure() && steps.deny.outcome == 'failure'
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
title="Daily cargo-deny advisory scan is failing"
run_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
body=$(printf '%s\n\n%s\n\n%s' \
"The nightly \`cargo deny check advisories\` run failed — a new RustSec advisory or a yanked dependency was found. See the run for the crate and RUSTSEC id." \
"Failed run: ${run_url}" \
"Triage in \`deny.toml\`: bump the dependency, or add a justified \`ignore\` entry. Close this issue once the nightly scan is green again.")
# Tolerate a transient list failure (|| true) so a flaky API can't swallow the alert, and
# match the title EXACTLY (gh search is tokenized/fuzzy) so we never comment on a look-alike.
existing=$(gh issue list -R "$REPO" --state open --search "${title} in:title" \
--json number,title --jq "map(select(.title == \"${title}\")) | .[0].number // empty" || true)
if [ -n "${existing}" ]; then
gh issue comment "${existing}" -R "$REPO" --body "${body}"
else
gh issue create -R "$REPO" --title "${title}" --body "${body}"
fi