Skip to content

Commit 8f0ed32

Browse files
committed
Redact URLs in Collecting... logs
1 parent 2333ef3 commit 8f0ed32

File tree

5 files changed

+39
-2
lines changed

5 files changed

+39
-2
lines changed

news/12350.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Redact password from URLs in some additional places.

src/pip/_internal/operations/prepare.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
display_path,
4848
hash_file,
4949
hide_url,
50+
redact_auth_from_requirement,
5051
)
5152
from pip._internal.utils.temp_dir import TempDirectory
5253
from pip._internal.utils.unpacking import unpack_file
@@ -277,7 +278,7 @@ def _log_preparing_link(self, req: InstallRequirement) -> None:
277278
information = str(display_path(req.link.file_path))
278279
else:
279280
message = "Collecting %s"
280-
information = str(req.req or req)
281+
information = redact_auth_from_requirement(req.req) if req.req else str(req)
281282

282283
# If we used req.req, inject requirement source if available (this
283284
# would already be included if we used req directly)

src/pip/_internal/req/req_install.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
display_path,
5050
hide_url,
5151
is_installable_dir,
52+
redact_auth_from_requirement,
5253
redact_auth_from_url,
5354
)
5455
from pip._internal.utils.packaging import safe_extra
@@ -188,7 +189,7 @@ def __init__(
188189

189190
def __str__(self) -> str:
190191
if self.req:
191-
s = str(self.req)
192+
s = redact_auth_from_requirement(self.req)
192193
if self.link:
193194
s += " from {}".format(redact_auth_from_url(self.link.url))
194195
elif self.link:

src/pip/_internal/utils/misc.py

+8
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
cast,
3636
)
3737

38+
from pip._vendor.packaging.requirements import Requirement
3839
from pip._vendor.pyproject_hooks import BuildBackendHookCaller
3940
from pip._vendor.tenacity import retry, stop_after_delay, wait_fixed
4041

@@ -578,6 +579,13 @@ def redact_auth_from_url(url: str) -> str:
578579
return _transform_url(url, _redact_netloc)[0]
579580

580581

582+
def redact_auth_from_requirement(req: Requirement) -> str:
583+
"""Replace the password in a given requirement url with ****."""
584+
if not req.url:
585+
return str(req)
586+
return str(req).replace(req.url, redact_auth_from_url(req.url))
587+
588+
581589
class HiddenText:
582590
def __init__(self, secret: str, redacted: str) -> None:
583591
self.secret = secret

tests/unit/test_utils.py

+26
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from unittest.mock import Mock, patch
1515

1616
import pytest
17+
from pip._vendor.packaging.requirements import Requirement
1718

1819
from pip._internal.exceptions import HashMismatch, HashMissing, InstallationError
1920
from pip._internal.utils.deprecation import PipDeprecationWarning, deprecated
@@ -37,6 +38,7 @@
3738
normalize_path,
3839
normalize_version_info,
3940
parse_netloc,
41+
redact_auth_from_requirement,
4042
redact_auth_from_url,
4143
redact_netloc,
4244
remove_auth_from_url,
@@ -765,6 +767,30 @@ def test_redact_auth_from_url(auth_url: str, expected_url: str) -> None:
765767
assert url == expected_url
766768

767769

770+
@pytest.mark.parametrize(
771+
"req, expected",
772+
[
773+
("pkga", "pkga"),
774+
(
775+
"resolvelib@ "
776+
" git+https://test-user:[email protected]/sarugaku/[email protected]",
777+
"resolvelib@"
778+
" git+https://test-user:****@github.com/sarugaku/[email protected]",
779+
),
780+
(
781+
"resolvelib@"
782+
" git+https://test-user:[email protected]/sarugaku/[email protected]"
783+
" ; python_version>='3.6'",
784+
"resolvelib@"
785+
" git+https://test-user:****@github.com/sarugaku/[email protected]"
786+
' ; python_version >= "3.6"',
787+
),
788+
],
789+
)
790+
def test_redact_auth_from_requirement(req: str, expected: str) -> None:
791+
assert redact_auth_from_requirement(Requirement(req)) == expected
792+
793+
768794
class TestHiddenText:
769795
def test_basic(self) -> None:
770796
"""

0 commit comments

Comments
 (0)