fix(auth): make the owner role real — provisioning, staff doors, panel guards
Found live while verifying the admin email-edit fix: the Owner account could
not load /api/v1/users at all. Root cause: migration 0011 adds the 'owner'
role and gates every user-administration route on it, but NOTHING ever wrote
it. break-glass (UpsertOwner), the setup MC-bind (CompleteOwnerSetup), and the
re-provision path all forced 'admin', so in a fresh install the entire
owner tier — list/create/edit/disable/delete users, quotas, sessions — was
unreachable. The role was a dead letter in the other direction too: staff
predicates that predate the role did not know it.
- UpsertOwner and CompleteOwnerSetup now write role='owner'; the username-
conflict arm re-asserts it, which is also the documented pre-0011 promotion
path ("re-provision via break-glass"). InsertOperator stays plain 'admin'.
- Staff doors learn the role: op-login start/finish admit the Owner; the
player email door refuses it like any staff account; the in-game approver
check already used staffRole.
- Reclaim protection: IsProtectedAdminLink (and the break-glass bootstrap
switch AdminExists) count admin OR owner — the Owner must never be displaced
by a Mojang-priority reclaim.
- Panel guards make migration 0011's claim true now that owner rows exist: an
owner can never be demoted, deleted, or disabled through the API (only the
local break-glass console resets the identity); username/email edits still
work.
Tests: pgint pins both provisioning paths, the protected-link predicate and
the reset/promote semantics; hermetic suites cover the owner-admitting staff
door, the owner-refusing player door, the three panel guards, and break-glass
attribution.
This commit is contained in:
16 files changed
+349
-80
No files matched your search
@@ -44,11 +44,11 @@ var (
|
||||
// consumed, or expired) — so handlers map it to 400, not 404.
|
||||
ErrPasskeyChallengeInvalid = errors.New("passkey challenge invalid or expired")
|
||||
// ErrPlayerBindForbidden means a public Bind-Code redemption resolved to a STAFF
|
||||
// account (role=admin), which the player-console bootstrap refuses (console-tier
|
||||
// access model). Operators authenticate at op.console behind Zero Trust, never via
|
||||
// the account-less console.<root_domain> door, so the public bootstrap provably
|
||||
// never mints a session for an admin identity. It is distinct from ErrConflict so
|
||||
// the handler answers 403 (wrong door) rather than 409 (already linked).
|
||||
// account (admin or owner), which the player-console bootstrap refuses
|
||||
// (console-tier access model). Staff authenticate at op.console behind Zero Trust,
|
||||
// never via the account-less console.<root_domain> door, so the public bootstrap
|
||||
// provably never mints a session for a staff identity. It is distinct from
|
||||
// ErrConflict so the handler answers 403 (wrong door) rather than 409.
|
||||
ErrPlayerBindForbidden = errors.New("bind code belongs to a staff account")
|
||||
// ErrEmailTaken means a verified email would collide with another account's
|
||||
// already-verified address (spec §B email-first login foundation; the
|
||||
|
||||
Reference in new issue
Block a user