feat: harden provider connection authority resolution (339)
This commit is contained in:
parent
2fa468bdc7
commit
1313ced181
@ -21,8 +21,8 @@
|
||||
use App\Support\Badges\BadgeRenderer;
|
||||
use App\Support\Filament\TablePaginationProfiles;
|
||||
use App\Support\ManagedEnvironmentLinks;
|
||||
use App\Support\Navigation\WorkspaceHubNavigation;
|
||||
use App\Support\Navigation\WorkspaceHubEnvironmentFilter;
|
||||
use App\Support\Navigation\WorkspaceHubNavigation;
|
||||
use App\Support\OperationRunLinks;
|
||||
use App\Support\OperationRunType;
|
||||
use App\Support\OpsUx\OpsUxBrowserEvents;
|
||||
@ -270,6 +270,12 @@ private static function resolveTenantExternalIdFromLivewireRequest(): ?string
|
||||
// Ignore and fall back to referer.
|
||||
}
|
||||
|
||||
$externalId = static::extractTenantExternalIdFromLivewireSnapshot();
|
||||
|
||||
if (is_string($externalId) && $externalId !== '') {
|
||||
return $externalId;
|
||||
}
|
||||
|
||||
$referer = request()->headers->get('referer');
|
||||
|
||||
if (! is_string($referer) || $referer === '') {
|
||||
@ -279,6 +285,56 @@ private static function resolveTenantExternalIdFromLivewireRequest(): ?string
|
||||
return static::extractTenantExternalIdFromUrl($referer);
|
||||
}
|
||||
|
||||
private static function extractTenantExternalIdFromLivewireSnapshot(): ?string
|
||||
{
|
||||
$snapshotJson = request()->input('components.0.snapshot');
|
||||
|
||||
if (! is_string($snapshotJson) || $snapshotJson === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snapshot = json_decode($snapshotJson, true);
|
||||
|
||||
if (! is_array($snapshot)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$componentName = data_get($snapshot, 'memo.name');
|
||||
|
||||
if (! is_string($componentName) || $componentName !== Pages\CreateProviderConnection::class) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$environmentId = data_get($snapshot, 'data.environmentId');
|
||||
|
||||
if (is_array($environmentId) || filter_var($environmentId, FILTER_VALIDATE_INT) === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
|
||||
|
||||
if (! is_int($workspaceId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$tenant = ManagedEnvironment::query()
|
||||
->whereKey((int) $environmentId)
|
||||
->where('workspace_id', $workspaceId)
|
||||
->first();
|
||||
|
||||
if (! $tenant instanceof ManagedEnvironment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = request()->user();
|
||||
|
||||
if ($user instanceof User && ! $user->canAccessTenant($tenant)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $tenant->slug;
|
||||
}
|
||||
|
||||
private static function extractTenantExternalIdFromUrl(string $url): ?string
|
||||
{
|
||||
$query = parse_url($url, PHP_URL_QUERY);
|
||||
@ -341,14 +397,6 @@ private static function applyMembershipScope(Builder $query): Builder
|
||||
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
|
||||
$user = auth()->user();
|
||||
|
||||
if (! is_int($workspaceId)) {
|
||||
$tenant = static::resolveTenantContextForCurrentPanel();
|
||||
|
||||
if ($tenant instanceof ManagedEnvironment) {
|
||||
$workspaceId = (int) $tenant->workspace_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_int($workspaceId) || ! $user instanceof User) {
|
||||
return $query->whereRaw('1 = 0');
|
||||
}
|
||||
|
||||
@ -9,19 +9,34 @@
|
||||
use App\Support\Providers\ProviderConnectionType;
|
||||
use App\Support\Providers\ProviderConsentStatus;
|
||||
use App\Support\Providers\ProviderReasonCodes;
|
||||
use App\Support\Providers\ProviderVerificationStatus;
|
||||
use App\Support\Providers\TargetScope\ProviderConnectionTargetScopeDescriptor;
|
||||
use App\Support\Providers\TargetScope\ProviderConnectionTargetScopeNormalizer;
|
||||
use App\Support\Providers\ProviderVerificationStatus;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Livewire\Attributes\Locked;
|
||||
|
||||
class CreateProviderConnection extends CreateRecord
|
||||
{
|
||||
protected static string $resource = ProviderConnectionResource::class;
|
||||
|
||||
#[Locked]
|
||||
public ?int $environmentId = null;
|
||||
|
||||
protected bool $shouldMakeDefault = false;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$environmentId = request()->query('environment_id');
|
||||
|
||||
if (! is_array($environmentId) && filter_var($environmentId, FILTER_VALIDATE_INT) !== false) {
|
||||
$this->environmentId = (int) $environmentId;
|
||||
}
|
||||
|
||||
parent::mount();
|
||||
}
|
||||
|
||||
protected function mutateFormDataBeforeCreate(array $data): array
|
||||
{
|
||||
$tenant = $this->currentTenant();
|
||||
|
||||
@ -9,10 +9,10 @@
|
||||
use App\Services\Auth\ManagedEnvironmentAccessScopeResolver;
|
||||
use App\Support\Auth\Capabilities;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Livewire\Livewire as LivewireFacade;
|
||||
|
||||
class ProviderConnectionPolicy
|
||||
{
|
||||
@ -210,14 +210,6 @@ private function currentWorkspace(User $user): ?Workspace
|
||||
{
|
||||
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
|
||||
|
||||
if (! is_int($workspaceId)) {
|
||||
$filamentTenant = Filament::getTenant();
|
||||
|
||||
if ($filamentTenant instanceof ManagedEnvironment) {
|
||||
$workspaceId = (int) $filamentTenant->workspace_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_int($workspaceId)) {
|
||||
return null;
|
||||
}
|
||||
@ -237,33 +229,117 @@ private function currentWorkspace(User $user): ?Workspace
|
||||
|
||||
private function resolveCreateTenant(Workspace $workspace): ?ManagedEnvironment
|
||||
{
|
||||
$requestedEnvironmentId = request()->query('environment_id');
|
||||
|
||||
if (! is_numeric($requestedEnvironmentId)) {
|
||||
$lastEnvironmentId = app(WorkspaceContext::class)->lastEnvironmentId(request());
|
||||
|
||||
if (is_int($lastEnvironmentId)) {
|
||||
return ManagedEnvironment::query()
|
||||
->whereKey($lastEnvironmentId)
|
||||
->where('workspace_id', (int) $workspace->getKey())
|
||||
->first();
|
||||
}
|
||||
|
||||
$filamentTenant = Filament::getTenant();
|
||||
|
||||
if ($filamentTenant instanceof ManagedEnvironment && (int) $filamentTenant->workspace_id === (int) $workspace->getKey()) {
|
||||
return $filamentTenant;
|
||||
}
|
||||
$requestedEnvironmentId = $this->requestedEnvironmentId();
|
||||
|
||||
if ($requestedEnvironmentId === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ManagedEnvironment::query()
|
||||
->whereKey((int) $requestedEnvironmentId)
|
||||
->whereKey($requestedEnvironmentId)
|
||||
->where('workspace_id', (int) $workspace->getKey())
|
||||
->first();
|
||||
}
|
||||
|
||||
private function requestedEnvironmentId(): ?int
|
||||
{
|
||||
$environmentId = request()->query('environment_id');
|
||||
|
||||
if (is_numeric($environmentId)) {
|
||||
return (int) $environmentId;
|
||||
}
|
||||
|
||||
if (is_array($environmentId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$resolved = $this->extractEnvironmentIdFromLivewireSnapshot();
|
||||
|
||||
if ($resolved !== null) {
|
||||
return $resolved;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// Ignore and fall back to originalUrl() parsing.
|
||||
}
|
||||
|
||||
try {
|
||||
$url = LivewireFacade::originalUrl();
|
||||
|
||||
$resolved = $this->extractEnvironmentIdFromUrl($url);
|
||||
|
||||
if ($resolved !== null) {
|
||||
return $resolved;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// Ignore and fall back to referer header.
|
||||
}
|
||||
|
||||
$referer = request()->headers->get('referer');
|
||||
|
||||
if (! is_string($referer) || $referer === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->extractEnvironmentIdFromUrl($referer);
|
||||
}
|
||||
|
||||
private function extractEnvironmentIdFromLivewireSnapshot(): ?int
|
||||
{
|
||||
if (! request()->headers->has('x-livewire') && ! request()->headers->has('x-livewire-navigate')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snapshotJson = request()->input('components.0.snapshot');
|
||||
|
||||
if (! is_string($snapshotJson) || $snapshotJson === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$snapshot = json_decode($snapshotJson, true);
|
||||
|
||||
if (! is_array($snapshot)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$componentName = data_get($snapshot, 'memo.name');
|
||||
|
||||
if (! is_string($componentName) || $componentName !== \App\Filament\Resources\ProviderConnectionResource\Pages\CreateProviderConnection::class) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$environmentId = data_get($snapshot, 'data.environmentId');
|
||||
|
||||
if (is_array($environmentId) || filter_var($environmentId, FILTER_VALIDATE_INT) === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int) $environmentId;
|
||||
}
|
||||
|
||||
private function extractEnvironmentIdFromUrl(?string $url): ?int
|
||||
{
|
||||
if (! is_string($url) || $url === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$query = parse_url($url, PHP_URL_QUERY);
|
||||
|
||||
if (! is_string($query) || $query === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
parse_str($query, $params);
|
||||
|
||||
$environmentId = $params['environment_id'] ?? null;
|
||||
|
||||
if (is_array($environmentId) || filter_var($environmentId, FILTER_VALIDATE_INT) === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int) $environmentId;
|
||||
}
|
||||
|
||||
private function tenantForConnection(ProviderConnection $connection): ?ManagedEnvironment
|
||||
{
|
||||
if ($connection->relationLoaded('tenant') && $connection->tenant instanceof ManagedEnvironment) {
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
|
||||
use App\Filament\Resources\ProviderConnectionResource\Pages\CreateProviderConnection;
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\ProviderConnection;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\ProviderConnection;
|
||||
use App\Models\User;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
@ -76,6 +76,9 @@
|
||||
Filament::setTenant($tenant, true);
|
||||
|
||||
Livewire::actingAs($user)
|
||||
->withQueryParams([
|
||||
'environment_id' => (int) $tenant->getKey(),
|
||||
])
|
||||
->test(CreateProviderConnection::class)
|
||||
->fillForm([
|
||||
'display_name' => 'Audit target scope connection',
|
||||
|
||||
@ -15,7 +15,11 @@
|
||||
$tenant->makeCurrent();
|
||||
Filament::setTenant($tenant, true);
|
||||
|
||||
Livewire::test(CreateProviderConnection::class)
|
||||
$component = Livewire::withQueryParams([
|
||||
'environment_id' => (int) $tenant->getKey(),
|
||||
])->test(CreateProviderConnection::class);
|
||||
|
||||
$component
|
||||
->fillForm([
|
||||
'display_name' => 'MVP Scope Connection',
|
||||
'entra_tenant_id' => (string) fake()->uuid(),
|
||||
|
||||
@ -81,6 +81,9 @@
|
||||
Filament::setTenant($tenant, true);
|
||||
|
||||
Livewire::actingAs($user)
|
||||
->withQueryParams([
|
||||
'environment_id' => (int) $tenant->getKey(),
|
||||
])
|
||||
->test(CreateProviderConnection::class)
|
||||
->fillForm([
|
||||
'display_name' => 'Missing target scope',
|
||||
|
||||
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\Workspace;
|
||||
use App\Policies\ProviderConnectionPolicy;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
it('ScopeHardening requires explicit environment_id for ProviderConnectionPolicy::create even if a remembered environment exists', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-env-remembered',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
$this->actingAs($user);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $environment->workspace_id);
|
||||
session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
|
||||
(string) $environment->workspace_id => (int) $environment->getKey(),
|
||||
]);
|
||||
|
||||
/** @var ProviderConnectionPolicy $policy */
|
||||
$policy = app(ProviderConnectionPolicy::class);
|
||||
|
||||
$result = $policy->create($user);
|
||||
|
||||
expect($result)->toBeInstanceOf(Response::class);
|
||||
expect($result->denied())->toBeTrue();
|
||||
});
|
||||
|
||||
it('ScopeHardening requires explicit environment_id for ProviderConnectionPolicy::create even if Filament tenant is set', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-env-filament',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
Filament::setTenant($environment, true);
|
||||
|
||||
$this->actingAs($user);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $environment->workspace_id);
|
||||
|
||||
/** @var ProviderConnectionPolicy $policy */
|
||||
$policy = app(ProviderConnectionPolicy::class);
|
||||
|
||||
$result = $policy->create($user);
|
||||
|
||||
expect($result)->toBeInstanceOf(Response::class);
|
||||
expect($result->denied())->toBeTrue();
|
||||
});
|
||||
|
||||
it('ScopeHardening ignores legacy query aliases for ProviderConnectionPolicy::create authority', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-env-alias',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
$request = Request::create('/admin/provider-connections/create', 'GET', [
|
||||
'managed_environment_id' => (int) $environment->getKey(),
|
||||
]);
|
||||
|
||||
$this->app->instance('request', $request);
|
||||
|
||||
$this->actingAs($user);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $environment->workspace_id);
|
||||
session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
|
||||
(string) $environment->workspace_id => (int) $environment->getKey(),
|
||||
]);
|
||||
|
||||
/** @var ProviderConnectionPolicy $policy */
|
||||
$policy = app(ProviderConnectionPolicy::class);
|
||||
|
||||
$result = $policy->create($user);
|
||||
|
||||
expect($result)->toBeInstanceOf(Response::class);
|
||||
expect($result->denied())->toBeTrue();
|
||||
});
|
||||
|
||||
it('ScopeHardening denies ProviderConnectionPolicy::create for environment_id that belongs to another workspace', function (): void {
|
||||
$environmentA = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-env-a',
|
||||
]);
|
||||
[$user, $environmentA] = createUserWithTenant(tenant: $environmentA, role: 'owner');
|
||||
|
||||
$workspaceB = Workspace::factory()->create();
|
||||
$environmentB = ManagedEnvironment::factory()->active()->create([
|
||||
'workspace_id' => (int) $workspaceB->getKey(),
|
||||
'external_id' => 'spec339-scopehardening-env-b',
|
||||
]);
|
||||
|
||||
$request = Request::create('/admin/provider-connections/create', 'GET', [
|
||||
'environment_id' => (int) $environmentB->getKey(),
|
||||
]);
|
||||
|
||||
$this->app->instance('request', $request);
|
||||
|
||||
$this->actingAs($user);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $environmentA->workspace_id);
|
||||
|
||||
/** @var ProviderConnectionPolicy $policy */
|
||||
$policy = app(ProviderConnectionPolicy::class);
|
||||
|
||||
$result = $policy->create($user);
|
||||
|
||||
expect($result)->toBeInstanceOf(Response::class);
|
||||
expect($result->denied())->toBeTrue();
|
||||
});
|
||||
|
||||
it('ScopeHardening returns 403 (not 404) for the create page when environment_id is missing (UI entry behavior)', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-create-page',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $environment->workspace_id,
|
||||
])
|
||||
->get('/admin/provider-connections/create')
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
it('ScopeHardening returns 404 for the create page when environment_id belongs to another workspace (UI entry behavior)', function (): void {
|
||||
$environmentA = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-create-page-a',
|
||||
]);
|
||||
[$user, $environmentA] = createUserWithTenant(tenant: $environmentA, role: 'owner');
|
||||
|
||||
$workspaceB = Workspace::factory()->create();
|
||||
$environmentB = ManagedEnvironment::factory()->active()->create([
|
||||
'workspace_id' => (int) $workspaceB->getKey(),
|
||||
'external_id' => 'spec339-scopehardening-create-page-b',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $environmentA->workspace_id,
|
||||
])
|
||||
->get('/admin/provider-connections/create?environment_id='.(int) $environmentB->getKey())
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
it('ScopeHardening returns 403 (not 404) for the create page when legacy alias is provided (UI entry behavior)', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-create-page-alias',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $environment->workspace_id,
|
||||
])
|
||||
->get('/admin/provider-connections/create?managed_environment_id='.(int) $environment->getKey())
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
it('ScopeHardening returns 403 (not 404) for the create page even if a remembered environment exists (UI entry behavior)', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-create-page-remembered',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $environment->workspace_id,
|
||||
WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [
|
||||
(string) $environment->workspace_id => (int) $environment->getKey(),
|
||||
],
|
||||
])
|
||||
->get('/admin/provider-connections/create')
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
it('ScopeHardening returns 403 (not 404) for the create page even if Filament tenant is set (UI entry behavior)', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-create-page-filament',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
Filament::setTenant($environment, true);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $environment->workspace_id,
|
||||
])
|
||||
->get('/admin/provider-connections/create')
|
||||
->assertForbidden();
|
||||
});
|
||||
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\User;
|
||||
use App\Policies\ProviderConnectionPolicy;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Filament\Facades\Filament;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
|
||||
it('ScopeHardening does not derive workspace authority from Filament tenant in ProviderConnectionPolicy', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-policy-env',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
expect($user)->toBeInstanceOf(User::class);
|
||||
|
||||
session()->forget(WorkspaceContext::SESSION_KEY);
|
||||
|
||||
Filament::setTenant($environment, true);
|
||||
|
||||
/** @var ProviderConnectionPolicy $policy */
|
||||
$policy = app(ProviderConnectionPolicy::class);
|
||||
|
||||
$result = $policy->viewAny($user);
|
||||
|
||||
expect($result)->toBeInstanceOf(Response::class);
|
||||
expect($result->denied())->toBeTrue();
|
||||
});
|
||||
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Filament\Resources\ProviderConnectionResource\Pages\ListProviderConnections;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\ProviderConnection;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Filament\Facades\Filament;
|
||||
use Livewire\Livewire;
|
||||
|
||||
it('ScopeHardening does not infer provider connection list workspace from Filament tenant when no workspace is selected', function (): void {
|
||||
$environment = ManagedEnvironment::factory()->active()->create([
|
||||
'external_id' => 'spec339-scopehardening-resource-env',
|
||||
]);
|
||||
|
||||
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner');
|
||||
|
||||
$connection = ProviderConnection::factory()->create([
|
||||
'workspace_id' => (int) $environment->workspace_id,
|
||||
'managed_environment_id' => (int) $environment->getKey(),
|
||||
'display_name' => 'Spec339 ScopeHardening Connection',
|
||||
'provider' => 'microsoft',
|
||||
]);
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
session()->forget(WorkspaceContext::SESSION_KEY);
|
||||
|
||||
Filament::setTenant($environment, true);
|
||||
|
||||
$component = Livewire::test(ListProviderConnections::class);
|
||||
|
||||
expect($component->instance())->toBeNull();
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user