"""Unit tests for safe_next_url — the auth post-login return-path guard.""" from steward.auth.middleware import safe_next_url def test_relative_path_passes(): assert safe_next_url("/hosts/") == "/hosts/" assert safe_next_url("/hosts/abc?range=24h") == "/hosts/abc?range=24h" def test_full_url_reduced_to_path(): # HTMX HX-Current-URL is absolute; we keep only the same-site path+query. assert safe_next_url("http://steward.local/d/1") == "/d/1" assert safe_next_url("https://steward.local/hosts/x?a=1") == "/hosts/x?a=1" def test_offsite_host_is_dropped_not_redirected(): # A crafted absolute URL can't become an open redirect — netloc is discarded. assert safe_next_url("http://evil.com/phish") == "/phish" def test_protocol_relative_rejected(): assert safe_next_url("//evil.com/x") is None assert safe_next_url("/\\evil.com") is None def test_scheme_only_rejected(): assert safe_next_url("javascript:alert(1)") is None def test_auth_pages_not_returned_to(): assert safe_next_url("/login") is None assert safe_next_url("/login?next=/x") is None assert safe_next_url("/logout") is None assert safe_next_url("/setup") is None def test_empty_and_none(): assert safe_next_url(None) is None assert safe_next_url("") is None