diff --git a/tests/test_app.py b/tests/test_app.py index f2fc37e..681fae3 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -261,3 +261,51 @@ def test_overview_is_compact_deterministic_and_light_model_friendly(monkeypatch) assert [item["code"] for item in result["findings"]] == [ "host_unreachable", "service_auth_failed", "backup_warning", "disk_high" ] + + +def test_proxy_route_validation_restricts_domain_and_upstream(): + assert app._validate_proxy_route("speed.guck.tv", "127.0.0.1:8080") == ( + "speed.guck.tv", "127.0.0.1:8080", "guck.tv", "speed" + ) + + for domain, upstream in [ + ("guck.tv", "127.0.0.1:8080"), + ("speed.evil.example", "127.0.0.1:8080"), + ("speed.guck.tv", "10.0.0.1:8080"), + ("speed.guck.tv", "127.0.0.1:70000"), + ("speed.guck.tv;rm", "127.0.0.1:8080"), + ]: + try: + app._validate_proxy_route(domain, upstream) + except ValueError: + pass + else: + raise AssertionError(f"unsafe route accepted: {domain} -> {upstream}") + + +def test_proxy_route_endpoint_configures_caddy_and_dns(monkeypatch): + calls = [] + + def fake_caddy(domain, upstream): + calls.append(("caddy", domain, upstream)) + return {"status": "reloaded", "backup": "/app-config/caddy/Caddyfile.bak-test"} + + async def fake_dns(zone, name): + calls.append(("dns", zone, name)) + return {"zone_id": 123, "records": ["A", "AAAA"]} + + monkeypatch.setattr(app, "_configure_caddy_route", fake_caddy) + monkeypatch.setattr(app, "_upsert_dns_records", fake_dns) + with TestClient(app.app) as client: + response = client.post( + "/vps/proxy-route", + headers={"Authorization": "Bearer test-token"}, + json={"domain": "speed.guck.tv", "upstream": "127.0.0.1:8080"}, + ) + + assert response.status_code == 200 + assert response.json()["status"] == "configured" + assert calls == [ + ("caddy", "speed.guck.tv", "127.0.0.1:8080"), + ("dns", "guck.tv", "speed"), + ]