"""Route and request-boundary contracts for the Atlas Gitea client.""" from __future__ import annotations import urllib.error import urllib.request import pytest from testing.tests.test_hermes_gitea_support import HEAD_SHA, Response, _load def test_default_opener_rejects_redirects_under_an_absolute_deadline(monkeypatch): client = _load() source = urllib.request.Request( "https://scm.bstein.dev/api/v1/repos/titan/cassandra", headers={"Authorization": "token redirect-sentinel"}, ) with pytest.raises(urllib.error.URLError) as exc: client.deadline_http._RejectRedirect().redirect_request( source, None, 302, "Found", {}, "https://evil.example/collect", ) assert "redirect-sentinel" not in str(exc.value) seen = [] monkeypatch.setattr( client.deadline_http, "open_bounded", lambda request, *, maximum, timeout: seen.append( (request, maximum, timeout) ), ) client._safe_urlopen(source, 30) assert seen == [(source, client.MAX_RESPONSE_BYTES, 30)] @pytest.mark.parametrize( ("base_url", "path"), [ ("https://evil.example", "/api/v1/repos/titan/cassandra"), ("http://scm.bstein.dev", "/api/v1/repos/titan/cassandra"), ("https://scm.bstein.dev:443", "/api/v1/repos/titan/cassandra"), ("https://scm.bstein.dev/", "/api/v1/repos/titan/cassandra"), ("HTTPS://scm.bstein.dev", "/api/v1/repos/titan/cassandra"), ("https://SCM.bstein.dev", "/api/v1/repos/titan/cassandra"), ("https://user@scm.bstein.dev", "/api/v1/repos/titan/cassandra"), ("https://scm.bstein.dev", "https://evil.example/api/v1/repos/titan/cassandra"), ("https://scm.bstein.dev", "/api/v1/repos/evil/cassandra"), ("https://scm.bstein.dev", "/api/v1/repos/%61tlas/cassandra"), ("https://scm.bstein.dev", "/api/v1/repos/titan/../admin"), ], ) def test_host_owner_and_path_escape_attempts_are_rejected(base_url: str, path: str): client = _load() with pytest.raises(client.PolicyError): client.build_request("GET", path, base_url=base_url, token="secret") @pytest.mark.parametrize( "path", [ "/api/v1/repos/titan/cassandra/pulls/1\nHost: evil.example", "/api/v1/repos/titan/cassandra/pulls/1\r\nX-Test: value", "/api/v1/repos/titan/cassandra/pulls/1\tignored", "/api/v1/repos/titan/cassandra/pulls/1\x00ignored", "/api/v1/repos/titan/cassandra/pulls/1\x1fignored", "/api/v1/repos/titan/cassandra/pulls/1\x7fignored", "/api/v1/repos/titan/cassandra\\pulls\\1", "/api/v1/repos/titan/cassandra/pulls/%31", "/api/v1/repos/titan/cassandra/pulls/1", " https://scm.bstein.dev/api/v1/repos/titan/cassandra", "https://scm.bstein.dev/api/v1/repos/titan/cassandra", ], ) def test_raw_noncanonical_target_is_rejected_before_urlsplit_and_opener( path: str, monkeypatch ): client = _load() split_called = False opener_called = False original_urlsplit = client.urllib.parse.urlsplit def urlsplit(*args, **kwargs): nonlocal split_called split_called = True return original_urlsplit(*args, **kwargs) def opener(*_args, **_kwargs): nonlocal opener_called opener_called = True return Response(b"{}") monkeypatch.setattr(client.urllib.parse, "urlsplit", urlsplit) with pytest.raises(client.PolicyError): client.read(path, token="runtime", opener=opener) assert split_called is False assert opener_called is False @pytest.mark.parametrize( "path", [ "/api/v1/repos/titan/cassandra/pulls/1?", "//scm.bstein.dev/api/v1/repos/titan/cassandra", "/api/v1/repos/titan/cassandra/./pulls/1", "/api/v1/repos/titan/cassandra/../admin", "/api/v1/repos/titan/cassandra//pulls/1", "/api/v1/repos/titan/cassandra/pulls/1?limit=01", ], ) def test_noncanonical_round_trip_or_segments_never_reach_opener(path: str): client = _load() opener_called = False def opener(*_args, **_kwargs): nonlocal opener_called opener_called = True return Response(b"{}") with pytest.raises(client.PolicyError): client.read(path, token="runtime", opener=opener) assert opener_called is False @pytest.mark.parametrize( "path", [ "/api/v1/user", "/api/v1/repos/titan/cassandra", "/api/v1/repos/titan/cassandra/pulls?state=open&limit=20&page=1", "/api/v1/repos/titan/cassandra/pulls/7", "/api/v1/repos/titan/cassandra/pulls/7/commits?limit=20", "/api/v1/repos/titan/cassandra/pulls/7/files?page=1", "/api/v1/repos/titan/cassandra/branches", "/api/v1/repos/titan/cassandra/branches/main", "/api/v1/repos/titan/cassandra/commits?limit=10", f"/api/v1/repos/titan/cassandra/git/commits/{HEAD_SHA}", f"/api/v1/repos/titan/cassandra/commits/{HEAD_SHA}/status", f"/api/v1/repos/titan/cassandra/commits/{HEAD_SHA}/statuses?limit=10", f"/api/v1/repos/titan/cassandra/statuses/{HEAD_SHA}?page=1", ], ) def test_explicit_read_allowlist_accepts_only_engineering_metadata(path: str): client = _load() request = client.build_request( "GET", path, base_url=client.CANONICAL_BASE_URL, token="runtime" ) assert request.method == "GET" def test_the_identity_route_reads_only_the_bare_user_document(): """`/api/v1/user` answers with the broker identity's own metadata. Acceptance tooling uses it to prove the platform's forge identity is not an administrator; every sibling or sub-route stays refused. """ client = _load() assert client.authorize_request("GET", "/api/v1/user", None) == "identity" for path in ( "/api/v1/user?full=true", "/api/v1/user/tokens", "/api/v1/user/emails", "/api/v1/users/atlas", "/api/v1/userx", ): with pytest.raises(client.PolicyError): client.authorize_request("GET", path, None) @pytest.mark.parametrize( "path", [ "/api/v1/repos/titan/cassandra/hooks", "/api/v1/repos/titan/cassandra/actions/secrets", "/api/v1/repos/titan/cassandra/actions/variables", "/api/v1/repos/titan/cassandra/collaborators", "/api/v1/repos/titan/cassandra/branch_protections", "/api/v1/repos/titan/cassandra/keys", "/api/v1/repos/titan/cassandra/pulls/7/reviews", "/api/v1/repos/titan/cassandra/pulls/7/merge", "/api/v1/repos/titan/cassandra/pulls/7.diff", "/api/v1/repos/titan/cassandra/releases", ], ) def test_privileged_or_content_routes_are_denied_even_for_get(path: str): client = _load() with pytest.raises(client.PolicyError, match="outside the metadata read allowlist"): client.authorize_request("GET", path, None) @pytest.mark.parametrize( "path", [ "/api/v1/repos/titan/cassandra/pulls?limit=51", "/api/v1/repos/titan/cassandra/pulls?state=merged", "/api/v1/repos/titan/cassandra/pulls?private=true", "/api/v1/repos/titan/cassandra/pulls?limit=1&limit=2", "/api/v1/repos/titan/cassandra?p=1", ], ) def test_read_query_is_bounded(path: str): client = _load() with pytest.raises(client.PolicyError): client.authorize_request("GET", path, None) @pytest.mark.parametrize( "query", [ "page=0", "page=10001", "page=01", "limit=0", "limit=51", "limit=01", "page=" + "9" * 4000, "page=0", "page=%EF%BC%90", "state=%6fpen", "p%61ge=1", "page=1&page=2", "page=1&" + "x" * 17 + "=1", "state=" + "x" * 17, "page=1&limit=2&state=open&extra=3", ], ) def test_read_query_requires_canonical_bounded_ascii(query: str): client = _load() with pytest.raises(client.PolicyError): client.authorize_request( "GET", f"/api/v1/repos/titan/cassandra/pulls?{query}", None ) @pytest.mark.parametrize( "suffix", [ "pulls/{number}", "pulls/{number}.patch", "pulls/{number}.diff", "pulls/{number}/commits", "pulls/{number}/files", "commits/{number}/status", "commits/{number}/statuses", "statuses/{number}", "branches/{number}", ], ) def test_oversized_numeric_or_captured_path_never_reaches_opener(suffix: str): client = _load() called = False def opener(*_args, **_kwargs): nonlocal called called = True return Response(b"{}") path = "/api/v1/repos/titan/cassandra/" + suffix.format(number="9" * 4000) with pytest.raises(client.PolicyError): client.read(path, token="runtime", opener=opener) assert called is False @pytest.mark.parametrize( "number", ["0", "01", "2147483648", "12", "%31", "12345678901"], ) @pytest.mark.parametrize("tail", ["", ".patch", ".diff", "/commits", "/files"]) def test_noncanonical_or_out_of_range_pr_number_never_reaches_opener( number: str, tail: str ): client = _load() called = False def opener(*_args, **_kwargs): nonlocal called called = True return Response(b"{}") with pytest.raises(client.PolicyError): client.read( f"/api/v1/repos/titan/cassandra/pulls/{number}{tail}", token="runtime", opener=opener, ) assert called is False def test_maximum_bounded_pr_number_is_readable(): client = _load() called = False def opener(*_args, **_kwargs): nonlocal called called = True return Response(b"{}") assert ( client.read( "/api/v1/repos/titan/cassandra/pulls/2147483647", token="runtime", opener=opener, ) == b"{}" ) assert called is True