Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m12s
Added BaselineSubjectResolution page and supporting logic to visualize missing identities, ambiguous matches, and skipped coverages per Spec 384.
148 lines
5.3 KiB
PHP
148 lines
5.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Feature\Baselines\Support;
|
|
|
|
use App\Models\InventoryItem;
|
|
use App\Support\Baselines\OperatorActionCategory;
|
|
use App\Support\Baselines\ResolutionOutcome;
|
|
use App\Support\Baselines\ResolutionPath;
|
|
use App\Support\Baselines\SubjectClass;
|
|
use App\Support\Resources\ProviderResourceDescriptor;
|
|
use App\Support\Resources\ResourceIdentity;
|
|
|
|
final class BaselineSubjectResolutionFixtures
|
|
{
|
|
/**
|
|
* @param array<string, mixed> $overrides
|
|
* @return array<string, mixed>
|
|
*/
|
|
public static function structuredGap(array $overrides = []): array
|
|
{
|
|
return array_replace([
|
|
'policy_type' => 'deviceConfiguration',
|
|
'subject_external_id' => 'subject-1',
|
|
'subject_key' => 'deviceconfiguration|subject-1',
|
|
'subject_class' => SubjectClass::PolicyBacked->value,
|
|
'resolution_path' => ResolutionPath::Policy->value,
|
|
'resolution_outcome' => ResolutionOutcome::PolicyRecordMissing->value,
|
|
'reason_code' => 'policy_record_missing',
|
|
'operator_action_category' => OperatorActionCategory::RunPolicySyncOrBackup->value,
|
|
'structural' => false,
|
|
'retryable' => false,
|
|
'source_model_expected' => 'policy',
|
|
'source_model_found' => null,
|
|
], $overrides);
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $subjects
|
|
* @param array<string, mixed> $overrides
|
|
* @return array<string, mixed>
|
|
*/
|
|
public static function compareContext(array $subjects, array $overrides = []): array
|
|
{
|
|
$byReason = [];
|
|
|
|
foreach ($subjects as $subject) {
|
|
$reasonCode = is_string($subject['reason_code'] ?? null) ? $subject['reason_code'] : 'unknown';
|
|
$byReason[$reasonCode] = ($byReason[$reasonCode] ?? 0) + 1;
|
|
}
|
|
|
|
return array_replace_recursive([
|
|
'baseline_compare' => [
|
|
'evidence_gaps' => [
|
|
'count' => count($subjects),
|
|
'by_reason' => $byReason,
|
|
'subjects' => $subjects,
|
|
],
|
|
],
|
|
], $overrides);
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $subjects
|
|
* @param array<string, mixed> $overrides
|
|
* @return array<string, mixed>
|
|
*/
|
|
public static function captureContext(array $subjects, array $overrides = []): array
|
|
{
|
|
$byReason = [];
|
|
|
|
foreach ($subjects as $subject) {
|
|
$reasonCode = is_string($subject['reason_code'] ?? null) ? $subject['reason_code'] : 'unknown';
|
|
$byReason[$reasonCode] = ($byReason[$reasonCode] ?? 0) + 1;
|
|
}
|
|
|
|
return array_replace_recursive([
|
|
'baseline_capture' => [
|
|
'gaps' => [
|
|
'count' => count($subjects),
|
|
'by_reason' => $byReason,
|
|
'subjects' => $subjects,
|
|
],
|
|
],
|
|
], $overrides);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $overrides
|
|
* @return array<string, mixed>
|
|
*/
|
|
public static function semanticOutcome(array $overrides = []): array
|
|
{
|
|
return array_replace_recursive([
|
|
'reason' => 'identity_required',
|
|
'category' => 'action_required',
|
|
'actionability' => 'binding_required',
|
|
'readiness_impact' => 'customer_blocker',
|
|
'identity_status' => 'unresolved',
|
|
'comparison_status' => 'not_compared',
|
|
'coverage_status' => 'missing_local_evidence',
|
|
'trust_level' => 'untrusted',
|
|
'subject' => [
|
|
'subject_domain' => 'baseline',
|
|
'subject_class' => SubjectClass::PolicyBacked->value,
|
|
'subject_type_key' => 'deviceConfiguration',
|
|
'subject_key' => 'subject-key',
|
|
'display_label' => 'Subject label',
|
|
],
|
|
'proof' => [],
|
|
], $overrides);
|
|
}
|
|
|
|
public static function inventoryCandidate(mixed $tenant, ResourceIdentity $identity, string $displayName): InventoryItem
|
|
{
|
|
$descriptor = self::providerDescriptor($identity, $displayName);
|
|
|
|
return InventoryItem::factory()->create([
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'policy_type' => 'deviceConfiguration',
|
|
'external_id' => $identity->providerResourceId,
|
|
'display_name' => $displayName,
|
|
'meta_jsonb' => [
|
|
'provider_resource_descriptor' => $descriptor->toArray(),
|
|
'provider_resource_identity' => $identity->toArray(),
|
|
'provider_resource_fingerprint' => $identity->fingerprint(),
|
|
],
|
|
'last_seen_at' => now(),
|
|
]);
|
|
}
|
|
|
|
public static function providerDescriptor(ResourceIdentity $identity, string $displayName): ProviderResourceDescriptor
|
|
{
|
|
return ProviderResourceDescriptor::fromIdentity(
|
|
identity: $identity,
|
|
subjectDomain: 'baseline',
|
|
subjectClass: SubjectClass::PolicyBacked,
|
|
subjectTypeKey: 'deviceConfiguration',
|
|
displayLabel: $displayName,
|
|
sourceReferences: [],
|
|
fingerprint: $identity->fingerprint(),
|
|
lastSeenAt: now()->toIso8601String(),
|
|
);
|
|
}
|
|
}
|