ci: enforce cargo lockfile age policy on PRs - #2549
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2549 +/- ##
==========================================
+ Coverage 88.61% 88.65% +0.03%
==========================================
Files 179 179
Lines 60472 60600 +128
Branches 60472 60600 +128
==========================================
+ Hits 53589 53726 +137
+ Misses 4828 4816 -12
- Partials 2055 2058 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Adds scripts/upgrade_lockfile.py (Python 3.7+, no third-party deps) and a lockfile-age-policy job in build.yml that runs `--check --strict` on every PR/push/merge_group. Gates the actual work via dorny/paths-filter so it only runs when Cargo.toml, Cargo.lock, any workspace member Cargo.toml, or the script itself changed. The script supports four CUJs: - --check: read-only audit; exits 1 on any package younger than --days. - (no args): cargo update everything, walk back too-new fallout. - PKG: auto-pick newest compliant version of PKG, walk back transitives. - PKG --precise VER: bump PKG to VER, walk back transitives. Uses `cargo metadata --locked` for lock parsing (no tomllib required) and concurrently fetches publish dates from crates.io. --strict makes CI fail closed if crates.io is unreachable. All output and comments are ASCII-only to satisfy the repo's PR body validator when contributors paste script output as evidence.
1b717fd to
b8a34c2
Compare
thinh2
left a comment
There was a problem hiding this comment.
Generally looks good for me ! Thank you! I have one question regarding the failure handling.
| rc = 1 | ||
|
|
||
| if rc == 0 and not dry_run: | ||
| print("\nDone. [OK] Tip: commit both Cargo.toml and Cargo.lock.") |
There was a problem hiding this comment.
when updating dependency/walk back dependency failed, the Cargo.toml and Cargo.lock will be in a bad state (e.g mixed of new version satisfied 7 days cutoff and less than 7 days cutoff). I think we need to revert the changes automatically or warn the user about it.
Furthermore, the cargo update does not run any build/test command. I think the suggestion for user when updating is Done is to run the build/test script verifying the new package works.
What changes are proposed in this pull request?
Adds a script + CI gate that enforces a "no newer than 7 days" supply-chain policy on every crates.io-sourced package in
Cargo.lock. Gives malicious uploads a week to be detected and yanked before they can land via a dependency bump.Main CUJs
scripts/upgrade_lockfile.py(Python 3.7+, no third-party deps):./scripts/upgrade_lockfile.py --checkRead-only; exits 1 on any package younger than
--days N(default 7)../scripts/upgrade_lockfile.pycargo updateeverything, then walk back any package that came in too new../scripts/upgrade_lockfile.py object_storeAuto-picks newest version
>= --daysold, bumps it, walks back transitive fallout../scripts/upgrade_lockfile.py object_store --precise 0.13.2Fails fast if the target version is itself too new.
CI integration
A
lockfile-age-policyjob inbuild.ymlruns--check --stricton every PR.dorny/paths-filtergates the actual work to PRs that touchCargo.toml,Cargo.lock, any workspaceCargo.toml, or the script itself.--strictmakes the run fail closed if crates.io is unreachable (escape hatch documented inline).How was this change tested?
Each CUJ exercised manually. Some outputs below show the script's earlier name
fix_lockfile.py(renamed mid-iteration; behavior is identical).CUJ 1:
--checkon clean main (passes)CUJ 1:
--check --days 200(220 violators)CUJ 2: bulk upgrade + walk-back (no args)
CUJ 3: auto-pick newest compliant (
object_store)Lock already had the newest compliant version, so the bump was a no-op. Confirms the resolution + disambiguation path:
CUJ 4: explicit version (
object_store --precise 0.13.2)