"""Flask API integration tests for authentication and route boundaries.""" import uuid SERVICE_KEY = "integration-service-key-0123456789abcdef" ALLOWED_DISCORD_ID = "integration-discord-user" def _bearer(token): return {"Authorization": f"Bearer {token}"} def test_health_and_error_routes(client): assert client.get("/health/live").get_json() == {"status": "ok"} assert client.get("/health/ready").get_json() == {"status": "ready"} assert client.get("/health").get_json() == {"status": "ready"} missing = client.get("/api/route-that-does-not-exist") assert missing.status_code == 404 assert missing.get_json() == {"error": "not found"} wrongMethod = client.get("/api/register") assert wrongMethod.status_code == 405 assert wrongMethod.get_json() == {"error": "method not allowed"} invalidJson = client.post( "/api/register", data="[]", content_type="application/json" ) assert invalidJson.status_code == 400 assert invalidJson.get_json() == {"error": "JSON object required"} def test_password_registration_keeps_values_parameterized_and_protected(client): from core import postgres injectedUsername = "alice'; DROP TABLE users; --" injectedUUID = str(uuid.uuid4()) response = client.post( "/api/register", json={ "username": injectedUsername, "password": "long-enough-password", "timezone": "America/Chicago", "id": injectedUUID, "password_hashed": "attacker-controlled", "created_at": "1900-01-01T00:00:00Z", "unexpected_admin": True, }, ) assert response.status_code == 201, response.get_json() assert postgres.table_exists("users") record = postgres.select_one("users", {"username": injectedUsername}) assert record is not None assert str(record["id"]) != injectedUUID assert bytes(record["password_hashed"]) != b"attacker-controlled" assert record["timezone"] == "America/Chicago" assert record["created_at"].year > 1900 login = client.post( "/api/login", json={"username": injectedUsername, "password": "long-enough-password"}, ) assert login.status_code == 200 assert login.get_json()["token"] def test_jwt_user_key_creation_authentication_and_revocation( client, createAuthenticatedUser ): from core import postgres user = createAuthenticatedUser("api-key-owner") jwtHeaders = _bearer(user["token"]) profile = client.get(f"/api/user/{user['user_uuid']}", headers=jwtHeaders) assert profile.status_code == 200 assert profile.get_json()["username"] == user["username"] assert "password_hashed" not in profile.get_json() update = client.put( f"/api/user/{user['user_uuid']}", headers=jwtHeaders, json={"timezone": "America/Chicago", "username": "cannot-change"}, ) assert update.status_code == 200 assert client.get( "/api/user/me/timezone", headers=jwtHeaders ).get_json() == {"timezone": "America/Chicago"} created = client.post( "/api/keys", headers=jwtHeaders, json={"name": "integration key"} ) assert created.status_code == 201, created.get_json() keyRecord = created.get_json() secret = keyRecord["key"] assert secret.startswith("llmbot_user_") assert "key_hash" not in keyRecord storedKey = postgres.select_one("api_keys", {"id": keyRecord["id"]}) assert storedKey["key_hash"] != secret assert secret not in {str(value) for value in storedKey.values()} listed = client.get("/api/keys", headers=jwtHeaders) assert listed.status_code == 200 listedKey = listed.get_json()["keys"][0] assert listedKey["id"] == keyRecord["id"] assert "key" not in listedKey assert "key_hash" not in listedKey apiKeyHeaders = _bearer(secret) timezone = client.get("/api/user/me/timezone", headers=apiKeyHeaders) assert timezone.status_code == 200 assert timezone.get_json() == {"timezone": "America/Chicago"} assert postgres.select_one("api_keys", {"id": keyRecord["id"]})[ "last_used_at" ] is not None cannotManageKeys = client.post( "/api/keys", headers=apiKeyHeaders, json={"name": "nested key"} ) assert cannotManageKeys.status_code == 401 revoked = client.delete(f"/api/keys/{keyRecord['id']}", headers=jwtHeaders) assert revoked.status_code == 200 assert postgres.select_one("api_keys", {"id": keyRecord["id"]})[ "revoked_at" ] is not None assert client.get("/api/user/me/timezone", headers=apiKeyHeaders).status_code == 401 def test_discord_allowlist_and_service_key_boundaries(client, createAuthenticatedUser): serviceHeaders = _bearer(SERVICE_KEY) assert client.post( "/api/auth/discord/session", json={"discord_id": ALLOWED_DISCORD_ID}, ).status_code == 401 assert client.post( "/api/auth/discord/session", headers=_bearer("not-the-configured-service-key-0123456789"), json={"discord_id": ALLOWED_DISCORD_ID}, ).status_code == 401 denied = client.post( "/api/auth/discord/session", headers=serviceHeaders, json={"discord_id": "not-allowlisted", "display_name": "No Access"}, ) assert denied.status_code == 403 accepted = client.post( "/api/auth/discord/session", headers=serviceHeaders, json={"discord_id": ALLOWED_DISCORD_ID, "display_name": "First Name"}, ) assert accepted.status_code == 200, accepted.get_json() discordSession = accepted.get_json() assert discordSession["timezone"] == "UTC" assert discordSession["token"] repeated = client.post( "/api/auth/discord/session", headers=serviceHeaders, json={"discord_id": ALLOWED_DISCORD_ID, "display_name": "New Name"}, ) assert repeated.status_code == 200 assert repeated.get_json()["user_uuid"] == discordSession["user_uuid"] profile = client.get( f"/api/user/{discordSession['user_uuid']}", headers=_bearer(discordSession["token"]), ) assert profile.status_code == 200 assert profile.get_json()["username"] is None passwordUser = createAuthenticatedUser("service-boundary-user") assert client.post( "/api/auth/discord/session", headers=_bearer(passwordUser["token"]), json={"discord_id": ALLOWED_DISCORD_ID}, ).status_code == 401 assert client.get( "/api/user/me/timezone", headers=serviceHeaders ).status_code == 401 def test_service_outbox_claim_retry_and_delivery_routes(client): from core import outbox, postgres serviceHeaders = _bearer(SERVICE_KEY) session = client.post( "/api/auth/discord/session", headers=serviceHeaders, json={"discord_id": ALLOWED_DISCORD_ID, "display_name": "Recipient"}, ).get_json() queued = outbox.enqueue_message( session["user_uuid"], "discord_dm", {"content": "integration delivery"}, idempotency_key=f"api-outbox-{uuid.uuid4()}", ) claimed = client.post( "/api/internal/outbox/claim", headers=serviceHeaders, json={"worker_id": "api-worker-one", "limit": 1}, ) assert claimed.status_code == 200 message = claimed.get_json()["messages"][0] assert message["id"] == str(queued["id"]) assert message["provider_user_id"] == ALLOWED_DISCORD_ID assert message["content"] == "integration delivery" assert message["worker_id"] == "api-worker-one" missingWorker = client.post( f"/api/internal/outbox/{message['id']}/result", headers=serviceHeaders, json={"status": "sent"}, ) assert missingWorker.status_code == 409 wrongWorker = client.post( f"/api/internal/outbox/{message['id']}/result", headers=serviceHeaders, json={"status": "sent", "worker_id": "not-the-lease-owner"}, ) assert wrongWorker.status_code == 409 stillLeased = outbox.get_message(message["id"]) assert stillLeased["status"] == "delivering" assert stillLeased["leased_by"] == "api-worker-one" assert stillLeased["delivered_at"] is None retried = client.post( f"/api/internal/outbox/{message['id']}/result", headers=serviceHeaders, json={ "status": "retry", "error": "temporary failure", "worker_id": "api-worker-one", }, ) assert retried.status_code == 200 assert retried.get_json()["message"]["status"] == "pending" postgres.execute( "UPDATE outbound_messages SET available_at = NOW() WHERE id = %(id)s", {"id": message["id"]}, ) claimedAgain = client.post( "/api/internal/outbox/claim", headers=serviceHeaders, json={"worker_id": "api-worker-two", "limit": 1}, ) assert claimedAgain.status_code == 200 assert claimedAgain.get_json()["messages"][0]["attempts"] == 2 delivered = client.post( f"/api/internal/outbox/{message['id']}/result", headers=serviceHeaders, json={"status": "sent", "worker_id": "api-worker-two"}, ) assert delivered.status_code == 200 assert delivered.get_json()["message"]["status"] == "delivered"