Compare commits
	
		
			No commits in common. "c8" and "c9-beta" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | |||||||
| SOURCES/pip-9.0.3.tar.gz | SOURCES/pip-21.3.1.tar.gz | ||||||
|  | |||||||
| @ -1 +1 @@ | |||||||
| 1f5f44d433ca599d40f8e46f440479b2c73802d8 SOURCES/pip-9.0.3.tar.gz | 5f98a502c4ae2fec713eda155bf5994196d97cd9 SOURCES/pip-21.3.1.tar.gz | ||||||
|  | |||||||
| @ -1,90 +0,0 @@ | |||||||
| From ffbfdb53681207b23bcf67dd76368ad6185ade24 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lumir Balhar <lbalhar@redhat.com> |  | ||||||
| Date: Thu, 16 Jan 2020 07:06:09 +0100 |  | ||||||
| Subject: [PATCH] Fix for CVE-2018-18074 |  | ||||||
| 
 |  | ||||||
| This patch contains the fix for CVE-2018-18074 and |  | ||||||
| a subsequent regression fix combined in one. |  | ||||||
| ---
 |  | ||||||
|  sessions.py | 36 +++++++++++++++++++++++++++++------- |  | ||||||
|  utils.py    |  1 + |  | ||||||
|  2 files changed, 30 insertions(+), 7 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/sessions.py b/sessions.py
 |  | ||||||
| index 6570e73..4038047 100644
 |  | ||||||
| --- a/sessions.py
 |  | ||||||
| +++ b/sessions.py
 |  | ||||||
| @@ -29,7 +29,7 @@ from .adapters import HTTPAdapter
 |  | ||||||
|   |  | ||||||
|  from .utils import ( |  | ||||||
|      requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies, |  | ||||||
| -    get_auth_from_url, rewind_body
 |  | ||||||
| +    get_auth_from_url, rewind_body, DEFAULT_PORTS
 |  | ||||||
|  ) |  | ||||||
|   |  | ||||||
|  from .status_codes import codes |  | ||||||
| @@ -116,6 +116,32 @@ class SessionRedirectMixin(object):
 |  | ||||||
|              return to_native_string(location, 'utf8') |  | ||||||
|          return None |  | ||||||
|   |  | ||||||
| +
 |  | ||||||
| +    def should_strip_auth(self, old_url, new_url):
 |  | ||||||
| +        """Decide whether Authorization header should be removed when redirecting"""
 |  | ||||||
| +        old_parsed = urlparse(old_url)
 |  | ||||||
| +        new_parsed = urlparse(new_url)
 |  | ||||||
| +        if old_parsed.hostname != new_parsed.hostname:
 |  | ||||||
| +            return True
 |  | ||||||
| +        # Special case: allow http -> https redirect when using the standard
 |  | ||||||
| +        # ports. This isn't specified by RFC 7235, but is kept to avoid
 |  | ||||||
| +        # breaking backwards compatibility with older versions of requests
 |  | ||||||
| +        # that allowed any redirects on the same host.
 |  | ||||||
| +        if (old_parsed.scheme == 'http' and old_parsed.port in (80, None)
 |  | ||||||
| +                and new_parsed.scheme == 'https' and new_parsed.port in (443, None)):
 |  | ||||||
| +            return False
 |  | ||||||
| +
 |  | ||||||
| +        # Handle default port usage corresponding to scheme.
 |  | ||||||
| +        changed_port = old_parsed.port != new_parsed.port
 |  | ||||||
| +        changed_scheme = old_parsed.scheme != new_parsed.scheme
 |  | ||||||
| +        default_port = (DEFAULT_PORTS.get(old_parsed.scheme, None), None)
 |  | ||||||
| +        if (not changed_scheme and old_parsed.port in default_port
 |  | ||||||
| +                and new_parsed.port in default_port):
 |  | ||||||
| +            return False
 |  | ||||||
| +
 |  | ||||||
| +        # Standard case: root URI must match
 |  | ||||||
| +        return changed_port or changed_scheme
 |  | ||||||
| +
 |  | ||||||
|      def resolve_redirects(self, resp, req, stream=False, timeout=None, |  | ||||||
|                            verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs): |  | ||||||
|          """Receives a Response. Returns a generator of Responses or Requests.""" |  | ||||||
| @@ -232,14 +258,10 @@ class SessionRedirectMixin(object):
 |  | ||||||
|          headers = prepared_request.headers |  | ||||||
|          url = prepared_request.url |  | ||||||
|   |  | ||||||
| -        if 'Authorization' in headers:
 |  | ||||||
| +        if 'Authorization' in headers and self.should_strip_auth(response.request.url, url):
 |  | ||||||
|              # If we get redirected to a new host, we should strip out any |  | ||||||
|              # authentication headers. |  | ||||||
| -            original_parsed = urlparse(response.request.url)
 |  | ||||||
| -            redirect_parsed = urlparse(url)
 |  | ||||||
| -
 |  | ||||||
| -            if (original_parsed.hostname != redirect_parsed.hostname):
 |  | ||||||
| -                del headers['Authorization']
 |  | ||||||
| +            del headers['Authorization']
 |  | ||||||
|   |  | ||||||
|          # .netrc might have more auth for us on our new host. |  | ||||||
|          new_auth = get_netrc_auth(url) if self.trust_env else None |  | ||||||
| diff --git a/utils.py b/utils.py
 |  | ||||||
| index 5c47de9..5695ab0 100644
 |  | ||||||
| --- a/utils.py
 |  | ||||||
| +++ b/utils.py
 |  | ||||||
| @@ -38,6 +38,7 @@ NETRC_FILES = ('.netrc', '_netrc')
 |  | ||||||
|   |  | ||||||
|  DEFAULT_CA_BUNDLE_PATH = certs.where() |  | ||||||
|   |  | ||||||
| +DEFAULT_PORTS = {'http': 80, 'https': 443}
 |  | ||||||
|   |  | ||||||
|  if platform.system() == 'Windows': |  | ||||||
|      # provide a proxy_bypass version on Windows without DNS lookups |  | ||||||
| -- 
 |  | ||||||
| 2.24.1 |  | ||||||
| 
 |  | ||||||
| @ -1,94 +0,0 @@ | |||||||
| From c734f873270cf9ca414832423f7aad98443c379f Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lumir Balhar <lbalhar@redhat.com> |  | ||||||
| Date: Thu, 9 Jan 2020 11:26:24 +0100 |  | ||||||
| Subject: [PATCH] CVE-2018-20060 |  | ||||||
| 
 |  | ||||||
| ---
 |  | ||||||
|  poolmanager.py | 11 ++++++++++- |  | ||||||
|  util/retry.py  | 12 +++++++++++- |  | ||||||
|  2 files changed, 21 insertions(+), 2 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/poolmanager.py b/poolmanager.py
 |  | ||||||
| index 4ae9174..bfa5115 100644
 |  | ||||||
| --- a/poolmanager.py
 |  | ||||||
| +++ b/poolmanager.py
 |  | ||||||
| @@ -312,8 +312,9 @@ class PoolManager(RequestMethods):
 |  | ||||||
|   |  | ||||||
|          kw['assert_same_host'] = False |  | ||||||
|          kw['redirect'] = False |  | ||||||
| +
 |  | ||||||
|          if 'headers' not in kw: |  | ||||||
| -            kw['headers'] = self.headers
 |  | ||||||
| +            kw['headers'] = self.headers.copy()
 |  | ||||||
|   |  | ||||||
|          if self.proxy is not None and u.scheme == "http": |  | ||||||
|              response = conn.urlopen(method, url, **kw) |  | ||||||
| @@ -335,6 +336,14 @@ class PoolManager(RequestMethods):
 |  | ||||||
|          if not isinstance(retries, Retry): |  | ||||||
|              retries = Retry.from_int(retries, redirect=redirect) |  | ||||||
|   |  | ||||||
| +        # Strip headers marked as unsafe to forward to the redirected location.
 |  | ||||||
| +        # Check remove_headers_on_redirect to avoid a potential network call within
 |  | ||||||
| +        # conn.is_same_host() which may use socket.gethostbyname() in the future.
 |  | ||||||
| +        if (retries.remove_headers_on_redirect
 |  | ||||||
| +                and not conn.is_same_host(redirect_location)):
 |  | ||||||
| +            for header in retries.remove_headers_on_redirect:
 |  | ||||||
| +                kw['headers'].pop(header, None)
 |  | ||||||
| +
 |  | ||||||
|          try: |  | ||||||
|              retries = retries.increment(method, url, response=response, _pool=conn) |  | ||||||
|          except MaxRetryError: |  | ||||||
| diff --git a/util/retry.py b/util/retry.py
 |  | ||||||
| index c603cb4..0b83963 100644
 |  | ||||||
| --- a/util/retry.py
 |  | ||||||
| +++ b/util/retry.py
 |  | ||||||
| @@ -126,6 +126,11 @@ class Retry(object):
 |  | ||||||
|          exhausted, to raise a MaxRetryError, or to return a response with a |  | ||||||
|          response code in the 3xx range. |  | ||||||
|   |  | ||||||
| +    :param iterable remove_headers_on_redirect:
 |  | ||||||
| +        Sequence of headers to remove from the request when a response
 |  | ||||||
| +        indicating a redirect is returned before firing off the redirected
 |  | ||||||
| +        request
 |  | ||||||
| +
 |  | ||||||
|      :param bool raise_on_status: Similar meaning to ``raise_on_redirect``: |  | ||||||
|          whether we should raise an exception, or return a response, |  | ||||||
|          if status falls in ``status_forcelist`` range and retries have |  | ||||||
| @@ -144,6 +149,8 @@ class Retry(object):
 |  | ||||||
|      DEFAULT_METHOD_WHITELIST = frozenset([ |  | ||||||
|          'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']) |  | ||||||
|   |  | ||||||
| +    DEFAULT_REDIRECT_HEADERS_BLACKLIST = frozenset(['Authorization'])
 |  | ||||||
| +
 |  | ||||||
|      RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) |  | ||||||
|   |  | ||||||
|      #: Maximum backoff time. |  | ||||||
| @@ -152,7 +159,8 @@ class Retry(object):
 |  | ||||||
|      def __init__(self, total=10, connect=None, read=None, redirect=None, status=None, |  | ||||||
|                   method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None, |  | ||||||
|                   backoff_factor=0, raise_on_redirect=True, raise_on_status=True, |  | ||||||
| -                 history=None, respect_retry_after_header=True):
 |  | ||||||
| +                 history=None, respect_retry_after_header=True,
 |  | ||||||
| +                 remove_headers_on_redirect=DEFAULT_REDIRECT_HEADERS_BLACKLIST):
 |  | ||||||
|   |  | ||||||
|          self.total = total |  | ||||||
|          self.connect = connect |  | ||||||
| @@ -171,6 +179,7 @@ class Retry(object):
 |  | ||||||
|          self.raise_on_status = raise_on_status |  | ||||||
|          self.history = history or tuple() |  | ||||||
|          self.respect_retry_after_header = respect_retry_after_header |  | ||||||
| +        self.remove_headers_on_redirect = remove_headers_on_redirect
 |  | ||||||
|   |  | ||||||
|      def new(self, **kw): |  | ||||||
|          params = dict( |  | ||||||
| @@ -182,6 +191,7 @@ class Retry(object):
 |  | ||||||
|              raise_on_redirect=self.raise_on_redirect, |  | ||||||
|              raise_on_status=self.raise_on_status, |  | ||||||
|              history=self.history, |  | ||||||
| +            remove_headers_on_redirect=self.remove_headers_on_redirect,
 |  | ||||||
|          ) |  | ||||||
|          params.update(kw) |  | ||||||
|          return type(self)(**params) |  | ||||||
| -- 
 |  | ||||||
| 2.24.1 |  | ||||||
| 
 |  | ||||||
| @ -1,43 +0,0 @@ | |||||||
| From b40eb0f43daecc6e2e3ce47b0be49cf570d02adc Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lumir Balhar <lbalhar@redhat.com> |  | ||||||
| Date: Thu, 9 Jan 2020 11:14:58 +0100 |  | ||||||
| Subject: [PATCH] CVE-2019-9740 |  | ||||||
| 
 |  | ||||||
| ---
 |  | ||||||
|  util/url.py | 7 +++++++ |  | ||||||
|  1 file changed, 7 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/util/url.py b/util/url.py
 |  | ||||||
| index 6b6f996..2784c85 100644
 |  | ||||||
| --- a/util/url.py
 |  | ||||||
| +++ b/util/url.py
 |  | ||||||
| @@ -1,5 +1,6 @@
 |  | ||||||
|  from __future__ import absolute_import |  | ||||||
|  from collections import namedtuple |  | ||||||
| +import re
 |  | ||||||
|   |  | ||||||
|  from ..exceptions import LocationParseError |  | ||||||
|   |  | ||||||
| @@ -10,6 +11,8 @@ url_attrs = ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment']
 |  | ||||||
|  # urllib3 infers URLs without a scheme (None) to be http. |  | ||||||
|  NORMALIZABLE_SCHEMES = ('http', 'https', None) |  | ||||||
|   |  | ||||||
| +_contains_disallowed_url_pchar_re = re.compile('[\x00-\x20\x7f]')
 |  | ||||||
| +from ..packages.six.moves.urllib.parse import quote
 |  | ||||||
|   |  | ||||||
|  class Url(namedtuple('Url', url_attrs)): |  | ||||||
|      """ |  | ||||||
| @@ -155,6 +158,10 @@ def parse_url(url):
 |  | ||||||
|          # Empty |  | ||||||
|          return Url() |  | ||||||
|   |  | ||||||
| +    # Prevent CVE-2019-9740.
 |  | ||||||
| +    # adapted from https://github.com/python/cpython/pull/12755
 |  | ||||||
| +    url = _contains_disallowed_url_pchar_re.sub(lambda match: quote(match.group()), url)
 |  | ||||||
| +
 |  | ||||||
|      scheme = None |  | ||||||
|      auth = None |  | ||||||
|      host = None |  | ||||||
| -- 
 |  | ||||||
| 2.24.1 |  | ||||||
| 
 |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| From 54e768a6dbe3cadeb456dea37bbeaf6e1e17e87c Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lumir Balhar <lbalhar@redhat.com> |  | ||||||
| Date: Thu, 9 Jan 2020 10:47:27 +0100 |  | ||||||
| Subject: [PATCH] CVE-2019-11324 Certification mishandle when error should be |  | ||||||
|  thrown |  | ||||||
| 
 |  | ||||||
| ---
 |  | ||||||
|  util/ssl_.py | 2 +- |  | ||||||
|  1 file changed, 1 insertion(+), 1 deletion(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/util/ssl_.py b/util/ssl_.py
 |  | ||||||
| index 32fd9ed..f9f12ff 100644
 |  | ||||||
| --- a/util/ssl_.py
 |  | ||||||
| +++ b/util/ssl_.py
 |  | ||||||
| @@ -319,7 +319,7 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
 |  | ||||||
|              if e.errno == errno.ENOENT: |  | ||||||
|                  raise SSLError(e) |  | ||||||
|              raise |  | ||||||
| -    elif getattr(context, 'load_default_certs', None) is not None:
 |  | ||||||
| +    elif ssl_context is None and hasattr(context, 'load_default_certs'):
 |  | ||||||
|          # try to load OS default certs; works well on Windows (require Python3.4+) |  | ||||||
|          context.load_default_certs() |  | ||||||
|   |  | ||||||
| -- 
 |  | ||||||
| 2.24.1 |  | ||||||
| 
 |  | ||||||
| @ -1,53 +0,0 @@ | |||||||
| Backport of https://github.com/pypa/pip/pull/9827 with parts of |  | ||||||
| https://github.com/pypa/pip/pull/4690 to make it work with pip v9.0.1 |  | ||||||
| diff --git a/pip/vcs/git.py b/pip/vcs/git.py
 |  | ||||||
| index 2187dd8..d1502f8 100644
 |  | ||||||
| --- a/pip/vcs/git.py
 |  | ||||||
| +++ b/pip/vcs/git.py
 |  | ||||||
| @@ -81,7 +81,7 @@ class Git(VersionControl):
 |  | ||||||
|          and branches may need origin/ as a prefix. |  | ||||||
|          Returns the SHA1 of the branch or tag if found. |  | ||||||
|          """ |  | ||||||
| -        revisions = self.get_short_refs(dest)
 |  | ||||||
| +        revisions = self.get_short_refs(dest, rev)
 |  | ||||||
|   |  | ||||||
|          origin_rev = 'origin/%s' % rev |  | ||||||
|          if origin_rev in revisions: |  | ||||||
| @@ -171,12 +171,20 @@ class Git(VersionControl):
 |  | ||||||
|              ['rev-parse', 'HEAD'], show_stdout=False, cwd=location) |  | ||||||
|          return current_rev.strip() |  | ||||||
|   |  | ||||||
| -    def get_full_refs(self, location):
 |  | ||||||
| +    def get_full_refs(self, location, pattern=''):
 |  | ||||||
|          """Yields tuples of (commit, ref) for branches and tags""" |  | ||||||
| -        output = self.run_command(['show-ref'],
 |  | ||||||
| +        output = self.run_command(['show-ref', pattern],
 |  | ||||||
|                                    show_stdout=False, cwd=location) |  | ||||||
| -        for line in output.strip().splitlines():
 |  | ||||||
| -            commit, ref = line.split(' ', 1)
 |  | ||||||
| +        for line in output.split("\n"):
 |  | ||||||
| +            line = line.rstrip("\r")
 |  | ||||||
| +            if not line:
 |  | ||||||
| +                continue
 |  | ||||||
| +            try:
 |  | ||||||
| +                commit, ref = line.split(' ', 1)
 |  | ||||||
| +            except ValueError:
 |  | ||||||
| +                # Include the offending line to simplify troubleshooting if
 |  | ||||||
| +                # this error ever occurs.
 |  | ||||||
| +                raise ValueError(f'unexpected show-ref line: {line!r}')
 |  | ||||||
|              yield commit.strip(), ref.strip() |  | ||||||
|   |  | ||||||
|      def is_ref_remote(self, ref): |  | ||||||
| @@ -200,10 +208,10 @@ class Git(VersionControl):
 |  | ||||||
|      def get_refs(self, location): |  | ||||||
|          return self.get_short_refs(location) |  | ||||||
|   |  | ||||||
| -    def get_short_refs(self, location):
 |  | ||||||
| +    def get_short_refs(self, location, pattern=''):
 |  | ||||||
|          """Return map of named refs (branches or tags) to commit hashes.""" |  | ||||||
|          rv = {} |  | ||||||
| -        for commit, ref in self.get_full_refs(location):
 |  | ||||||
| +        for commit, ref in self.get_full_refs(location, pattern):
 |  | ||||||
|              ref_name = None |  | ||||||
|              if self.is_ref_remote(ref): |  | ||||||
|                  ref_name = ref[len('refs/remotes/'):] |  | ||||||
| @ -1,95 +0,0 @@ | |||||||
| diff -up pip-9.0.1/pip/commands/install.py.orig pip-9.0.1/pip/commands/install.py
 |  | ||||||
| --- pip-9.0.1/pip/commands/install.py.orig	2016-11-06 11:49:45.000000000 -0700
 |  | ||||||
| +++ pip-9.0.1/pip/commands/install.py	2016-11-16 16:20:48.638906543 -0700
 |  | ||||||
| @@ -151,6 +151,14 @@ class InstallCommand(RequirementCommand)
 |  | ||||||
|                   "directory.") |  | ||||||
|   |  | ||||||
|          cmd_opts.add_option( |  | ||||||
| +            '--strip-file-prefix',
 |  | ||||||
| +            dest='strip_file_prefix',
 |  | ||||||
| +            metavar='prefix',
 |  | ||||||
| +            default=None,
 |  | ||||||
| +            help="Strip given prefix from script paths in wheel RECORD."
 |  | ||||||
| +        )
 |  | ||||||
| +
 |  | ||||||
| +        cmd_opts.add_option(
 |  | ||||||
|              '--prefix', |  | ||||||
|              dest='prefix_path', |  | ||||||
|              metavar='dir', |  | ||||||
| @@ -340,6 +348,7 @@ class InstallCommand(RequirementCommand)
 |  | ||||||
|                              global_options, |  | ||||||
|                              root=options.root_path, |  | ||||||
|                              prefix=options.prefix_path, |  | ||||||
| +                            strip_file_prefix=options.strip_file_prefix,
 |  | ||||||
|                          ) |  | ||||||
|   |  | ||||||
|                          possible_lib_locations = get_lib_location_guesses( |  | ||||||
| diff -up pip-9.0.1/pip/req/req_install.py.orig pip-9.0.1/pip/req/req_install.py
 |  | ||||||
| --- pip-9.0.1/pip/req/req_install.py.orig	2016-11-06 11:49:45.000000000 -0700
 |  | ||||||
| +++ pip-9.0.1/pip/req/req_install.py	2016-11-16 16:19:24.848336960 -0700
 |  | ||||||
| @@ -838,8 +838,7 @@ class InstallRequirement(object):
 |  | ||||||
|          else: |  | ||||||
|              return True |  | ||||||
|   |  | ||||||
| -    def install(self, install_options, global_options=[], root=None,
 |  | ||||||
| -                prefix=None):
 |  | ||||||
| +    def install(self, install_options, global_options=[], root=None, prefix=None, strip_file_prefix=None):
 |  | ||||||
|          if self.editable: |  | ||||||
|              self.install_editable( |  | ||||||
|                  install_options, global_options, prefix=prefix) |  | ||||||
| @@ -848,7 +847,12 @@ class InstallRequirement(object):
 |  | ||||||
|              version = pip.wheel.wheel_version(self.source_dir) |  | ||||||
|              pip.wheel.check_compatibility(version, self.name) |  | ||||||
|   |  | ||||||
| -            self.move_wheel_files(self.source_dir, root=root, prefix=prefix)
 |  | ||||||
| +            self.move_wheel_files(
 |  | ||||||
| +                self.source_dir,
 |  | ||||||
| +                root=root,
 |  | ||||||
| +                prefix=prefix,
 |  | ||||||
| +                strip_file_prefix=strip_file_prefix
 |  | ||||||
| +            )
 |  | ||||||
|              self.install_succeeded = True |  | ||||||
|              return |  | ||||||
|   |  | ||||||
| @@ -1053,7 +1057,7 @@ class InstallRequirement(object):
 |  | ||||||
|      def is_wheel(self): |  | ||||||
|          return self.link and self.link.is_wheel |  | ||||||
|   |  | ||||||
| -    def move_wheel_files(self, wheeldir, root=None, prefix=None):
 |  | ||||||
| +    def move_wheel_files(self, wheeldir, root=None, prefix=None, strip_file_prefix=None):
 |  | ||||||
|          move_wheel_files( |  | ||||||
|              self.name, self.req, wheeldir, |  | ||||||
|              user=self.use_user_site, |  | ||||||
| @@ -1062,6 +1066,7 @@ class InstallRequirement(object):
 |  | ||||||
|              prefix=prefix, |  | ||||||
|              pycompile=self.pycompile, |  | ||||||
|              isolated=self.isolated, |  | ||||||
| +            strip_file_prefix=strip_file_prefix,
 |  | ||||||
|          ) |  | ||||||
|   |  | ||||||
|      def get_dist(self): |  | ||||||
| diff -up pip-9.0.1/pip/wheel.py.orig pip-9.0.1/pip/wheel.py
 |  | ||||||
| --- pip-9.0.1/pip/wheel.py.orig	2016-11-06 11:49:45.000000000 -0700
 |  | ||||||
| +++ pip-9.0.1/pip/wheel.py	2016-11-16 16:19:24.848336960 -0700
 |  | ||||||
| @@ -238,7 +238,7 @@ def get_entrypoints(filename):
 |  | ||||||
|   |  | ||||||
|   |  | ||||||
|  def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None, |  | ||||||
| -                     pycompile=True, scheme=None, isolated=False, prefix=None):
 |  | ||||||
| +                     pycompile=True, scheme=None, isolated=False, prefix=None, strip_file_prefix=None):
 |  | ||||||
|      """Install a wheel""" |  | ||||||
|   |  | ||||||
|      if not scheme: |  | ||||||
| @@ -521,7 +521,11 @@ if __name__ == '__main__':
 |  | ||||||
|                  writer.writerow(row) |  | ||||||
|              for f in generated: |  | ||||||
|                  h, l = rehash(f) |  | ||||||
| -                writer.writerow((normpath(f, lib_dir), h, l))
 |  | ||||||
| +                final_path = normpath(f, lib_dir)
 |  | ||||||
| +                if strip_file_prefix and final_path.startswith(strip_file_prefix):
 |  | ||||||
| +                    final_path = os.path.join(os.sep,
 |  | ||||||
| +                            os.path.relpath(final_path, strip_file_prefix))
 |  | ||||||
| +                writer.writerow((final_path, h, l))
 |  | ||||||
|              for f in installed: |  | ||||||
|                  writer.writerow((installed[f], '', '')) |  | ||||||
|      shutil.move(temp_record, record) |  | ||||||
| @ -1,12 +1,23 @@ | |||||||
| Minimal patch for pip | From 1819805f2019c731bcaefd6b12fd814790f88fcd Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Lumir Balhar <lbalhar@redhat.com> | ||||||
|  | Date: Tue, 19 Mar 2024 12:43:07 +0100 | ||||||
|  | Subject: [PATCH] cve-2007-4559-tarfile | ||||||
| 
 | 
 | ||||||
| diff -rU3 pip-22.3.1-orig/src/pip/_internal/utils/unpacking.py pip-22.3.1/src/pip/_internal/utils/unpacking.py
 | Minimal patch for pip | ||||||
| --- a/pip/utils/__init__.py	2022-11-05 16:25:43.000000000 +0100
 | ---
 | ||||||
| +++ b/pip/utils/__init__.py	2023-08-08 13:17:47.705613554 +0200
 |  src/pip/_internal/utils/unpacking.py |  7 +++++++ | ||||||
| @@ -559,6 +559,13 @@
 |  src/pip/_vendor/distlib/util.py      | 13 +++++++++++++ | ||||||
|              if leading: |  tests/unit/test_utils_unpacking.py   | 17 +++++++++++++++++ | ||||||
|                  fn = split_leading_dir(fn)[1] |  3 files changed, 37 insertions(+) | ||||||
|              path = os.path.join(location, fn) | 
 | ||||||
|  | diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py
 | ||||||
|  | index 5f63f97..c31542f 100644
 | ||||||
|  | --- a/src/pip/_internal/utils/unpacking.py
 | ||||||
|  | +++ b/src/pip/_internal/utils/unpacking.py
 | ||||||
|  | @@ -184,6 +184,13 @@ def untar_file(filename: str, location: str) -> None:
 | ||||||
|  |                      "outside target directory ({})" | ||||||
|  |                  ) | ||||||
|  |                  raise InstallationError(message.format(filename, path, location)) | ||||||
| +
 | +
 | ||||||
| +            # Call the `data` filter for its side effect (raising exception)
 | +            # Call the `data` filter for its side effect (raising exception)
 | ||||||
| +            try:
 | +            try:
 | ||||||
| @ -17,15 +28,11 @@ diff -rU3 pip-22.3.1-orig/src/pip/_internal/utils/unpacking.py pip-22.3.1/src/pi | |||||||
|              if member.isdir(): |              if member.isdir(): | ||||||
|                  ensure_dir(path) |                  ensure_dir(path) | ||||||
|              elif member.issym(): |              elif member.issym(): | ||||||
| 
 | diff --git a/src/pip/_vendor/distlib/util.py b/src/pip/_vendor/distlib/util.py
 | ||||||
| 
 | index 80bfc86..7e0941a 100644
 | ||||||
| Patch for vendored distlib from https://github.com/pypa/distlib/pull/201 | --- a/src/pip/_vendor/distlib/util.py
 | ||||||
| 
 | +++ b/src/pip/_vendor/distlib/util.py
 | ||||||
| diff --git a/distlib/util.py b/distlib/util.py
 | @@ -1249,6 +1249,19 @@ def unarchive(archive_filename, dest_dir, format=None, check=True):
 | ||||||
| index e0622e4..4349d0b 100644
 |  | ||||||
| --- a/pip/_vendor/distlib/util.py
 |  | ||||||
| +++ b/pip/_vendor/distlib/util.py
 |  | ||||||
| @@ -1249,6 +1249,19 @@ def check_path(path):
 |  | ||||||
|              for tarinfo in archive.getmembers(): |              for tarinfo in archive.getmembers(): | ||||||
|                  if not isinstance(tarinfo.name, text_type): |                  if not isinstance(tarinfo.name, text_type): | ||||||
|                      tarinfo.name = tarinfo.name.decode('utf-8') |                      tarinfo.name = tarinfo.name.decode('utf-8') | ||||||
| @ -45,3 +52,34 @@ index e0622e4..4349d0b 100644 | |||||||
|          archive.extractall(dest_dir) |          archive.extractall(dest_dir) | ||||||
|   |   | ||||||
|      finally: |      finally: | ||||||
|  | diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py
 | ||||||
|  | index ccb7a30..05324ad 100644
 | ||||||
|  | --- a/tests/unit/test_utils_unpacking.py
 | ||||||
|  | +++ b/tests/unit/test_utils_unpacking.py
 | ||||||
|  | @@ -171,6 +171,23 @@ class TestUnpackArchives:
 | ||||||
|  |          test_tar = self.make_tar_file("test_tar.tar", files) | ||||||
|  |          untar_file(test_tar, self.tempdir) | ||||||
|  |   | ||||||
|  | +    def test_unpack_tar_filter(self) -> None:
 | ||||||
|  | +        """
 | ||||||
|  | +        Test that the tarfile.data_filter is used to disallow dangerous
 | ||||||
|  | +        behaviour (PEP-721)
 | ||||||
|  | +        """
 | ||||||
|  | +        test_tar = os.path.join(self.tempdir, "test_tar_filter.tar")
 | ||||||
|  | +        with tarfile.open(test_tar, "w") as mytar:
 | ||||||
|  | +            file_tarinfo = tarfile.TarInfo("bad-link")
 | ||||||
|  | +            file_tarinfo.type = tarfile.SYMTYPE
 | ||||||
|  | +            file_tarinfo.linkname = "../../../../pwn"
 | ||||||
|  | +            mytar.addfile(file_tarinfo, io.BytesIO(b""))
 | ||||||
|  | +        with pytest.raises(InstallationError) as e:
 | ||||||
|  | +            untar_file(test_tar, self.tempdir)
 | ||||||
|  | +
 | ||||||
|  | +        assert "is outside the destination" in str(e.value)
 | ||||||
|  | +
 | ||||||
|  | +
 | ||||||
|  |   | ||||||
|  |  def test_unpack_tar_unicode(tmpdir: Path) -> None: | ||||||
|  |      test_tar = tmpdir / "test.tar" | ||||||
|  | -- 
 | ||||||
|  | 2.44.0 | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -1,15 +1,36 @@ | |||||||
| diff --git a/pip/_vendor/certifi/core.py b/pip/_vendor/certifi/core.py
 | From 2c58d7301dd5a47570f782fe2fce7fbb1918f60c Mon Sep 17 00:00:00 2001 | ||||||
| index eab9d1d..9614a88 100644
 | From: Karolina Surma <ksurma@redhat.com> | ||||||
| --- a/pip/_vendor/certifi/core.py
 | Date: Mon, 10 May 2021 16:38:50 +0200 | ||||||
| +++ b/pip/_vendor/certifi/core.py
 | Subject: [PATCH] Dummy certifi patch | ||||||
| @@ -19,9 +19,7 @@ class DeprecatedBundleWarning(DeprecationWarning):
 | 
 | ||||||
|  | Co-Authored-By: Tomas Hrnciar <thrnciar@redhat.com> | ||||||
|  | ---
 | ||||||
|  |  src/pip/_vendor/certifi/core.py | 5 ++--- | ||||||
|  |  1 file changed, 2 insertions(+), 3 deletions(-) | ||||||
|  | 
 | ||||||
|  | diff --git a/src/pip/_vendor/certifi/core.py b/src/pip/_vendor/certifi/core.py
 | ||||||
|  | index b8140cf..f1a0b01 100644
 | ||||||
|  | --- a/src/pip/_vendor/certifi/core.py
 | ||||||
|  | +++ b/src/pip/_vendor/certifi/core.py
 | ||||||
|  | @@ -14,6 +14,7 @@ class _PipPatchedCertificate(Exception):
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  def where(): |  try: | ||||||
| -    f = os.path.dirname(__file__)
 | +    raise ImportError  # force fallback
 | ||||||
|  |      # Return a certificate file on disk for a standalone pip zipapp running in | ||||||
|  |      # an isolated build environment to use. Passing --cert to the standalone | ||||||
|  |      # pip does not work since requests calls where() unconditionally on import. | ||||||
|  | @@ -67,9 +68,7 @@ except ImportError:
 | ||||||
|  |      # If we don't have importlib.resources, then we will just do the old logic | ||||||
|  |      # of assuming we're on the filesystem and munge the path directly. | ||||||
|  |      def where(): | ||||||
|  | -        f = os.path.dirname(__file__)
 | ||||||
| -
 | -
 | ||||||
| -    return os.path.join(f, 'cacert.pem')
 | -        return os.path.join(f, "cacert.pem")
 | ||||||
| +    return '/etc/pki/tls/certs/ca-bundle.crt'
 | +        return '/etc/pki/tls/certs/ca-bundle.crt'
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  def old_where(): |  def contents(): | ||||||
|  | --
 | ||||||
|  | 2.30.2 | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -1,44 +0,0 @@ | |||||||
| From 18a617e9e0f64b727938422d4f941dfddfbf5d00 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tomas Orsava <torsava@redhat.com> |  | ||||||
| Date: Tue, 14 Feb 2017 17:10:09 +0100 |  | ||||||
| Subject: [PATCH] Emit a warning when running with root privileges. |  | ||||||
| 
 |  | ||||||
| ---
 |  | ||||||
|  pip/commands/install.py | 14 ++++++++++++++ |  | ||||||
|  1 file changed, 14 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/pip/commands/install.py b/pip/commands/install.py
 |  | ||||||
| index 227c526..277a3d1 100644
 |  | ||||||
| --- a/pip/commands/install.py
 |  | ||||||
| +++ b/pip/commands/install.py
 |  | ||||||
| @@ -6,6 +6,8 @@ import os
 |  | ||||||
|  import tempfile |  | ||||||
|  import shutil |  | ||||||
|  import warnings |  | ||||||
| +import sys
 |  | ||||||
| +from os import path
 |  | ||||||
|  try: |  | ||||||
|      import wheel |  | ||||||
|  except ImportError: |  | ||||||
| @@ -193,6 +195,18 @@ class InstallCommand(RequirementCommand):
 |  | ||||||
|          cmdoptions.resolve_wheel_no_use_binary(options) |  | ||||||
|          cmdoptions.check_install_build_global(options) |  | ||||||
|   |  | ||||||
| +        def is_venv():
 |  | ||||||
| +            return hasattr(sys, 'real_prefix') or \
 |  | ||||||
| +                    (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix)
 |  | ||||||
| +
 |  | ||||||
| +        # Check whether we have root privileges and aren't in venv/virtualenv
 |  | ||||||
| +        if os.getuid() == 0 and not is_venv():
 |  | ||||||
| +            logger.warning(
 |  | ||||||
| +                "WARNING: Running pip install with root privileges is "
 |  | ||||||
| +                "generally not a good idea. Try `%s install --user` instead."
 |  | ||||||
| +                        % path.basename(sys.argv[0])
 |  | ||||||
| +            )
 |  | ||||||
| +
 |  | ||||||
|          if options.as_egg: |  | ||||||
|              warnings.warn( |  | ||||||
|                  "--egg has been deprecated and will be removed in the future. " |  | ||||||
| -- 
 |  | ||||||
| 2.11.0 |  | ||||||
| 
 |  | ||||||
							
								
								
									
										16
									
								
								SOURCES/no-version-warning.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								SOURCES/no-version-warning.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | diff --git a/src/pip/_vendor/packaging/version.py b/src/pip/_vendor/packaging/version.py
 | ||||||
|  | index de9a09a..154e94d 100644
 | ||||||
|  | --- a/src/pip/_vendor/packaging/version.py
 | ||||||
|  | +++ b/src/pip/_vendor/packaging/version.py
 | ||||||
|  | @@ -108,11 +108,6 @@ class LegacyVersion(_BaseVersion):
 | ||||||
|  |          self._version = str(version) | ||||||
|  |          self._key = _legacy_cmpkey(self._version) | ||||||
|  |   | ||||||
|  | -        warnings.warn(
 | ||||||
|  | -            "Creating a LegacyVersion has been deprecated and will be "
 | ||||||
|  | -            "removed in the next major release",
 | ||||||
|  | -            DeprecationWarning,
 | ||||||
|  | -        )
 | ||||||
|  |   | ||||||
|  |      def __str__(self) -> str: | ||||||
|  |          return self._version | ||||||
							
								
								
									
										74
									
								
								SOURCES/nowarn-pip._internal.main.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								SOURCES/nowarn-pip._internal.main.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | |||||||
|  | From 619782ad2d181fe2933ddf4edc7127fdc13dd0df Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Karolina Surma <ksurma@redhat.com> | ||||||
|  | Date: Mon, 10 May 2021 16:48:49 +0200 | ||||||
|  | Subject: [PATCH] Don't warn the user about pip._internal.main() entrypoint | ||||||
|  | 
 | ||||||
|  | In Fedora, we use that in ensurepip and users cannot do anything about it, | ||||||
|  | this warning is juts moot. Also, the warning breaks CPython test suite. | ||||||
|  | 
 | ||||||
|  | Co-Authored-By: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz> | ||||||
|  | ---
 | ||||||
|  |  src/pip/_internal/__init__.py          |  2 +- | ||||||
|  |  src/pip/_internal/utils/entrypoints.py | 19 ++++++++++--------- | ||||||
|  |  tests/functional/test_cli.py           |  3 ++- | ||||||
|  |  3 files changed, 13 insertions(+), 11 deletions(-) | ||||||
|  | 
 | ||||||
|  | diff --git a/src/pip/_internal/__init__.py b/src/pip/_internal/__init__.py
 | ||||||
|  | index 6afb5c6..faf25af 100755
 | ||||||
|  | --- a/src/pip/_internal/__init__.py
 | ||||||
|  | +++ b/src/pip/_internal/__init__.py
 | ||||||
|  | @@ -16,4 +16,4 @@ def main(args: (Optional[List[str]]) = None) -> int:
 | ||||||
|  |      """ | ||||||
|  |      from pip._internal.utils.entrypoints import _wrapper | ||||||
|  |   | ||||||
|  | -    return _wrapper(args)
 | ||||||
|  | +    return _wrapper(args, _nowarn=True)
 | ||||||
|  | diff --git a/src/pip/_internal/utils/entrypoints.py b/src/pip/_internal/utils/entrypoints.py
 | ||||||
|  | index 1504a12..07d941b 100644
 | ||||||
|  | --- a/src/pip/_internal/utils/entrypoints.py
 | ||||||
|  | +++ b/src/pip/_internal/utils/entrypoints.py
 | ||||||
|  | @@ -4,7 +4,7 @@ from typing import List, Optional
 | ||||||
|  |  from pip._internal.cli.main import main | ||||||
|  |   | ||||||
|  |   | ||||||
|  | -def _wrapper(args: Optional[List[str]] = None) -> int:
 | ||||||
|  | +def _wrapper(args: Optional[List[str]] = None, _nowarn: bool = False) -> int:
 | ||||||
|  |      """Central wrapper for all old entrypoints. | ||||||
|  |   | ||||||
|  |      Historically pip has had several entrypoints defined. Because of issues | ||||||
|  | @@ -16,12 +16,13 @@ def _wrapper(args: Optional[List[str]] = None) -> int:
 | ||||||
|  |      directing them to an appropriate place for help, we now define all of | ||||||
|  |      our old entrypoints as wrappers for the current one. | ||||||
|  |      """ | ||||||
|  | -    sys.stderr.write(
 | ||||||
|  | -        "WARNING: pip is being invoked by an old script wrapper. This will "
 | ||||||
|  | -        "fail in a future version of pip.\n"
 | ||||||
|  | -        "Please see https://github.com/pypa/pip/issues/5599 for advice on "
 | ||||||
|  | -        "fixing the underlying issue.\n"
 | ||||||
|  | -        "To avoid this problem you can invoke Python with '-m pip' instead of "
 | ||||||
|  | -        "running pip directly.\n"
 | ||||||
|  | -    )
 | ||||||
|  | +    if not _nowarn:
 | ||||||
|  | +        sys.stderr.write(
 | ||||||
|  | +            "WARNING: pip is being invoked by an old script wrapper. This will "
 | ||||||
|  | +            "fail in a future version of pip.\n"
 | ||||||
|  | +            "Please see https://github.com/pypa/pip/issues/5599 for advice on "
 | ||||||
|  | +            "fixing the underlying issue.\n"
 | ||||||
|  | +            "To avoid this problem you can invoke Python with '-m pip' instead of "
 | ||||||
|  | +            "running pip directly.\n"
 | ||||||
|  | +        )
 | ||||||
|  |      return main(args) | ||||||
|  | diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py
 | ||||||
|  | index e416315..7f57f67 100644
 | ||||||
|  | --- a/tests/functional/test_cli.py
 | ||||||
|  | +++ b/tests/functional/test_cli.py
 | ||||||
|  | @@ -31,4 +31,5 @@ def test_entrypoints_work(entrypoint, script):
 | ||||||
|  |      result = script.pip("-V") | ||||||
|  |      result2 = script.run("fake_pip", "-V", allow_stderr_warning=True) | ||||||
|  |      assert result.stdout == result2.stdout | ||||||
|  | -    assert "old script wrapper" in result2.stderr
 | ||||||
|  | +    if entrypoint[0] != "fake_pip = pip._internal:main":
 | ||||||
|  | +        assert "old script wrapper" in result2.stderr
 | ||||||
|  | -- 
 | ||||||
|  | 2.32.0 | ||||||
|  | 
 | ||||||
							
								
								
									
										27
									
								
								SOURCES/pip-allow-different-versions.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								SOURCES/pip-allow-different-versions.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | --- /usr/bin/pip3	2019-11-12 17:37:34.793131862 +0100
 | ||||||
|  | +++ pip3	2019-11-12 17:40:42.014107134 +0100
 | ||||||
|  | @@ -2,7 +2,23 @@
 | ||||||
|  |  # -*- coding: utf-8 -*- | ||||||
|  |  import re | ||||||
|  |  import sys | ||||||
|  | -from pip._internal.cli.main import main
 | ||||||
|  | +
 | ||||||
|  | +try:
 | ||||||
|  | +    from pip._internal.cli.main import main
 | ||||||
|  | +except ImportError:
 | ||||||
|  | +    try:
 | ||||||
|  | +        from pip._internal.main import main
 | ||||||
|  | +    except ImportError:
 | ||||||
|  | +        try:
 | ||||||
|  | +            # If the user has downgraded pip, the above import will fail.
 | ||||||
|  | +            # Let's try older methods of invoking it:
 | ||||||
|  | +
 | ||||||
|  | +            # pip 19 uses this
 | ||||||
|  | +            from pip._internal import main
 | ||||||
|  | +        except ImportError:
 | ||||||
|  | +            # older pip versions use this
 | ||||||
|  | +            from pip import main
 | ||||||
|  | +
 | ||||||
|  |  if __name__ == '__main__': | ||||||
|  |      sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) | ||||||
|  |      sys.exit(main()) | ||||||
| @ -1,122 +0,0 @@ | |||||||
| From 7917dbda14ef64a5e7fdea48383a266577484ac8 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Tomas Orsava <torsava@redhat.com> |  | ||||||
| Date: Wed, 19 Aug 2020 12:51:16 +0200 |  | ||||||
| Subject: [PATCH 2/2] FIX #6413 pip install <url> allow directory traversal |  | ||||||
|  (tests) |  | ||||||
| 
 |  | ||||||
| ---
 |  | ||||||
|  tests/unit/test_download.py | 85 +++++++++++++++++++++++++++++++++++++ |  | ||||||
|  1 file changed, 85 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/tests/unit/test_download.py b/tests/unit/test_download.py
 |  | ||||||
| index ee4b11c..15f99ec 100644
 |  | ||||||
| --- a/tests/unit/test_download.py
 |  | ||||||
| +++ b/tests/unit/test_download.py
 |  | ||||||
| @@ -1,5 +1,6 @@
 |  | ||||||
|  import hashlib |  | ||||||
|  import os |  | ||||||
| +import sys
 |  | ||||||
|  from io import BytesIO |  | ||||||
|  from shutil import rmtree, copy |  | ||||||
|  from tempfile import mkdtemp |  | ||||||
| @@ -13,6 +14,7 @@ import pip
 |  | ||||||
|  from pip.exceptions import HashMismatch |  | ||||||
|  from pip.download import ( |  | ||||||
|      PipSession, SafeFileCache, path_to_url, unpack_http_url, url_to_path, |  | ||||||
| +    _download_http_url, parse_content_disposition, sanitize_content_filename,
 |  | ||||||
|      unpack_file_url, |  | ||||||
|  ) |  | ||||||
|  from pip.index import Link |  | ||||||
| @@ -123,6 +125,89 @@ def test_unpack_http_url_bad_downloaded_checksum(mock_unpack_file):
 |  | ||||||
|          rmtree(download_dir) |  | ||||||
|   |  | ||||||
|   |  | ||||||
| +@pytest.mark.parametrize("filename, expected", [
 |  | ||||||
| +    ('dir/file', 'file'),
 |  | ||||||
| +    ('../file', 'file'),
 |  | ||||||
| +    ('../../file', 'file'),
 |  | ||||||
| +    ('../', ''),
 |  | ||||||
| +    ('../..', '..'),
 |  | ||||||
| +    ('/', ''),
 |  | ||||||
| +])
 |  | ||||||
| +def test_sanitize_content_filename(filename, expected):
 |  | ||||||
| +    """
 |  | ||||||
| +    Test inputs where the result is the same for Windows and non-Windows.
 |  | ||||||
| +    """
 |  | ||||||
| +    assert sanitize_content_filename(filename) == expected
 |  | ||||||
| +
 |  | ||||||
| +
 |  | ||||||
| +@pytest.mark.parametrize("filename, win_expected, non_win_expected", [
 |  | ||||||
| +    ('dir\\file', 'file', 'dir\\file'),
 |  | ||||||
| +    ('..\\file', 'file', '..\\file'),
 |  | ||||||
| +    ('..\\..\\file', 'file', '..\\..\\file'),
 |  | ||||||
| +    ('..\\', '', '..\\'),
 |  | ||||||
| +    ('..\\..', '..', '..\\..'),
 |  | ||||||
| +    ('\\', '', '\\'),
 |  | ||||||
| +])
 |  | ||||||
| +def test_sanitize_content_filename__platform_dependent(
 |  | ||||||
| +    filename,
 |  | ||||||
| +    win_expected,
 |  | ||||||
| +    non_win_expected
 |  | ||||||
| +):
 |  | ||||||
| +    """
 |  | ||||||
| +    Test inputs where the result is different for Windows and non-Windows.
 |  | ||||||
| +    """
 |  | ||||||
| +    if sys.platform == 'win32':
 |  | ||||||
| +        expected = win_expected
 |  | ||||||
| +    else:
 |  | ||||||
| +        expected = non_win_expected
 |  | ||||||
| +    assert sanitize_content_filename(filename) == expected
 |  | ||||||
| +
 |  | ||||||
| +
 |  | ||||||
| +@pytest.mark.parametrize("content_disposition, default_filename, expected", [
 |  | ||||||
| +    ('attachment;filename="../file"', 'df', 'file'),
 |  | ||||||
| +])
 |  | ||||||
| +def test_parse_content_disposition(
 |  | ||||||
| +    content_disposition,
 |  | ||||||
| +    default_filename,
 |  | ||||||
| +    expected
 |  | ||||||
| +):
 |  | ||||||
| +    actual = parse_content_disposition(content_disposition, default_filename)
 |  | ||||||
| +    assert actual == expected
 |  | ||||||
| +
 |  | ||||||
| +
 |  | ||||||
| +def test_download_http_url__no_directory_traversal(tmpdir):
 |  | ||||||
| +    """
 |  | ||||||
| +    Test that directory traversal doesn't happen on download when the
 |  | ||||||
| +    Content-Disposition header contains a filename with a ".." path part.
 |  | ||||||
| +    """
 |  | ||||||
| +    mock_url = 'http://www.example.com/whatever.tgz'
 |  | ||||||
| +    contents = b'downloaded'
 |  | ||||||
| +    link = Link(mock_url)
 |  | ||||||
| +
 |  | ||||||
| +    session = Mock()
 |  | ||||||
| +    resp = MockResponse(contents)
 |  | ||||||
| +    resp.url = mock_url
 |  | ||||||
| +    resp.headers = {
 |  | ||||||
| +        # Set the content-type to a random value to prevent
 |  | ||||||
| +        # mimetypes.guess_extension from guessing the extension.
 |  | ||||||
| +        'content-type': 'random',
 |  | ||||||
| +        'content-disposition': 'attachment;filename="../out_dir_file"'
 |  | ||||||
| +    }
 |  | ||||||
| +    session.get.return_value = resp
 |  | ||||||
| +
 |  | ||||||
| +    download_dir = tmpdir.join('download')
 |  | ||||||
| +    os.mkdir(download_dir)
 |  | ||||||
| +    file_path, content_type = _download_http_url(
 |  | ||||||
| +        link,
 |  | ||||||
| +        session,
 |  | ||||||
| +        download_dir,
 |  | ||||||
| +        hashes=None,
 |  | ||||||
| +    )
 |  | ||||||
| +    # The file should be downloaded to download_dir.
 |  | ||||||
| +    actual = os.listdir(download_dir)
 |  | ||||||
| +    assert actual == ['out_dir_file']
 |  | ||||||
| +
 |  | ||||||
| +
 |  | ||||||
|  @pytest.mark.skipif("sys.platform == 'win32'") |  | ||||||
|  def test_path_to_url_unix(): |  | ||||||
|      assert path_to_url('/tmp/file') == 'file:///tmp/file' |  | ||||||
| -- 
 |  | ||||||
| 2.25.4 |  | ||||||
| 
 |  | ||||||
| @ -1,79 +0,0 @@ | |||||||
| From 8044d9f2fbcb09f09a62b26ac1d8a134976bb2ac Mon Sep 17 00:00:00 2001 |  | ||||||
| From: gzpan123 <gzpan123@gmail.com> |  | ||||||
| Date: Wed, 17 Apr 2019 21:25:45 +0800 |  | ||||||
| Subject: [PATCH 1/2] FIX #6413 pip install <url> allow directory traversal |  | ||||||
| 
 |  | ||||||
| ---
 |  | ||||||
|  news/6413.bugfix |  3 +++ |  | ||||||
|  pip/download.py  | 31 ++++++++++++++++++++++++++----- |  | ||||||
|  2 files changed, 29 insertions(+), 5 deletions(-) |  | ||||||
|  create mode 100644 news/6413.bugfix |  | ||||||
| 
 |  | ||||||
| diff --git a/news/6413.bugfix b/news/6413.bugfix
 |  | ||||||
| new file mode 100644 |  | ||||||
| index 0000000..68d0a72
 |  | ||||||
| --- /dev/null
 |  | ||||||
| +++ b/news/6413.bugfix
 |  | ||||||
| @@ -0,0 +1,3 @@
 |  | ||||||
| +Prevent ``pip install <url>`` from permitting directory traversal if e.g.
 |  | ||||||
| +a malicious server sends a ``Content-Disposition`` header with a filename
 |  | ||||||
| +containing ``../`` or ``..\\``.
 |  | ||||||
| diff --git a/pip/download.py b/pip/download.py
 |  | ||||||
| index 039e55a..b3d169b 100644
 |  | ||||||
| --- a/pip/download.py
 |  | ||||||
| +++ b/pip/download.py
 |  | ||||||
| @@ -54,7 +54,8 @@ __all__ = ['get_file_content',
 |  | ||||||
|             'is_url', 'url_to_path', 'path_to_url', |  | ||||||
|             'is_archive_file', 'unpack_vcs_link', |  | ||||||
|             'unpack_file_url', 'is_vcs_url', 'is_file_url', |  | ||||||
| -           'unpack_http_url', 'unpack_url']
 |  | ||||||
| +           'unpack_http_url', 'unpack_url',
 |  | ||||||
| +           'parse_content_disposition', 'sanitize_content_filename']
 |  | ||||||
|   |  | ||||||
|   |  | ||||||
|  logger = logging.getLogger(__name__) |  | ||||||
| @@ -824,6 +825,29 @@ def unpack_url(link, location, download_dir=None,
 |  | ||||||
|          write_delete_marker_file(location) |  | ||||||
|   |  | ||||||
|   |  | ||||||
| +def sanitize_content_filename(filename):
 |  | ||||||
| +    # type: (str) -> str
 |  | ||||||
| +    """
 |  | ||||||
| +    Sanitize the "filename" value from a Content-Disposition header.
 |  | ||||||
| +    """
 |  | ||||||
| +    return os.path.basename(filename)
 |  | ||||||
| +
 |  | ||||||
| +
 |  | ||||||
| +def parse_content_disposition(content_disposition, default_filename):
 |  | ||||||
| +    # type: (str, str) -> str
 |  | ||||||
| +    """
 |  | ||||||
| +    Parse the "filename" value from a Content-Disposition header, and
 |  | ||||||
| +    return the default filename if the result is empty.
 |  | ||||||
| +    """
 |  | ||||||
| +    _type, params = cgi.parse_header(content_disposition)
 |  | ||||||
| +    filename = params.get('filename')
 |  | ||||||
| +    if filename:
 |  | ||||||
| +        # We need to sanitize the filename to prevent directory traversal
 |  | ||||||
| +        # in case the filename contains ".." path parts.
 |  | ||||||
| +        filename = sanitize_content_filename(filename)
 |  | ||||||
| +    return filename or default_filename
 |  | ||||||
| +
 |  | ||||||
| +
 |  | ||||||
|  def _download_http_url(link, session, temp_dir, hashes): |  | ||||||
|      """Download link url into temp_dir using provided session""" |  | ||||||
|      target_url = link.url.split('#', 1)[0] |  | ||||||
| @@ -864,10 +888,7 @@ def _download_http_url(link, session, temp_dir, hashes):
 |  | ||||||
|      # Have a look at the Content-Disposition header for a better guess |  | ||||||
|      content_disposition = resp.headers.get('content-disposition') |  | ||||||
|      if content_disposition: |  | ||||||
| -        type, params = cgi.parse_header(content_disposition)
 |  | ||||||
| -        # We use ``or`` here because we don't want to use an "empty" value
 |  | ||||||
| -        # from the filename param.
 |  | ||||||
| -        filename = params.get('filename') or filename
 |  | ||||||
| +        filename = parse_content_disposition(content_disposition, filename)
 |  | ||||||
|      ext = splitext(filename)[1] |  | ||||||
|      if not ext: |  | ||||||
|          ext = mimetypes.guess_extension(content_type) |  | ||||||
| -- 
 |  | ||||||
| 2.25.4 |  | ||||||
| 
 |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| diff --git a/pip/utils/outdated.py b/pip/utils/outdated.py
 |  | ||||||
| index 2164cc3..c71539f 100644
 |  | ||||||
| --- a/pip/utils/outdated.py
 |  | ||||||
| +++ b/pip/utils/outdated.py
 |  | ||||||
| @@ -92,6 +92,21 @@ def load_selfcheck_statefile():
 |  | ||||||
|          return GlobalSelfCheckState() |  | ||||||
|   |  | ||||||
|   |  | ||||||
| +def pip_installed_by_pip():
 |  | ||||||
| +    """Checks whether pip was installed by pip
 |  | ||||||
| +
 |  | ||||||
| +    This is used not to display the upgrade message when pip is in fact
 |  | ||||||
| +    installed by system package manager, such as dnf on Fedora.
 |  | ||||||
| +    """
 |  | ||||||
| +    import pkg_resources
 |  | ||||||
| +    try:
 |  | ||||||
| +        dist = pkg_resources.get_distribution('pip')
 |  | ||||||
| +        return (dist.has_metadata('INSTALLER') and
 |  | ||||||
| +                'pip' in dist.get_metadata_lines('INSTALLER'))
 |  | ||||||
| +    except pkg_resources.DistributionNotFound:
 |  | ||||||
| +        return False
 |  | ||||||
| +
 |  | ||||||
| +
 |  | ||||||
|  def pip_version_check(session): |  | ||||||
|      """Check for an update for pip. |  | ||||||
|   |  | ||||||
| @@ -141,7 +156,8 @@ def pip_version_check(session):
 |  | ||||||
|   |  | ||||||
|          # Determine if our pypi_version is older |  | ||||||
|          if (pip_version < remote_version and |  | ||||||
| -                pip_version.base_version != remote_version.base_version):
 |  | ||||||
| +                pip_version.base_version != remote_version.base_version and
 |  | ||||||
| +                pip_installed_by_pip()):
 |  | ||||||
|              # Advise "python -m pip" on Windows to avoid issues |  | ||||||
|              # with overwriting pip.exe. |  | ||||||
|              if WINDOWS: |  | ||||||
| @ -1,85 +1,126 @@ | |||||||
| diff --git a/pip/req/req_install.py b/pip/req/req_install.py
 | From f5c7cdc676e6884580fde4689a296ff50a9847a5 Mon Sep 17 00:00:00 2001 | ||||||
| index 6911fba..8524932 100644
 | From: Lumir Balhar <lbalhar@redhat.com> | ||||||
| --- a/pip/req/req_install.py
 | Date: Wed, 20 Mar 2024 13:43:12 +0100 | ||||||
| +++ b/pip/req/req_install.py
 | Subject: [PATCH] Prevent removing of the system packages installed under | ||||||
| @@ -34,7 +34,7 @@ from pip.locations import (
 |  /usr/lib when pip install -U is executed. | ||||||
|  ) | MIME-Version: 1.0 | ||||||
|  from pip.utils import ( | Content-Type: text/plain; charset=UTF-8 | ||||||
|      display_path, rmtree, ask_path_exists, backup_dir, is_installable_dir, | Content-Transfer-Encoding: 8bit | ||||||
| -    dist_in_usersite, dist_in_site_packages, egg_link_path,
 | 
 | ||||||
| +    dist_in_usersite, dist_in_site_packages, dist_in_install_path, egg_link_path,
 | Resolves: rhbz#1550368 | ||||||
|      call_subprocess, read_text_file, FakeFile, _make_build_dir, ensure_dir, | 
 | ||||||
|      get_installed_version, normalize_path, dist_is_local, | Co-Authored-By: Michal Cyprian <m.cyprian@gmail.com> | ||||||
|  ) | Co-Authored-By: Victor Stinner <vstinner@redhat.com> | ||||||
| @@ -1049,7 +1049,7 @@ class InstallRequirement(object):
 | Co-Authored-By: Petr Viktorin <pviktori@redhat.com> | ||||||
|                          "lack sys.path precedence to %s in %s" % | Co-Authored-By: Lumir Balhar <lbalhar@redhat.com> | ||||||
|                          (existing_dist.project_name, existing_dist.location) | Co-Authored-By: Miro Hrončok <miro@hroncok.cz> | ||||||
|  | ---
 | ||||||
|  |  src/pip/_internal/req/req_install.py               |  3 ++- | ||||||
|  |  src/pip/_internal/resolution/legacy/resolver.py    |  5 ++++- | ||||||
|  |  src/pip/_internal/resolution/resolvelib/factory.py | 10 ++++++++++ | ||||||
|  |  src/pip/_internal/utils/misc.py                    | 11 +++++++++++ | ||||||
|  |  4 files changed, 27 insertions(+), 2 deletions(-) | ||||||
|  | 
 | ||||||
|  | diff --git a/src/pip/_internal/req/req_install.py b/src/pip/_internal/req/req_install.py
 | ||||||
|  | index 95dacab..b9679fa 100644
 | ||||||
|  | --- a/src/pip/_internal/req/req_install.py
 | ||||||
|  | +++ b/src/pip/_internal/req/req_install.py
 | ||||||
|  | @@ -47,6 +47,7 @@ from pip._internal.utils.misc import (
 | ||||||
|  |      ask_path_exists, | ||||||
|  |      backup_dir, | ||||||
|  |      display_path, | ||||||
|  | +    dist_in_install_path,
 | ||||||
|  |      dist_in_site_packages, | ||||||
|  |      dist_in_usersite, | ||||||
|  |      get_distribution, | ||||||
|  | @@ -442,7 +443,7 @@ class InstallRequirement:
 | ||||||
|  |                              existing_dist.project_name, existing_dist.location | ||||||
|  |                          ) | ||||||
|                      ) |                      ) | ||||||
| -            else:
 | -            else:
 | ||||||
| +            elif dist_in_install_path(existing_dist):
 | +            elif dist_in_install_path(existing_dist):
 | ||||||
|                  self.conflicts_with = existing_dist |                  self.should_reinstall = True | ||||||
|          return True |          else: | ||||||
|  |              if self.editable: | ||||||
|  | diff --git a/src/pip/_internal/resolution/legacy/resolver.py b/src/pip/_internal/resolution/legacy/resolver.py
 | ||||||
|  | index 09caaa6..c1542ec 100644
 | ||||||
|  | --- a/src/pip/_internal/resolution/legacy/resolver.py
 | ||||||
|  | +++ b/src/pip/_internal/resolution/legacy/resolver.py
 | ||||||
|  | @@ -44,6 +44,7 @@ from pip._internal.resolution.base import BaseResolver, InstallRequirementProvid
 | ||||||
|  |  from pip._internal.utils.compatibility_tags import get_supported | ||||||
|  |  from pip._internal.utils.logging import indent_log | ||||||
|  |  from pip._internal.utils.misc import dist_in_usersite, normalize_version_info | ||||||
|  | +from pip._internal.utils.misc import dist_in_install_path
 | ||||||
|  |  from pip._internal.utils.packaging import check_requires_python | ||||||
|   |   | ||||||
| diff --git a/pip/req/req_set.py b/pip/req/req_set.py
 |  logger = logging.getLogger(__name__) | ||||||
| index 76aec06..b93304a 100644
 | @@ -203,7 +204,9 @@ class Resolver(BaseResolver):
 | ||||||
| --- a/pip/req/req_set.py
 |          """ | ||||||
| +++ b/pip/req/req_set.py
 |          # Don't uninstall the conflict if doing a user install and the | ||||||
| @@ -18,7 +18,8 @@ from pip.exceptions import (InstallationError, BestVersionAlreadyInstalled,
 |          # conflict is not a user install. | ||||||
|                              UnsupportedPythonVersion) | -        if not self.use_user_site or dist_in_usersite(req.satisfied_by):
 | ||||||
|  from pip.req.req_install import InstallRequirement | +        if ((not self.use_user_site
 | ||||||
|  from pip.utils import ( | +                or dist_in_usersite(req.satisfied_by))
 | ||||||
| -    display_path, dist_in_usersite, ensure_dir, normalize_path)
 | +                and dist_in_install_path(req.satisfied_by)):
 | ||||||
| +    display_path, dist_in_usersite, dist_in_install_path, ensure_dir,
 |              req.should_reinstall = True | ||||||
| +    normalize_path)
 |          req.satisfied_by = None | ||||||
|  from pip.utils.hashes import MissingHashes |  | ||||||
|  from pip.utils.logging import indent_log |  | ||||||
|  from pip.utils.packaging import check_dist_requires_python |  | ||||||
| @@ -437,10 +438,12 @@ class RequirementSet(object):
 |  | ||||||
|   |   | ||||||
|                  if not best_installed: | diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py
 | ||||||
|                      # don't uninstall conflict if user install and | index 766dc26..baf61ba 100644
 | ||||||
| -                    # conflict is not user install
 | --- a/src/pip/_internal/resolution/resolvelib/factory.py
 | ||||||
| +                    # conflict is not user install or conflict lives
 | +++ b/src/pip/_internal/resolution/resolvelib/factory.py
 | ||||||
| +                    # in a different path (/usr/lib vs /usr/local/lib/)
 | @@ -1,6 +1,7 @@
 | ||||||
|                      if not (self.use_user_site and not |  import contextlib | ||||||
| -                            dist_in_usersite(req_to_install.satisfied_by)):
 |  import functools | ||||||
| -                        req_to_install.conflicts_with = \
 |  import logging | ||||||
| +                            dist_in_usersite(req_to_install.satisfied_by) or not
 | +import sys
 | ||||||
| +                            dist_in_install_path(req_to_install.satisfied_by)):
 |  from typing import ( | ||||||
| +                        req_to_install.conflicts_with = \
 |      TYPE_CHECKING, | ||||||
|                              req_to_install.satisfied_by |      Dict, | ||||||
|                      req_to_install.satisfied_by = None | @@ -33,6 +34,7 @@ from pip._internal.exceptions import (
 | ||||||
|   |      UnsupportedWheel, | ||||||
| @@ -644,10 +647,12 @@ class RequirementSet(object):
 |  | ||||||
|                  if req_to_install.satisfied_by: |  | ||||||
|                      if self.upgrade or self.ignore_installed: |  | ||||||
|                          # don't uninstall conflict if user install and |  | ||||||
| -                        # conflict is not user install
 |  | ||||||
| +                        # conflict is not user install or conflict lives
 |  | ||||||
| +                        # in a different path (/usr/lib vs /usr/local/lib/)
 |  | ||||||
|                          if not (self.use_user_site and not |  | ||||||
|                                  dist_in_usersite( |  | ||||||
| -                                    req_to_install.satisfied_by)):
 |  | ||||||
| +                                    req_to_install.satisfied_by) or not
 |  | ||||||
| +                                dist_in_install_path(req_to_install.satisfied_by)):
 |  | ||||||
|                              req_to_install.conflicts_with = \ |  | ||||||
|                                  req_to_install.satisfied_by |  | ||||||
|                          req_to_install.satisfied_by = None |  | ||||||
| diff --git a/pip/utils/__init__.py b/pip/utils/__init__.py
 |  | ||||||
| index 815bd33..0ed59f7 100644
 |  | ||||||
| --- a/pip/utils/__init__.py
 |  | ||||||
| +++ b/pip/utils/__init__.py
 |  | ||||||
| @@ -22,7 +22,7 @@ from pip.exceptions import InstallationError
 |  | ||||||
|  from pip.compat import console_to_str, expanduser, stdlib_pkgs |  | ||||||
|  from pip.locations import ( |  | ||||||
|      site_packages, user_site, running_under_virtualenv, virtualenv_no_global, |  | ||||||
| -    write_delete_marker_file,
 |  | ||||||
| +    write_delete_marker_file, distutils_scheme,
 |  | ||||||
|  ) |  ) | ||||||
|  from pip._vendor import pkg_resources |  from pip._internal.index.package_finder import PackageFinder | ||||||
|  from pip._vendor.six.moves import input | +from pip._internal.locations import get_scheme
 | ||||||
| @@ -315,6 +315,16 @@ def dist_in_site_packages(dist):
 |  from pip._internal.metadata import BaseDistribution, get_default_environment | ||||||
|      ).startswith(normalize_path(site_packages)) |  from pip._internal.models.link import Link | ||||||
|  |  from pip._internal.models.wheel import Wheel | ||||||
|  | @@ -45,6 +47,7 @@ from pip._internal.req.req_install import (
 | ||||||
|  |  from pip._internal.resolution.base import InstallRequirementProvider | ||||||
|  |  from pip._internal.utils.compatibility_tags import get_supported | ||||||
|  |  from pip._internal.utils.hashes import Hashes | ||||||
|  | +from pip._internal.utils.misc import dist_location
 | ||||||
|  |  from pip._internal.utils.packaging import get_requirement | ||||||
|  |  from pip._internal.utils.virtualenv import running_under_virtualenv | ||||||
|  |   | ||||||
|  | @@ -526,6 +529,13 @@ class Factory:
 | ||||||
|  |          if dist is None:  # Not installed, no uninstallation required. | ||||||
|  |              return None | ||||||
|  |   | ||||||
|  | +        # Prevent uninstalling packages from /usr
 | ||||||
|  | +        if dist_location(dist._dist) in (
 | ||||||
|  | +                get_scheme('', prefix=sys.base_prefix).purelib,
 | ||||||
|  | +                get_scheme('', prefix=sys.base_prefix).platlib,
 | ||||||
|  | +            ):
 | ||||||
|  | +            return None
 | ||||||
|  | +
 | ||||||
|  |          # We're installing into global site. The current installation must | ||||||
|  |          # be uninstalled, no matter it's in global or user site, because the | ||||||
|  |          # user site installation has precedence over global. | ||||||
|  | diff --git a/src/pip/_internal/utils/misc.py b/src/pip/_internal/utils/misc.py
 | ||||||
|  | index d3e9053..d25d1c3 100644
 | ||||||
|  | --- a/src/pip/_internal/utils/misc.py
 | ||||||
|  | +++ b/src/pip/_internal/utils/misc.py
 | ||||||
|  | @@ -38,6 +38,7 @@ from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed
 | ||||||
|  |  from pip import __version__ | ||||||
|  |  from pip._internal.exceptions import CommandError | ||||||
|  |  from pip._internal.locations import get_major_minor_version, site_packages, user_site | ||||||
|  | +from pip._internal.locations import get_scheme
 | ||||||
|  |  from pip._internal.utils.compat import WINDOWS | ||||||
|  |  from pip._internal.utils.egg_link import egg_link_path_from_location | ||||||
|  |  from pip._internal.utils.virtualenv import running_under_virtualenv | ||||||
|  | @@ -354,6 +355,16 @@ def dist_in_site_packages(dist: Distribution) -> bool:
 | ||||||
|  |      return dist_location(dist).startswith(normalize_path(site_packages)) | ||||||
|   |   | ||||||
|   |   | ||||||
| +def dist_in_install_path(dist):
 | +def dist_in_install_path(dist):
 | ||||||
| @ -89,9 +130,12 @@ index 815bd33..0ed59f7 100644 | |||||||
| +    """
 | +    """
 | ||||||
| +    norm_path = normalize_path(dist_location(dist))
 | +    norm_path = normalize_path(dist_location(dist))
 | ||||||
| +    return norm_path.startswith(normalize_path(
 | +    return norm_path.startswith(normalize_path(
 | ||||||
| +        distutils_scheme("")['purelib'].split('python')[0]))
 | +        get_scheme("").purelib.split('python')[0]))
 | ||||||
| +
 | +
 | ||||||
| +
 | +
 | ||||||
|  def dist_is_editable(dist): |  def get_distribution(req_name: str) -> Optional[Distribution]: | ||||||
|      """Is distribution an editable install?""" |      """Given a requirement name, return the installed Distribution object. | ||||||
|      for path_item in sys.path: |   | ||||||
|  | -- 
 | ||||||
|  | 2.44.0 | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -1,91 +0,0 @@ | |||||||
| From b97ef609100fbdd5895dab48cdab578dfeba396c Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lumir Balhar <lbalhar@redhat.com> |  | ||||||
| Date: Fri, 10 Sep 2021 13:38:40 +0200 |  | ||||||
| Subject: [PATCH 1/2] Implement handling of yanked_reason from the HTML anchor |  | ||||||
| 
 |  | ||||||
| ---
 |  | ||||||
|  pip/index.py | 10 ++++++++-- |  | ||||||
|  1 file changed, 8 insertions(+), 2 deletions(-) |  | ||||||
| 
 |  | ||||||
| diff --git a/pip/index.py b/pip/index.py
 |  | ||||||
| index f653f6e6a..ced52ce5a 100644
 |  | ||||||
| --- a/pip/index.py
 |  | ||||||
| +++ b/pip/index.py
 |  | ||||||
| @@ -865,7 +865,11 @@ class HTMLPage(object):
 |  | ||||||
|                  ) |  | ||||||
|                  pyrequire = anchor.get('data-requires-python') |  | ||||||
|                  pyrequire = unescape(pyrequire) if pyrequire else None |  | ||||||
| -                yield Link(url, self, requires_python=pyrequire)
 |  | ||||||
| +                yanked_reason = anchor.get('data-yanked', default=None)
 |  | ||||||
| +                # Empty or valueless attribute are both parsed as empty string
 |  | ||||||
| +                if yanked_reason is not None:
 |  | ||||||
| +                    yanked_reason = unescape(yanked_reason)
 |  | ||||||
| +                yield Link(url, self, requires_python=pyrequire, yanked_reason=yanked_reason)
 |  | ||||||
|   |  | ||||||
|      _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) |  | ||||||
|   |  | ||||||
| @@ -879,7 +883,7 @@ class HTMLPage(object):
 |  | ||||||
|   |  | ||||||
|  class Link(object): |  | ||||||
|   |  | ||||||
| -    def __init__(self, url, comes_from=None, requires_python=None):
 |  | ||||||
| +    def __init__(self, url, comes_from=None, requires_python=None, yanked_reason=None):
 |  | ||||||
|          """ |  | ||||||
|          Object representing a parsed link from https://pypi.python.org/simple/* |  | ||||||
|   |  | ||||||
| @@ -900,6 +904,8 @@ class Link(object):
 |  | ||||||
|          self.url = url |  | ||||||
|          self.comes_from = comes_from |  | ||||||
|          self.requires_python = requires_python if requires_python else None |  | ||||||
| +        self.yanked_reason = yanked_reason
 |  | ||||||
| +        self.yanked = yanked_reason is not None
 |  | ||||||
|   |  | ||||||
|      def __str__(self): |  | ||||||
|          if self.requires_python: |  | ||||||
| -- 
 |  | ||||||
| 2.31.1 |  | ||||||
| 
 |  | ||||||
| From d8dc6ee5d6809736dce43dc1e57d497f9ff91f26 Mon Sep 17 00:00:00 2001 |  | ||||||
| From: Lumir Balhar <lbalhar@redhat.com> |  | ||||||
| Date: Fri, 10 Sep 2021 13:43:22 +0200 |  | ||||||
| Subject: [PATCH 2/2] Skip all yanked candidates if possible |  | ||||||
| 
 |  | ||||||
| ---
 |  | ||||||
|  pip/index.py | 21 +++++++++++++++++++++ |  | ||||||
|  1 file changed, 21 insertions(+) |  | ||||||
| 
 |  | ||||||
| diff --git a/pip/index.py b/pip/index.py
 |  | ||||||
| index ced52ce5a..823bbaf7d 100644
 |  | ||||||
| --- a/pip/index.py
 |  | ||||||
| +++ b/pip/index.py
 |  | ||||||
| @@ -489,6 +489,27 @@ class PackageFinder(object):
 |  | ||||||
|          if applicable_candidates: |  | ||||||
|              best_candidate = max(applicable_candidates, |  | ||||||
|                                   key=self._candidate_sort_key) |  | ||||||
| +            # If we cannot find a non-yanked candidate,
 |  | ||||||
| +            # use the best one and print a warning about it.
 |  | ||||||
| +            # Otherwise, try to find another best candidate, ignoring
 |  | ||||||
| +            # all the yanked releases.
 |  | ||||||
| +            if getattr(best_candidate.location, "yanked", False):
 |  | ||||||
| +                nonyanked_candidates = [
 |  | ||||||
| +                    c for c in applicable_candidates
 |  | ||||||
| +                    if not getattr(c.location, "yanked", False)
 |  | ||||||
| +                ]
 |  | ||||||
| +
 |  | ||||||
| +                if set(nonyanked_candidates):
 |  | ||||||
| +                    best_candidate = max(nonyanked_candidates,
 |  | ||||||
| +                                         key=self._candidate_sort_key)
 |  | ||||||
| +                else:
 |  | ||||||
| +                    warning_message = (
 |  | ||||||
| +                        "WARNING: The candidate selected for download or install "
 |  | ||||||
| +                        "is a yanked version: '{}' candidate (version {} at {})"
 |  | ||||||
| +                    ).format(best_candidate.project, best_candidate.version, best_candidate.location)
 |  | ||||||
| +                    if best_candidate.location.yanked_reason:
 |  | ||||||
| +                        warning_message += "\nReason for being yanked: {}".format(best_candidate.location.yanked_reason)
 |  | ||||||
| +                    logger.warning(warning_message)
 |  | ||||||
|          else: |  | ||||||
|              best_candidate = None |  | ||||||
|   |  | ||||||
| -- 
 |  | ||||||
| 2.31.1 |  | ||||||
| 
 |  | ||||||
| @ -1,491 +1,642 @@ | |||||||
| %bcond_with bootstrap | # The original RHEL 9 content set is defined by (build)dependencies | ||||||
|  | # of the packages in Fedora ELN. Hence we disable tests and documentation here | ||||||
|  | # to prevent pulling many unwanted packages in. | ||||||
|  | # Once the RHEL 9 content set is defined and/or RHEL 9 forks from ELN, | ||||||
|  | # the conditional can be removed from the Fedora spec file. | ||||||
|  | # We intentionally keep this enabled on EPEL. | ||||||
|  | %if 0%{?rhel} >= 9 && !0%{?epel} | ||||||
| %bcond_with tests | %bcond_with tests | ||||||
| 
 | %bcond_with doc | ||||||
|  | %else | ||||||
|  | %bcond_without tests | ||||||
| %bcond_without doc | %bcond_without doc | ||||||
| 
 |  | ||||||
| %global srcname pip |  | ||||||
| %global python3_wheelname %{srcname}-%{version}-py2.py3-none-any.whl |  | ||||||
| %if %{without bootstrap} |  | ||||||
| %global python3_wheeldir %{_datadir}/python3-wheels |  | ||||||
| %endif | %endif | ||||||
| 
 | 
 | ||||||
| %global bashcompdir %(b=$(pkg-config --variable=completionsdir bash-completion 2>/dev/null); echo ${b:-%{_sysconfdir}/bash_completion.d}) | %global srcname pip | ||||||
|  | %global base_version 21.3.1 | ||||||
|  | %global upstream_version %{base_version}%{?prerel} | ||||||
|  | %global python_wheel_name %{srcname}-%{upstream_version}-py3-none-any.whl | ||||||
|  | 
 | ||||||
|  | %global bashcompdir %(pkg-config --variable=completionsdir bash-completion 2>/dev/null) | ||||||
| 
 | 
 | ||||||
| Name:           python-%{srcname} | Name:           python-%{srcname} | ||||||
| # When updating, update the bundled libraries versions bellow! | Version:        %{base_version}%{?prerel:~%{prerel}} | ||||||
| Version:        9.0.3 | Release:        1%{?dist} | ||||||
| Release:        24%{?dist} |  | ||||||
| Summary:        A tool for installing and managing Python packages | Summary:        A tool for installing and managing Python packages | ||||||
| 
 | 
 | ||||||
| Group:          Development/Libraries |  | ||||||
| 
 |  | ||||||
| # 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. | ||||||
| # Here is the list of the libraries with corresponding licenses: | # Here is the list of the libraries with corresponding licenses: | ||||||
| 
 | 
 | ||||||
| # appdirs: MIT | # appdirs: MIT | ||||||
| # CacheControl: ASL 2.0 |  | ||||||
| # certifi: MPLv2.0 | # certifi: MPLv2.0 | ||||||
| # chardet: LGPLv2 | # chardet: LGPLv2 | ||||||
| # colorama: BSD | # colorama: BSD | ||||||
|  | # CacheControl: ASL 2.0 | ||||||
| # distlib: Python | # distlib: Python | ||||||
| # distro: ASL 2.0 | # distro: ASL 2.0 | ||||||
| # html5lib: MIT | # html5lib: MIT | ||||||
| # idna: BSD | # idna: BSD | ||||||
| # ipaddress: Python | # ipaddress: Python | ||||||
| # lockfile: MIT | # msgpack: ASL 2.0 | ||||||
| # packaging: ASL 2.0 or BSD | # packaging: ASL 2.0 or BSD | ||||||
|  | # pep517: MIT | ||||||
| # progress: ISC | # progress: ISC | ||||||
| # pyparsing: MIT | # pyparsing: MIT | ||||||
| # requests: ASL 2.0 | # requests: ASL 2.0 | ||||||
| # retrying: ASL 2.0 | # resolvelib: ISC | ||||||
| # urllib3: MIT | # setuptools: MIT | ||||||
| # six: MIT | # six: MIT | ||||||
|  | # tenacity: ASL 2.0 | ||||||
|  | # tomli: MIT | ||||||
| # urllib3: MIT | # urllib3: MIT | ||||||
| # webencodings: BSD | # webencodings: BSD | ||||||
| 
 | 
 | ||||||
| License:        MIT and Python and ASL 2.0 and BSD and ISC and LGPLv2 and MPLv2.0 and (ASL 2.0 or BSD) | License:        MIT and Python and ASL 2.0 and BSD and ISC and LGPLv2 and MPLv2.0 and (ASL 2.0 or BSD) | ||||||
| URL:            http://www.pip-installer.org | URL:            https://pip.pypa.io/ | ||||||
| Source0:        https://files.pythonhosted.org/packages/source/p/%{srcname}/%{srcname}-%{version}.tar.gz | Source0:        https://github.com/pypa/pip/archive/%{upstream_version}/%{srcname}-%{upstream_version}.tar.gz | ||||||
| 
 | 
 | ||||||
| BuildArch:      noarch | BuildArch:      noarch | ||||||
| 
 | 
 | ||||||
| %if %{with tests} | %if %{with tests} | ||||||
| BuildRequires:  git | BuildRequires:  /usr/bin/git | ||||||
| BuildRequires:  bzr | BuildRequires:  /usr/bin/hg | ||||||
|  | BuildRequires:  /usr/bin/bzr | ||||||
|  | BuildRequires:  /usr/bin/svn | ||||||
|  | BuildRequires:  python-setuptools-wheel | ||||||
|  | BuildRequires:  python-wheel-wheel | ||||||
| %endif | %endif | ||||||
| 
 | 
 | ||||||
| # to get tests: |  | ||||||
| # git clone https://github.com/pypa/pip && cd pip |  | ||||||
| # git checkout 9.0.1 && tar -czvf ../pip-9.0.1-tests.tar.gz tests/ |  | ||||||
| %if %{with tests} |  | ||||||
| Source1:        pip-%{version}-tests.tar.gz |  | ||||||
| %endif |  | ||||||
| 
 |  | ||||||
| # Patch until the following issue gets implemented upstream: |  | ||||||
| # https://github.com/pypa/pip/issues/1351 |  | ||||||
| Patch0:         allow-stripping-given-prefix-from-wheel-RECORD-files.patch |  | ||||||
| 
 |  | ||||||
| # Downstream only patch |  | ||||||
| # Emit a warning to the user if pip install is run with root privileges |  | ||||||
| # Issue upstream: https://github.com/pypa/pip/issues/4288 |  | ||||||
| Patch1:         emit-a-warning-when-running-with-root-privileges.patch |  | ||||||
| 
 |  | ||||||
| # Prevent removing of the system packages installed under /usr/lib | # Prevent removing of the system packages installed under /usr/lib | ||||||
| # when pip install -U is executed. | # when pip install -U is executed. | ||||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=1626408 | # https://bugzilla.redhat.com/show_bug.cgi?id=1550368#c24 | ||||||
| # Author: Michal Cyprian | Patch3:         remove-existing-dist-only-if-path-conflicts.patch | ||||||
| Patch2:         remove-existing-dist-only-if-path-conflicts.patch |  | ||||||
| 
 |  | ||||||
| # Do not show the "new version of pip" warning outside of venv |  | ||||||
| # Upstream issue: https://github.com/pypa/pip/issues/5346 |  | ||||||
| # Fedora bug: https://bugzilla.redhat.com/show_bug.cgi?id=1573755 |  | ||||||
| Patch3:         pip-nowarn-upgrade.patch |  | ||||||
| 
 | 
 | ||||||
| # Use the system level root certificate instead of the one bundled in certifi | # Use the system level root certificate instead of the one bundled in certifi | ||||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=1655255 | # https://bugzilla.redhat.com/show_bug.cgi?id=1655253 | ||||||
| Patch4:         dummy-certifi.patch | Patch4:         dummy-certifi.patch | ||||||
| 
 | 
 | ||||||
| # Patch for CVE in the bundled urllib3 | # Don't warn the user about pip._internal.main() entrypoint | ||||||
| # CVE-2018-20060 Cross-host redirect does not remove Authorization header allow for credential exposure | # In Fedora, we use that in ensurepip and users cannot do anything about it, | ||||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2018-20060 | # this warning is juts moot. Also, the warning breaks CPython test suite. | ||||||
| Patch5:         CVE-2018-20060.patch | Patch5:         nowarn-pip._internal.main.patch | ||||||
| 
 | 
 | ||||||
| # Patch for CVE in the bundled urllib3 | # Don't warn the user about packaging's LegacyVersion being deprecated. | ||||||
| # CVE-2019-11236 CRLF injection due to not encoding the '\r\n' sequence leading to possible attack on internal service | # (This also breaks Python's test suite when warnings are treated as errors.) | ||||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2019-11236 | # Upstream issue: https://github.com/pypa/packaging/issues/368 | ||||||
| Patch6:         CVE-2019-11236.patch | Patch6:         no-version-warning.patch | ||||||
| 
 |  | ||||||
| # Patch for CVE in the bundled urllib3 |  | ||||||
| # CVE-2019-11324 Certification mishandle when error should be thrown |  | ||||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2019-11324 |  | ||||||
| Patch7:         CVE-2019-11324.patch |  | ||||||
| 
 |  | ||||||
| # Patch for CVE in the bundled requests |  | ||||||
| # CVE-2018-18074 Redirect from HTTPS to HTTP does not remove Authorization header |  | ||||||
| # This patch fixes both the CVE |  | ||||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=1643829 |  | ||||||
| # and the subsequent regression |  | ||||||
| # https://github.com/psf/requests/pull/4851 |  | ||||||
| Patch8:         CVE-2018-18074.patch |  | ||||||
| 
 |  | ||||||
| # Patch for pip install <url> allow directory traversal, leading to arbitrary file write |  | ||||||
| # - Upstream PR: https://github.com/pypa/pip/pull/6418/files |  | ||||||
| # - Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1868016 |  | ||||||
| # Patch9 fixes the issue |  | ||||||
| # Patch10 adds unit tests for the issue |  | ||||||
| Patch9:         pip-directory-traversal-security-issue.patch |  | ||||||
| Patch10:        pip-directory-traversal-security-issue-tests.patch |  | ||||||
| 
 |  | ||||||
| # Patch for CVE-2021-3572 - pip incorrectly handled unicode separators in git references |  | ||||||
| # The patch is adjusted for older pip where it's necessary to also switch |  | ||||||
| # the way pip gets revisions from git |  | ||||||
| # Upstream PR: https://github.com/pypa/pip/pull/9827 |  | ||||||
| # Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1962856 |  | ||||||
| Patch11:        CVE-2021-3572.patch |  | ||||||
| 
 |  | ||||||
| # Downstream-only implementation of support of yanked releases |  | ||||||
| # PEP 592 - Adding "Yank" Support to the Simple API: |  | ||||||
| #   https://www.python.org/dev/peps/pep-0592/ |  | ||||||
| # Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2000135 |  | ||||||
| Patch12:        skip_yanked_releases.patch |  | ||||||
| 
 | 
 | ||||||
| # CVE-2007-4559, PEP-721, PEP-706: Use tarfile.data_filter for extracting | # CVE-2007-4559, PEP-721, PEP-706: Use tarfile.data_filter for extracting | ||||||
| # - Minimal downstream-only patch, to be replaced by upstream solution | # - Minimal downstream-only patch, to be replaced by upstream solution | ||||||
| #   proposed in https://github.com/pypa/pip/pull/12214 | #   proposed in https://github.com/pypa/pip/pull/12214 | ||||||
|  | # - Test patch submitted upstream in the above pull request | ||||||
| # - Patch for vendored distlib, accepted upstream: | # - Patch for vendored distlib, accepted upstream: | ||||||
| #   https://github.com/pypa/distlib/pull/201 | #   https://github.com/pypa/distlib/pull/201 | ||||||
| Patch13:         cve-2007-4559-tarfile.patch | Patch7:         cve-2007-4559-tarfile.patch | ||||||
| 
 | 
 | ||||||
| %global _description \ | # Downstream only patch | ||||||
| pip is a package management system used to install and manage software packages \ | # Users might have local installations of pip from using | ||||||
| written in Python. Many packages can be found in the Python Package Index \ | # `pip install --user --upgrade pip` on older/newer versions. | ||||||
| (PyPI). pip is a recursive acronym that can stand for either "Pip Installs \ | # If they do that and they run `pip` or  `pip3`, the one from /usr/bin is used. | ||||||
|  | # However that's the one from this RPM package and the import in there might | ||||||
|  | # fail (it tries to import from ~/.local, but older or newer pip is there with | ||||||
|  | # a bit different API). | ||||||
|  | # We add this patch as a dirty workaround to make /usr/bin/pip* work with | ||||||
|  | # both pip10+ (from this RPM) and older or newer (19.3+) pip (from whatever). | ||||||
|  | # A proper fix is to put ~/.local/bin in front of /usr/bin in the PATH, | ||||||
|  | # however others are against that and we cannot change it for existing | ||||||
|  | # installs/user homes anyway. | ||||||
|  | # https://bugzilla.redhat.com/show_bug.cgi?id=1569488 | ||||||
|  | # https://bugzilla.redhat.com/show_bug.cgi?id=1571650 | ||||||
|  | # https://bugzilla.redhat.com/show_bug.cgi?id=1767212 | ||||||
|  | # WARNING: /usr/bin/pip* are entrypoints, this cannot be applied in %%prep! | ||||||
|  | # %%patch10 doesn't work outside of %%prep, so we add it as a source | ||||||
|  | # Note that since pip 20, old main() import paths are preserved for backwards | ||||||
|  | # compatibility: https://github.com/pypa/pip/issues/7498 | ||||||
|  | # Meaning we don't need to update any of the older pips to support 20+ | ||||||
|  | # We also don't need to update Pythons to use new import path in ensurepip | ||||||
|  | Source10:        pip-allow-different-versions.patch | ||||||
|  | 
 | ||||||
|  | %description | ||||||
|  | pip is a package management system used to install and manage software packages | ||||||
|  | written in Python. Many packages can be found in the Python Package Index | ||||||
|  | (PyPI). pip is a recursive acronym that can stand for either "Pip Installs | ||||||
| Packages" or "Pip Installs Python". | Packages" or "Pip Installs Python". | ||||||
| 
 | 
 | ||||||
| %description %_description |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| %package -n platform-python-%{srcname} |  | ||||||
| Summary:        A tool for installing and managing Python3 packages |  | ||||||
| Group:          Development/Libraries |  | ||||||
| Conflicts:      python%{python3_pkgversion}-pip < 9.0.3-5%{?dist} |  | ||||||
| Obsoletes:      python%{python3_pkgversion}-pip < 9.0.3-6%{?dist} |  | ||||||
| 
 |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-devel |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-setuptools |  | ||||||
| BuildRequires:  bash-completion |  | ||||||
| %if %{with tests} |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-mock |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-pytest |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-pretend |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-freezegun |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-pytest-capturelog |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-scripttest |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-virtualenv |  | ||||||
| %endif |  | ||||||
| %if %{without bootstrap} |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-pip |  | ||||||
| BuildRequires:  python%{python3_pkgversion}-wheel |  | ||||||
| %endif |  | ||||||
| Requires:  platform-python-setuptools |  | ||||||
| 
 |  | ||||||
| BuildRequires:  ca-certificates |  | ||||||
| Requires:       ca-certificates |  | ||||||
| # pip has to require explicit version of platform-python that provides |  | ||||||
| # filters in tarfile module (fix for CVE-2007-4559). |  | ||||||
| Requires:       platform-python >= 3.6.8-55 |  | ||||||
| 
 |  | ||||||
| # Virtual provides for the packages bundled by pip. | # Virtual provides for the packages bundled by pip. | ||||||
| # See the python2 list above for instructions. | # You can generate it with: | ||||||
| Provides: bundled(python3dist(appdirs)) = 1.4.0 | # %%{_rpmconfigdir}/pythonbundles.py --namespace 'python%%{1}dist' src/pip/_vendor/vendor.txt | ||||||
| Provides: bundled(python3dist(cachecontrol)) = 0.11.7 | %global bundled() %{expand: | ||||||
| Provides: bundled(python3dist(colorama)) = 0.3.7 | Provides: bundled(python%{1}dist(cachecontrol)) = 0.12.6 | ||||||
| Provides: bundled(python3dist(distlib)) = 0.2.4 | Provides: bundled(python%{1}dist(certifi)) = 2021.5.30 | ||||||
| Provides: bundled(python3dist(distro)) = 1.0.1 | Provides: bundled(python%{1}dist(chardet)) = 4 | ||||||
| Provides: bundled(python3dist(html5lib)) = 1.0b10 | Provides: bundled(python%{1}dist(colorama)) = 0.4.4 | ||||||
| Provides: bundled(python3dist(ipaddress) = 1.0.17 | Provides: bundled(python%{1}dist(distlib)) = 0.3.3 | ||||||
| Provides: bundled(python3dist(lockfile)) = 0.12.2 | Provides: bundled(python%{1}dist(distro)) = 1.6 | ||||||
| Provides: bundled(python3dist(packaging)) = 16.8 | Provides: bundled(python%{1}dist(html5lib)) = 1.1 | ||||||
| Provides: bundled(python3dist(setuptools)) = 28.8.0 | Provides: bundled(python%{1}dist(idna)) = 3.2 | ||||||
| Provides: bundled(python3dist(progress)) = 1.2 | Provides: bundled(python%{1}dist(msgpack)) = 1.0.2 | ||||||
| Provides: bundled(python3dist(pyparsing)) = 2.1.10 | Provides: bundled(python%{1}dist(packaging)) = 21 | ||||||
| Provides: bundled(python3dist(requests)) = 2.11.1 | Provides: bundled(python%{1}dist(pep517)) = 0.12 | ||||||
| Provides: bundled(python3dist(retrying)) = 1.3.3 | Provides: bundled(python%{1}dist(platformdirs)) = 2.4 | ||||||
| Provides: bundled(python3dist(six)) = 1.10.0 | Provides: bundled(python%{1}dist(progress)) = 1.6 | ||||||
| Provides: bundled(python3dist(webencodings)) = 0.5 | Provides: bundled(python%{1}dist(pyparsing)) = 2.4.7 | ||||||
|  | Provides: bundled(python%{1}dist(requests)) = 2.26 | ||||||
|  | Provides: bundled(python%{1}dist(resolvelib)) = 0.8 | ||||||
|  | Provides: bundled(python%{1}dist(setuptools)) = 44 | ||||||
|  | Provides: bundled(python%{1}dist(six)) = 1.16 | ||||||
|  | Provides: bundled(python%{1}dist(tenacity)) = 8.0.1 | ||||||
|  | Provides: bundled(python%{1}dist(tomli)) = 1.0.3 | ||||||
|  | Provides: bundled(python%{1}dist(urllib3)) = 1.26.7 | ||||||
|  | Provides: bundled(python%{1}dist(webencodings)) = 0.5.1 | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| # Bundled within the requests bundle | # Some manylinux1 wheels need libcrypt.so.1. | ||||||
| Provides: bundled(python3dist(chardet)) = 2.3.0 | # Manylinux1, a common (as of 2019) platform tag for binary wheels, relies | ||||||
| Provides: bundled(python3dist(urllib3)) = 1.16 | # on a glibc version that included ancient crypto functions, which were | ||||||
|  | # moved to libxcrypt and then removed in: | ||||||
|  | #  https://fedoraproject.org/wiki/Changes/FullyRemoveDeprecatedAndUnsafeFunctionsFromLibcrypt | ||||||
|  | # The manylinux1 standard assumed glibc would keep ABI compatibility, | ||||||
|  | # but that's only the case if libcrypt.so.1 (libxcrypt-compat) is around. | ||||||
|  | # This should be solved in the next manylinux standard (but it may be | ||||||
|  | # a long time until manylinux1 is phased out). | ||||||
|  | # See: https://github.com/pypa/manylinux/issues/305 | ||||||
|  | # Note that manylinux is only applicable to x86 (both 32 and 64 bits) | ||||||
|  | %global crypt_compat_recommends() %{expand: | ||||||
|  | Recommends: (libcrypt.so.1()(64bit) if python%{1}(x86-64)) | ||||||
|  | Recommends: (libcrypt.so.1 if python%{1}(x86-32)) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| %description -n platform-python-%{srcname} %_description |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| %package -n python%{python3_pkgversion}-%{srcname} | %package -n python%{python3_pkgversion}-%{srcname} | ||||||
| Summary:        A tool for installing and managing Python3 packages | Summary:        A tool for installing and managing Python3 packages | ||||||
| Group:          Development/Libraries |  | ||||||
| 
 | 
 | ||||||
| Requires:       platform-python-pip = %{version}-%{release} | BuildRequires:  python%{python3_pkgversion}-devel | ||||||
| Requires:       python36 | # python3 bootstrap: this is rebuilt before the final build of python3, which | ||||||
| %{?python_provide:%python_provide python%{python3_pkgversion}-%{srcname}} | # adds the dependency on python3-rpm-generators, so we require it manually | ||||||
|  | # Note that the package prefix is always python3-, even if we build for 3.X | ||||||
|  | # The minimal version is for bundled provides verification script | ||||||
|  | BuildRequires:  python3-rpm-generators >= 11-8 | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-setuptools | ||||||
|  | BuildRequires:  bash-completion | ||||||
|  | %if %{with tests} | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-cryptography | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-mock | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-pytest | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-pretend | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-freezegun | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-scripttest | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-virtualenv | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-werkzeug | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-pyyaml | ||||||
|  | %endif | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-wheel | ||||||
|  | BuildRequires:  ca-certificates | ||||||
|  | Requires:       ca-certificates | ||||||
| 
 | 
 | ||||||
| %description -n python%{python3_pkgversion}-%{srcname} %_description | # pip has to require explicit version of python3 that provides | ||||||
|  | # filters in tarfile module (fix for CVE-2007-4559). | ||||||
|  | Requires:       python3 >= 3.9.17-2 | ||||||
| 
 | 
 | ||||||
|  | # This was previously required and we keep it recommended because a lot of | ||||||
|  | # sdists installed via pip will try to import setuptools. | ||||||
|  | # But pip doesn't actually require setuptools. | ||||||
|  | # It can install wheels without them and it can build wheels in isolation mode | ||||||
|  | # (using setuptools/flit/poetry/... installed from PyPI). | ||||||
|  | # Side note: pip bundles pkg_resources from setuptools for internal usage. | ||||||
|  | Recommends:     python%{python3_pkgversion}-setuptools | ||||||
|  | 
 | ||||||
|  | # Virtual provides for the packages bundled by pip: | ||||||
|  | %{bundled 3} | ||||||
|  | 
 | ||||||
|  | Provides:       pip = %{version}-%{release} | ||||||
|  | Conflicts:      python-pip < %{version}-%{release} | ||||||
|  | 
 | ||||||
|  | %{crypt_compat_recommends 3} | ||||||
|  | 
 | ||||||
|  | # Provide platform-python-pip for backwards compatibility with RHEL 8 | ||||||
|  | Provides:       platform-python-pip = %{version}-%{release} | ||||||
|  | 
 | ||||||
|  | %description -n python%{python3_pkgversion}-%{srcname} | ||||||
|  | pip is a package management system used to install and manage software packages | ||||||
|  | written in Python. Many packages can be found in the Python Package Index | ||||||
|  | (PyPI). pip is a recursive acronym that can stand for either "Pip Installs | ||||||
|  | Packages" or "Pip Installs Python". | ||||||
| 
 | 
 | ||||||
| %if %{with doc} | %if %{with doc} | ||||||
| %package doc | %package doc | ||||||
| Summary:        A documentation for a tool for installing and managing Python packages | Summary:        A documentation for a tool for installing and managing Python packages | ||||||
| 
 | 
 | ||||||
| BuildRequires:  python%{python3_pkgversion}-sphinx | BuildRequires:  python%{python3_pkgversion}-sphinx | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-sphinx-inline-tabs | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-sphinx-copybutton | ||||||
|  | BuildRequires:  python%{python3_pkgversion}-myst-parser | ||||||
| 
 | 
 | ||||||
| %description doc | %description doc | ||||||
| A documentation for a tool for installing and managing Python packages | A documentation for a tool for installing and managing Python packages | ||||||
| 
 | 
 | ||||||
| %endif | %endif | ||||||
| 
 | 
 | ||||||
| %if %{without bootstrap} | %package -n     %{python_wheel_pkg_prefix}-%{srcname}-wheel | ||||||
| %package -n python3-%{srcname}-wheel |  | ||||||
| Summary:        The pip wheel | Summary:        The pip wheel | ||||||
| # Older Python does not provide tarfile filters (fix for CVE-2007-4559). | Requires:       ca-certificates | ||||||
| Conflicts:      platform-python < 3.6.8-55 | Provides:       %{name}-wheel = %{version}-%{release} | ||||||
|  | Obsoletes:      %{name}-wheel < %{version}-%{release} | ||||||
| 
 | 
 | ||||||
| # Virtual provides for the packages bundled by pip. | # Older versions of python3-libs (< 3.9.9-2) expect Python wheels at the old unversioned | ||||||
| # You can find the versions in pip/_vendor/vendor.txt file. | # location, so we conflict with the old Python versions that wouldn't work with | ||||||
| Provides: bundled(python3dist(appdirs)) = 1.4.0 | # the new wheel location. | ||||||
| Provides: bundled(python3dist(cachecontrol)) = 0.11.7 | # Moreover, Python older than (3.9.16-2) does not provide tarfile filters (fix for CVE-2007-4559). | ||||||
| Provides: bundled(python3dist(colorama)) = 0.3.7 | Conflicts:      python3-libs < 3.9.17-2 | ||||||
| Provides: bundled(python3dist(distlib)) = 0.2.4 |  | ||||||
| Provides: bundled(python3dist(distro)) = 1.0.1 |  | ||||||
| Provides: bundled(python3dist(html5lib)) = 1.0b10 |  | ||||||
| Provides: bundled(python3dist(ipaddress) = 1.0.17 |  | ||||||
| Provides: bundled(python3dist(lockfile)) = 0.12.2 |  | ||||||
| Provides: bundled(python3dist(packaging)) = 16.8 |  | ||||||
| Provides: bundled(python3dist(setuptools)) = 28.8.0 |  | ||||||
| Provides: bundled(python3dist(progress)) = 1.2 |  | ||||||
| Provides: bundled(python3dist(pyparsing)) = 2.1.10 |  | ||||||
| Provides: bundled(python3dist(requests)) = 2.11.1 |  | ||||||
| Provides: bundled(python3dist(retrying)) = 1.3.3 |  | ||||||
| Provides: bundled(python3dist(six)) = 1.10.0 |  | ||||||
| Provides: bundled(python3dist(webencodings)) = 0.5 |  | ||||||
| 
 | 
 | ||||||
| # Bundled within the requests bundle | # Virtual provides for the packages bundled by pip: | ||||||
| Provides: bundled(python3dist(chardet)) = 2.3.0 | %{bundled 3} | ||||||
| Provides: bundled(python3dist(urllib3)) = 1.16 |  | ||||||
| 
 | 
 | ||||||
| %description -n python3-%{srcname}-wheel | %{crypt_compat_recommends 3} | ||||||
|  | 
 | ||||||
|  | %description -n %{python_wheel_pkg_prefix}-%{srcname}-wheel | ||||||
| A Python wheel of pip to use with venv. | A Python wheel of pip to use with venv. | ||||||
| %endif |  | ||||||
| 
 | 
 | ||||||
| %prep | %prep | ||||||
| %setup -q -n %{srcname}-%{version} | %autosetup -p1 -n %{srcname}-%{upstream_version} | ||||||
| 
 |  | ||||||
| %if %{with tests} |  | ||||||
| tar -xf %{SOURCE1} |  | ||||||
| %endif |  | ||||||
| 
 |  | ||||||
| %patch0 -p1 |  | ||||||
| %patch1 -p1 |  | ||||||
| %patch2 -p1 |  | ||||||
| %patch3 -p1 |  | ||||||
| %patch4 -p1 |  | ||||||
| 
 |  | ||||||
| # Patching of bundled libraries |  | ||||||
| pushd pip/_vendor/urllib3 |  | ||||||
| %patch5 -p1 |  | ||||||
| %patch6 -p1 |  | ||||||
| %patch7 -p1 |  | ||||||
| popd |  | ||||||
| pushd pip/_vendor/requests |  | ||||||
| %patch8 -p1 |  | ||||||
| popd |  | ||||||
| %patch9 -p1 |  | ||||||
| %if %{with tests} |  | ||||||
| %patch10 -p1 |  | ||||||
| %endif |  | ||||||
| %patch11 -p1 |  | ||||||
| %patch12 -p1 |  | ||||||
| %patch13 -p1 |  | ||||||
| 
 | 
 | ||||||
| # this goes together with patch4 | # this goes together with patch4 | ||||||
| rm pip/_vendor/certifi/*.pem | rm src/pip/_vendor/certifi/*.pem | ||||||
| rm pip/_vendor/requests/*.pem |  | ||||||
| sed -i '/\.pem$/d' pip.egg-info/SOURCES.txt |  | ||||||
| 
 | 
 | ||||||
| sed -i '1d' pip/__init__.py | # Do not use furo as HTML theme in docs | ||||||
|  | # furo is not available in Fedora | ||||||
|  | sed -i '/html_theme = "furo"/d' docs/html/conf.py | ||||||
| 
 | 
 | ||||||
| # Remove ordereddict as it is only required for python <= 2.6 | # towncrier extension for Sphinx is not yet available in Fedora | ||||||
| rm pip/_vendor/ordereddict.py | sed -i '/"sphinxcontrib.towncrier",/d' docs/html/conf.py | ||||||
|  | 
 | ||||||
|  | # tests expect wheels in here | ||||||
|  | ln -s %{python_wheel_dir} tests/data/common_wheels | ||||||
|  | 
 | ||||||
|  | # Remove shebang from files in bundled chardet | ||||||
|  | grep -lr "^#\!/usr/bin/env python" src/pip/_vendor/chardet/ | xargs sed -i "1d" | ||||||
| 
 | 
 | ||||||
| # Remove windows executable binaries | # Remove windows executable binaries | ||||||
| rm -v pip/_vendor/distlib/*.exe | rm -v src/pip/_vendor/distlib/*.exe | ||||||
| sed -i '/\.exe/d' setup.py | sed -i '/\.exe/d' setup.py | ||||||
| 
 | 
 | ||||||
| # Backports for Python 2 |  | ||||||
| rm pip/_vendor/distlib/_backport/tarfile.py |  | ||||||
| rm pip/_vendor/distlib/_backport/shutil.py |  | ||||||
| 
 |  | ||||||
| %build | %build | ||||||
| %if %{without bootstrap} |  | ||||||
| %py3_build_wheel | %py3_build_wheel | ||||||
| %else |  | ||||||
| %py3_build |  | ||||||
| %endif |  | ||||||
| 
 | 
 | ||||||
| %if %{with doc} | %if %{with doc} | ||||||
| pushd docs | export PYTHONPATH=./src/ | ||||||
| make html | # from tox.ini | ||||||
| make man | sphinx-build-3 -b html docs/html docs/build/html | ||||||
| rm _build/html/.buildinfo | sphinx-build-3 -b man  docs/man  docs/build/man  -c docs/html | ||||||
| popd | rm -rf docs/build/html/{.doctrees,.buildinfo} | ||||||
| %endif | %endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| %install | %install | ||||||
| %if %{without bootstrap} | # The following is similar to %%pyproject_install, but we don't have | ||||||
| %py3_install_wheel %{python3_wheelname} | # /usr/bin/pip yet, so we install using the wheel directly. | ||||||
| %else | # (This is not standard wheel usage, but the pip wheel supports it -- see | ||||||
| %py3_install | #  pip/__main__.py) | ||||||
| %endif | %{python3} dist/%{python_wheel_name}/pip install \ | ||||||
| 
 |     --root %{buildroot} \ | ||||||
| rm %{buildroot}%{_bindir}/pip |     --no-deps \ | ||||||
|  |     --disable-pip-version-check \ | ||||||
|  |     --progress-bar off \ | ||||||
|  |     --verbose \ | ||||||
|  |     --ignore-installed \ | ||||||
|  |     --no-warn-script-location \ | ||||||
|  |     --no-index \ | ||||||
|  |     --no-cache-dir \ | ||||||
|  |     --find-links dist \ | ||||||
|  |     'pip==%{upstream_version}' | ||||||
| 
 | 
 | ||||||
| %if %{with doc} | %if %{with doc} | ||||||
|  | pushd docs/build/man | ||||||
| install -d %{buildroot}%{_mandir}/man1 | install -d %{buildroot}%{_mandir}/man1 | ||||||
| install -pm0644 docs/_build/man/*.1 %{buildroot}%{_mandir}/man1/pip3.1 | for MAN in *1; do | ||||||
| %endif # with doc | install -pm0644 $MAN %{buildroot}%{_mandir}/man1/$MAN | ||||||
|  | for pip in "pip3" "pip-3" "pip%{python3_version}" "pip-%{python3_version}"; do | ||||||
|  | echo ".so $MAN" > %{buildroot}%{_mandir}/man1/${MAN/pip/$pip} | ||||||
|  | done | ||||||
|  | done | ||||||
|  | popd | ||||||
|  | %endif | ||||||
|  | 
 | ||||||
|  | # before we ln -s anything, we apply Source10 patch to all pips: | ||||||
|  | for PIP in %{buildroot}%{_bindir}/pip*; do | ||||||
|  |   patch -p1 --no-backup-if-mismatch $PIP < %{SOURCE10} | ||||||
|  | done | ||||||
| 
 | 
 | ||||||
| mkdir -p %{buildroot}%{bashcompdir} | mkdir -p %{buildroot}%{bashcompdir} | ||||||
| PYTHONPATH=%{buildroot}%{python3_sitelib} \ | PYTHONPATH=%{buildroot}%{python3_sitelib} \ | ||||||
|     %{buildroot}%{_bindir}/pip3 completion --bash \ |     %{buildroot}%{_bindir}/pip completion --bash \ | ||||||
|     > %{buildroot}%{bashcompdir}/pip3 |     > %{buildroot}%{bashcompdir}/pip3 | ||||||
| 
 | 
 | ||||||
| sed -i -e "s/^\\(complete.*\\) pip\$/\\1 pip3 pip-3 pip3.6 pip-3.6/" \ | # Make bash completion apply to all the 5 symlinks we install | ||||||
|  | sed -i -e "s/^\\(complete.*\\) pip\$/\\1 pip pip{,-}{3,%{python3_version}}/" \ | ||||||
|     -e s/_pip_completion/_pip3_completion/ \ |     -e s/_pip_completion/_pip3_completion/ \ | ||||||
|     %{buildroot}%{bashcompdir}/pip3 |     %{buildroot}%{bashcompdir}/pip3 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| # Provide symlinks to executables to comply with Fedora guidelines for Python | # Provide symlinks to executables to comply with Fedora guidelines for Python | ||||||
| mv %{buildroot}%{_bindir}/pip3 %{buildroot}%{_bindir}/pip%{python3_version} |  | ||||||
| ln -s ./pip%{python3_version} %{buildroot}%{_bindir}/pip-%{python3_version} | ln -s ./pip%{python3_version} %{buildroot}%{_bindir}/pip-%{python3_version} | ||||||
|  | ln -s ./pip-%{python3_version} %{buildroot}%{_bindir}/pip-3 | ||||||
| 
 | 
 | ||||||
| # Change shebang in /usr/bin/pip3.6 to /usr/bin/python3.6 |  | ||||||
| pathfix.py -i /usr/bin/python%{python3_version} -np %{buildroot}%{_bindir}/pip%{python3_version} |  | ||||||
| 
 | 
 | ||||||
| # Make sure the INSTALLER is not pip, otherwise pip-nowarn-upgrade.patch | # Make sure the INSTALLER is not pip and remove RECORD | ||||||
| # (Patch3) won't work | # %%pyproject macros do this for all packages | ||||||
| echo rpm > %{buildroot}%{python3_sitelib}/pip-%{version}.dist-info/INSTALLER | echo rpm > %{buildroot}%{python3_sitelib}/pip-%{upstream_version}.dist-info/INSTALLER | ||||||
|  | rm %{buildroot}%{python3_sitelib}/pip-%{upstream_version}.dist-info/RECORD | ||||||
|  | 
 | ||||||
|  | mkdir -p %{buildroot}%{python_wheel_dir} | ||||||
|  | install -p dist/%{python_wheel_name} -t %{buildroot}%{python_wheel_dir} | ||||||
| 
 | 
 | ||||||
| %if %{without bootstrap} |  | ||||||
| mkdir -p %{buildroot}%{python3_wheeldir} |  | ||||||
| install -p dist/%{python3_wheelname} -t %{buildroot}%{python3_wheeldir} |  | ||||||
| %endif |  | ||||||
| 
 | 
 | ||||||
| %if %{with tests} | %if %{with tests} | ||||||
| %check | %check | ||||||
| py.test-%{python3_version} -m 'not network' | # Verify bundled provides are up to date | ||||||
|  | %{_rpmconfigdir}/pythonbundles.py src/pip/_vendor/vendor.txt --compare-with '%{bundled 3}' | ||||||
|  | 
 | ||||||
|  | # Upstream tests | ||||||
|  | # bash completion tests only work from installed package | ||||||
|  | # needs unaltered sys.path and we cannot do that in %%check | ||||||
|  | #     test_pep517_and_build_options | ||||||
|  | #     test_config_file_venv_option | ||||||
|  | # Incompatible with the latest virtualenv | ||||||
|  | #     test_from_link_vcs_with_source_dir_obtains_commit_id | ||||||
|  | #     test_from_link_vcs_without_source_dir | ||||||
|  | #     test_should_cache_git_sha | ||||||
|  | pytest_k='not completion and | ||||||
|  |           not test_pep517_and_build_options and | ||||||
|  |           not test_config_file_venv_option and | ||||||
|  |           not test_from_link_vcs_with_source_dir_obtains_commit_id and | ||||||
|  |           not test_from_link_vcs_without_source_dir and | ||||||
|  |           not test_should_cache_git_sha' | ||||||
|  | 
 | ||||||
|  | # test_pep517 and test_pep660 are ignored entirely, as they import tomli_w and we don't have that packaged yet | ||||||
|  | # --deselect'ed tests are not compatible with the latest virtualenv | ||||||
|  | # These files contain almost 500 tests so we should enable them back | ||||||
|  | # as soon as pip will be compatible upstream | ||||||
|  | # https://github.com/pypa/pip/pull/8441 | ||||||
|  | %pytest -m 'not network' -k "$(echo $pytest_k)" \ | ||||||
|  |     --ignore tests/functional/test_pep660.py --ignore tests/functional/test_pep517.py \ | ||||||
|  |     --deselect tests/functional --deselect tests/lib/test_lib.py --deselect tests/unit/test_build_env.py | ||||||
| %endif | %endif | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| %files -n platform-python-%{srcname} |  | ||||||
| %license LICENSE.txt |  | ||||||
| %doc README.rst |  | ||||||
| %if %{with doc} |  | ||||||
| %{_mandir}/man1/pip3.* |  | ||||||
| %endif |  | ||||||
| %{python3_sitelib}/pip* |  | ||||||
| 
 |  | ||||||
| %files -n python%{python3_pkgversion}-%{srcname} | %files -n python%{python3_pkgversion}-%{srcname} | ||||||
| %license LICENSE.txt |  | ||||||
| %doc README.rst | %doc README.rst | ||||||
| # The pip3 binary is created using alternatives | %license %{python3_sitelib}/pip-%{upstream_version}.dist-info/LICENSE.txt | ||||||
| # defined in the python36 package | %if %{with doc} | ||||||
|  | %{_mandir}/man1/pip.* | ||||||
|  | %{_mandir}/man1/pip-*.* | ||||||
|  | %{_mandir}/man1/pip3.* | ||||||
|  | %{_mandir}/man1/pip3-*.* | ||||||
|  | %endif | ||||||
|  | %{_bindir}/pip | ||||||
|  | %{_bindir}/pip3 | ||||||
|  | %{_bindir}/pip-3 | ||||||
| %{_bindir}/pip%{python3_version} | %{_bindir}/pip%{python3_version} | ||||||
| %{_bindir}/pip-%{python3_version} | %{_bindir}/pip-%{python3_version} | ||||||
|  | %{python3_sitelib}/pip* | ||||||
| %dir %{bashcompdir} | %dir %{bashcompdir} | ||||||
| %{bashcompdir}/pip* | %{bashcompdir}/pip3 | ||||||
| 
 | 
 | ||||||
| %if %{with doc} | %if %{with doc} | ||||||
| %files doc | %files doc | ||||||
| %license LICENSE.txt | %license LICENSE.txt | ||||||
| %doc README.rst | %doc README.rst | ||||||
| %doc docs/_build/html | %doc docs/build/html | ||||||
| %endif # with doc |  | ||||||
| 
 |  | ||||||
| %if %{without bootstrap} |  | ||||||
| %files -n python3-%{srcname}-wheel |  | ||||||
| %license LICENSE.txt |  | ||||||
| # we own the dir for simplicity |  | ||||||
| %dir %{python3_wheeldir}/ |  | ||||||
| %{python3_wheeldir}/%{python3_wheelname} |  | ||||||
| %endif | %endif | ||||||
| 
 | 
 | ||||||
|  | %files -n %{python_wheel_pkg_prefix}-%{srcname}-wheel | ||||||
|  | %license LICENSE.txt | ||||||
|  | # we own the dir for simplicity | ||||||
|  | %dir %{python_wheel_dir}/ | ||||||
|  | %{python_wheel_dir}/%{python_wheel_name} | ||||||
|  | 
 | ||||||
| %changelog | %changelog | ||||||
| * Wed Feb 14 2024 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-24 | * Tue Mar 19 2024 Lumír Balhar <lbalhar@redhat.com> - 21.3.1-1 | ||||||
|  | - Update to 21.3.1 | ||||||
|  | Resolves: RHEL-29310 | ||||||
|  | 
 | ||||||
|  | * Wed Feb 14 2024 Lumír Balhar <lbalhar@redhat.com> - 21.2.3-8 | ||||||
| - Require Python with tarfile filters | - Require Python with tarfile filters | ||||||
| Resolves: RHEL-25446 | Resolves: RHEL-25451 | ||||||
| 
 | 
 | ||||||
| * Tue Aug 08 2023 Petr Viktorin <pviktori@redhat.com> - 9.0.3-23 | * Tue Aug 08 2023 Petr Viktorin <pviktori@redhat.com> - 21.2.3-7 | ||||||
| - Use tarfile.data_filter for extracting (CVE-2007-4559, PEP-721, PEP-706) | - Use tarfile.data_filter for extracting (CVE-2007-4559, PEP-721, PEP-706) | ||||||
| Resolves: RHBZ#2218241 | Resolves: RHBZ#2207997 | ||||||
| 
 | 
 | ||||||
| * Wed Oct 06 2021 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-22 | * Thu Feb 03 2022 Tomas Orsava <torsava@redhat.com> - 21.2.3-6 | ||||||
|  | - Add automatically generated Obsoletes tag with the python39- prefix | ||||||
|  |   for smoother upgrade from RHEL8 | ||||||
|  | - Related: rhbz#1990421 | ||||||
|  | 
 | ||||||
|  | * Wed Nov 24 2021 Tomas Orsava <torsava@redhat.com> - 21.2.3-5 | ||||||
|  | - Conflict with old Python versions that use the old unversioned wheel location | ||||||
|  | - Resolves: rhbz#1982668 | ||||||
|  | 
 | ||||||
|  | * Fri Nov 5 2021 Tomas Orsava <torsava@redhat.com> - 21.2.3-4 | ||||||
|  | - Make the python-pip-wheel subpackage versioned (python3-pip-wheel), | ||||||
|  |   and move its contents to a versioned directory /usr/share/python3-wheels | ||||||
|  | - Resolves: rhbz#1982668 | ||||||
|  | 
 | ||||||
|  | * Wed Oct 06 2021 Charalampos Stratakis <cstratak@redhat.com> - 21.2.3-3 | ||||||
| - Remove bundled windows executables | - Remove bundled windows executables | ||||||
| - Resolves: rhbz#2006788 | - Resolves: rhbz#2006795 | ||||||
| 
 | 
 | ||||||
| * Tue Oct 05 2021 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-21 | * Mon Sep 13 2021 Miro Hrončok <mhroncok@redhat.com> - 21.2.3-2 | ||||||
| - Support of yanked releases | - Fix broken uninstallation by a bogus downstream patch | ||||||
| Resolves: rhbz#2000135 |  | ||||||
| 
 | 
 | ||||||
| * Mon Jun 07 2021 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-20 | * Mon Sep 13 2021 Miro Hrončok <mhroncok@redhat.com> - 21.2.3-1 | ||||||
| - Fix for CVE-2021-3572 - pip incorrectly handled unicode separators in git references | - Update to 21.2.3 | ||||||
| Resolves: rhbz#1962856 | - Resolves: rhbz#1985635 | ||||||
| 
 | 
 | ||||||
| * Fri Jan 08 2021 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-19 | * Mon Sep 13 2021 Lumír Balhar <lbalhar@redhat.com> - 21.1.3-1 | ||||||
| - Fix bash completion files and simplify spec | - Update to 21.1.3 | ||||||
| Resolves: rhbz#1904478 | Resolves: rhbz#1976449 | ||||||
| 
 | 
 | ||||||
| * Wed Aug 19 2020 Tomas Orsava <torsava@redhat.com> - 9.0.3-18 | * Mon Sep 13 2021 Karolina Surma <ksurma@redhat.com> - 21.1.2-1 | ||||||
| - Patch for pip install <url> allow directory traversal, leading to arbitrary file write | - Update to 21.1.2 | ||||||
| Resolves: rhbz#1868016 | Resolves: rhbz#1963433 | ||||||
| 
 | 
 | ||||||
| * Wed Mar 04 2020 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-17 | * Mon Sep 13 2021 Karolina Surma <ksurma@redhat.com> - 21.1.1-1 | ||||||
| - Remove unused CA bundle from the bundled requests library | - Update to 21.1.1 | ||||||
| Resolves: rhbz#1775200 |  | ||||||
| 
 | 
 | ||||||
| * Mon Jan 13 2020 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-16 | * Tue Aug 10 2021 Mohan Boddu <mboddu@redhat.com> - 21.0.1-6 | ||||||
| - Add four new patches for CVEs in bundled urllib3 and requests | - Rebuilt for IMA sigs, glibc 2.34, aarch64 flags | ||||||
| CVE-2018-20060, CVE-2019-11236, CVE-2019-11324, CVE-2018-18074 |   Related: rhbz#1991688 | ||||||
| Resolves: rhbz#1649153 |  | ||||||
| Resolves: rhbz#1700824 |  | ||||||
| Resolves: rhbz#1702473 |  | ||||||
| Resolves: rhbz#1643829 |  | ||||||
| 
 | 
 | ||||||
| * Thu Jun 06 2019 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-15 | * Wed Jul 28 2021 Tomas Orsava <torsava@redhat.com> - 21.0.1-5 | ||||||
| - Create python-pip-wheel package with the wheel | - Provide the platform-python-pip name for backwards compatibility | ||||||
| Resolves: rhbz#1718031 |   with RHEL 8 | ||||||
|  | - Related: rhbz#1891487 | ||||||
| 
 | 
 | ||||||
| * Wed Mar 13 2019 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-14 | * Mon May 17 2021 Karolina Surma <ksurma@redhat.com> - 21.0.1-4 | ||||||
| - Move bash completion files from platform-python- to python3- subpackage | - Backport security fixes from pip 21.1.1 | ||||||
| - resolves: rhbz#1664749 |  | ||||||
| 
 | 
 | ||||||
| * Mon Dec 03 2018 Miro Hrončok <mhroncok@redhat.com> - 9.0.3-13 | * Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> | ||||||
|  | - Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 | ||||||
|  | 
 | ||||||
|  | * Sat Mar 13 2021 Miro Hrončok <mhroncok@redhat.com> - 21.0.1-2 | ||||||
|  | - python-pip-wheel: Remove bundled provides and libcrypt recommends for Python 2 | ||||||
|  |   (The wheel is Python 3 only for a while) | ||||||
|  | 
 | ||||||
|  | * Wed Feb 17 2021 Lumír Balhar <lbalhar@redhat.com> - 21.0.1-1 | ||||||
|  | - Update to 21.0.1 | ||||||
|  | Resolves: rhbz#1922592 | ||||||
|  | 
 | ||||||
|  | * Tue Jan 26 2021 Lumír Balhar <lbalhar@redhat.com> - 21.0-1 | ||||||
|  | - Update to 21.0 (#1919530) | ||||||
|  | 
 | ||||||
|  | * Thu Dec 17 2020 Petr Viktorin <pviktori@redhat.com> - 20.3.3-1 | ||||||
|  | - Update to 20.3.3 | ||||||
|  | 
 | ||||||
|  | * Mon Nov 30 2020 Miro Hrončok <mhroncok@redhat.com> - 20.3-1 | ||||||
|  | - Update to 20.3 | ||||||
|  | - Add support for PEP 600: Future manylinux Platform Tags | ||||||
|  | - New resolver | ||||||
|  | - Fixes: rhbz#1893470 | ||||||
|  | 
 | ||||||
|  | * Mon Oct 19 2020 Lumír Balhar <lbalhar@redhat.com> - 20.2.4-1 | ||||||
|  | - Update to 20.2.4 (#1889112) | ||||||
|  | 
 | ||||||
|  | * Wed Aug 05 2020 Tomas Orsava <torsava@redhat.com> - 20.2.2-1 | ||||||
|  | - Update to 20.2.2 (#1838553) | ||||||
|  | 
 | ||||||
|  | * Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 20.1.1-7 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Fri Jul 10 2020 Lumír Balhar <lbalhar@redhat.com> - 20.1.1-6 | ||||||
|  | - Do not emit a warning about root privileges when --root is used | ||||||
|  | 
 | ||||||
|  | * Wed Jul 08 2020 Miro Hrončok <mhroncok@redhat.com> - 20.1.1-5 | ||||||
|  | - Update bundled provides to match 20.1.1 | ||||||
|  | 
 | ||||||
|  | * Tue Jun 16 2020 Lumír Balhar <lbalhar@redhat.com> - 20.1.1-4 | ||||||
|  | - Deselect tests incompatible with the latest virtualenv | ||||||
|  | 
 | ||||||
|  | * Sun May 24 2020 Miro Hrončok <mhroncok@redhat.com> - 20.1.1-3 | ||||||
|  | - Rebuilt for Python 3.9 | ||||||
|  | 
 | ||||||
|  | * Thu May 21 2020 Miro Hrončok <mhroncok@redhat.com> - 20.1.1-2 | ||||||
|  | - Bootstrap for Python 3.9 | ||||||
|  | 
 | ||||||
|  | * Wed May 20 2020 Tomas Hrnciar <thrnciar@redhat.com> - 20.1.1-1 | ||||||
|  | - Update to 20.1.1 | ||||||
|  | 
 | ||||||
|  | * Wed Apr 29 2020 Tomas Hrnciar <thrnciar@redhat.com> - 20.1-1 | ||||||
|  | - Update to 20.1 | ||||||
|  | 
 | ||||||
|  | * Mon Apr 27 2020 Tomas Hrnciar <thrnciar@redhat.com> - 20.1~b1-1 | ||||||
|  | - Update to 20.1~b1 | ||||||
|  | 
 | ||||||
|  | * Wed Apr 15 2020 Miro Hrončok <mhroncok@redhat.com> - 20.0.2-4 | ||||||
|  | - Only recommend setuptools, don't require them | ||||||
|  | 
 | ||||||
|  | * Fri Apr 10 2020 Miro Hrončok <mhroncok@redhat.com> - 20.0.2-3 | ||||||
|  | - Allow setting $TMPDIR to $PWD/... during pip wheel (#1806625) | ||||||
|  | 
 | ||||||
|  | * Tue Mar 10 2020 Miro Hrončok <mhroncok@redhat.com> - 20.0.2-2 | ||||||
|  | - Don't warn the user about pip._internal.main() entrypoint to fix ensurepip | ||||||
|  | 
 | ||||||
|  | * Mon Mar 02 2020 Miro Hrončok <mhroncok@redhat.com> - 20.0.2-1 | ||||||
|  | - Update to 20.0.2 (#1793456) | ||||||
|  | 
 | ||||||
|  | * Thu Jan 30 2020 Fedora Release Engineering <releng@fedoraproject.org> - 19.3.1-2 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Mon Nov 04 2019 Tomas Orsava <torsava@redhat.com> - 19.3.1-1 | ||||||
|  | - Update to 19.3.1 (#1761508) | ||||||
|  | - Drop upstreamed patch that fixed expected output in test to not break with alpha/beta/rc Python versions | ||||||
|  | 
 | ||||||
|  | * Wed Oct 30 2019 Miro Hrončok <mhroncok@redhat.com> - 19.2.3-2 | ||||||
|  | - Make /usr/bin/pip(3) work with user-installed pip 19.3+ (#1767212) | ||||||
|  | 
 | ||||||
|  | * Mon Sep 02 2019 Miro Hrončok <mhroncok@redhat.com> - 19.2.3-1 | ||||||
|  | - Update to 19.2.3 (#1742230) | ||||||
|  | - Drop patch that should strip path prefixes from RECORD files, the paths are relative | ||||||
|  | 
 | ||||||
|  | * Wed Aug 21 2019 Petr Viktorin <pviktori@redhat.com> - 19.1.1-8 | ||||||
|  | - Remove python2-pip | ||||||
|  | - Make pip bootstrap itself, rather than with an extra bootstrap RPM build | ||||||
|  | 
 | ||||||
|  | * Sat Aug 17 2019 Miro Hrončok <mhroncok@redhat.com> - 19.1.1-7 | ||||||
|  | - Rebuilt for Python 3.8 | ||||||
|  | 
 | ||||||
|  | * Wed Aug 14 2019 Miro Hrončok <mhroncok@redhat.com> - 19.1.1-6 | ||||||
|  | - Bootstrap for Python 3.8 | ||||||
|  | 
 | ||||||
|  | * Wed Aug 14 2019 Miro Hrončok <mhroncok@redhat.com> - 19.1.1-5 | ||||||
|  | - Bootstrap for Python 3.8 | ||||||
|  | 
 | ||||||
|  | * Fri Jul 26 2019 Fedora Release Engineering <releng@fedoraproject.org> - 19.1.1-4 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Mon Jul 15 2019 Petr Viktorin <pviktori@redhat.com> - 19.1.1-3 | ||||||
|  | - Recommend libcrypt.so.1 for manylinux1 compatibility | ||||||
|  | - Make /usr/bin/pip Python 3 | ||||||
|  | 
 | ||||||
|  | * Mon Jun 10 2019 Miro Hrončok <mhroncok@redhat.com> - 19.1.1-2 | ||||||
|  | - Fix root warning when pip is invoked via python -m pip | ||||||
|  | - Remove a redundant second WARNING prefix form the abovementioned warning | ||||||
|  | 
 | ||||||
|  | * Wed May 15 2019 Miro Hrončok <mhroncok@redhat.com> - 19.1.1-1 | ||||||
|  | - Update to 19.1.1 (#1706995) | ||||||
|  | 
 | ||||||
|  | * Thu Apr 25 2019 Miro Hrončok <mhroncok@redhat.com> - 19.1-1 | ||||||
|  | - Update to 19.1 (#1702525) | ||||||
|  | 
 | ||||||
|  | * Wed Mar 06 2019 Miro Hrončok <mhroncok@redhat.com> - 19.0.3-1 | ||||||
|  | - Update to 19.0.3 (#1679277) | ||||||
|  | 
 | ||||||
|  | * Wed Feb 13 2019 Miro Hrončok <mhroncok@redhat.com> - 19.0.2-1 | ||||||
|  | - Update to 19.0.2 (#1668492) | ||||||
|  | 
 | ||||||
|  | * Sat Feb 02 2019 Fedora Release Engineering <releng@fedoraproject.org> - 18.1-3 | ||||||
|  | - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild | ||||||
|  | 
 | ||||||
|  | * Mon Dec 03 2018 Miro Hrončok <mhroncok@redhat.com> - 18.1-2 | ||||||
| - Use the system level root certificate instead of the one bundled in certifi | - Use the system level root certificate instead of the one bundled in certifi | ||||||
| - Resolves: rhbz#1655255 |  | ||||||
| 
 | 
 | ||||||
| * Wed Nov 28 2018 Tomas Orsava <torsava@redhat.com> - 9.0.3-12 | * Thu Nov 22 2018 Miro Hrončok <mhroncok@redhat.com> - 18.1-1 | ||||||
| - Do not show the "new version of pip" warning outside of venv | - Update to 18.1 (#1652089) | ||||||
| - Resolves: rhbz#1656171 |  | ||||||
| 
 | 
 | ||||||
| * Mon Nov 19 2018 Victor Stinner <vstinner@redhat.com> - 9.0.3-11 | * Tue Sep 18 2018 Victor Stinner <vstinner@redhat.com> - 18.0-4 | ||||||
| - Prevent removing of the system packages installed under /usr/lib | - Prevent removing of the system packages installed under /usr/lib | ||||||
|   when pip install -U is executed. Patch by Michal Cyprian. |   when pip install -U is executed. Original patch by Michal Cyprian. | ||||||
|   Resolves: rhbz#1626408. |   Resolves: rhbz#1550368. | ||||||
| 
 | 
 | ||||||
| * Fri Nov 16 2018 Tomas Orsava <torsava@redhat.com> - 9.0.3-10 | * Wed Aug 08 2018 Miro Hrončok <mhroncok@redhat.com> - 18.0-3 | ||||||
| - Bump the NVR so it's higher than previous builds of python3-pip that have | - Create python-pip-wheel package with the wheel | ||||||
|   mistakenly gotten into the python27 module build when we were dealing with an |  | ||||||
|   MBS filtering problem. See BZ#1650568. |  | ||||||
| - Resolves: rhbz#1638836 |  | ||||||
| 
 | 
 | ||||||
| * Mon Nov 12 2018 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-6 | * Tue Jul 31 2018 Miro Hrončok <mhroncok@redhat.com> - 18.0-2 | ||||||
| - python3-pip requires python36 and obsoletes previous version | - Remove redundant "Unicode" from License | ||||||
|   where python3- and platform-python- were in one package |  | ||||||
| - Resolves: rhbz#1638836 |  | ||||||
| 
 | 
 | ||||||
| * Mon Oct 22 2018 Tomas Orsava <torsava@redhat.com> - 9.0.3-5 | * Mon Jul 23 2018 Marcel Plch <mplch@redhat.com> - 18.0-7 | ||||||
| - Split part of the python3-pip package into platform-python-pip | - Update to 18.0 | ||||||
| - python3-pip will only contain binaries in /usr/bin |  | ||||||
| - Resolves: rhbz#1638836 |  | ||||||
| 
 | 
 | ||||||
| * Mon Aug 06 2018 Petr Viktorin <pviktori@redhat.com> - 9.0.3-4 | * Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 9.0.3-6 | ||||||
| - Remove the python2 subpackage | - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild | ||||||
| - Remove unversioned executables (only *-3.6 should be provided) |  | ||||||
| 
 | 
 | ||||||
| * Mon Aug 06 2018 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-3 | * Mon Jun 18 2018 Miro Hrončok <mhroncok@redhat.com> - 9.0.3-5 | ||||||
| - Correct license information | - Rebuilt for Python 3.7 | ||||||
| 
 | 
 | ||||||
| * Mon Jun 25 2018 Petr Viktorin <pviktori@redhat.com> - 9.0.3-2 | * Wed Jun 13 2018 Miro Hrončok <mhroncok@redhat.com> - 9.0.3-4 | ||||||
| - Don't build the python2 subpackage | - Bootstrap for Python 3.7 | ||||||
|   https://bugzilla.redhat.com/show_bug.cgi?id=1594335 | 
 | ||||||
|  | * Wed Jun 13 2018 Miro Hrončok <mhroncok@redhat.com> - 9.0.3-3 | ||||||
|  | - Bootstrap for Python 3.7 | ||||||
|  | 
 | ||||||
|  | * Fri May 04 2018 Miro Hrončok <mhroncok@redhat.com> - 9.0.3-2 | ||||||
|  | - Allow to import pip10's main from pip9's /usr/bin/pip | ||||||
|  | - Do not show the "new version of pip" warning outside of venv | ||||||
|  | Resolves: rhbz#1569488 | ||||||
|  | Resolves: rhbz#1571650 | ||||||
|  | Resolves: rhbz#1573755 | ||||||
| 
 | 
 | ||||||
| * Thu Mar 29 2018 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-1 | * Thu Mar 29 2018 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-1 | ||||||
| - Update to 9.0.3 | - Update to 9.0.3 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user