syncDefaults(); [$user, $environment] = createMinimalUserWithTenant(role: 'owner'); $connection = ProviderConnection::factory()->withCredential()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'scopes_granted' => ['Exchange.ManageAsApp', 'Policy.Read.All'], ]); $graph = spec427NoEvidenceGraphClient(); app()->instance(GraphClientInterface::class, $graph); $run = spec427NoEvidenceRun($user, $environment, $connection, spec427NoEvidenceTypes()); $result = app(GenericContentEvidenceCaptureService::class)->capture( tenant: $environment, providerConnection: $connection, operationRun: $run, canonicalTypes: spec427NoEvidenceTypes(), ); expect($graph->calls)->toBe([]) ->and($result['summary_counts'])->toMatchArray([ 'total' => 4, 'processed' => 4, 'succeeded' => 0, 'skipped' => 4, 'failed' => 0, 'errors_recorded' => 0, ]) ->and($result['run_outcome'])->toBe(OperationRunOutcome::Blocked->value) ->and(TenantConfigurationResource::query()->count())->toBe(0) ->and(TenantConfigurationResourceEvidence::query()->count())->toBe(0); foreach (collect($result['outcomes'])->keyBy('canonical_type') as $canonicalType => $outcome) { expect(spec427NoEvidenceTypes())->toContain($canonicalType) ->and($outcome['outcome'])->toBe(CaptureOutcome::BlockedMissingContract->value) ->and($outcome['reason_code'])->toBe('contract_blocked_repo_adapter_missing') ->and($outcome['source_contract_key'])->toBeNull(); } }); /** * @return list */ function spec427NoEvidenceTypes(): array { return ['acceptedDomain', 'appPermissionPolicy', 'meetingPolicy', 'transportRule']; } function spec427NoEvidenceRun($user, $environment, ProviderConnection $connection, array $resourceTypes): OperationRun { return OperationRun::factory()->withUser($user)->forTenant($environment)->create([ 'type' => OperationRunType::TenantConfigurationCapture->value, 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, 'context' => [ 'target_scope' => [ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), ], 'resource_types' => $resourceTypes, 'required_capability' => 'evidence.manage', ], ]); } function spec427NoEvidenceGraphClient(): GraphClientInterface { return new class implements GraphClientInterface { /** * @var list}> */ public array $calls = []; public function listPolicies(string $policyType, array $options = []): GraphResponse { $this->calls[] = ['policy_type' => $policyType, 'options' => $options]; return new GraphResponse(true, [['id' => 'unexpected-provider-call']]); } public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse { return new GraphResponse(false, [], 501); } public function getOrganization(array $options = []): GraphResponse { return new GraphResponse(false, [], 501); } public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse { return new GraphResponse(false, [], 501); } public function getServicePrincipalPermissions(array $options = []): GraphResponse { return new GraphResponse(false, [], 501); } public function request(string $method, string $path, array $options = []): GraphResponse { return new GraphResponse(false, [], 501); } }; }