mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-15 04:49:41 +00:00
Block scripts from overwriting python
(#13051)
uv adds some binaries and scripts to a venv, and installed packages should not be allowed to overwrite them. Fixes #12983
This commit is contained in:
parent
9fb19cd43c
commit
cd7621043e
3 changed files with 97 additions and 0 deletions
|
@ -82,4 +82,6 @@ pub enum Error {
|
||||||
InvalidEggLink(PathBuf),
|
InvalidEggLink(PathBuf),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
LauncherError(#[from] uv_trampoline_builder::Error),
|
LauncherError(#[from] uv_trampoline_builder::Error),
|
||||||
|
#[error("Scripts must not use the reserved name {0}")]
|
||||||
|
ReservedScriptName(String),
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ use uv_normalize::PackageName;
|
||||||
use uv_pypi_types::DirectUrl;
|
use uv_pypi_types::DirectUrl;
|
||||||
use uv_shell::escape_posix_for_single_quotes;
|
use uv_shell::escape_posix_for_single_quotes;
|
||||||
use uv_trampoline_builder::windows_script_launcher;
|
use uv_trampoline_builder::windows_script_launcher;
|
||||||
|
use uv_warnings::warn_user_once;
|
||||||
|
|
||||||
use crate::record::RecordEntry;
|
use crate::record::RecordEntry;
|
||||||
use crate::script::{scripts_from_ini, Script};
|
use crate::script::{scripts_from_ini, Script};
|
||||||
|
@ -186,6 +187,25 @@ pub(crate) fn write_script_entrypoints(
|
||||||
is_gui: bool,
|
is_gui: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
for entrypoint in entrypoints {
|
for entrypoint in entrypoints {
|
||||||
|
let warn_names = ["activate", "activate_this.py"];
|
||||||
|
if warn_names.contains(&entrypoint.name.as_str())
|
||||||
|
|| entrypoint.name.starts_with("activate.")
|
||||||
|
{
|
||||||
|
warn_user_once!(
|
||||||
|
"The script name `{}` is reserved for virtual environment activation scripts.",
|
||||||
|
entrypoint.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let reserved_names = ["python", "pythonw", "python3"];
|
||||||
|
if reserved_names.contains(&entrypoint.name.as_str())
|
||||||
|
|| entrypoint
|
||||||
|
.name
|
||||||
|
.strip_prefix("python3.")
|
||||||
|
.is_some_and(|suffix| suffix.parse::<u8>().is_ok())
|
||||||
|
{
|
||||||
|
return Err(Error::ReservedScriptName(entrypoint.name.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
let entrypoint_absolute = entrypoint_path(entrypoint, layout);
|
let entrypoint_absolute = entrypoint_path(entrypoint, layout);
|
||||||
|
|
||||||
let entrypoint_relative = pathdiff::diff_paths(&entrypoint_absolute, site_packages)
|
let entrypoint_relative = pathdiff::diff_paths(&entrypoint_absolute, site_packages)
|
||||||
|
|
|
@ -11161,3 +11161,78 @@ async fn bogus_redirect() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reserved_script_name() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "project"
|
||||||
|
version = "0.1.0"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
"activate.bash" = "project:activate"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
context
|
||||||
|
.temp_dir
|
||||||
|
.child("src")
|
||||||
|
.child("project")
|
||||||
|
.child("__init__.py")
|
||||||
|
.touch()?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.pip_install().arg("."), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
Prepared 1 package in [TIME]
|
||||||
|
warning: The script name `activate.bash` is reserved for virtual environment activation scripts.
|
||||||
|
Installed 1 package in [TIME]
|
||||||
|
+ project==0.1.0 (from file://[TEMP_DIR]/)
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
pyproject_toml.write_str(
|
||||||
|
r#"
|
||||||
|
[project]
|
||||||
|
name = "project"
|
||||||
|
version = "0.1.0"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
"python" = "project:python"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.pip_install().arg("."), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Resolved 1 package in [TIME]
|
||||||
|
Prepared 1 package in [TIME]
|
||||||
|
Uninstalled 1 package in [TIME]
|
||||||
|
error: Failed to install: project-0.1.0-py3-none-any.whl (project==0.1.0 (from file://[TEMP_DIR]/))
|
||||||
|
Caused by: Scripts must not use the reserved name python
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue