from __future__ import annotations import requests from fastapi.testclient import TestClient from app.main import app def test_legacy_get_bootstrap_url_redirects_to_welcome_page() -> None: with TestClient(app) as client: response = client.get("/workspaces/bootstrap", follow_redirects=False) assert response.status_code in {302, 303, 307} assert response.headers["location"] == "/" def test_bootstrap_workspace_rejects_missing_turnstile_token(monkeypatch, tmp_path) -> None: from app.models import workspace as workspace_module from app.models.workspace import WorkspaceRepository repo = WorkspaceRepository(base_path=tmp_path / "workspaces") monkeypatch.setattr(workspace_module, "_workspace_repo", repo) with TestClient(app) as client: response = client.post("/workspaces/bootstrap", follow_redirects=False) assert response.status_code == 303 assert response.headers["location"] == "/?captcha_error=1" def test_bootstrap_workspace_creates_workspace_when_turnstile_verification_succeeds(monkeypatch, tmp_path) -> None: from app.models import workspace as workspace_module from app.models.workspace import WorkspaceRepository from app.services import turnstile as turnstile_module repo = WorkspaceRepository(base_path=tmp_path / "workspaces") monkeypatch.setattr(workspace_module, "_workspace_repo", repo) monkeypatch.setattr(turnstile_module, "verify_turnstile_token", lambda *args, **kwargs: True) with TestClient(app) as client: response = client.post( "/workspaces/bootstrap", data={"cf-turnstile-response": "token-ok"}, follow_redirects=False, ) assert response.status_code in {302, 303, 307} workspace_id = response.headers["location"].strip("/") assert repo.workspace_exists(workspace_id) assert response.cookies.get("workspace_id") == workspace_id def test_bootstrap_workspace_rejects_failed_turnstile_verification(monkeypatch, tmp_path) -> None: from app.models import workspace as workspace_module from app.models.workspace import WorkspaceRepository from app.services import turnstile as turnstile_module repo = WorkspaceRepository(base_path=tmp_path / "workspaces") monkeypatch.setattr(workspace_module, "_workspace_repo", repo) monkeypatch.setattr(turnstile_module, "verify_turnstile_token", lambda *args, **kwargs: False) with TestClient(app) as client: response = client.post( "/workspaces/bootstrap", data={"cf-turnstile-response": "token-bad"}, follow_redirects=False, ) assert response.status_code == 303 assert response.headers["location"] == "/?captcha_error=1" assert not any(repo.base_path.iterdir()) def test_turnstile_settings_use_default_test_keys_when_env_is_missing(monkeypatch) -> None: from app.services import turnstile as turnstile_module monkeypatch.setenv("APP_ENV", "test") monkeypatch.setenv("APP_ENV", "test") monkeypatch.delenv("TURNSTILE_SITE_KEY", raising=False) monkeypatch.delenv("TURNSTILE_SECRET_KEY", raising=False) settings = turnstile_module.load_turnstile_settings() assert settings.site_key == turnstile_module.DEFAULT_TURNSTILE_TEST_SITE_KEY assert settings.secret_key == turnstile_module.DEFAULT_TURNSTILE_TEST_SECRET_KEY assert settings.enabled is True assert settings.uses_test_keys is True assert settings.uses_test_keys is True def test_turnstile_settings_fail_loudly_without_keys_outside_dev(monkeypatch) -> None: from app.services import turnstile as turnstile_module monkeypatch.setenv("APP_ENV", "production") monkeypatch.delenv("TURNSTILE_SITE_KEY", raising=False) monkeypatch.delenv("TURNSTILE_SECRET_KEY", raising=False) import pytest with pytest.raises(RuntimeError, match="Turnstile keys must be configured"): turnstile_module.load_turnstile_settings() def test_turnstile_verification_returns_false_on_transport_error(monkeypatch) -> None: from app.services import turnstile as turnstile_module monkeypatch.setenv("APP_ENV", "test") def raise_error(*args, **kwargs): raise requests.RequestException("boom") monkeypatch.setattr(turnstile_module.requests, "post", raise_error) assert turnstile_module.verify_turnstile_token("token") is False def test_turnstile_settings_support_always_fail_test_keys(monkeypatch) -> None: from app.services import turnstile as turnstile_module monkeypatch.setenv("APP_ENV", "test") monkeypatch.setenv("TURNSTILE_SITE_KEY", turnstile_module.ALWAYS_FAIL_TURNSTILE_TEST_SITE_KEY) monkeypatch.setenv("TURNSTILE_SECRET_KEY", turnstile_module.ALWAYS_FAIL_TURNSTILE_TEST_SECRET_KEY) settings = turnstile_module.load_turnstile_settings() assert settings.site_key == turnstile_module.ALWAYS_FAIL_TURNSTILE_TEST_SITE_KEY assert settings.secret_key == turnstile_module.ALWAYS_FAIL_TURNSTILE_TEST_SECRET_KEY assert settings.enabled is True assert settings.uses_test_keys is False def test_bootstrap_stays_blocked_under_always_fail_turnstile_test_keys(monkeypatch, tmp_path) -> None: from app.models import workspace as workspace_module from app.models.workspace import WorkspaceRepository from app.services import turnstile as turnstile_module repo = WorkspaceRepository(base_path=tmp_path / "workspaces") monkeypatch.setattr(workspace_module, "_workspace_repo", repo) monkeypatch.setenv("APP_ENV", "test") monkeypatch.setenv("TURNSTILE_SITE_KEY", turnstile_module.ALWAYS_FAIL_TURNSTILE_TEST_SITE_KEY) monkeypatch.setenv("TURNSTILE_SECRET_KEY", turnstile_module.ALWAYS_FAIL_TURNSTILE_TEST_SECRET_KEY) monkeypatch.setattr(turnstile_module, "verify_turnstile_token", lambda *args, **kwargs: False) with TestClient(app) as client: response = client.post( "/workspaces/bootstrap", data={"cf-turnstile-response": "blocked-token"}, follow_redirects=False, ) assert response.status_code == 303 assert response.headers["location"] == "/?captcha_error=1" assert not any(repo.base_path.iterdir())