TenantAtlas/apps/platform/tests/Unit/Support/TenantConfiguration/Spec420M365CaptureEligibilityTest.php
ahmido a73a8f5882 feat: complete m365 generic evidence coverage pack (#487)
Committing and publishing the current Spec 420 package changes.

Includes updated services, coverage tests, browser smoke coverage, and the spec/plan/tasks artifacts for the package.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #487
2026-06-27 12:24:00 +00:00

91 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Graph\GraphContractRegistry;
use App\Services\TenantConfiguration\CoverageSourceContractResolver;
use App\Models\TenantConfigurationResourceType;
use App\Services\TenantConfiguration\ResourceTypeRegistry;
use App\Support\TenantConfiguration\CaptureOutcome;
use App\Support\TenantConfiguration\ClaimState;
use App\Support\TenantConfiguration\CoverageLevel;
use App\Support\TenantConfiguration\EvidenceState;
use App\Support\TenantConfiguration\IdentityState;
use App\Support\TenantConfiguration\ResourceClass;
use App\Support\TenantConfiguration\RestoreTier;
use App\Support\TenantConfiguration\SourceClass;
use App\Support\TenantConfiguration\SupportState;
use App\Support\TenantConfiguration\Workload;
it('Spec420 never derives runtime endpoints from M365 source aliases', function (string $canonicalType): void {
$resourceType = spec420EligibilityResourceType($canonicalType);
$aliases = $resourceType->metadata['source_aliases'] ?? [];
$decision = (new CoverageSourceContractResolver(new GraphContractRegistry))->resolve($resourceType);
expect($aliases)->toBeArray()->not->toBeEmpty()
->and($decision->outcome)->toBe(CaptureOutcome::BlockedMissingContract)
->and($decision->sourceEndpoint)->toBeNull()
->and($decision->sourceMetadata['reason_code'])->toBe('missing_source_contract_mapping');
})->with([
'acceptedDomain',
'appPermissionPolicy',
'dlpCompliancePolicy',
]);
it('Spec420 keeps existing beta and unsupported outcomes instead of adding a new outcome family', function (): void {
$resolver = new CoverageSourceContractResolver(new GraphContractRegistry);
$beta = $resolver->resolve(spec420EligibilityAdHocResourceType(
canonicalType: 'roleScopeTag',
sourceClass: \App\Support\TenantConfiguration\SourceClass::GraphBetaExperimental,
supportState: \App\Support\TenantConfiguration\SupportState::Experimental,
));
$unsupported = $resolver->resolve(spec420EligibilityAdHocResourceType(
canonicalType: 'unsupportedResource',
supportState: \App\Support\TenantConfiguration\SupportState::Unsupported,
));
expect($beta->outcome)->toBe(CaptureOutcome::BlockedBeta)
->and($unsupported->outcome)->toBe(CaptureOutcome::BlockedUnsupported)
->and(CaptureOutcome::values())->toBe([
'captured',
'capture_blocked_missing_contract',
'capture_blocked_permission',
'capture_blocked_beta',
'capture_blocked_unsupported',
'capture_failed',
]);
});
function spec420EligibilityResourceType(string $canonicalType): TenantConfigurationResourceType
{
$definition = collect(ResourceTypeRegistry::defaultDefinitions())
->firstWhere('canonical_type', $canonicalType);
expect($definition)->not->toBeNull("Missing default resource type definition for {$canonicalType}.");
return new TenantConfigurationResourceType($definition);
}
function spec420EligibilityAdHocResourceType(
string $canonicalType,
SourceClass $sourceClass = SourceClass::Tcm,
SupportState $supportState = SupportState::Supported,
): TenantConfigurationResourceType {
return new TenantConfigurationResourceType([
'canonical_type' => $canonicalType,
'display_name' => $canonicalType,
'source_class' => $sourceClass->value,
'workload' => Workload::Intune->value,
'resource_class' => ResourceClass::Configuration->value,
'support_state' => $supportState->value,
'default_coverage_level' => CoverageLevel::ContentBacked->value,
'default_evidence_state' => EvidenceState::ContentBacked->value,
'default_identity_state' => IdentityState::Stable->value,
'default_claim_state' => ClaimState::ClaimAllowed->value,
'restore_tier' => RestoreTier::PreviewOnly->value,
'is_active' => true,
]);
}