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(GovernanceInbox::getUrl(panel: 'admin')) ->assertRedirect('/admin/choose-workspace'); }); it('returns 404 for users outside the active workspace on the governance inbox 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(GovernanceInbox::getUrl(panel: 'admin')) ->assertNotFound(); }); it('returns 403 for workspace members with no qualifying family visibility 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', ]); mock(WorkspaceCapabilityResolver::class, function ($mock): void { $mock->shouldReceive('isMember')->andReturnTrue(); $mock->shouldReceive('can')->andReturnFalse(); }); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()]) ->get(GovernanceInbox::getUrl(panel: 'admin')) ->assertForbidden(); }); it('allows readonly tenant members to open the governance inbox through operations-family visibility', function (): void { $tenant = Tenant::factory()->create(['status' => 'active']); [$user, $tenant] = createUserWithTenant($tenant, role: 'readonly', workspaceRole: 'readonly'); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(GovernanceInbox::getUrl(panel: 'admin')) ->assertOk() ->assertSee('Governance inbox'); }); it('returns 404 for explicit tenant filters outside the actor scope', 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, ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id]) ->get(GovernanceInbox::getUrl(panel: 'admin').'?tenant_id='.(string) $hiddenTenant->getKey()) ->assertNotFound(); });