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.
169 lines
7.2 KiB
PHP
169 lines
7.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Services\Baselines\BaselineSubjectResolutionQuery;
|
|
use App\Support\Baselines\SubjectClass;
|
|
use App\Support\OperationRunOutcome;
|
|
use App\Support\OperationRunStatus;
|
|
use App\Support\Resources\ResourceIdentity;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\Feature\Baselines\Support\BaselineSubjectResolutionFixtures;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
it('derives actionable rows and candidates from persisted compare semantics and inventory identities', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
[$profile, $snapshot] = seedActiveBaselineForTenant($tenant);
|
|
$leftIdentity = ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-left');
|
|
$rightIdentity = ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-right');
|
|
|
|
BaselineSubjectResolutionFixtures::inventoryCandidate($tenant, $leftIdentity, 'Duplicate policy');
|
|
BaselineSubjectResolutionFixtures::inventoryCandidate($tenant, $rightIdentity, 'Duplicate policy');
|
|
$leftDescriptor = BaselineSubjectResolutionFixtures::providerDescriptor($leftIdentity, 'Duplicate policy');
|
|
$rightDescriptor = BaselineSubjectResolutionFixtures::providerDescriptor($rightIdentity, 'Duplicate policy');
|
|
|
|
$run = seedBaselineCompareRun(
|
|
tenant: $tenant,
|
|
profile: $profile,
|
|
snapshot: $snapshot,
|
|
compareContext: [
|
|
'result_semantics' => [
|
|
'version' => 1,
|
|
'subject_outcomes' => [
|
|
BaselineSubjectResolutionFixtures::semanticOutcome([
|
|
'reason' => 'unresolved_duplicate_candidates',
|
|
'actionability' => 'binding_required',
|
|
'readiness_impact' => 'customer_blocker',
|
|
'subject' => [
|
|
'subject_domain' => 'baseline',
|
|
'subject_class' => SubjectClass::PolicyBacked->value,
|
|
'subject_type_key' => 'deviceConfiguration',
|
|
'subject_key' => 'legacy-display-key',
|
|
'display_label' => 'Duplicate policy',
|
|
'candidate_descriptors' => [
|
|
$leftDescriptor->toArray(),
|
|
$rightDescriptor->toArray(),
|
|
],
|
|
],
|
|
]),
|
|
BaselineSubjectResolutionFixtures::semanticOutcome([
|
|
'reason' => 'verified_no_drift',
|
|
'actionability' => 'none',
|
|
'readiness_impact' => 'no_impact',
|
|
'subject' => [
|
|
'subject_type_key' => 'deviceConfiguration',
|
|
'subject_key' => 'resolved-subject',
|
|
'display_label' => 'Resolved subject',
|
|
],
|
|
]),
|
|
],
|
|
],
|
|
],
|
|
status: OperationRunStatus::Completed->value,
|
|
outcome: OperationRunOutcome::PartiallySucceeded->value,
|
|
);
|
|
|
|
$rows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
]);
|
|
|
|
expect($rows)->toHaveCount(1)
|
|
->and($rows[0]['reason'])->toBe('unresolved_duplicate_candidates')
|
|
->and($rows[0]['actionability'])->toBe('binding_required')
|
|
->and($rows[0]['candidate_count'])->toBe(2)
|
|
->and($rows[0]['decision_identity'])->toBeNull()
|
|
->and(collect($rows[0]['candidates'])->pluck('identity.provider_resource_id')->all())
|
|
->toContain('candidate-left', 'candidate-right');
|
|
|
|
expect(app(BaselineSubjectResolutionQuery::class)->rows($tenant, [
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
'actionability' => 'binding_required',
|
|
'readiness_impact' => 'customer_blocker',
|
|
'reason' => 'unresolved_duplicate_candidates',
|
|
'resource_type' => 'deviceConfiguration',
|
|
'candidates' => 'yes',
|
|
'active_binding' => 'no',
|
|
]))->toHaveCount(1);
|
|
|
|
$resolvedRows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
'include_resolved' => true,
|
|
]);
|
|
|
|
expect($resolvedRows)->toHaveCount(2);
|
|
});
|
|
|
|
it('does not derive bindable candidates from display label matches alone', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
[$profile, $snapshot] = seedActiveBaselineForTenant($tenant);
|
|
|
|
BaselineSubjectResolutionFixtures::inventoryCandidate(
|
|
$tenant,
|
|
ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-left'),
|
|
'Duplicate policy',
|
|
);
|
|
BaselineSubjectResolutionFixtures::inventoryCandidate(
|
|
$tenant,
|
|
ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-right'),
|
|
'Duplicate policy',
|
|
);
|
|
|
|
$run = seedBaselineCompareRun(
|
|
tenant: $tenant,
|
|
profile: $profile,
|
|
snapshot: $snapshot,
|
|
compareContext: [
|
|
'result_semantics' => [
|
|
'version' => 1,
|
|
'subject_outcomes' => [
|
|
BaselineSubjectResolutionFixtures::semanticOutcome([
|
|
'reason' => 'unresolved_duplicate_candidates',
|
|
'actionability' => 'binding_required',
|
|
'readiness_impact' => 'customer_blocker',
|
|
'subject' => [
|
|
'subject_domain' => 'baseline',
|
|
'subject_class' => SubjectClass::PolicyBacked->value,
|
|
'subject_type_key' => 'deviceConfiguration',
|
|
'subject_key' => 'legacy-display-key',
|
|
'display_label' => 'Duplicate policy',
|
|
],
|
|
]),
|
|
],
|
|
],
|
|
],
|
|
status: OperationRunStatus::Completed->value,
|
|
outcome: OperationRunOutcome::PartiallySucceeded->value,
|
|
);
|
|
|
|
$rows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
]);
|
|
|
|
expect($rows)->toHaveCount(1)
|
|
->and($rows[0]['candidate_count'])->toBe(0)
|
|
->and($rows[0]['candidates'])->toBe([]);
|
|
});
|
|
|
|
it('does not treat legacy evidence-gap payloads as authoritative subject decisions', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
[$profile, $snapshot] = seedActiveBaselineForTenant($tenant);
|
|
|
|
$run = seedBaselineCompareRun($tenant, $profile, $snapshot, [
|
|
'evidence_gaps' => [
|
|
'count' => 1,
|
|
'by_reason' => ['unresolved_duplicate_candidates' => 1],
|
|
'subjects' => [[
|
|
'policy_type' => 'deviceConfiguration',
|
|
'subject_key' => 'legacy-only',
|
|
'reason_code' => 'unresolved_duplicate_candidates',
|
|
]],
|
|
],
|
|
], outcome: OperationRunOutcome::PartiallySucceeded->value);
|
|
|
|
$query = app(BaselineSubjectResolutionQuery::class);
|
|
|
|
expect($query->rows($tenant, ['operation_run_id' => (int) $run->getKey()]))->toBe([])
|
|
->and($query->summary($tenant, (int) $run->getKey())['legacy_payload_only'])->toBeTrue();
|
|
});
|