Skip to content

feat(solver): add minimum package age filter for security#1890

Merged
baszalmstra merged 8 commits intoconda:mainfrom
baszalmstra:claude/add-release-age-filter-01Jnto7XmZCZchzwpL3A25nu
Nov 27, 2025
Merged

feat(solver): add minimum package age filter for security#1890
baszalmstra merged 8 commits intoconda:mainfrom
baszalmstra:claude/add-release-age-filter-01Jnto7XmZCZchzwpL3A25nu

Conversation

@baszalmstra
Copy link
Collaborator

Add support for filtering packages based on their "minimum age", similar to pnpm's minimumReleaseAge feature. This helps reduce the risk of installing compromised packages by delaying the installation of newly published versions.

In most cases, malicious releases are discovered and removed from channels within a short time window (often within an hour). By requiring packages to have been published for a minimum duration, users can give the community time to identify and report malicious packages before they are installed.

Mostly written by Claude Opus 4.5.

I actually want to merge #1836 first so that we can use the much nicer test framework from that PR.

@baszalmstra baszalmstra requested a review from wolfv November 26, 2025 15:19
@baszalmstra baszalmstra force-pushed the claude/add-release-age-filter-01Jnto7XmZCZchzwpL3A25nu branch 5 times, most recently from a712619 to 141cdad Compare November 26, 2025 17:50
Add support for filtering packages based on their minimum age, similar to
pnpm's `minimumReleaseAge` feature. This helps reduce the risk of installing
compromised packages by delaying the installation of newly published versions.

In most cases, malicious releases are discovered and removed from channels
within a short time window (often within an hour). By requiring packages to
have been published for a minimum duration, users can give the community time
to identify and report malicious packages before they are installed.

## New API

Added `MinimumAgeConfig` struct with the following fields:
- `min_age: Duration` - The minimum age a package must have
- `now: DateTime<Utc>` - Reference time for calculating cutoff (defaults to current time)
- `exempt_packages: HashSet<PackageName>` - Packages exempt from the check

Added `min_age: Option<MinimumAgeConfig>` field to `SolverTask`.

## Example Usage

```rust
use std::time::Duration;
use rattler_solve::MinimumAgeConfig;

// Only allow packages published at least 1 hour ago
let config = MinimumAgeConfig::new(Duration::from_secs(60 * 60))
    .with_exempt_package("my-trusted-package".parse().unwrap());
```

## Implementation

- Implemented in both `resolvo` and `libsolv_c` backends
- Packages newer than `now - min_age` are excluded from the solve
- Exempt packages bypass the age check
- Clear error messages indicate when packages are excluded due to age
@baszalmstra baszalmstra force-pushed the claude/add-release-age-filter-01Jnto7XmZCZchzwpL3A25nu branch from 141cdad to bb1cb05 Compare November 27, 2025 08:24
…e-filter-01Jnto7XmZCZchzwpL3A25nu

# Conflicts:
#	Cargo.lock
#	py-rattler/Cargo.lock
Move min_age tests from the macro in main.rs to a dedicated
min_age_tests.rs module using the new SolverCase testing framework.

- Add min_age support to SolverCase helper
- Create new min_age_tests module with 5 test cases:
  - solve_min_age_filters_new_packages
  - solve_min_age_with_exemption
  - solve_min_age_with_dependencies
  - solve_min_age_exempt_dependency
  - solve_min_age_no_timestamp
Copy link
Contributor

@wolfv wolfv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool stuff!

Packages without a timestamp are now excluded by default when a minimum
age filter is active. Add `include_unknown_timestamp` option (defaults to
false) to allow including them if desired.

- Add `include_unknown_timestamp` field to MinimumAgeConfig
- Add `with_include_unknown_timestamp()` builder method
- Update filtering logic in both resolvo and libsolv_c backends
- Update Python bindings with new constructor parameter
- Add tests for the new behavior
Updated test to verify that when a package has two versions where the
higher version lacks a timestamp, the solver correctly selects the
lower version with a valid timestamp (since packages without timestamps
are excluded by default).
Verifies that packages exempted from min_age filtering are included
even when they don't have a timestamp. The exemption takes precedence
over the unknown timestamp exclusion.
@wolfv wolfv enabled auto-merge (squash) November 27, 2025 13:52
@baszalmstra baszalmstra disabled auto-merge November 27, 2025 14:24
@baszalmstra baszalmstra merged commit 1d9dfa4 into conda:main Nov 27, 2025
16 of 17 checks passed
@github-actions github-actions bot mentioned this pull request Nov 27, 2025
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.

3 participants