Tool for validating that all workspace dependencies are at least cooldown_minutes minutes old.
Inspired by cargo-cooldown.
Cargo dependencies in Cargo.toml declare version requirements — ranges, not exact versions. The default caret syntax ("1.4", equivalent to "^1.4") allows any semver-compatible release (>=1.4.0, <2.0.0). Cargo automatically resolves to the newest compatible version and locks the result in Cargo.lock. There is no need to pin a specific patch to get the latest — Cargo does that on its own. Cargo.toml should express restrictions, and Cargo.lock records the exact resolved versions.
Supply-chain attacks exploit this by publishing a malicious patch or minor release that Cargo will adopt the next time dependencies are resolved. This creates a tension: version requirements should be as broad as possible to give the resolver flexibility, but that same breadth means freshly-published — and potentially compromised — versions are adopted automatically. This tool resolves that tension by validating that every dependency in Cargo.lock, including transitive ones, is older than a configurable cooldown period.
Broad requirements remain the right default — tighter constraints do not prevent adopting a compromised version, since Cargo still picks the newest within the allowed range. Narrowing a requirement down to a patch (e.g. =1.4.2 or ~1.4.2) only reduces flexibility for the resolver and for this tool when suggesting alternative versions. Avoid it unless earlier versions have known issues you need to exclude.
- Fail if any dependency violates the cooldown period
- Identify which dependencies fail the check
- Suggest candidate versions that satisfy the cooldown
- Automatically update
Cargo.lockwith older dependencies - Create
Cargo.lockif it is not present
cargo install --git https://github.com/NomicFoundation/cargo-cooldown-checkAdd the following step to your workflow:
- uses: NomicFoundation/cargo-cooldown-check@v0.1.2 # or pin to a commit SHA
# with:
# verbose: "true" # optionalThe action reads configuration from .cargo/cooldown.toml and .cargo/cooldown-allowlist.toml in your repository, so make sure to commit these files.
Each release publishes a hermit search index as the index release asset, so this repository can be used as a custom hermit source. To let Renovate automatically open update PRs for the pinned hermit package, add a packageRules entry in renovate.json that points the hermit manager at this repo for the cargo-cooldown-check package:
{
"packageRules": [
{
"matchManagers": ["hermit"],
"matchPackageNames": ["cargo-cooldown-check"],
"registryUrls": ["https://github.com/NomicFoundation/cargo-cooldown-check"]
}
]
}# Run from the workspace root
cargo cooldown-check
# Verbose output
cargo cooldown-check -vWorkspace configuration is defined in <workspace_root>/.cargo/cooldown.toml:
cooldown_minutes = 10080 # 7 days
# cache_dir = "/tmp/cooldown-cache" # optional
# cache_ttl_seconds = 86400 # optional, defaults to 1 dayAllowlist rules can lower the effective cooldown per crate or permit an explicit version via <workspace_root>/.cargo/cooldown-allowlist.toml:
# Skip cooldown for a specific crate version
[[allow.exact]]
crate = "foo"
version = "1.2.3"
# Lower the cooldown for a specific crate (minutes)
[[allow.package]]
crate = "tokio"
minutes = 1440The tool only identifies dependencies that violate the cooldown period and suggests actions — it never modifies Cargo.lock itself.
When a dependency fails the check, one of two things happens:
- Candidate versions exist: the tool lists older versions that satisfy the cooldown and prints a command to downgrade:
cargo update <crate> --precise <version> - No candidate versions exist: no published version is both old enough and compatible with the semver constraints in the dependency graph. The tool suggests to relax the constraints, wait for the cooldown to elapse, or allowlist the crate.
Candidate versions will:
- Not have been yanked
- Satisfy all observed semver requirements (across every dependent in the graph)
- Be older than the current lockfile entry
- Have been published before the cooldown cutoff
- The tool invokes
cargo metadatato read the full dependency graph and records everyVersionReqthat parents impose on their children. - For each crate sourced from a watched registry, it fetches publication metadata from the crates.io HTTP API through a small on-disk cache and computes the package age.
- Only dependencies sourced from the crates.io registry are checked. Packages from other registries, git sources, or local paths are silently skipped.
- Configuration file paths are not configurable (
cooldown.tomlandcooldown-allowlist.toml). - Configuration is only possible through files; environment variables are not supported.
See CONTRIBUTING.md for the release workflow and how to publish new versions.
- Identify if the violating crate is a direct or transitive dependency.
- If it's a transitive dependency suggest the user how to identify which crate is pulling it in.