Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions tests/test_url_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,33 @@ def test_path_and_scheme_are_preserved() -> None:
assert out.startswith("https://example.com:8443/api/v1/foo?")
parsed = dict(parse_qsl(urlparse(out).query))
assert parsed == {"token": MASK, "page": "1"}


# ── IPv6 host edge cases (issue #4) ──────────────────────────────────────


def test_ipv6_loopback_with_port_token_redacted() -> None:
"""IPv6 loopback with port: token redacted, host/port preserved."""
out = redact_url_query("http://[::1]:8080/api?token=abc")
assert "abc" not in out
parsed = dict(parse_qsl(urlparse(out).query))
assert parsed == {"token": MASK}
assert "[::1]" in out
assert ":8080" in out


def test_ipv6_full_address_without_port() -> None:
"""Full IPv6 address without port: api_key redacted, page preserved."""
out = redact_url_query("http://[2001:db8::1]/api?api_key=abc&page=1")
assert "abc" not in out
parsed = dict(parse_qsl(urlparse(out).query))
assert parsed == {"api_key": MASK, "page": "1"}


def test_ipv6_no_misparse_brackets() -> None:
"""IPv6 brackets must not be confused with query delimiters."""
out = redact_url_query("http://[fe80::1%25eth0]/path?token=secret")
assert "secret" not in out
parsed = dict(parse_qsl(urlparse(out).query))
assert parsed == {"token": MASK}
assert "[fe80::1%25eth0]" in out