Files
uv/crates/uv-dev/src/lib.rs
T
Charlie Marsh 7f1eaf48c1 Harden ZIP streaming to reject repeated entries and other malformed ZIP files (#15136)
## Summary

uv will now reject ZIP files that meet any of the following conditions:

- Multiple local header entries exist for the same file with different
contents.
- A local header entry exists for a file that isn't included in the
end-of-central directory record.
- An entry exists in the end-of-central directory record that does not
have a corresponding local header.
- The ZIP file contains contents after the first end-of-central
directory record.
- The CRC32 doesn't match between the local file header and the
end-of-central directory record.
- The compressed size doesn't match between the local file header and
the end-of-central directory record.
- The uncompressed size doesn't match between the local file header and
the end-of-central directory record.
- The reported central directory offset (in the end-of-central-directory
header) does not match the actual offset.
- The reported ZIP64 end of central directory locator offset does not
match the actual offset.

We also validate the above for files with data descriptors, which we
previously ignored.

Wheels from the most recent releases of the top 15,000 packages on PyPI
have been confirmed to pass these checks, and PyPI will also reject ZIPs
under many of the same conditions (at upload time) in the future.

In rare cases, this validation can be disabled by setting
`UV_INSECURE_NO_ZIP_VALIDATION=1`. Any validations should be reported to
the uv issue tracker and to the upstream package maintainer.
2025-08-07 15:31:48 +01:00

80 lines
3.3 KiB
Rust

use std::env;
use anyhow::Result;
use clap::Parser;
use tracing::instrument;
use crate::clear_compile::ClearCompileArgs;
use crate::compile::CompileArgs;
use crate::generate_all::Args as GenerateAllArgs;
use crate::generate_cli_reference::Args as GenerateCliReferenceArgs;
use crate::generate_env_vars_reference::Args as GenerateEnvVarsReferenceArgs;
use crate::generate_json_schema::Args as GenerateJsonSchemaArgs;
use crate::generate_options_reference::Args as GenerateOptionsReferenceArgs;
use crate::generate_sysconfig_mappings::Args as GenerateSysconfigMetadataArgs;
#[cfg(feature = "render")]
use crate::render_benchmarks::RenderBenchmarksArgs;
use crate::validate_zip::ValidateZipArgs;
use crate::wheel_metadata::WheelMetadataArgs;
mod clear_compile;
mod compile;
mod generate_all;
mod generate_cli_reference;
mod generate_env_vars_reference;
mod generate_json_schema;
mod generate_options_reference;
mod generate_sysconfig_mappings;
mod render_benchmarks;
mod validate_zip;
mod wheel_metadata;
const ROOT_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../");
#[derive(Parser)]
enum Cli {
/// Display the metadata for a `.whl` at a given URL.
WheelMetadata(WheelMetadataArgs),
/// Validate that a `.whl` or `.zip` file at a given URL is a valid ZIP file.
ValidateZip(ValidateZipArgs),
/// Compile all `.py` to `.pyc` files in the tree.
Compile(CompileArgs),
/// Remove all `.pyc` in the tree.
ClearCompile(ClearCompileArgs),
/// Run all code and documentation generation steps.
GenerateAll(GenerateAllArgs),
/// Generate JSON schema for the TOML configuration file.
GenerateJSONSchema(GenerateJsonSchemaArgs),
/// Generate the options reference for the documentation.
GenerateOptionsReference(GenerateOptionsReferenceArgs),
/// Generate the CLI reference for the documentation.
GenerateCliReference(GenerateCliReferenceArgs),
/// Generate the environment variables reference for the documentation.
GenerateEnvVarsReference(GenerateEnvVarsReferenceArgs),
/// Generate the sysconfig metadata from derived targets.
GenerateSysconfigMetadata(GenerateSysconfigMetadataArgs),
#[cfg(feature = "render")]
/// Render the benchmarks.
RenderBenchmarks(RenderBenchmarksArgs),
}
#[instrument] // Anchor span to check for overhead
pub async fn run() -> Result<()> {
let cli = Cli::parse();
match cli {
Cli::WheelMetadata(args) => wheel_metadata::wheel_metadata(args).await?,
Cli::ValidateZip(args) => validate_zip::validate_zip(args).await?,
Cli::Compile(args) => compile::compile(args).await?,
Cli::ClearCompile(args) => clear_compile::clear_compile(&args)?,
Cli::GenerateAll(args) => generate_all::main(&args).await?,
Cli::GenerateJSONSchema(args) => generate_json_schema::main(&args)?,
Cli::GenerateOptionsReference(args) => generate_options_reference::main(&args)?,
Cli::GenerateCliReference(args) => generate_cli_reference::main(&args)?,
Cli::GenerateEnvVarsReference(args) => generate_env_vars_reference::main(&args)?,
Cli::GenerateSysconfigMetadata(args) => generate_sysconfig_mappings::main(&args).await?,
#[cfg(feature = "render")]
Cli::RenderBenchmarks(args) => render_benchmarks::render_benchmarks(&args)?,
}
Ok(())
}