opschain admin identity convert-username-subjects
Included from Basic tier
Converts every subject and approver entry still stored as a username into the principal id it names. Transport grants with a user subject and the approver lines of approval policies match on the principal id — a username is a mapped claim one account per provider may hold, so matching on it would let a federated sign-in inherit a same-named local account's authority. Records written before that rule carried usernames; this command rewrites them, directly against the database (no server, no login), after a dry run.
The sweep covers every record family that names people:
| record | field |
|---|---|
| transport grant | subject_id (user subjects) and approvers |
| approval policy | approvers.users |
| subtree owner declaration | owners.users |
| open approval checklist line | approvers.users (the frozen copy a pending or approved checklist still decides on) |
Each stored username resolves exactly as the write seams resolve a typed one:
- a username one account holds becomes that account's principal id
(
converted); - a username several accounts hold — a local
sambeside a federatedsam— is refused by name (ambiguous) and left as stored, with the remedy: rewrite the entry as<provider>:<username>(local:sam,ldap:corp:sam,oidc:okta:sam— the account'sauth_providervalue, which is whatopschain admin users listshows) and re-run; - a username no account holds is reported (
unknown) and left as stored: re-point the record at an existing principal or remove the entry.
The resolvable rows are rewritten set-based in one transaction; a run
with refusals still converts everything it could, prints them, and exits
non-zero so they are not missed. Until every row converts, a stored
username keeps matching through the dual-read window and every such hit
records warn:identity:username_match naming the record (never the
username) with this command as the remedy; once the sweep finds nothing
to do the username leg is inert. The run records
audit:identity:username_subjects_conversion with its counts.
opschain admin identity convert-username-subjects --store postgres://… --dry-run
Username-subject conversion (dry run — nothing written): converted=5 ambiguous=2 unknown=1
RECORD ID FIELD VALUE OUTCOME PRINCIPAL REMEDY
transport_grant 019a… subject_id priya converted 019a… -
transport_grant 019a… approvers sam ambiguous - held by several accounts: rewrite the entry as one of ldap:corp:sam, local:sam
approval_policy 019a… approvers.users nobody unknown - no account holds this username: re-point the record at an existing principal, or remove the entry
…
Re-run without --dry-run to apply. The command is idempotent: a rerun
finds only the rows it could not convert.
Flags
| Flag | Meaning |
|---|---|
--store <dsn> | Required. A postgres:// (or postgresql://) DSN over the adopted governance tables. |
--dry-run | Compute and print the conversion plan without writing anything. |
Global -o, --output json|yaml switches to the machine document (the rows
and the counts map).
See also
opschain docs cli/admin-transport-grants-create— the subject and approver inputs take a principal id, a username or<provider>:<username>.opschain docs cli/approval-policies-create— the approver-user input likewise.opschain docs identity— same username in two providers.opschain docs events—warn:identity:username_match.