Skip to content

ci(supply-chain): yanks warn, not block — stop dep drift gating unrelated PRs (#82) - #122

Merged
hellno merged 2 commits into
mainfrom
hellno/medan
Jun 21, 2026
Merged

ci(supply-chain): yanks warn, not block — stop dep drift gating unrelated PRs (#82)#122
hellno merged 2 commits into
mainfrom
hellno/medan

Conversation

@hellno

@hellno hellno commented Jun 20, 2026

Copy link
Copy Markdown
Owner

Closes #82.

Problem

cargo-deny's advisory check re-reads the live RustSec advisory DB + crates.io yank status on
every run, so a dependency yank or a freshly-published CVE can turn an unrelated PR red with
no change on our side. PR #81 (a swap/refresh feature) was blocked when bitcoin_hashes 0.14.100
was yanked — code was fine, the outside world changed.

Approach (chosen via /autoplan review)

Split the supply-chain gate by determinism, and within advisories, by kind:

  • Deterministic checks stay required, blocking PR gatesbans / licenses / sources only
    change when we change dependencies. Unchanged.
  • A real RUSTSEC advisory still blocks — on PRs, at release, and in the daily scan. A known
    vulnerability stops the line until fixed or given a justified ignore. Gating logic untouched.
  • A bare crates.io yank is now warn-level (deny.toml: yanked = "deny""warn"). A yank is
    usually a pulled publish, not a vulnerability; if it is a security pull it also carries a RUSTSEC
    advisory and still blocks. So yanks stay visible without gating unrelated PRs.

This is the mainstream Rust-OSS posture (schedule the non-deterministic check, gate the deterministic
ones), tuned so "we take security seriously" means never ship a vulnerable build, not block every
contributor on outside-world drift
. The daily watch (audit.yml, already present) + the
release-boundary gate (ci.yml reused by release.yml) are the safety net, not the PR gate.

Why not continue-on-error: that reports a green check even on a live CVE, hiding the signal.
Rejected for visibility. Approach D keeps the gating logic intact, so the release gate is unchanged
by construction.

Changes

  • deny.toml: yanked = "warn" + rationale.
  • .github/workflows/audit.yml: open/refresh a tracking issue on a failed daily scan (uses the
    preinstalled gh CLI, no third-party action added) so a new advisory is loud, not just an email.
  • .github/workflows/ci.yml: advisories-job comment reflects the yank policy.
  • docs/AGENTIC-ENGINEERING.md section 4: document the PR-vs-release advisory policy.

Verification

  • cargo deny check advisoriesadvisories ok (exit 0) with yanked = "warn".
  • Both workflow YAMLs parse cleanly.
  • No Rust code touched, so fmt/clippy/tests are unaffected; CI confirms.
  • Release-gate behavior on real CVEs is unchanged by construction (advisories job + release.yml
    untouched; only deny.toml's yank level changed, which applies uniformly).

Follow-ups (separate)

  • Dependabot security updates enabled (repo settings) for low-noise auto-remediation of real CVEs.
  • A separate issue tracks that build/test/clippy are not required status checks today (only
    the two cargo-deny jobs gate merges).

hellno added 2 commits June 20, 2026 21:41
…ated PRs (#82)

cargo-deny's advisory check re-reads the live RustSec DB + crates.io yank status
on every run, so a yank or fresh CVE could turn an UNRELATED PR red with no change
on our side (PR #81 ate a bitcoin_hashes yank). Split the gate by determinism:
deterministic bans/licenses/sources still gate PRs; a bare crates.io yank is now
warn-level so outside-world drift can't block work that never touched that dep.
Real RUSTSEC advisories still block: on PRs, at release, and in the daily scan.

- deny.toml: yanked = "deny" -> "warn" (with rationale)
- audit.yml: open/refresh a tracking issue on a failed daily scan (gh CLI, no new action)
- ci.yml: advisories-job comment reflects the yank policy
- docs/AGENTIC-ENGINEERING.md section 4: document the PR-vs-release advisory policy

The daily watch + the release-boundary gate are the safety net, not the PR gate.
Mainstream Rust-OSS posture; never ship a vulnerable build.
…review on #82)

Cross-model code review (Codex + subagents) on PR #122 found that applying
yanked=warn uniformly let a release ship a yanked dependency, and the new
audit.yml alert step had shell/robustness gaps. Adopt variant D2 and harden it.

D2 (release boundary): deny.toml keeps `yanked = "deny"`; only the PR-time
cargo-deny-advisories job downgrades yanks to a warning (`--warn yanked`, gated
on pull_request). Releases, push-to-main, and the nightly audit still block
yanks. Real RUSTSEC advisories still block everywhere.

audit.yml alert hardening:
- gate on `steps.deny.outcome == 'failure'` so a checkout/infra failure no longer
  files a misleading "advisory landed" issue
- tolerate a transient `gh issue list` failure (|| true) so `set -e` can't
  swallow the alert
- exact-title de-dup (post-filter; gh search is fuzzy) + a concurrency group so
  overlapping runs can't open duplicate trackers
- pass `-R "$REPO"` explicitly to the gh calls

Also: fix a stale deny.toml header that called the supply-chain gate
"non-blocking" (it is required + blocking), annotate the ci.yml summary diagram,
and stop the docs claiming a security yank always carries a RUSTSEC advisory.
@hellno
hellno merged commit b5e886f into main Jun 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI: keep dependency yanks/CVEs from blocking unrelated PRs

1 participant