saphan identity
Seed, edit and project the signed identity store (import | export | enroll | revoke)
saphan identity
Seed, edit and project the signed identity store (import | export | enroll | revoke)
Subcommands
| Subcommand | What it does |
|---|---|
saphan identity enroll | Enroll an actor, binding, issuer or alias as a new owner-root-signed identity record |
saphan identity export | Regenerate the bridge/registry/*.md projection from the signed identity store |
saphan identity import | Seed the signed identity store from bridge/registry/*.md (import-once), then regenerate the .md projection |
saphan identity revoke | Revoke an actor, binding or issuer with a new owner-root-signed revoke record |
saphan identity enroll
Enroll an actor, binding, issuer or alias as a new owner-root-signed identity record
Appends one owner-root-signed enroll row to the signed identity_record store for the chosen --kind, then regenerates the .md projection. The kind- specific fields mirror the roster tables' columns:
--kind actor --subject <name> --key-id <apk-/wsk- id> [--reason <r>]
--kind binding --subject <client_id> --actor <name> --redirect-uri <uri> [--redirect-uri ...]
--stream <slug> [--stream ...] | --stream '*'
--kind issuer --subject <issuer-url> --alg <alg> --audience <aud> --jwks-uri <uri>
--kind alias --subject <old-name> --canonical <registry handle> [--reason <r>]
AN ALIAS SAYS THAT ONE HISTORICAL ACTOR SPELLING NAMES THE SAME PERSON AS ONE CANONICAL REGISTRY ACTOR — nothing more. It GRANTS NOTHING: it can never let a name sign, write or gate, and two laws bound it.
E-1 An alias resolves NAMES FOR AGGREGATION and NEVER A SIGNATURE. The gate
log renders the stored actor VERBATIM and may append a derived
"(= <canonical>)" marker beside it; the marker is never the column.
E-2 Aliases are BOUNDED BELOW THE GATE-ACTOR EPOCH. At or below that
boundary an old spelling is history and an alias may resolve it. ABOVE
it, an old spelling is a FORGERY, not an old spelling, and no alias
applies. A row being written is always above the boundary, so enrolling
an alias can never make a near-miss name writable.
Use it when the log carries decisions under a spelling that predates the actor column meaning a resolved registry handle. Do NOT use it to "fix" a typo an operator is making today: that earns the actor-near-miss refusal at the gate, and the remedy there is to type the canonical spelling, not to enrol it.
--stream IS THE ROW-LEVEL GRANT, and it is REQUIRED for a binding: a token bound to this client sees exactly the streams named here and nothing else. To grant the whole fleet, say so: --stream '*'. There is no default, because the default that used to exist — an absent grant read as "everything" — is how a token issued for one tenant read every other tenant's streams.
The per-subject sequence is DB-sourced (never caller-chosen); a revocation is a separate act ("identity revoke"), never a delete. Owner ceremony: run on the machine holding ~/.saphan/trust/root.key.
Options
| Option | Type | Default | Description |
|---|---|---|---|
--actor | string | unset | binding: the actor name the client binds to (required for --kind binding) |
--added-by | string | root | provenance: who enrolled this record |
--alg | string | unset | issuer: the JWS alg (required for --kind issuer) |
--audience | string | unset | issuer: the expected token audience (required for --kind issuer) |
--canonical | string | unset | alias: the canonical registry handle this historical spelling resolves to (required for --kind alias) |
--jwks-uri | string | unset | issuer: the issuer's JWKS URI (required for --kind issuer) |
--key-id | string | unset | actor: the actor's apk-/wsk- key-id (required for --kind actor) |
--kind | string | unset | record kind: actor | binding | issuer | alias (required) |
--reason | string | unset | actor: optional reason note |
--redirect-uri | stringSlice | [] | binding: an allowed OAuth redirect URI (repeatable; required for --kind binding) |
--root-key | string | unset | root private key path (default: ~/.saphan/trust/root.key) |
--stream | stringSlice | [] | binding: a stream slug this client's tokens may read, or '*' for the whole fleet (repeatable; required for --kind binding) |
--subject | string | unset | record subject: actor name | client_id | issuer URL | historical actor spelling (required) |
saphan identity export
Regenerate the bridge/registry/*.md projection from the signed identity store
Regenerates bridge/registry/{ACTORS,BINDINGS,ISSUERS}.md from the signed identity_record store: full actor history + DELEGATIONS, latest-state bindings and issuers, each under a GENERATED banner. The .md files are an audit mirror, never read at runtime. An empty (never-imported) store is refused rather than overwrite the source roster with empty files.
saphan identity import
Seed the signed identity store from bridge/registry/*.md (import-once), then regenerate the .md projection
Reads the human-gated bridge/registry/{ACTORS,BINDINGS,ISSUERS}.md roster ONE LAST TIME and writes one owner-root-signed identity_record row per markdown row, all-or-nothing in a single transaction. Import is import-once: a store that already holds identity records is REFUSED (re-running never merges). A roster with no actor rows is refused (the empty-roster disease is unimportable). On success the .md files are regenerated as the store's audit projection.
Owner ceremony: run on the machine holding ~/.saphan/trust/root.key.
Options
| Option | Type | Default | Description |
|---|---|---|---|
--root-key | string | unset | root private key path (default: ~/.saphan/trust/root.key) |
saphan identity revoke
Revoke an actor, binding or issuer with a new owner-root-signed revoke record
Appends one owner-root-signed revoke row for an existing (kind, subject) to the signed identity_record store, then regenerates the .md projection. A revoke is a NEW row (never a delete): latest-wins then reads a revoked actor as retired (the row stays in the audit history) and a revoked binding / issuer as absent. The current record's payload is carried forward, so a revoked actor keeps its key-id. Refuses when the subject has no live record to revoke.
Owner ceremony: run on the machine holding ~/.saphan/trust/root.key.
Options
| Option | Type | Default | Description |
|---|---|---|---|
--added-by | string | root | provenance: who revoked this record |
--kind | string | unset | record kind: actor | binding | issuer | alias (required) |
--root-key | string | unset | root private key path (default: ~/.saphan/trust/root.key) |
--subject | string | unset | record subject: actor name | client_id | issuer URL | alias spelling (required) |