*/ public static function fixture(string $family, string $name): array { $path = base_path("tests/Fixtures/TenantConfiguration/Spec425/{$family}/{$name}.json"); $json = file_get_contents($path); if ($json === false) { throw new \RuntimeException("Missing Spec425 fixture [{$family}/{$name}]."); } $payload = json_decode($json, true, flags: JSON_THROW_ON_ERROR); if (! is_array($payload)) { throw new \RuntimeException("Invalid Spec425 fixture [{$family}/{$name}]."); } return $payload; } public static function syncDefaults(): void { app(ResourceTypeRegistry::class)->syncDefaults(); app(SupportedScopeResolver::class)->syncDefaults(); } public static function resourceType(string $canonicalType): TenantConfigurationResourceType { return TenantConfigurationResourceType::query() ->active() ->where('canonical_type', $canonicalType) ->orderBy('source_class') ->firstOrFail(); } public static function createRun(ManagedEnvironment $environment, ProviderConnection $connection): OperationRun { return OperationRun::factory() ->forTenant($environment) ->create([ 'type' => OperationRunType::TenantConfigurationCapture->value, 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Succeeded->value, 'context' => [ 'target_scope' => [ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), ], 'resource_types' => ['conditionalAccessPolicy', 'securityDefaults'], 'required_capability' => 'evidence.manage', ], ]); } /** * @param array $payload * @param array $resourceOverrides * @param array $evidenceOverrides */ public static function createResourceWithEvidence( ManagedEnvironment $environment, ProviderConnection $connection, string $canonicalType, array $payload, array $resourceOverrides = [], array $evidenceOverrides = [], ): TenantConfigurationResource { $resourceType = self::resourceType($canonicalType); $normalizedPayload = self::normalizedPayload($payload); $payloadHash = self::payloadHash($normalizedPayload); $run = self::createRun($environment, $connection); $sourceResourceId = (string) ($payload['id'] ?? $canonicalType); /** @var TenantConfigurationResource $resource */ $resource = TenantConfigurationResource::factory()->create(array_replace([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), 'resource_type_id' => (int) $resourceType->getKey(), 'source_class' => $resourceType->source_class, 'canonical_type' => $canonicalType, 'canonical_resource_key' => "{$canonicalType}:graph_object_id:{$sourceResourceId}", 'canonical_key_kind' => CanonicalKeyKind::GraphObjectId->value, 'source_resource_id' => $sourceResourceId, 'source_display_name' => (string) ($payload['displayName'] ?? $payload['name'] ?? $canonicalType), 'source_metadata' => [ 'source_contract_key' => self::sourceContractKey($canonicalType), 'source_endpoint' => self::sourceEndpoint($canonicalType), 'source_version' => 'v1.0', ], 'identity_strategy' => $canonicalType === 'securityDefaults' ? 'graph.security_defaults.v1' : 'graph.conditional_access_policy.v1', 'source_identity' => [ 'primary_value' => $sourceResourceId, 'strategy_identifier' => $canonicalType === 'securityDefaults' ? 'graph.security_defaults.v1' : 'graph.conditional_access_policy.v1', ], 'secondary_identity_keys' => (object) [], 'identity_diagnostics' => (object) [], 'latest_evidence_state' => EvidenceState::ContentBacked->value, 'latest_identity_state' => IdentityState::Stable->value, 'latest_claim_state' => ClaimState::InternalOnly->value, 'latest_payload_hash' => $payloadHash, 'latest_captured_at' => now(), ], $resourceOverrides)); /** @var TenantConfigurationResourceEvidence $evidence */ $evidence = TenantConfigurationResourceEvidence::factory()->create(array_replace([ 'resource_id' => (int) $resource->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), 'resource_type_id' => (int) $resourceType->getKey(), 'operation_run_id' => (int) $run->getKey(), 'source_contract_key' => self::sourceContractKey($canonicalType), 'source_endpoint' => self::sourceEndpoint($canonicalType), 'source_version' => 'v1.0', 'source_schema_hash' => hash('sha256', $canonicalType), 'source_metadata' => [ 'source_contract_key' => self::sourceContractKey($canonicalType), 'source_endpoint' => self::sourceEndpoint($canonicalType), 'source_version' => 'v1.0', ], 'raw_payload' => $payload, 'normalized_payload' => $normalizedPayload, 'payload_hash' => $payloadHash, 'permission_context' => ['scopes_granted' => ['Policy.Read.All']], 'evidence_state' => EvidenceState::ContentBacked->value, 'coverage_level' => CoverageLevel::Renderable->value, 'capture_outcome' => CaptureOutcome::Captured->value, 'captured_at' => now(), ], $evidenceOverrides)); $resource->forceFill([ 'latest_evidence_id' => (int) $evidence->getKey(), 'latest_payload_hash' => (string) $evidence->payload_hash, 'latest_captured_at' => $evidence->captured_at, ])->save(); return $resource->refresh(); } /** * @param array $payload * @return array */ public static function normalizedPayload(array $payload): array { $redacted = app(CoveragePayloadRedactor::class)->redact($payload); return is_array($redacted) ? $redacted : []; } /** * @param array $payload */ public static function payloadHash(array $payload): string { return hash('sha256', json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR)); } public static function sourceContractKey(string $canonicalType): string { return $canonicalType === 'securityDefaults' ? 'securityDefaults' : 'conditionalAccessPolicy'; } public static function sourceEndpoint(string $canonicalType): string { return $canonicalType === 'securityDefaults' ? '/policies/identitySecurityDefaultsEnforcementPolicy' : '/identity/conditionalAccess/policies'; } }