Add a system administrator role, and gate account management behind it #10
Reference in New Issue
Block a user
Delete Branch "admin-role"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #3. Second step of #1, and a prerequisite for #4 and #5.
Until now every authenticated caller could create and delete users, set anybody's password and mint anybody's API keys —
auth.gosaid so in a comment. Defensible with one operator and a hand-made account; not once people sign themselves up (#7), and not in a multi-tenant install (#4) where the user list stops being "everybody who works here".The line
Two deliberate choices that differ from the issue's first sketch:
/api/usersstays readable by everybody. The queue's assignment control and the on-call schedule both have to name people, and hiding the roster from the people on it buys nothing.The self-or-admin endpoints go through
requireSelfOrAdminin the handler rather than sitting behindAdminOnly, because which rule applies depends on the{id}in the path, not on the route.The migration makes every existing user an administrator
They already hold these powers, so nobody's access changes on upgrade — it names what is already true and leaves demotion as a deliberate act afterwards. Promoting only user 1 would silently strip the others, and could leave an install whose only administrator is an account nobody has a password for.
Keeping an install administrable
Two guards: the last administrator can be neither deleted nor demoted, and nobody can delete or demote themselves — the likelier accident, where the only admin clears their own flag while tidying and locks the door behind them.
Verified
make fmt lint test helm-lintgreen with-raceagainst Postgres 17. Six new tests inadmin_test.go, covering:403on all six previously-open endpoints, including the ones that used to let any user take over any account (set the admin's password, mint a key for the admin, retarget the admin's notifications);409;/api/mereports the flag, which is what #5's admin page will render from.Not in here
No UI changes — there are no account-management screens yet.
models.Usernow carriesis_admin(notomitempty, so a client can tellfalsefrom an old server), which is the hook #5 needs.