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
 | ||||
| --- 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
 | ||||
| @@ -559,6 +559,13 @@
 | ||||
|              if leading: | ||||
|                  fn = split_leading_dir(fn)[1] | ||||
|              path = os.path.join(location, fn) | ||||
| Minimal patch for pip | ||||
| ---
 | ||||
|  src/pip/_internal/utils/unpacking.py |  7 +++++++ | ||||
|  src/pip/_vendor/distlib/util.py      | 13 +++++++++++++ | ||||
|  tests/unit/test_utils_unpacking.py   | 17 +++++++++++++++++ | ||||
|  3 files changed, 37 insertions(+) | ||||
| 
 | ||||
| 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)
 | ||||
| +            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(): | ||||
|                  ensure_dir(path) | ||||
|              elif member.issym(): | ||||
| 
 | ||||
| 
 | ||||
| Patch for vendored distlib from https://github.com/pypa/distlib/pull/201 | ||||
| 
 | ||||
| diff --git a/distlib/util.py b/distlib/util.py
 | ||||
| index e0622e4..4349d0b 100644
 | ||||
| --- a/pip/_vendor/distlib/util.py
 | ||||
| +++ b/pip/_vendor/distlib/util.py
 | ||||
| @@ -1249,6 +1249,19 @@ def check_path(path):
 | ||||
| diff --git a/src/pip/_vendor/distlib/util.py b/src/pip/_vendor/distlib/util.py
 | ||||
| index 80bfc86..7e0941a 100644
 | ||||
| --- a/src/pip/_vendor/distlib/util.py
 | ||||
| +++ b/src/pip/_vendor/distlib/util.py
 | ||||
| @@ -1249,6 +1249,19 @@ def unarchive(archive_filename, dest_dir, format=None, check=True):
 | ||||
|              for tarinfo in archive.getmembers(): | ||||
|                  if not isinstance(tarinfo.name, text_type): | ||||
|                      tarinfo.name = tarinfo.name.decode('utf-8') | ||||
| @ -45,3 +52,34 @@ index e0622e4..4349d0b 100644 | ||||
|          archive.extractall(dest_dir) | ||||
|   | ||||
|      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
 | ||||
| index eab9d1d..9614a88 100644
 | ||||
| --- a/pip/_vendor/certifi/core.py
 | ||||
| +++ b/pip/_vendor/certifi/core.py
 | ||||
| @@ -19,9 +19,7 @@ class DeprecatedBundleWarning(DeprecationWarning):
 | ||||
| From 2c58d7301dd5a47570f782fe2fce7fbb1918f60c Mon Sep 17 00:00:00 2001 | ||||
| From: Karolina Surma <ksurma@redhat.com> | ||||
| Date: Mon, 10 May 2021 16:38:50 +0200 | ||||
| Subject: [PATCH] Dummy certifi patch | ||||
| 
 | ||||
| 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):
 | ||||
| 
 | ||||
| 
 | ||||
|  try: | ||||
| +    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'
 | ||||
| 
 | ||||
| 
 | ||||
|  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
 | ||||
| index 6911fba..8524932 100644
 | ||||
| --- a/pip/req/req_install.py
 | ||||
| +++ b/pip/req/req_install.py
 | ||||
| @@ -34,7 +34,7 @@ from pip.locations import (
 | ||||
| From f5c7cdc676e6884580fde4689a296ff50a9847a5 Mon Sep 17 00:00:00 2001 | ||||
| From: Lumir Balhar <lbalhar@redhat.com> | ||||
| Date: Wed, 20 Mar 2024 13:43:12 +0100 | ||||
| Subject: [PATCH] Prevent removing of the system packages installed under | ||||
|  /usr/lib when pip install -U is executed. | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| Resolves: rhbz#1550368 | ||||
| 
 | ||||
| Co-Authored-By: Michal Cyprian <m.cyprian@gmail.com> | ||||
| Co-Authored-By: Victor Stinner <vstinner@redhat.com> | ||||
| Co-Authored-By: Petr Viktorin <pviktori@redhat.com> | ||||
| Co-Authored-By: Lumir Balhar <lbalhar@redhat.com> | ||||
| 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 | ||||
|                          ) | ||||
|  from pip.utils import ( | ||||
|      display_path, rmtree, ask_path_exists, backup_dir, is_installable_dir, | ||||
| -    dist_in_usersite, dist_in_site_packages, egg_link_path,
 | ||||
| +    dist_in_usersite, dist_in_site_packages, dist_in_install_path, egg_link_path,
 | ||||
|      call_subprocess, read_text_file, FakeFile, _make_build_dir, ensure_dir, | ||||
|      get_installed_version, normalize_path, dist_is_local, | ||||
|  ) | ||||
| @@ -1049,7 +1049,7 @@ class InstallRequirement(object):
 | ||||
|                          "lack sys.path precedence to %s in %s" % | ||||
|                          (existing_dist.project_name, existing_dist.location) | ||||
|                      ) | ||||
| -            else:
 | ||||
| +            elif dist_in_install_path(existing_dist):
 | ||||
|                  self.conflicts_with = existing_dist | ||||
|          return True | ||||
|                  self.should_reinstall = 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
 | ||||
| index 76aec06..b93304a 100644
 | ||||
| --- a/pip/req/req_set.py
 | ||||
| +++ b/pip/req/req_set.py
 | ||||
| @@ -18,7 +18,8 @@ from pip.exceptions import (InstallationError, BestVersionAlreadyInstalled,
 | ||||
|                              UnsupportedPythonVersion) | ||||
|  from pip.req.req_install import InstallRequirement | ||||
|  from pip.utils import ( | ||||
| -    display_path, dist_in_usersite, ensure_dir, normalize_path)
 | ||||
| +    display_path, dist_in_usersite, dist_in_install_path, ensure_dir,
 | ||||
| +    normalize_path)
 | ||||
|  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):
 | ||||
|  logger = logging.getLogger(__name__) | ||||
| @@ -203,7 +204,9 @@ class Resolver(BaseResolver):
 | ||||
|          """ | ||||
|          # Don't uninstall the conflict if doing a user install and the | ||||
|          # conflict is not a user install. | ||||
| -        if not self.use_user_site or dist_in_usersite(req.satisfied_by):
 | ||||
| +        if ((not self.use_user_site
 | ||||
| +                or dist_in_usersite(req.satisfied_by))
 | ||||
| +                and dist_in_install_path(req.satisfied_by)):
 | ||||
|              req.should_reinstall = True | ||||
|          req.satisfied_by = None | ||||
|   | ||||
|                  if not best_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.conflicts_with = \
 | ||||
| +                            dist_in_usersite(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 | ||||
|   | ||||
| @@ -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,
 | ||||
| diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py
 | ||||
| index 766dc26..baf61ba 100644
 | ||||
| --- a/src/pip/_internal/resolution/resolvelib/factory.py
 | ||||
| +++ b/src/pip/_internal/resolution/resolvelib/factory.py
 | ||||
| @@ -1,6 +1,7 @@
 | ||||
|  import contextlib | ||||
|  import functools | ||||
|  import logging | ||||
| +import sys
 | ||||
|  from typing import ( | ||||
|      TYPE_CHECKING, | ||||
|      Dict, | ||||
| @@ -33,6 +34,7 @@ from pip._internal.exceptions import (
 | ||||
|      UnsupportedWheel, | ||||
|  ) | ||||
|  from pip._vendor import pkg_resources | ||||
|  from pip._vendor.six.moves import input | ||||
| @@ -315,6 +315,16 @@ def dist_in_site_packages(dist):
 | ||||
|      ).startswith(normalize_path(site_packages)) | ||||
|  from pip._internal.index.package_finder import PackageFinder | ||||
| +from pip._internal.locations import get_scheme
 | ||||
|  from pip._internal.metadata import BaseDistribution, get_default_environment | ||||
|  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):
 | ||||
| @ -89,9 +130,12 @@ index 815bd33..0ed59f7 100644 | ||||
| +    """
 | ||||
| +    norm_path = normalize_path(dist_location(dist))
 | ||||
| +    return norm_path.startswith(normalize_path(
 | ||||
| +        distutils_scheme("")['purelib'].split('python')[0]))
 | ||||
| +        get_scheme("").purelib.split('python')[0]))
 | ||||
| +
 | ||||
| +
 | ||||
|  def dist_is_editable(dist): | ||||
|      """Is distribution an editable install?""" | ||||
|      for path_item in sys.path: | ||||
|  def get_distribution(req_name: str) -> Optional[Distribution]: | ||||
|      """Given a requirement name, return the installed Distribution object. | ||||
|   | ||||
| -- 
 | ||||
| 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 doc | ||||
| %else | ||||
| %bcond_without tests | ||||
| %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 | ||||
| 
 | ||||
| %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} | ||||
| # When updating, update the bundled libraries versions bellow! | ||||
| Version:        9.0.3 | ||||
| Release:        24%{?dist} | ||||
| Version:        %{base_version}%{?prerel:~%{prerel}} | ||||
| Release:        1%{?dist} | ||||
| 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. | ||||
| # Here is the list of the libraries with corresponding licenses: | ||||
| 
 | ||||
| # appdirs: MIT | ||||
| # CacheControl: ASL 2.0 | ||||
| # certifi: MPLv2.0 | ||||
| # chardet: LGPLv2 | ||||
| # colorama: BSD | ||||
| # CacheControl: ASL 2.0 | ||||
| # distlib: Python | ||||
| # distro: ASL 2.0 | ||||
| # html5lib: MIT | ||||
| # idna: BSD | ||||
| # ipaddress: Python | ||||
| # lockfile: MIT | ||||
| # msgpack: ASL 2.0 | ||||
| # packaging: ASL 2.0 or BSD | ||||
| # pep517: MIT | ||||
| # progress: ISC | ||||
| # pyparsing: MIT | ||||
| # requests: ASL 2.0 | ||||
| # retrying: ASL 2.0 | ||||
| # urllib3: MIT | ||||
| # resolvelib: ISC | ||||
| # setuptools: MIT | ||||
| # six: MIT | ||||
| # tenacity: ASL 2.0 | ||||
| # tomli: MIT | ||||
| # urllib3: MIT | ||||
| # 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) | ||||
| URL:            http://www.pip-installer.org | ||||
| Source0:        https://files.pythonhosted.org/packages/source/p/%{srcname}/%{srcname}-%{version}.tar.gz | ||||
| URL:            https://pip.pypa.io/ | ||||
| Source0:        https://github.com/pypa/pip/archive/%{upstream_version}/%{srcname}-%{upstream_version}.tar.gz | ||||
| 
 | ||||
| BuildArch:      noarch | ||||
| 
 | ||||
| %if %{with tests} | ||||
| BuildRequires:  git | ||||
| BuildRequires:  bzr | ||||
| BuildRequires:  /usr/bin/git | ||||
| BuildRequires:  /usr/bin/hg | ||||
| BuildRequires:  /usr/bin/bzr | ||||
| BuildRequires:  /usr/bin/svn | ||||
| BuildRequires:  python-setuptools-wheel | ||||
| BuildRequires:  python-wheel-wheel | ||||
| %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 | ||||
| # when pip install -U is executed. | ||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=1626408 | ||||
| # Author: Michal Cyprian | ||||
| 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 | ||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=1550368#c24 | ||||
| Patch3:         remove-existing-dist-only-if-path-conflicts.patch | ||||
| 
 | ||||
| # 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 | ||||
| 
 | ||||
| # Patch for CVE in the bundled urllib3 | ||||
| # CVE-2018-20060 Cross-host redirect does not remove Authorization header allow for credential exposure | ||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2018-20060 | ||||
| Patch5:         CVE-2018-20060.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. | ||||
| Patch5:         nowarn-pip._internal.main.patch | ||||
| 
 | ||||
| # Patch for CVE in the bundled urllib3 | ||||
| # CVE-2019-11236 CRLF injection due to not encoding the '\r\n' sequence leading to possible attack on internal service | ||||
| # https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2019-11236 | ||||
| Patch6:         CVE-2019-11236.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 | ||||
| # Don't warn the user about packaging's LegacyVersion being deprecated. | ||||
| # (This also breaks Python's test suite when warnings are treated as errors.) | ||||
| # Upstream issue: https://github.com/pypa/packaging/issues/368 | ||||
| Patch6:         no-version-warning.patch | ||||
| 
 | ||||
| # CVE-2007-4559, PEP-721, PEP-706: Use tarfile.data_filter for extracting | ||||
| # - Minimal downstream-only patch, to be replaced by upstream solution | ||||
| #   proposed in https://github.com/pypa/pip/pull/12214 | ||||
| # - Test patch submitted upstream in the above pull request | ||||
| # - Patch for vendored distlib, accepted upstream: | ||||
| #   https://github.com/pypa/distlib/pull/201 | ||||
| Patch13:         cve-2007-4559-tarfile.patch | ||||
| Patch7:         cve-2007-4559-tarfile.patch | ||||
| 
 | ||||
| %global _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 \ | ||||
| # Downstream only patch | ||||
| # Users might have local installations of pip from using | ||||
| # `pip install --user --upgrade pip` on older/newer versions. | ||||
| # 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". | ||||
| 
 | ||||
| %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. | ||||
| # See the python2 list above for instructions. | ||||
| Provides: bundled(python3dist(appdirs)) = 1.4.0 | ||||
| Provides: bundled(python3dist(cachecontrol)) = 0.11.7 | ||||
| Provides: bundled(python3dist(colorama)) = 0.3.7 | ||||
| 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 | ||||
| # You can generate it with: | ||||
| # %%{_rpmconfigdir}/pythonbundles.py --namespace 'python%%{1}dist' src/pip/_vendor/vendor.txt | ||||
| %global bundled() %{expand: | ||||
| Provides: bundled(python%{1}dist(cachecontrol)) = 0.12.6 | ||||
| Provides: bundled(python%{1}dist(certifi)) = 2021.5.30 | ||||
| Provides: bundled(python%{1}dist(chardet)) = 4 | ||||
| Provides: bundled(python%{1}dist(colorama)) = 0.4.4 | ||||
| Provides: bundled(python%{1}dist(distlib)) = 0.3.3 | ||||
| Provides: bundled(python%{1}dist(distro)) = 1.6 | ||||
| Provides: bundled(python%{1}dist(html5lib)) = 1.1 | ||||
| Provides: bundled(python%{1}dist(idna)) = 3.2 | ||||
| Provides: bundled(python%{1}dist(msgpack)) = 1.0.2 | ||||
| Provides: bundled(python%{1}dist(packaging)) = 21 | ||||
| Provides: bundled(python%{1}dist(pep517)) = 0.12 | ||||
| Provides: bundled(python%{1}dist(platformdirs)) = 2.4 | ||||
| Provides: bundled(python%{1}dist(progress)) = 1.6 | ||||
| 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 | ||||
| Provides: bundled(python3dist(chardet)) = 2.3.0 | ||||
| Provides: bundled(python3dist(urllib3)) = 1.16 | ||||
| # Some manylinux1 wheels need libcrypt.so.1. | ||||
| # Manylinux1, a common (as of 2019) platform tag for binary wheels, relies | ||||
| # 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} | ||||
| Summary:        A tool for installing and managing Python3 packages | ||||
| Group:          Development/Libraries | ||||
| 
 | ||||
| Requires:       platform-python-pip = %{version}-%{release} | ||||
| Requires:       python36 | ||||
| %{?python_provide:%python_provide python%{python3_pkgversion}-%{srcname}} | ||||
| BuildRequires:  python%{python3_pkgversion}-devel | ||||
| # python3 bootstrap: this is rebuilt before the final build of python3, which | ||||
| # 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} | ||||
| %package doc | ||||
| Summary:        A documentation for a tool for installing and managing Python packages | ||||
| 
 | ||||
| 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 | ||||
| A documentation for a tool for installing and managing Python packages | ||||
| 
 | ||||
| %endif | ||||
| 
 | ||||
| %if %{without bootstrap} | ||||
| %package -n python3-%{srcname}-wheel | ||||
| %package -n     %{python_wheel_pkg_prefix}-%{srcname}-wheel | ||||
| Summary:        The pip wheel | ||||
| # Older Python does not provide tarfile filters (fix for CVE-2007-4559). | ||||
| Conflicts:      platform-python < 3.6.8-55 | ||||
| Requires:       ca-certificates | ||||
| Provides:       %{name}-wheel = %{version}-%{release} | ||||
| Obsoletes:      %{name}-wheel < %{version}-%{release} | ||||
| 
 | ||||
| # Virtual provides for the packages bundled by pip. | ||||
| # You can find the versions in pip/_vendor/vendor.txt file. | ||||
| Provides: bundled(python3dist(appdirs)) = 1.4.0 | ||||
| Provides: bundled(python3dist(cachecontrol)) = 0.11.7 | ||||
| Provides: bundled(python3dist(colorama)) = 0.3.7 | ||||
| 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 | ||||
| # Older versions of python3-libs (< 3.9.9-2) expect Python wheels at the old unversioned | ||||
| # location, so we conflict with the old Python versions that wouldn't work with | ||||
| # the new wheel location. | ||||
| # Moreover, Python older than (3.9.16-2) does not provide tarfile filters (fix for CVE-2007-4559). | ||||
| Conflicts:      python3-libs < 3.9.17-2 | ||||
| 
 | ||||
| # Bundled within the requests bundle | ||||
| Provides: bundled(python3dist(chardet)) = 2.3.0 | ||||
| Provides: bundled(python3dist(urllib3)) = 1.16 | ||||
| # Virtual provides for the packages bundled by pip: | ||||
| %{bundled 3} | ||||
| 
 | ||||
| %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. | ||||
| %endif | ||||
| 
 | ||||
| %prep | ||||
| %setup -q -n %{srcname}-%{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 | ||||
| %autosetup -p1 -n %{srcname}-%{upstream_version} | ||||
| 
 | ||||
| # this goes together with patch4 | ||||
| rm pip/_vendor/certifi/*.pem | ||||
| rm pip/_vendor/requests/*.pem | ||||
| sed -i '/\.pem$/d' pip.egg-info/SOURCES.txt | ||||
| rm src/pip/_vendor/certifi/*.pem | ||||
| 
 | ||||
| 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 | ||||
| rm pip/_vendor/ordereddict.py | ||||
| # towncrier extension for Sphinx is not yet available in Fedora | ||||
| 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 | ||||
| rm -v pip/_vendor/distlib/*.exe | ||||
| rm -v src/pip/_vendor/distlib/*.exe | ||||
| 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 | ||||
| %if %{without bootstrap} | ||||
| %py3_build_wheel | ||||
| %else | ||||
| %py3_build | ||||
| %endif | ||||
| 
 | ||||
| %if %{with doc} | ||||
| pushd docs | ||||
| make html | ||||
| make man | ||||
| rm _build/html/.buildinfo | ||||
| popd | ||||
| export PYTHONPATH=./src/ | ||||
| # from tox.ini | ||||
| sphinx-build-3 -b html docs/html docs/build/html | ||||
| sphinx-build-3 -b man  docs/man  docs/build/man  -c docs/html | ||||
| rm -rf docs/build/html/{.doctrees,.buildinfo} | ||||
| %endif | ||||
| 
 | ||||
| 
 | ||||
| %install | ||||
| %if %{without bootstrap} | ||||
| %py3_install_wheel %{python3_wheelname} | ||||
| %else | ||||
| %py3_install | ||||
| %endif | ||||
| 
 | ||||
| rm %{buildroot}%{_bindir}/pip | ||||
| # The following is similar to %%pyproject_install, but we don't have | ||||
| # /usr/bin/pip yet, so we install using the wheel directly. | ||||
| # (This is not standard wheel usage, but the pip wheel supports it -- see | ||||
| #  pip/__main__.py) | ||||
| %{python3} dist/%{python_wheel_name}/pip install \ | ||||
|     --root %{buildroot} \ | ||||
|     --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} | ||||
| pushd docs/build/man | ||||
| install -d %{buildroot}%{_mandir}/man1 | ||||
| install -pm0644 docs/_build/man/*.1 %{buildroot}%{_mandir}/man1/pip3.1 | ||||
| %endif # with doc | ||||
| for MAN in *1; do | ||||
| 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} | ||||
| PYTHONPATH=%{buildroot}%{python3_sitelib} \ | ||||
|     %{buildroot}%{_bindir}/pip3 completion --bash \ | ||||
|     %{buildroot}%{_bindir}/pip completion --bash \ | ||||
|     > %{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/ \ | ||||
|     %{buildroot}%{bashcompdir}/pip3 | ||||
| 
 | ||||
| 
 | ||||
| # 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-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 | ||||
| # (Patch3) won't work | ||||
| echo rpm > %{buildroot}%{python3_sitelib}/pip-%{version}.dist-info/INSTALLER | ||||
| # Make sure the INSTALLER is not pip and remove RECORD | ||||
| # %%pyproject macros do this for all packages | ||||
| 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} | ||||
| %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 | ||||
| 
 | ||||
| 
 | ||||
| %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} | ||||
| %license LICENSE.txt | ||||
| %doc README.rst | ||||
| # The pip3 binary is created using alternatives | ||||
| # defined in the python36 package | ||||
| %license %{python3_sitelib}/pip-%{upstream_version}.dist-info/LICENSE.txt | ||||
| %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} | ||||
| %{python3_sitelib}/pip* | ||||
| %dir %{bashcompdir} | ||||
| %{bashcompdir}/pip* | ||||
| %{bashcompdir}/pip3 | ||||
| 
 | ||||
| %if %{with doc} | ||||
| %files doc | ||||
| %license LICENSE.txt | ||||
| %doc README.rst | ||||
| %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} | ||||
| %doc docs/build/html | ||||
| %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 | ||||
| * 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 | ||||
| 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) | ||||
| 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 | ||||
| - Resolves: rhbz#2006788 | ||||
| - Resolves: rhbz#2006795 | ||||
| 
 | ||||
| * Tue Oct 05 2021 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-21 | ||||
| - Support of yanked releases | ||||
| Resolves: rhbz#2000135 | ||||
| * Mon Sep 13 2021 Miro Hrončok <mhroncok@redhat.com> - 21.2.3-2 | ||||
| - Fix broken uninstallation by a bogus downstream patch | ||||
| 
 | ||||
| * Mon Jun 07 2021 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-20 | ||||
| - Fix for CVE-2021-3572 - pip incorrectly handled unicode separators in git references | ||||
| Resolves: rhbz#1962856 | ||||
| * Mon Sep 13 2021 Miro Hrončok <mhroncok@redhat.com> - 21.2.3-1 | ||||
| - Update to 21.2.3 | ||||
| - Resolves: rhbz#1985635 | ||||
| 
 | ||||
| * Fri Jan 08 2021 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-19 | ||||
| - Fix bash completion files and simplify spec | ||||
| Resolves: rhbz#1904478 | ||||
| * Mon Sep 13 2021 Lumír Balhar <lbalhar@redhat.com> - 21.1.3-1 | ||||
| - Update to 21.1.3 | ||||
| Resolves: rhbz#1976449 | ||||
| 
 | ||||
| * Wed Aug 19 2020 Tomas Orsava <torsava@redhat.com> - 9.0.3-18 | ||||
| - Patch for pip install <url> allow directory traversal, leading to arbitrary file write | ||||
| Resolves: rhbz#1868016 | ||||
| * Mon Sep 13 2021 Karolina Surma <ksurma@redhat.com> - 21.1.2-1 | ||||
| - Update to 21.1.2 | ||||
| Resolves: rhbz#1963433 | ||||
| 
 | ||||
| * Wed Mar 04 2020 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-17 | ||||
| - Remove unused CA bundle from the bundled requests library | ||||
| Resolves: rhbz#1775200 | ||||
| * Mon Sep 13 2021 Karolina Surma <ksurma@redhat.com> - 21.1.1-1 | ||||
| - Update to 21.1.1 | ||||
| 
 | ||||
| * Mon Jan 13 2020 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-16 | ||||
| - Add four new patches for CVEs in bundled urllib3 and requests | ||||
| CVE-2018-20060, CVE-2019-11236, CVE-2019-11324, CVE-2018-18074 | ||||
| Resolves: rhbz#1649153 | ||||
| Resolves: rhbz#1700824 | ||||
| Resolves: rhbz#1702473 | ||||
| Resolves: rhbz#1643829 | ||||
| * Tue Aug 10 2021 Mohan Boddu <mboddu@redhat.com> - 21.0.1-6 | ||||
| - Rebuilt for IMA sigs, glibc 2.34, aarch64 flags | ||||
|   Related: rhbz#1991688 | ||||
| 
 | ||||
| * Thu Jun 06 2019 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-15 | ||||
| - Create python-pip-wheel package with the wheel | ||||
| Resolves: rhbz#1718031 | ||||
| * Wed Jul 28 2021 Tomas Orsava <torsava@redhat.com> - 21.0.1-5 | ||||
| - Provide the platform-python-pip name for backwards compatibility | ||||
|   with RHEL 8 | ||||
| - Related: rhbz#1891487 | ||||
| 
 | ||||
| * Wed Mar 13 2019 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-14 | ||||
| - Move bash completion files from platform-python- to python3- subpackage | ||||
| - resolves: rhbz#1664749 | ||||
| * Mon May 17 2021 Karolina Surma <ksurma@redhat.com> - 21.0.1-4 | ||||
| - Backport security fixes from pip 21.1.1 | ||||
| 
 | ||||
| * 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 | ||||
| - Resolves: rhbz#1655255 | ||||
| 
 | ||||
| * Wed Nov 28 2018 Tomas Orsava <torsava@redhat.com> - 9.0.3-12 | ||||
| - Do not show the "new version of pip" warning outside of venv | ||||
| - Resolves: rhbz#1656171 | ||||
| * Thu Nov 22 2018 Miro Hrončok <mhroncok@redhat.com> - 18.1-1 | ||||
| - Update to 18.1 (#1652089) | ||||
| 
 | ||||
| * 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 | ||||
|   when pip install -U is executed. Patch by Michal Cyprian. | ||||
|   Resolves: rhbz#1626408. | ||||
|   when pip install -U is executed. Original patch by Michal Cyprian. | ||||
|   Resolves: rhbz#1550368. | ||||
| 
 | ||||
| * Fri Nov 16 2018 Tomas Orsava <torsava@redhat.com> - 9.0.3-10 | ||||
| - Bump the NVR so it's higher than previous builds of python3-pip that have | ||||
|   mistakenly gotten into the python27 module build when we were dealing with an | ||||
|   MBS filtering problem. See BZ#1650568. | ||||
| - Resolves: rhbz#1638836 | ||||
| * Wed Aug 08 2018 Miro Hrončok <mhroncok@redhat.com> - 18.0-3 | ||||
| - Create python-pip-wheel package with the wheel | ||||
| 
 | ||||
| * Mon Nov 12 2018 Lumír Balhar <lbalhar@redhat.com> - 9.0.3-6 | ||||
| - python3-pip requires python36 and obsoletes previous version | ||||
|   where python3- and platform-python- were in one package | ||||
| - Resolves: rhbz#1638836 | ||||
| * Tue Jul 31 2018 Miro Hrončok <mhroncok@redhat.com> - 18.0-2 | ||||
| - Remove redundant "Unicode" from License | ||||
| 
 | ||||
| * Mon Oct 22 2018 Tomas Orsava <torsava@redhat.com> - 9.0.3-5 | ||||
| - Split part of the python3-pip package into platform-python-pip | ||||
| - python3-pip will only contain binaries in /usr/bin | ||||
| - Resolves: rhbz#1638836 | ||||
| * Mon Jul 23 2018 Marcel Plch <mplch@redhat.com> - 18.0-7 | ||||
| - Update to 18.0 | ||||
| 
 | ||||
| * Mon Aug 06 2018 Petr Viktorin <pviktori@redhat.com> - 9.0.3-4 | ||||
| - Remove the python2 subpackage | ||||
| - Remove unversioned executables (only *-3.6 should be provided) | ||||
| * Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 9.0.3-6 | ||||
| - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild | ||||
| 
 | ||||
| * Mon Aug 06 2018 Charalampos Stratakis <cstratak@redhat.com> - 9.0.3-3 | ||||
| - Correct license information | ||||
| * Mon Jun 18 2018 Miro Hrončok <mhroncok@redhat.com> - 9.0.3-5 | ||||
| - Rebuilt for Python 3.7 | ||||
| 
 | ||||
| * Mon Jun 25 2018 Petr Viktorin <pviktori@redhat.com> - 9.0.3-2 | ||||
| - Don't build the python2 subpackage | ||||
|   https://bugzilla.redhat.com/show_bug.cgi?id=1594335 | ||||
| * Wed Jun 13 2018 Miro Hrončok <mhroncok@redhat.com> - 9.0.3-4 | ||||
| - Bootstrap for Python 3.7 | ||||
| 
 | ||||
| * 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 | ||||
| - Update to 9.0.3 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user