## Summary - consolidate internal platform naming from `Tenant` to `Environment` / `ManagedEnvironment` across models, controllers, services, and Filament resources - rename environment-scoped UI surfaces such as dashboards, chooser flows, navigation, and related widgets to match the updated environment-first domain language - align middleware, onboarding/review lifecycle services, jobs, and route/context controllers with the new environment-scoped architecture ## Validation - not rerun as part of this commit/push/PR request ## Notes - branch is 1 commit ahead of `platform-dev` - main commit: `refactor: consolidate internal tenant model naming` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #355
202 lines
8.4 KiB
PHP
202 lines
8.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Pages\CrossEnvironmentComparePage;
|
|
use App\Models\OperationRun;
|
|
use App\Models\OperationalControlActivation;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\User;
|
|
use App\Services\Auth\CapabilityResolver;
|
|
use App\Support\Auth\Capabilities;
|
|
use App\Support\PortfolioCompare\CrossEnvironmentComparePreviewBuilder;
|
|
use App\Support\PortfolioCompare\CrossEnvironmentCompareSelection;
|
|
use App\Support\PortfolioCompare\CrossEnvironmentPromotionPreflight;
|
|
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->makeCrossEnvironmentCompareFixture(workspaceRole: 'owner', tenantRole: 'readonly');
|
|
|
|
$this->createPortfolioCompareSubject(
|
|
tenant: $fixture['sourceEnvironment'],
|
|
displayName: 'Compare Only Policy',
|
|
snapshot: ['settings' => [['key' => 'readonly', 'value' => 1]]],
|
|
);
|
|
|
|
$this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
|
|
|
|
$query = [
|
|
'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
|
|
'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
|
|
'policy_type' => ['deviceConfiguration'],
|
|
];
|
|
|
|
$component = Livewire::withQueryParams($query)
|
|
->actingAs($fixture['user'])
|
|
->test(CrossEnvironmentComparePage::class)
|
|
->call('generatePromotionPreflight');
|
|
|
|
$realResolver = app(CapabilityResolver::class);
|
|
$resolver = \Mockery::mock(CapabilityResolver::class);
|
|
$resolver->shouldReceive('isMember')
|
|
->andReturnUsing(fn (User $user, ManagedEnvironment $tenant): bool => $realResolver->isMember($user, $tenant));
|
|
$resolver->shouldReceive('can')
|
|
->andReturnUsing(function (User $user, ManagedEnvironment $tenant, string $capability) use ($fixture, $realResolver): bool {
|
|
if ($tenant->is($fixture['targetEnvironment']) && $capability === Capabilities::TENANT_MANAGE) {
|
|
return false;
|
|
}
|
|
|
|
return $realResolver->can($user, $tenant, $capability);
|
|
});
|
|
|
|
app()->instance(CapabilityResolver::class, $resolver);
|
|
|
|
$component
|
|
->assertActionVisible('executePromotion')
|
|
->assertActionDisabled('executePromotion')
|
|
->assertActionExists('executePromotion', fn (Action $action): bool => $action->getTooltip() === 'You need target environment 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->makeCrossEnvironmentCompareFixture(workspaceRole: 'readonly', tenantRole: 'owner');
|
|
|
|
$this->createPortfolioCompareSubject(
|
|
tenant: $fixture['sourceEnvironment'],
|
|
displayName: 'Workspace Gate Policy',
|
|
snapshot: ['settings' => [['key' => 'workspace', 'value' => 1]]],
|
|
);
|
|
|
|
$this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
|
|
|
|
$selection = new CrossEnvironmentCompareSelection(
|
|
$fixture['sourceEnvironment'],
|
|
$fixture['targetEnvironment'],
|
|
['deviceConfiguration'],
|
|
);
|
|
$preview = app(CrossEnvironmentComparePreviewBuilder::class)->build($selection);
|
|
$preflight = app(CrossEnvironmentPromotionPreflight::class)->build($preview);
|
|
|
|
Livewire::withQueryParams([
|
|
'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
|
|
'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
|
|
'policy_type' => ['deviceConfiguration'],
|
|
])
|
|
->actingAs($fixture['user'])
|
|
->test(CrossEnvironmentComparePage::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 environment', function (): void {
|
|
$fixture = $this->makeCrossEnvironmentCompareFixture();
|
|
|
|
$this->createPortfolioCompareSubject(
|
|
tenant: $fixture['sourceEnvironment'],
|
|
displayName: 'Stale Policy',
|
|
snapshot: ['settings' => [['key' => 'stale', 'value' => 1]]],
|
|
);
|
|
|
|
$staleTarget = ManagedEnvironment::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 CrossEnvironmentCompareSelection(
|
|
$fixture['sourceEnvironment'],
|
|
$staleTarget,
|
|
['deviceConfiguration'],
|
|
);
|
|
$currentSelection = new CrossEnvironmentCompareSelection(
|
|
$fixture['sourceEnvironment'],
|
|
$fixture['targetEnvironment'],
|
|
['deviceConfiguration'],
|
|
);
|
|
$currentPreview = app(CrossEnvironmentComparePreviewBuilder::class)->build($currentSelection);
|
|
$stalePreview = app(CrossEnvironmentComparePreviewBuilder::class)->build($staleSelection);
|
|
$stalePreflight = app(CrossEnvironmentPromotionPreflight::class)->build($stalePreview);
|
|
|
|
Livewire::withQueryParams([
|
|
'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
|
|
'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
|
|
'policy_type' => ['deviceConfiguration'],
|
|
])
|
|
->actingAs($fixture['user'])
|
|
->test(CrossEnvironmentComparePage::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->makeCrossEnvironmentCompareFixture();
|
|
|
|
$this->createPortfolioCompareSubject(
|
|
tenant: $fixture['sourceEnvironment'],
|
|
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_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
|
|
'target_environment_id' => (int) $fixture['targetEnvironment']->getKey(),
|
|
'policy_type' => ['deviceConfiguration'],
|
|
])
|
|
->actingAs($fixture['user'])
|
|
->test(CrossEnvironmentComparePage::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 environment is outside the actor scope', function (): void {
|
|
$fixture = $this->makeCrossEnvironmentCompareFixture();
|
|
$hiddenTarget = ManagedEnvironment::factory()->create([
|
|
'workspace_id' => (int) $fixture['workspace']->getKey(),
|
|
'name' => 'Hidden Promotion Target',
|
|
]);
|
|
|
|
$session = $this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
|
|
|
|
$this->withSession($session)
|
|
->get(CrossEnvironmentComparePage::getUrl(parameters: [
|
|
'source_environment_id' => (int) $fixture['sourceEnvironment']->getKey(),
|
|
'target_environment_id' => (int) $hiddenTarget->getKey(),
|
|
'policy_type' => ['deviceConfiguration'],
|
|
], panel: 'admin'))
|
|
->assertNotFound();
|
|
|
|
expect(OperationRun::query()->count())->toBe(0);
|
|
});
|