## Summary - move Baseline Compare onto the canonical workspace plus environment owned route instead of workspace-style access - remove legacy environment query and remembered-context fallback paths from the affected Baseline Compare entry points and shell handling - update related navigation, support links, and regression coverage for admin surface scope and managed environment route contracts - add Spec 319 artifacts for the environment-owned surface routing and shell context contract ## Testing - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/BaselineCompareEnvironmentRouteContractTest.php tests/Feature/Filament/BaselineCompareLandingAdminTenantParityTest.php tests/Feature/Filament/BaselineCompareLandingDuplicateNamesBannerTest.php tests/Feature/Filament/BaselineCompareLandingRbacLabelsTest.php tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php tests/Feature/Filament/BaselineCompareLandingWhyNoFindingsTest.php tests/Feature/Filament/PanelNavigationSegregationTest.php tests/Feature/Guards/ManagedEnvironmentCanonicalRouteContractTest.php tests/Feature/Navigation/WorkspaceHubRegistryTest.php tests/Feature/Rbac/BaselineCompareMatrixAuthorizationTest.php tests/Feature/Rbac/DriftLandingUiEnforcementTest.php tests/Unit/Tenants/AdminSurfaceScopeTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #374
125 lines
4.7 KiB
PHP
125 lines
4.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Pages\BaselineCompareLanding;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Support\EnvironmentDashboard\EnvironmentDashboardSummaryBuilder;
|
|
use App\Support\ManagedEnvironmentLinks;
|
|
use App\Support\Workspaces\WorkspaceContext;
|
|
use Filament\Facades\Filament;
|
|
use Illuminate\Support\Arr;
|
|
|
|
function baselineCompareRouteContractForbiddenQueryKeys(): array
|
|
{
|
|
return [
|
|
'environment_id',
|
|
'tenant',
|
|
'tenant_id',
|
|
'managed_environment_id',
|
|
'environment',
|
|
'tenant_scope',
|
|
'tableFilters',
|
|
];
|
|
}
|
|
|
|
it('generates a canonical environment-owned baseline compare URL without legacy scope query keys', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
|
|
$url = ManagedEnvironmentLinks::baselineCompareUrl($tenant, [
|
|
'environment_id' => (int) $tenant->getKey(),
|
|
'tenant' => (string) $tenant->external_id,
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'environment' => 'legacy-query-value',
|
|
'tenant_scope' => 'selected',
|
|
'tableFilters' => ['managed_environment_id' => ['value' => (int) $tenant->getKey()]],
|
|
'baseline_profile_id' => 42,
|
|
'subject_key' => 'wifi-corp-profile',
|
|
]);
|
|
|
|
parse_str((string) parse_url($url, PHP_URL_QUERY), $query);
|
|
|
|
expect((string) parse_url($url, PHP_URL_PATH))
|
|
->toBe(sprintf(
|
|
'/admin/workspaces/%s/environments/%s/baseline-compare',
|
|
$tenant->workspace()->firstOrFail()->slug,
|
|
$tenant->getRouteKey(),
|
|
))
|
|
->and(array_keys($query))->not->toContain(...baselineCompareRouteContractForbiddenQueryKeys())
|
|
->and($query)->toMatchArray([
|
|
'baseline_profile_id' => '42',
|
|
'subject_key' => 'wifi-corp-profile',
|
|
]);
|
|
});
|
|
|
|
it('renders baseline compare from the route-owned environment context', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user)
|
|
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
|
->get(ManagedEnvironmentLinks::baselineCompareUrl($tenant))
|
|
->assertOk()
|
|
->assertSeeText('Baseline Compare')
|
|
->assertSeeText($tenant->workspace()->firstOrFail()->name)
|
|
->assertSeeText($tenant->name)
|
|
->assertSeeText('This environment has no baseline assignment');
|
|
});
|
|
|
|
it('rejects old workspace-style baseline compare URLs and remembered environment fallback', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
Filament::setTenant(null, true);
|
|
|
|
$this->actingAs($user)
|
|
->withSession([
|
|
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
|
WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [
|
|
(string) $tenant->workspace_id => (int) $tenant->getKey(),
|
|
],
|
|
])
|
|
->get('/admin/baseline-compare-landing?environment_id='.(int) $tenant->getKey())
|
|
->assertNotFound();
|
|
|
|
expect(BaselineCompareLanding::canAccess())->toBeFalse();
|
|
});
|
|
|
|
it('rejects baseline compare when the workspace route and environment route disagree', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
$foreignTenant = ManagedEnvironment::factory()->active()->create(['name' => 'Foreign Environment']);
|
|
createUserWithTenant(tenant: $foreignTenant, user: $user, role: 'owner');
|
|
|
|
$url = sprintf(
|
|
'/admin/workspaces/%s/environments/%s/baseline-compare',
|
|
$tenant->workspace()->firstOrFail()->slug,
|
|
$foreignTenant->getRouteKey(),
|
|
);
|
|
|
|
$this->actingAs($user)
|
|
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
|
->get($url)
|
|
->assertNotFound();
|
|
});
|
|
|
|
it('emits the environment-owned route from the environment dashboard baseline compare action', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$summary = app(EnvironmentDashboardSummaryBuilder::class)
|
|
->build($tenant, $user)
|
|
->toArray();
|
|
|
|
$baselineCompareStatus = Arr::first(
|
|
$summary['governanceStatus'],
|
|
static fn (array $status): bool => ($status['key'] ?? null) === 'baseline_compare',
|
|
);
|
|
|
|
$url = is_array($baselineCompareStatus) ? ($baselineCompareStatus['actionUrl'] ?? null) : null;
|
|
parse_str((string) parse_url((string) $url, PHP_URL_QUERY), $query);
|
|
|
|
expect($url)->toBe(ManagedEnvironmentLinks::baselineCompareUrl($tenant))
|
|
->and((string) parse_url((string) $url, PHP_URL_PATH))->toEndWith('/environments/'.$tenant->getRouteKey().'/baseline-compare')
|
|
->and(array_keys($query))->not->toContain(...baselineCompareRouteContractForbiddenQueryKeys());
|
|
});
|