create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'provider.connection.check', 'status' => 'completed', 'outcome' => 'blocked', 'initiator_name' => 'System', ]); $this->actingAs($user); Bus::fake(); Filament::setTenant(null, true); $session = [ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ]; assertNoOutboundHttp(function () use ($run, $session): void { $this->withSession($session) ->get(route('admin.operations.index')) ->assertOk() ->assertSee('All tenants') ->assertDontSee('Scope: Tenant') ->assertDontSee('Scope: Workspace'); $this->withSession($session) ->get(route('admin.operations.view', ['run' => (int) $run->getKey()])) ->assertOk() ->assertSee('All tenants') ->assertDontSee('Scope: Tenant') ->assertDontSee('Scope: Workspace'); $this->withSession($session) ->followingRedirects() ->get(AlertsCluster::getUrl(panel: 'admin')) ->assertOk() ->assertSee('All tenants') ->assertDontSee('Scope: Tenant') ->assertDontSee('Scope: Workspace'); $this->withSession($session) ->get(route('admin.monitoring.audit-log')) ->assertOk() ->assertSee('All tenants') ->assertDontSee('Scope: Tenant') ->assertDontSee('Scope: Workspace'); }); Bus::assertNothingDispatched(); })->group('ops-ux'); it('shows back to tenant on run detail when tenant context is active and entitled', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'policy.sync', 'status' => 'queued', 'outcome' => 'pending', ]); $this->actingAs($user); Filament::setTenant($tenant, true); $response = $this->withSession([ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ])->get(route('admin.operations.view', ['run' => (int) $run->getKey()])); $response ->assertOk() ->assertSee('← Back to '.$tenant->name) ->assertSee(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant), false) ->assertDontSee('Back to Operations'); $this->withSession([ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ])->followingRedirects() ->get(AlertsCluster::getUrl(panel: 'admin')) ->assertOk() ->assertDontSee('Back to Operations'); expect(substr_count((string) $response->getContent(), '← Back to '.$tenant->name))->toBe(1); })->group('ops-ux'); it('shows back to tenant when filament tenant is absent but last tenant memory exists', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'policy.sync', 'status' => 'queued', 'outcome' => 'pending', ]); $this->actingAs($user); Filament::setTenant(null, true); $workspaceId = (int) $tenant->workspace_id; $lastTenantMap = [(string) $workspaceId => (int) $tenant->getKey()]; $response = $this->withSession([ WorkspaceContext::SESSION_KEY => $workspaceId, WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => $lastTenantMap, ])->get(route('admin.operations.view', ['run' => (int) $run->getKey()])); $response ->assertOk() ->assertSee('← Back to '.$tenant->name) ->assertSee(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant), false) ->assertSee('Show all operations') ->assertDontSee('Back to Operations'); })->group('ops-ux'); it('shows no tenant return affordance when active and last tenant contexts are not entitled', function (): void { [$user, $entitledTenant] = createUserWithTenant(role: 'owner'); $nonEntitledTenant = Tenant::factory()->create([ 'workspace_id' => (int) $entitledTenant->workspace_id, ]); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $entitledTenant->getKey(), 'workspace_id' => (int) $entitledTenant->workspace_id, 'type' => 'policy.sync', 'status' => 'queued', 'outcome' => 'pending', ]); $this->actingAs($user); Filament::setTenant($nonEntitledTenant, true); $workspaceId = (int) $entitledTenant->workspace_id; $response = $this->withSession([ WorkspaceContext::SESSION_KEY => $workspaceId, WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [(string) $workspaceId => (int) $nonEntitledTenant->getKey()], ])->get(route('admin.operations.view', ['run' => (int) $run->getKey()])); $response ->assertOk() ->assertSee('Back to Operations') ->assertDontSee('← Back to '.$nonEntitledTenant->name) ->assertDontSee('Show all operations'); })->group('ops-ux'); it('returns 404 for non-member workspace access on /admin/operations', function (): void { $user = User::factory()->create(); $workspace = Workspace::factory()->create(); // User is NOT a member — stale workspace context is denied as not found. $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()]) ->get(route('admin.operations.index')) ->assertNotFound(); })->group('ops-ux'); it('returns 404 for non-entitled tenant dashboard direct access', function (): void { $tenant = Tenant::factory()->create(); $user = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'user_id' => (int) $user->getKey(), 'role' => 'owner', ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant)) ->assertNotFound(); })->group('ops-ux'); it('keeps member-without-capability workflow start denial as 403 with no run side effects', function (): void { [$user, $tenant] = createUserWithTenant(role: 'operator'); $this->actingAs($user); Filament::setTenant($tenant, true); $this->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(RestoreRunResource::getUrl('create', tenant: $tenant)) ->assertForbidden(); expect(OperationRun::query() ->where('tenant_id', (int) $tenant->getKey()) ->exists())->toBeFalse(); })->group('ops-ux'); it('does not mutate workspace or last-tenant session memory on /admin/operations', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); $workspaceId = (int) $tenant->workspace_id; $lastTenantMap = [(string) $workspaceId => (int) $tenant->getKey()]; $response = $this->withSession([ WorkspaceContext::SESSION_KEY => $workspaceId, WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => $lastTenantMap, ])->get(route('admin.operations.index')); $response->assertOk(); $response->assertSessionHas(WorkspaceContext::SESSION_KEY, $workspaceId); $response->assertSessionHas(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, $lastTenantMap); })->group('ops-ux'); it('prefers the filament tenant over remembered workspace tenant state when both are entitled', function (): void { $tenantA = Tenant::factory()->create(); [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner'); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, ]); createUserWithTenant(tenant: $tenantB, user: $user, role: 'owner'); $this->actingAs($user); Filament::setTenant($tenantB, true); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $tenantA->workspace_id => (int) $tenantA->getKey(), ]); $resolved = app(OperateHubShell::class)->activeEntitledTenant(); expect($resolved?->is($tenantB))->toBeTrue(); })->group('ops-ux'); it('prefers the current filament tenant over remembered tenant state on canonical run routes', function (): void { $runTenant = Tenant::factory()->create([ 'workspace_id' => null, ]); [$user, $runTenant] = createUserWithTenant(tenant: $runTenant, role: 'owner'); $currentTenant = Tenant::factory()->create([ 'workspace_id' => (int) $runTenant->workspace_id, ]); createUserWithTenant(tenant: $currentTenant, user: $user, role: 'owner'); $run = OperationRun::factory()->create([ 'workspace_id' => (int) $runTenant->workspace_id, 'tenant_id' => (int) $runTenant->getKey(), 'type' => 'policy.sync', ]); $this->actingAs($user); Filament::setTenant($currentTenant, true); $workspaceId = (int) $runTenant->workspace_id; session()->put(WorkspaceContext::SESSION_KEY, $workspaceId); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $workspaceId => (int) $runTenant->getKey(), ]); $request = Request::create(route('admin.operations.view', ['run' => (int) $run->getKey()])); $request->setLaravelSession(app('session.store')); $route = app('router')->getRoutes()->match($request); $request->setRouteResolver(static fn () => $route); $resolved = app(OperateHubShell::class)->activeEntitledTenant($request); expect($resolved?->is($currentTenant))->toBeTrue(); })->group('ops-ux'); it('clears stale remembered tenant ids when the remembered tenant is no longer entitled', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $staleTenant = Tenant::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, ]); $this->actingAs($user); Filament::setTenant(null, true); $workspaceId = (int) $tenant->workspace_id; session()->put(WorkspaceContext::SESSION_KEY, $workspaceId); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $workspaceId => (int) $staleTenant->getKey(), ]); $resolved = app(OperateHubShell::class)->activeEntitledTenant(); expect($resolved)->toBeNull(); expect(session()->get(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [])) ->not->toHaveKey((string) $workspaceId); })->group('ops-ux'); it('prefers the routed tenant over remembered workspace tenant state when a tenant route parameter is present', function (): void { $rememberedTenant = Tenant::factory()->create([ 'name' => 'YPTW2', 'environment' => 'dev', 'status' => 'active', ]); [$user, $rememberedTenant] = createUserWithTenant(tenant: $rememberedTenant, role: 'owner'); $routedTenant = Tenant::factory()->create([ 'workspace_id' => (int) $rememberedTenant->workspace_id, 'name' => 'Phoenicon', 'environment' => 'dev', 'status' => 'active', ]); createUserWithTenant(tenant: $routedTenant, user: $user, role: 'owner'); $this->actingAs($user); Filament::setTenant(null, true); $workspaceId = (int) $rememberedTenant->workspace_id; session()->put(WorkspaceContext::SESSION_KEY, $workspaceId); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $workspaceId => (int) $rememberedTenant->getKey(), ]); $request = Request::create("/admin/tenants/{$routedTenant->external_id}/required-permissions"); $request->setLaravelSession(app('session.store')); $route = app('router')->getRoutes()->match($request); $request->setRouteResolver(static fn () => $route); $resolved = app(OperateHubShell::class)->activeEntitledTenant($request); expect($resolved?->is($routedTenant))->toBeTrue(); })->group('ops-ux'); it('prefers the routed tenant resource record over active tenant state on admin tenant view routes', function (): void { $rememberedTenant = Tenant::factory()->create([ 'name' => 'YPTW2', 'environment' => 'dev', 'status' => 'active', ]); [$user, $rememberedTenant] = createUserWithTenant(tenant: $rememberedTenant, role: 'owner'); $routedTenant = Tenant::factory()->create([ 'workspace_id' => (int) $rememberedTenant->workspace_id, 'name' => 'Test', 'environment' => 'dev', 'status' => Tenant::STATUS_ONBOARDING, ]); createUserWithTenant(tenant: $routedTenant, user: $user, role: 'owner'); $this->actingAs($user); Filament::setTenant($rememberedTenant, true); $workspaceId = (int) $rememberedTenant->workspace_id; session()->put(WorkspaceContext::SESSION_KEY, $workspaceId); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $workspaceId => (int) $rememberedTenant->getKey(), ]); $request = Request::create("/admin/tenants/{$routedTenant->external_id}"); $request->setLaravelSession(app('session.store')); $route = app('router')->getRoutes()->match($request); $request->setRouteResolver(static fn () => $route); $resolved = app(OperateHubShell::class)->activeEntitledTenant($request); expect($resolved?->is($routedTenant))->toBeTrue(); })->group('ops-ux'); it('shows tenant filter label when tenant context is active', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); $this->withSession([ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ])->get(route('admin.operations.index')) ->assertOk() ->assertSee('Tenant scope: '.$tenant->name) ->assertDontSee('Scope: Tenant') ->assertDontSee('Scope: Workspace') ->assertDontSee('All tenants'); })->group('ops-ux'); it('does not create audit entries when viewing operate hub pages', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'policy.sync', 'status' => 'queued', 'outcome' => 'pending', ]); $this->actingAs($user); Filament::setTenant(null, true); $before = (int) AuditLog::query()->count(); $session = [ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ]; $this->withSession($session) ->get(route('admin.operations.index')) ->assertOk(); $this->withSession($session) ->get(route('admin.operations.view', ['run' => (int) $run->getKey()])) ->assertOk(); $this->withSession($session) ->followingRedirects() ->get(AlertsCluster::getUrl(panel: 'admin')) ->assertOk(); $this->withSession($session) ->get(route('admin.monitoring.audit-log')) ->assertOk(); expect((int) AuditLog::query()->count())->toBe($before); })->group('ops-ux'); it('suppresses tenant indicator on alert rules list page (manage page)', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); $this->withSession([ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ])->get(AlertRuleResource::getUrl(panel: 'admin')) ->assertOk() ->assertDontSee('Filtered by tenant') ->assertDontSee('Scope: Tenant') ->assertDontSee('Scope: Workspace'); })->group('ops-ux'); it('suppresses tenant indicator on alert destinations list page (manage page)', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); $this->withSession([ WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id, ])->get(AlertDestinationResource::getUrl(panel: 'admin')) ->assertOk() ->assertDontSee('Filtered by tenant') ->assertDontSee('Scope: Tenant') ->assertDontSee('Scope: Workspace'); })->group('ops-ux'); it('suppresses tenant indicator on alert rules list with lastTenantId fallback', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant(null, true); $workspaceId = (int) $tenant->workspace_id; $lastTenantMap = [(string) $workspaceId => (int) $tenant->getKey()]; $this->withSession([ WorkspaceContext::SESSION_KEY => $workspaceId, WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => $lastTenantMap, ])->get(AlertRuleResource::getUrl(panel: 'admin')) ->assertOk() ->assertDontSee('Filtered by tenant') ->assertDontSee('Scope: Tenant'); })->group('ops-ux');