Auto-promote first OAuth login to admin when no admin exists#531
Merged
Auto-promote first OAuth login to admin when no admin exists#531
Conversation
When .env is pre-populated by configuration management on a fresh install, the install wizard's UI flow is skipped (rootHandler only checks .env, not the DB) and the wizard's updateAdminUser is never called. The site comes up with no admin_users row, so even after the operator successfully logs in via /login they remain unable to administer the site. Add EnsureAdmin to Auth and call it from LoginPostHandler. It promotes the logging-in user to admin if and only if no admin_users row exists. Same trust model as the wizard (whoever first completes OAuth against the server's client_secret becomes the admin), but reachable from the regular login path so automated deploys work end-to-end. Refs #529 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
compscidr
added a commit
to compscidr/iac
that referenced
this pull request
Apr 30, 2026
Includes goblogplatform/goblog#531 (auto-promote first OAuth login to admin), so a fresh deploy with pre-populated .env can finish setup just by signing in with GitHub — no manual wizard step needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
This PR addresses fresh-install deployments where a pre-populated .env causes the install wizard UI to be skipped, leaving the DB without an admin_users row and therefore no way to administer the site after OAuth login.
Changes:
- Add
Auth.EnsureAdmin(blogUserID)to auto-promote the first successful OAuth login to admin when no admin exists yet. - Call
EnsureAdminfromLoginPostHandlerafter a successful OAuth login. - Add unit tests covering
EnsureAdmincreate/no-op behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
auth/auth.go |
Adds EnsureAdmin and invokes it during OAuth login to create the initial admin user when missing. |
auth/auth_test.go |
Adds tests ensuring EnsureAdmin creates the first admin row and is a no-op once one exists. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address PR feedback: - Surface DB lookup errors other than gorm.ErrRecordNotFound rather than treating any error as "no admin exists" and proceeding to create one. - Wrap the check-and-create in a transaction so two concurrent first logins can't both observe an empty admin_users table and each create a row. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the second half of #529.
When `.env` is pre-populated by configuration management on a fresh install, `rootHandler` only checks `.env` (not the DB) when deciding whether to show the install wizard, so the wizard's UI flow is skipped entirely. The wizard is the only existing path that creates an `admin_users` row, so the site comes up with no admin user. After #530 made `IsAdmin` strict, the symptom for the operator becomes: `/login` and `/logout` work, the OAuth dance succeeds, the BlogUser is created — but no admin link, no admin pages, no way to administer the site.
This PR adds `Auth.EnsureAdmin(blogUserID)` and calls it from `LoginPostHandler` after a successful OAuth login. It promotes the logging-in user to admin if and only if no `admin_users` row exists yet — same trust model as the wizard's `updateAdminUser` (whoever first completes OAuth against the server's `client_secret` becomes the admin), but reachable from the regular login path so an operator who pre-populates `.env` can finish setup just by clicking "Sign in with GitHub".
The wizard's own flow is unchanged: it still runs when `.env` is missing or incomplete, still ends in `updateAdminUser`. `EnsureAdmin` is idempotent — once an admin exists, subsequent logins are pure authentications and no promotion happens.
Tests
`auth/auth_test.go` covers:
```
ok goblog/admin 0.029s
ok goblog/auth 0.007s
ok goblog/blog 0.028s
```
Note on the trust model
Anyone with a GitHub account can complete OAuth against the public site's `/login`, so "first to log in becomes admin" is a race that the operator has to win on first deploy. This is unchanged from the existing wizard flow, which has the same race. A stricter model (e.g. configuring an expected GitHub login in `.env` and only promoting that user) is a reasonable follow-up but out of scope here.
🤖 Generated with Claude Code