Implemented the final operator workflow for the Governance Inbox. This includes refactoring the inbox page, updating finding resources, adding UI enforcement policies, updating related blade views, and adding comprehensive tests for operator workflow and scope contracts. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #418
304 lines
11 KiB
PHP
304 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Pages\Monitoring\FindingExceptionsQueue;
|
|
use App\Filament\Resources\EnvironmentReviewResource;
|
|
use App\Filament\Resources\EvidenceSnapshotResource;
|
|
use App\Filament\Resources\FindingExceptionResource;
|
|
use App\Filament\Resources\ManagedEnvironmentResource;
|
|
use App\Models\EvidenceSnapshot;
|
|
use App\Models\Finding;
|
|
use App\Models\FindingException;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\OperationRun;
|
|
use App\Models\PlatformUser;
|
|
use App\Models\ReviewPack;
|
|
use App\Models\User;
|
|
use App\Services\Findings\FindingExceptionService;
|
|
use App\Support\Auth\PlatformCapabilities;
|
|
use App\Support\EnvironmentReviewCompletenessState;
|
|
use App\Support\EnvironmentReviewStatus;
|
|
use App\Support\Evidence\EvidenceCompletenessState;
|
|
use App\Support\Evidence\EvidenceSnapshotStatus;
|
|
use App\Support\OperationRunOutcome;
|
|
use App\Support\OperationRunStatus;
|
|
use App\Support\System\SystemOperationRunLinks;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
pest()->browser()->timeout(20_000);
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
function spec194ApprovedFindingException(ManagedEnvironment $tenant, User $requester): FindingException
|
|
{
|
|
$approver = User::factory()->create();
|
|
createUserWithTenant(
|
|
tenant: $tenant,
|
|
user: $approver,
|
|
role: 'owner',
|
|
workspaceRole: 'manager',
|
|
ensureDefaultMicrosoftProviderConnection: false,
|
|
);
|
|
|
|
$finding = Finding::factory()->for($tenant)->create([
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'status' => Finding::STATUS_RISK_ACCEPTED,
|
|
]);
|
|
|
|
/** @var FindingExceptionService $service */
|
|
$service = app(FindingExceptionService::class);
|
|
|
|
$requested = $service->request($finding, $tenant, $requester, [
|
|
'owner_user_id' => (int) $requester->getKey(),
|
|
'request_reason' => 'Spec194 browser smoke request.',
|
|
'review_due_at' => now()->addDays(7)->toDateTimeString(),
|
|
'expires_at' => now()->addDays(14)->toDateTimeString(),
|
|
]);
|
|
|
|
return $service->approve($requested, $approver, [
|
|
'effective_from' => now()->subDay()->toDateTimeString(),
|
|
'expires_at' => now()->addDays(14)->toDateTimeString(),
|
|
'approval_reason' => 'Spec194 browser smoke approval.',
|
|
]);
|
|
}
|
|
|
|
function spec194SmokeLoginUrl(User $user, ManagedEnvironment $tenant, string $redirect = ''): string
|
|
{
|
|
$redirect = spec194RelativeRedirect($redirect);
|
|
|
|
return route('admin.local.smoke-login', array_filter([
|
|
'email' => $user->email,
|
|
'tenant' => $tenant->external_id,
|
|
'workspace' => $tenant->workspace->slug,
|
|
'redirect' => $redirect,
|
|
], static fn (?string $value): bool => filled($value)));
|
|
}
|
|
|
|
function spec194RelativeRedirect(string $redirect): string
|
|
{
|
|
$redirect = trim($redirect);
|
|
|
|
if ($redirect === '') {
|
|
return '';
|
|
}
|
|
|
|
$parts = parse_url($redirect);
|
|
|
|
if ($parts === false || ! isset($parts['path'])) {
|
|
return '';
|
|
}
|
|
|
|
return $parts['path']
|
|
.(isset($parts['query']) ? '?'.$parts['query'] : '')
|
|
.(isset($parts['fragment']) ? '#'.$parts['fragment'] : '');
|
|
}
|
|
|
|
it('smokes tenant and admin governance semantics through modal entry points', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(
|
|
role: 'owner',
|
|
workspaceRole: 'owner',
|
|
ensureDefaultMicrosoftProviderConnection: false,
|
|
clearCapabilityCaches: true,
|
|
);
|
|
|
|
$finding = Finding::factory()->for($tenant)->create();
|
|
|
|
$pendingException = FindingException::query()->create([
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'finding_id' => (int) $finding->getKey(),
|
|
'requested_by_user_id' => (int) $user->getKey(),
|
|
'owner_user_id' => (int) $user->getKey(),
|
|
'status' => FindingException::STATUS_PENDING,
|
|
'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT,
|
|
'request_reason' => 'Spec194 focused review queue smoke.',
|
|
'requested_at' => now()->subDay(),
|
|
'review_due_at' => now()->addDay(),
|
|
'evidence_summary' => ['reference_count' => 0],
|
|
]);
|
|
|
|
$approvedException = spec194ApprovedFindingException($tenant, $user);
|
|
|
|
$snapshotRun = OperationRun::factory()->forTenant($tenant)->create([
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
]);
|
|
|
|
$snapshot = EvidenceSnapshot::query()->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'operation_run_id' => (int) $snapshotRun->getKey(),
|
|
'initiated_by_user_id' => (int) $user->getKey(),
|
|
'status' => EvidenceSnapshotStatus::Active->value,
|
|
'completeness_state' => EvidenceCompletenessState::Complete->value,
|
|
'summary' => ['finding_count' => 2],
|
|
'generated_at' => now(),
|
|
]);
|
|
|
|
ReviewPack::factory()->ready()->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'evidence_snapshot_id' => (int) $snapshot->getKey(),
|
|
'initiated_by_user_id' => (int) $user->getKey(),
|
|
]);
|
|
|
|
$review = composeEnvironmentReviewForTest($tenant, $user, $snapshot);
|
|
|
|
$review->forceFill([
|
|
'status' => EnvironmentReviewStatus::Ready->value,
|
|
'completeness_state' => EnvironmentReviewCompletenessState::Complete->value,
|
|
'summary' => array_replace_recursive(is_array($review->summary) ? $review->summary : [], [
|
|
'publish_blockers' => [],
|
|
'section_state_counts' => [
|
|
'complete' => 6,
|
|
'partial' => 0,
|
|
'missing' => 0,
|
|
'stale' => 0,
|
|
],
|
|
]),
|
|
])->save();
|
|
|
|
$review = $review->refresh();
|
|
|
|
$archivedTenant = ManagedEnvironment::factory()->archived()->create([
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'name' => 'Spec194 Archived ManagedEnvironment',
|
|
]);
|
|
|
|
createUserWithTenant(
|
|
tenant: $archivedTenant,
|
|
user: $user,
|
|
role: 'owner',
|
|
workspaceRole: 'owner',
|
|
ensureDefaultMicrosoftProviderConnection: false,
|
|
clearCapabilityCaches: true,
|
|
);
|
|
|
|
visit(spec194SmokeLoginUrl($user, $tenant))
|
|
->waitForText($tenant->name)
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
|
|
visit(FindingExceptionsQueue::getUrl(panel: 'admin').'?exception='.(int) $pendingException->getKey())
|
|
->waitForText('Focused review lane')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee('The selected exception defines the focused review context.')
|
|
->assertSee('Approve exception')
|
|
->assertSee('Reject exception');
|
|
|
|
visit(FindingExceptionResource::getUrl('view', ['record' => $approvedException], tenant: $tenant))
|
|
->waitForText('Related context')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee('Renew exception')
|
|
->assertSee('Revoke exception');
|
|
|
|
visit(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $review], $tenant))
|
|
->waitForText('Related context')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->click('Publish review')
|
|
->waitForText('Publication reason')
|
|
->click('button:has-text("Cancel")')
|
|
->click('[aria-label="More"]')
|
|
->assertSee('Refresh review')
|
|
->assertSee('Export executive pack')
|
|
->click('[aria-label="Danger"]')
|
|
->click('Archive review')
|
|
->waitForText('Archive reason')
|
|
->click('button:has-text("Cancel")')
|
|
->assertSee('Publish review')
|
|
->assertSee('Evidence snapshot');
|
|
|
|
visit(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant))
|
|
->waitForText('Related context')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->click('Refresh evidence')
|
|
->waitForText('Confirm')
|
|
->click('button:has-text("Cancel")')
|
|
->click('Expire snapshot')
|
|
->waitForText('Expiry reason')
|
|
->click('button:has-text("Cancel")')
|
|
->assertSee('Refresh evidence')
|
|
->assertSee('Expire snapshot');
|
|
|
|
visit(ManagedEnvironmentResource::getUrl('view', ['record' => $tenant], panel: 'admin'))
|
|
->waitForText('Environment governance overview')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee((string) $tenant->name)
|
|
->assertSee('Recommended next actions');
|
|
|
|
visit(ManagedEnvironmentResource::getUrl('edit', ['record' => $tenant], panel: 'admin'))
|
|
->waitForText('Environment governance overview')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee((string) $tenant->name);
|
|
|
|
visit(spec194SmokeLoginUrl(
|
|
$user,
|
|
$archivedTenant,
|
|
ManagedEnvironmentResource::getUrl('view', ['record' => $archivedTenant], panel: 'admin'),
|
|
))
|
|
->waitForText('Environment governance overview')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee((string) $archivedTenant->name);
|
|
|
|
visit(spec194SmokeLoginUrl(
|
|
$user,
|
|
$archivedTenant,
|
|
ManagedEnvironmentResource::getUrl('edit', ['record' => $archivedTenant], panel: 'admin'),
|
|
))
|
|
->waitForText('Environment governance overview')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee((string) $archivedTenant->name);
|
|
});
|
|
|
|
it('smokes system run triage semantics without javascript errors', function (): void {
|
|
$failedRun = OperationRun::factory()->create([
|
|
'status' => OperationRunStatus::Completed->value,
|
|
'outcome' => OperationRunOutcome::Failed->value,
|
|
'type' => 'inventory_sync',
|
|
]);
|
|
|
|
$runningRun = OperationRun::factory()->create([
|
|
'status' => OperationRunStatus::Running->value,
|
|
'outcome' => OperationRunOutcome::Pending->value,
|
|
'type' => 'inventory_sync',
|
|
'created_at' => now()->subMinutes(15),
|
|
'started_at' => now()->subMinutes(10),
|
|
]);
|
|
|
|
$platformUser = PlatformUser::factory()->create([
|
|
'capabilities' => [
|
|
PlatformCapabilities::ACCESS_SYSTEM_PANEL,
|
|
PlatformCapabilities::OPERATIONS_VIEW,
|
|
PlatformCapabilities::OPERATIONS_MANAGE,
|
|
],
|
|
'is_active' => true,
|
|
]);
|
|
|
|
auth('web')->logout();
|
|
$this->flushSession();
|
|
$this->actingAs($platformUser, 'platform');
|
|
|
|
visit(SystemOperationRunLinks::view($failedRun))
|
|
->waitForText('Operation #'.(int) $failedRun->getKey())
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee('Retry')
|
|
->assertSee('Mark investigated')
|
|
->assertDontSee('Cancel');
|
|
|
|
visit(SystemOperationRunLinks::view($runningRun))
|
|
->waitForText('Operation #'.(int) $runningRun->getKey())
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->assertSee('Mark investigated')
|
|
->assertSee('Cancel');
|
|
});
|