11import base64
22import os
3+ import re
34import tarfile
45
56from io import BytesIO
3940
4041@pytest .fixture
4142def private_package_tar (tmp_path : Path ):
43+ """A private package to be served from the default port"""
4244 sdist_path = (
4345 clone_test_dir ("test-pip-repositories" , tmp_path ) / "fake-private-package-1.0.0"
4446 )
@@ -49,11 +51,29 @@ def private_package_tar(tmp_path: Path):
4951 return tar_path
5052
5153
54+ @pytest .fixture
55+ def private_package_tar_custom_port (tmp_path : Path ):
56+ """A second private package to be served from a non-default port"""
57+ sdist_path = (
58+ clone_test_dir ("test-pip-repositories" , tmp_path )
59+ / "fake-private-package-custom-port-1.0.0"
60+ )
61+ assert sdist_path .exists ()
62+ tar_path = sdist_path / "fake-private-package-custom-port-1.0.0.tar.gz"
63+ with tarfile .open (tar_path , "w:gz" ) as tar :
64+ tar .add (sdist_path , arcname = os .path .basename (sdist_path ))
65+ return tar_path
66+
67+
5268@pytest .fixture (
5369 autouse = True ,
5470 params = ["response_url_without_credentials" , "response_url_with_credentials" ],
5571)
56- def mock_private_pypi (private_package_tar : Path , request : pytest .FixtureRequest ):
72+ def mock_private_pypi ( # noqa: C901
73+ private_package_tar : Path ,
74+ private_package_tar_custom_port : Path ,
75+ request : pytest .FixtureRequest ,
76+ ):
5777 with requests_mock .Mocker (real_http = True ) as mocker :
5878 fixture_request = request
5979
@@ -82,11 +102,14 @@ def _make_response(
82102 response .raw .write (file_handler .read ())
83103 response .raw .seek (0 )
84104
85- url = urlparse (request .url )
86105 if fixture_request .param == "response_url_with_credentials" :
87106 response .url = request .url
88107 else :
89- response .url = request .url .replace (url .netloc , url .hostname )
108+ # Strip credentials using regex, preserving port if present:
109+ # ^([^:]+://) - Capture group 1: scheme (http:// or https://)
110+ # [^@]+@ - Match and remove credentials (anything up to @)
111+ # \1 - Replace with just the captured scheme
112+ response .url = re .sub (r"^([^:]+://)[^@]+@" , r"\1" , request .url )
90113 response .reason = reason
91114 return response
92115
@@ -105,22 +128,64 @@ def _parse_auth(request: requests.Request) -> Tuple[str, str]:
105128
106129 @mocker ._adapter .add_matcher
107130 def handle_request (request : requests .Request ) -> Optional [requests .Response ]:
131+ """Intercept requests to private-pypi.org and private-pypi-custom-port.org.
132+
133+ Requests to other hosts are passed through to the real internet.
134+
135+ On private-pypi.org:80, we publish fake-private-package.
136+
137+ On private-pypi-custom-port.org:8080, we publish fake-private-package-custom-port.
138+ """
108139 url = urlparse (request .url )
109- if url .hostname != "private-pypi.org" :
140+ if url .hostname not in ["private-pypi.org" , "private-pypi-custom-port.org" ]:
141+ # Bail out and use normal requests.get()
110142 return None
111143 username , password = _parse_auth (request )
112144 if username != _PRIVATE_REPO_USERNAME or password != _PRIVATE_REPO_PASSWORD :
113145 return _make_response (request , status = 401 , reason = "Not authorized" )
114146 path = url .path .rstrip ("/" )
115- if path == "/api/pypi/simple" :
116- return _make_response (request , status = 200 , text = _PRIVATE_REPO_ROOT )
117- if path == "/api/pypi/simple/fake-private-package" :
118- return _make_response (request , status = 200 , text = _PRIVATE_REPO_PACKAGE )
119- if path == "/files/fake-private-package-1.0.0.tar.gz" :
120- return _make_response (
121- request , status = 200 , file = str (private_package_tar )
122- )
123- return _make_response (request , status = 404 , reason = "Not Found" )
147+ if url .port :
148+ port = url .port
149+ elif url .scheme == "https" :
150+ port = 443
151+ elif url .scheme == "http" :
152+ port = 80
153+ else :
154+ raise ValueError (f"Unknown scheme: { url .scheme } " )
155+ if url .hostname == "private-pypi.org" :
156+ if port != 80 :
157+ return None
158+ text = ""
159+ file = None
160+ if path == "/api/pypi/simple" :
161+ text = _PRIVATE_REPO_ROOT
162+ if path == "/api/pypi/simple/fake-private-package" :
163+ text = _PRIVATE_REPO_PACKAGE
164+ if path == "/files/fake-private-package-1.0.0.tar.gz" :
165+ file = str (private_package_tar )
166+ if text == "" and file is None :
167+ return _make_response (request , status = 404 , reason = "Not Found" )
168+ return _make_response (request , status = 200 , text = text , file = file )
169+ elif url .hostname == "private-pypi-custom-port.org" :
170+ if port != 8080 :
171+ return None
172+ text = ""
173+ file = None
174+ if path == "/api/pypi/simple" :
175+ text = _PRIVATE_REPO_ROOT .replace (
176+ "fake-private-package" , "fake-private-package-custom-port"
177+ )
178+ if path == "/api/pypi/simple/fake-private-package-custom-port" :
179+ text = _PRIVATE_REPO_PACKAGE .replace (
180+ "fake-private-package" , "fake-private-package-custom-port"
181+ )
182+ if path == "/files/fake-private-package-custom-port-1.0.0.tar.gz" :
183+ file = str (private_package_tar_custom_port )
184+ if text == "" and file is None :
185+ return _make_response (request , status = 404 , reason = "Not Found" )
186+ return _make_response (request , status = 200 , text = text , file = file )
187+ else :
188+ return None
124189
125190 yield
126191
@@ -157,24 +222,30 @@ def test_it_uses_pip_repositories_with_env_var_substitution(
157222 lockfile_content = lockfile_path .read_text (encoding = "utf-8" )
158223 packages = {package .name : package for package in lockfile .package }
159224
160- # AND the private package is in the lockfile
161- package = packages .get ("fake-private-package" )
162- assert package , lockfile_content
163-
164- package_url = urlparse (package .url )
165-
166- # AND the package was sourced from the private repository
167- assert package_url .hostname == "private-pypi.org" , (
168- "Package was fetched from incorrect host. See full lock-file:\n "
169- + lockfile_content
170- )
171-
172- # AND environment variables are occluded
173- assert package_url .username == "$PIP_USER" , (
174- "User environment variable was not respected, See full lock-file:\n "
175- + lockfile_content
176- )
177- assert package_url .password == "$PIP_PASSWORD" , (
178- "Password environment variable was not respected, See full lock-file:\n "
179- + lockfile_content
180- )
225+ # AND the private packages are in the lockfile
226+ for package_name in ["fake-private-package" , "fake-private-package-custom-port" ]:
227+ package = packages .get (package_name )
228+ assert package , lockfile_content
229+
230+ package_url = urlparse (package .url )
231+
232+ # AND the package was sourced from the private repository
233+ expected_hostname = (
234+ "private-pypi.org"
235+ if package_name == "fake-private-package"
236+ else "private-pypi-custom-port.org"
237+ )
238+ assert package_url .hostname == expected_hostname , (
239+ "Package was fetched from incorrect host. See full lock-file:\n "
240+ + lockfile_content
241+ )
242+
243+ # AND environment variables are occluded
244+ assert package_url .username == "$PIP_USER" , (
245+ "User environment variable was not respected, See full lock-file:\n "
246+ + lockfile_content
247+ )
248+ assert package_url .password == "$PIP_PASSWORD" , (
249+ "Password environment variable was not respected, See full lock-file:\n "
250+ + lockfile_content
251+ )
0 commit comments