169 lines
6.7 KiB
Python
169 lines
6.7 KiB
Python
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_ignore_real_credentials_in_test_environment(monkeypatch) -> None:
|
|
from app.services import turnstile as turnstile_module
|
|
|
|
monkeypatch.setenv("APP_ENV", "test")
|
|
monkeypatch.setenv("TURNSTILE_SITE_KEY", "real-site-key")
|
|
monkeypatch.setenv("TURNSTILE_SECRET_KEY", "real-secret-key")
|
|
|
|
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
|
|
|
|
|
|
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())
|