diff --git a/tests/Feature/ApplicationHealthCheckApiTest.php b/tests/Feature/Api/ApplicationHealthCheckApiTest.php similarity index 100% rename from tests/Feature/ApplicationHealthCheckApiTest.php rename to tests/Feature/Api/ApplicationHealthCheckApiTest.php diff --git a/tests/Feature/CloudProviderTokenApiTest.php b/tests/Feature/Api/CloudProviderTokenApiTest.php similarity index 100% rename from tests/Feature/CloudProviderTokenApiTest.php rename to tests/Feature/Api/CloudProviderTokenApiTest.php diff --git a/tests/Feature/DatabaseBackupCreationApiTest.php b/tests/Feature/Api/DatabaseBackupCreationApiTest.php similarity index 100% rename from tests/Feature/DatabaseBackupCreationApiTest.php rename to tests/Feature/Api/DatabaseBackupCreationApiTest.php diff --git a/tests/Feature/DeploymentCancellationApiTest.php b/tests/Feature/Api/DeploymentCancellationApiTest.php similarity index 100% rename from tests/Feature/DeploymentCancellationApiTest.php rename to tests/Feature/Api/DeploymentCancellationApiTest.php diff --git a/tests/Feature/DomainsByServerApiTest.php b/tests/Feature/Api/DomainsByServerApiTest.php similarity index 93% rename from tests/Feature/DomainsByServerApiTest.php rename to tests/Feature/Api/DomainsByServerApiTest.php index 1e799bec5..8c675c202 100644 --- a/tests/Feature/DomainsByServerApiTest.php +++ b/tests/Feature/Api/DomainsByServerApiTest.php @@ -25,7 +25,7 @@ $this->environment = Environment::factory()->create(['project_id' => $this->project->id]); }); -function authHeaders(): array +function domainApiAuthHeaders(): array { return [ 'Authorization' => 'Bearer '.test()->bearerToken, @@ -40,7 +40,7 @@ function authHeaders(): array 'destination_type' => $this->destination->getMorphClass(), ]); - $response = $this->withHeaders(authHeaders()) + $response = $this->withHeaders(domainApiAuthHeaders()) ->getJson("/api/v1/servers/{$this->server->uuid}/domains?uuid={$application->uuid}"); $response->assertOk(); @@ -64,7 +64,7 @@ function authHeaders(): array 'destination_type' => $otherDestination->getMorphClass(), ]); - $response = $this->withHeaders(authHeaders()) + $response = $this->withHeaders(domainApiAuthHeaders()) ->getJson("/api/v1/servers/{$this->server->uuid}/domains?uuid={$otherApplication->uuid}"); $response->assertNotFound(); @@ -72,7 +72,7 @@ function authHeaders(): array }); test('returns 404 for nonexistent application uuid', function () { - $response = $this->withHeaders(authHeaders()) + $response = $this->withHeaders(domainApiAuthHeaders()) ->getJson("/api/v1/servers/{$this->server->uuid}/domains?uuid=nonexistent-uuid"); $response->assertNotFound(); diff --git a/tests/Feature/EnvironmentVariableUpdateApiTest.php b/tests/Feature/Api/EnvironmentVariableUpdateApiTest.php similarity index 100% rename from tests/Feature/EnvironmentVariableUpdateApiTest.php rename to tests/Feature/Api/EnvironmentVariableUpdateApiTest.php diff --git a/tests/Feature/GithubAppsListApiTest.php b/tests/Feature/Api/GithubAppsListApiTest.php similarity index 100% rename from tests/Feature/GithubAppsListApiTest.php rename to tests/Feature/Api/GithubAppsListApiTest.php diff --git a/tests/Feature/HetznerApiTest.php b/tests/Feature/Api/HetznerApiTest.php similarity index 100% rename from tests/Feature/HetznerApiTest.php rename to tests/Feature/Api/HetznerApiTest.php diff --git a/tests/Feature/ScheduledTaskApiTest.php b/tests/Feature/Api/ScheduledTaskApiTest.php similarity index 100% rename from tests/Feature/ScheduledTaskApiTest.php rename to tests/Feature/Api/ScheduledTaskApiTest.php diff --git a/tests/Feature/ApplicationBuildpackCleanupTest.php b/tests/Feature/Application/ApplicationBuildpackCleanupTest.php similarity index 100% rename from tests/Feature/ApplicationBuildpackCleanupTest.php rename to tests/Feature/Application/ApplicationBuildpackCleanupTest.php diff --git a/tests/Feature/BuildpackSwitchCleanupTest.php b/tests/Feature/Application/BuildpackSwitchCleanupTest.php similarity index 100% rename from tests/Feature/BuildpackSwitchCleanupTest.php rename to tests/Feature/Application/BuildpackSwitchCleanupTest.php diff --git a/tests/Feature/GithubSourceChangeTest.php b/tests/Feature/Application/GithubSourceChangeTest.php similarity index 100% rename from tests/Feature/GithubSourceChangeTest.php rename to tests/Feature/Application/GithubSourceChangeTest.php diff --git a/tests/Feature/GithubSourceCreateTest.php b/tests/Feature/Application/GithubSourceCreateTest.php similarity index 100% rename from tests/Feature/GithubSourceCreateTest.php rename to tests/Feature/Application/GithubSourceCreateTest.php diff --git a/tests/Feature/DeletesUserSessionsTest.php b/tests/Feature/Auth/DeletesUserSessionsTest.php similarity index 100% rename from tests/Feature/DeletesUserSessionsTest.php rename to tests/Feature/Auth/DeletesUserSessionsTest.php diff --git a/tests/Feature/LoginRateLimitIPTest.php b/tests/Feature/Auth/LoginRateLimitIPTest.php similarity index 100% rename from tests/Feature/LoginRateLimitIPTest.php rename to tests/Feature/Auth/LoginRateLimitIPTest.php diff --git a/tests/Feature/TwoFactorChallengeAccessTest.php b/tests/Feature/Auth/TwoFactorChallengeAccessTest.php similarity index 100% rename from tests/Feature/TwoFactorChallengeAccessTest.php rename to tests/Feature/Auth/TwoFactorChallengeAccessTest.php diff --git a/tests/Feature/ApiAuthorizationTest.php b/tests/Feature/Authorization/ApiAuthorizationTest.php similarity index 100% rename from tests/Feature/ApiAuthorizationTest.php rename to tests/Feature/Authorization/ApiAuthorizationTest.php diff --git a/tests/Feature/ApiTokenPermissionTest.php b/tests/Feature/Authorization/ApiTokenPermissionTest.php similarity index 100% rename from tests/Feature/ApiTokenPermissionTest.php rename to tests/Feature/Authorization/ApiTokenPermissionTest.php diff --git a/tests/Feature/ApplicationConfigAuthorizationTest.php b/tests/Feature/Authorization/ApplicationConfigAuthorizationTest.php similarity index 100% rename from tests/Feature/ApplicationConfigAuthorizationTest.php rename to tests/Feature/Authorization/ApplicationConfigAuthorizationTest.php diff --git a/tests/Feature/CloudProviderAuthorizationTest.php b/tests/Feature/Authorization/CloudProviderAuthorizationTest.php similarity index 100% rename from tests/Feature/CloudProviderAuthorizationTest.php rename to tests/Feature/Authorization/CloudProviderAuthorizationTest.php diff --git a/tests/Feature/DashboardAuthorizationTest.php b/tests/Feature/Authorization/DashboardAuthorizationTest.php similarity index 100% rename from tests/Feature/DashboardAuthorizationTest.php rename to tests/Feature/Authorization/DashboardAuthorizationTest.php diff --git a/tests/Feature/DatabaseConfigAuthorizationTest.php b/tests/Feature/Authorization/DatabaseConfigAuthorizationTest.php similarity index 100% rename from tests/Feature/DatabaseConfigAuthorizationTest.php rename to tests/Feature/Authorization/DatabaseConfigAuthorizationTest.php diff --git a/tests/Feature/DestinationOwnershipTest.php b/tests/Feature/Authorization/DestinationOwnershipTest.php similarity index 100% rename from tests/Feature/DestinationOwnershipTest.php rename to tests/Feature/Authorization/DestinationOwnershipTest.php diff --git a/tests/Feature/NavbarDeleteTeamAuthorizationTest.php b/tests/Feature/Authorization/NavbarDeleteTeamAuthorizationTest.php similarity index 100% rename from tests/Feature/NavbarDeleteTeamAuthorizationTest.php rename to tests/Feature/Authorization/NavbarDeleteTeamAuthorizationTest.php diff --git a/tests/Feature/NotificationAuthorizationTest.php b/tests/Feature/Authorization/NotificationAuthorizationTest.php similarity index 100% rename from tests/Feature/NotificationAuthorizationTest.php rename to tests/Feature/Authorization/NotificationAuthorizationTest.php diff --git a/tests/Feature/ProjectEnvironmentAuthorizationTest.php b/tests/Feature/Authorization/ProjectEnvironmentAuthorizationTest.php similarity index 100% rename from tests/Feature/ProjectEnvironmentAuthorizationTest.php rename to tests/Feature/Authorization/ProjectEnvironmentAuthorizationTest.php diff --git a/tests/Feature/ResourceHeadingAuthorizationTest.php b/tests/Feature/Authorization/ResourceHeadingAuthorizationTest.php similarity index 100% rename from tests/Feature/ResourceHeadingAuthorizationTest.php rename to tests/Feature/Authorization/ResourceHeadingAuthorizationTest.php diff --git a/tests/Feature/ResourceOperationsCrossTenantTest.php b/tests/Feature/Authorization/ResourceOperationsCrossTenantTest.php similarity index 100% rename from tests/Feature/ResourceOperationsCrossTenantTest.php rename to tests/Feature/Authorization/ResourceOperationsCrossTenantTest.php diff --git a/tests/Feature/SecurityPageAuthorizationTest.php b/tests/Feature/Authorization/SecurityPageAuthorizationTest.php similarity index 100% rename from tests/Feature/SecurityPageAuthorizationTest.php rename to tests/Feature/Authorization/SecurityPageAuthorizationTest.php diff --git a/tests/Feature/ServerAuthorizationTest.php b/tests/Feature/Authorization/ServerAuthorizationTest.php similarity index 100% rename from tests/Feature/ServerAuthorizationTest.php rename to tests/Feature/Authorization/ServerAuthorizationTest.php diff --git a/tests/Feature/ServiceConfigAuthorizationTest.php b/tests/Feature/Authorization/ServiceConfigAuthorizationTest.php similarity index 100% rename from tests/Feature/ServiceConfigAuthorizationTest.php rename to tests/Feature/Authorization/ServiceConfigAuthorizationTest.php diff --git a/tests/Feature/SharedResourceAuthorizationTest.php b/tests/Feature/Authorization/SharedResourceAuthorizationTest.php similarity index 100% rename from tests/Feature/SharedResourceAuthorizationTest.php rename to tests/Feature/Authorization/SharedResourceAuthorizationTest.php diff --git a/tests/Feature/TeamAuthorizationTest.php b/tests/Feature/Authorization/TeamAuthorizationTest.php similarity index 63% rename from tests/Feature/TeamAuthorizationTest.php rename to tests/Feature/Authorization/TeamAuthorizationTest.php index af30c8dee..e99e55a2c 100644 --- a/tests/Feature/TeamAuthorizationTest.php +++ b/tests/Feature/Authorization/TeamAuthorizationTest.php @@ -205,3 +205,123 @@ expect(auth()->user()->can('manageMembers', $this->team))->toBeFalse(); }); + +// --- Team Policy: view --- + +test('owner can view team', function () { + $this->actingAs($this->owner); + session(['currentTeam' => $this->team]); + + expect(auth()->user()->can('view', $this->team))->toBeTrue(); +}); + +test('admin can view team', function () { + $this->actingAs($this->admin); + session(['currentTeam' => $this->team]); + + expect(auth()->user()->can('view', $this->team))->toBeTrue(); +}); + +test('member can view team', function () { + $this->actingAs($this->member); + session(['currentTeam' => $this->team]); + + expect(auth()->user()->can('view', $this->team))->toBeTrue(); +}); + +test('non-team member cannot view team', function () { + $outsider = User::factory()->create(); + $this->actingAs($outsider); + session(['currentTeam' => $this->team]); + + expect($outsider->can('view', $this->team))->toBeFalse(); +}); + +// --- Team Policy: viewAdmin --- + +test('owner can view admin panel', function () { + $this->actingAs($this->owner); + session(['currentTeam' => $this->team]); + + expect(auth()->user()->can('viewAdmin', $this->team))->toBeTrue(); +}); + +test('admin can view admin panel', function () { + $this->actingAs($this->admin); + session(['currentTeam' => $this->team]); + + expect(auth()->user()->can('viewAdmin', $this->team))->toBeTrue(); +}); + +test('member cannot view admin panel', function () { + $this->actingAs($this->member); + session(['currentTeam' => $this->team]); + + expect(auth()->user()->can('viewAdmin', $this->team))->toBeFalse(); +}); + +test('non-team member cannot view admin panel', function () { + $outsider = User::factory()->create(); + $this->actingAs($outsider); + session(['currentTeam' => $this->team]); + + expect($outsider->can('viewAdmin', $this->team))->toBeFalse(); +}); + +// --- Non-team member isolation --- + +test('non-team member cannot update team', function () { + $outsider = User::factory()->create(); + $this->actingAs($outsider); + session(['currentTeam' => $this->team]); + + expect($outsider->can('update', $this->team))->toBeFalse(); +}); + +test('non-team member cannot delete team', function () { + $outsider = User::factory()->create(); + $this->actingAs($outsider); + session(['currentTeam' => $this->team]); + + expect($outsider->can('delete', $this->team))->toBeFalse(); +}); + +test('non-team member cannot manage members', function () { + $outsider = User::factory()->create(); + $this->actingAs($outsider); + session(['currentTeam' => $this->team]); + + expect($outsider->can('manageMembers', $this->team))->toBeFalse(); +}); + +test('non-team member cannot manage invitations', function () { + $outsider = User::factory()->create(); + $this->actingAs($outsider); + session(['currentTeam' => $this->team]); + + expect($outsider->can('manageInvitations', $this->team))->toBeFalse(); +}); + +// --- Team creation and model-level protection --- + +test('member can create a new independent team', function () { + $this->actingAs($this->member); + session(['currentTeam' => $this->team]); + + $newTeam = Team::create([ + 'name' => 'New Team', + 'description' => 'Created by member', + 'personal_team' => false, + ]); + + expect($newTeam)->toBeInstanceOf(Team::class) + ->and($newTeam->name)->toBe('New Team'); +}); + +test('member cannot update an existing team at model level', function () { + $this->actingAs($this->member); + session(['currentTeam' => $this->team]); + + expect(fn () => $this->team->update(['name' => 'Hacked'])) + ->toThrow(\Exception::class, 'You are not allowed to update this team.'); +}); diff --git a/tests/Feature/ConvertContainerEnvsToArray.php b/tests/Feature/EnvironmentVariable/ConvertContainerEnvsToArrayTest.php similarity index 100% rename from tests/Feature/ConvertContainerEnvsToArray.php rename to tests/Feature/EnvironmentVariable/ConvertContainerEnvsToArrayTest.php diff --git a/tests/Feature/EnvironmentVariableSharedSpacingTest.php b/tests/Feature/EnvironmentVariable/EnvironmentVariableSharedSpacingTest.php similarity index 100% rename from tests/Feature/EnvironmentVariableSharedSpacingTest.php rename to tests/Feature/EnvironmentVariable/EnvironmentVariableSharedSpacingTest.php diff --git a/tests/Feature/MultilineEnvironmentVariableTest.php b/tests/Feature/EnvironmentVariable/MultilineEnvironmentVariableTest.php similarity index 100% rename from tests/Feature/MultilineEnvironmentVariableTest.php rename to tests/Feature/EnvironmentVariable/MultilineEnvironmentVariableTest.php diff --git a/tests/Feature/ExecuteContainerCommandTest.php b/tests/Feature/ExecuteContainerCommandTest.php deleted file mode 100644 index 6d485fe65..000000000 --- a/tests/Feature/ExecuteContainerCommandTest.php +++ /dev/null @@ -1,57 +0,0 @@ -shouldSetUpDatabase()) { - $this->setUpTestDatabase(); - } - // Create test data - $this->user = User::factory()->create(); - $this->team = $this->user->teams()->first(); - $this->server = Server::factory()->create(['team_id' => $this->team->id]); - $this->application = Application::factory()->create(); - - // Login the user - $this->actingAs($this->user); - } - - protected function tearDown(): void - { - if ($this->shouldSetUpDatabase()) { - $this->tearDownTestDatabase(); - } - parent::tearDown(); - } - - private function shouldSetUpDatabase(): bool - { - return in_array($this->name(), [ - 'it_allows_valid_container_access', - 'it_prevents_cross_server_container_access', - ]); - } -} diff --git a/tests/Feature/CloudInitScriptTest.php b/tests/Feature/Helpers/CloudInitScriptTest.php similarity index 100% rename from tests/Feature/CloudInitScriptTest.php rename to tests/Feature/Helpers/CloudInitScriptTest.php diff --git a/tests/Feature/ConvertArraysTest.php b/tests/Feature/Helpers/ConvertArraysTest.php similarity index 100% rename from tests/Feature/ConvertArraysTest.php rename to tests/Feature/Helpers/ConvertArraysTest.php diff --git a/tests/Feature/ConvertingGitUrlsTest.php b/tests/Feature/Helpers/ConvertingGitUrlsTest.php similarity index 100% rename from tests/Feature/ConvertingGitUrlsTest.php rename to tests/Feature/Helpers/ConvertingGitUrlsTest.php diff --git a/tests/Feature/DockerCustomCommandsTest.php b/tests/Feature/Helpers/DockerCustomCommandsTest.php similarity index 100% rename from tests/Feature/DockerCustomCommandsTest.php rename to tests/Feature/Helpers/DockerCustomCommandsTest.php diff --git a/tests/Feature/Utf8HandlingTest.php b/tests/Feature/Helpers/Utf8HandlingTest.php similarity index 97% rename from tests/Feature/Utf8HandlingTest.php rename to tests/Feature/Helpers/Utf8HandlingTest.php index 50a52c5b2..6b100b067 100644 --- a/tests/Feature/Utf8HandlingTest.php +++ b/tests/Feature/Helpers/Utf8HandlingTest.php @@ -1,6 +1,6 @@ team = Team::factory()->create(); - - $this->owner = User::factory()->create(); - $this->admin = User::factory()->create(); - $this->member = User::factory()->create(); - - $this->team->members()->attach($this->owner->id, ['role' => 'owner']); - $this->team->members()->attach($this->admin->id, ['role' => 'admin']); - $this->team->members()->attach($this->member->id, ['role' => 'member']); -}); - -describe('update permission', function () { - test('owner can update team', function () { - $this->actingAs($this->owner); - session(['currentTeam' => $this->team]); - expect($this->owner->can('update', $this->team))->toBeTrue(); - }); - - test('admin can update team', function () { - $this->actingAs($this->admin); - session(['currentTeam' => $this->team]); - expect($this->admin->can('update', $this->team))->toBeTrue(); - }); - - test('member cannot update team', function () { - $this->actingAs($this->member); - session(['currentTeam' => $this->team]); - expect($this->member->can('update', $this->team))->toBeFalse(); - }); - - test('non-team member cannot update team', function () { - $outsider = User::factory()->create(); - $this->actingAs($outsider); - session(['currentTeam' => $this->team]); - expect($outsider->can('update', $this->team))->toBeFalse(); - }); -}); - -describe('delete permission', function () { - test('owner can delete team', function () { - $this->actingAs($this->owner); - session(['currentTeam' => $this->team]); - expect($this->owner->can('delete', $this->team))->toBeTrue(); - }); - - test('admin can delete team', function () { - $this->actingAs($this->admin); - session(['currentTeam' => $this->team]); - expect($this->admin->can('delete', $this->team))->toBeTrue(); - }); - - test('member cannot delete team', function () { - $this->actingAs($this->member); - session(['currentTeam' => $this->team]); - expect($this->member->can('delete', $this->team))->toBeFalse(); - }); - - test('non-team member cannot delete team', function () { - $outsider = User::factory()->create(); - $this->actingAs($outsider); - session(['currentTeam' => $this->team]); - expect($outsider->can('delete', $this->team))->toBeFalse(); - }); -}); - -describe('manageMembers permission', function () { - test('owner can manage members', function () { - $this->actingAs($this->owner); - session(['currentTeam' => $this->team]); - expect($this->owner->can('manageMembers', $this->team))->toBeTrue(); - }); - - test('admin can manage members', function () { - $this->actingAs($this->admin); - session(['currentTeam' => $this->team]); - expect($this->admin->can('manageMembers', $this->team))->toBeTrue(); - }); - - test('member cannot manage members', function () { - $this->actingAs($this->member); - session(['currentTeam' => $this->team]); - expect($this->member->can('manageMembers', $this->team))->toBeFalse(); - }); - - test('non-team member cannot manage members', function () { - $outsider = User::factory()->create(); - $this->actingAs($outsider); - session(['currentTeam' => $this->team]); - expect($outsider->can('manageMembers', $this->team))->toBeFalse(); - }); -}); - -describe('viewAdmin permission', function () { - test('owner can view admin panel', function () { - $this->actingAs($this->owner); - session(['currentTeam' => $this->team]); - expect($this->owner->can('viewAdmin', $this->team))->toBeTrue(); - }); - - test('admin can view admin panel', function () { - $this->actingAs($this->admin); - session(['currentTeam' => $this->team]); - expect($this->admin->can('viewAdmin', $this->team))->toBeTrue(); - }); - - test('member cannot view admin panel', function () { - $this->actingAs($this->member); - session(['currentTeam' => $this->team]); - expect($this->member->can('viewAdmin', $this->team))->toBeFalse(); - }); - - test('non-team member cannot view admin panel', function () { - $outsider = User::factory()->create(); - $this->actingAs($outsider); - session(['currentTeam' => $this->team]); - expect($outsider->can('viewAdmin', $this->team))->toBeFalse(); - }); -}); - -describe('manageInvitations permission (privilege escalation fix)', function () { - test('owner can manage invitations', function () { - $this->actingAs($this->owner); - session(['currentTeam' => $this->team]); - expect($this->owner->can('manageInvitations', $this->team))->toBeTrue(); - }); - - test('admin can manage invitations', function () { - $this->actingAs($this->admin); - session(['currentTeam' => $this->team]); - expect($this->admin->can('manageInvitations', $this->team))->toBeTrue(); - }); - - test('member cannot manage invitations (SECURITY FIX)', function () { - // This test verifies the privilege escalation vulnerability is fixed - // Previously, members could see and manage admin invitations - $this->actingAs($this->member); - session(['currentTeam' => $this->team]); - expect($this->member->can('manageInvitations', $this->team))->toBeFalse(); - }); - - test('non-team member cannot manage invitations', function () { - $outsider = User::factory()->create(); - $this->actingAs($outsider); - session(['currentTeam' => $this->team]); - expect($outsider->can('manageInvitations', $this->team))->toBeFalse(); - }); -}); - -describe('create team', function () { - test('member can create a new independent team', function () { - $this->actingAs($this->member); - session(['currentTeam' => $this->team]); - - $newTeam = Team::create([ - 'name' => 'New Team', - 'description' => 'Created by member', - 'personal_team' => false, - ]); - - expect($newTeam)->toBeInstanceOf(Team::class) - ->and($newTeam->name)->toBe('New Team'); - }); - - test('member cannot update an existing team', function () { - $this->actingAs($this->member); - session(['currentTeam' => $this->team]); - - expect(fn () => $this->team->update(['name' => 'Hacked'])) - ->toThrow(\Exception::class, 'You are not allowed to update this team.'); - }); - - test('owner can create a new team', function () { - $this->actingAs($this->owner); - session(['currentTeam' => $this->team]); - - $newTeam = Team::create([ - 'name' => 'Owner New Team', - 'personal_team' => false, - ]); - - expect($newTeam)->toBeInstanceOf(Team::class); - }); - - test('admin can create a new team', function () { - $this->actingAs($this->admin); - session(['currentTeam' => $this->team]); - - $newTeam = Team::create([ - 'name' => 'Admin New Team', - 'personal_team' => false, - ]); - - expect($newTeam)->toBeInstanceOf(Team::class); - }); -}); - -describe('view permission', function () { - test('owner can view team', function () { - $this->actingAs($this->owner); - session(['currentTeam' => $this->team]); - expect($this->owner->can('view', $this->team))->toBeTrue(); - }); - - test('admin can view team', function () { - $this->actingAs($this->admin); - session(['currentTeam' => $this->team]); - expect($this->admin->can('view', $this->team))->toBeTrue(); - }); - - test('member can view team', function () { - $this->actingAs($this->member); - session(['currentTeam' => $this->team]); - expect($this->member->can('view', $this->team))->toBeTrue(); - }); - - test('non-team member cannot view team', function () { - $outsider = User::factory()->create(); - $this->actingAs($outsider); - session(['currentTeam' => $this->team]); - expect($outsider->can('view', $this->team))->toBeFalse(); - }); -});