ci: require crates.io dependencies to be at least 48h old - #9312
Merged
Merged
Conversation
Cargo's `registry.global-min-publish-age` only constrains resolution, so versions already pinned in a Cargo.lock are grandfathered in and never re-checked. It cannot answer whether what we committed is too new. Add ci/check_dependency_age.py, which dates every crates.io version in the three lockfiles from the sparse index `pubtime` field and fails on anything under 48h old. Give dependabot a matching two-day cooldown so grouped bumps do not land versions CI will then reject. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
cmccabe
approved these changes
Sep 16, 2026
Dependabot security updates ignore cooldown by design, so a security fix can propose a version that is only minutes old. Without an escape hatch that PR sits red until the version ages out, which is backwards for exactly the updates that should land fastest. Add ci/dependency-age-allowlist.toml. Each entry names a crate, a version and a reason, and the reason is required so every exemption is reviewable in the diff. Entries go inert once the version passes the minimum age. The same floor is enforced on developer machines by Aikido endpoint protection, so an entry here must be paired with an Aikido allowlist entry; on its own it only unblocks CI. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
This check will succeed in 6 hours. It's a new rule and I don't want to have to revert and republish #9236 |
wjones127
marked this pull request as ready for review
September 16, 2026 21:06
Contributor
There was a problem hiding this comment.
The merge from main leaves the assessed patch unchanged, and the dependency-age scan now succeeds against the updated lockfiles; the earlier OpenDAL age window elapsed as expected.
The escape hatch remains an operational two-system contract: CI cannot verify that the matching Aikido exception was installed, so an exemption merged out of order can still leave developer builds blocked. The allowlist documents the required ordering; maintainers should confirm the Aikido change before accepting an exemption.
westonpace
approved these changes
Sep 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Aikido endpoint protection blocks developers from pulling crates.io versions that are too young, so a dependency bump that looks fine to whoever opened the PR can leave everyone else unable to build. Today nothing catches that until it reaches someone's machine, and the failure they see is an opaque cargo resolution error rather than "this version is too new".
This PR moves the check into CI.
ci/check_dependency_age.pydates every crates.io version inCargo.lock,python/Cargo.lockandjava/lance-jni/Cargo.lock, and fails if any of them is under 48 hours old. It runs as a new step in the existing cargo-deny job.Cargo's own
registry.global-min-publish-agesetting does not work for this. It only constrains resolution — versions already written into a lockfile are grandfathered in and never looked at again, so it cannot tell us whether what we committed is too new.Publish times come from the
pubtimefield of the sparse index, looked up in three tiers: cargo's index cache under$CARGO_HOME/registry/index/*/.cachefirst, which dates all three lockfiles in about two seconds with no network at all; then index.crates.io; then the crates.io API. The last tier matters more than it looks — Aikido filters the index it serves to developer machines, so on a laptop the index simply omits the offending version, and without the API fallback the script would report "cannot be dated" for precisely the versions it exists to flag.A version that no source can date fails rather than passing silently. A few very old versions predate the index
pubtimebackfill; those are reported and allowed.Escape hatch
Dependabot security updates ignore cooldown by design, so a security fix can arrive minutes after publication.
ci/dependency-age-allowlist.tomlexempts a specific crate and version, with a requiredreasonso every exemption is reviewable in the diff. Entries go inert once the version passes 48 hours, so pruning them is housekeeping rather than urgent.An entry here only unblocks CI. The version has to be allowlisted in Aikido too, or developers stay blocked locally — the file says so at the top.
Also changed
Dependabot gets a matching two-day
cooldownon the cargo ecosystem so grouped weekly bumps stop proposing versions CI would reject.python/Cargo.lockandjava/lance-jni/Cargo.lockare added to thepathsfilter inrust.yml, since otherwise a bump confined to one of those would not trigger the job that checks it.Testing
The check fails on
mainright now, which demonstrates it works rather than indicating a problem with the PR. #9236 bumped opendal to 0.59.2 about six hours after that version was published; it clears the 48h floor around 02:40 UTC on 2026-09-17, after which CI here should go green on its own. Verified locally that adding the opendal family to the allowlist takes the run from 18 violations to a clean exit.Not included
The
uv,pipandmavenecosystems get no cooldown, and there is no equivalent age check for Python or Java dependencies. The same argument applies to them, but Aikido's Rust path is what is biting today.🤖 Generated with Claude Code