## Summary
When the uv version is read from dependencies (`requirements.txt`, or
`project.dependencies` / `optional-dependencies` / `dependency-groups`
in `pyproject.toml` via `version-file`), the specifier was matched with
`/^uv([=<>~!]+\S*)/`. PEP 508 allows whitespace around operators and
after commas, and those valid forms were misread:
| dependency | before | after |
|---|---|---|
| `uv >= 0.5.0` | not found, latest uv installed | `>=0.5.0` |
| `uv == 0.11.20` | not found, latest uv installed | `==0.11.20` |
| `uv>=0.5.0, <0.6.0` | `>=0.5.0,`, fails with `No version found for
>=0.5.0,` | `>=0.5.0,<0.6.0` |
The regex now allows whitespace around operators and between
comma-separated clauses, and strips it from the result. Inputs that
worked before give the same result, including inline `--hash=` options,
trailing ` # comments`, the `\` continuation lines from `uv pip compile
--generate-hashes`, and names that only start with `uv` (`uvicorn`,
`uv-build`).
## Test plan
- Added cases for spaced operators, spaced clauses, inline `--hash` and
trailing comments. The four whitespace cases failed before the change.
- `npm run all` on Ubuntu (WSL) with Node 24.19.0: build, Biome (no
fixes), packaging, and 165 tests across 15 suites pass. The rebuilt
`dist/setup/index.cjs` only differs in the changed line.
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary
`~=` is the PEP 440 compatible release operator, but the resolver tries
`semver.validRange()` first, and semver accepts `~=` as a tilde range:
| specifier | semver | PEP 440 |
|---|---|---|
| `~=0.9` | `>=0.9.0 <0.10.0` | `>=0.9, ==0.*` |
So with the default `highest` strategy, `version: "~=0.9"` (or
`required-version = "~=0.9"` picked up through `version-file`) installs
the highest 0.9.x instead of the highest 0.x. The same happens with
`manifest-file`, where `tc.evaluateVersions` is semver-based.
This skips the semver evaluation for specifiers containing `~=`, so they
are only evaluated with `@renovatebot/pep440`. No semver range
legitimately uses `~=`.
Notes:
- Only a bare two-segment `~=X.Y` resolved incorrectly. `~=X.Y.Z` gives
the same result in both, and compound specifiers like `~=0.9, !=0.9.3`
were already rejected by semver and fell through to PEP 440.
- `minSatisfying` gets the same check for consistency. The lower bound
is the same under both interpretations, so `lowest` didn't produce wrong
results before.
- A single-segment `~=1` is invalid PEP 440. semver used to resolve it
to 1.x; it now fails with `No version found for ~=1`, same as other
invalid specifiers.
## Test plan
- Added tests for `~=0.9` with the default manifest and with
`manifest-file`. Both returned `0.9.26` instead of `0.10.2` before the
change.
- `npm run all` on Ubuntu (WSL) with Node 24.19.0: build, Biome (no
fixes), packaging, and 161 tests across 15 suites pass. The rebuilt
`dist/setup/index.cjs` only differs in the changed lines.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary
The post step logs `uv cache saved with key: ...` (and `Python cache
saved with key: ...`) even when the save failed. The log in #769 shows
it right after `Warning: Failed to save: ...`:
```
Warning: Failed to save: "C:\Program failed with error: The process 'C:\Program Files\Git\usr\bin\tar.exe' failed with exit code 2
uv cache saved with key: setup-uv-2-x86_64-pc-windows-msvc-windows-11-3.12.12-pruned-...
```
`@actions/cache`'s `saveCache` doesn't throw for these failures. It logs
them and returns `-1`, and `saveCacheToKey` ignored the return value.
This now checks for `-1` before logging, which is the same check the
`actions/cache` save step uses (`if (cacheId != -1) core.info("Cache
saved with key: ...")`). `@actions/cache` already logs the reason, so
nothing else is logged on failure, and the exit code stays the same.
This only changes the log line. It doesn't address the underlying
tar/gzip failure in #769. One limitation: with the legacy (v1) cache
service, an upload that fails after the cache was reserved still returns
the reserved id, so that one case is still reported as saved. That's on
the `@actions/cache` side and affects `actions/cache` the same way.
Related to #769
## Test plan
- Added `__tests__/cache/save-cache.test.ts`. The `-1` case fails before
the change and passes after it.
- `npm run all` on Ubuntu (WSL) with Node 24.19.0 / npm 11.17.0: build,
Biome (no fixes), packaging, and all 161 tests across 16 suites pass.
The regenerated `dist/save-cache/index.cjs` only differs in the changed
lines.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary
Roll up the remaining dependency changes from eight open Dependabot PRs
against current `main`, without reverting newer workflow settings:
- CodeQL init, analyze, and autobuild: 4.37.7 → 4.38.1 (#1097, #1096,
#1095)
- zizmor-action: 0.6.3 → 0.6.4 (#1085)
- @biomejs/biome: 2.5.9 → 2.5.11, including its schema URL (#1075)
- @types/node: 26.2.0 → 26.4.0 (#1074)
- Jest: 30.4.2 → 30.5.0 (#1073)
- js-yaml: 5.3.0 → 5.4.1 (#1072)
All nine open Dependabot PRs had remaining dependency changes; none was
a no-op. TypeScript 7.0.2 (#1029) is intentionally deferred with
maintainer approval: ts-jest 29.4.11 requires TypeScript <7, and
applying the update caused all 15 test suites to fail before running
with `Cannot read properties of undefined (reading 'readFile')`.
The lockfile was regenerated using npm install with scripts disabled. No
runtime dependency entries changed, and repackaging produced no `dist/`
changes.
## Validation
Using Node 24.19.0 and npm 11.10.0:
- `npm ci --ignore-scripts`
- `npm run all` — passed; 15 test suites, 159 tests; Biome applied no
fixes
- `npm audit signatures` — all 353 audited packages have verified
registry signatures; 38 have verified attestations
- `actionlint .github/workflows/codeql-analysis.yml
.github/workflows/test.yml` — passed
- `uvx zizmor --no-progress --offline
.github/workflows/codeql-analysis.yml .github/workflows/test.yml` — no
findings
- `git diff --check` — passed
Refs: pi-session 01a15ec2-de1a-7557-a0bb-00369b0a4a10
## Summary
- Preserve class names in the save-cache bundle so `@actions/cache`
error-name comparisons distinguish validation errors, benign
cache-reservation races, and finalization errors correctly.
- Add regression coverage that exercises the bundled `ValidationError`,
`ReserveCacheError`, and `FinalizeCacheError` constructors.
Fixes#1028
## Verification
- `npm run all` passed on Ubuntu 24.04 with Node 24.19.0: build, Biome,
packaging, and all 159 tests across 15 suites.
- `git diff --check` passed.
The save-cache bundle increases by about 77 KB raw (14 KB gzip) to
preserve the required names.
CI installs the locked npm dependency tree without running lifecycle
scripts, but it does not verify registry signatures or available
provenance attestations. Run `npm audit signatures` after installation
in both the test and checksum-update workflows, before `npm run all`
executes dependency tooling. The check follows npm's registry-signature
support and verifies attestations when present; it does not require
every dependency to publish provenance.
Related: astral-sh/ruff-action#402 adds the same signature and
provenance verification. astral-sh/setup-uv#1026 separately hardens
`npm` install defaults.
Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
Windows ARM64 jobs may need x64 Python independently of their Python
version pin. Add `python-arch` to export `UV_PYTHON_ARCH` for subsequent
steps and include the selected architecture in the uv and managed-Python
cache keys. The input takes precedence over an inherited environment
value, and unsupported uv versions fail before environment creation.
Requires a uv release with `UV_PYTHON_ARCH` support.
We move the `macos-14` test jobs to `macos-15` ahead of GitHub’s
[October 5 brownout and November 2, 2026
retirement](https://github.com/actions/runner-images/issues/13518).
We also remove the macOS 14 cache-key test case; the matrix already
covers macOS 15.
## Summary
- bump `@biomejs/biome` from 2.5.7 to 2.5.8 (#1042)
- bump `@types/node` from 26.1.2 to 26.2.0 (#1039)
- bump `esbuild` from 0.28.1 to 0.28.2 (#1040)
- update the Biome schema URL to 2.5.8
The TypeScript 7.0.2 update from #1029 is intentionally excluded:
`ts-jest` currently declares TypeScript `<7`, and the update causes all
unit suites to fail during ts-jest configuration.
## Validation
- `npm run all` (npm 11.10.0)
Refs: pi-session 01a08ca1-d3b3-7190-a02e-9a955e1b58b0
https://github.com/pyca/cryptography/pull/15572#discussion_r3913508686
has the context for this: TL;DR our current `python-version` output
mirrors the "request" version exactly, which means that it's
insufficient for any downstream that needs to manage its own cache keys
(since caches shouldn't be shared across release candidates, but the `uv
python` request version doesn't include RC numbers).
The first commit here was my attempt to fix this by exposing the runtime
Python version, but this too is imprecise: the runtime version doesn't
indicate the interpreter variant (e.g. freethreading), which is also
important to capture in the cache identity.
My solution here is to expose `python-runtime-id`, which is just the
`key` of the active Python version from `uv python list
--output-format=json`.
---------
Signed-off-by: William Woodruff <william@yossarian.net>
`setup-uv` currently ignores the `sha256` supplied by the default
`astral-sh/versions` manifest when a selected artifact is newer than its
bundled checksum table, allowing that download to proceed without
validation. Use the manifest checksum as a fallback after explicit and
bundled checksums, and reject manifest entries that do not provide one.
This preserves the stronger pinned hashes for known releases while
verifying newer releases without requiring an action update. Part of
#1032.
---------
Co-authored-by: Zanie Blue <contact@zanie.dev>
Co-authored-by: William Woodruff <william@yossarian.net>
Co-authored-by: Kevin Stillhammer <kevin.stillhammer@gmail.com>
CI already disables npm lifecycle scripts, but ordinary installs from
the repository still run them. Set `ignore-scripts = true` in `.npmrc`
so developer and maintenance installs use the same default. Keep the
existing seven-day `min-release-age` policy for new resolutions. Require
`npm>=11.10.0` through `engines.npm` and `engine-strict`, while
retaining `devEngines` for newer clients; older installers can otherwise
ignore `devEngines` and the age setting. Pin the build and checksum
workflows to Node.js `24.19.0` so their bundled `npm` supports the
policy. Explicit project commands such as `npm run package` remain
available.
Related: astral-sh/ruff-action#401 applies the matching `npm` defaults,
and astral-sh/ruff-action#411 adds the same legacy-aware version floor.
astral-sh/ruff#27837 applies the install-script default to Ruff's
JavaScript projects. astral-sh/setup-uv#1027 separately adds
registry-signature and provenance verification.
---------
Co-authored-by: zaniebot <242828183+zaniebot@users.noreply.github.com>
With the self-repo syntax, we also shouldn't need any of these
`actions/checkout` calls.
Signed-off-by: William Woodruff <william@yossarian.net>
---------
Signed-off-by: William Woodruff <william@yossarian.net>
This just adds some pins to the action tests; these tests don't rely on
the packages under test being unpinned.
---
<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>