Code

Authorization with SpiceDB

Relationship-based authorization for Cuitty Code Apps and Registry.

Cuitty Git uses SpiceDB for relationship-based authorization across repositories, organizations, apps, installs, packages, and registry resources. The database remains the source of metadata, while SpiceDB answers permission checks.

Required services

Environment variables

SPICEDB_ENDPOINT=http://localhost:50051
SPICEDB_PRESHARED_KEY=dev-secret
AUTH_ISSUER=http://localhost:7705
AUTH_CLIENT_ID=cuitty-git

Use TLS and managed secrets for production SpiceDB deployments.

Schema and object types

Load the schema before API writes:

zed schema write spicedb/schema.zed

Representative object types include:

Verify representative permissions with known local data:

zed permission check user:alice read repository:acme/demo
zed permission check user:alice view package:acme/npm/acme-widget
zed permission check user:alice install app_listing:acme/review-bot

Permissions model

Security-expanding writes, such as creating public visibility, granting install permission, or publishing package access, should fail closed if SpiceDB writes cannot be committed. Security-reducing writes, such as revoking access or making a package private, should continue to be retried until the graph reflects the database state.

Private apps and packages may return 404 to callers without view permission. Authenticated callers with partial permission may receive 403 for actions such as publish, install, or settings updates.

Outbox statuses

Authorization relationship writes are recorded in authz_outbox with these statuses:

Inspect stuck rows directly when operational tooling is not available:

SELECT id, operation_kind, resource_kind, resource_id, status, attempts, last_error
FROM authz_outbox
WHERE status IN ('pending', 'processing', 'failed_retryable', 'failed_terminal')
ORDER BY created_at ASC
LIMIT 50;

Replay and reconciliation

Replay retryable relationship writes with the deployment’s authz dispatcher or maintenance command. If the deployment exposes only SQL access, mark stale processing rows back to pending after confirming no dispatcher is running, then restart the API or worker that drains the outbox.

UPDATE authz_outbox
SET status = 'pending'
WHERE status = 'processing'
  AND updated_at < datetime('now', '-15 minutes');

After replay, spot-check resource permissions with zed permission check and compare database visibility against SpiceDB relationships.

Failure modes and recovery