Add a --require-hashes command-line setting (#2824)

## Summary

I'll likely only merge this once the PR chain is further along, but this
PR wires up the setting fro the CLI.
This commit is contained in:
Charlie Marsh 2024-04-10 14:07:03 -04:00 committed by GitHub
parent 520cd4689b
commit a9d554fa90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 53 additions and 0 deletions

View file

@ -9,6 +9,7 @@ pub struct Options {
pub prerelease_mode: PreReleaseMode,
pub dependency_mode: DependencyMode,
pub exclude_newer: Option<DateTime<Utc>>,
pub require_hashes: bool,
}
/// Builder for [`Options`].
@ -18,6 +19,7 @@ pub struct OptionsBuilder {
prerelease_mode: PreReleaseMode,
dependency_mode: DependencyMode,
exclude_newer: Option<DateTime<Utc>>,
require_hashes: bool,
}
impl OptionsBuilder {
@ -54,6 +56,13 @@ impl OptionsBuilder {
self
}
/// Sets the `--requires-hash` flag.
#[must_use]
pub fn require_hashes(mut self, require_hashes: bool) -> Self {
self.require_hashes = require_hashes;
self
}
/// Builds the options.
pub fn build(self) -> Options {
Options {
@ -61,6 +70,7 @@ impl OptionsBuilder {
prerelease_mode: self.prerelease_mode,
dependency_mode: self.dependency_mode,
exclude_newer: self.exclude_newer,
require_hashes: self.require_hashes,
}
}
}

View file

@ -67,6 +67,7 @@ pub(crate) async fn pip_install(
reinstall: Reinstall,
link_mode: LinkMode,
compile: bool,
require_hashes: bool,
setup_py: SetupPyStrategy,
connectivity: Connectivity,
config_settings: &ConfigSettings,
@ -84,6 +85,11 @@ pub(crate) async fn pip_install(
printer: Printer,
) -> Result<ExitStatus> {
let start = std::time::Instant::now();
if require_hashes {
warn_user!("Hash-checking mode (via `--require-hashes`) is not yet supported.");
}
let client_builder = BaseClientBuilder::new()
.connectivity(connectivity)
.native_tls(native_tls)
@ -292,6 +298,7 @@ pub(crate) async fn pip_install(
.prerelease_mode(prerelease_mode)
.dependency_mode(dependency_mode)
.exclude_newer(exclude_newer)
.require_hashes(require_hashes)
.build();
// Resolve the requirements.

View file

@ -45,6 +45,7 @@ pub(crate) async fn pip_sync(
reinstall: &Reinstall,
link_mode: LinkMode,
compile: bool,
require_hashes: bool,
index_locations: IndexLocations,
index_strategy: IndexStrategy,
keyring_provider: KeyringProvider,
@ -64,6 +65,10 @@ pub(crate) async fn pip_sync(
) -> Result<ExitStatus> {
let start = std::time::Instant::now();
if require_hashes {
warn_user!("Hash-checking mode (via `--require-hashes`) is not yet supported.");
}
let client_builder = BaseClientBuilder::new()
.connectivity(connectivity)
.native_tls(native_tls)
@ -289,6 +294,7 @@ pub(crate) async fn pip_sync(
// Resolve with `--no-deps`.
let options = OptionsBuilder::new()
.dependency_mode(DependencyMode::Direct)
.require_hashes(require_hashes)
.build();
// Create a bound on the progress bar, since we know the number of packages upfront.

View file

@ -593,6 +593,20 @@ struct PipSyncArgs {
#[clap(long, default_value_t, value_enum, env = "UV_INDEX_STRATEGY")]
index_strategy: IndexStrategy,
/// Require a matching hash for each requirement.
///
/// Hash-checking mode is all or nothing. If enabled, _all_ requirements must be provided
/// with a corresponding hash or set of hashes. Additionally, if enabled, _all_ requirements
/// must either be pinned to exact versions (e.g., `==1.0.0`), or be specified via direct URL.
///
/// Hash-checking mode introduces a number of additional constraints:
/// - Git dependencies are not supported.
/// - Editable installs are not supported.
/// - Local dependencies are not supported, unless they point to a specific wheel (`.whl`) or
/// source archive (`.zip`, `.tar.gz`), as opposed to a directory.
#[clap(long, hide = true)]
require_hashes: bool,
/// Attempt to use `keyring` for authentication for index urls
///
/// Function's similar to `pip`'s `--keyring-provider subprocess` argument,
@ -867,6 +881,20 @@ struct PipInstallArgs {
#[clap(long, default_value_t, value_enum, env = "UV_INDEX_STRATEGY")]
index_strategy: IndexStrategy,
/// Require a matching hash for each requirement.
///
/// Hash-checking mode is all or nothing. If enabled, _all_ requirements must be provided
/// with a corresponding hash or set of hashes. Additionally, if enabled, _all_ requirements
/// must either be pinned to exact versions (e.g., `==1.0.0`), or be specified via direct URL.
///
/// Hash-checking mode introduces a number of additional constraints:
/// - Git dependencies are not supported.
/// - Editable installs are not supported.
/// - Local dependencies are not supported, unless they point to a specific wheel (`.whl`) or
/// source archive (`.zip`, `.tar.gz`), as opposed to a directory.
#[clap(long, hide = true)]
require_hashes: bool,
/// Attempt to use `keyring` for authentication for index urls
///
/// Due to not having Python imports, only `--keyring-provider subprocess` argument is currently
@ -1650,6 +1678,7 @@ async fn run() -> Result<ExitStatus> {
&reinstall,
args.link_mode,
args.compile,
args.require_hashes,
index_urls,
args.index_strategy,
args.keyring_provider,
@ -1750,6 +1779,7 @@ async fn run() -> Result<ExitStatus> {
reinstall,
args.link_mode,
args.compile,
args.require_hashes,
setup_py,
if args.offline {
Connectivity::Offline