TenantAtlas/apps/platform/tests/Feature/System/SupportAccessRequestFlowTest.php
ahmido 1e0f21365b PR: 276-support-access-governance → platform-dev (#332)
Automated PR created via MCP by Copilot on user request: "pr gegen platform-dev".

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #332
2026-05-05 21:54:26 +00:00

151 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\System\Pages\Directory\ViewWorkspace;
use App\Models\AuditLog;
use App\Models\PlatformUser;
use App\Models\SupportAccessGrant;
use App\Models\Tenant;
use App\Models\Workspace;
use App\Services\Auth\BreakGlassSession;
use App\Support\Audit\AuditActionId;
use App\Support\Auth\PlatformCapabilities;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Livewire\Livewire;
beforeEach(function (): void {
Filament::setCurrentPanel('system');
Filament::bootCurrentPanel();
config()->set('tenantpilot.support_access.max_ttl_minutes', 120);
config()->set('tenantpilot.break_glass.enabled', true);
config()->set('tenantpilot.break_glass.ttl_minutes', 15);
});
function spec276_system_platform_user(array $extraCapabilities = []): PlatformUser
{
return PlatformUser::factory()->create([
'capabilities' => array_values(array_unique([
PlatformCapabilities::ACCESS_SYSTEM_PANEL,
PlatformCapabilities::DIRECTORY_VIEW,
...$extraCapabilities,
])),
]);
}
it('lets an authorized platform operator start and end audit-view support access from the workspace detail page', function (): void {
$workspace = Workspace::factory()->create(['name' => 'Acme Recovery']);
$platformUser = spec276_system_platform_user([
PlatformCapabilities::SUPPORT_ACCESS_MANAGE,
]);
$component = Livewire::actingAs($platformUser, 'platform')
->test(ViewWorkspace::class, ['workspace' => $workspace])
->assertActionVisible('request_support_access')
->assertActionExists('request_support_access', fn (Action $action): bool => $action->isConfirmationRequired())
->callAction('request_support_access', data: [
'scope' => SupportAccessGrant::SCOPE_AUDIT_VIEW,
'reason' => 'Investigate managed tenant audit evidence',
'ttl_minutes' => 45,
])
->assertNotified('Support access active')
->assertActionVisible('end_support_access')
->assertActionExists('end_support_access', fn (Action $action): bool => $action->isConfirmationRequired());
$grant = SupportAccessGrant::query()
->where('workspace_id', (int) $workspace->getKey())
->firstOrFail();
expect($grant->status)->toBe(SupportAccessGrant::STATUS_ACTIVE)
->and($grant->reason)->toBe('Investigate managed tenant audit evidence');
$component
->callAction('end_support_access')
->assertNotified('Support access ended');
expect($grant->fresh()->status)->toBe(SupportAccessGrant::STATUS_ENDED);
expect(AuditLog::query()
->where('workspace_id', (int) $workspace->getKey())
->whereIn('action', [
AuditActionId::SupportAccessRequested->value,
AuditActionId::SupportAccessActivated->value,
AuditActionId::SupportAccessEnded->value,
])
->count())->toBe(3);
});
it('hides support-access mutations from platform users without support-access capability', function (): void {
$workspace = Workspace::factory()->create();
$platformUser = spec276_system_platform_user();
Livewire::actingAs($platformUser, 'platform')
->test(ViewWorkspace::class, ['workspace' => $workspace])
->assertActionHidden('request_support_access')
->assertActionHidden('end_support_access');
});
it('activates ownerless workspace-recovery support access only through a break-glass waiver', function (): void {
Tenant::factory()->create([
'tenant_id' => null,
'external_id' => 'platform',
'name' => 'Platform',
]);
$workspace = Workspace::factory()->create(['name' => 'Ownerless Support Workspace']);
$platformUser = spec276_system_platform_user([
PlatformCapabilities::SUPPORT_ACCESS_MANAGE,
PlatformCapabilities::USE_BREAK_GLASS,
]);
$this->actingAs($platformUser, 'platform');
app(BreakGlassSession::class)->start($platformUser, 'Ownerless recovery support access');
Livewire::actingAs($platformUser, 'platform')
->test(ViewWorkspace::class, ['workspace' => $workspace])
->callAction('request_support_access', data: [
'scope' => SupportAccessGrant::SCOPE_WORKSPACE_RECOVERY,
'reason' => 'Recover ownerless workspace safely',
'ttl_minutes' => 30,
'waiver_reason' => 'Verified the workspace has no owner membership',
])
->assertNotified('Support access active');
$grant = SupportAccessGrant::query()
->where('workspace_id', (int) $workspace->getKey())
->where('scope', SupportAccessGrant::SCOPE_WORKSPACE_RECOVERY)
->firstOrFail();
expect($grant->status)->toBe(SupportAccessGrant::STATUS_ACTIVE)
->and($grant->approval_mode)->toBe(SupportAccessGrant::APPROVAL_MODE_OWNERLESS_WAIVER)
->and($grant->waiver_reason)->toBe('Verified the workspace has no owner membership');
expect(AuditLog::query()
->where('workspace_id', (int) $workspace->getKey())
->where('action', AuditActionId::SupportAccessOwnerlessWaiverUsed->value)
->exists())->toBeTrue();
});
it('renders current support-access posture on the system workspace detail page', function (): void {
$workspace = Workspace::factory()->create(['name' => 'Northwind Workspace']);
$platformUser = spec276_system_platform_user([
PlatformCapabilities::SUPPORT_ACCESS_MANAGE,
]);
SupportAccessGrant::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'requested_by_platform_user_id' => (int) $platformUser->getKey(),
'scope' => SupportAccessGrant::SCOPE_AUDIT_VIEW,
'reason' => 'Inspect audit evidence for a support case',
]);
$this->actingAs($platformUser, 'platform')
->get(ViewWorkspace::getUrl(panel: 'system', parameters: ['workspace' => $workspace]))
->assertSuccessful()
->assertSee('Support access')
->assertSee('Audit trail review')
->assertSee('Inspect audit evidence for a support case');
});