From 575bb7ebe83d75c20794d6972727c958b66c729e Mon Sep 17 00:00:00 2001 From: Frederic Cabassut Date: Mon, 23 Mar 2026 10:29:45 +0100 Subject: [PATCH] fix: replace hardcoded test passwords with runtime-generated UUIDs Generate random passwords in global-setup and share via temp file so all Playwright workers use the same credentials. Screenshot scripts use module-level crypto.randomUUID() since they run single-process. Unit test auth passwords also use randomUUID(). Eliminates security scanner alerts for passwords committed to git. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/screenshots/constants.ts | 4 ++-- src/lib/server/auth.test.ts | 10 +++++----- tests/e2e/auth.spec.ts | 6 +++++- tests/e2e/global-setup.ts | 14 +++++++++++++- tests/e2e/helpers/fixtures.ts | 8 ++++++-- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/scripts/screenshots/constants.ts b/scripts/screenshots/constants.ts index f616555..ad04c9c 100644 --- a/scripts/screenshots/constants.ts +++ b/scripts/screenshots/constants.ts @@ -8,11 +8,11 @@ export const MOBILE_VIEWPORT = { width: 390, height: 844 }; export const ADMIN = { email: 'admin@bretzel.app', displayName: 'Bretzel Admin', - password: 'bretzel2026!' + password: crypto.randomUUID() }; export const COLLABORATOR = { email: 'salzig@bretzel.app', displayName: 'Salzig Bretzel', - password: 'salzig2026!!' + password: crypto.randomUUID() }; diff --git a/src/lib/server/auth.test.ts b/src/lib/server/auth.test.ts index ad3f6ec..40755ee 100644 --- a/src/lib/server/auth.test.ts +++ b/src/lib/server/auth.test.ts @@ -3,7 +3,7 @@ import { createTestDb } from './db/test-helpers.js'; import { users, sessions } from './db/schema.js'; import { eq } from 'drizzle-orm'; import * as argon2 from 'argon2'; -import { randomBytes } from 'crypto'; +import { randomBytes, randomUUID } from 'crypto'; import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3'; import type * as schema from './db/schema.js'; @@ -16,16 +16,16 @@ beforeEach(() => { describe('Auth - Password Hashing', () => { it('should hash and verify a password correctly', async () => { - const password = 'mysecurepassword'; + const password = randomUUID(); const hash = await argon2.hash(password); expect(hash).not.toBe(password); expect(await argon2.verify(hash, password)).toBe(true); - expect(await argon2.verify(hash, 'wrongpassword')).toBe(false); + expect(await argon2.verify(hash, randomUUID())).toBe(false); }); it('should produce different hashes for the same password', async () => { - const password = 'mysecurepassword'; + const password = randomUUID(); const hash1 = await argon2.hash(password); const hash2 = await argon2.hash(password); @@ -37,7 +37,7 @@ describe('Auth - Password Hashing', () => { describe('Auth - User Setup', () => { it('should create a user with hashed password', async () => { - const password = 'testpassword123'; + const password = randomUUID(); const hash = await argon2.hash(password); await db.insert(users).values({ diff --git a/tests/e2e/auth.spec.ts b/tests/e2e/auth.spec.ts index ee55ff9..14335ca 100644 --- a/tests/e2e/auth.spec.ts +++ b/tests/e2e/auth.spec.ts @@ -1,4 +1,8 @@ import { test, expect, setupAndLogin } from './helpers/fixtures.js'; +import { readFileSync } from 'fs'; +import { TEST_CREDENTIALS_FILE } from './global-setup'; + +const { userPassword } = JSON.parse(readFileSync(TEST_CREDENTIALS_FILE, 'utf-8')); test.describe.serial('Authentication', () => { test('Scenario: Unauthenticated user is prompted to set up or log in', async ({ page }) => { @@ -78,7 +82,7 @@ test.describe('Multi-user', () => { data: { email: 'user2@test.com', displayName: 'User Two', - password: 'userpassword123', + password: userPassword, role: 'user' } }); diff --git a/tests/e2e/global-setup.ts b/tests/e2e/global-setup.ts index c448303..fb7d85e 100644 --- a/tests/e2e/global-setup.ts +++ b/tests/e2e/global-setup.ts @@ -1,6 +1,8 @@ -import { existsSync, unlinkSync } from 'fs'; +import { existsSync, unlinkSync, writeFileSync } from 'fs'; +import { randomUUID } from 'crypto'; const TEST_DB = './data/test-crumbs.db'; +export const TEST_CREDENTIALS_FILE = './data/test-credentials.json'; export default function globalSetup() { // Clean test database before E2E run so each run starts fresh @@ -10,4 +12,14 @@ export default function globalSetup() { unlinkSync(path); } } + + // Generate random passwords for this test run, shared across all workers + writeFileSync( + TEST_CREDENTIALS_FILE, + JSON.stringify({ + testPassword: `test-${randomUUID()}`, + collabPassword: `collab-${randomUUID()}`, + userPassword: `user-${randomUUID()}` + }) + ); } diff --git a/tests/e2e/helpers/fixtures.ts b/tests/e2e/helpers/fixtures.ts index 5f8dd68..a1d3baf 100644 --- a/tests/e2e/helpers/fixtures.ts +++ b/tests/e2e/helpers/fixtures.ts @@ -1,12 +1,16 @@ import { test as base, expect, type Page, type Locator } from '@playwright/test'; +import { readFileSync } from 'fs'; import { collectCoverage } from './coverage'; +import { TEST_CREDENTIALS_FILE } from '../global-setup'; + +const { testPassword, collabPassword } = JSON.parse(readFileSync(TEST_CREDENTIALS_FILE, 'utf-8')); const TEST_EMAIL = 'admin@test.com'; -const TEST_PASSWORD = 'testpassword123'; +const TEST_PASSWORD = testPassword; const TEST_DISPLAY_NAME = 'Test Admin'; const COLLAB_EMAIL = 'collab@test.com'; -const COLLAB_PASSWORD = 'collabpass123'; +const COLLAB_PASSWORD = collabPassword; const COLLAB_NAME = 'Collaborator User'; /** Find a specific note card by its title text */