Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…word Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a failed recovery sign out Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CLI already finds the admin before prompting, so it now passes that id to the new setAdminPassword instead of looking the email up a second time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…otes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ticks the verify steps and the scope boxes, and adds the review findings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and stack test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n:reset-password end to end findAdminId and disableAdmin return null instead of throwing; the scripts turn that into the same "No admin has that email." exit. resetAdminPassword, which only the tests called, is gone: the stack test now runs the real script with piped passwords, including the 13 character and mismatch refusals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… type Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… not expired Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also ticks the AC-12 grep step in the 0019 verify list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <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.
What
Admins now sign in to
/adminwith email and password only. The TOTP step (authenticator app codes) is gone, and so is the admin password reset by email: an admin password is now reset only from the terminal with the newpnpm admin:reset-password. The branch also moves "Analytics & error tracking" out of the launch scope into the deferred list.Why
Implements spec 0019 (rationale in rationale.md). It supersedes the TOTP and admin reset parts of spec 0004 and the admin branch of spec 0012 AC-8 and AC-19.
With the password as the only lock, an inbox alone must never be able to change it or open the panel. So the email reset goes, the guard requires a session that was opened by a password, and admin passwords get stricter.
Changes
Password only guard
decideAdminAccessdrops the assurance level check and themfaverdict. An admin session must now carry apasswordentry in itsamrlist (both the string and the{ method }shape are read, via the newhasPasswordMethod). A session opened by an email link (recovery,otp, sign up confirm) is treated like no session.amrfromgetClaims(), so noauth.mfaAPI is used anymore./admin/sign-infor a password less session on page loads, instead of letting the page'sredirect()answer 200.signIngoes straight to the validatednextpath or/admin.safeAdminPathandpublicAdminPageslist/admin/sign-inonly.admin:createandadmin:disable.TOTP removed
/admin/mfa, the enroll and verify actions,factors.ts,mfa-lockout.ts,mfa-view.ts, the TOTP form components,admin:reset-mfa, the MFA log events and messages, and their tests (includingtests/stack/mfa-challenges.stack.test.ts).supabase/config.tomlsets TOTP enroll and verify tofalse. Theotpauthdev dependency is gone.signInAsAdmin), which touches most admin and catalog specs.Admin email reset replaced by a terminal script
pnpm admin:reset-password --email <e> [--env-file <path>]: finds the admin inadmin_users(enabled or disabled), prompts twice for a hidden password, and sets it withauth.admin.updateUserById. Supabase then ends every session the admin had; a stack test pins that./admin/forgot-password,/admin/reset-password,/auth/confirm(now 404, and the proxy no longer runs on/auth/*), the admin reset action, theadmin_resetemail kind andemails/admin-reset-password.tsx.reasonmessages are onlyexpiredandsigned_out; old keys show nothing.Closing the inbox path for store runners
runsTheStorechecksadmin_usersonly (no moreauth.mfa_factorsread).recoveryemail, loggingauth_email.skippedwithreason: "runs_the_store". The customer forgot password page replies the same way, at the same speed.confirmEmailends the session and redirects to?failed=1&type=recoveryif an old recovery link for a store runner still arrives.Stronger admin passwords
adminPasswordSchema: the shared password rule plus at least 14 characters. Both admin scripts use it.admin:createon an existing auth user (for example a customer) now always prompts for and sets a new password withemail_confirm: true, so a password planted through public sign up can never become an admin password.Docs
docs/runbooks/admin-accounts.md: sign in without TOTP,admin:reset-password, the 14 character rule, the compromised account steps, deleting existing factors, the hook check, and the Firewall rule onPOST /admin/sign-inandPOST /account/sign-in.README.md,src/features/account/AGENTS.md, the scope, the spec 0019 verify steps and the review record.How to test / verify
pnpm db:stop && pnpm db:start.pnpm lint && pnpm typecheck && pnpm testpnpm test:stack:admin-amr.stack.test.tsshows a password sign in has apasswordamr entry and a verified recovery link has none;admin-scripts.stack.test.tscovers the reset (enabled and disabled admins, customer only email refused, 13 characters rejected, every session ended) andadmin:createoverwriting a planted password.pnpm test:dbandpnpm test:e2e/admin/sign-inlands on/adminwith no code step;/admin/mfa,/admin/forgot-passwordand/admin/reset-passwordredirect a visitor to sign in and 404 for an admin;/auth/confirmis 404;/account/forgot-passwordwith an admin email shows the usual reply and Mailpit stays empty.Risk & rollout
DELETE FROM auth.mfa_factors;or a stack reset.Notes for reviewers
feat/defer-analytics) is older than its main content: only the first commit is the analytics deferral, the rest is spec 0019.amrrule insrc/features/admin-auth/access.tsand the proxy redirect insrc/features/admin-auth/proxy-decision.ts, since they now carry what TOTP used to.admin:reset-passwordrelies on Supabase ending every session on a password change. If a future Supabase version stops doing that, the stack test fails, and the runbook's fallback is to wait 12 hours before re-enabling a compromised admin.auth.mfa,auth.reset.requestedorauth.password.changedleft insrc) is still unticked in verify.md; the grep returns nothing today.🤖 Generated with Claude Code