TenantAtlas/apps/platform/tests/Feature/System/OpsControls/OperationalControlManagementTest.php
ahmido d96abc65fb
Some checks failed
Main Confidence / confidence (push) Failing after 1m23s
Remove Findings lifecycle backfill operational surface (controls slice) (#280)
Removes the Findings lifecycle backfill from the Operational Controls UI and OperationalControlCatalog.

This patch is a safe, controls-only change; runbooks, jobs and other runtime artifacts are NOT removed yet. Follow-up work will delete the runbook service/scope, jobs, commands, and update tests.

Files changed:
- apps/platform/app/Filament/System/Pages/Ops/Controls.php
- apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php
- apps/platform/tests/Feature/System/OpsControls/OperationalControlManagementTest.php
- apps/platform/tests/Unit/Support/OperationalControls/OperationalControlCatalogTest.php
- apps/platform/tests/Unit/Support/OperationalControls/OperationalControlScopeResolutionTest.php

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #280
2026-04-26 15:43:47 +00:00

243 lines
9.6 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\System\Pages\Ops\Controls;
use App\Models\AuditLog;
use App\Models\OperationalControlActivation;
use App\Models\PlatformUser;
use App\Models\Tenant;
use App\Models\Workspace;
use App\Support\Audit\AuditActionId;
use App\Support\Auth\PlatformCapabilities;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
uses(RefreshDatabase::class);
beforeEach(function (): void {
Filament::setCurrentPanel('system');
Filament::bootCurrentPanel();
});
function makeControlsManager(): PlatformUser
{
return PlatformUser::factory()->create([
'capabilities' => [
PlatformCapabilities::ACCESS_SYSTEM_PANEL,
PlatformCapabilities::OPS_CONTROLS_MANAGE,
],
'is_active' => true,
]);
}
it('returns 403 for platform users missing the operational controls capability', function (): void {
$user = PlatformUser::factory()->create([
'capabilities' => [PlatformCapabilities::ACCESS_SYSTEM_PANEL],
'is_active' => true,
]);
$this->actingAs($user, 'platform')
->get(Controls::getUrl(panel: 'system'))
->assertForbidden();
});
it('renders compact card actions and only shows the action that matches the current control state', function (): void {
$user = makeControlsManager();
$this->actingAs($user, 'platform');
$this->get(Controls::getUrl(panel: 'system'))
->assertSuccessful()
->assertSee("mountAction('pause_restore_execute')", escape: false)
->assertDontSee('Findings lifecycle backfill')
->assertDontSee("mountAction('pause_findings_lifecycle_backfill')", escape: false)
->assertDontSee("mountAction('resume_findings_lifecycle_backfill')", escape: false)
->assertDontSee("mountAction('view_history_findings_lifecycle_backfill')", escape: false)
->assertDontSee('Pause Restore execution')
->assertDontSee('Resume Restore execution');
OperationalControlActivation::factory()->forGlobalScope()->create([
'control_key' => 'restore.execute',
'reason_text' => 'Paused for compact action rendering coverage.',
]);
$this->get(Controls::getUrl(panel: 'system'))
->assertSuccessful()
->assertSee("mountAction('resume_restore_execute')", escape: false)
->assertDontSee("mountAction('pause_restore_execute')", escape: false)
->assertDontSee('Findings lifecycle backfill');
});
it('previews, pauses, updates, resumes, and exposes on-demand history for restore execution', function (): void {
$workspaceA = Workspace::factory()->create(['name' => 'Acme']);
$workspaceB = Workspace::factory()->create(['name' => 'Bravo']);
Tenant::factory()->count(2)->create(['workspace_id' => (int) $workspaceA->getKey()]);
Tenant::factory()->count(1)->create(['workspace_id' => (int) $workspaceB->getKey()]);
$user = makeControlsManager();
$this->actingAs($user, 'platform');
$component = Livewire::test(Controls::class)
->assertActionExists('pause_restore_execute', fn (Action $action): bool => $action->isConfirmationRequired())
->assertActionExists('resume_restore_execute', fn (Action $action): bool => $action->isConfirmationRequired())
->assertActionExists('view_history_restore_execute', fn (Action $action): bool => $action->getLabel() === 'View Restore execution history');
$preview = $component->instance()->scopeImpactPreview('restore.execute', 'global', null);
expect($preview['workspace_count'])->toBe(2)
->and($preview['tenant_count'])->toBe(3)
->and($preview['summary'])->toContain('2 workspaces')
->and($preview['summary'])->toContain('3 tenants');
$component
->callAction('pause_restore_execute', data: [
'scope_type' => 'global',
'reason_text' => 'Paused for incident review.',
'expires_at' => now()->addDay()->toDateTimeString(),
])
->assertNotified('Restore execution paused');
$activation = OperationalControlActivation::query()
->forControl('restore.execute')
->forGlobalScope()
->first();
expect($activation)->not->toBeNull()
->and($activation?->reason_text)->toBe('Paused for incident review.');
$summary = $component->instance()->controlSummary('restore.execute');
expect($summary['effective_state'])->toBe('paused')
->and($summary['active_activations'])->toHaveCount(1)
->and($summary['active_activations'][0]['owner_name'])->toBe($user->name);
$component
->callAction('pause_restore_execute', data: [
'scope_type' => 'global',
'reason_text' => 'Updated incident review scope.',
'expires_at' => now()->addDays(2)->toDateTimeString(),
])
->assertNotified('Restore execution updated');
expect($activation?->fresh()?->reason_text)->toBe('Updated incident review scope.');
$component
->callAction('resume_restore_execute', data: [
'scope_type' => 'global',
])
->assertNotified('Restore execution resumed');
expect(OperationalControlActivation::query()
->forControl('restore.execute')
->forGlobalScope()
->count())->toBe(0);
$audits = AuditLog::query()
->whereIn('action', [
AuditActionId::OperationalControlPaused->value,
AuditActionId::OperationalControlUpdated->value,
AuditActionId::OperationalControlResumed->value,
])
->where('metadata->control_key', 'restore.execute')
->orderBy('id')
->get();
expect($audits)->toHaveCount(3)
->and($audits->pluck('workspace_id')->unique()->all())->toBe([null])
->and($audits->pluck('tenant_id')->unique()->all())->toBe([null])
->and($audits[0]->action)->toBe(AuditActionId::OperationalControlPaused->value)
->and($audits[1]->action)->toBe(AuditActionId::OperationalControlUpdated->value)
->and($audits[2]->action)->toBe(AuditActionId::OperationalControlResumed->value);
$component
->mountAction('view_history_restore_execute')
->assertActionMounted('view_history_restore_execute');
});
it('supports workspace-scoped pauses and removes expired conflicting activations before replacement writes', function (): void {
$workspaceA = Workspace::factory()->create(['name' => 'Acme']);
$workspaceB = Workspace::factory()->create(['name' => 'Bravo']);
Tenant::factory()->count(2)->create(['workspace_id' => (int) $workspaceA->getKey()]);
Tenant::factory()->count(1)->create(['workspace_id' => (int) $workspaceB->getKey()]);
$expired = OperationalControlActivation::factory()->workspaceScoped()->create([
'control_key' => 'restore.execute',
'workspace_id' => (int) $workspaceA->getKey(),
'reason_text' => 'Expired pause.',
'expires_at' => now()->subHour(),
]);
$user = makeControlsManager();
$this->actingAs($user, 'platform');
$component = Livewire::test(Controls::class)
->assertActionExists('pause_restore_execute', fn (Action $action): bool => $action->isConfirmationRequired())
->assertActionExists('resume_restore_execute', fn (Action $action): bool => $action->isConfirmationRequired());
$preview = $component->instance()->scopeImpactPreview('restore.execute', 'workspace', (int) $workspaceA->getKey());
expect($preview['workspace_count'])->toBe(1)
->and($preview['tenant_count'])->toBe(2)
->and($preview['summary'])->toContain('Acme');
$component
->callAction('pause_restore_execute', data: [
'scope_type' => 'workspace',
'workspace_id' => (int) $workspaceA->getKey(),
'reason_text' => 'Paused for workspace restore maintenance.',
'expires_at' => now()->addDay()->toDateTimeString(),
])
->assertNotified('Restore execution paused');
expect(OperationalControlActivation::query()->whereKey((int) $expired->getKey())->exists())->toBeFalse();
$activation = OperationalControlActivation::query()
->forControl('restore.execute')
->forWorkspaceScope((int) $workspaceA->getKey())
->notExpired()
->first();
expect($activation)->not->toBeNull()
->and((int) ($activation?->workspace_id ?? 0))->toBe((int) $workspaceA->getKey());
$component
->callAction('pause_restore_execute', data: [
'scope_type' => 'workspace',
'workspace_id' => (int) $workspaceA->getKey(),
'reason_text' => 'Updated workspace restore maintenance.',
'expires_at' => now()->addDays(3)->toDateTimeString(),
])
->assertNotified('Restore execution updated');
expect($activation?->fresh()?->reason_text)->toBe('Updated workspace restore maintenance.');
$component
->callAction('resume_restore_execute', data: [
'scope_type' => 'workspace',
'workspace_id' => (int) $workspaceA->getKey(),
])
->assertNotified('Restore execution resumed');
expect(OperationalControlActivation::query()
->forControl('restore.execute')
->forWorkspaceScope((int) $workspaceA->getKey())
->count())->toBe(0);
$audits = AuditLog::query()
->whereIn('action', [
AuditActionId::OperationalControlPaused->value,
AuditActionId::OperationalControlUpdated->value,
AuditActionId::OperationalControlResumed->value,
])
->where('metadata->control_key', 'restore.execute')
->orderBy('id')
->get();
expect($audits)->toHaveCount(3)
->and($audits[0]->workspace_id)->toBe((int) $workspaceA->getKey())
->and($audits[0]->tenant_id)->toBeNull();
});