Roles & permissions
The composition
Section titled “The composition”Every guarded request evaluates:
effective permission = organization role base grant from your membership + repository override per-repository access level, when set + token scope a hard cap — never widens + account status must be ACTIVE + organization status must be activeAny input denying produces 403 forbidden. Scopes only ever subtract.
Permissions
Section titled “Permissions”The granular capabilities the API checks. You rarely name these directly, but they’re what the tables below resolve to.
| Permission | Covers |
|---|---|
organization.read |
Read the organization |
organization.update |
Change settings, manage webhooks |
organization.delete |
Delete the organization |
members.read |
List members |
members.invite |
Invite members |
members.remove |
Remove members, change roles |
billing.read |
Read plan, subscription, invoices |
billing.update |
Checkout, billing portal, add-ons |
repositories.create |
Create repositories |
repositories.read |
List and read repositories |
repositories.update |
Change repository settings |
repositories.delete |
Delete repositories |
repository.pull |
Download objects |
repository.push |
Upload objects, index, snapshot |
repository.admin |
Full control of one repository |
repository.members.manage |
Manage collaborators and repository invitations |
tokens.create / tokens.revoke |
Manage API tokens |
audit.read |
Read the audit log |
usage.read |
Read usage and storage metrics |
storage.read / storage.manage |
Read / manage storage connections and groups |
Organization roles
Section titled “Organization roles”| Permission | OWNER | ADMIN | DEVELOPER | VIEWER | BILLING |
|---|---|---|---|---|---|
organization.read |
✓ | ✓ | ✓ | ✓ | ✓ |
organization.update |
✓ | ✓ | |||
organization.delete |
✓ | ||||
members.read |
✓ | ✓ | ✓ | ✓ | |
members.invite |
✓ | ✓ | |||
members.remove |
✓ | ✓ | |||
billing.read |
✓ | ✓ | |||
billing.update |
✓ | ✓ | |||
repositories.create |
✓ | ✓ | ✓ | ||
repositories.read |
✓ | ✓ | ✓ | ✓ | |
repositories.update |
✓ | ✓ | ✓ | ||
repositories.delete |
✓ | ✓ | |||
repository.pull |
✓ | ✓ | ✓ | ✓ | |
repository.push |
✓ | ✓ | ✓ | ||
repository.admin |
✓ | ✓ | |||
repository.members.manage |
✓ | ✓ | |||
tokens.create |
✓ | ✓ | ✓ | ||
tokens.revoke |
✓ | ✓ | ✓ | ||
audit.read |
✓ | ✓ | |||
usage.read |
✓ | ✓ | ✓ | ✓ | ✓ |
storage.read |
✓ | ✓ | ✓ | ✓ | |
storage.manage |
✓ | ✓ |
Picking a role
Section titled “Picking a role”| Person | Role | Why |
|---|---|---|
| Founder, platform lead | OWNER |
Needs deletion and billing |
| Team lead, SRE | ADMIN |
Manages people and storage, not spend |
| Engineer, researcher | DEVELOPER |
Pushes and pulls, makes repositories |
| Auditor, PM, stakeholder | VIEWER |
Reads and pulls only |
| Finance | BILLING |
Invoices and usage, no data |
| Contractor on one project | any + a repository override, or an external repository invitation | Least privilege |
Repository access overrides
Section titled “Repository access overrides”An override replaces the org role for that repository only.
| Access | Grants |
|---|---|
NONE |
Nothing. Revokes access an org role would otherwise give. |
READ |
repository.pull, repositories.read |
WRITE |
READ + repository.push, repositories.update |
ADMIN |
WRITE + repository.admin, repositories.delete, repository.members.manage |
Managed at Repository → Settings → Collaborators, or:
export API=https://cavsnode.com/api/v1export H="Authorization: Bearer $CAVS_TOKEN"
curl -sS "$API/repositories/$REPO/members" -H "$H"
curl -sS -X POST "$API/repositories/$REPO/members" \ -H "$H" -H "Content-Type: application/json" \ -d '{"user_id": "…", "access": "WRITE"}'
curl -sS -X DELETE "$API/repositories/$REPO/members/$USER_ID" -H "$H"Requires repository.members.manage (ADMIN/OWNER, or an ADMIN override).
Token scopes
Section titled “Token scopes”What each scope satisfies:
| Permission | repo:read |
repo:write |
repo:admin |
org:read |
usage:read |
|---|---|---|---|---|---|
repository.pull / repositories.read |
✓ | ✓ | ✓ | ||
repository.push / repositories.update |
✓ | ✓ | |||
repository.admin / repositories.delete |
✓ | ||||
repositories.create |
✓ | ||||
repository.members.manage |
✓ | ||||
organization.read / members.read |
✓ | ✓ | |||
usage.read |
✓ | ✓ |
Note the two conveniences: repo:read also satisfies organization reads (so a
read-only token can resolve slugs), and org:read also satisfies usage reads.
Anything not in this table — billing, audit, token management, storage connections, organization update or delete — cannot be reached by any token scope. Those operations require a Firebase-authenticated session with the right role. This is intentional: a leaked CI token can’t change your plan, read your audit trail, mint more tokens or repoint your storage.
Worked examples
Section titled “Worked examples”| Situation | Outcome |
|---|---|
DEVELOPER + repo:write token → push |
✓ |
VIEWER + repo:write token → push |
✗ 403 — the role doesn’t grant push; the scope can’t add it |
DEVELOPER + repo:read token → push |
✗ 403 — the scope caps it |
DEVELOPER, repository override NONE → pull that repository |
✗ 403 |
VIEWER, repository override WRITE → push that repository |
✓ |
cavs_ci_ with repo:write, no user → push |
✓ — scope alone decides |
cavs_ci_ with repo:admin → read the audit log |
✗ 403 — no scope reaches audit |
| Any role, suspended account | ✗ 403 — “account is suspended” |
ADMIN → start a checkout |
✗ 403 — billing is OWNER/BILLING |
Debugging a 403
Section titled “Debugging a 403”GET /users/me— which organizations and roles does this credential actually see?- If it’s a token, check its scopes in the token list. Is the scope narrower than the operation?
- Check for a repository override on the repository in question — an override wins over the role.
- Check the account and organization status.
- Confirm the operation is reachable by tokens at all (billing, audit, token and storage management are not).
The request_id in the error body ties the denial to a specific server-side
event if you need support to look.
- API tokens — creating and scoping them.
- Invitations & collaborators — sharing with people outside your org.
- Audit log — verifying what was done.

