import UBI python3.14-pip-25.2-3.el9_8.5
This commit is contained in:
parent
b1b75a2cc6
commit
cfecaad950
@ -1 +0,0 @@
|
|||||||
1
|
|
||||||
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,7 +1,4 @@
|
|||||||
/*.tar.gz
|
SOURCES/coverage-0-py3-none-any.whl
|
||||||
/*.zip
|
SOURCES/pip-25.2.tar.gz
|
||||||
/pip-*/
|
SOURCES/setuptools-79.0.1-py3-none-any.whl
|
||||||
/pip/
|
SOURCES/wheel-0.45.1-py3-none-any.whl
|
||||||
/results_python-pip/
|
|
||||||
*.rpm
|
|
||||||
*.whl
|
|
||||||
|
|||||||
4
.python3.14-pip.metadata
Normal file
4
.python3.14-pip.metadata
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
57b654cf22903d90b8184a53bc1390f13caab37d SOURCES/coverage-0-py3-none-any.whl
|
||||||
|
5e4d76e9fba6d45c43711e16c953ea77ad5413ad SOURCES/pip-25.2.tar.gz
|
||||||
|
78bd508f7b09dc1570d629c323e19bdc81229aaf SOURCES/setuptools-79.0.1-py3-none-any.whl
|
||||||
|
2c6c56f64de6d3c413eb5b94b8496f33468f8c98 SOURCES/wheel-0.45.1-py3-none-any.whl
|
||||||
140
SOURCES/pip-CVE-2026-8643.patch
Normal file
140
SOURCES/pip-CVE-2026-8643.patch
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
From dba24a5eeb065d5ac552b3049d2cc99c0bda13fb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Damian Shaw <damian.peter.shaw@gmail.com>
|
||||||
|
Date: Wed, 20 May 2026 15:20:25 -0400
|
||||||
|
Subject: [PATCH] Reject entry point names that escape scripts dir (#14000)
|
||||||
|
|
||||||
|
* Reject entry point names that escape scripts dir
|
||||||
|
|
||||||
|
* NEWS ENTRY
|
||||||
|
---
|
||||||
|
news/14000.bugfix.rst | 2 +
|
||||||
|
src/pip/_internal/operations/install/wheel.py | 26 +++++++-
|
||||||
|
tests/unit/test_wheel.py | 64 +++++++++++++++++++
|
||||||
|
2 files changed, 87 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/pip/_internal/operations/install/wheel.py b/src/pip/_internal/operations/install/wheel.py
|
||||||
|
index 2724f150f..ec2faaa5d 100644
|
||||||
|
--- a/src/pip/_internal/operations/install/wheel.py
|
||||||
|
+++ b/src/pip/_internal/operations/install/wheel.py
|
||||||
|
@@ -397,11 +397,31 @@ class MissingCallableSuffix(InstallationError):
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
-def _raise_for_invalid_entrypoint(specification: str) -> None:
|
||||||
|
+def _script_within_dir(name: str, scripts_dir: str) -> bool:
|
||||||
|
+ """Return whether script ``name`` resolves to a path inside the ``scripts_dir``.
|
||||||
|
+
|
||||||
|
+ distlib joins the entry point name onto the scripts directory, so a name
|
||||||
|
+ with path separators or ``..`` components can resolve elsewhere.
|
||||||
|
+ """
|
||||||
|
+ root = os.path.normpath(scripts_dir)
|
||||||
|
+ dest = os.path.normpath(os.path.join(scripts_dir, name))
|
||||||
|
+ return dest.startswith(root + os.sep)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def _raise_for_invalid_entrypoint(specification: str, scripts_dir: str) -> None:
|
||||||
|
entry = get_export_entry(specification)
|
||||||
|
- if entry is not None and entry.suffix is None:
|
||||||
|
+ if entry is None:
|
||||||
|
+ return
|
||||||
|
+
|
||||||
|
+ if entry.suffix is None:
|
||||||
|
raise MissingCallableSuffix(str(entry))
|
||||||
|
|
||||||
|
+ if not _script_within_dir(entry.name, scripts_dir):
|
||||||
|
+ raise InstallationError(
|
||||||
|
+ f"Invalid script entry point name {entry.name!r}: the script "
|
||||||
|
+ f"would be installed outside the scripts directory ({scripts_dir})."
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
|
||||||
|
class PipScriptMaker(ScriptMaker):
|
||||||
|
# Override distlib's default script template with one that
|
||||||
|
@@ -420,7 +440,7 @@ class PipScriptMaker(ScriptMaker):
|
||||||
|
def make(
|
||||||
|
self, specification: str, options: dict[str, Any] | None = None
|
||||||
|
) -> list[str]:
|
||||||
|
- _raise_for_invalid_entrypoint(specification)
|
||||||
|
+ _raise_for_invalid_entrypoint(specification, self.target_dir)
|
||||||
|
return super().make(specification, options)
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/tests/unit/test_wheel.py b/tests/unit/test_wheel.py
|
||||||
|
index 028ad3a46..bce0607ec 100644
|
||||||
|
--- a/tests/unit/test_wheel.py
|
||||||
|
+++ b/tests/unit/test_wheel.py
|
||||||
|
@@ -519,6 +519,32 @@ class TestInstallUnpackedWheel:
|
||||||
|
assert os.path.basename(wheel_path) in exc_text
|
||||||
|
assert entrypoint in exc_text
|
||||||
|
|
||||||
|
+ @pytest.mark.parametrize("bad_name", ["../../outside", "..", "."])
|
||||||
|
+ @pytest.mark.parametrize("entry_point_type", ["console_scripts", "gui_scripts"])
|
||||||
|
+ def test_wheel_install_rejects_entry_point_path_traversal(
|
||||||
|
+ self, data: TestData, tmpdir: Path, bad_name: str, entry_point_type: str
|
||||||
|
+ ) -> None:
|
||||||
|
+ """An entry point name with separators or ``..`` must not install a
|
||||||
|
+ script outside the scripts directory.
|
||||||
|
+ """
|
||||||
|
+ self.prep(data, tmpdir)
|
||||||
|
+ wheel_path = make_wheel(
|
||||||
|
+ "simple",
|
||||||
|
+ "0.1.0",
|
||||||
|
+ entry_points={entry_point_type: [f"{bad_name} = simple:main"]},
|
||||||
|
+ ).save_to_dir(tmpdir)
|
||||||
|
+ with pytest.raises(InstallationError) as e:
|
||||||
|
+ wheel.install_wheel(
|
||||||
|
+ "simple",
|
||||||
|
+ str(wheel_path),
|
||||||
|
+ scheme=self.scheme,
|
||||||
|
+ req_description="simple",
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ assert "outside the scripts directory" in str(e.value)
|
||||||
|
+ # Nothing was written outside the install destination.
|
||||||
|
+ assert not os.path.exists(os.path.join(str(tmpdir), "outside"))
|
||||||
|
+
|
||||||
|
|
||||||
|
class TestMessageAboutScriptsNotOnPATH:
|
||||||
|
tilde_warning_msg = (
|
||||||
|
@@ -722,3 +748,41 @@ def test_get_console_script_specs_replaces_python_version(
|
||||||
|
"not_pip_or_easy_install-99 = whatever",
|
||||||
|
"not_pip_or_easy_install-99.88 = whatever",
|
||||||
|
]
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+@pytest.mark.parametrize(
|
||||||
|
+ "name, within",
|
||||||
|
+ [
|
||||||
|
+ ("pip", True),
|
||||||
|
+ ("pip3.13", True),
|
||||||
|
+ ("foo-bar.baz", True),
|
||||||
|
+ ("...", True), # a literal filename, not a path component
|
||||||
|
+ ("sub/script", True), # in-tree subdirectory
|
||||||
|
+ ("a/../b", True),
|
||||||
|
+ ("sub\\script", True), # backslash stays in-tree on POSIX and Windows
|
||||||
|
+ (" ../../inside", True), # distlib keeps a leading space; resolves in-tree
|
||||||
|
+ ("../outside", False),
|
||||||
|
+ ("../../outside", False),
|
||||||
|
+ ("a/../../outside", False),
|
||||||
|
+ ("/etc/cron.d/outside", False), # absolute path; os.path.join drops the root
|
||||||
|
+ # "." and ".." pass PyPI's [\w.-]+ name check but must be rejected here.
|
||||||
|
+ (".", False),
|
||||||
|
+ ("..", False),
|
||||||
|
+ ("", False),
|
||||||
|
+ ],
|
||||||
|
+)
|
||||||
|
+def test_script_within_dir(name: str, within: bool) -> None:
|
||||||
|
+ assert wheel._script_within_dir(name, "/srv/env/bin") is within
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def test_script_within_dir_allows_doubled_slash_root() -> None:
|
||||||
|
+ # A scripts directory can have a doubled leading slash
|
||||||
|
+ assert wheel._script_within_dir("pip", "//srv/env/bin") is True
|
||||||
|
+ assert wheel._script_within_dir("../outside", "//srv/env/bin") is False
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+@pytest.mark.skipif(not WINDOWS, reason="drive letters only matter on Windows")
|
||||||
|
+def test_script_within_dir_rejects_other_drive() -> None:
|
||||||
|
+ # Validate that a script on a different drive is rejected,
|
||||||
|
+ # and doesn't throw an error
|
||||||
|
+ assert wheel._script_within_dir("D:\\outside", "C:\\env\\bin") is False
|
||||||
@ -1,3 +1,13 @@
|
|||||||
|
## START: Set by rpmautospec
|
||||||
|
## (rpmautospec version 0.8.4)
|
||||||
|
## RPMAUTOSPEC: autorelease, autochangelog
|
||||||
|
%define autorelease(e:s:pb:n) %{?-p:0.}%{lua:
|
||||||
|
release_number = 5;
|
||||||
|
base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}"));
|
||||||
|
print(release_number + base_release_number - 1);
|
||||||
|
}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}}
|
||||||
|
## END: Set by rpmautospec
|
||||||
|
|
||||||
%global python3_pkgversion 3.14
|
%global python3_pkgversion 3.14
|
||||||
|
|
||||||
# The original RHEL N+1 content set is defined by (build)dependencies
|
# The original RHEL N+1 content set is defined by (build)dependencies
|
||||||
@ -14,7 +24,7 @@
|
|||||||
|
|
||||||
Name: python%{python3_pkgversion}-%{srcname}
|
Name: python%{python3_pkgversion}-%{srcname}
|
||||||
Version: %{base_version}%{?prerel:~%{prerel}}
|
Version: %{base_version}%{?prerel:~%{prerel}}
|
||||||
Release: %autorelease
|
Release: 3%{?dist}.%{autorelease -n}
|
||||||
Summary: A tool for installing and managing Python packages
|
Summary: A tool for installing and managing Python packages
|
||||||
|
|
||||||
# We bundle a lot of libraries with pip, which itself is under MIT license.
|
# We bundle a lot of libraries with pip, which itself is under MIT license.
|
||||||
@ -109,6 +119,10 @@ Patch: downstream-remove-pytest-subket.patch
|
|||||||
# Upstream fix: https://github.com/urllib3/urllib3/commit/f05b1329126d5be6de501f9d1e3e36738bc08857
|
# Upstream fix: https://github.com/urllib3/urllib3/commit/f05b1329126d5be6de501f9d1e3e36738bc08857
|
||||||
Patch: urllib3-CVE-2025-50181.patch
|
Patch: urllib3-CVE-2025-50181.patch
|
||||||
|
|
||||||
|
# Reject entry point names that escape scripts dir (CVE-2026-8643)
|
||||||
|
# Upstream fix: https://github.com/pypa/pip/commit/8eb178480bd1a2b223f509fc430796b265158dfb
|
||||||
|
Patch: pip-CVE-2026-8643.patch
|
||||||
|
|
||||||
# Remove -s from Python shebang - ensure that packages installed with pip
|
# Remove -s from Python shebang - ensure that packages installed with pip
|
||||||
# to user locations are seen by pip itself
|
# to user locations are seen by pip itself
|
||||||
%undefine _py3_shebang_s
|
%undefine _py3_shebang_s
|
||||||
@ -355,4 +369,32 @@ pytest_k="$pytest_k and not test_check_unsupported"
|
|||||||
%{python_wheel_dir}/%{python_wheel_name}
|
%{python_wheel_dir}/%{python_wheel_name}
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
%autochangelog
|
## START: Generated by rpmautospec
|
||||||
|
* Thu Jul 02 2026 Lukáš Zachar <lzachar@redhat.com> - 25.2-5
|
||||||
|
- Fix gating plan
|
||||||
|
- removed unnecessary older VERSION= tests
|
||||||
|
- removed bootstrap test
|
||||||
|
- fix pip_install_upgrade to run pip-3.14
|
||||||
|
- fix bash completion + remove unused metadata file
|
||||||
|
|
||||||
|
* Wed Jul 01 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 25.2-4
|
||||||
|
- Security fix for CVE-2026-8643: path traversal in wheel entry points
|
||||||
|
|
||||||
|
* Wed Nov 26 2025 Tomáš Hrnčiar <thrnciar@redhat.com> - 25.2-3
|
||||||
|
- Security fix for the bundled urllib3 for CVE-2025-50181
|
||||||
|
|
||||||
|
* Wed Nov 26 2025 Tomáš Hrnčiar <thrnciar@redhat.com> - 25.2-2
|
||||||
|
- Include SBOM in the .whl file in python-pip-wheel
|
||||||
|
|
||||||
|
* Wed Nov 26 2025 Tomáš Hrnčiar <thrnciar@redhat.com> - 25.2-1
|
||||||
|
- Update to 25.2 (rhbz#2385294)
|
||||||
|
|
||||||
|
* Wed Nov 26 2025 Lukáš Zachar <lzachar@redhat.com> - 25.1.1-3
|
||||||
|
- Gating
|
||||||
|
|
||||||
|
* Wed Nov 26 2025 Tomáš Hrnčiar <thrnciar@redhat.com> - 25.1.1-2
|
||||||
|
- Convert from Fedora for the Python 3.14 stack in RHEL
|
||||||
|
|
||||||
|
* Wed Nov 26 2025 Tomáš Hrnčiar <thrnciar@redhat.com> - 25.1.1-1
|
||||||
|
- RHEL: Rename SPEC to python3.14-pip.spec
|
||||||
|
## END: Generated by rpmautospec
|
||||||
@ -1,6 +0,0 @@
|
|||||||
--- !Policy
|
|
||||||
product_versions:
|
|
||||||
- rhel-*
|
|
||||||
decision_context: osci_compose_gate
|
|
||||||
rules:
|
|
||||||
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}
|
|
||||||
63
plan.fmf
63
plan.fmf
@ -1,63 +0,0 @@
|
|||||||
execute:
|
|
||||||
how: tmt
|
|
||||||
|
|
||||||
discover:
|
|
||||||
- name: tests_python
|
|
||||||
how: shell
|
|
||||||
url: https://gitlab.com/redhat/centos-stream/tests/python.git
|
|
||||||
tests:
|
|
||||||
- name: smoke312
|
|
||||||
path: /smoke
|
|
||||||
test: VERSION=3.12 ./venv.sh
|
|
||||||
- name: smoke314
|
|
||||||
path: /smoke
|
|
||||||
test: VERSION=3.14 ./venv.sh
|
|
||||||
- name: smoke312_virtualenv
|
|
||||||
path: /smoke
|
|
||||||
test: VERSION=3.12 METHOD=virtualenv ./venv.sh
|
|
||||||
- name: smoke314_virtualenv
|
|
||||||
path: /smoke
|
|
||||||
test: VERSION=3.14 METHOD=virtualenv ./venv.sh
|
|
||||||
- name: rpms_pyproject-rpm-macros
|
|
||||||
how: shell
|
|
||||||
url: https://gitlab.com/redhat/centos-stream/rpms/pyproject-rpm-macros.git
|
|
||||||
ref: c10s
|
|
||||||
tests:
|
|
||||||
- name: pyproject_isort
|
|
||||||
path: /tests
|
|
||||||
test: ./mocktest.sh python-isort
|
|
||||||
- name: same_repo
|
|
||||||
how: shell
|
|
||||||
dist-git-source: true
|
|
||||||
dist-git-download-only: true
|
|
||||||
tests:
|
|
||||||
- name: mock_bootstrap_build
|
|
||||||
test: |
|
|
||||||
cd $TMT_SOURCE_DIR &&
|
|
||||||
$TMT_TREE/../discover/rpms_pyproject-rpm-macros/tests/tests/mocktest.sh python-pip --without tests --without man
|
|
||||||
- name: pip_install_upgrade
|
|
||||||
path: /tests/pip_install_upgrade/
|
|
||||||
test: ./runtest.sh
|
|
||||||
- name: bash_completion
|
|
||||||
path: /tests/bash_completion
|
|
||||||
test: ./pip_completion_full_test.sh
|
|
||||||
prepare:
|
|
||||||
- name: Install dependencies
|
|
||||||
how: install
|
|
||||||
package:
|
|
||||||
- gcc
|
|
||||||
- virtualenv
|
|
||||||
- python3.14-devel
|
|
||||||
- python3-devel
|
|
||||||
- python3-tox
|
|
||||||
- mock
|
|
||||||
- rpmdevtools
|
|
||||||
- rpm-build
|
|
||||||
- grep
|
|
||||||
- util-linux
|
|
||||||
- shadow-utils
|
|
||||||
- expect
|
|
||||||
- dnf
|
|
||||||
- name: Update packages
|
|
||||||
how: shell
|
|
||||||
script: dnf upgrade -y
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
# This is just temporary, when upstream merges PRs it can be removed
|
|
||||||
# https://github.com/psf/requests/pull/5410
|
|
||||||
addFilter(r'(non-executable-script|wrong-script-interpreter) .+/pip/_vendor/requests/certs.py\b')
|
|
||||||
|
|
||||||
# This file is actually a script but in the vendored context of pip, it is never executed
|
|
||||||
addFilter(r'non-executable-script .+/pip/_vendor/distro/distro.py\b')
|
|
||||||
|
|
||||||
# We ship README with the main package but not with the wheel
|
|
||||||
addFilter(r'python-pip-wheel.noarch: W: no-documentation')
|
|
||||||
4
sources
4
sources
@ -1,4 +0,0 @@
|
|||||||
SHA512 (pip-25.2.tar.gz) = 5cc65c9091fdda7905e26ce32ddaa3a1c2fd287d69fd3da67c814ba7e8e5be59301d8327c06cdca78c1b95f4a5b5f75c87f36a549022408cc0e8f9411c0db11e
|
|
||||||
SHA512 (setuptools-79.0.1-py3-none-any.whl) = fef6cfc6f95a5bb7320f1680e1c665cb8d9a4e4227cde4d8aab8a50bed4bcf04320085b9d7d5343359f887008db5c5a861e57f3d08b7b0b2311a28adaeee6b4a
|
|
||||||
SHA512 (wheel-0.45.1-py3-none-any.whl) = 86c16248ec804ee0ac95d43b03d47351dceb534d0cdc4025ca1eb073e39e539de44c870b9261f0373144e1537f0e42675a759a318a8d5d346bbd9efcb704061d
|
|
||||||
SHA512 (coverage-0-py3-none-any.whl) = e734192565347010efe68f8ba600254259c9b647f3c553fd4e5d87b1d7f955cb15d6f7d807716f4a6415d239beed945fbec7210feaf502e9cc849c332845926e
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
summary: PIP bash completion functionality smoke test
|
|
||||||
description: |
|
|
||||||
Comprehensive test for pip bash completion functionality on Fedora/RHEL systems.
|
|
||||||
|
|
||||||
The test performs the following steps:
|
|
||||||
1. Finds the bash completion script in the given (e.g. python3-pip) RPM package
|
|
||||||
2. Discovers all pip executables in the package (e.g. /usr/bin/pip and /usr/bin/pip3.14)
|
|
||||||
3. Sources the completion script and verifies completion for all executables is registered
|
|
||||||
4. Runs functional TAB completion tests using expect (for regular and POSIX mode of Bash)
|
|
||||||
5. Validates that completion works for basic pip commands
|
|
||||||
|
|
||||||
This is a smoke test to ensure pip bash completion is properly
|
|
||||||
installed and functional after package installation.
|
|
||||||
|
|
||||||
component:
|
|
||||||
- python3-pip
|
|
||||||
|
|
||||||
test: ./pip_completion_full_test.sh
|
|
||||||
|
|
||||||
framework: shell
|
|
||||||
|
|
||||||
duration: 5m
|
|
||||||
tier: 1
|
|
||||||
|
|
||||||
|
|
||||||
require:
|
|
||||||
- python3-pip
|
|
||||||
- bash-completion
|
|
||||||
- expect
|
|
||||||
- rpm
|
|
||||||
- bash
|
|
||||||
|
|
||||||
|
|
||||||
environment:
|
|
||||||
PACKAGE: python3-pip
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Comprehensive PIP bash completion test for RHEL
|
|
||||||
# Finds completion scripts from RPM, tests all pip binaries, and runs functional tests
|
|
||||||
|
|
||||||
PACKAGE="${PACKAGE:-python3-pip}"
|
|
||||||
|
|
||||||
|
|
||||||
# Step 1: Find bash completion scripts in python3-pip RPM package
|
|
||||||
echo "Step 1: Finding bash completion scripts in $PACKAGE RPM package..."
|
|
||||||
|
|
||||||
COMPLETION_FILE=$(rpm -ql $PACKAGE 2>/dev/null | grep -E "/usr/share/bash-completion/completions/" || true)
|
|
||||||
|
|
||||||
if [[ -z "$COMPLETION_FILE" ]]; then
|
|
||||||
echo "✗ No bash completion files found in $PACKAGE package"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if there's exactly one completion file
|
|
||||||
COMPLETION_FILE_COUNT=$(echo "$COMPLETION_FILE" | wc -l)
|
|
||||||
|
|
||||||
if [[ $COMPLETION_FILE_COUNT -gt 1 ]]; then
|
|
||||||
echo "✗ Multiple bash completion files found in $PACKAGE package:"
|
|
||||||
echo "$COMPLETION_FILE" | sed 's/^/ - /'
|
|
||||||
echo "Expected exactly one completion file, found $COMPLETION_FILE_COUNT"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
echo "✓ Found completion file from $PACKAGE package:"
|
|
||||||
echo "$COMPLETION_FILE" | sed 's/^/ - /'
|
|
||||||
|
|
||||||
# Step 2: Find all pip binaries
|
|
||||||
echo
|
|
||||||
echo "Step 2: Finding all pip binaries..."
|
|
||||||
PIP_BINARIES=()
|
|
||||||
PIP_FILES=$(rpm -ql $PACKAGE | grep /bin/p)
|
|
||||||
for pip_file in $PIP_FILES; do
|
|
||||||
if [[ -x "$pip_file" ]]; then
|
|
||||||
pip_cmd=$(basename "$pip_file")
|
|
||||||
PIP_BINARIES+=("$pip_cmd")
|
|
||||||
echo "✓ Found: $pip_cmd -> $pip_file"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ ${#PIP_BINARIES[@]} -eq 0 ]]; then
|
|
||||||
echo "✗ No pip binaries found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Total pip binaries found: ${#PIP_BINARIES[@]}"
|
|
||||||
|
|
||||||
# Step 3: Source completion scripts and test each binary
|
|
||||||
echo
|
|
||||||
echo "Step 3: Testing completion for each pip binary..."
|
|
||||||
|
|
||||||
for AS_POSIX in 0 1; do
|
|
||||||
if [[ $AS_POSIX -eq 1 ]]; then
|
|
||||||
echo "Testing in POSIX mode"
|
|
||||||
POSIX="--posix"
|
|
||||||
else
|
|
||||||
echo "Testing in non-POSIX mode"
|
|
||||||
POSIX=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Sourcing: $COMPLETION_FILE"
|
|
||||||
if bash --norc $POSIX -c "source $COMPLETION_FILE" ; then
|
|
||||||
echo "✓ Successfully sourced $COMPLETION_FILE"
|
|
||||||
else
|
|
||||||
echo "! Warning: Failed to source $COMPLETION_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
export AS_POSIX
|
|
||||||
for pip_exec in "${PIP_BINARIES[@]}"; do
|
|
||||||
echo "Running expect test with $COMPLETION_FILE and $pip_exec..."
|
|
||||||
if ./test_pip_completion.exp "$COMPLETION_FILE" "$pip_exec"; then
|
|
||||||
echo "✓ Functional test passed"
|
|
||||||
else
|
|
||||||
echo "✗ Functional test failed"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
echo "✓ All tests completed successfully!"
|
|
||||||
@ -1,117 +0,0 @@
|
|||||||
#!/usr/bin/expect -f
|
|
||||||
|
|
||||||
# PIP bash completion smoke test using expect
|
|
||||||
# Tests actual TAB completion functionality
|
|
||||||
# Usage: test_pip_completion.exp [completion_file] [pip_binary]
|
|
||||||
|
|
||||||
set timeout 5
|
|
||||||
|
|
||||||
|
|
||||||
set completion_file [lindex $argv 0]
|
|
||||||
set pip_exec [lindex $argv 1]
|
|
||||||
|
|
||||||
|
|
||||||
puts "=== PIP Bash Completion Test (using expect) ==="
|
|
||||||
puts "Testing completion file: $completion_file"
|
|
||||||
puts "Testing pip binary: $pip_exec"
|
|
||||||
|
|
||||||
# Check if completion file exists first
|
|
||||||
if {![file exists $completion_file]} {
|
|
||||||
puts "✗ Completion file not found: $completion_file"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
puts "✓ Completion file found: $completion_file"
|
|
||||||
|
|
||||||
# Start bash shell
|
|
||||||
if {[info exists env(AS_POSIX)] && $env(AS_POSIX) == "1"} {
|
|
||||||
spawn bash --norc --posix
|
|
||||||
} else {
|
|
||||||
spawn bash --norc
|
|
||||||
}
|
|
||||||
expect "$ "
|
|
||||||
|
|
||||||
# Source the completion file
|
|
||||||
send "source $completion_file\r"
|
|
||||||
expect "$ "
|
|
||||||
puts "Attempted to source completion file"
|
|
||||||
|
|
||||||
# Test 1: Basic pip command completion
|
|
||||||
puts "\nTest 1: Testing '$pip_exec ' + TAB completion..."
|
|
||||||
send "$pip_exec "
|
|
||||||
sleep 0.1
|
|
||||||
# Send TAB TAB using hex codes
|
|
||||||
send "\x09\x09"
|
|
||||||
expect {
|
|
||||||
-re "(install|uninstall|list|show)" {
|
|
||||||
puts "✓ Basic pip commands found in completion"
|
|
||||||
expect "$ "
|
|
||||||
}
|
|
||||||
-re "Display all" {
|
|
||||||
puts "✓ Completion showing options menu"
|
|
||||||
send "n\r"
|
|
||||||
expect "$ "
|
|
||||||
}
|
|
||||||
timeout {
|
|
||||||
puts "✗ Timeout waiting for completion - test failed"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Clear the line and ensure clean prompt
|
|
||||||
send "\x03"
|
|
||||||
expect "$ "
|
|
||||||
send "\r"
|
|
||||||
expect "$ "
|
|
||||||
|
|
||||||
# Test 2: Test partial command completion (simpler test)
|
|
||||||
puts "\nTest 2: Testing '$pip_exec insta' + TAB completion..."
|
|
||||||
send "$pip_exec insta"
|
|
||||||
sleep 0.1
|
|
||||||
# Single TAB for completion
|
|
||||||
send "\x09"
|
|
||||||
expect {
|
|
||||||
-re "install" {
|
|
||||||
puts "✓ Partial command completion works (insta -> install)"
|
|
||||||
expect "$ "
|
|
||||||
}
|
|
||||||
timeout {
|
|
||||||
puts "✗ Timeout on partial completion test - test failed"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Clear the line and ensure clean prompt
|
|
||||||
send "\x03"
|
|
||||||
expect "$ "
|
|
||||||
send "\r"
|
|
||||||
expect "$ "
|
|
||||||
|
|
||||||
# Test 3: Test help completion
|
|
||||||
puts "\nTest 3: Testing '$pip_exec --' + TAB completion..."
|
|
||||||
send "$pip_exec --"
|
|
||||||
sleep 0.1
|
|
||||||
send "\x09\x09"
|
|
||||||
expect {
|
|
||||||
-re "(--help|--version)" {
|
|
||||||
puts "✓ Command options found in completion"
|
|
||||||
expect "$ "
|
|
||||||
}
|
|
||||||
timeout {
|
|
||||||
puts "✗ Timeout on options completion test - test failed"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Final cleanup - make sure we're at clean prompt
|
|
||||||
send "\x03"
|
|
||||||
expect "$ "
|
|
||||||
send "\r"
|
|
||||||
expect "$ "
|
|
||||||
|
|
||||||
# Exit bash cleanly
|
|
||||||
send "exit\r"
|
|
||||||
expect eof
|
|
||||||
|
|
||||||
puts "\n=== Completion Test Complete ==="
|
|
||||||
puts "PIP bash completion functionality tested!"
|
|
||||||
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
#!/bin/sh -eux
|
|
||||||
# This script requires root privileges and you should never run it on your own machine
|
|
||||||
test $EUID -eq 0
|
|
||||||
|
|
||||||
PYTHON_VERSION=$(/usr/bin/python3 -c 'import sys; print("{}.{}".format(*sys.version_info))')
|
|
||||||
RPM_SITELIB="/usr/lib/python${PYTHON_VERSION}/site-packages"
|
|
||||||
LOCAL_SITELIB="/usr/local/lib/python${PYTHON_VERSION}/site-packages"
|
|
||||||
USER_SITELIB="/home/fedora-test-user/.local/lib/python${PYTHON_VERSION}/site-packages"
|
|
||||||
|
|
||||||
# First, let's install older Pello with pip as if it was installed by RPM
|
|
||||||
# This is an approximation, but it usually works
|
|
||||||
RPM_BUILD_ROOT=/ /usr/bin/pip install 'Pello==1.0.1'
|
|
||||||
|
|
||||||
# Now, we'll upgrade it with regular pip
|
|
||||||
/usr/bin/pip install --upgrade 'Pello==1.0.2'
|
|
||||||
|
|
||||||
# pip should see it
|
|
||||||
/usr/bin/pip freeze | grep '^Pello==1\.0\.2$'
|
|
||||||
|
|
||||||
# Both installations should still exist
|
|
||||||
test -d "${RPM_SITELIB}/pello-1.0.1.dist-info"
|
|
||||||
test -d "${LOCAL_SITELIB}/Pello-1.0.2.dist-info"
|
|
||||||
|
|
||||||
# Let's ditch the local one
|
|
||||||
/usr/bin/pip uninstall --yes Pello
|
|
||||||
|
|
||||||
# It should only remove one of them
|
|
||||||
test -d "${RPM_SITELIB}/pello-1.0.1.dist-info"
|
|
||||||
! test -d "${LOCAL_SITELIB}/Pello-1.0.2.dist-info"
|
|
||||||
|
|
||||||
# And pip should still see the RPM-installed one
|
|
||||||
/usr/bin/pip freeze | grep '^Pello==1\.0\.1$'
|
|
||||||
|
|
||||||
# Again, but as regular user
|
|
||||||
useradd fedora-test-user
|
|
||||||
su fedora-test-user -c '/usr/bin/pip install "Pello==1.0.2"'
|
|
||||||
test -d "${USER_SITELIB}/Pello-1.0.2.dist-info"
|
|
||||||
su fedora-test-user -c '/usr/bin/pip freeze' | grep '^Pello==1\.0\.2$'
|
|
||||||
su fedora-test-user -c '/usr/bin/pip uninstall --yes Pello'
|
|
||||||
su fedora-test-user -c '/usr/bin/pip freeze' | grep '^Pello==1\.0\.1$'
|
|
||||||
Loading…
Reference in New Issue
Block a user