Alpha. Vary is under active development and not ready for production use. Syntax, APIs, performance, and behaviour may change between releases.

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.