From 73d2baed2fd0d7dc77ee4ee82b6d4e0fbd2abd93 Mon Sep 17 00:00:00 2001 From: roble Date: Thu, 11 Jun 2026 13:55:38 +0100 Subject: [PATCH 1/6] feat(command): add MakeAdminCommand to promote users to admin --- src/Console/Commands/MakeAdminCommand.php | 37 +++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/Console/Commands/MakeAdminCommand.php diff --git a/src/Console/Commands/MakeAdminCommand.php b/src/Console/Commands/MakeAdminCommand.php new file mode 100644 index 0000000..56ca4ad --- /dev/null +++ b/src/Console/Commands/MakeAdminCommand.php @@ -0,0 +1,37 @@ +argument('email') ?? text('Email address', required: true); + + $user = User::where('email', $email)->first(); + + if (! $user) { + $this->error("No user found with email: {$email}"); + $this->line('Register an account first, then re-run this command.'); + + return self::FAILURE; + } + + $user->syncRoles([Role::ADMIN->value]); + + $this->info("Promoted admin: {$user->name} <{$user->email}>"); + + return self::SUCCESS; + } +} From 0cd157de3a22286f93112a87cb66857f5ab77fbd Mon Sep 17 00:00:00 2001 From: roble Date: Thu, 11 Jun 2026 13:55:59 +0100 Subject: [PATCH 2/6] fix(taskfile): update commands to use APP variable for consistency --- Taskfile.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 5f75072..bee7410 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -5,7 +5,7 @@ tasks: # ── Testing ─────────────────────────────────────────────────── test:php: desc: Run PHPUnit tests for Auth module - cmd: php artisan test --testsuite=Modules --filter='^Modules\\Auth\\Tests' + cmd: '{{.APP}} php artisan test --testsuite=Modules --filter=''^Modules\\Auth\\Tests''' test:e2e: desc: Run E2E tests for Auth module @@ -16,10 +16,10 @@ tasks: db:seed: desc: Seed the Auth module database - cmd: php artisan modules:seed --module=auth + cmd: '{{.APP}} php artisan modules:seed --module=auth' # ── Code Generation ──────────────────────────────────────────── types:generate: desc: Generate TypeScript types from PHP DTOs and enums - cmd: php artisan module:generate-types auth + cmd: '{{.APP}} php artisan module:generate-types auth' From ab11be81e1c68e4ddd5ea23d81cfb031fac2394d Mon Sep 17 00:00:00 2001 From: roble Date: Thu, 11 Jun 2026 16:11:13 +0100 Subject: [PATCH 3/6] test(make-admin): add feature tests for MakeAdminCommand functionality --- tests/Feature/MakeAdminCommandTest.php | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/Feature/MakeAdminCommandTest.php diff --git a/tests/Feature/MakeAdminCommandTest.php b/tests/Feature/MakeAdminCommandTest.php new file mode 100644 index 0000000..7367fcb --- /dev/null +++ b/tests/Feature/MakeAdminCommandTest.php @@ -0,0 +1,53 @@ +createUser(); + + $this->artisan('auth:make-admin', ['email' => $user->email]) + ->assertSuccessful() + ->expectsOutputToContain('Promoted admin'); + + $this->assertTrue($user->fresh()->hasRole(Role::ADMIN)); + } + + public function test_fails_when_user_not_found(): void + { + $this->artisan('auth:make-admin', ['email' => 'nobody@example.com']) + ->assertFailed() + ->expectsOutputToContain('No user found'); + } + + public function test_replaces_existing_role_with_admin(): void + { + $user = $this->createUser(); + $user->assignRole(Role::USER); + + $this->artisan('auth:make-admin', ['email' => $user->email]) + ->assertSuccessful(); + + $this->assertTrue($user->fresh()->hasRole(Role::ADMIN)); + $this->assertFalse($user->fresh()->hasRole(Role::USER)); + } + + public function test_is_idempotent(): void + { + $user = $this->createUser(); + + $this->artisan('auth:make-admin', ['email' => $user->email])->assertSuccessful(); + $this->artisan('auth:make-admin', ['email' => $user->email])->assertSuccessful(); + + $this->assertCount(1, $user->fresh()->roles); + $this->assertTrue($user->fresh()->hasRole(Role::ADMIN)); + } +} From 82afa1422aa8e48fbc6061966f7e792cd2f333dc Mon Sep 17 00:00:00 2001 From: roble Date: Thu, 11 Jun 2026 20:49:28 +0100 Subject: [PATCH 4/6] fix(Taskfile): update command for PHPUnit tests and add make-admin task refactor(AuthDatabaseSeeder): simplify user creation and remove unused admin role assignment fix(login.security): configure test.describe for serial execution --- Taskfile.yml | 6 +++++- database/seeders/AuthDatabaseSeeder.php | 15 +-------------- tests/e2e/tests/login/login.security.spec.ts | 5 +++-- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index bee7410..3d44077 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -5,7 +5,7 @@ tasks: # ── Testing ─────────────────────────────────────────────────── test:php: desc: Run PHPUnit tests for Auth module - cmd: '{{.APP}} php artisan test --testsuite=Modules --filter=''^Modules\\Auth\\Tests''' + cmd: 'php artisan test --testsuite=Modules --filter=''^Modules\\Auth\\Tests''' test:e2e: desc: Run E2E tests for Auth module @@ -17,6 +17,10 @@ tasks: db:seed: desc: Seed the Auth module database cmd: '{{.APP}} php artisan modules:seed --module=auth' + + make-admin: + desc: Promote an user to Admin + cmd: '{{.APP}} php artisan auth:make-admin' # ── Code Generation ──────────────────────────────────────────── diff --git a/database/seeders/AuthDatabaseSeeder.php b/database/seeders/AuthDatabaseSeeder.php index 9447c4a..ba49583 100644 --- a/database/seeders/AuthDatabaseSeeder.php +++ b/database/seeders/AuthDatabaseSeeder.php @@ -12,7 +12,7 @@ class AuthDatabaseSeeder extends Seeder */ public function run(): void { - $adminUser = User::firstOrCreate( + $user = User::firstOrCreate( ['email' => 'chef@saucebase.dev'], [ 'name' => 'Admin Chef', @@ -20,19 +20,6 @@ public function run(): void ] ); - // Assign the admin role to the admin user - $adminUser->assignRole('admin'); - - // Create test users for E2E tests - $user = User::firstOrCreate( - ['email' => 'test@example.com'], - [ - 'name' => 'Test User', - 'password' => bcrypt('secretsauce'), - 'email_verified_at' => now(), - ] - ); - $user->assignRole('user'); } } diff --git a/tests/e2e/tests/login/login.security.spec.ts b/tests/e2e/tests/login/login.security.spec.ts index 9e4db8a..c06cadc 100644 --- a/tests/e2e/tests/login/login.security.spec.ts +++ b/tests/e2e/tests/login/login.security.spec.ts @@ -2,6 +2,8 @@ import { test, expect } from '@e2e/fixtures'; import { LoginPage } from '../../pages/LoginPage'; test.describe('Login Security', () => { + test.describe.configure({ mode: 'serial' }); + let loginPage: LoginPage; test.beforeEach(async ({ page }) => { @@ -10,8 +12,7 @@ test.describe('Login Security', () => { }); test.describe('Rate Limiting', () => { - test.describe.configure({ mode: 'serial' }); - + test('blocks login after too many failed attempts', async () => { const invalidUser = { email: 'invalid@example.com', password: 'wrongpassword' }; From f668ba56d944bdf70b2197d1f0fc915b0a970483 Mon Sep 17 00:00:00 2001 From: roble Date: Thu, 11 Jun 2026 21:02:11 +0100 Subject: [PATCH 5/6] fix(Taskfile): correct syntax for PHPUnit test command filter --- Taskfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.yml b/Taskfile.yml index 3d44077..d8f52b7 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -5,7 +5,7 @@ tasks: # ── Testing ─────────────────────────────────────────────────── test:php: desc: Run PHPUnit tests for Auth module - cmd: 'php artisan test --testsuite=Modules --filter=''^Modules\\Auth\\Tests''' + cmd: php artisan test --testsuite=Modules --filter=''^Modules\\Auth\\Tests'' test:e2e: desc: Run E2E tests for Auth module From 937d4dbeebcd295ee582eee8bb4587cddbf91ec0 Mon Sep 17 00:00:00 2001 From: roble Date: Thu, 11 Jun 2026 21:03:54 +0100 Subject: [PATCH 6/6] fix(Taskfile): correct syntax for PHPUnit test command filter --- Taskfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.yml b/Taskfile.yml index d8f52b7..2c43997 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -5,7 +5,7 @@ tasks: # ── Testing ─────────────────────────────────────────────────── test:php: desc: Run PHPUnit tests for Auth module - cmd: php artisan test --testsuite=Modules --filter=''^Modules\\Auth\\Tests'' + cmd: php artisan test --testsuite=Modules --filter='^Modules\\Auth\\Tests' test:e2e: desc: Run E2E tests for Auth module