create(); $workspaceA = Workspace::factory()->create(); $workspaceB = Workspace::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => (int) $workspaceA->getKey(), 'user_id' => (int) $user->getKey(), 'role' => 'owner', ]); WorkspaceMembership::factory()->create([ 'workspace_id' => (int) $workspaceB->getKey(), 'user_id' => (int) $user->getKey(), 'role' => 'owner', ]); $this->actingAs($user) ->get(FindingsIntakeQueue::getUrl(panel: 'admin')) ->assertRedirect('/admin/choose-workspace'); }); it('returns 404 for users outside the active workspace on the intake route', function (): void { $user = User::factory()->create(); $workspace = Workspace::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => (int) Workspace::factory()->create()->getKey(), 'user_id' => (int) $user->getKey(), 'role' => 'owner', ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()]) ->get(FindingsIntakeQueue::getUrl(panel: 'admin')) ->assertNotFound(); }); it('returns 403 for workspace members with no currently viewable findings scope anywhere', function (): void { $user = User::factory()->create(); $workspace = Workspace::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'user_id' => (int) $user->getKey(), 'role' => 'owner', ]); Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'status' => 'active', ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()]) ->get(FindingsIntakeQueue::getUrl(panel: 'admin')) ->assertForbidden(); }); it('suppresses hidden-tenant findings and keeps their detail route not found', function (): void { $visibleTenant = Tenant::factory()->create(['status' => 'active']); [$user, $visibleTenant] = createUserWithTenant($visibleTenant, role: 'readonly', workspaceRole: 'readonly'); $hiddenTenant = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $visibleTenant->workspace_id, ]); $visibleFinding = Finding::factory()->for($visibleTenant)->create([ 'workspace_id' => (int) $visibleTenant->workspace_id, 'status' => Finding::STATUS_TRIAGED, 'assignee_user_id' => null, ]); $hiddenFinding = Finding::factory()->for($hiddenTenant)->create([ 'workspace_id' => (int) $hiddenTenant->workspace_id, 'status' => Finding::STATUS_NEW, 'assignee_user_id' => null, ]); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $visibleTenant->workspace_id); Livewire::actingAs($user) ->test(FindingsIntakeQueue::class) ->assertCanSeeTableRecords([$visibleFinding]) ->assertCanNotSeeTableRecords([$hiddenFinding]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id]) ->get(FindingResource::getUrl('view', ['record' => $hiddenFinding], panel: 'tenant', tenant: $hiddenTenant)) ->assertNotFound(); }); it('keeps inspect access while disabling claim for members without assign capability', function (): void { $tenant = Tenant::factory()->create(['status' => 'active']); [$user, $tenant] = createUserWithTenant($tenant, role: 'readonly', workspaceRole: 'readonly'); $finding = Finding::factory()->for($tenant)->create([ 'workspace_id' => (int) $tenant->workspace_id, 'status' => Finding::STATUS_NEW, 'assignee_user_id' => null, ]); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); Livewire::actingAs($user) ->test(FindingsIntakeQueue::class) ->assertCanSeeTableRecords([$finding]) ->assertTableActionVisible('claim', $finding) ->assertTableActionDisabled('claim', $finding) ->callTableAction('claim', $finding); expect($finding->refresh()->assignee_user_id)->toBeNull(); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(FindingResource::getUrl('view', ['record' => $finding], panel: 'tenant', tenant: $tenant)) ->assertOk(); });