chore: codify unversioned prod signup-lock security trigger#1343
Merged
Conversation
The block_user_signup_security_2026_05_21 trigger was installed live on prod during incident response and has no committed migration. A fresh DB rebuilt from migrations would silently lose this protection. This migration codifies the trigger and its function exactly as they exist in prod (verified via pg_get_triggerdef and pg_get_functiondef against prod). DROP TRIGGER IF EXISTS plus CREATE OR REPLACE FUNCTION make it a no-op when re-applied to a DB that already has the trigger. This is codification only. The lockout currently blocks all non-employee signups and should be retired or converted to a non-blocking audit signal in a follow-up, once app-layer signup gating is confirmed.
Migration 0084 (also in this branch) restores the signup-block trigger that rejects any INSERT on users whose email is not under techops.services or keeperhub.com. Existing test fixtures and dev seed scripts use various non-routable domains (@test.local, @example.com, @keeperhub.test, @localhost, @keeperhub.local) that would all fail the trigger after merge. Updated 7 sites across 4 vitest e2e tests and 2 seed scripts to use @techops.services, matching the convention already in tests/e2e/playwright/utils/seed.ts. Local-parts are preserved so test intent stays readable. Also added a SEED_EMAIL constraint note to seed-user.ts so anyone overriding via env knows about the trigger allowlist.
🧹 PR Environment Cleaned UpThe PR environment has been successfully deleted. Deleted Resources:
All resources have been cleaned up and will no longer incur costs. |
ℹ️ No PR Environment to Clean UpNo PR environment was found for this PR. This is expected if:
|
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
0084that creates the existing prod triggerblock_user_signup_security_2026_05_21onusersplus its plpgsql function.pg_get_triggerdefandpg_get_functiondefoutput identical to prod after applying locally.DROP TRIGGER IF EXISTSandCREATE OR REPLACE FUNCTION.Why
The trigger was installed directly on the prod DB during incident response (2026-05-21) and was never committed. A clean rebuild from migrations (CI, ephemeral env, disaster recovery) would silently lose this protection. A broader scan of prod (all schemas) confirms this is the only remaining unversioned trigger or function. Migrations
0082and0083already covered the other two triggers from the same incident; the file content hashes there match the prod ledger rows exactly, so those are fully reconciled.Not in this PR
The trigger currently blocks every non-employee signup with errcode
42501and messageSignup paused (security incident 2026-05-21). Contact security team.This PR is codification only and does not address the customer-lockout side effect. A follow-up should either retire the trigger (once app-layer signup gating is confirmed sufficient) or convert it to a non-blocking audit signal.Test plan
INSERTwith non-employee email rejected with the expected message and42501INSERTwith employee email (@keeperhub.com) acceptedpnpm db:migrateagainst staging before merge to confirm drizzle picks up the new journal entry cleanlyNotes
0084_snapshot.jsonis a verbatim copy of0083_snapshot.jsonsince the schema did not change (same pattern0081 -> 0082 -> 0083already follows: sameid/prevIdacross all three).whenis1779409707320(2026-05-22), monotonically newer than0083's1779383340528. If an intermediate migration lands first, bump this value before merge.