"""In-process synthetic HTTP/stream checks; no monolith, provider or live data.""" import asyncio import inspect import json import os from pathlib import Path import tempfile from types import SimpleNamespace import unittest from unittest import mock from fastapi import FastAPI, HTTPException from fastapi.testclient import TestClient from starlette.requests import ClientDisconnect from interactive_chat_share_routes import create_interactive_chat_share_router, COOKIE, HTTP_COOKIE from interactive_chat_shares import InteractiveChatShareStore, csrf_token from public_chat_transcript import PublicTranscriptError from interactive_chat_controls import ChatControlError import interactive_chat_share_web as web class InteractiveShareRouteTests(unittest.TestCase): def setUp(self): temporary = tempfile.TemporaryDirectory(prefix="interactive-share-http-") self.addCleanup(temporary.cleanup) self.root = Path(temporary.name) / "shares" self.origin = "https://share.example.test" self.public_origin = self.origin self.sessions = {"chat-one"} self.load = mock.AsyncMock(return_value={"revision": "1", "messages": [], "busy": False}) self.submit = mock.AsyncMock(return_value={"accepted": True, "queued": True}) self.save = mock.AsyncMock(return_value="private-file-reference") self.wait = mock.AsyncMock(return_value=False) self.control = mock.AsyncMock(return_value={"accepted": True, "result": {"ok": True}}) self.open_video = mock.AsyncMock() def authorize(request): if request.headers.get("x-agentsdock-token") != "synthetic-native-admin" or request.headers.get("origin") or request.headers.get("cookie"): raise HTTPException(403, "Native administration required") self.router = create_interactive_chat_share_router(storage_root=self.root, authorize=authorize, session_exists=lambda session: session in self.sessions, public_base_url=lambda: self.public_origin, load_transcript=self.load, submit_prompt=self.submit, save_upload=self.save, wait_for_change=self.wait, chat_control=self.control, open_video=self.open_video) app = FastAPI() app.include_router(self.router) self.client = TestClient(app, base_url=self.origin, raise_server_exceptions=False) self.client.__enter__() self.addCleanup(self.client.__exit__, None, None, None) self.admin = "/api/admin/interactive-chat-shares/chat-one" self.admin_headers = {"X-AgentsDock-Token": "synthetic-native-admin"} def create(self, **options): response = self.client.post(self.admin, headers=self.admin_headers, json={"confirmed_interactive": True, **options}) self.assertEqual(response.status_code, 201, response.text) return response.json() def redeem(self, share): path, invite = share["path"], share["access_token"] response = self.client.post(path + "/redeem", headers={"Origin": self.origin}, json={"invitation_token": invite}) self.assertEqual(response.status_code, 200, response.text) return path, {"Origin": self.origin, "X-Chat-CSRF": response.json()["csrf"]} def test_scanner_get_never_redeems_and_cookie_is_secure_scoped(self): share = self.create() path = share["path"] self.assertEqual(self.client.get(path).status_code, 200) self.assertEqual(self.client.head(path).status_code, 200) self.assertEqual(self.client.get(path + "/state").status_code, 404) response = self.client.post(path + "/redeem", headers={"Origin": self.origin}, json={"invitation_token": share["access_token"]}) cookie = response.headers["set-cookie"] for flag in ("Secure", "HttpOnly", "SameSite=strict", "Path=" + path): self.assertIn(flag, cookie) self.assertEqual(self.client.post(path + "/redeem", headers={"Origin": self.origin}, json={"invitation_token": share["access_token"]}).status_code, 200) self.assertEqual(self.client.get(path + "/state").json()["messages"], []) self.assertNotIn("session_id", self.client.get(path + "/state").text) def video_fixture(self): path = self.root.parent / "synthetic.mp4" data = b"0123456789abcdef" path.write_bytes(data) handles = [] async def open_video(session_id, handle): descriptor = os.open(path, os.O_RDONLY) handles.append(descriptor) return {"file_fd": descriptor, "filename": path.name, "content_type": "video/mp4", "size": len(data)} self.open_video.side_effect = open_video handle = "video_" + "a" * 16 + "." + "b" * 64 return handle, data, handles def test_scoped_video_requires_cookie_and_grant_before_opening(self): handle, _, _ = self.video_fixture() share = self.create() url = share["path"] + "/media/" + handle for headers in ({}, self.admin_headers, {"Authorization": "Bearer " + share["access_token"]}): self.assertEqual(self.client.get(url, headers=headers).status_code, 404) self.open_video.assert_not_awaited() self.redeem(share) for headers in ({"Origin": "https://foreign.example.test"}, {"Sec-Fetch-Site": "cross-site"}): self.assertEqual(self.client.get(url, headers=headers).status_code, 403) self.assertEqual(self.client.get(url + "?token=ignored").status_code, 403) self.assertEqual(self.client.get(share["path"] + "/media/not-advertised").status_code, 404) self.open_video.assert_not_awaited() other = self.create() self.assertEqual(self.client.get(other["path"] + "/media/" + handle).status_code, 404) def test_scoped_video_range_head_and_revoke_close_every_descriptor(self): handle, data, handles = self.video_fixture() share = self.create() self.redeem(share) url = share["path"] + "/media/" + handle full = self.client.get(url) self.assertEqual((full.status_code, full.content), (200, data)) self.assertEqual(full.headers["content-type"], "video/mp4") self.assertEqual(full.headers["accept-ranges"], "bytes") self.assertEqual(full.headers["cache-control"], "no-store") self.assertIn("media-src 'self'", self.client.get(share["path"]).headers["content-security-policy"]) for value, expected in (("bytes=3-7", data[3:8]), ("bytes=8-", data[8:]), ("bytes=-4", data[-4:])): response = self.client.get(url, headers={"Range": value}) self.assertEqual((response.status_code, response.content), (206, expected)) response = self.client.head(url) self.assertEqual((response.status_code, response.content), (200, b"")) self.assertEqual(response.headers["content-length"], str(len(data))) self.assertEqual(self.client.get(url, headers={"Range": "bytes=99-"}).status_code, 416) for call in self.open_video.await_args_list: self.assertEqual(call.args, ("chat-one", handle)) for descriptor in handles: with self.assertRaises(OSError): os.fstat(descriptor) accepted_calls = self.open_video.await_count self.client.delete(self.admin + "/" + share["id"], headers=self.admin_headers) self.assertEqual(self.client.get(url).status_code, 404) self.assertEqual(self.open_video.await_count, accepted_calls) def test_video_denied_after_open_during_revocation_and_session_removal(self): handle, _, handles = self.video_fixture() share = self.create() self.redeem(share) original = self.open_video.side_effect async def revoked_during_open(session_id, media_id): opened = await original(session_id, media_id) InteractiveChatShareStore.open_existing(self.root).revoke_share(share["id"], session_id=session_id) return opened self.open_video.side_effect = revoked_during_open response = self.client.get(share["path"] + "/media/" + handle) self.assertEqual((response.status_code, response.content), (404, b"")) for descriptor in handles: with self.assertRaises(OSError): os.fstat(descriptor) self.sessions.clear() self.assertEqual(self.client.get(share["path"] + "/media/" + handle).status_code, 404) def test_video_changed_before_response_is_unavailable_and_descriptor_closed(self): handle, _, handles = self.video_fixture() share = self.create() self.redeem(share) original = self.open_video.side_effect async def changed_during_open(session_id, media_id): opened = await original(session_id, media_id) info = os.fstat(opened["file_fd"]) opened["file_revision"] = (info.st_dev, info.st_ino, info.st_size, info.st_mtime_ns, info.st_ctime_ns - 1, info.st_uid, info.st_mode, info.st_nlink) return opened self.open_video.side_effect = changed_during_open response = self.client.get(share["path"] + "/media/" + handle) self.assertEqual(response.status_code, 404) self.assertNotIn(str(self.root), response.text) for descriptor in handles: with self.assertRaises(OSError): os.fstat(descriptor) def test_separate_reusable_token_allows_two_browsers_and_revokes_both(self): share = self.create() self.assertNotIn(share["access_token"], share["path"]) self.assertNotIn(share["access_token"], share["url"]) self.assertNotIn("#", share["url"]) self.assertNotIn("token_url", share) path, _ = self.redeem(share) with TestClient(self.client.app, base_url=self.origin) as other: self.assertEqual(other.get(path + "/state").status_code, 404) entered = other.post(path + "/redeem", headers={"Origin": self.origin}, json={"invitation_token": share["access_token"]}) self.assertEqual(entered.status_code, 200, entered.text) self.assertEqual(other.get(path + "/state").status_code, 200) self.assertEqual(self.client.get(path + "/state").status_code, 200) listing = self.client.get(self.admin, headers=self.admin_headers) self.assertNotIn(share["access_token"], listing.text) self.assertEqual(self.client.delete(self.admin + "/" + share["id"], headers=self.admin_headers).status_code, 200) self.assertEqual(other.get(path + "/state").status_code, 404) self.assertEqual(self.client.get(path + "/state").status_code, 404) def test_http_direct_create_cookie_and_csrf_work_without_public_origin(self): self.public_origin = "" self.origin = "http://192.0.2.42:8080" self.client.base_url = self.origin share = self.create() self.assertEqual(share["url"], self.origin + share["path"]) self.assertEqual(InteractiveChatShareStore.open_existing(self.root).share_origin(share["id"]), self.origin) self.load.assert_not_awaited() path, invite = share["path"], share["access_token"] response = self.client.post(path + "/redeem", headers={"Origin": self.origin}, json={"invitation_token": invite}) self.assertEqual(response.status_code, 200, response.text) cookie = response.headers["set-cookie"] self.assertTrue(cookie.startswith(HTTP_COOKIE + "="), cookie) self.assertNotIn("Secure", cookie) for flag in ("HttpOnly", "SameSite=strict", "Path=" + path): self.assertIn(flag, cookie) self.assertNotIn("Domain=", cookie) self.assertEqual(self.client.get(path + "/state").status_code, 200) csrf = response.json()["csrf"] headers = {"Origin": self.origin, "X-Chat-CSRF": csrf} payload = {"prompt": "A direct HTTP reply", "request_id": "request_http_0001"} for denied in ({}, {"Origin": self.origin}, {**headers, "X-Chat-CSRF": "0" * 64}, {**headers, "Origin": "http://192.0.2.43:8080"}, {**headers, "Sec-Fetch-Site": "cross-site"}): with self.subTest(headers=denied): self.assertEqual(self.client.post(path + "/prompts", headers=denied, json=payload).status_code, 403) self.submit.assert_not_awaited() accepted = self.client.post(path + "/prompts", headers=headers, json=payload) self.assertEqual(accepted.status_code, 202, accepted.text) self.submit.assert_awaited_once() token = next(item.value for item in self.client.cookies.jar if item.name == HTTP_COOKIE) for raw_cookie in (f"{HTTP_COOKIE}={token}; {HTTP_COOKIE}={token}", f"{COOKIE}={token}"): self.assertEqual(self.client.get(path + "/state", headers={"Cookie": raw_cookie}).status_code, 404) def test_share_origin_stays_bound_after_configuration_changes(self): original = self.origin share = self.create() path, headers = self.redeem(share) self.public_origin = "http://192.0.2.44:9090" self.assertEqual(self.client.get(path).status_code, 200) self.assertEqual(self.client.get(path + "/state").status_code, 200) self.assertEqual(self.client.get(self.public_origin + path).status_code, 403) self.assertEqual(self.client.get(path + "/state", headers={"Origin": self.public_origin}).status_code, 403) self.assertEqual(self.client.post(path + "/prompts", headers=headers, json={"prompt": "Still on the original origin", "request_id": "request_bound_001"}).status_code, 202) self.assertEqual(InteractiveChatShareStore.open_existing(self.root).share_origin(share["id"]), original) def test_explicit_http_origin_overrides_configured_https_and_is_bound(self): direct = "http://192.0.2.42:8080" share = self.create(base_url=direct + "/") self.assertEqual(share["url"], direct + share["path"]) path = share["path"] self.assertEqual(self.client.get(path).status_code, 403) self.client.base_url = direct self.origin = direct self.redeem(share) self.assertEqual(self.client.get(path + "/state").status_code, 200) self.assertTrue(any(item.name == HTTP_COOKIE and not item.secure for item in self.client.cookies.jar)) def test_native_connection_creates_lan_share_without_rebinding_existing_share(self): original = self.create(title="Existing connection share") lan_origin = "http://192.0.2.42:7850" share = self.create(base_url=lan_origin + "/", title="LAN collaboration") path = share["path"] self.assertEqual(share["url"], lan_origin + path) self.assertNotIn(share["access_token"], share["url"]) ledger = InteractiveChatShareStore.open_existing(self.root) self.assertEqual(ledger.share_origin(original["id"]), self.origin) self.assertEqual(ledger.share_origin(share["id"]), lan_origin) self.assertEqual(self.client.get(original["path"]).status_code, 200) self.assertEqual(self.client.get(path).status_code, 403) self.assertEqual(self.client.post(path + "/redeem", headers={"Origin": self.origin}, json={"invitation_token": share["access_token"]}).status_code, 403) with TestClient(self.client.app, base_url=lan_origin) as lan: self.assertEqual(lan.get(path).status_code, 200) self.assertEqual(lan.get(path + "/state").status_code, 404) self.assertEqual(lan.get(original["path"]).status_code, 403) self.assertEqual(lan.post(path + "/redeem", headers={"Origin": lan_origin}, json={"invitation_token": "A" * 43}).status_code, 404) entered = lan.post(path + "/redeem", headers={"Origin": lan_origin}, json={"invitation_token": share["access_token"]}) self.assertEqual(entered.status_code, 200, entered.text) cookie = next(item for item in lan.cookies.jar if item.name == HTTP_COOKIE) self.assertFalse(cookie.secure) self.assertFalse(cookie.domain_specified) self.assertEqual(cookie.path, path) self.assertIn("HttpOnly", entered.headers["set-cookie"]) self.assertIn("SameSite=strict", entered.headers["set-cookie"]) self.assertEqual(lan.get(path + "/state").status_code, 200) headers = {"Origin": lan_origin, "X-Chat-CSRF": entered.json()["csrf"]} control = {"action": "turn.steer", "payload": {"prompt": "LAN follow-up"}, "request_id": "control_lan_000001"} for denied in ({"Origin": lan_origin}, {**headers, "Origin": self.origin}, {**headers, "X-Chat-CSRF": "0" * 64}, {**headers, "Sec-Fetch-Site": "cross-site"}): with self.subTest(headers=denied): self.assertEqual(lan.post(path + "/controls", headers=denied, json=control).status_code, 403) self.control.assert_not_awaited() accepted = lan.post(path + "/controls", headers=headers, json=control) self.assertEqual(accepted.status_code, 202, accepted.text) self.control.assert_awaited_once_with("chat-one", "turn.steer", {"prompt": "LAN follow-up"}, share_id=share["id"], request_id=control["request_id"]) self.assertEqual(lan.post(path + "/prompts", headers=headers, json={"prompt": "LAN question", "request_id": "prompt_lan_000001"}).status_code, 202) self.submit.assert_awaited_once() # Even replaying the correct LAN cookie at origin A cannot widen # the immutable share binding or authorize a native control route. self.assertEqual(self.client.get(path + "/state", headers={ "Cookie": HTTP_COOKIE + "=" + cookie.value}).status_code, 403) self.assertEqual(self.client.delete(self.admin + "/" + share["id"], headers=self.admin_headers).status_code, 200) self.assertEqual(lan.get(path + "/state").status_code, 404) self.assertEqual(lan.post(path + "/redeem", headers={"Origin": lan_origin}, json={"invitation_token": share["access_token"]}).status_code, 404) def test_invalid_explicit_origin_does_not_create_a_grant(self): for base in (None, "", False, "ftp://example.test", "http://example.test/private", "http://@example.test", "http://user:password@example.test", "http://example.test?token=value"): with self.subTest(base=base): response = self.client.post(self.admin, headers=self.admin_headers, json={"confirmed_interactive": True, "base_url": base}) self.assertEqual(response.status_code, 400, response.text) self.assertFalse(self.root.exists()) self.load.assert_not_awaited() def test_origin_normalization_matches_browser_navigation_and_cookie_scheme(self): for base, expected in (("http://192.0.2.42:80/", "http://192.0.2.42"), ("HTTPS://SHARE.EXAMPLE.TEST:443/", "https://share.example.test")): with self.subTest(base=base): share = self.create(base_url=base) self.assertEqual(share["url"], expected + share["path"]) self.assertEqual(InteractiveChatShareStore.open_existing(self.root).share_origin(share["id"]), expected) self.origin = expected self.client.base_url = expected path, _ = self.redeem(share) self.assertEqual(self.client.get(path).status_code, 200) self.assertEqual(self.client.get(path + "/state").status_code, 200) cookie_name = COOKIE if expected.startswith("https:") else HTTP_COOKIE cookie = next(item for item in self.client.cookies.jar if item.name == cookie_name) self.assertEqual(cookie.secure, expected.startswith("https:")) def test_cold_legacy_https_share_is_read_without_migration_then_admin_create_upgrades(self): legacy = InteractiveChatShareStore(self.root) share = legacy.create_share("chat-one") with legacy._connection(write=True) as db: db.execute("ALTER TABLE interactive_shares DROP COLUMN public_origin") before = legacy.database_path.read_bytes() path = "/interactive-chat/" + share["id"] self.assertEqual(self.client.get(path).status_code, 200) self.assertEqual(legacy.database_path.read_bytes(), before) with legacy._connection() as db: self.assertNotIn("public_origin", {row[1] for row in db.execute("PRAGMA table_info(interactive_shares)")}) created = self.create() # An anonymous cached store must not block the authenticated upgrade. self.assertEqual(InteractiveChatShareStore.open_existing(self.root).share_origin(created["id"]), self.origin) response = self.client.post(path + "/redeem", headers={"Origin": self.origin}, json={"invitation_token": share["invitation_token"]}) self.assertEqual(response.status_code, 200, response.text) self.assertTrue(response.headers["set-cookie"].startswith(COOKIE + "=")) self.assertIn("Secure", response.headers["set-cookie"]) self.assertEqual(self.client.get(path + "/state").status_code, 200) def test_prompt_origin_csrf_allowlist_and_exact_durable_retry(self): path, headers = self.redeem(self.create()) payload = {"prompt": "Synthetic question", "upload_ids": [], "request_id": "request_0000000001"} for wrong in ({}, {**headers, "Origin": "https://other.example.test"}, {"Origin": self.origin}): self.assertEqual(self.client.post(path + "/prompts", headers=wrong, json=payload).status_code, 403) for forbidden in ("session_id", "backend", "file_ids", "references", "purpose"): self.assertEqual(self.client.post(path + "/prompts", headers=headers, json={**payload, forbidden: "not-authorized"}).status_code, 400) first = self.client.post(path + "/prompts", headers=headers, json=payload) self.assertEqual(first.status_code, 202, first.text) self.assertEqual(self.client.post(path + "/prompts", headers=headers, json=payload).json(), first.json()) self.assertEqual(self.client.post(path + "/prompts", headers=headers, json={**payload, "prompt": "Changed"}).status_code, 409) self.submit.assert_awaited_once() self.assertEqual(self.submit.call_args.args[0], "chat-one") self.assertEqual(self.submit.call_args.args[2:], ("Synthetic question", [], "request_0000000001")) def test_cross_site_invitation_navigation_only_exposes_static_shell(self): share = self.create() path = share["path"] navigation = {"Sec-Fetch-Site": "cross-site", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Dest": "document"} for method in ("GET", "HEAD"): response = self.client.request(method, path, headers=navigation) self.assertEqual(response.status_code, 200, response.text) self.assertNotIn("set-cookie", response.headers) self.assertEqual(self.client.get(path, headers={**navigation, "Sec-Fetch-Dest": "iframe"}).status_code, 403) self.assertEqual(self.client.get(path + "/state", headers=navigation).status_code, 403) self.assertEqual(self.client.post(path + "/redeem", headers={**navigation, "Origin": self.origin}, json={"invitation_token": share["access_token"]}).status_code, 403) self.load.assert_not_called() self.redeem(share) # Cross-site probes did not consume the invitation. def test_callback_errors_are_private_and_indeterminate_work_is_not_replayed(self): path, headers = self.redeem(self.create()) self.submit.side_effect = HTTPException(400, "private internal filesystem detail") payload = {"prompt": "Question", "request_id": "request_0000000002"} first = self.client.post(path + "/prompts", headers=headers, json=payload) self.assertEqual(first.status_code, 503) self.assertNotIn("private internal", first.text) self.assertEqual(self.client.post(path + "/prompts", headers=headers, json=payload).status_code, 409) self.submit.assert_awaited_once() self.load.side_effect = PublicTranscriptError("private source path") response = self.client.get(path + "/state") self.assertEqual(response.status_code, 503) self.assertNotIn("private source", response.text) def test_exact_queued_message_id_survives_acceptance_and_durable_retry(self): path, headers = self.redeem(self.create()) self.submit.return_value = {"accepted": True, "queued": True, "queued_id": "queued_synthetic_001"} payload = {"prompt": "Queued message", "request_id": "request_queued_001"} first = self.client.post(path + "/prompts", headers=headers, json=payload) self.assertEqual(first.status_code, 202, first.text) self.assertEqual(first.json()["queued_id"], "queued_synthetic_001") self.assertEqual(self.client.post(path + "/prompts", headers=headers, json=payload).json(), first.json()) self.submit.assert_awaited_once() def test_upload_response_has_no_private_reference_and_cross_share_attach_denied(self): first = self.create() second = self.create() path, headers = self.redeem(first) response = self.client.post(path + "/uploads", headers={**headers, "Content-Type": "text/plain", "X-Chat-Filename": "note.txt"}, content=b"Safe synthetic file") self.assertEqual(response.status_code, 201, response.text) self.assertEqual(set(response.json()), {"id", "name", "media_type", "byte_size"}) self.assertNotIn("private-file", response.text) other, other_headers = self.redeem(second) response = self.client.post(other + "/prompts", headers=other_headers, json={"prompt": "Question", "request_id": "request_0000000003", "upload_ids": [response.json()["id"]]}) self.assertEqual(response.status_code, 404) self.submit.assert_not_called() def test_failed_upload_keeps_charged_reservation_and_deleted_chat_denies(self): share = self.create() path, headers = self.redeem(share) self.save.side_effect = RuntimeError("private upload path") response = self.client.post(path + "/uploads", headers={**headers, "Content-Type": "text/plain", "X-Chat-Filename": "note.txt"}, content=b"bytes") self.assertEqual(response.status_code, 503) self.assertNotIn("private upload", response.text) with InteractiveChatShareStore.open_existing(self.root)._connection() as db: self.assertEqual(tuple(db.execute("SELECT byte_size,private_ref FROM interactive_uploads").fetchone()), (5, None)) self.sessions.clear() self.assertEqual(self.client.get(path + "/state").status_code, 404) def test_stream_keepalive_does_not_load_transcript_and_revision_signal_does(self): share = self.create() path, _ = self.redeem(share) cookie = next(cookie.value for cookie in self.client.cookies.jar if cookie.name == COOKIE) request = SimpleNamespace(base_url=self.origin + "/", url=SimpleNamespace(query=""), headers={"cookie": COOKIE + "=" + cookie}, is_disconnected=mock.AsyncMock(return_value=False)) endpoint = next(route.endpoint for route in self.router.routes if route.path.endswith("/{share_id}/events")) self.wait.side_effect = [False, True] async def consume(): response = await endpoint(share["id"], request) iterator = response.body_iterator self.assertIn("event: state", await anext(iterator)) self.assertEqual(await anext(iterator), ": keepalive\n\n") self.assertEqual(self.load.await_count, 1) with mock.patch("interactive_chat_share_routes.asyncio.sleep", new=mock.AsyncMock()): self.assertIn("event: state", await anext(iterator)) self.assertEqual(self.load.await_count, 2) await iterator.aclose() asyncio.run(consume()) def test_stream_disconnect_before_body_starts_releases_admission(self): share = self.create() self.redeem(share) cookie = next(cookie.value for cookie in self.client.cookies.jar if cookie.name == COOKIE) request = SimpleNamespace(base_url=self.origin + "/", url=SimpleNamespace(query=""), headers={"cookie": COOKIE + "=" + cookie}, is_disconnected=mock.AsyncMock(return_value=False)) endpoint = next(route.endpoint for route in self.router.routes if route.path.endswith("/{share_id}/events")) async def disconnect(): response = await endpoint(share["id"], request) def leases(): return inspect.getclosurevars(type(response).__call__).nonlocals["streams"] self.assertEqual(leases(), 0) # Merely creating a response owns no slot. async def send(message): self.assertEqual(message["type"], "http.response.start") self.assertEqual(leases(), 1) raise OSError("Synthetic connection closed before response headers") with self.assertRaises(ClientDisconnect): await response({"type": "http", "asgi": {"spec_version": "2.4"}}, mock.AsyncMock(), send) self.assertEqual(leases(), 0) await response.body_iterator.aclose() asyncio.run(disconnect()) self.load.assert_not_awaited() self.wait.assert_not_awaited() def test_upload_disconnect_joins_committed_save_and_retains_accounting(self): share = self.create() self.redeem(share) cookie = next(cookie.value for cookie in self.client.cookies.jar if cookie.name == COOKIE) async def chunks(): yield b"safe bytes" request = SimpleNamespace(base_url=self.origin + "/", url=SimpleNamespace(query=""), stream=chunks, headers={"cookie": COOKIE + "=" + cookie, "origin": self.origin, "x-chat-csrf": csrf_token(cookie), "x-chat-filename": "note.txt", "content-type": "text/plain"}) endpoint = next(route.endpoint for route in self.router.routes if route.path.endswith("/{share_id}/uploads")) original = InteractiveChatShareStore.complete_upload async def exercise(): entered, release, completed = asyncio.Event(), asyncio.Event(), asyncio.Event() loop = asyncio.get_running_loop() async def save(*_): entered.set() await release.wait() return "private-committed-file" def finish(*args): original(*args) loop.call_soon_threadsafe(completed.set) self.save.side_effect = save with mock.patch.object(InteractiveChatShareStore, "complete_upload", finish): task = asyncio.create_task(endpoint(share["id"], request)) await asyncio.wait_for(entered.wait(), 2) task.cancel() with self.assertRaises(asyncio.CancelledError): await task release.set() await asyncio.wait_for(completed.wait(), 2) await asyncio.sleep(0) asyncio.run(exercise()) with InteractiveChatShareStore.open_existing(self.root)._connection() as db: self.assertEqual(tuple(db.execute("SELECT byte_size,private_ref FROM interactive_uploads").fetchone()), (10, "private-committed-file")) def test_native_state_preserves_exact_events_and_rejects_foreign_chat(self): path, _ = self.redeem(self.create()) native = {"revision": "native-1", "session": {"id": "chat-one"}, "events": [ {"id": "native-event-one", "session_id": "chat-one", "seq": 9, "type": "assistant_text", "text": "Answer"}], "queue": [], "active": False, "goal": None, "jobs": [], "codex_runtime": {}, "claude_runtime": {}, "health": {}, "runtime_catalog": {}, "hasMoreEvents": True, "nextTimelineBefore": 9, "eventsTotal": 9} self.load.return_value = native response = self.client.get(path + "/state") self.assertEqual(response.status_code, 200, response.text) self.assertEqual(response.json()["events"], native["events"]) self.assertNotIn("messages", response.json()) self.load.return_value = {**native, "session": {"id": "other-chat"}} self.assertEqual(self.client.get(path + "/state").status_code, 503) self.load.return_value = {**native, "events": [{"session_id": "other-chat"}]} self.assertEqual(self.client.get(path + "/state").status_code, 503) def test_control_receipt_result_and_trusted_scope_replay_without_duplicate(self): share = self.create() path, headers = self.redeem(share) payload = {"action": "turn.steer", "payload": {"prompt": "New direction"}, "request_id": "control_000000001"} first = self.client.post(path + "/controls", headers=headers, json=payload) self.assertEqual(first.status_code, 202, first.text) self.assertEqual(first.json()["result"], {"ok": True}) self.assertEqual(self.client.post(path + "/controls", headers=headers, json=payload).json(), first.json()) self.control.assert_awaited_once_with("chat-one", "turn.steer", {"prompt": "New direction"}, share_id=share["id"], request_id=payload["request_id"]) self.assertEqual(self.client.post(path + "/controls", headers=headers, json={**payload, "action": "turn.stop", "payload": {}}).status_code, 409) def test_control_typed_denial_is_durable_but_unknown_callback_error_is_indeterminate(self): path, headers = self.redeem(self.create()) self.control.side_effect = ChatControlError("forbidden") payload = {"action": "goal.delete", "payload": {}, "request_id": "control_000000002"} first = self.client.post(path + "/controls", headers=headers, json=payload) self.assertEqual(first.status_code, 403) self.assertEqual(self.client.post(path + "/controls", headers=headers, json=payload).json(), first.json()) self.control.assert_awaited_once() self.control.side_effect = HTTPException(409, "private path after possible write") payload["request_id"] = "control_000000003" first = self.client.post(path + "/controls", headers=headers, json=payload) self.assertEqual(first.status_code, 503) self.assertNotIn("private path", first.text) self.assertEqual(self.client.post(path + "/controls", headers=headers, json=payload).status_code, 409) self.assertEqual(self.control.await_count, 2) def test_explicit_native_reads_have_no_write_ledger_or_file_proxy(self): path, headers = self.redeem(self.create()) self.control.return_value = {"events": [], "has_more": False} for action in ("timeline.older", "timeline.around", "timeline.trace", "timeline.index", "jobs.runs", "runtime.catalog", "handoffs.get"): response = self.client.post(path + "/controls", headers=headers, json={"action": action, "payload": {"id": "handoff-synthetic"} if action == "handoffs.get" else {}, "request_id": "read_request_0001"}) self.assertEqual(response.status_code, 200, response.text) self.assertEqual(response.json()["result"], self.control.return_value) self.assertEqual(self.control.call_args.kwargs, {}) with InteractiveChatShareStore.open_existing(self.root)._connection() as db: self.assertEqual(db.execute("SELECT count(*) FROM interactive_submissions").fetchone()[0], 0) for action in ("files.read", "files.list", "terminal.execute", "admin.call", "http.proxy", []): response = self.client.post(path + "/controls", headers=headers, json={"action": action, "payload": {}, "request_id": "read_request_0001"}) self.assertEqual(response.status_code, 400) def test_assets_are_exact_generated_keys_not_filesystem_routes(self): assets = {"native-entry.js": ("text/javascript", b"export const native = true;"), "fonts/example.woff2": ("font/woff2", b"synthetic-font")} with mock.patch.object(web, "ASSETS", assets, create=True), mock.patch.object(Path, "read_bytes", side_effect=AssertionError("No guest asset filesystem lookup")): response = self.client.get("/interactive-chat/assets/native-entry.js") self.assertEqual((response.status_code, response.content), (200, assets["native-entry.js"][1])) self.assertEqual(self.client.head("/interactive-chat/assets/fonts/example.woff2").status_code, 200) for path in ("unknown.js", "files/private.txt", "%2e%2e%2fprivate.txt"): self.assertEqual(self.client.get("/interactive-chat/assets/" + path).status_code, 404) self.assertNotIn("'unsafe-inline'", response.headers["content-security-policy"].split("script-src")[1].split(";")[0]) if __name__ == "__main__": unittest.main()