TenantAtlas/apps/platform/tests/Feature/Audit/TenantMembershipAuditLogTest.php
ahmido c7b38606a9 feat: implement spec 285 workspace-first environment access (#344)
Implements platform feature branch `285-workspace-rbac-environment-access`.

Summary:
- switch managed environment authorization to workspace-first role resolution with explicit environment-scope narrowing
- rewire Filament pages, resources, policies, and user tenant access helpers to the shared access-scope resolver
- add Spec 285 coverage across unit, feature, and browser tests plus full spec artifacts

Validation:
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Auth/WorkspaceFirstCapabilityResolverTest.php tests/Unit/Auth/ManagedEnvironmentAccessScopeResolverTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Auth/WorkspaceFirstManagedEnvironmentAccessTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Filament/WorkspaceMembershipRoleManagementTest.php tests/Feature/Rbac/GovernanceArtifactsWorkspaceFirstAuthorizationTest.php tests/Feature/Rbac/OperationRunWorkspaceFirstAuthorizationTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Verification/ProviderExecutionReauthorizationTest.php tests/Feature/ProviderConnections/ProviderConnectionHealthCheckStartSurfaceTest.php tests/Feature/Tenants/TenantProviderBackedActionStartTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Audit/TenantMembershipAuditLogTest.php tests/Feature/Filament/TenantMembersTest.php tests/Feature/TenantRBAC/TenantMembershipCrudTest.php tests/Feature/TenantRBAC/TenantSwitcherScopeTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

Target branch: `platform-dev`.

Follow-up integration path after merge:
- `platform-dev` -> `dev`.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #344
2026-05-09 12:40:50 +00:00

92 lines
2.9 KiB
PHP

<?php
use App\Models\AuditLog;
use App\Models\ManagedEnvironmentMembership;
use App\Models\User;
use App\Models\WorkspaceMembership;
use App\Services\Auth\TenantMembershipManager;
use App\Support\Audit\AuditActionId;
it('writes canonical audit action IDs for environment access-scope mutations', function () {
[$owner, $tenant] = createUserWithTenant(role: 'owner');
$member = User::factory()->create();
WorkspaceMembership::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'user_id' => (int) $member->getKey(),
'role' => 'readonly',
]);
/** @var TenantMembershipManager $manager */
$manager = app(TenantMembershipManager::class);
$membership = $manager->grantScope(
tenant: $tenant,
actor: $owner,
member: $member,
source: 'manual',
);
$manager->removeMember(
tenant: $tenant,
actor: $owner,
membership: $membership,
);
$logs = AuditLog::query()
->where('managed_environment_id', $tenant->id)
->whereIn('action', [
AuditActionId::ManagedEnvironmentAccessScopeGrant->value,
AuditActionId::ManagedEnvironmentAccessScopeRemove->value,
])
->get()
->keyBy('action');
expect($logs)->toHaveCount(2);
$grantLog = $logs->get(AuditActionId::ManagedEnvironmentAccessScopeGrant->value);
$removeLog = $logs->get(AuditActionId::ManagedEnvironmentAccessScopeRemove->value);
expect($grantLog)->not->toBeNull();
expect($removeLog)->not->toBeNull();
expect($grantLog->status)->toBe('success');
expect($removeLog->status)->toBe('success');
expect($grantLog->metadata)
->toHaveKey('member_user_id', $member->id)
->toHaveKey('workspace_role', 'readonly')
->toHaveKey('source', 'manual')
->not->toHaveKey('member_email')
->not->toHaveKey('member_name');
expect($removeLog->metadata)
->toHaveKey('member_user_id', $member->id)
->not->toHaveKey('member_email')
->not->toHaveKey('member_name');
});
it('rejects managed-environment role-change attempts without writing role-change audit truth', function () {
[$owner, $tenant] = createUserWithTenant(role: 'owner');
$membership = ManagedEnvironmentMembership::query()
->where('managed_environment_id', $tenant->id)
->where('user_id', $owner->id)
->firstOrFail();
/** @var TenantMembershipManager $manager */
$manager = app(TenantMembershipManager::class);
expect(fn () => $manager->changeRole(
tenant: $tenant,
actor: $owner,
membership: $membership,
newRole: 'manager',
))->toThrow(DomainException::class);
expect(AuditLog::query()
->where('managed_environment_id', $tenant->id)
->where('action', AuditActionId::TenantMembershipRoleChange->value)
->exists())->toBeFalse();
});