Currently, path normalization doesn't catch some cases, such as
`foo//bar` or `foo/./bar`, because they are not shown as components. By
checking whether the normalized version build from iterating over
components would be the same length as the current path, we can check
whether we need to normalize, without allocating when the path is
already normalized.
---------
Co-authored-by: Tomasz Kramkowski <tom@astral.sh>
## Summary
This fixes two (unrelated) bugs in `uv audit`:
1. We now correctly handle `--script` in general, including producing an
appropriate error message when the user requests `uv audit --script ...
--frozen` without a lockfile being present. Doing this required adapting
`MissingLockfile` slightly to ensure we can return an appropriate
lockfile name rather than just the generic `uv.lock`.
2. We now correctly collect extras on requirements/dep groups when
performing the `packages_for_audit` BFS. This was an oversight in my
original traversal.
## Test Plan
Added integration tests for both of these.
---------
Signed-off-by: William Woodruff <william@astral.sh>
`workspace metadata` was the only subcommand with quotes in the linehaul
data, splitting this into an array as we do for `uv pip <…>` subcommands
should fix this.
Closes https://github.com/astral-sh/uv/issues/18890
Resolves the unexpected regression in 0.11 where `rustls-native-certs`
was previously performing filtering and switching to populating
certificates in reqwest ourselves resulted in stricter validation.
Follows https://github.com/astral-sh/uv/pull/18924 which added
pre-validation of certificates with better error messages. We retain
some of the error infrastructure for formatting a warning, but no longer
propagate it upward. We emit a log instead of a noisy user-facing
warning because they are often powerless to fix this and it's only
consequential if they attempt to communicate with a service that
requires the certificate (at which point, we'd just fail anyway).
Ideally, there's an upstream resolution in
https://github.com/rustls/webpki/issues/464 as we're still reading and
validating all of these certificates more than once.
## Summary
This is towards #18781 -- we now have a small `Filter` type, and we can
filter an OSV query to limit it to just malware results by passing
`Filter::Malware`. This has no performance cost versus normal queries
since with OSV's "batch query" API we can cheaply pre-filter IDs before
actually fetching the full OSV payloads.
## Test Plan
Added a unit test that exhibits the filtering.
---------
Signed-off-by: William Woodruff <william@astral.sh>
Check the RECORD of a wheel file and heal it if necessary, to ensure the
RECORD and the wheel contents always match, and uninstallation can't
remove files that don't belong to the wheel. This check and repair
happen between unpacking a wheel and persisting it in the cache,
ensuring that every wheel that ends up in the cache has a valid RECORD.
We collect the paths from the archive in the unpacking step, I added it
in all unpacking steps for consistency. I also improved the consistency
around RECORD handling code.
---------
Co-authored-by: Zanie Blue <contact@zanie.dev>
## Summary
Closes#16586
Adds a public function to `uv-fs` crate called `verbatim_path` which is
now leveraged by `rm_rf` in `uv-cache` crate for cleaning paths that
require verbatim composition to avoid failures seen in #16586.
## Test Plan
Tested locally on Windows 10 and 11 by setting `UV_CACHE_DIR` to a local
directory and then running `uv init`, `uv add uwsgi`, and `uv cache
clean` to ensure there is no failures.
Additionally unit and integration tests were added to avoid future
regressions.
Check that only files inside the installation scheme can be removed when
uv uninstalls a package. This fixes a bug where uv would try to remove
arbitrary files due to a malformed or malicious RECORD file in a wheel.
For venvs, the installation prefix is the entire venv, as `.data/data`
allows wheels to write to the entire venv, so all files in the venv can
also be removed.
This is both a correctness fix (uv should never remove files outside its
domain) and a low severity security fix, where a malicious wheel could
remove a user's files during uninstallation, such as a `uv sync` that
upgrades the package version. Note that this requires an attacker having
control over the wheel, which also allows them to modify arbitrary
Python code. There are no known cases of wheels actually referencing
files outside the installation scheme in their RECORD.
See https://github.com/astral-sh/uv/issues/18890
Adds special-case validation for `SSL_CERT_FILE` and `SSL_CERT_DIR`
where we actually check if webpki will accept the given certificates
and, if not, emit a better error message about why. This means we
perform eager validation of certificates, parsing them more than once
since reqwest will parse them again on client build. Unfortunately,
there's not a straight-forward way to provide our pre-parsed
certificates to reqwest without doing a lot more work. Nor is there a
clear way to retrieve the parsed certificates on error.
We use https://github.com/rusticata/x509-parser for parsing which seems
reputable.
We may want to _drop_ all invalid certificates instead, but that can be
a future decision and this machinery can be reused for warnings.
Ideally webpki would just have better error messages, but that's a
separate project.
## Summary
This PR enables users to set an `exclude-newer` override on a per-index
basis.
The priority is such that global `exclude-newer-package` has highest
priority, followed by `exclude-newer` on an index, followed by global
`exclude-newer`.
Closes https://github.com/astral-sh/uv/issues/16813.
## Summary
This makes one small QoL change to `uv audit`:
- We now warn the user if they ignore (via CLI or config) a
vulnerability ID, but that ID doesn't actually match any known
vulnerabilities discovered during the audit. This can happen due to
drift (e.g. the user upgrades but forgets to removed a stale ID) or user
error (the user typos a vulnerability ID).
~~- We now report the number of ignored vulnerabilities as a statistic
in the output. In practice, this means users will see something like "5
vulnerabilities (2 ignored)" in the header of `uv audit`'s output if
they ignore vulnerabilities.~~
See #18506.
## Test Plan
Added integration tests for the new behavior.
---------
Signed-off-by: William Woodruff <william@astral.sh>
## Summary
This PR attempts to apply the same canonicalization we apply at
serialization time, but in-memory when constructing the `Lock`, to
further avoid mismatches between the deserialized and in-memory
representations.
Closes https://github.com/astral-sh/uv/issues/18553.
## Summary
Reproduces and fixes#18793.
Previously, when uninstalling Python versions on Windows, we'd remove
junctions (i.e. soft links) for the minor version _after_ deleting the
installation itself. This worked correctly on Linux and macOS but _not_
on Windows, since on Windows we'd call `junction::get_target` (via
`PythonMinorVersionLink::exists`), which would fail because the junction
would be dangling following the deletion. Specifically, `read_target`
returns `None`, short circuiting the `target_directory` check.
The fix here is to reorder the uninstallation flow so that we precompute
and remove the links _before_ the underlying installations are deleted.
I've added two tests that both reproduced the behavior and now
demonstrate the fix working.
Note:
https://github.com/astral-sh/uv/pull/18815/changes/81c27ba0e1f225189949ddb60bc11e6902e55dd0
shows a smaller alternative fix -- instead of reordering the
installation flow, we can change the "entry exists" logic on Windows to
not require that the target still exists. I believe this would also be
functionally correct, but I think reordering the uninstallation flow
makes more sense (in terms of eliminating the surprising state rather
than trying to work around it).
## Test Plan
Look at me, I am the test plan now.
---------
Signed-off-by: William Woodruff <william@astral.sh>
Co-authored-by: Zanie Blue <contact@zanie.dev>
A small typo:
uv init example --bare --> uv init example-bare --bare
<!--
Thank you for contributing to uv! To help us out with reviewing, please
consider the following:
- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->
## Summary
<!-- What's the purpose of the change? What does it do, and why? -->
## Test Plan
<!-- How was it tested? -->
We now enforce that a successful deployment was created to prevent a
malicious actor from making this job pass without going through the
release-gate environment
See https://github.com/astral-sh/uv/issues/18890
We can load a certificate that is a valid bundle, but on client build we
can fail if the certificate is unsupported for various reasons. This
propagates the error instead of panicking.
In `normalize_path`, also remove trailing (back)slashes. Rust ignores
trailing slashes in many operations, such as iterating components and
notably equality (`Path::new("foo/") == Path::new("foo")`), but it does
break workspace discovery and caching if not normalized.
The implementation is inelegant as Rust exposes no way to access the
last char of a path properly, so we look at the last byte instead.
## Summary
These requirements are technically "transitive", so we miss them in our
initial pass. As such, we need to collect them while we lookahead.
Closes https://github.com/astral-sh/uv/issues/18778.
## Summary
If we encounter multiple hashes for the same direct URL, we now (1)
reject if they use the same algorithm but different values, and (2)
collect if they use different algorithms. This includes cases in which a
user provides _both_ a hash in the fragment _and_ via `--hash`.
For now, if _any_ hash is correct, the URL will be accepted; we'll
change this in the future. (On main, we only consider the last-seen hash
anyway.)
## Summary
We want to reuse this in `[[tool.uv.index]]` definitions, so it both (1)
needs to be more generic (rather than `ExcludeNewerPackage`) and (2)
needs to be accessible to more crates (so it's now in
`uv-distribution-types`).
## Summary
Tool receipts were only storing the absolute timestamp, not the relative
span. So upgrades, `--outdated`, etc., were operating off the fixed
cutoff. We now follow the approach used in the lockfile, whereby we
store the cutoff and the relative span, and use that to recompute
offsets.