Policy Spec

What a principal may do, written as a TOML file: its grants, each some actions on some resources, and its limits. The same file is an API key's scopes, a role, an agent's grants beyond its sandbox, and what a host lets a guest it accepted do. What it doesn't grant is refused.

Every option

name and version are needed, and every other key is optional.

# ci.toml
name = "ci"
version = 1

# A grant: every action it names, on every resource it names.
[[allow]]
actions = ["cloud.read", "cloud.use"]
on = ["cloud:aws", "cloud:ci-*"]

[[allow]]
actions = ["box.*"]
on = ["box:ci-*"]

# How much: each left out is no limit but the service's own.
[limits]
boxes = 2          # boxes at once
cpus = 4           # CPUs a box
memory_gb = 8      # memory a box, in GB
disk_gb = 40       # disk a box, in GB
hours = 12         # how long a box lives

A policy holds at most 64 grants. A key it doesn't have is refused by its name, as an empty table is.

Actions

An action is <kind>.<verb>, from one list: a verb the list doesn't hold can't be granted or checked. Three verbs a kind: what's read, what's used, what changes it.

Agent actions

agent.read reads an agent's status and logs, agent.message messages it (a teammate's message, a post to its webhook), and agent.admin starts, stops, moves it or changes its spec.

Team actions

team.read reads a team, team.member is on it (its chats, its folder, its spec), and team.admin changes who's on it and what each reaches.

Bucket actions

bucket.read reads and lists a bucket or a path of it, bucket.write writes there, and bucket.share shares it. A path is the resource's id after the bucket's, bucket:team-r7/drafts/, and a pattern reaches what it begins, bucket:team-r7/drafts/*.

Cloud actions

cloud.read reads a cloud's boxes and limits. cloud.use has boxes made on it within those limits, and cloud.admin accepts it and changes who may use it.

Box actions

box.read reads a box, box.ssh reaches it over SSH, and box.admin makes, deletes or resizes it. These verbs apply to box resources rather than cloud resources.

Grant patterns

A grant's actions takes an action, <kind>.* (every verb of a kind), or * (every action, the owner's). Its actions and its resources are of one kind: box.ssh on cloud:aws is refused.

Resources

A resource is named by its id, <kind>:<id>; another account's is <account>/<kind>:<id>, as in acct-7f3a/cloud:mac. A name without an account is the principal's own account's.

Resource patterns

A grant's on takes a name or a pattern. A * ends a pattern or is one; nothing else is a pattern, so a grant reads as what it reaches.

One resource

cloud:aws reaches that cloud alone. cloud:ci-* reaches every cloud whose id begins ci-, within the principal's account unless an account is named explicitly.

Clouds of one or every account

cloud:* reaches every cloud of the principal's account. */cloud:* reaches clouds of any account where the resource's [access] lets the principal in.

Every resource of the account

* reaches everything of the principal's account. Cross-account access still needs an account-qualified pattern and the resource's own [access] permission.

Principals

Each principal has a permanent id, <kind>:<id>, its id after its kind of the characters A-Z a-z 0-9 . _ : / -, at most 128:

Signed-in principals

person: identifies a signed-in person, and machine: identifies a machine by its machine key. Both principals end when they are signed out.

Agent principals

agent: identifies an agent wherever it runs. Its identity remains with the agent while it exists, and the principal ends when the agent is removed.

Principals with an expiry

api-key: identifies an API key and always expires. guest: is issued by a self-hosted host, without an account service, for a cloud session it accepted; a guest always expires, in hours.

Roles

A role is a Policy Spec given to principals: each holder may do what the role grants as if its own policy granted it, and a change to the role reaches every holder at once. A role is named by its name, lowercase letters, digits and -, which never changes: a renamed role is a new one. A role's pattern on agents, teams or buckets ends a segment, * alone or after a / (bucket:team-r7/*), since their ids are made, not chosen, and one beginning as another does is another's. A check allowed by a role says so, as "allowed by grant 1 of the role research".

A resource's [access]

A resource reached from outside its account says who in its own spec, in one section every resource's spec shares, a verb of its kind to a list: * (anyone), an account (acct-<id>, every principal of it) or a principal. A cloud's [access] with use = ["acct-7f3a"] lets every principal of that account have boxes made on it, when their own policy allows it too. Inside the account, the principal's policy alone decides, and [access] isn't read.

Policy boundaries

A policy states grants and limits. Its principal and the service that holds it determine when it ends and who receives it; the policy keeps no separate deny or conditional rule system.

  • No deny rules. What isn't granted is refused; a narrower principal is made rather than a wider one denied.
  • No conditions on a grant. No address, time or hours: an end is the principal's, and how much is [limits].
  • Not who it's given to. The service that holds the principal holds which policy it has.

The cases every check is held to are in tests/specs/policy/ of this workspace, each a policy and the answers it gives.

Checked reference

The field names below come from link_iam::Policy. Optional values remain unset until the feature resolves its environment or inherited settings.

root: allow, limits, name, version
allow: actions, on
limits: boxes, cpus, disk_gb, hours, memory_gb

Checked defaults

These values come from the shipped defaults, including nested settings. Omitted optional values have no stored default at this layer.

limits = {}