create([ 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => fake()->uuid(), ]); ProviderCredential::factory()->create([ 'provider_connection_id' => (int) $connection->getKey(), 'payload' => [ 'tenant_id' => (string) $connection->entra_tenant_id, 'client_id' => fake()->uuid(), 'client_secret' => fake()->sha1(), ], ]); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'user_id' => (int) $user->getKey(), 'type' => 'provider.connection.check', 'status' => 'running', 'outcome' => 'pending', 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), ], ]); $this->mock(GraphClientInterface::class, function ($mock): void { $mock->shouldReceive('getOrganization') ->once() ->andReturn(new GraphResponse(false, [], 401, ['Bearer super-secret-token'])); }); $job = new ProviderConnectionHealthCheckJob( tenantId: (int) $tenant->getKey(), userId: (int) $user->getKey(), providerConnectionId: (int) $connection->getKey(), operationRun: $run, ); $job->handle( healthCheck: app(MicrosoftProviderHealthCheck::class), runs: app(OperationRunService::class), ); $run = $run->fresh(); expect($run)->not->toBeNull(); expect($run->status)->toBe('completed'); expect($run->outcome)->toBe('failed'); $context = is_array($run->context) ? $run->context : []; $report = $context['verification_report'] ?? null; expect($report)->toBeArray(); expect(VerificationReportSchema::isValidReport($report))->toBeTrue(); expect(json_encode($report))->not->toContain('Bearer '); expect($report['checks'][0]['reason_code'] ?? null)->toBe('authentication_failed'); foreach (($report['checks'] ?? []) as $check) { expect($check)->toBeArray(); foreach (($check['evidence'] ?? []) as $pointer) { expect($pointer)->toBeArray(); expect(array_keys($pointer))->toEqualCanonicalizing(['kind', 'value']); } } $audit = AuditLog::query() ->where('workspace_id', (int) $tenant->workspace_id) ->where('action', AuditActionId::VerificationCompleted->value) ->latest('id') ->first(); expect($audit)->not->toBeNull(); expect($audit?->metadata)->toMatchArray([ 'operation_run_id' => (int) $run->getKey(), ]); }); it('writes a verification report for successful provider connection checks', function (): void { [$user, $tenant] = createUserWithTenant(role: 'operator'); $connection = ProviderConnection::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => fake()->uuid(), ]); ProviderCredential::factory()->create([ 'provider_connection_id' => (int) $connection->getKey(), 'payload' => [ 'tenant_id' => (string) $connection->entra_tenant_id, 'client_id' => fake()->uuid(), 'client_secret' => fake()->sha1(), ], ]); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'user_id' => (int) $user->getKey(), 'type' => 'provider.connection.check', 'status' => 'running', 'outcome' => 'pending', 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), ], ]); $this->mock(GraphClientInterface::class, function ($mock): void { $mock->shouldReceive('getOrganization') ->once() ->andReturn(new GraphResponse(true, [ 'id' => 'org_123', 'displayName' => 'Org 123', ], 200)); }); $job = new ProviderConnectionHealthCheckJob( tenantId: (int) $tenant->getKey(), userId: (int) $user->getKey(), providerConnectionId: (int) $connection->getKey(), operationRun: $run, ); $job->handle( healthCheck: app(MicrosoftProviderHealthCheck::class), runs: app(OperationRunService::class), ); $run = $run->fresh(); expect($run)->not->toBeNull(); expect($run->status)->toBe('completed'); expect($run->outcome)->toBe('succeeded'); $context = is_array($run->context) ? $run->context : []; $report = $context['verification_report'] ?? null; expect($report)->toBeArray(); expect(VerificationReportSchema::isValidReport($report))->toBeTrue(); expect($report['summary']['counts'] ?? [])->toMatchArray([ 'total' => 1, 'pass' => 1, 'fail' => 0, ]); });