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).
Capability checks live in three places:
| Layer | Responsibility |
|---|---|
| Route metadata | Declares policy via auth capability clauses. |
| Runtime | Verifies session, exposes capability set on ctx. |
| Handler | Ad-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).
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")
| Constructor | Purpose |
|---|---|
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?)
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:
| Helper | Capability |
|---|---|
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").
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.
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())
}
auth capabilityauth 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.