create([ 'tenant_id' => 'tenant-1', 'name' => 'Contoso', ]); $response = $this->get(route('admin.consent.callback', [ 'tenant' => $tenant->tenant_id, 'admin_consent' => 'true', ])); $response->assertOk(); $response->assertSeeText('Verification state:'); $response->assertSeeText('Needs verification'); $response->assertSee( route('filament.admin.resources.tenants.view', ['tenant' => $tenant->external_id, 'record' => $tenant]), false, ); $connection = ProviderConnection::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('provider', 'microsoft') ->where('entra_tenant_id', $tenant->graphTenantId()) ->first(); expect($connection)->not->toBeNull() ->and($connection?->is_enabled)->toBeTrue() ->and($connection?->consent_status?->value ?? $connection?->consent_status)->toBe('granted') ->and($connection?->verification_status?->value ?? $connection?->verification_status)->toBe('unknown') ->and($connection?->last_error_reason_code)->toBeNull(); $this->assertDatabaseHas('audit_logs', [ 'tenant_id' => $tenant->id, 'action' => 'tenant.consent.callback', 'status' => 'success', ]); }); it('links back to onboarding when tenant is onboarding', function () { $tenant = Tenant::factory()->create([ 'tenant_id' => 'tenant-3', 'name' => 'Onboarding Tenant', 'status' => Tenant::STATUS_ONBOARDING, ]); $response = $this->get(route('admin.consent.callback', [ 'tenant' => $tenant->tenant_id, 'admin_consent' => 'true', ])); $response->assertOk(); $response->assertSee(route('admin.onboarding'), false); }); it('invalidates resumable onboarding verification state for the same platform connection after a successful callback', function () { $tenant = Tenant::factory()->create([ 'tenant_id' => 'tenant-verify-reset', 'name' => 'Reset Tenant', 'status' => Tenant::STATUS_ONBOARDING, ]); $connection = ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'provider' => 'microsoft', 'entra_tenant_id' => $tenant->graphTenantId(), 'is_default' => true, ]); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'provider.connection.check', ]); $draft = TenantOnboardingSession::query()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'entra_tenant_id' => (string) $tenant->tenant_id, 'current_step' => 'verify', 'state' => [ 'provider_connection_id' => (int) $connection->getKey(), 'verification_operation_run_id' => (int) $run->getKey(), 'verification_run_id' => (int) $run->getKey(), 'bootstrap_operation_runs' => [123, 456], 'bootstrap_operation_types' => ['inventory_sync'], 'bootstrap_run_ids' => [123, 456], ], ]); $this->get(route('admin.consent.callback', [ 'tenant' => $tenant->tenant_id, 'admin_consent' => 'true', ]))->assertOk(); $draft->refresh(); expect($draft->state['verification_operation_run_id'] ?? null)->toBeNull() ->and($draft->state['verification_run_id'] ?? null)->toBeNull() ->and($draft->state['bootstrap_operation_runs'] ?? null)->toBeNull() ->and($draft->state['bootstrap_operation_types'] ?? null)->toBeNull() ->and($draft->state['bootstrap_run_ids'] ?? null)->toBeNull() ->and($draft->state['connection_recently_updated'] ?? null)->toBeTrue(); }); it('creates tenant and provider connection when callback tenant does not exist', function () { $workspace = Workspace::factory()->create(); $response = $this->withSession([ 'tenant_onboard_workspace_id' => (int) $workspace->getKey(), 'tenant_onboard_state' => 'state-456', ])->get(route('admin.consent.callback', [ 'tenant' => 'new-tenant', 'state' => 'state-456', ])); $response->assertOk(); $tenant = Tenant::where('tenant_id', 'new-tenant')->first(); expect($tenant)->not->toBeNull(); $connection = ProviderConnection::query() ->where('tenant_id', (int) $tenant->id) ->where('provider', 'microsoft') ->where('entra_tenant_id', $tenant->graphTenantId()) ->first(); expect($connection)->not->toBeNull() ->and($connection?->is_enabled)->toBeTrue() ->and($connection?->consent_status?->value ?? $connection?->consent_status)->toBe('required') ->and($connection?->verification_status?->value ?? $connection?->verification_status)->toBe('unknown') ->and($connection?->last_error_reason_code)->toBe(ProviderReasonCodes::ProviderConsentMissing); }); it('records consent callback errors on provider connection canonical state', function () { $tenant = Tenant::factory()->create([ 'tenant_id' => 'tenant-2', 'name' => 'Fabrikam', ]); $response = $this->get(route('admin.consent.callback', [ 'tenant' => $tenant->tenant_id, 'error' => 'access_denied', ])); $response->assertOk(); $response->assertSeeText('Verification state:'); $response->assertSeeText('Not verified'); $connection = ProviderConnection::query() ->where('tenant_id', (int) $tenant->getKey()) ->where('provider', 'microsoft') ->where('entra_tenant_id', $tenant->graphTenantId()) ->first(); expect($connection)->not->toBeNull() ->and($connection?->is_enabled)->toBeTrue() ->and($connection?->consent_status?->value ?? $connection?->consent_status)->toBe('failed') ->and($connection?->verification_status?->value ?? $connection?->verification_status)->toBe('unknown') ->and($connection?->last_error_reason_code)->toBe(ProviderReasonCodes::ProviderAuthFailed) ->and($connection?->last_error_message)->toBe('access_denied'); $this->assertDatabaseHas('audit_logs', [ 'tenant_id' => $tenant->id, 'action' => 'tenant.consent.callback', 'status' => 'failed', ]); });