Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:
cargo-cooldown is a Cargo wrapper designed to mitigate supply-chain risks by delaying the adoption of freshly published registry crate versions. It intercepts Cargo's resolution process, identifies versions that fall within a specified "cooldown" window, and attempts to replace them with the newest compatible older versions that Cargo will still accept. Sources: README.md:1-5
The system operates as an iterative resolver that repeatedly interacts with Cargo's metadata and lockfile mechanisms. It provides two primary modes of operation: guard-style commands (e.g., check, build) that cool the current lockfile before execution, and the update command, which allows Cargo to resolve the newest graph first before applying the cooling logic. Sources: README.md:28-40
Execution Pipeline
The core logic follows a pinning flow that manages the state of the Cargo.lock file. The process begins by capturing the initial state of the lockfile to establish a baseline and provide a restoration point in case of failure. Sources: src/executor.rs:43-52, src/executor.rs:59-62
The Pinning Flow
The pinning flow is an iterative loop that continues until a stable, cooled dependency graph is achieved or a failure condition (enforcement policy) is met.
The diagram above shows the iterative resolution loop managed by the executor to arrive at a cooled lockfile.
Sources: src/executor.rs:72-180
Core Components
1. Configuration System
The configuration system manages a hierarchy of settings, ranging from global defaults to project-specific overrides and environment variables. Sources: src/config.rs:88-100
| Component | Description |
|---|---|
cooldown_minutes | Threshold age (default 1440) for accepting a release. Sources: src/config.rs:163 |
enforcement | Defines behavior (Strict, CargoCompatible, Off) when fresh versions cannot be cooled. Sources: src/config.rs:15-32 |
lockfile_baseline | Determines if the initial lockfile acts as a version floor (Floor) or can be downgraded (Ignore). Sources: src/config.rs:59-71 |
AllowRules | Manual overrides for specific packages or exact versions. Sources: src/config.rs:79-80, README.md:83-100 |
2. Resolution State & Snapshot
Before cooling, the system builds a CargoSnapshot from cargo metadata. This compact representation contains only the reachable dependency closure relevant to the current command. Sources: src/resolution_state.rs:128-140
The ResolutionState aggregates facts for the current pass, including:
- Crate State: Metadata about each registry package (age, source, skip status). Sources: src/resolution_state.rs:36-46
- Requirement Origins: Tracking which parent package and which semver string constrained a child. Sources: src/resolution_state.rs:64-70
- Equality Dependents: Identifying crates tied by exact version requirements (
=x.y.z). Sources: src/resolution_state.rs:242-246
3. Batch Solver
The CooldownBatchSolver is an optimization that attempts to resolve multiple fresh crates in a single lockfile rewrite. It uses a local dependency solver to ensure that proposed assignments are internally consistent before asking Cargo to validate them. Sources: src/executor.rs:491-525
The sequence of validating a batch of cooled versions against Cargo's resolver.
Sources: src/executor.rs:541-576, src/executor.rs:638-662
Data Flow: Release Inspection
The system determines crate "freshness" by querying registry data. It prioritizes local information to minimize network overhead. Sources: README.md:104-106
- Local Index: Reads
pubtimedirectly from the local registry index. - HTTP Fallback: If
pubtimeis missing from the index, it queries the registry API (e.g., crates.io API). Sources: tests/integration.rs:135-155 - Cutoff Comparison: Compares the
published_attimestamp againstnow - cooldown_minutes. Sources: src/resolution_state.rs:206-215
// Logic for calculating the cutoff time based on configuration
fn cutoff_time(minimum_minutes: u64, now: DateTime<Utc>) -> DateTime<Utc> {
now - chrono::Duration::minutes(minimum_minutes as i64)
}
// Sources: src/resolver.rs (referenced in src/resolution_state.rs:214)
Setup and Initialization
The init module provides an interactive wizard to generate cooldown.toml files. It detects whether the project is a standalone crate or a workspace and plans the file creation accordingly, refusing to overwrite existing configurations. Sources: src/init.rs:35-50
Initialization flow for generating project configurations.
Sources: src/init.rs:53-112
Enforcement Policies
The architecture enforces cooling through different strategies based on the Enforcement setting:
| Policy | Behavior |
|---|---|
Strict | If any fresh version remains after all cooling attempts, the process fails and the original Cargo.lock is restored. Sources: src/executor.rs:260-272 |
CargoCompatible | Allows fresh versions to remain if Cargo requires them (e.g., due to semver constraints). It warns the user and may prompt for acceptance. Sources: src/executor.rs:277-310 |
Off | Bypasses all cooldown checks. Sources: src/config.rs:24 |
Sources: src/executor.rs:260-310, src/config.rs:15-32, README.md:65-80
Conclusion
The architecture of cargo-cooldown is designed to be a non-intrusive but rigorous layer over Cargo's own resolver. By leveraging cargo metadata for graph discovery and performing controlled Cargo.lock mutations, it ensures that any cooled dependency graph remains valid according to Cargo’s own logic while adhering to user-defined age requirements for registry packages. Sources: README.md:1-15, src/executor.rs:15-20