fix: correct Argon2 password hash and organization UUIDs in migrations
All checks were successful
CI/CD Pipeline / Backend - Build, Test & Push (push) Successful in 7m52s
CI/CD Pipeline / Frontend - Build, Test & Push (push) Successful in 11m40s
CI/CD Pipeline / Integration Tests (push) Has been skipped
CI/CD Pipeline / Deployment Summary (push) Successful in 1s
CI/CD Pipeline / Deploy to Portainer (push) Successful in 14s
CI/CD Pipeline / Discord Notification (Failure) (push) Has been skipped
CI/CD Pipeline / Discord Notification (Success) (push) Successful in 1s

- Fixed test user migration to use real Argon2id hash for Password123!
- Replaced random uuidv4() with fixed UUIDs in organization seeds
- Updated auth.service.ts to use DEFAULT_ORG_ID constant
- Added ON CONFLICT DO UPDATE to migration for existing users
- Ensures consistent UUIDs across environments (dev/preprod/prod)

Fixes:
- Registration 500 error (foreign key constraint violation)
- Login 401 error (invalid password hash)
- Organization ID mismatch between migrations and application code

Test users (Password: Password123!):
- admin@xpeditis.com (ADMIN)
- manager@xpeditis.com (MANAGER)
- user@xpeditis.com (USER)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
David 2025-11-20 20:05:22 +01:00
parent 6e3191b50e
commit dc62166272
3 changed files with 28 additions and 30 deletions

View File

@ -11,6 +11,7 @@ import * as argon2 from 'argon2';
import { UserRepository, USER_REPOSITORY } from '@domain/ports/out/user.repository';
import { User, UserRole } from '@domain/entities/user.entity';
import { v4 as uuidv4 } from 'uuid';
import { DEFAULT_ORG_ID } from '@infrastructure/persistence/typeorm/seeds/test-organizations.seed';
export interface JwtPayload {
sub: string; // user ID
@ -221,8 +222,7 @@ export class AuthService {
// Use default organization "Test Freight Forwarder Inc." if not provided
// This ID comes from the seed migration 1730000000006-SeedOrganizations
const defaultOrgId = '1fa9a565-f3c8-4e11-9b30-120d1052cef0';
this.logger.log(`Using default organization ID for user registration: ${defaultOrgId}`);
return defaultOrgId;
this.logger.log(`Using default organization ID for user registration: ${DEFAULT_ORG_ID}`);
return DEFAULT_ORG_ID;
}
}

View File

@ -2,36 +2,26 @@
* Seed Test Users Migration
*
* Seeds test users for development and testing
* Password for all users: AdminPassword123!
* Hash generated with bcrypt rounds=10
* Password for all users: Password123!
* Hash generated with Argon2id
*/
import { MigrationInterface, QueryRunner } from 'typeorm';
import { v4 as uuidv4 } from 'uuid';
import { DEFAULT_ORG_ID } from '../seeds/test-organizations.seed';
export class SeedTestUsers1730000000007 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
// Get the first organization ID from the database
const result = await queryRunner.query(`
SELECT id FROM organizations WHERE type = 'FREIGHT_FORWARDER' LIMIT 1
`);
// Use fixed organization ID from seed
const organizationId = DEFAULT_ORG_ID;
if (result.length === 0) {
throw new Error(
'No organization found to seed users. Please run organization seed migration first.'
);
}
// Pre-hashed password: Password123! (Argon2id)
// Generated with: argon2.hash('Password123!', { type: argon2.argon2id, memoryCost: 65536, timeCost: 3, parallelism: 4 })
const passwordHash = '$argon2id$v=19$m=65536,t=3,p=4$Uj+yeQiaqgBFqyTJ5FX3Cw$wpRCYORyFwjQFSuO3gpmzh10gx9wjYFOCvVZ8TVaP8Q';
const organizationId = result[0].id;
// Pre-hashed password: AdminPassword123! (bcrypt rounds=10)
// This hash is deterministic for testing purposes
const passwordHash = '$2b$10$5qK9KqP7YqXZ5Z0kZ0kZ0OqK9KqP7YqXZ5Z0kZ0kZ0OqK9KqP7YqX';
// Insert test users
// Fixed UUIDs for test users (matching existing data in database)
const users = [
{
id: uuidv4(),
id: 'c59ae389-da30-4533-be0c-fdfe6ac945de',
email: 'admin@xpeditis.com',
passwordHash,
firstName: 'Admin',
@ -39,7 +29,7 @@ export class SeedTestUsers1730000000007 implements MigrationInterface {
role: 'ADMIN',
},
{
id: uuidv4(),
id: '496ba881-c055-4b78-b0c0-6c048215253b',
email: 'manager@xpeditis.com',
passwordHash,
firstName: 'Manager',
@ -47,7 +37,7 @@ export class SeedTestUsers1730000000007 implements MigrationInterface {
role: 'MANAGER',
},
{
id: uuidv4(),
id: '361b409d-a32b-4ff9-a61b-e927450c1daf',
email: 'user@xpeditis.com',
passwordHash,
firstName: 'Regular',
@ -66,7 +56,10 @@ export class SeedTestUsers1730000000007 implements MigrationInterface {
'${user.firstName}', '${user.lastName}', '${user.role}',
'${organizationId}', NULL, true, NOW(), NOW()
)
ON CONFLICT ("email") DO NOTHING;
ON CONFLICT ("email") DO UPDATE SET
"password_hash" = EXCLUDED."password_hash",
"organization_id" = EXCLUDED."organization_id",
"updated_at" = NOW();
`);
}
@ -74,7 +67,7 @@ export class SeedTestUsers1730000000007 implements MigrationInterface {
console.log(' - admin@xpeditis.com (ADMIN)');
console.log(' - manager@xpeditis.com (MANAGER)');
console.log(' - user@xpeditis.com (USER)');
console.log(' - Password: AdminPassword123!');
console.log(' - Password: Password123!');
}
public async down(queryRunner: QueryRunner): Promise<void> {

View File

@ -19,9 +19,14 @@ export interface OrganizationSeed {
isActive: boolean;
}
// Fixed UUIDs for consistent seed data across environments
export const DEFAULT_ORG_ID = 'c6042c7b-cffe-4fef-94f6-f27c2d0eb809';
export const DEMO_CARRIER_ID = '462001d1-6829-4554-a4e1-477667edab6b';
export const SAMPLE_SHIPPER_ID = '39e49605-5292-4935-9bff-c4abb547d3b9';
export const organizationSeeds: OrganizationSeed[] = [
{
id: uuidv4(),
id: DEFAULT_ORG_ID,
name: 'Test Freight Forwarder Inc.',
type: 'FREIGHT_FORWARDER',
scac: null,
@ -33,7 +38,7 @@ export const organizationSeeds: OrganizationSeed[] = [
isActive: true,
},
{
id: uuidv4(),
id: DEMO_CARRIER_ID,
name: 'Demo Shipping Company',
type: 'CARRIER',
scac: 'DEMO',
@ -45,7 +50,7 @@ export const organizationSeeds: OrganizationSeed[] = [
isActive: true,
},
{
id: uuidv4(),
id: SAMPLE_SHIPPER_ID,
name: 'Sample Shipper Ltd.',
type: 'SHIPPER',
scac: null,