actingAs($user); Filament::setTenant($tenant, true); $profile = BaselineProfile::factory()->active()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'name' => 'Security Baseline', ]); $snapshot = BaselineSnapshot::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'baseline_profile_id' => (int) $profile->getKey(), ]); $policy = Policy::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), ]); $version = PolicyVersion::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_id' => (int) $policy->getKey(), ]); $run = OperationRun::factory()->for($tenant)->create([ 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'baseline_compare', ]); $finding = Finding::factory()->for($tenant)->create([ 'current_operation_run_id' => (int) $run->getKey(), 'evidence_jsonb' => [ 'current' => [ 'policy_version_id' => (int) $version->getKey(), ], 'provenance' => [ 'baseline_profile_id' => (int) $profile->getKey(), 'baseline_snapshot_id' => (int) $snapshot->getKey(), 'compare_operation_run_id' => (int) $run->getKey(), ], ], ]); $resolver = app(RelatedNavigationResolver::class); $first = $resolver->primaryListAction(CrossResourceNavigationMatrix::SOURCE_FINDING, $finding); $second = $resolver->primaryListAction(CrossResourceNavigationMatrix::SOURCE_FINDING, $finding); expect($first?->targetUrl)->toBe($second?->targetUrl); $store = app(RequestScopedDerivedStateStore::class); expect($store->countStored( DerivedStateFamily::RelatedNavigationPrimary, Finding::class, (string) $finding->getKey(), CrossResourceNavigationMatrix::SOURCE_FINDING, ))->toBe(1); $orphanedFinding = Finding::factory()->for($tenant)->create([ 'evidence_jsonb' => [], ]); expect($resolver->primaryListAction(CrossResourceNavigationMatrix::SOURCE_FINDING, $orphanedFinding))->toBeNull() ->and($resolver->primaryListAction(CrossResourceNavigationMatrix::SOURCE_FINDING, $orphanedFinding))->toBeNull(); $negativeKey = DerivedStateKey::fromModel( DerivedStateFamily::RelatedNavigationPrimary, $orphanedFinding, CrossResourceNavigationMatrix::SOURCE_FINDING, [ 'source_type' => CrossResourceNavigationMatrix::SOURCE_FINDING, 'surface' => CrossResourceNavigationMatrix::SURFACE_LIST_ROW, 'active_tenant_id' => (int) $tenant->getKey(), 'route_name' => null, 'user_id' => (int) $user->getKey(), ], ); expect($store->resolutionRecord($negativeKey)['negative_result'])->toBeTrue(); }); it('reuses operation-run related context across detail and header consumers', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); $run = OperationRun::factory()->for($tenant)->create([ 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'backup_set.add_policies', 'context' => [ 'backup_set_id' => 123, ], ]); $resolver = app(RelatedNavigationResolver::class); $resolver->detailEntries(CrossResourceNavigationMatrix::SOURCE_OPERATION_RUN, $run); $resolver->operationLinks($run, $tenant); expect(app(RequestScopedDerivedStateStore::class)->countStored( DerivedStateFamily::RelatedNavigationDetail, OperationRun::class, (string) $run->getKey(), CrossResourceNavigationMatrix::SOURCE_OPERATION_RUN, ))->toBe(1); }); it('keeps related-navigation target routes tenant-safe for non-members and capability-limited members', function (): void { $workspaceTenant = \App\Models\Tenant::factory()->create(); [$member, $workspaceTenant] = createUserWithTenant(tenant: $workspaceTenant, role: 'readonly'); $nonMember = \App\Models\User::factory()->create(); $profile = BaselineProfile::factory()->active()->create([ 'workspace_id' => (int) $workspaceTenant->workspace_id, ]); $snapshot = BaselineSnapshot::factory()->create([ 'workspace_id' => (int) $workspaceTenant->workspace_id, 'baseline_profile_id' => (int) $profile->getKey(), ]); Filament::setTenant(null, true); $this->actingAs($nonMember) ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspaceTenant->workspace_id]) ->get(BaselineSnapshotResource::getUrl('view', ['record' => $snapshot], panel: 'admin')) ->assertNotFound(); $resolver = \Mockery::mock(WorkspaceCapabilityResolver::class); $resolver->shouldReceive('isMember')->andReturnTrue(); $resolver->shouldReceive('can')->andReturnFalse(); app()->instance(WorkspaceCapabilityResolver::class, $resolver); $this->actingAs($member) ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspaceTenant->workspace_id]) ->get(BaselineSnapshotResource::getUrl('view', ['record' => $snapshot], panel: 'admin')) ->assertForbidden(); });