seed(RolesAndPermissionsSeeder::class)); it('блокирует вход после превышения числа попыток (ИАФ.6)', function () { $user = User::factory()->create(['email' => 'lock@example.local']); $max = (int) config('security.lockout.max_attempts'); for ($i = 0; $i < $max; $i++) { post('/login', ['email' => $user->email, 'password' => 'wrong-password']); } // Превышение лимита: попытка отклоняется и фиксируется блокировка (РСБ.2). post('/login', ['email' => $user->email, 'password' => 'wrong-password']) ->assertSessionHasErrors('email'); $this->assertDatabaseHas('audit_log', ['event_type' => 'auth.locked'], config('audit.connection')); }); it('регистрирует неудачный вход в журнале аудита (РСБ.2)', function () { User::factory()->create(['email' => 'audit-login@example.local']); post('/login', ['email' => 'audit-login@example.local', 'password' => 'wrong']); $this->assertDatabaseHas('audit_log', ['event_type' => 'auth.login.failed'], config('audit.connection')); }); it('требует второй фактор после входа, если MFA не настроена (ИАФ.4)', function () { $user = User::factory()->create(['password' => bcrypt('Password123!@#')]); post('/login', ['email' => $user->email, 'password' => 'Password123!@#']); // Доступ в защищённую зону перенаправляет на настройку MFA. $this->get('/dashboard')->assertRedirect(route('mfa.setup')); });