Skip to content

Commit ea764a2

Browse files
authored
fix(seed): use predefined admin credentials instead of auto-generated (#417)
- Remove NODE_ENV-based logic that generated random admin credentials during build ([email protected]) - Always use predefined - Add warning log when using defaults in production - Add one-time migration to fix existing deployments with auto-generated admin accounts (updates both email and password)
2 parents de226a0 + a8c0376 commit ea764a2

File tree

1 file changed

+55
-54
lines changed

1 file changed

+55
-54
lines changed

lib/db/seed.ts

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -144,63 +144,24 @@ export async function runSeed(): Promise<void> {
144144

145145
console.log(`[Seed] Will seed: ${tablesToSeedNames.join(', ')}`);
146146

147-
// Resolve admin credentials with environment-sensitive defaults
148-
const isProd = process.env.NODE_ENV === 'production';
149-
147+
// Resolve admin credentials - always use predefined defaults unless explicitly configured
150148
const envAdminEmail = process.env.SEED_ADMIN_EMAIL;
151149
const envAdminPassword = process.env.SEED_ADMIN_PASSWORD;
152150

153-
let adminEmail: string;
154-
let adminPassword: string;
155-
let credentialsAutoGenerated = false;
156-
157-
if (isProd) {
158-
if (!envAdminEmail || !envAdminPassword) {
159-
// Auto-generate secure credentials in production if not provided
160-
// Generate a secure random password (32 chars with mixed case, numbers, symbols)
161-
const generateSecurePassword = () => {
162-
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
163-
const randomValues = new Uint8Array(32);
164-
crypto.getRandomValues(randomValues);
165-
return Array.from(randomValues, (v) => chars[v % chars.length]).join('');
166-
};
167-
168-
adminEmail = envAdminEmail || `admin-${crypto.randomUUID().slice(0, 8)}@auto.generated`;
169-
adminPassword = envAdminPassword || generateSecurePassword();
170-
credentialsAutoGenerated = true;
171-
172-
// Log the auto-generated credentials prominently
173-
console.log('');
174-
console.log('╔══════════════════════════════════════════════════════════════════════════════╗');
175-
console.log('║ ⚠️ AUTO-GENERATED ADMIN CREDENTIALS (SAVE THESE NOW!) ║');
176-
console.log('╠══════════════════════════════════════════════════════════════════════════════╣');
177-
console.log('║ ║');
178-
console.log(`║ Email: ${adminEmail.padEnd(64)}║`);
179-
console.log(`║ Password: ${adminPassword.padEnd(64)}║`);
180-
console.log('║ ║');
181-
console.log('║ These credentials will only be shown ONCE. ║');
182-
console.log('║ To set custom credentials, configure these environment variables: ║');
183-
console.log('║ - SEED_ADMIN_EMAIL ║');
184-
console.log('║ - SEED_ADMIN_PASSWORD ║');
185-
console.log('║ ║');
186-
console.log('╚══════════════════════════════════════════════════════════════════════════════╝');
187-
console.log('');
188-
} else {
189-
adminEmail = envAdminEmail;
190-
adminPassword = envAdminPassword;
191-
192-
// Warn if using the insecure default password in production
193-
if (envAdminPassword === 'Passw0rd123!') {
194-
console.warn('');
195-
console.warn('⚠️ WARNING: Using insecure default password in production!');
196-
console.warn(' Please set SEED_ADMIN_PASSWORD to a strong, unique password.');
197-
console.warn('');
198-
}
199-
}
200-
} else {
201-
// In non-production, allow safe defaults for developer convenience
202-
adminEmail = envAdminEmail || '[email protected]';
203-
adminPassword = envAdminPassword || 'Passw0rd123!';
151+
// Always use predefined defaults unless explicitly configured
152+
// This ensures consistent admin credentials across all environments (dev, build, production)
153+
const adminEmail = envAdminEmail || '[email protected]';
154+
const adminPassword = envAdminPassword || 'Passw0rd123!';
155+
156+
// Warn if using defaults in production
157+
if (process.env.NODE_ENV === 'production' && (!envAdminEmail || !envAdminPassword)) {
158+
console.warn('');
159+
console.warn('⚠️ WARNING: Using default admin credentials in production!');
160+
console.warn(' Email: [email protected]');
161+
console.warn(' Password: Passw0rd123!');
162+
console.warn('');
163+
console.warn(' Set SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD for secure credentials.');
164+
console.warn('');
204165
}
205166

206167
const hashedPassword = await bcrypt.hash(adminPassword, 10);
@@ -431,6 +392,46 @@ export async function runSeed(): Promise<void> {
431392
}
432393
}
433394

395+
// ============================================
396+
// MIGRATION: Fix auto-generated admin emails
397+
// One-time migration for existing deployments that have admin-*@auto.generated
398+
// ============================================
399+
const existingDemoAdmin = await db.select().from(users).where(eq(users.email, '[email protected]')).limit(1);
400+
401+
if (existingDemoAdmin.length === 0) {
402+
// No demo admin exists - check for auto-generated admin to migrate
403+
const autoGeneratedAdmin = await db
404+
.select()
405+
.from(users)
406+
.where(sql`email LIKE 'admin-%@auto.generated'`)
407+
.limit(1);
408+
409+
if (autoGeneratedAdmin.length > 0) {
410+
console.log('[Seed] 🔄 Found auto-generated admin account, migrating to predefined credentials...');
411+
412+
// Update the user's email and password
413+
await db
414+
.update(users)
415+
.set({
416+
417+
passwordHash: hashedPassword
418+
})
419+
.where(eq(users.id, autoGeneratedAdmin[0].id));
420+
421+
// Update the associated account
422+
await db
423+
.update(accounts)
424+
.set({
425+
426+
providerAccountId: '[email protected]',
427+
passwordHash: hashedPassword
428+
})
429+
.where(eq(accounts.userId, autoGeneratedAdmin[0].id));
430+
431+
console.log('[Seed] ✓ Migrated auto-generated admin to [email protected] with default password');
432+
}
433+
}
434+
434435
// ============================================
435436
// DEMO MODE: Seed additional tables
436437
// ============================================

0 commit comments

Comments
 (0)