Add a uv resolution cooldown for the Python deps#861
Open
timhaines wants to merge 1 commit into
Open
Conversation
Contributor
Greptile SummaryThis PR adds a release-age cooldown for Python dependency resolution. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (2): Last reviewed commit: "Add a uv resolution cooldown (exclude-ne..." | Re-trigger Greptile |
timhaines
force-pushed
the
add-uv-cooldown
branch
2 times, most recently
from
July 23, 2026 05:06
d29b552 to
a0f326d
Compare
timhaines
commented
Jul 23, 2026
| # 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" |
Contributor
Author
There was a problem hiding this comment.
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).
This was referenced 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>
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
force-pushed
the
add-uv-cooldown
branch
from
July 24, 2026 22:24
a0f326d to
ff44890
Compare
Contributor
Author
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.
A resolver-layer release-age cooldown for the Python dependency tree. uv won't resolve a version until it's a few days old.
This gates what
uv lock/uv add/uv syncwill resolve, which means it also covers the manual and local updates nobody opens a PR for. It does not affectuv 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: malicious1.82.7/1.82.8sat on PyPI for ~40 minutes, long enough for tens of thousands of downloads, running a.pthinjector on import to exfiltrate cloud credentials. The same actor backdooredtelnyx, and Microsoft'sdurabletaskfell 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 lockor 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.
cryptographyis exempt viaexclude-newer-package = { cryptography = false }, so its security patches land immediately. Its<49cap needs nothing extra here — uv honours thatpyproject.tomlconstraint natively at resolution.uv version
The relative
exclude-newerandexclude-newer-packageoptions both landed in uv 0.9.17 (Dec 2025), sorequired-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'sastral-sh/setup-uvinstalls 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-newerforces a full re-resolution, and uv records the window inuv.lock's[options]block.uv lock --checkfails 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.
setuptoolsstays at83.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 thepyinstaller/macholibdependency edges, which is an artifact of resolving from scratch instead of incrementally. The control for that: a plainuv lockwith 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 lockresolves, so it's happily droppable if you'd rather keep just the updater-side cooldown.🤖 Generated with Claude Code