[object Object]

← back to Govarbitrage

set-admin: generate strong random password server-side (no hardcoded default)

bba7207ccedd3fc4458154fdc405d8c67e79b5d1 · 2026-07-12 23:49:50 -0700 · Steve

Files touched

Diff

commit bba7207ccedd3fc4458154fdc405d8c67e79b5d1
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun Jul 12 23:49:50 2026 -0700

    set-admin: generate strong random password server-side (no hardcoded default)
---
 scripts/set-admin.ts | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/scripts/set-admin.ts b/scripts/set-admin.ts
index 5256497..8b09170 100644
--- a/scripts/set-admin.ts
+++ b/scripts/set-admin.ts
@@ -1,13 +1,26 @@
 // Set/reset the admin login credential without running the full seed.
-// Usage: ADMIN_EMAIL=admin@agentabrams.com ADMIN_PASSWORD='DW2024!' npx tsx scripts/set-admin.ts
-// Defaults to the unified fleet credential.
+// Usage:
+//   ADMIN_EMAIL=admin@agentabrams.com ADMIN_PASSWORD='...' npx tsx scripts/set-admin.ts
+//   (omit ADMIN_PASSWORD to GENERATE a strong random one and print it once)
+// Never hardcodes a real password.
 
+import { randomBytes } from "node:crypto";
 import { prisma } from "../src/lib/db";
 import { hashPassword } from "../src/lib/password";
 
+// Readable strong password: 3 base32-ish blocks, ~120 bits.
+function generatePassword(): string {
+  const alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // no ambiguous 0/O/1/I
+  const bytes = randomBytes(18);
+  const chars = Array.from(bytes, (b) => alphabet[b % alphabet.length]);
+  return `${chars.slice(0, 6).join("")}-${chars.slice(6, 12).join("")}-${chars.slice(12, 18).join("")}`;
+}
+
 async function main() {
   const email = process.env.ADMIN_EMAIL || process.argv[2] || "admin@agentabrams.com";
-  const password = process.env.ADMIN_PASSWORD || process.argv[3] || "DW2024!";
+  const provided = process.env.ADMIN_PASSWORD || process.argv[3];
+  const generated = !provided;
+  const password = provided || generatePassword();
   const hash = hashPassword(password);
   const user = await prisma.user.upsert({
     where: { email },
@@ -15,6 +28,10 @@ async function main() {
     create: { email, name: "Admin", role: "ADMIN", passwordHash: hash },
   });
   console.log(`Admin credential set: ${user.email} (role ${user.role}).`);
+  if (generated) {
+    // Printed ONCE so the operator can capture it; never stored to disk/git.
+    console.log(`GENERATED_PASSWORD=${password}`);
+  }
   await prisma.$disconnect();
 }
 

← deba4c5 seed: never hardcode admin password — set out-of-band via se  ·  back to Govarbitrage  ·  Honesty Gate: confidence-discounted, capped, disclaimed hot- 1162672 →