Skip to content

Add a uv resolution cooldown for the Python deps#861

Open
timhaines wants to merge 1 commit into
usestrix:mainfrom
timhaines:add-uv-cooldown
Open

Add a uv resolution cooldown for the Python deps#861
timhaines wants to merge 1 commit into
usestrix:mainfrom
timhaines:add-uv-cooldown

Conversation

@timhaines

@timhaines timhaines commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

A resolver-layer release-age cooldown for the Python dependency tree. uv won't resolve a version until it's a few days old.

[tool.uv]
required-version = ">=0.9.17"
exclude-newer = "6 days"
exclude-newer-package = { cryptography = false }

This gates what uv lock / uv add / uv sync will resolve, which means it also covers the manual and local updates nobody opens a PR for. It does not affect uv sync --frozen, which installs the lockfile verbatim, so the release workflow behaves exactly as it does today.

Why bother — this isn't hypothetical for this project

litellm, a core strix dependency, was compromised in the TeamPCP campaign on 24 Mar 2026: malicious 1.82.7/1.82.8 sat on PyPI for ~40 minutes, long enough for tens of thousands of downloads, running a .pth injector on import to exfiltrate cloud credentials. The same actor backdoored telnyx, and Microsoft's durabletask fell the same way in May (three bad versions in a 35-minute window).

These are smash-and-grab attacks. The malicious version harvests credentials the moment it installs, gets spotted, and is pulled within minutes to hours. The blast radius is whoever resolves the newest version inside that window. A few-days cooldown means a uv lock or a bump never resolves to a release that young.

The honest limit: a cooldown does nothing against a compromise that stays hidden longer than the window. It filters the fast ones, which is what these have been.

Why 6 days

Long enough to clear the window every incident above sat in, short enough not to stall ordinary updates for a week.

cryptography is exempt via exclude-newer-package = { cryptography = false }, so its security patches land immediately. Its <49 cap needs nothing extra here — uv honours that pyproject.toml constraint natively at resolution.

uv version

The relative exclude-newer and exclude-newer-package options both landed in uv 0.9.17 (Dec 2025), so required-version = ">=0.9.17" is set. An older uv then fails with a clear "upgrade uv" message rather than a confusing parse error. The release workflow's astral-sh/setup-uv installs current uv, so CI is already well above this floor; it only matters for a contributor on a stale local uv.

About the lockfile

Adding exclude-newer forces a full re-resolution, and uv records the window in uv.lock's [options] block. uv lock --check fails until the lock is regenerated, so it's committed here.

A cooldown PR that touches the lock deserves scrutiny, so here's exactly what moved: no package versions changed. setuptools stays at 83.0.0 — the recent GHSA-h35f-9h28-mq5c bump is in the base and survives the cooldown untouched. The only other delta is uv emitting more precise environment markers on the pyinstaller/macholib dependency edges, which is an artifact of resolving from scratch instead of incrementally. The control for that: a plain uv lock with no cooldown on the same tree produces a no-op diff, so the markers are attributable to the re-resolve and not to this setting.

Rebased on current main.

Relationship to #860

Stands alone. Merge it in any order, or on its own if you'd rather not take the Dependabot config.

The two are complementary rather than sequential. #860's cooldown gates when a bump PR opens; this gates what any resolution produces, so the resolver layer covers the local and manual path Dependabot never sees, and it keeps working if the Dependabot config is ever changed or removed. The 6 days is picked to sit one day under #860's 7 so a version Dependabot proposes still resolves cleanly here if both land. If #860 doesn't land, 6 days is a sensible standalone window either way.

It is a little opinionated, since it changes what uv lock resolves, so it's happily droppable if you'd rather keep just the updater-side cooldown.

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a release-age cooldown for Python dependency resolution. The main changes are:

  • A six-day cooldown for packages resolved by uv.
  • An exemption that allows immediate cryptography updates.
  • A minimum supported uv version.
  • Updated lockfile options and environment markers.

Confidence Score: 5/5

This looks safe to merge.

  • The minimum uv version addresses the previously reported compatibility path.
  • The lockfile records the configured cooldown and exemption.
  • No blocking issue was found in the updated code.

Important Files Changed

Filename Overview
pyproject.toml Adds the uv version requirement, six-day package cooldown, and cryptography exemption.
uv.lock Records the cooldown settings and refines markers on PyInstaller-related dependency edges without changing package versions.

Reviews (2): Last reviewed commit: "Add a uv resolution cooldown (exclude-ne..." | Re-trigger Greptile

Comment thread pyproject.toml
@timhaines
timhaines force-pushed the add-uv-cooldown branch 2 times, most recently from d29b552 to a0f326d Compare July 23, 2026 05:06
Comment thread pyproject.toml
# Don't resolve a version until it's a few days old — a guard against a freshly-
# compromised upstream. One day under the Dependabot cooldown so its bumps still
# resolve here; cryptography is exempt for fast security patches. Needs uv >= 0.9.17.
required-version = ">=0.9.17"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For reviewers: uv 0.9.17 shipped Dec 2025 (~7 months ago), and the release workflow's astral-sh/setup-uv@v5 installs the latest uv — so CI is unaffected. This floor only guards a contributor on a stale local uv (giving a clear "upgrade uv" error rather than a confusing parse failure).

timhaines added a commit to timhaines/strix that referenced this pull request Jul 23, 2026
The npm analog of the uv exclude-newer in usestrix#861. min-release-age=6 in an
.npmrc under the frontend gates tree resolution (npm install/update,
lockfile regen) so a version has to age a few days before it resolves —
one day under the Dependabot cooldown so bumps still land here.

min-release-age arrived in npm 11.10.0 and is a no-op on older npm, which
would fail the cooldown open. engine-strict + engines.npm >= 11.10.0 make
an older npm error instead. Does not affect npm ci (lockfile verbatim).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@timhaines timhaines changed the title Add a uv resolution cooldown to match the Dependabot config Add a uv resolution cooldown for the Python deps Jul 23, 2026
timhaines added a commit to timhaines/strix that referenced this pull request Jul 23, 2026
The npm analog of the uv exclude-newer in usestrix#861. min-release-age=6 in an
.npmrc under the frontend gates tree resolution (npm install/update,
lockfile regen) so a version has to age a few days before it resolves —
one day under the Dependabot cooldown so bumps still land here.

min-release-age arrived in npm 11.10.0 and is a no-op on older npm, which
would fail the cooldown open. engine-strict + engines.npm >= 11.10.0 make
an older npm error instead. Does not affect npm ci (lockfile verbatim).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…config

Adds [tool.uv] exclude-newer = "6 days" so uv won't resolve to a brand-new
release for a few days -- a guard against pulling a just-published, possibly
compromised version. Set one day under the companion 7-day Dependabot cooldown
so a version Dependabot proposes still resolves cleanly here; cryptography is
exempt from the cooldown to mirror the Dependabot cooldown exclude so its
security patches aren't delayed. uv sync --frozen is unaffected.

These options landed in uv 0.9.17 (Dec 2025); required-version = ">=0.9.17"
enforces the floor so an older uv fails with a clear message rather than a
confusing parse error.

Also commits the regenerated uv.lock. Adding exclude-newer forces a full
re-resolution, so uv records the window in the lockfile's [options] block and
`uv lock --check` fails until the lock is regenerated. No package versions
change -- the only other delta is uv emitting more precise environment markers
on the pyinstaller/macholib dependency edges, which is a re-resolution artifact
(a plain `uv lock` on the current tree is a no-op diff).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@timhaines

Copy link
Copy Markdown
Contributor Author

@greptile

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.

1 participant