TenantAtlas/apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuthorizationTest.php
Ahmed Darrazi 983abb18a1
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 3m22s
chore: commit workspace changes (automated)
2026-05-02 16:36:21 +02:00

182 lines
7.3 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\CrossTenantComparePage;
use App\Models\OperationRun;
use App\Models\OperationalControlActivation;
use App\Models\Tenant;
use App\Services\Auth\CapabilityResolver;
use App\Support\PortfolioCompare\CrossTenantComparePreviewBuilder;
use App\Support\PortfolioCompare\CrossTenantCompareSelection;
use App\Support\PortfolioCompare\CrossTenantPromotionPreflight;
use Filament\Actions\Action;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\Feature\Concerns\BuildsPortfolioCompareFixtures;
uses(RefreshDatabase::class, BuildsPortfolioCompareFixtures::class);
it('keeps execute promotion visible but disabled for compare-only actors without target manage access', function (): void {
$fixture = $this->makeCrossTenantCompareFixture(workspaceRole: 'owner', tenantRole: 'readonly');
$this->createPortfolioCompareSubject(
tenant: $fixture['sourceTenant'],
displayName: 'Compare Only Policy',
snapshot: ['settings' => [['key' => 'readonly', 'value' => 1]]],
);
$this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
$query = [
'source_tenant_id' => (int) $fixture['sourceTenant']->getKey(),
'target_tenant_id' => (int) $fixture['targetTenant']->getKey(),
'policy_type' => ['deviceConfiguration'],
];
Livewire::withQueryParams($query)
->actingAs($fixture['user'])
->test(CrossTenantComparePage::class)
->call('generatePromotionPreflight')
->assertActionVisible('executePromotion')
->assertActionDisabled('executePromotion')
->assertActionExists('executePromotion', fn (Action $action): bool => $action->getTooltip() === 'You need target tenant manage access to execute promotion.')
->call('executePromotion')
->assertForbidden();
});
it('keeps execute promotion visible but disabled without workspace baseline manage access and forbids forced execution', function (): void {
$fixture = $this->makeCrossTenantCompareFixture(workspaceRole: 'readonly', tenantRole: 'owner');
$this->createPortfolioCompareSubject(
tenant: $fixture['sourceTenant'],
displayName: 'Workspace Gate Policy',
snapshot: ['settings' => [['key' => 'workspace', 'value' => 1]]],
);
$this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
$selection = new CrossTenantCompareSelection(
$fixture['sourceTenant'],
$fixture['targetTenant'],
['deviceConfiguration'],
);
$preview = app(CrossTenantComparePreviewBuilder::class)->build($selection);
$preflight = app(CrossTenantPromotionPreflight::class)->build($preview);
Livewire::withQueryParams([
'source_tenant_id' => (int) $fixture['sourceTenant']->getKey(),
'target_tenant_id' => (int) $fixture['targetTenant']->getKey(),
'policy_type' => ['deviceConfiguration'],
])
->actingAs($fixture['user'])
->test(CrossTenantComparePage::class)
->set('preview', $preview)
->set('preflight', $preflight)
->assertActionVisible('executePromotion')
->assertActionDisabled('executePromotion')
->assertActionExists('executePromotion', fn (Action $action): bool => $action->getTooltip() === 'You need workspace baseline manage access to execute promotion.')
->call('executePromotion')
->assertForbidden();
});
it('does not queue a promotion run when the current preflight is stale for the selected target tenant', function (): void {
$fixture = $this->makeCrossTenantCompareFixture();
$this->createPortfolioCompareSubject(
tenant: $fixture['sourceTenant'],
displayName: 'Stale Policy',
snapshot: ['settings' => [['key' => 'stale', 'value' => 1]]],
);
$staleTarget = Tenant::factory()->create([
'workspace_id' => (int) $fixture['workspace']->getKey(),
'name' => 'Stale Target',
]);
$fixture['user']->tenants()->syncWithoutDetaching([
(int) $staleTarget->getKey() => ['role' => 'owner'],
]);
app(CapabilityResolver::class)->clearCache();
$this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
$staleSelection = new CrossTenantCompareSelection(
$fixture['sourceTenant'],
$staleTarget,
['deviceConfiguration'],
);
$currentSelection = new CrossTenantCompareSelection(
$fixture['sourceTenant'],
$fixture['targetTenant'],
['deviceConfiguration'],
);
$currentPreview = app(CrossTenantComparePreviewBuilder::class)->build($currentSelection);
$stalePreview = app(CrossTenantComparePreviewBuilder::class)->build($staleSelection);
$stalePreflight = app(CrossTenantPromotionPreflight::class)->build($stalePreview);
Livewire::withQueryParams([
'source_tenant_id' => (int) $fixture['sourceTenant']->getKey(),
'target_tenant_id' => (int) $fixture['targetTenant']->getKey(),
'policy_type' => ['deviceConfiguration'],
])
->actingAs($fixture['user'])
->test(CrossTenantComparePage::class)
->set('preview', $currentPreview)
->set('preflight', $stalePreflight)
->call('executePromotion')
->assertNotified('Promotion execution unavailable');
expect(OperationRun::query()->count())->toBe(0);
});
it('does not queue a promotion run when promotion execution is paused by operational control', function (): void {
$fixture = $this->makeCrossTenantCompareFixture();
$this->createPortfolioCompareSubject(
tenant: $fixture['sourceTenant'],
displayName: 'Paused Policy',
snapshot: ['settings' => [['key' => 'paused', 'value' => 1]]],
);
$this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
OperationalControlActivation::factory()->workspaceScoped()->create([
'control_key' => 'promotion.execute',
'workspace_id' => (int) $fixture['workspace']->getKey(),
'reason_text' => 'Paused during promotion review.',
]);
Livewire::withQueryParams([
'source_tenant_id' => (int) $fixture['sourceTenant']->getKey(),
'target_tenant_id' => (int) $fixture['targetTenant']->getKey(),
'policy_type' => ['deviceConfiguration'],
])
->actingAs($fixture['user'])
->test(CrossTenantComparePage::class)
->call('generatePromotionPreflight')
->call('executePromotion')
->assertNotified('Promotion execution paused');
expect(OperationRun::query()->count())->toBe(0);
});
it('returns 404 and does not queue a promotion run when the requested target tenant is outside the actor scope', function (): void {
$fixture = $this->makeCrossTenantCompareFixture();
$hiddenTarget = Tenant::factory()->create([
'workspace_id' => (int) $fixture['workspace']->getKey(),
'name' => 'Hidden Promotion Target',
]);
$session = $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
$this->withSession($session)
->get(CrossTenantComparePage::getUrl(parameters: [
'source_tenant_id' => (int) $fixture['sourceTenant']->getKey(),
'target_tenant_id' => (int) $hiddenTarget->getKey(),
'policy_type' => ['deviceConfiguration'],
], panel: 'admin'))
->assertNotFound();
expect(OperationRun::query()->count())->toBe(0);
});