Standard Library

access

import access keeps capability checks, allowed issue actions, audit writes, and rate-limit decisions in one reusable component instead of handler-local checks. The module pairs with import api_context (which exposes the verified caller) and with route auth and capability clauses (which declare the policy).

Mental model

Capability checks live in three places:

LayerResponsibility
Route metadataDeclares policy via auth capability clauses.
RuntimeVerifies session, exposes capability set on ctx.
HandlerAd-hoc checks via api_context and access.

The route adds extra capability clauses for cross-cutting requirements; the runtime publishes the verified set as RequestContext.capabilities; the handler uses access for richer authorizers (roles, allow-listed actions, rate-limit keys, audit writes).

Building services

import access

let svc = access.memory_service()
let user = access.tracker_principal(
    user_id = "u1",
    session_id = "s1",
    api_token_id = "",
    profile = "moderator",
    trust_level = "trusted")
ConstructorPurpose
memory_service()Deterministic in-memory AccessService for tests.
anonymous_user(ip)Anonymous principal keyed by IP.
authenticated_user(user_id, session_id, ...)Authenticated principal with capability/role list.
tracker_principal(user_id, session_id, ...)Issue-tracker principal from profile or token scope.

Full signatures:

authenticated_user(user_id, session_id, api_token_id?, roles?,
                   trust_level?, suspended?)
tracker_principal(user_id, session_id, api_token_id?, profile?,
                  trust_level?, suspended?, token_scopes?)

Roles and capabilities

import access

let cap_read = access.capability("issues.private.read")
let cap_write = access.issue_create()

access.capability(name) declares a required handler capability; access.role(name, capabilities) declares a role with a comma-separated capability list.

The module also ships built-in capability constructors for the issue tracker domain:

HelperCapability
issue_create()issues.create
issue_private_read()issues.private.read
issue_comment()issues.comment
issue_edit_own()issues.edit.own
issue_triage()issues.triage
issue_lock()issues.lock
issue_delete()issues.delete
issue_moderate()issues.moderate
user_suspend()users.suspend
audit_read()audit.read

tracker_profile_capabilities(profile) returns the comma-separated capability set for a reusable access profile (e.g. "member", "triager", "moderator").

Rate-limit keys

import access

let rate_key = access.rate_limit_key(
    request_ip,
    actor_user_id,
    "/api/v1/issues",
    "create",
    trust_level)

Rate-limit keys cover at least IP, user, route, action, and trust level so a single hostile client cannot exhaust a route by rotating one dimension. See Public API security: audit and rate limits.

Issue-tracker example

import access
import api_context

def moderate_issue(request: ModerateIssueRequest, ctx: RequestContext, svc: AccessService) -> Str {
    api_context.required_capability(ctx, "issues.moderate")?
    let actor = api_context.authenticated_user(ctx)?
    let principal = access.tracker_principal(
        actor.value, ctx.session_id ?: "", "", "moderator", "trusted")
    let allowed = svc.allowed_actions(principal, request.issue_id)
    if not allowed.contains("moderate") {
        return api_response.capability_error("forbidden", "issues.moderate", ctx.request_id.value)
    }
    svc.record_audit_event(...)
    return api_response.ok_object("issue", Json.empty_object())
}

Relation to route auth capability

auth capability <name> requires both auth_verified and the named capability. access is what fills out the capability story past that gate: derive capabilities from a role or profile, run extra cross-cutting checks, and emit audit events with the same actor identity the authorizer used.

← Time
Environment →