ctfy.sdk.admin
Operator / admin client for the ctfy platform.
AdminClient is the operator-facing counterpart to
~ctfy.sdk.client.PlatformClient, mirroring the ctfy /
ctfy-admin CLI split: the player client never surfaces admin methods, so
agents and players reading the SDK reference aren't distracted by operator
endpoints they can't call.
Reach it two ways:
client.adminon an existingPlatformClient— shares that client's transport (connection pool + bearer)::from ctfy.sdk import PlatformClient client = PlatformClient("https://ctfy.example", token="pf_xxx") client.admin.users.set_role(user_id, "admin")AdminClient.connect()for operator tooling that doesn't already hold a player client::from ctfy.sdk import AdminClient with AdminClient.connect("https://ctfy.example", token="pf_xxx") as admin: admin.observability.overview()
Every endpoint here is role-gated server-side (admin / super-admin); the SDK only relays — the token's role decides access.
1"""Operator / admin client for the ctfy platform. 2 3``AdminClient`` is the operator-facing counterpart to 4:class:`~ctfy.sdk.client.PlatformClient`, mirroring the ``ctfy`` / 5``ctfy-admin`` CLI split: the player client never surfaces admin methods, so 6agents and players reading the SDK reference aren't distracted by operator 7endpoints they can't call. 8 9Reach it two ways: 10 11* ``client.admin`` on an existing :class:`PlatformClient` — shares that 12 client's transport (connection pool + bearer):: 13 14 from ctfy.sdk import PlatformClient 15 16 client = PlatformClient("https://ctfy.example", token="pf_xxx") 17 client.admin.users.set_role(user_id, "admin") 18 19* :meth:`AdminClient.connect` for operator tooling that doesn't already hold 20 a player client:: 21 22 from ctfy.sdk import AdminClient 23 24 with AdminClient.connect("https://ctfy.example", token="pf_xxx") as admin: 25 admin.observability.overview() 26 27Every endpoint here is role-gated server-side (admin / super-admin); the SDK 28only relays — the token's role decides access. 29""" 30 31from __future__ import annotations 32 33from functools import cached_property 34from types import TracebackType 35from typing import Self 36 37from ctfy.core.constants import DEFAULT_CLIENT_TIMEOUT 38from ctfy.sdk.admin_resources.achievements import AdminAchievementsResource 39from ctfy.sdk.admin_resources.admin_invites import AdminAdminInvitesResource 40from ctfy.sdk.admin_resources.announcements import AdminAnnouncementsResource 41from ctfy.sdk.admin_resources.authoring import AdminAuthoredChallengesResource 42from ctfy.sdk.admin_resources.authoring_review import ( 43 AdminAuthoringReviewersResource, 44 AdminCompetitionAuthoredChallengesResource, 45) 46from ctfy.sdk.admin_resources.awd import AdminAwdResource 47from ctfy.sdk.admin_resources.challenge_schedule import AdminChallengeScheduleResource 48from ctfy.sdk.admin_resources.challenge_stats import AdminChallengeStatsResource 49from ctfy.sdk.admin_resources.challenges import AdminChallengesResource 50from ctfy.sdk.admin_resources.changelog import AdminChangelogResource 51from ctfy.sdk.admin_resources.competition_admins import AdminCompetitionAdminsResource 52from ctfy.sdk.admin_resources.competition_applications import ( 53 AdminCompetitionApplicationsResource, 54) 55from ctfy.sdk.admin_resources.competition_attachments import ( 56 AdminCompetitionAttachmentsResource, 57) 58from ctfy.sdk.admin_resources.competition_boards import AdminCompetitionBoardsResource 59from ctfy.sdk.admin_resources.competition_invites import AdminCompetitionInvitesResource 60from ctfy.sdk.admin_resources.competition_topics import AdminCompetitionTopicsResource 61from ctfy.sdk.admin_resources.competitions import AdminCompetitionsResource 62from ctfy.sdk.admin_resources.contact_messages import AdminContactMessagesResource 63from ctfy.sdk.admin_resources.email import AdminEmailResource 64from ctfy.sdk.admin_resources.env_sharing import AdminEnvSharingResource 65from ctfy.sdk.admin_resources.eval import ( 66 AdminEvalAllowancesResource, 67 AdminEvalCampaignsResource, 68 AdminEvalHarnessesResource, 69 AdminEvalRunsResource, 70 AdminEvalVendorsResource, 71 AdminLlmModelsResource, 72 AdminRegistryResource, 73) 74from ctfy.sdk.admin_resources.exclusion_groups import AdminExclusionGroupsResource 75from ctfy.sdk.admin_resources.gauntlet import AdminGauntletResource 76from ctfy.sdk.admin_resources.instances import AdminInstancesResource 77from ctfy.sdk.admin_resources.institutions import AdminInstitutionsResource 78from ctfy.sdk.admin_resources.ip_location import AdminIpLocationResource 79from ctfy.sdk.admin_resources.llm_calls import AdminLlmCallsResource 80from ctfy.sdk.admin_resources.llm_providers import AdminLlmProvidersResource 81from ctfy.sdk.admin_resources.machines import AdminMachinesResource 82from ctfy.sdk.admin_resources.messages import AdminMessagesResource 83from ctfy.sdk.admin_resources.nodes import AdminNodesResource 84from ctfy.sdk.admin_resources.observability import AdminObservabilityResource 85from ctfy.sdk.admin_resources.patches import AdminPatchesResource 86from ctfy.sdk.admin_resources.prewarm import AdminPrewarmResource 87from ctfy.sdk.admin_resources.recap import AdminRecapResource 88from ctfy.sdk.admin_resources.records import AdminRecordsResource 89from ctfy.sdk.admin_resources.registrations import AdminRegistrationsResource 90from ctfy.sdk.admin_resources.release_plan import AdminReleasePlanResource 91from ctfy.sdk.admin_resources.reports import AdminReportsResource 92from ctfy.sdk.admin_resources.risk import AdminRiskResource 93from ctfy.sdk.admin_resources.series import AdminSeriesResource 94from ctfy.sdk.admin_resources.settings import AdminSettingsResource 95from ctfy.sdk.admin_resources.suites import AdminSuitesResource 96from ctfy.sdk.admin_resources.tasks import ( 97 AdminScheduledJobsResource, 98 AdminTasksResource, 99) 100from ctfy.sdk.admin_resources.teams import AdminTeamsResource 101from ctfy.sdk.admin_resources.users import AdminUsersResource 102from ctfy.sdk.base import BaseHttpClient 103 104__all__ = ["AdminClient"] 105 106 107class AdminClient: 108 """Admin / operator surface, grouped into resource namespaces. 109 110 Namespaces: :attr:`users`, :attr:`competitions`, :attr:`suites`, :attr:`announcements`, 111 :attr:`achievements`, :attr:`challenges`, :attr:`gauntlet`, 112 :attr:`instances`, 113 :attr:`records`, :attr:`nodes`, :attr:`observability`, :attr:`settings`, 114 :attr:`competition_admins`. 115 """ 116 117 def __init__(self, http: BaseHttpClient) -> None: 118 #: Shared transport (the parent PlatformClient when reached via 119 #: ``client.admin``, or an owned client when built via ``connect``). 120 self._http = http 121 122 @classmethod 123 def connect( 124 cls, 125 server_url: str, 126 token: str = "", 127 *, 128 max_retries: int = 2, 129 timeout: int = DEFAULT_CLIENT_TIMEOUT, 130 ) -> AdminClient: 131 """Build an ``AdminClient`` that owns its own transport. 132 133 For operator tooling that doesn't already hold a 134 :class:`PlatformClient`. The returned client is a context manager 135 that closes its transport on exit. 136 """ 137 base = server_url.rstrip("/") 138 http = BaseHttpClient(f"{base}/api/v1", token, timeout=timeout, max_retries=max_retries) 139 return cls(http) 140 141 @cached_property 142 def users(self) -> AdminUsersResource: 143 return AdminUsersResource(self._http) 144 145 @cached_property 146 def competitions(self) -> AdminCompetitionsResource: 147 return AdminCompetitionsResource(self._http) 148 149 @cached_property 150 def suites(self) -> AdminSuitesResource: 151 """A suite through its own door: its own fields only (#2896).""" 152 return AdminSuitesResource(self._http) 153 154 @cached_property 155 def announcements(self) -> AdminAnnouncementsResource: 156 return AdminAnnouncementsResource(self._http) 157 158 @cached_property 159 def changelog(self) -> AdminChangelogResource: 160 return AdminChangelogResource(self._http) 161 162 @cached_property 163 def contact_messages(self) -> AdminContactMessagesResource: 164 """What visitors wrote on the Contact page (#3414).""" 165 return AdminContactMessagesResource(self._http) 166 167 @cached_property 168 def institutions(self) -> AdminInstitutionsResource: 169 return AdminInstitutionsResource(self._http) 170 171 @cached_property 172 def exclusion_groups(self) -> AdminExclusionGroupsResource: 173 return AdminExclusionGroupsResource(self._http) 174 175 @cached_property 176 def achievements(self) -> AdminAchievementsResource: 177 return AdminAchievementsResource(self._http) 178 179 @cached_property 180 def challenges(self) -> AdminChallengesResource: 181 return AdminChallengesResource(self._http) 182 183 @cached_property 184 def gauntlet(self) -> AdminGauntletResource: 185 return AdminGauntletResource(self._http) 186 187 @cached_property 188 def email(self) -> AdminEmailResource: 189 return AdminEmailResource(self._http) 190 191 @cached_property 192 def ip_location(self) -> AdminIpLocationResource: 193 return AdminIpLocationResource(self._http) 194 195 @cached_property 196 def llm_calls(self) -> AdminLlmCallsResource: 197 return AdminLlmCallsResource(self._http) 198 199 @cached_property 200 def llm_providers(self) -> AdminLlmProvidersResource: 201 return AdminLlmProvidersResource(self._http) 202 203 @cached_property 204 def patches(self) -> AdminPatchesResource: 205 return AdminPatchesResource(self._http) 206 207 @cached_property 208 def reports(self) -> AdminReportsResource: 209 return AdminReportsResource(self._http) 210 211 @cached_property 212 def awd(self) -> AdminAwdResource: 213 return AdminAwdResource(self._http) 214 215 @cached_property 216 def series(self) -> AdminSeriesResource: 217 return AdminSeriesResource(self._http) 218 219 @cached_property 220 def instances(self) -> AdminInstancesResource: 221 return AdminInstancesResource(self._http) 222 223 @cached_property 224 def records(self) -> AdminRecordsResource: 225 return AdminRecordsResource(self._http) 226 227 @cached_property 228 def nodes(self) -> AdminNodesResource: 229 return AdminNodesResource(self._http) 230 231 @cached_property 232 def observability(self) -> AdminObservabilityResource: 233 return AdminObservabilityResource(self._http) 234 235 @cached_property 236 def settings(self) -> AdminSettingsResource: 237 return AdminSettingsResource(self._http) 238 239 @cached_property 240 def competition_admins(self) -> AdminCompetitionAdminsResource: 241 return AdminCompetitionAdminsResource(self._http) 242 243 @cached_property 244 def admin_invites(self) -> AdminAdminInvitesResource: 245 """Invite an address with no account yet to be an administrator.""" 246 return AdminAdminInvitesResource(self._http) 247 248 @cached_property 249 def competition_invites(self) -> AdminCompetitionInvitesResource: 250 return AdminCompetitionInvitesResource(self._http) 251 252 @cached_property 253 def competition_applications(self) -> AdminCompetitionApplicationsResource: 254 """Applications to a private competition, and the verdict on each.""" 255 return AdminCompetitionApplicationsResource(self._http) 256 257 @cached_property 258 def competition_attachments(self) -> AdminCompetitionAttachmentsResource: 259 """A competition's rules / handbook / notice files (#1808).""" 260 return AdminCompetitionAttachmentsResource(self._http) 261 262 @cached_property 263 def competition_boards(self) -> AdminCompetitionBoardsResource: 264 """A competition's extra boards — published and shadow (#1965 G).""" 265 return AdminCompetitionBoardsResource(self._http) 266 267 @cached_property 268 def recap(self) -> AdminRecapResource: 269 """A competition's recap, its publication and its report email (#3023).""" 270 return AdminRecapResource(self._http) 271 272 @cached_property 273 def challenge_schedule(self) -> AdminChallengeScheduleResource: 274 """When each challenge of a competition appears and shuts (#2093).""" 275 return AdminChallengeScheduleResource(self._http) 276 277 @cached_property 278 def release_plan(self) -> AdminReleasePlanResource: 279 """Waves, per-challenge rules and hints: drafts, publish, release (#2093, #2101).""" 280 return AdminReleasePlanResource(self._http) 281 282 @cached_property 283 def env_sharing(self) -> AdminEnvSharingResource: 284 """How many teams stand on one environment, the groups behind it and 285 the health of the shared environments (#2129 B).""" 286 return AdminEnvSharingResource(self._http) 287 288 @cached_property 289 def machines(self) -> AdminMachinesResource: 290 """Machine logins handed to teams, captain-only (#2132).""" 291 return AdminMachinesResource(self._http) 292 293 @cached_property 294 def messages(self) -> AdminMessagesResource: 295 """Site messages from an event's organisers or the platform (#2073).""" 296 return AdminMessagesResource(self._http) 297 298 @cached_property 299 def prewarm(self) -> AdminPrewarmResource: 300 """Whether a competition's images are warm on its nodes (#2129).""" 301 return AdminPrewarmResource(self._http) 302 303 @cached_property 304 def competition_topics(self) -> AdminCompetitionTopicsResource: 305 """A competition's scheduled topics, released by the clock (#1965).""" 306 return AdminCompetitionTopicsResource(self._http) 307 308 @cached_property 309 def registrations(self) -> AdminRegistrationsResource: 310 """Entrant roster, eligibility review, and CSV export.""" 311 return AdminRegistrationsResource(self._http) 312 313 @cached_property 314 def teams(self) -> AdminTeamsResource: 315 """Enforcement against a squad — disqualify and reinstate. 316 317 Separate from ``registrations`` on purpose: that one rules on 318 eligibility (which decides prizes), this one decides whether the 319 team is in the event at all. 320 """ 321 return AdminTeamsResource(self._http) 322 323 @cached_property 324 def challenge_stats(self) -> AdminChallengeStatsResource: 325 """How players did against an event's challenges: the organiser's 326 table and the single-challenge reading (#2146).""" 327 return AdminChallengeStatsResource(self._http) 328 329 @cached_property 330 def risk(self) -> AdminRiskResource: 331 """Risk control: the case queue (organisers) and an account's sealed 332 sightings (platform administrators). Detection reports; people decide.""" 333 return AdminRiskResource(self._http) 334 335 @cached_property 336 def tasks(self) -> AdminTasksResource: 337 return AdminTasksResource(self._http) 338 339 @cached_property 340 def scheduled_jobs(self) -> AdminScheduledJobsResource: 341 return AdminScheduledJobsResource(self._http) 342 343 @cached_property 344 def authored_challenges(self) -> AdminAuthoredChallengesResource: 345 """The review queue for player-authored challenges.""" 346 return AdminAuthoredChallengesResource(self._http) 347 348 @cached_property 349 def authoring_reviewers(self) -> AdminAuthoringReviewersResource: 350 """Who may rule on one competition's uploads (super-admin).""" 351 return AdminAuthoringReviewersResource(self._http) 352 353 @cached_property 354 def competition_authored_challenges(self) -> AdminCompetitionAuthoredChallengesResource: 355 """One competition's uploads, for its delegated reviewer: read, 356 audit and rule — never publish.""" 357 return AdminCompetitionAuthoredChallengesResource(self._http) 358 359 @cached_property 360 def llm_models(self) -> AdminLlmModelsResource: 361 return AdminLlmModelsResource(self._http) 362 363 @cached_property 364 def eval_vendors(self) -> AdminEvalVendorsResource: 365 return AdminEvalVendorsResource(self._http) 366 367 @cached_property 368 def eval_harnesses(self) -> AdminEvalHarnessesResource: 369 return AdminEvalHarnessesResource(self._http) 370 371 @property 372 def eval_allowances(self) -> AdminEvalAllowancesResource: 373 return AdminEvalAllowancesResource(self._http) 374 375 @property 376 def registry(self) -> AdminRegistryResource: 377 """Registry storage: the usage report and the manual reclaim.""" 378 return AdminRegistryResource(self._http) 379 380 @cached_property 381 def eval_runs(self) -> AdminEvalRunsResource: 382 return AdminEvalRunsResource(self._http) 383 384 @cached_property 385 def eval_campaigns(self) -> AdminEvalCampaignsResource: 386 return AdminEvalCampaignsResource(self._http) 387 388 def close(self) -> None: 389 """Close the underlying transport. 390 391 Only call this on a standalone client built via :meth:`connect`; 392 when reached via ``PlatformClient.admin`` the transport is shared 393 with — and closed by — the parent player client. 394 """ 395 self._http.close() 396 397 def __enter__(self) -> Self: 398 return self 399 400 def __exit__( 401 self, 402 exc_type: type[BaseException] | None, 403 exc: BaseException | None, 404 tb: TracebackType | None, 405 ) -> None: 406 self.close()
108class AdminClient: 109 """Admin / operator surface, grouped into resource namespaces. 110 111 Namespaces: :attr:`users`, :attr:`competitions`, :attr:`suites`, :attr:`announcements`, 112 :attr:`achievements`, :attr:`challenges`, :attr:`gauntlet`, 113 :attr:`instances`, 114 :attr:`records`, :attr:`nodes`, :attr:`observability`, :attr:`settings`, 115 :attr:`competition_admins`. 116 """ 117 118 def __init__(self, http: BaseHttpClient) -> None: 119 #: Shared transport (the parent PlatformClient when reached via 120 #: ``client.admin``, or an owned client when built via ``connect``). 121 self._http = http 122 123 @classmethod 124 def connect( 125 cls, 126 server_url: str, 127 token: str = "", 128 *, 129 max_retries: int = 2, 130 timeout: int = DEFAULT_CLIENT_TIMEOUT, 131 ) -> AdminClient: 132 """Build an ``AdminClient`` that owns its own transport. 133 134 For operator tooling that doesn't already hold a 135 :class:`PlatformClient`. The returned client is a context manager 136 that closes its transport on exit. 137 """ 138 base = server_url.rstrip("/") 139 http = BaseHttpClient(f"{base}/api/v1", token, timeout=timeout, max_retries=max_retries) 140 return cls(http) 141 142 @cached_property 143 def users(self) -> AdminUsersResource: 144 return AdminUsersResource(self._http) 145 146 @cached_property 147 def competitions(self) -> AdminCompetitionsResource: 148 return AdminCompetitionsResource(self._http) 149 150 @cached_property 151 def suites(self) -> AdminSuitesResource: 152 """A suite through its own door: its own fields only (#2896).""" 153 return AdminSuitesResource(self._http) 154 155 @cached_property 156 def announcements(self) -> AdminAnnouncementsResource: 157 return AdminAnnouncementsResource(self._http) 158 159 @cached_property 160 def changelog(self) -> AdminChangelogResource: 161 return AdminChangelogResource(self._http) 162 163 @cached_property 164 def contact_messages(self) -> AdminContactMessagesResource: 165 """What visitors wrote on the Contact page (#3414).""" 166 return AdminContactMessagesResource(self._http) 167 168 @cached_property 169 def institutions(self) -> AdminInstitutionsResource: 170 return AdminInstitutionsResource(self._http) 171 172 @cached_property 173 def exclusion_groups(self) -> AdminExclusionGroupsResource: 174 return AdminExclusionGroupsResource(self._http) 175 176 @cached_property 177 def achievements(self) -> AdminAchievementsResource: 178 return AdminAchievementsResource(self._http) 179 180 @cached_property 181 def challenges(self) -> AdminChallengesResource: 182 return AdminChallengesResource(self._http) 183 184 @cached_property 185 def gauntlet(self) -> AdminGauntletResource: 186 return AdminGauntletResource(self._http) 187 188 @cached_property 189 def email(self) -> AdminEmailResource: 190 return AdminEmailResource(self._http) 191 192 @cached_property 193 def ip_location(self) -> AdminIpLocationResource: 194 return AdminIpLocationResource(self._http) 195 196 @cached_property 197 def llm_calls(self) -> AdminLlmCallsResource: 198 return AdminLlmCallsResource(self._http) 199 200 @cached_property 201 def llm_providers(self) -> AdminLlmProvidersResource: 202 return AdminLlmProvidersResource(self._http) 203 204 @cached_property 205 def patches(self) -> AdminPatchesResource: 206 return AdminPatchesResource(self._http) 207 208 @cached_property 209 def reports(self) -> AdminReportsResource: 210 return AdminReportsResource(self._http) 211 212 @cached_property 213 def awd(self) -> AdminAwdResource: 214 return AdminAwdResource(self._http) 215 216 @cached_property 217 def series(self) -> AdminSeriesResource: 218 return AdminSeriesResource(self._http) 219 220 @cached_property 221 def instances(self) -> AdminInstancesResource: 222 return AdminInstancesResource(self._http) 223 224 @cached_property 225 def records(self) -> AdminRecordsResource: 226 return AdminRecordsResource(self._http) 227 228 @cached_property 229 def nodes(self) -> AdminNodesResource: 230 return AdminNodesResource(self._http) 231 232 @cached_property 233 def observability(self) -> AdminObservabilityResource: 234 return AdminObservabilityResource(self._http) 235 236 @cached_property 237 def settings(self) -> AdminSettingsResource: 238 return AdminSettingsResource(self._http) 239 240 @cached_property 241 def competition_admins(self) -> AdminCompetitionAdminsResource: 242 return AdminCompetitionAdminsResource(self._http) 243 244 @cached_property 245 def admin_invites(self) -> AdminAdminInvitesResource: 246 """Invite an address with no account yet to be an administrator.""" 247 return AdminAdminInvitesResource(self._http) 248 249 @cached_property 250 def competition_invites(self) -> AdminCompetitionInvitesResource: 251 return AdminCompetitionInvitesResource(self._http) 252 253 @cached_property 254 def competition_applications(self) -> AdminCompetitionApplicationsResource: 255 """Applications to a private competition, and the verdict on each.""" 256 return AdminCompetitionApplicationsResource(self._http) 257 258 @cached_property 259 def competition_attachments(self) -> AdminCompetitionAttachmentsResource: 260 """A competition's rules / handbook / notice files (#1808).""" 261 return AdminCompetitionAttachmentsResource(self._http) 262 263 @cached_property 264 def competition_boards(self) -> AdminCompetitionBoardsResource: 265 """A competition's extra boards — published and shadow (#1965 G).""" 266 return AdminCompetitionBoardsResource(self._http) 267 268 @cached_property 269 def recap(self) -> AdminRecapResource: 270 """A competition's recap, its publication and its report email (#3023).""" 271 return AdminRecapResource(self._http) 272 273 @cached_property 274 def challenge_schedule(self) -> AdminChallengeScheduleResource: 275 """When each challenge of a competition appears and shuts (#2093).""" 276 return AdminChallengeScheduleResource(self._http) 277 278 @cached_property 279 def release_plan(self) -> AdminReleasePlanResource: 280 """Waves, per-challenge rules and hints: drafts, publish, release (#2093, #2101).""" 281 return AdminReleasePlanResource(self._http) 282 283 @cached_property 284 def env_sharing(self) -> AdminEnvSharingResource: 285 """How many teams stand on one environment, the groups behind it and 286 the health of the shared environments (#2129 B).""" 287 return AdminEnvSharingResource(self._http) 288 289 @cached_property 290 def machines(self) -> AdminMachinesResource: 291 """Machine logins handed to teams, captain-only (#2132).""" 292 return AdminMachinesResource(self._http) 293 294 @cached_property 295 def messages(self) -> AdminMessagesResource: 296 """Site messages from an event's organisers or the platform (#2073).""" 297 return AdminMessagesResource(self._http) 298 299 @cached_property 300 def prewarm(self) -> AdminPrewarmResource: 301 """Whether a competition's images are warm on its nodes (#2129).""" 302 return AdminPrewarmResource(self._http) 303 304 @cached_property 305 def competition_topics(self) -> AdminCompetitionTopicsResource: 306 """A competition's scheduled topics, released by the clock (#1965).""" 307 return AdminCompetitionTopicsResource(self._http) 308 309 @cached_property 310 def registrations(self) -> AdminRegistrationsResource: 311 """Entrant roster, eligibility review, and CSV export.""" 312 return AdminRegistrationsResource(self._http) 313 314 @cached_property 315 def teams(self) -> AdminTeamsResource: 316 """Enforcement against a squad — disqualify and reinstate. 317 318 Separate from ``registrations`` on purpose: that one rules on 319 eligibility (which decides prizes), this one decides whether the 320 team is in the event at all. 321 """ 322 return AdminTeamsResource(self._http) 323 324 @cached_property 325 def challenge_stats(self) -> AdminChallengeStatsResource: 326 """How players did against an event's challenges: the organiser's 327 table and the single-challenge reading (#2146).""" 328 return AdminChallengeStatsResource(self._http) 329 330 @cached_property 331 def risk(self) -> AdminRiskResource: 332 """Risk control: the case queue (organisers) and an account's sealed 333 sightings (platform administrators). Detection reports; people decide.""" 334 return AdminRiskResource(self._http) 335 336 @cached_property 337 def tasks(self) -> AdminTasksResource: 338 return AdminTasksResource(self._http) 339 340 @cached_property 341 def scheduled_jobs(self) -> AdminScheduledJobsResource: 342 return AdminScheduledJobsResource(self._http) 343 344 @cached_property 345 def authored_challenges(self) -> AdminAuthoredChallengesResource: 346 """The review queue for player-authored challenges.""" 347 return AdminAuthoredChallengesResource(self._http) 348 349 @cached_property 350 def authoring_reviewers(self) -> AdminAuthoringReviewersResource: 351 """Who may rule on one competition's uploads (super-admin).""" 352 return AdminAuthoringReviewersResource(self._http) 353 354 @cached_property 355 def competition_authored_challenges(self) -> AdminCompetitionAuthoredChallengesResource: 356 """One competition's uploads, for its delegated reviewer: read, 357 audit and rule — never publish.""" 358 return AdminCompetitionAuthoredChallengesResource(self._http) 359 360 @cached_property 361 def llm_models(self) -> AdminLlmModelsResource: 362 return AdminLlmModelsResource(self._http) 363 364 @cached_property 365 def eval_vendors(self) -> AdminEvalVendorsResource: 366 return AdminEvalVendorsResource(self._http) 367 368 @cached_property 369 def eval_harnesses(self) -> AdminEvalHarnessesResource: 370 return AdminEvalHarnessesResource(self._http) 371 372 @property 373 def eval_allowances(self) -> AdminEvalAllowancesResource: 374 return AdminEvalAllowancesResource(self._http) 375 376 @property 377 def registry(self) -> AdminRegistryResource: 378 """Registry storage: the usage report and the manual reclaim.""" 379 return AdminRegistryResource(self._http) 380 381 @cached_property 382 def eval_runs(self) -> AdminEvalRunsResource: 383 return AdminEvalRunsResource(self._http) 384 385 @cached_property 386 def eval_campaigns(self) -> AdminEvalCampaignsResource: 387 return AdminEvalCampaignsResource(self._http) 388 389 def close(self) -> None: 390 """Close the underlying transport. 391 392 Only call this on a standalone client built via :meth:`connect`; 393 when reached via ``PlatformClient.admin`` the transport is shared 394 with — and closed by — the parent player client. 395 """ 396 self._http.close() 397 398 def __enter__(self) -> Self: 399 return self 400 401 def __exit__( 402 self, 403 exc_type: type[BaseException] | None, 404 exc: BaseException | None, 405 tb: TracebackType | None, 406 ) -> None: 407 self.close()
Admin / operator surface, grouped into resource namespaces.
Namespaces: users, competitions, suites, announcements,
achievements, challenges, gauntlet,
instances,
records, nodes, observability, settings,
competition_admins.
123 @classmethod 124 def connect( 125 cls, 126 server_url: str, 127 token: str = "", 128 *, 129 max_retries: int = 2, 130 timeout: int = DEFAULT_CLIENT_TIMEOUT, 131 ) -> AdminClient: 132 """Build an ``AdminClient`` that owns its own transport. 133 134 For operator tooling that doesn't already hold a 135 :class:`PlatformClient`. The returned client is a context manager 136 that closes its transport on exit. 137 """ 138 base = server_url.rstrip("/") 139 http = BaseHttpClient(f"{base}/api/v1", token, timeout=timeout, max_retries=max_retries) 140 return cls(http)
Build an AdminClient that owns its own transport.
For operator tooling that doesn't already hold a
PlatformClient. The returned client is a context manager
that closes its transport on exit.
150 @cached_property 151 def suites(self) -> AdminSuitesResource: 152 """A suite through its own door: its own fields only (#2896).""" 153 return AdminSuitesResource(self._http)
A suite through its own door: its own fields only (#2896).
163 @cached_property 164 def contact_messages(self) -> AdminContactMessagesResource: 165 """What visitors wrote on the Contact page (#3414).""" 166 return AdminContactMessagesResource(self._http)
What visitors wrote on the Contact page (#3414).
244 @cached_property 245 def admin_invites(self) -> AdminAdminInvitesResource: 246 """Invite an address with no account yet to be an administrator.""" 247 return AdminAdminInvitesResource(self._http)
Invite an address with no account yet to be an administrator.
253 @cached_property 254 def competition_applications(self) -> AdminCompetitionApplicationsResource: 255 """Applications to a private competition, and the verdict on each.""" 256 return AdminCompetitionApplicationsResource(self._http)
Applications to a private competition, and the verdict on each.
258 @cached_property 259 def competition_attachments(self) -> AdminCompetitionAttachmentsResource: 260 """A competition's rules / handbook / notice files (#1808).""" 261 return AdminCompetitionAttachmentsResource(self._http)
A competition's rules / handbook / notice files (#1808).
263 @cached_property 264 def competition_boards(self) -> AdminCompetitionBoardsResource: 265 """A competition's extra boards — published and shadow (#1965 G).""" 266 return AdminCompetitionBoardsResource(self._http)
A competition's extra boards — published and shadow (#1965 G).
268 @cached_property 269 def recap(self) -> AdminRecapResource: 270 """A competition's recap, its publication and its report email (#3023).""" 271 return AdminRecapResource(self._http)
A competition's recap, its publication and its report email (#3023).
273 @cached_property 274 def challenge_schedule(self) -> AdminChallengeScheduleResource: 275 """When each challenge of a competition appears and shuts (#2093).""" 276 return AdminChallengeScheduleResource(self._http)
When each challenge of a competition appears and shuts (#2093).
278 @cached_property 279 def release_plan(self) -> AdminReleasePlanResource: 280 """Waves, per-challenge rules and hints: drafts, publish, release (#2093, #2101).""" 281 return AdminReleasePlanResource(self._http)
Waves, per-challenge rules and hints: drafts, publish, release (#2093, #2101).
283 @cached_property 284 def env_sharing(self) -> AdminEnvSharingResource: 285 """How many teams stand on one environment, the groups behind it and 286 the health of the shared environments (#2129 B).""" 287 return AdminEnvSharingResource(self._http)
How many teams stand on one environment, the groups behind it and the health of the shared environments (#2129 B).
289 @cached_property 290 def machines(self) -> AdminMachinesResource: 291 """Machine logins handed to teams, captain-only (#2132).""" 292 return AdminMachinesResource(self._http)
Machine logins handed to teams, captain-only (#2132).
294 @cached_property 295 def messages(self) -> AdminMessagesResource: 296 """Site messages from an event's organisers or the platform (#2073).""" 297 return AdminMessagesResource(self._http)
Site messages from an event's organisers or the platform (#2073).
299 @cached_property 300 def prewarm(self) -> AdminPrewarmResource: 301 """Whether a competition's images are warm on its nodes (#2129).""" 302 return AdminPrewarmResource(self._http)
Whether a competition's images are warm on its nodes (#2129).
304 @cached_property 305 def competition_topics(self) -> AdminCompetitionTopicsResource: 306 """A competition's scheduled topics, released by the clock (#1965).""" 307 return AdminCompetitionTopicsResource(self._http)
A competition's scheduled topics, released by the clock (#1965).
309 @cached_property 310 def registrations(self) -> AdminRegistrationsResource: 311 """Entrant roster, eligibility review, and CSV export.""" 312 return AdminRegistrationsResource(self._http)
Entrant roster, eligibility review, and CSV export.
314 @cached_property 315 def teams(self) -> AdminTeamsResource: 316 """Enforcement against a squad — disqualify and reinstate. 317 318 Separate from ``registrations`` on purpose: that one rules on 319 eligibility (which decides prizes), this one decides whether the 320 team is in the event at all. 321 """ 322 return AdminTeamsResource(self._http)
Enforcement against a squad — disqualify and reinstate.
Separate from registrations on purpose: that one rules on
eligibility (which decides prizes), this one decides whether the
team is in the event at all.
324 @cached_property 325 def challenge_stats(self) -> AdminChallengeStatsResource: 326 """How players did against an event's challenges: the organiser's 327 table and the single-challenge reading (#2146).""" 328 return AdminChallengeStatsResource(self._http)
How players did against an event's challenges: the organiser's table and the single-challenge reading (#2146).
330 @cached_property 331 def risk(self) -> AdminRiskResource: 332 """Risk control: the case queue (organisers) and an account's sealed 333 sightings (platform administrators). Detection reports; people decide.""" 334 return AdminRiskResource(self._http)
Risk control: the case queue (organisers) and an account's sealed sightings (platform administrators). Detection reports; people decide.
376 @property 377 def registry(self) -> AdminRegistryResource: 378 """Registry storage: the usage report and the manual reclaim.""" 379 return AdminRegistryResource(self._http)
Registry storage: the usage report and the manual reclaim.
389 def close(self) -> None: 390 """Close the underlying transport. 391 392 Only call this on a standalone client built via :meth:`connect`; 393 when reached via ``PlatformClient.admin`` the transport is shared 394 with — and closed by — the parent player client. 395 """ 396 self._http.close()
Close the underlying transport.
Only call this on a standalone client built via connect();
when reached via PlatformClient.admin the transport is shared
with — and closed by — the parent player client.