Python 88.3%
TypeScript 7.6%
Shell 4.1%
1"""Admin API tests (read-only). Two layers:2- always: with the project key, every /v1/organization/* GET must be rejected 401/403 with a "Missing scopes" message3 (documents the ACCOUNT_RESTRICTED state observed on 2026-09-18) — unless OPENAI_ADMIN_KEY is set, then skipped;4- RUN_ADMIN_TESTS=true + OPENAI_ADMIN_KEY: real list calls succeed (never mutating).5Webhook endpoints list / event types work with a project key and are asserted here too (LIVE_VERIFIED 2026-09-18).6"""7from __future__ import annotations89import os10import time1112import pytest1314ADMIN_GETS = [15 ("/v1/organization/users?limit=1", "api.management.read"),16 ("/v1/organization/invites?limit=1", "api.management.read"),17 ("/v1/organization/projects?limit=1", "api.management.read"),18 ("/v1/organization/admin_api_keys?limit=1", "api.management.read"),19 ("/v1/organization/audit_logs?limit=1", "api.audit_logs.read"),20 ("/v1/organization/roles?limit=1", "api.roles.read"),21 ("/v1/organization/groups?limit=1", "api.groups.read"),22 ("/v1/organization/certificates?limit=1", "api.mtls.read"),23 ("/v1/organization/external_storage", "api.external_storage.read"),24 ("/v1/organization/spend_limit", "api.management.read"),25 ("/v1/organization/data_retention", "api.management.read"),26]272829@pytest.mark.parametrize("path,scope", ADMIN_GETS)30def test_admin_get_requires_scope_with_project_key(openai, path, scope):31 if os.environ.get("OPENAI_ADMIN_KEY"):32 pytest.skip("Admin key configured: restriction not reproducible with the project key")33 st, body, _ = openai("GET", path, note="test_admin restricted probe")34 assert st in (401, 403), (st, body)35 err = body["error"]36 msg = err if isinstance(err, str) else err["message"]37 assert "Missing scopes" in msg and scope in msg383940def test_usage_and_costs_require_usage_scope(openai):41 if os.environ.get("OPENAI_ADMIN_KEY"):42 pytest.skip("Admin key configured")43 start = int(time.time()) - 8640044 for path in (f"/v1/organization/usage/completions?start_time={start}&limit=1", f"/v1/organization/costs?start_time={start}&limit=1"):45 st, body, _ = openai("GET", path, note="test_admin usage probe")46 assert st == 403 and "api.usage.read" in str(body["error"])474849def test_webhook_endpoints_list_works_with_project_key(openai):50 st, body, hdrs = openai("GET", "/v1/webhook_endpoints?limit=1", note="test_admin webhook endpoints list")51 assert st == 200 and body["object"] == "list" and {"data", "first_id", "last_id", "has_more"} <= set(body)525354def test_webhook_event_types_list(openai):55 st, body, _ = openai("GET", "/v1/webhook_event_types", note="test_admin webhook event types")56 assert st == 200 and body["object"] == "list"57 types = set(body["data"])58 assert {"response.completed", "batch.completed", "fine_tuning.job.succeeded", "eval.run.succeeded", "realtime.call.incoming"} <= types596061# ------------------------------------------------------------------ gated real admin tests62@pytest.mark.run_admin_tests63def test_admin_list_users_projects(openai):64 if not os.environ.get("OPENAI_ADMIN_KEY"):65 pytest.skip("OPENAI_ADMIN_KEY not set")66 for path in ("/v1/organization/users?limit=5", "/v1/organization/projects?limit=5", "/v1/organization/audit_logs?limit=5"):67 st, body, _ = openai("GET", path, admin=True, note="test_admin real list")68 assert st == 200 and body["object"] == "list", (path, st, body)697071@pytest.mark.run_admin_tests72def test_admin_usage_costs(openai):73 if not os.environ.get("OPENAI_ADMIN_KEY"):74 pytest.skip("OPENAI_ADMIN_KEY not set")75 start = int(time.time()) - 7 * 8640076 st, body, _ = openai("GET", f"/v1/organization/usage/completions?start_time={start}&bucket_width=1d&group_by=model&limit=7", admin=True, note="test_admin usage")77 assert st == 200 and body["object"] == "page" and "data" in body78 st, body, _ = openai("GET", f"/v1/organization/costs?start_time={start}&bucket_width=1d&limit=7", admin=True, note="test_admin costs")79 assert st == 200 and body["object"] == "page"80