SPB Git

Repository Public MIT

PERMISSIONS.md 9.9 KB

# Permissions

Source of truth: packages/registry-core/src/constants.ts (scopes), apps/web/src/server/api.ts (route table), apps/web/src/server/auth.ts (rules). If this file and the code disagree, the code is right and this file has a bug.

# Principals

Principal How it authenticates What it carries
Anonymous nothing read access to public content, abuse reports
Session skills_session cookie after email + password login every non-elevated right of the user; elevated rights if the user is owner or admin; token creation and rotation need a password entry within 15 minutes
Token Authorization: Bearer skr_… exactly its scopes, within exactly its namespaces
Local operator shell on the server, pnpm admin … everything; never reachable over the network

# Scopes

Scope Allows In the default publisher token
artifacts:read Read artifacts in allowed namespaces, including non-public ones yes
artifacts:create Create artifacts in allowed namespaces yes
artifacts:update Update mutable metadata: summary, description, links, keywords, visibility yes
artifacts:deprecate Deprecate, undeprecate or archive artifacts no
uploads:create Begin release uploads and send archive bytes yes
releases:publish Finalize an upload into an immutable release yes
releases:update Edit release notes only yes
releases:revoke Revoke a compromised release no
tokens:read List the owner's tokens (metadata only) no
tokens:write Create or revoke tokens, never broader than the calling token no
audit:read Read the owner's audit trail no
admin:moderate ELEVATED. Reports, quarantine review, takedown, platform audit trail no
admin:settings ELEVATED. Collection curation no

Rules that apply on top of scopes:

  • Every write to an artifact or release also requires that the user owns the namespace (or holds org_admin or publisher in the owning organization) and, for a token, that the namespace is in the token's list.
  • Elevated scopes are only honoured for users whose platform role is owner or admin. Elevated tokens expire within 24 hours and cannot be issued or rotated by another token.
  • A token can always revoke or rotate itself without any token scope.
  • Public visibility, deprecation, archival, revocation and takedown require an explicit confirm / confirmPublic flag in the request; without it the API answers 428.

# Route matrix

All paths are under /api/v1. "Bucket" is the rate-limit bucket; the key is the token id, else the user id, else the client IP.

Method Path Auth Scope Bucket Idempotency-Key
GET /health/live public — — —
GET /health/ready public — — —
GET /openapi.json public — — —
GET /artifacts public — anon-read —
GET /search public — search —
GET /categories public — anon-read —
GET /collections public — anon-read —
GET /collections/{slug} public — anon-read —
GET /artifacts/{id} public — anon-read —
GET /artifacts/{namespace}/{slug} public — anon-read —
GET /artifacts/{namespace}/{slug}/versions public — anon-read —
GET /artifacts/{namespace}/{slug}/history public — anon-read —
GET /artifacts/{namespace}/{slug}/versions/{version} public — anon-read —
GET /artifacts/{namespace}/{slug}/versions/{version}/download public — download —
GET /artifacts/{namespace}/{slug}/versions/{version}/checksum public — anon-read —
GET /artifacts/{namespace}/{slug}/versions/{version}/files?path= public — anon-read —
GET /artifacts/{namespace}/{slug}/versions/{version}/install?client= public — anon-read —
POST /artifacts required artifacts:create token-write yes
PATCH /artifacts/{id} required artifacts:update token-write —
POST /artifacts/{id}/releases required uploads:create upload yes
GET /uploads/{id} required uploads:create token-write —
PUT /uploads/{id} required uploads:create upload —
POST /uploads/{id}/finalize required releases:publish publish yes
POST /artifacts/{id}/deprecate required artifacts:deprecate token-write —
POST /artifacts/{id}/undeprecate required artifacts:deprecate token-write —
POST /artifacts/{id}/archive required artifacts:deprecate token-write —
POST /releases/{id}/revoke required releases:revoke token-write —
PATCH /releases/{id} required releases:update token-write —
POST /validate-manifest required any token-write —
GET /me required any token-write —
GET /me/tokens required tokens:read token-write —
POST /me/tokens required tokens:write token-write —
DELETE /me/tokens/{id} required self: any; other tokens: tokens:write token-write —
POST /me/tokens/{id}/rotate required self: any; other tokens: tokens:write token-write —
GET /me/audit required audit:read token-write —
POST /reports public — report —
GET /admin/reports required admin:moderate token-write —
POST /admin/reports/{id}/resolve required admin:moderate token-write —
GET /admin/quarantine required admin:moderate token-write —
POST /admin/releases/{id}/review required admin:moderate token-write —
POST /admin/artifacts/{id}/moderate required admin:moderate token-write —
GET /admin/audit required admin:moderate token-write —

Public read routes still honour credentials: with a session or a suitable token, the same routes also return the caller's private, draft and quarantined items.

Not exposed over HTTP at all: owner bootstrap, user creation, namespace creation, password recovery, identity verification of a namespace. These exist only in the server console.

# Rate-limit buckets

Bucket Limit Window
anon-read 240 60 s
search 90 60 s
download 120 60 s
mcp 240 60 s
token-write 120 60 s
upload 30 1 h
publish 30 1 h
report 5 1 h
login 8 15 min (per IP and email)
auth-fail 20 10 min (per IP; locks out bearer authentication)

Responses carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Exceeding a limit returns 429 with Retry-After. Limits are held in process memory (ADR-0004).

# Roles

Platform roles are a column on users. Organization roles are rows in memberships.

Role Status in V1 Rights
Anonymous Implemented + tested Read public artifacts, releases, files, collections; download; file abuse reports
Member (platform) Implemented + tested Everything anonymous can do, plus publish to namespaces they own, manage their own tokens, read their own audit trail
Publisher (organization) Authorization check implemented; no interface to create organizations or memberships Publish to namespaces owned by the organization
Organization admin Same as above Same publish rights as publisher in V1; member management is Planned
Reviewer (platform or organization) Schema only Grants nothing in V1
Platform admin Implemented; role is assigned by the operator in the database Moderation (admin:moderate), curation (admin:settings), read private artifacts through a session. No implicit right to publish in someone else's namespace
Platform owner Implemented + tested Same as platform admin. Exactly one owner can exist (database constraint). Created only by pnpm admin:bootstrap
Local operator Implemented Server console: bootstrap, create users and namespaces, issue or revoke any user's tokens, recover accounts, verify namespace identity, seed and curate collections, cleanup

Planned: organization management, member invitations, ownership transfers with two-party confirmation, a reviewer role that can approve quarantined releases without full moderation rights.

# Troubleshooting 401 and 403

Status error.code Meaning What to do
401 unauthorized No credential sent Add Authorization: Bearer <token> or run skills login
401 invalid_token Malformed, unknown, wrong secret, IP not on the allowlist, or the user is disabled Check the stored token and the calling IP; create a new token
401 token_expired Past expiresAt Create a new token (an expired token cannot be rotated)
401 token_revoked Revoked or replaced by rotation Use the replacement or create a new token
403 insufficient_scope The token lacks the scope named in details.required Issue a token with that scope
403 namespace_forbidden The namespace is not yours or not on this token Use a token that lists the namespace
403 reauth_required Session password entry is older than 15 minutes Re-enter the password
403 admin_required / elevation_forbidden Elevated action without an administrator session or elevated token Use the dashboard or an elevated console-issued token
403 csrf Cookie-authenticated write without same-origin and CSRF token Use a bearer token for scripts
403 password_change_required Initial password not yet changed Sign in on the website and change it
428 confirmation_required Destructive or exposing action without confirmation Resend with confirm: true / confirmPublic: true after a human approved it
429 rate_limited Too many requests or too many failed authentications from this IP Wait for Retry-After
Files main
Menu

Theme