ump_sdk.scope
module ump-sdk
Who is calling, and which clients and actions they may touch (IAP/OIDC stand-in, read from core).
Apps call await caller_scope(p, core_url=..., transport=...) with the caller’s Principal (forwarded
X-UMP-Principal). It asks core GET /v1/whoami as that principal, caches the answer for a few seconds,
and returns a :class:CallerScope:
allows(client_id)andfilter(rows)for app-local data (sessions, scenarios, plan commitments);require_client(client_id)andrequire(permission)raise a 403FORBIDDENproblem whosedetailis one plain sentence (extra.reasonisclient_scopeorrole).
Permissions mirror core’s whoami.permissions: create_drafts, review, approve, anchor,
grant_override. Core stays the authority: it enforces the same rules on every forwarded write.
When core cannot be asked (not running, or a test double without /v1/whoami), the scope is
verified=False and allows everything; core still refuses out-of-scope writes. This keeps app unit tests
with mocked cores working, and is labelled in as_dict()["verified"].
Service principals (documented, used only for background or system work, never for a user’s request):
service:planner (stale sweeps), service:e2e-seed (pool-only benchmark contributors in the e2e
seed), service:<app> for scheduled jobs. Core treats service:* as all-client with draft and submit
scope and never lets one approve.
Classes
Section titled “Classes”CallerScope
Section titled “CallerScope”class
class CallerScopeFields
| Name | Type | Default | Description |
|---|---|---|---|
principal | str | ||
name | str | None | None | |
roles | tuple[str, ...] | () | |
clients | frozenset[str] | None | None | None means every client. |
is_agent | bool | False | |
permissions | dict[str, Any] | field(default_factory=dict) | |
verified | bool | True |
Methods and properties (10)
all_clients property
all_clients: boolread_only property
read_only: boolwho property
who: strcan method
def can(self, permission: str) -> boolallows method
def allows(self, client_id: str | None) -> boolfilter method
def filter(self, rows: Iterable[Any], key: str = 'client_id') -> list[Any]require_client method
def require_client(self, client_id: str | None, what: str = 'this client') -> Nonerequire method
def require(self, permission: str, what: str | None = None) -> Noneas_dict method
def as_dict(self) -> dict[str, Any]init constructor
CallerScope( self, principal: str, name: str | None = None, roles: tuple[str, ...] = (), clients: frozenset[str] | None = None, is_agent: bool = False, permissions: dict[str, Any] = dict(), verified: bool = True,) -> NoneSource: packages/ump-sdk/src/ump_sdk/scope.py, line 59
Functions
Section titled “Functions”caller_scope
Section titled “caller_scope”function
async def caller_scope( p: Principal | str, *, core_url: str | None = None, transport: Any = None, ttl: float = 10.0, fresh: bool = False,) -> CallerScopeThe caller’s scope from core /v1/whoami (cached ttl seconds per principal; fresh skips the
cache, e.g. after the caller created a client and was bound to it).
Source: packages/ump-sdk/src/ump_sdk/scope.py, line 144
caller_scope_sync
Section titled “caller_scope_sync”function
def caller_scope_sync( p: Principal | str, *, core_url: str | None = None, transport: Any = None, ttl: float = 10.0, fresh: bool = False,) -> CallerScopeSync twin of :func:caller_scope for sync route handlers (planner).
Source: packages/ump-sdk/src/ump_sdk/scope.py, line 168
invalidate_scope_cache
Section titled “invalidate_scope_cache”function
def invalidate_scope_cache() -> NoneSource: packages/ump-sdk/src/ump_sdk/scope.py, line 136
scope_from_whoami
Section titled “scope_from_whoami”function
def scope_from_whoami(d: dict[str, Any]) -> CallerScopeSource: packages/ump-sdk/src/ump_sdk/scope.py, line 122
require_client_scope
Section titled “require_client_scope”function
async def require_client_scope( p: Principal | str, client_id: str | None, what: str = 'this client', *, core_url: str | None = None, transport: Any = None,) -> CallerScopeRaise 403 unless client_id is in the caller’s scope (asks core again before refusing, so a client
the caller just created counts). Returns the scope.
Source: packages/ump-sdk/src/ump_sdk/scope.py, line 194
Constants
Section titled “Constants”| Name | Type | Value | Description |
|---|---|---|---|
SERVICE_PRINCIPALS | {'service:planner': 'planner background sweeps (stale scenarios after a model... |