from __future__ import annotations from collections.abc import Mapping, Sequence from fastapi.testclient import TestClient from game_data_capture.config import ServerConfig from game_data_capture.web.app import ( CaptureRecord, CaptureSessionStatus, ControlOutcome, MediaDescriptor, MutationOutcome, WebConfig, create_app, ) from game_data_capture.web.security import new_bootstrap_token class Control: def status(self) -> CaptureSessionStatus: return CaptureSessionStatus(False, 0, 1) def start_session(self) -> ControlOutcome: return "started" def stop_session(self) -> ControlOutcome: return "stopped" class EmptyCorpus: def list_captures(self, *, limit: int) -> Sequence[CaptureRecord]: return () def get_capture(self, capture_id: str) -> CaptureRecord | None: return None def open_media(self, capture_id: str) -> MediaDescriptor | None: return None def label(self, capture_id: str, classification: Mapping[str, object]) -> MutationOutcome: return "not_found" def reject_preserving_evidence(self, capture_id: str) -> MutationOutcome: return "not_found" def delete_with_retention(self, capture_id: str) -> MutationOutcome: return "not_found" def test_bootstrap_is_one_time_same_origin_and_does_not_enable_permissive_cors() -> None: token = new_bootstrap_token() app = create_app( config=WebConfig(ServerConfig()), capture_control=Control(), corpus=EmptyCorpus(), bootstrap_token=token, ) client = TestClient(app, base_url="http://127.0.0.1:8765") cross_origin = client.post( "/api/bootstrap", headers={"Origin": "http://evil.test"}, json={"token": token} ) accepted = client.post( "/api/bootstrap", headers={"Origin": "http://127.0.0.1:8765"}, json={"token": token} ) replay = client.post( "/api/bootstrap", headers={"Origin": "http://127.0.0.1:8765"}, json={"token": token} ) assert cross_origin.status_code == 403 assert accepted.status_code == 200 assert replay.status_code == 401 assert "access-control-allow-origin" not in accepted.headers