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:
| 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).
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")
| 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?)
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:
| 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").
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.