create(); $otherTenant = Tenant::factory()->create(); [$user] = createUserWithTenant($otherTenant, role: 'owner'); ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'display_name' => 'Unauthorized Tenant Connection', ]); $this->actingAs($user) ->get(ProviderConnectionResource::getUrl('index', tenant: $tenant)) ->assertOk() ->assertDontSee('Unauthorized Tenant Connection'); }); test('non-members cannot reach provider connection detail target-scope metadata', function (): void { $tenant = Tenant::factory()->create(); $otherTenant = Tenant::factory()->create(); [$user] = createUserWithTenant($otherTenant, role: 'owner'); $connection = ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'display_name' => 'Hidden Scope Connection', 'entra_tenant_id' => '77777777-7777-7777-7777-777777777777', ]); $this->actingAs($user) ->get(ProviderConnectionResource::getUrl('view', ['record' => $connection], tenant: $tenant)) ->assertNotFound(); }); test('members without capability see provider connection actions disabled with standard tooltip', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'readonly'); $connection = ProviderConnection::factory()->create([ 'tenant_id' => $tenant->getKey(), 'consent_status' => 'required', 'is_enabled' => true, 'provider' => 'microsoft', ]); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListProviderConnections::class) ->assertTableActionVisible('check_connection', $connection) ->assertTableActionDisabled('check_connection', $connection) ->assertTableActionExists('check_connection', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission(), $connection); Livewire::actingAs($user) ->test(ViewProviderConnection::class, ['record' => $connection->getKey()]) ->assertActionVisible('check_connection') ->assertActionDisabled('check_connection') ->assertActionExists('check_connection', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission()) ->assertActionVisible('inventory_sync') ->assertActionDisabled('inventory_sync') ->assertActionVisible('compliance_snapshot') ->assertActionDisabled('compliance_snapshot') ->assertActionVisible('edit') ->assertActionDisabled('edit') ->assertActionExists('edit', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission()); }); test('members with capability can see provider connection actions enabled', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'owner'); $connection = ProviderConnection::factory()->create([ 'tenant_id' => $tenant->getKey(), 'consent_status' => 'required', 'is_enabled' => true, 'provider' => 'microsoft', ]); $tenant->makeCurrent(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListProviderConnections::class) ->assertTableActionVisible('check_connection', $connection) ->assertTableActionEnabled('check_connection', $connection); Livewire::actingAs($user) ->test(ViewProviderConnection::class, ['record' => $connection->getKey()]) ->assertActionVisible('check_connection') ->assertActionEnabled('check_connection') ->assertActionVisible('inventory_sync') ->assertActionEnabled('inventory_sync') ->assertActionVisible('compliance_snapshot') ->assertActionEnabled('compliance_snapshot') ->assertActionVisible('edit') ->assertActionEnabled('edit'); }); test('sensitive provider connection mutations remain confirmation and capability gated', function (): void { $source = (string) file_get_contents(repo_path('apps/platform/app/Filament/Resources/ProviderConnectionResource.php')); foreach ([ 'makeSetDefaultAction', 'makeEnableDedicatedOverrideAction', 'makeRotateDedicatedCredentialAction', 'makeDeleteDedicatedCredentialAction', 'makeRevertToPlatformAction', 'makeEnableConnectionAction', 'makeDisableConnectionAction', ] as $method) { $start = strpos($source, 'public static function '.$method); expect($start)->not->toBeFalse(); $next = strpos($source, "\n public static function ", $start + 1); $block = substr($source, $start, $next === false ? null : $next - $start); expect($block)->toContain('->requiresConfirmation()') ->and($block)->toContain('->requireCapability('); } });