TenantAtlas/apps/platform/tests/Feature/Audit/ProviderConnectionIdentityAuditTest.php
ahmido 110245a9ec
Some checks are pending
Main Confidence / confidence (push) Waiting to run
feat: neutralize provider connection target-scope surfaces (#274)
## Summary
- add a shared provider target-scope descriptor, normalizer, identity-context metadata, and surface-summary layer
- update provider connection list, detail, create, edit, and onboarding surfaces to use neutral target-scope vocabulary while keeping Microsoft identity contextual
- align provider connection audit and resolver output with the neutral target-scope contract and add focused guard/unit/feature coverage for regressions

## Validation
- browser smoke: opened the tenant-scoped provider connection list, drilled into detail, and verified the edit/create surfaces in local admin context

## Notes
- this PR comes from the session branch created for the active feature work
- no additional runtime or persistence layer was introduced in this slice

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #274
2026-04-25 09:07:40 +00:00

122 lines
4.0 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Resources\ProviderConnectionResource\Pages\CreateProviderConnection;
use App\Models\AuditLog;
use App\Models\ProviderConnection;
use App\Models\Tenant;
use App\Models\User;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
uses(RefreshDatabase::class);
it('keeps provider connection identity audit payloads aligned across consent and migration flows', function (): void {
config()->set('graph.client_id', 'platform-client-id');
config()->set('graph.client_secret', 'platform-client-secret');
$user = User::factory()->create();
$tenant = Tenant::factory()->create([
'tenant_id' => 'identity-audit-tenant-id',
]);
[$user, $tenant] = createUserWithTenant(tenant: $tenant, user: $user, role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
$response = $this->actingAs($user)->get(route('admin.consent.start', [
'tenant' => $tenant->external_id,
]));
$response->assertRedirect();
$state = session('tenant_onboard_state');
$this->get(route('admin.consent.callback', [
'tenant' => $tenant->tenant_id,
'state' => $state,
'admin_consent' => 'True',
]))->assertSuccessful();
$this->artisan('tenantpilot:provider-connections:classify', ['--write' => true])
->assertSuccessful();
$logs = AuditLog::query()
->where('tenant_id', (int) $tenant->getKey())
->whereIn('action', [
'provider_connection.consent_started',
'provider_connection.consent_result',
'provider_connection.migration_classification_applied',
])
->orderBy('id')
->get();
expect($logs)->toHaveCount(3);
foreach ($logs as $log) {
expect($log->resource_type)->toBe('provider_connection')
->and($log->resource_id)->not->toBeNull();
$metadata = is_array($log->metadata) ? $log->metadata : [];
expect($metadata)->toHaveKeys([
'provider_connection_id',
'provider',
'connection_type',
'source',
]);
}
});
it('records provider connection create audits with neutral target-scope metadata', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner', ensureDefaultMicrosoftProviderConnection: false);
$this->actingAs($user);
$tenant->makeCurrent();
Filament::setTenant($tenant, true);
Livewire::actingAs($user)
->test(CreateProviderConnection::class)
->fillForm([
'display_name' => 'Audit target scope connection',
'entra_tenant_id' => '88888888-8888-8888-8888-888888888888',
'is_default' => true,
])
->call('create')
->assertHasNoFormErrors();
$connection = ProviderConnection::query()
->where('tenant_id', (int) $tenant->getKey())
->where('display_name', 'Audit target scope connection')
->firstOrFail();
$log = AuditLog::query()
->where('tenant_id', (int) $tenant->getKey())
->where('action', 'provider_connection.created')
->where('resource_id', (string) $connection->getKey())
->firstOrFail();
$metadata = is_array($log->metadata) ? $log->metadata : [];
expect($metadata)->toHaveKeys([
'provider_connection_id',
'provider',
'target_scope',
'provider_identity_context',
'connection_type',
])
->and($metadata)->not->toHaveKey('entra_tenant_id')
->and($metadata['target_scope'])->toMatchArray([
'provider' => 'microsoft',
'scope_kind' => 'tenant',
'scope_identifier' => '88888888-8888-8888-8888-888888888888',
'shared_label' => 'Target scope',
])
->and($metadata['provider_identity_context'][0] ?? [])->toMatchArray([
'provider' => 'microsoft',
'detail_key' => 'microsoft_tenant_id',
'detail_label' => 'Microsoft tenant ID',
'detail_value' => '88888888-8888-8888-8888-888888888888',
]);
});