TenantAtlas/apps/platform/tests/Pest.php
Ahmed Darrazi 549a9a0004
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m0s
feat: review pack output contract and readiness semantics (spec 347)
Implemented the output contract and readiness semantics for review packs. Also added spec 348.
Includes changes to ChooseEnvironment, CustomerReviewWorkspace, GenerateReviewPackJob and related blade views.
Added comprehensive tests.
2026-06-03 01:14:29 +02:00

1671 lines
57 KiB
PHP

<?php
use App\Models\BackupItem;
use App\Models\BackupSet;
use App\Models\BaselineProfile;
use App\Models\BaselineSnapshot;
use App\Models\BaselineTenantAssignment;
use App\Models\EnvironmentReview;
use App\Models\EnvironmentReviewSection;
use App\Models\EvidenceSnapshot;
use App\Models\Finding;
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentOnboardingSession;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ProviderCredential;
use App\Models\RestoreRun;
use App\Models\StoredReport;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Services\Auth\CapabilityResolver;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Services\EnvironmentReviews\EnvironmentReviewService;
use App\Services\Evidence\EvidenceSnapshotService;
use App\Services\Graph\GraphClientInterface;
use App\Services\Tenants\TenantActionPolicySurface;
use App\Support\EnvironmentReviewCompletenessState;
use App\Support\Evidence\EvidenceCompletenessState;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\Governance\Controls\ComplianceEvidenceMappingV1;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\Providers\ProviderConnectionType;
use App\Support\Providers\ProviderConsentStatus;
use App\Support\Providers\ProviderCredentialKind;
use App\Support\Providers\ProviderCredentialSource;
use App\Support\Providers\ProviderVerificationStatus;
use App\Support\Tenants\TenantActionDescriptor;
use App\Support\Tenants\TenantActionSurface;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Pest\PendingCalls\TestCall;
use Tests\Feature\Findings\Concerns\InteractsWithFindingsWorkflow;
use Tests\Support\AssertsNoOutboundHttp;
use Tests\Support\FailHardGraphClient;
/*
|--------------------------------------------------------------------------
| Test Case
|--------------------------------------------------------------------------
|
| The closure you provide to your test functions is always bound to a specific PHPUnit test
| case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
| need to change it using the "pest()" function to bind a different classes or traits.
|
*/
pest()->extend(Tests\TestCase::class)
->use(RefreshDatabase::class)
->in('Feature');
pest()->use(InteractsWithFindingsWorkflow::class)
->in('Feature/Findings', 'Feature/Audit');
pest()->extend(Tests\TestCase::class)
->use(RefreshDatabase::class)
->in('Browser');
pest()->extend(Tests\TestCase::class)
->in('Unit');
pest()->extend(Tests\TestCase::class)
->in('Architecture');
pest()->extend(Tests\TestCase::class)
->in('Deprecation');
pest()->group('browser')
->in('Browser');
pest()->group('ui-light')
->in(
'Feature/Filament/BackupSetAdminTenantParityTest.php',
);
pest()->group('ui-workflow')
->in(
'Feature/Baselines/BaselineCompareMatrixCompareAllActionTest.php',
'Feature/Baselines/BaselineCompareMatrixBuilderTest.php',
'Feature/Drift/DriftBulkAcknowledgeAllMatchingConfirmationTest.php',
'Feature/Findings/FindingExceptionRenewalTest.php',
'Feature/Findings/FindingsListFiltersTest.php',
'Feature/Findings/FindingWorkflowRowActionsTest.php',
'Feature/Findings/FindingWorkflowViewActionsTest.php',
'Feature/Filament/BaselineActionAuthorizationTest.php',
'Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php',
'Feature/Filament/BaselineProfileCompareStartSurfaceTest.php',
'Feature/Findings/FindingBulkActionsTest.php',
'Feature/SettingsFoundation/WorkspaceSettingsManageTest.php',
'Feature/Rbac/OnboardingWizardUiEnforcementTest.php',
);
pest()->group('surface-guard')
->in(
'Feature/OpsUx',
'Feature/Filament/Alerts/AlertsKpiHeaderTest.php',
'Feature/Filament/PanelNavigationSegregationTest.php',
'Feature/Filament/EnvironmentReviewHeaderDisciplineTest.php',
'Feature/Filament/WorkspaceOnlySurfaceTenantIndependenceTest.php',
'Feature/Guards/ActionSurfaceContractTest.php',
'Feature/Guards/OperationLifecycleOpsUxGuardTest.php',
'Feature/ProviderConnections/CredentialLeakGuardTest.php',
'Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php',
'Feature/Rbac/WorkspaceMembershipsRelationManagerUiEnforcementTest.php',
);
pest()->group('discovery-heavy')
->in(
'Feature/Filament/PolicyResourceAdminSearchParityTest.php',
'Feature/Filament/PolicyVersionAdminSearchParityTest.php',
);
beforeEach(function () {
putenv('INTUNE_TENANT_ID');
unset($_ENV['INTUNE_TENANT_ID'], $_SERVER['INTUNE_TENANT_ID']);
Filament::setCurrentPanel(null);
Filament::setTenant(null, true);
});
afterEach(function (): void {
Filament::setTenant(null, true);
Filament::setCurrentPanel(null);
});
/*
|--------------------------------------------------------------------------
| Expectations
|--------------------------------------------------------------------------
|
| When you're writing tests, you often need to check that values meet certain conditions. The
| "expect()" function gives you access to a set of "expectations" methods that you can use
| to assert different things. Of course, you may extend the Expectation API at any time.
|
*/
expect()->extend('toBeOne', function () {
return $this->toBe(1);
});
function fakeIdToken(string $tenantId): string
{
$header = rtrim(strtr(base64_encode(json_encode(['alg' => 'HS256', 'typ' => 'JWT'])), '+/', '-_'), '=');
$payload = rtrim(strtr(base64_encode(json_encode(['tid' => $tenantId])), '+/', '-_'), '=');
return $header.'.'.$payload.'.signature';
}
/*
|--------------------------------------------------------------------------
| Functions
|--------------------------------------------------------------------------
|
| While Pest is very powerful out-of-the-box, you may have some testing code specific to your
| project that you don't want to repeat in every file. Here you can also expose helpers as
| global functions to help you to reduce the number of lines of code in your test files.
|
*/
function something()
{
// ..
}
/**
* @return array{0: Workspace, 1: User}
*/
function localizationWorkspaceMember(string $role = 'manager'): array
{
$workspace = Workspace::factory()->create();
$user = User::factory()->create();
WorkspaceMembership::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'user_id' => (int) $user->getKey(),
'role' => $role,
]);
session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());
return [$workspace, $user];
}
function repo_root(): string
{
$configuredRoot = env('TENANTATLAS_REPO_ROOT');
if (is_string($configuredRoot) && $configuredRoot !== '') {
if (str_starts_with($configuredRoot, DIRECTORY_SEPARATOR)) {
return rtrim($configuredRoot, DIRECTORY_SEPARATOR);
}
$resolvedConfiguredRoot = realpath(base_path($configuredRoot));
if ($resolvedConfiguredRoot !== false) {
return $resolvedConfiguredRoot;
}
}
$resolvedDefaultRoot = realpath(base_path('../..'));
if ($resolvedDefaultRoot !== false) {
return $resolvedDefaultRoot;
}
return dirname(base_path(), 2);
}
function repo_path(string $path = ''): string
{
$root = repo_root();
if ($path === '') {
return $root;
}
return $root.DIRECTORY_SEPARATOR.ltrim($path, DIRECTORY_SEPARATOR);
}
/**
* @param array<string, mixed> $payload
* @param array<string, mixed> $overrides
* @return array<string, mixed>
*/
function mutateTrustedStatePayload(array $payload, array $overrides): array
{
return array_replace_recursive($payload, $overrides);
}
/**
* @param array<string, mixed> $data
* @param list<string> $errorKeys
*/
function assertScopedSelectorRejected(mixed $component, string $action, array $data, array $errorKeys = ['managed_environment_id']): mixed
{
return $component
->callAction($action, data: $data)
->assertHasActionErrors($errorKeys);
}
/**
* Spec test naming helper.
*
* Convention for focused runs:
* - Prefix every Spec 081 test title with "Spec081 ".
* - Keep filenames suffixed with "Spec081Test.php".
* - Command: `vendor/bin/sail artisan test --compact --filter=Spec081`
*/
function spec081(string $description): string
{
$normalized = trim($description);
if ($normalized === '') {
return 'Spec081';
}
return str_starts_with($normalized, 'Spec081 ')
? $normalized
: 'Spec081 '.$normalized;
}
/**
* Convenience wrapper for Spec 081 tests.
*/
function itSpec081(string $description, ?\Closure $closure = null): TestCall
{
$call = it(spec081($description), $closure);
$call->group('spec081');
return $call;
}
function bindFailHardGraphClient(): void
{
app()->instance(GraphClientInterface::class, new FailHardGraphClient);
}
function assertNoOutboundHttp(\Closure $callback): mixed
{
return AssertsNoOutboundHttp::run($callback);
}
/**
* @param array<string, mixed> $attributes
*/
function createInventorySyncOperationRun(ManagedEnvironment $tenant, array $attributes = []): \App\Models\OperationRun
{
$context = is_array($attributes['context'] ?? null) ? $attributes['context'] : [];
if (array_key_exists('selection_hash', $attributes)) {
if (is_string($attributes['selection_hash']) && $attributes['selection_hash'] !== '') {
$context['selection_hash'] = $attributes['selection_hash'];
}
unset($attributes['selection_hash']);
}
if (array_key_exists('selection_payload', $attributes)) {
if (is_array($attributes['selection_payload'])) {
$context = array_merge($context, $attributes['selection_payload']);
}
unset($attributes['selection_payload']);
}
if (! isset($context['selection_hash']) || ! is_string($context['selection_hash']) || $context['selection_hash'] === '') {
$context['selection_hash'] = hash('sha256', 'inventory-sync-selection-default');
}
if (! isset($context['policy_types']) || ! is_array($context['policy_types'])) {
$context['policy_types'] = ['deviceConfiguration'];
}
if (! isset($context['categories']) || ! is_array($context['categories'])) {
$context['categories'] = [];
}
if (! array_key_exists('include_foundations', $context)) {
$context['include_foundations'] = false;
}
if (! array_key_exists('include_dependencies', $context)) {
$context['include_dependencies'] = false;
}
$finishedAt = $attributes['finished_at'] ?? null;
unset($attributes['finished_at']);
$providedStatus = (string) ($attributes['status'] ?? 'success');
$normalizedStatus = match ($providedStatus) {
'pending', 'queued' => 'queued',
'running' => 'running',
'completed' => 'completed',
default => 'completed',
};
$normalizedOutcome = match ($providedStatus) {
'success' => 'succeeded',
'partial' => 'partially_succeeded',
'skipped' => 'blocked',
'failed' => 'failed',
'pending', 'queued', 'running' => 'pending',
default => $normalizedStatus === 'completed' ? 'succeeded' : 'pending',
};
$attributes['type'] = (string) ($attributes['type'] ?? 'inventory_sync');
$attributes['workspace_id'] = (int) ($attributes['workspace_id'] ?? $tenant->workspace_id);
$attributes['status'] = in_array($providedStatus, ['queued', 'running', 'completed'], true)
? $providedStatus
: $normalizedStatus;
$attributes['outcome'] = (string) ($attributes['outcome'] ?? $normalizedOutcome);
$attributes['context'] = array_merge($context, is_array($attributes['context'] ?? null) ? $attributes['context'] : []);
if ($finishedAt !== null && ! array_key_exists('completed_at', $attributes)) {
$attributes['completed_at'] = $finishedAt;
}
return \App\Models\OperationRun::factory()
->for($tenant)
->create($attributes);
}
/**
* Create a completed inventory sync run with coverage proof in context.
*
* @param array<string, string> $statusByType Example: ['deviceConfiguration' => 'succeeded']
* @param list<string> $foundationTypes
* @param array<string, mixed> $attributes
*/
function createInventorySyncOperationRunWithCoverage(
ManagedEnvironment $tenant,
array $statusByType,
array $foundationTypes = [],
array $attributes = [],
): \App\Models\OperationRun {
$context = is_array($attributes['context'] ?? null) ? $attributes['context'] : [];
$inventory = is_array($context['inventory'] ?? null) ? $context['inventory'] : [];
$inventory['coverage'] = \App\Support\Inventory\InventoryCoverage::buildPayload(
statusByType: $statusByType,
foundationTypes: $foundationTypes,
);
$context['inventory'] = $inventory;
$attributes['context'] = $context;
if (! array_key_exists('finished_at', $attributes) && ! array_key_exists('completed_at', $attributes)) {
$attributes['finished_at'] = now();
}
$attributes['type'] ??= \App\Support\OperationRunType::InventorySync->value;
$attributes['status'] ??= \App\Support\OperationRunStatus::Completed->value;
$attributes['outcome'] ??= \App\Support\OperationRunOutcome::Succeeded->value;
return createInventorySyncOperationRun($tenant, $attributes);
}
/**
* @return array<string, array{workspace: bool, membership: bool, session: bool, provider: bool, credential: bool, cache: bool, uiContext: bool}>
*/
function createUserWithTenantProfileCatalog(): array
{
return [
'minimal' => [
'workspace' => true,
'membership' => true,
'session' => true,
'provider' => false,
'credential' => false,
'cache' => false,
'uiContext' => false,
],
'standard' => [
'workspace' => true,
'membership' => true,
'session' => true,
'provider' => true,
'credential' => false,
'cache' => false,
'uiContext' => false,
],
'full' => [
'workspace' => true,
'membership' => true,
'session' => true,
'provider' => true,
'credential' => true,
'cache' => true,
'uiContext' => true,
],
];
}
/**
* @return array<string, array{profile: string, overrides?: array{workspace?: bool, membership?: bool, session?: bool, provider?: bool, credential?: bool, cache?: bool, uiContext?: bool}, removalTrigger: string}>
*/
function createUserWithTenantLegacyProfileAliases(): array
{
return [
'provider-enabled' => [
'profile' => 'standard',
'removalTrigger' => 'Retire after the first fast-feedback and confidence migration packs use the canonical standard profile directly.',
],
'credential-enabled' => [
'profile' => 'full',
'overrides' => [
'cache' => false,
'uiContext' => false,
],
'removalTrigger' => 'Retire after the credential-dependent caller pack adopts createFullUserWithTenant() or fixtureProfile: full plus local overrides.',
],
'ui-context' => [
'profile' => 'full',
'overrides' => [
'provider' => false,
'credential' => false,
],
'removalTrigger' => 'Retire after UI-context callers switch to the canonical full profile or an explicit local UI-context helper.',
],
'heavy' => [
'profile' => 'full',
'removalTrigger' => 'Retire after legacy heavy callers migrate to the canonical full profile.',
],
];
}
/**
* @return array{requestedProfile: string, canonicalProfile: string, sideEffects: array{workspace: bool, membership: bool, session: bool, provider: bool, credential: bool, cache: bool, uiContext: bool}, legacyAlias: ?string, removalTrigger: ?string}
*/
function resolveCreateUserWithTenantProfile(string $fixtureProfile): array
{
$catalog = createUserWithTenantProfileCatalog();
if (array_key_exists($fixtureProfile, $catalog)) {
return [
'requestedProfile' => $fixtureProfile,
'canonicalProfile' => $fixtureProfile,
'sideEffects' => $catalog[$fixtureProfile],
'legacyAlias' => null,
'removalTrigger' => null,
];
}
$aliases = createUserWithTenantLegacyProfileAliases();
if (! array_key_exists($fixtureProfile, $aliases)) {
throw new \InvalidArgumentException(sprintf('Unknown fixture profile [%s].', $fixtureProfile));
}
$resolution = $aliases[$fixtureProfile];
$canonicalProfile = $resolution['profile'];
if (! array_key_exists($canonicalProfile, $catalog)) {
throw new \InvalidArgumentException(sprintf('Unknown canonical fixture profile [%s].', $canonicalProfile));
}
return [
'requestedProfile' => $fixtureProfile,
'canonicalProfile' => $canonicalProfile,
'sideEffects' => array_replace($catalog[$canonicalProfile], $resolution['overrides'] ?? []),
'legacyAlias' => $fixtureProfile,
'removalTrigger' => $resolution['removalTrigger'],
];
}
/**
* @return array<string, array{workspace: bool, membership: bool, session: bool, provider: bool, credential: bool, cache: bool, uiContext: bool}>
*/
function createUserWithTenantProfiles(): array
{
$profiles = createUserWithTenantProfileCatalog();
foreach (createUserWithTenantLegacyProfileAliases() as $alias => $resolution) {
$profiles[$alias] = array_replace(
$profiles[$resolution['profile']],
$resolution['overrides'] ?? [],
);
}
return $profiles;
}
/**
* @return array{0: User, 1: ManagedEnvironment}
*/
function createMinimalUserWithTenant(
?ManagedEnvironment $tenant = null,
?User $user = null,
string $role = 'owner',
?string $workspaceRole = null,
bool $ensureDefaultMicrosoftProviderConnection = false,
string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
bool $ensureDefaultCredential = false,
?bool $clearCapabilityCaches = null,
?bool $setUiContext = null,
): array {
return createUserWithTenant(
tenant: $tenant,
user: $user,
role: $role,
workspaceRole: $workspaceRole,
ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
defaultProviderConnectionType: $defaultProviderConnectionType,
fixtureProfile: 'minimal',
ensureDefaultCredential: $ensureDefaultCredential,
clearCapabilityCaches: $clearCapabilityCaches,
setUiContext: $setUiContext,
);
}
/**
* @return array{0: User, 1: ManagedEnvironment}
*/
function createStandardUserWithTenant(
?ManagedEnvironment $tenant = null,
?User $user = null,
string $role = 'owner',
?string $workspaceRole = null,
bool $ensureDefaultMicrosoftProviderConnection = false,
string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
bool $ensureDefaultCredential = false,
?bool $clearCapabilityCaches = null,
?bool $setUiContext = null,
): array {
return createUserWithTenant(
tenant: $tenant,
user: $user,
role: $role,
workspaceRole: $workspaceRole,
ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
defaultProviderConnectionType: $defaultProviderConnectionType,
fixtureProfile: 'standard',
ensureDefaultCredential: $ensureDefaultCredential,
clearCapabilityCaches: $clearCapabilityCaches,
setUiContext: $setUiContext,
);
}
/**
* @return array{0: User, 1: ManagedEnvironment}
*/
function createFullUserWithTenant(
?ManagedEnvironment $tenant = null,
?User $user = null,
string $role = 'owner',
?string $workspaceRole = null,
bool $ensureDefaultMicrosoftProviderConnection = false,
string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
bool $ensureDefaultCredential = false,
?bool $clearCapabilityCaches = null,
?bool $setUiContext = null,
): array {
return createUserWithTenant(
tenant: $tenant,
user: $user,
role: $role,
workspaceRole: $workspaceRole,
ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
defaultProviderConnectionType: $defaultProviderConnectionType,
fixtureProfile: 'full',
ensureDefaultCredential: $ensureDefaultCredential,
clearCapabilityCaches: $clearCapabilityCaches,
setUiContext: $setUiContext,
);
}
/**
* @return array{0: User, 1: ManagedEnvironment}
*/
function createProviderEnabledUserWithTenant(
?ManagedEnvironment $tenant = null,
?User $user = null,
string $role = 'owner',
?string $workspaceRole = null,
bool $ensureDefaultMicrosoftProviderConnection = false,
string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
bool $ensureDefaultCredential = false,
?bool $clearCapabilityCaches = null,
?bool $setUiContext = null,
): array {
return createUserWithTenant(
tenant: $tenant,
user: $user,
role: $role,
workspaceRole: $workspaceRole,
ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
defaultProviderConnectionType: $defaultProviderConnectionType,
fixtureProfile: 'provider-enabled',
ensureDefaultCredential: $ensureDefaultCredential,
clearCapabilityCaches: $clearCapabilityCaches,
setUiContext: $setUiContext,
);
}
/**
* @return array{0: User, 1: ManagedEnvironment}
*/
function createCredentialEnabledUserWithTenant(
?ManagedEnvironment $tenant = null,
?User $user = null,
string $role = 'owner',
?string $workspaceRole = null,
bool $ensureDefaultMicrosoftProviderConnection = false,
string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
bool $ensureDefaultCredential = false,
?bool $clearCapabilityCaches = null,
?bool $setUiContext = null,
): array {
return createUserWithTenant(
tenant: $tenant,
user: $user,
role: $role,
workspaceRole: $workspaceRole,
ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
defaultProviderConnectionType: $defaultProviderConnectionType,
fixtureProfile: 'credential-enabled',
ensureDefaultCredential: $ensureDefaultCredential,
clearCapabilityCaches: $clearCapabilityCaches,
setUiContext: $setUiContext,
);
}
/**
* @return array{0: User, 1: ManagedEnvironment}
*/
function createUiContextUserWithTenant(
?ManagedEnvironment $tenant = null,
?User $user = null,
string $role = 'owner',
?string $workspaceRole = null,
bool $ensureDefaultMicrosoftProviderConnection = false,
string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
bool $ensureDefaultCredential = false,
?bool $clearCapabilityCaches = null,
?bool $setUiContext = null,
): array {
return createUserWithTenant(
tenant: $tenant,
user: $user,
role: $role,
workspaceRole: $workspaceRole,
ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
defaultProviderConnectionType: $defaultProviderConnectionType,
fixtureProfile: 'ui-context',
ensureDefaultCredential: $ensureDefaultCredential,
clearCapabilityCaches: $clearCapabilityCaches,
setUiContext: $setUiContext,
);
}
/**
* @return array{0: User, 1: ManagedEnvironment}
*/
function createHeavyUserWithTenant(
?ManagedEnvironment $tenant = null,
?User $user = null,
string $role = 'owner',
?string $workspaceRole = null,
bool $ensureDefaultMicrosoftProviderConnection = false,
string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
bool $ensureDefaultCredential = false,
?bool $clearCapabilityCaches = null,
?bool $setUiContext = null,
): array {
return createUserWithTenant(
tenant: $tenant,
user: $user,
role: $role,
workspaceRole: $workspaceRole,
ensureDefaultMicrosoftProviderConnection: $ensureDefaultMicrosoftProviderConnection,
defaultProviderConnectionType: $defaultProviderConnectionType,
fixtureProfile: 'heavy',
ensureDefaultCredential: $ensureDefaultCredential,
clearCapabilityCaches: $clearCapabilityCaches,
setUiContext: $setUiContext,
);
}
/**
* @return array{0: User, 1: ManagedEnvironment}
*/
function createUserWithTenant(
?ManagedEnvironment $tenant = null,
?User $user = null,
string $role = 'owner',
?string $workspaceRole = null,
bool $ensureDefaultMicrosoftProviderConnection = false,
string $defaultProviderConnectionType = ProviderConnectionType::Dedicated->value,
string $fixtureProfile = 'minimal',
bool $ensureDefaultCredential = false,
?bool $clearCapabilityCaches = null,
?bool $setUiContext = null,
): array {
$resolvedProfile = resolveCreateUserWithTenantProfile($fixtureProfile);
$profile = $resolvedProfile['sideEffects'];
$user ??= User::factory()->create();
$tenant ??= ManagedEnvironment::factory()->create();
$workspaceRole ??= $role;
$validWorkspaceRoles = array_map(
static fn (\App\Support\Auth\WorkspaceRole $role): string => $role->value,
\App\Support\Auth\WorkspaceRole::cases(),
);
if (! in_array($workspaceRole, $validWorkspaceRoles, true)) {
$workspaceRole = \App\Support\Auth\WorkspaceRole::Owner->value;
}
$workspace = null;
if ($tenant->workspace_id !== null) {
$workspace = Workspace::query()->whereKey($tenant->workspace_id)->first();
}
if (! $workspace instanceof Workspace) {
$workspace = Workspace::factory()->create();
$tenant->forceFill([
'workspace_id' => (int) $workspace->getKey(),
])->save();
}
if ($profile['membership']) {
WorkspaceMembership::query()->updateOrCreate([
'workspace_id' => (int) $workspace->getKey(),
'user_id' => (int) $user->getKey(),
], [
'role' => $workspaceRole,
]);
}
if ($profile['session']) {
session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());
$user->forceFill(['last_workspace_id' => (int) $workspace->getKey()])->save();
}
$user->tenants()->syncWithoutDetaching([
$tenant->getKey() => ['role' => $role],
]);
$shouldClearCapabilityCaches = $clearCapabilityCaches ?? $profile['cache'];
if ($shouldClearCapabilityCaches) {
app(CapabilityResolver::class)->clearCache();
app(WorkspaceCapabilityResolver::class)->clearCache();
}
$shouldEnsureProviderConnection = $ensureDefaultMicrosoftProviderConnection || $profile['provider'];
$shouldEnsureCredential = $ensureDefaultCredential || $profile['credential'];
if ($shouldEnsureProviderConnection) {
ensureDefaultProviderConnection(
$tenant,
'microsoft',
$defaultProviderConnectionType,
$shouldEnsureCredential,
);
}
$shouldSetUiContext = $setUiContext ?? $profile['uiContext'];
if ($shouldSetUiContext) {
$tenant->makeCurrent();
Filament::setTenant($tenant, true);
}
return [$user, $tenant];
}
function baselineCompareLandingLivewire(
ManagedEnvironment $tenant,
array $queryParams = [],
?\Illuminate\Contracts\Auth\Authenticatable $user = null,
): mixed
{
$manager = \Livewire\Livewire::withHeaders([
'Referer' => \App\Support\ManagedEnvironmentLinks::baselineCompareUrl($tenant),
]);
if ($user instanceof \Illuminate\Contracts\Auth\Authenticatable) {
$manager = $manager->actingAs($user);
}
if ($queryParams !== []) {
$manager = $manager->withQueryParams($queryParams);
}
return $manager->test(\App\Filament\Pages\BaselineCompareLanding::class, [
'environment' => $tenant,
]);
}
/**
* @return array{0: BaselineProfile, 1: BaselineSnapshot}
*/
function seedActiveBaselineForTenant(ManagedEnvironment $tenant): array
{
$profile = BaselineProfile::factory()->active()->create([
'workspace_id' => (int) $tenant->workspace_id,
]);
$snapshot = BaselineSnapshot::factory()->complete()->create([
'workspace_id' => (int) $tenant->workspace_id,
'baseline_profile_id' => (int) $profile->getKey(),
]);
$profile->forceFill([
'active_snapshot_id' => (int) $snapshot->getKey(),
])->save();
BaselineTenantAssignment::query()->updateOrCreate([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
], [
'baseline_profile_id' => (int) $profile->getKey(),
'override_scope_jsonb' => null,
]);
return [$profile, $snapshot];
}
/**
* @param array<string, mixed> $compareContext
*/
function seedBaselineCompareRun(
ManagedEnvironment $tenant,
BaselineProfile $profile,
BaselineSnapshot $snapshot,
array $compareContext = [],
string $status = OperationRunStatus::Completed->value,
string $outcome = OperationRunOutcome::Succeeded->value,
?\Carbon\CarbonInterface $completedAt = null,
): OperationRun {
$completedAt ??= now();
return OperationRun::factory()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'type' => OperationRunType::BaselineCompare->value,
'status' => $status,
'outcome' => $outcome,
'created_at' => $completedAt,
'completed_at' => $status === OperationRunStatus::Completed->value ? $completedAt : null,
'context' => [
'baseline_profile_id' => (int) $profile->getKey(),
'baseline_snapshot_id' => (int) $snapshot->getKey(),
'baseline_compare' => $compareContext,
],
]);
}
/**
* @return array<string, mixed>
*/
function workspaceOverviewCompareCoverage(): array
{
return [
'reason_code' => \App\Support\Baselines\BaselineCompareReasonCode::NoDriftDetected->value,
'coverage' => [
'effective_types' => ['deviceConfiguration'],
'covered_types' => ['deviceConfiguration'],
'uncovered_types' => [],
'proof' => true,
],
];
}
function workspaceOverviewSeedQuietTenantTruth(ManagedEnvironment $tenant): void
{
[$profile, $snapshot] = seedActiveBaselineForTenant($tenant);
seedBaselineCompareRun($tenant, $profile, $snapshot, workspaceOverviewCompareCoverage());
}
/**
* @param array<string, mixed> $backupSetAttributes
* @param array<string, mixed> $itemAttributes
*/
function workspaceOverviewSeedHealthyBackup(
ManagedEnvironment $tenant,
array $backupSetAttributes = [],
array $itemAttributes = [],
): BackupSet {
$backupSet = BackupSet::factory()
->for($tenant)
->create(array_merge([
'name' => 'Workspace overview healthy backup',
'item_count' => 1,
'completed_at' => now()->subMinutes(20),
], $backupSetAttributes));
BackupItem::factory()
->for($tenant)
->for($backupSet)
->create(array_merge([
'payload' => ['id' => 'workspace-overview-policy'],
'metadata' => [],
'assignments' => [],
], $itemAttributes));
return $backupSet;
}
/**
* @param array<string, mixed> $attributes
*/
function workspaceOverviewSeedRestoreHistory(
ManagedEnvironment $tenant,
BackupSet $backupSet,
string $state = 'completed',
array $attributes = [],
): RestoreRun {
$factory = match ($state) {
'failed' => RestoreRun::factory()->failedOutcome(),
'partial' => RestoreRun::factory()->partialOutcome(),
'follow_up' => RestoreRun::factory()->completedWithFollowUp(),
default => RestoreRun::factory()->completedOutcome(),
};
return $factory
->for($tenant)
->for($backupSet)
->create(array_merge([
'completed_at' => now()->subMinutes(10),
], $attributes));
}
/**
* @return array{tenant: string}
*/
function filamentTenantRouteParams(ManagedEnvironment $tenant): array
{
return ['tenant' => (string) $tenant->external_id];
}
function ensureDefaultProviderConnection(
ManagedEnvironment $tenant,
string $provider = 'microsoft',
string $connectionType = ProviderConnectionType::Dedicated->value,
bool $ensureCredential = true,
): ProviderConnection {
$resolvedConnectionType = ProviderConnectionType::tryFrom($connectionType) ?? ProviderConnectionType::Dedicated;
$connection = ProviderConnection::query()
->where('managed_environment_id', (int) $tenant->getKey())
->where('provider', $provider)
->orderByDesc('is_default')
->orderBy('id')
->first();
if (! $connection instanceof ProviderConnection) {
$connectionFactory = ProviderConnection::factory();
if ($resolvedConnectionType === ProviderConnectionType::Dedicated) {
$connectionFactory = $connectionFactory->dedicated();
}
$connection = $connectionFactory->verifiedHealthy()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'provider' => $provider,
'entra_tenant_id' => (string) ($tenant->managed_environment_id ?? fake()->uuid()),
'connection_type' => $resolvedConnectionType->value,
'is_default' => true,
]);
} else {
$entraTenantId = trim((string) $connection->entra_tenant_id);
$currentConnectionType = $connection->connection_type instanceof ProviderConnectionType
? $connection->connection_type->value
: (is_string($connection->connection_type) ? $connection->connection_type : null);
$currentConsentStatus = $connection->consent_status instanceof ProviderConsentStatus
? $connection->consent_status->value
: (is_string($connection->consent_status) ? $connection->consent_status : null);
$currentVerificationStatus = $connection->verification_status instanceof ProviderVerificationStatus
? $connection->verification_status->value
: (is_string($connection->verification_status) ? $connection->verification_status : null);
$updates = [];
if ($currentConnectionType !== $resolvedConnectionType->value) {
$updates['connection_type'] = $resolvedConnectionType->value;
}
if (! $connection->is_default) {
$updates['is_default'] = true;
}
if (! $connection->is_enabled) {
$updates['is_enabled'] = true;
}
if ($currentConsentStatus !== ProviderConsentStatus::Granted->value) {
$updates['consent_status'] = ProviderConsentStatus::Granted->value;
}
if ($currentVerificationStatus !== ProviderVerificationStatus::Healthy->value) {
$updates['verification_status'] = ProviderVerificationStatus::Healthy->value;
}
if ($entraTenantId === '') {
$updates['entra_tenant_id'] = (string) ($tenant->managed_environment_id ?? fake()->uuid());
}
if (! array_key_exists('consent_granted_at', $updates)) {
$updates['consent_granted_at'] = now();
}
if (! array_key_exists('consent_last_checked_at', $updates)) {
$updates['consent_last_checked_at'] = now();
}
if (! array_key_exists('last_health_check_at', $updates)) {
$updates['last_health_check_at'] = now();
}
if (! array_key_exists('migration_review_required', $updates)) {
$updates['migration_review_required'] = false;
}
if ($updates !== []) {
$connection->forceFill($updates)->save();
$connection->refresh();
}
}
$credential = $connection->credential()->first();
if ($resolvedConnectionType === ProviderConnectionType::Platform) {
if ($credential instanceof ProviderCredential) {
$credential->delete();
$connection->refresh();
}
return $connection;
}
if (! $ensureCredential) {
if ($credential instanceof ProviderCredential) {
$credential->delete();
$connection->refresh();
}
return $connection;
}
if (! $credential instanceof ProviderCredential) {
ProviderCredential::factory()->create([
'provider_connection_id' => (int) $connection->getKey(),
'type' => ProviderCredentialKind::ClientSecret->value,
'credential_kind' => ProviderCredentialKind::ClientSecret->value,
'source' => ProviderCredentialSource::DedicatedManual->value,
'last_rotated_at' => now(),
'expires_at' => now()->addYear(),
'payload' => [
'client_id' => fake()->uuid(),
'client_secret' => fake()->sha1(),
],
]);
$connection->refresh();
}
return $connection;
}
if (! function_exists('spec283ConfiguredPermissionRows')) {
function spec283ConfiguredPermissionRows(): array
{
return array_merge(
config('intune_permissions.permissions', []),
config('entra_permissions.permissions', []),
);
}
}
if (! function_exists('spec283SeedRequirementRows')) {
function spec283SeedRequirementRows(ManagedEnvironment $tenant, array $requirementKeys, array $missingKeys = [], array $errorKeys = []): void
{
foreach (spec283ConfiguredPermissionRows() as $permission) {
if (! is_array($permission)) {
continue;
}
$mappedRequirementKeys = \App\Support\Verification\ManagedEnvironmentPermissionCheckClusters::requirementKeysForPermissionRow($permission);
if (array_intersect($requirementKeys, $mappedRequirementKeys) === []) {
continue;
}
$permissionKey = (string) ($permission['key'] ?? '');
\App\Models\ManagedEnvironmentPermission::query()->updateOrCreate(
[
'managed_environment_id' => (int) $tenant->getKey(),
'permission_key' => $permissionKey,
'workspace_id' => (int) $tenant->workspace_id,
],
[
'status' => in_array($permissionKey, $errorKeys, true)
? 'error'
: (in_array($permissionKey, $missingKeys, true) ? 'missing' : 'granted'),
'details' => ['source' => 'spec-283-test'],
'last_checked_at' => now(),
],
);
}
}
}
/**
* @param array<string, mixed> $permissionPayload
* @param array<string, mixed> $rolePayload
*/
function seedEnvironmentReviewEvidence(
ManagedEnvironment $tenant,
array $permissionPayload = [],
array $rolePayload = [],
int $findingCount = 3,
int $driftCount = 1,
int $operationRunCount = 1,
): EvidenceSnapshot {
StoredReport::factory()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'report_type' => StoredReport::REPORT_TYPE_PERMISSION_POSTURE,
'payload' => array_replace_recursive([
'posture_score' => 86,
'required_count' => 14,
'granted_count' => 12,
'permissions' => [
['key' => 'DeviceManagementConfiguration.ReadWrite.All', 'status' => 'granted'],
],
], $permissionPayload),
]);
StoredReport::factory()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'report_type' => StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES,
'payload' => array_replace_recursive([
'roles' => [
[
'displayName' => 'Global Administrator',
'userPrincipalName' => 'admin@contoso.com',
],
],
], $rolePayload),
]);
Finding::factory()
->count($findingCount)
->create([
'managed_environment_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
]);
Finding::factory()
->count($driftCount)
->create([
'managed_environment_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'finding_type' => Finding::FINDING_TYPE_DRIFT,
]);
OperationRun::factory()
->count($operationRunCount)
->forTenant($tenant)
->create([
'type' => OperationRunType::PolicySync->value,
]);
/** @var EvidenceSnapshotService $service */
$service = app(EvidenceSnapshotService::class);
$payload = $service->buildSnapshotPayload($tenant);
$snapshot = EvidenceSnapshot::query()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'status' => EvidenceSnapshotStatus::Active->value,
'fingerprint' => $payload['fingerprint'],
'completeness_state' => $payload['completeness'],
'summary' => $payload['summary'],
'generated_at' => now(),
]);
foreach ($payload['items'] as $item) {
$snapshot->items()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'dimension_key' => $item['dimension_key'],
'state' => $item['state'],
'required' => $item['required'],
'source_kind' => $item['source_kind'],
'source_record_type' => $item['source_record_type'],
'source_record_id' => $item['source_record_id'],
'source_fingerprint' => $item['source_fingerprint'],
'measured_at' => $item['measured_at'],
'freshness_at' => $item['freshness_at'],
'summary_payload' => $item['summary_payload'],
'sort_order' => $item['sort_order'],
]);
}
return $snapshot->load('items');
}
/**
* @param array<string, mixed> $permissionPayload
* @param array<string, mixed> $rolePayload
*/
function seedStaleEnvironmentReviewEvidence(
ManagedEnvironment $tenant,
array $permissionPayload = [],
array $rolePayload = [],
int $findingCount = 3,
int $driftCount = 1,
int $operationRunCount = 1,
array $summaryOverrides = [],
): EvidenceSnapshot {
$snapshot = seedEnvironmentReviewEvidence(
tenant: $tenant,
permissionPayload: $permissionPayload,
rolePayload: $rolePayload,
findingCount: $findingCount,
driftCount: $driftCount,
operationRunCount: $operationRunCount,
);
return restateEnvironmentReviewEvidenceSnapshot(
$snapshot,
EvidenceCompletenessState::Stale,
array_replace([
'missing_dimensions' => 0,
'stale_dimensions' => 2,
], $summaryOverrides),
);
}
/**
* @param array<string, mixed> $permissionPayload
* @param array<string, mixed> $rolePayload
*/
function seedPartialEnvironmentReviewEvidence(
ManagedEnvironment $tenant,
array $permissionPayload = [],
array $rolePayload = [],
int $findingCount = 3,
int $driftCount = 1,
int $operationRunCount = 1,
array $summaryOverrides = [],
): EvidenceSnapshot {
$snapshot = seedEnvironmentReviewEvidence(
tenant: $tenant,
permissionPayload: $permissionPayload,
rolePayload: $rolePayload,
findingCount: $findingCount,
driftCount: $driftCount,
operationRunCount: $operationRunCount,
);
return restateEnvironmentReviewEvidenceSnapshot(
$snapshot,
EvidenceCompletenessState::Partial,
array_replace([
'missing_dimensions' => 1,
'stale_dimensions' => 0,
], $summaryOverrides),
);
}
function composeEnvironmentReviewForTest(ManagedEnvironment $tenant, User $user, ?EvidenceSnapshot $snapshot = null): EnvironmentReview
{
$snapshot ??= seedEnvironmentReviewEvidence($tenant);
/** @var EnvironmentReviewService $service */
$service = app(EnvironmentReviewService::class);
$review = $service->create($tenant, $snapshot, $user);
$review = $review->refresh();
if ($review->generated_at === null || ! $review->sections()->exists()) {
$review = $service->compose($review);
}
return $review->refresh();
}
function markEnvironmentReviewCustomerSafeReady(EnvironmentReview $review): EnvironmentReview
{
$review->loadMissing(['sections', 'evidenceSnapshot.items']);
$disclosure = 'TenantPilot interprets available evidence for review readiness. This is not a certification, legal attestation, or compliance guarantee.';
$controlSummary = [
'control_key' => 'customer-output',
'control_name' => 'Customer output',
'domain_key' => 'customer_delivery',
'readiness_bucket' => 'evidence_on_record',
'readiness_label' => 'Evidence on record',
'limitation_flags' => [],
'limitation_labels' => [],
'customer_summary' => 'Customer output has evidence on record in this released review.',
'evidence_basis_summary' => '1 evidence signal references this control.',
'accepted_risk_summary' => null,
'recommended_next_action' => 'Open the current customer review pack.',
'detail_anchor' => 'control-customer-output',
'supporting_finding_ids' => [],
'finding_count' => 0,
'open_finding_count' => 0,
'accepted_risk_count' => 0,
];
$controlExplanation = [
'title' => 'Customer output',
'control_key' => 'customer-output',
'control_name' => 'Customer output',
'readiness_bucket' => 'evidence_on_record',
'readiness_label' => 'Evidence on record',
'limitation_flags' => [],
'limitation_labels' => [],
'customer_summary' => 'Customer output has evidence on record in this released review.',
'evidence_basis_summary' => '1 evidence signal references this control.',
'accepted_risk_summary' => null,
'explanation_text' => 'Customer output has evidence on record in this released review.',
'evidence_basis_items' => [
'1 evidence signal references this control.',
],
'accepted_risk_context' => null,
'recommended_next_action' => 'Open the current customer review pack.',
'proof_access_state' => 'available',
'supporting_finding_ids' => [],
];
$snapshot = $review->evidenceSnapshot;
if ($snapshot instanceof EvidenceSnapshot) {
$snapshot->items->each(function ($item): void {
$item->forceFill([
'state' => EnvironmentReviewCompletenessState::Complete->value,
])->save();
});
$snapshotSummary = is_array($snapshot->summary) ? $snapshot->summary : [];
$snapshotSummary['missing_dimensions'] = 0;
$snapshotSummary['stale_dimensions'] = 0;
$snapshotSummary['dimensions'] = collect($snapshotSummary['dimensions'] ?? [])
->map(static function (mixed $dimension): mixed {
if (! is_array($dimension)) {
return $dimension;
}
$dimension['state'] = EnvironmentReviewCompletenessState::Complete->value;
return $dimension;
})
->values()
->all();
$snapshot->forceFill([
'completeness_state' => EnvironmentReviewCompletenessState::Complete->value,
'summary' => $snapshotSummary,
])->save();
}
$review->sections->each(function (EnvironmentReviewSection $section) use ($controlSummary, $controlExplanation, $disclosure): void {
$attributes = [
'completeness_state' => EnvironmentReviewCompletenessState::Complete->value,
];
if ($section->isControlInterpretation()) {
$attributes['summary_payload'] = array_replace_recursive([
'version_key' => ComplianceEvidenceMappingV1::VERSION_KEY,
'display_label' => 'Compliance evidence mapping v1',
'non_certification_disclosure' => $disclosure,
'mapped_control_count' => 1,
'follow_up_required_count' => 0,
'limitation_counts' => [],
'limitations' => [],
], is_array($section->summary_payload) ? $section->summary_payload : []);
$attributes['render_payload'] = array_replace_recursive([
'entries' => [$controlExplanation],
'disclosure' => $disclosure,
'next_actions' => ['Open the current customer review pack.'],
'empty_state' => null,
], is_array($section->render_payload) ? $section->render_payload : []);
}
$section->forceFill($attributes)->save();
});
$sectionCount = $review->sections->count();
$summary = is_array($review->summary) ? $review->summary : [];
$existingControlInterpretation = is_array($summary['control_interpretation'] ?? null)
? $summary['control_interpretation']
: [];
$existingControls = collect($existingControlInterpretation['controls'] ?? [])
->filter(static fn (mixed $control): bool => is_array($control))
->values();
$summary['control_interpretation'] = array_replace_recursive([
'version_key' => ComplianceEvidenceMappingV1::VERSION_KEY,
'display_label' => 'Compliance evidence mapping v1',
'non_certification_disclosure' => $disclosure,
'mapped_control_count' => 1,
'follow_up_required_count' => 0,
'limitation_counts' => [],
'limitations' => [],
'controls' => [$controlSummary],
], $existingControlInterpretation);
$summary['control_interpretation']['controls'] = [
array_replace(
$controlSummary,
is_array($existingControls->first()) ? $existingControls->first() : [],
),
];
$summary['publish_blockers'] = [];
$summary['section_count'] = $sectionCount;
$summary['section_state_counts'] = [
'complete' => $sectionCount,
'partial' => 0,
'missing' => 0,
'stale' => 0,
];
$review->forceFill([
'completeness_state' => EnvironmentReviewCompletenessState::Complete->value,
'summary' => $summary,
])->save();
return $review->refresh();
}
/**
* @param array<string, mixed> $summaryOverrides
*/
function restateEnvironmentReviewEvidenceSnapshot(
EvidenceSnapshot $snapshot,
EvidenceCompletenessState $completenessState,
array $summaryOverrides = [],
): EvidenceSnapshot {
$summary = is_array($snapshot->summary) ? $snapshot->summary : [];
$summary = array_replace($summary, match ($completenessState) {
EvidenceCompletenessState::Stale => [
'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
'missing_dimensions' => 0,
'stale_dimensions' => max(1, (int) ($summary['stale_dimensions'] ?? 1)),
],
EvidenceCompletenessState::Partial => [
'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
'missing_dimensions' => max(1, (int) ($summary['missing_dimensions'] ?? 1)),
'stale_dimensions' => 0,
],
EvidenceCompletenessState::Missing => [
'dimension_count' => (int) ($summary['dimension_count'] ?? 0),
'missing_dimensions' => max(1, (int) ($summary['missing_dimensions'] ?? 1)),
'stale_dimensions' => 0,
],
EvidenceCompletenessState::Complete => [
'dimension_count' => max(1, (int) ($summary['dimension_count'] ?? 5)),
'missing_dimensions' => 0,
'stale_dimensions' => 0,
],
});
$summary = array_replace_recursive($summary, $summaryOverrides);
$snapshot->forceFill([
'completeness_state' => $completenessState->value,
'summary' => $summary,
])->save();
$primaryItem = $snapshot->items()->where('required', true)->orderBy('sort_order')->first();
if ($primaryItem !== null) {
$primaryItem->forceFill([
'state' => $completenessState->value,
'measured_at' => $completenessState === EvidenceCompletenessState::Stale
? now()->subDays(45)
: ($primaryItem->measured_at ?? now()),
'freshness_at' => $completenessState === EvidenceCompletenessState::Stale
? now()->subDays(45)
: ($primaryItem->freshness_at ?? now()),
])->save();
}
return $snapshot->fresh('items');
}
function setAdminEnvironmentContext(ManagedEnvironment $tenant): void
{
setAdminPanelContext($tenant);
}
/**
* Set the workspace-first admin panel context for tests. There is no TenantPanel compatibility helper.
*/
function setAdminPanelContext(?ManagedEnvironment $tenant = null): void
{
if ($tenant instanceof ManagedEnvironment) {
$tenant->makeCurrent();
}
Filament::setCurrentPanel('admin');
Filament::setTenant($tenant, true);
Filament::bootCurrentPanel();
}
/**
* @param array<string, mixed> $attributes
*/
function createOnboardingDraft(array $attributes = []): ManagedEnvironmentOnboardingSession
{
$workspace = $attributes['workspace'] ?? Workspace::factory()->create();
$tenant = $attributes['tenant'] ?? null;
$startedBy = $attributes['started_by'] ?? User::factory()->create();
$updatedBy = $attributes['updated_by'] ?? $startedBy;
foreach ([$startedBy, $updatedBy] as $member) {
if (! $member instanceof User) {
continue;
}
WorkspaceMembership::query()->firstOrCreate([
'workspace_id' => (int) $workspace->getKey(),
'user_id' => (int) $member->getKey(),
], [
'role' => 'owner',
]);
}
$factory = ManagedEnvironmentOnboardingSession::factory()
->forWorkspace($workspace)
->startedBy($startedBy)
->updatedBy($updatedBy);
if ($tenant instanceof ManagedEnvironment) {
$factory = $factory->forTenant($tenant);
}
if (($attributes['status'] ?? null) === 'completed') {
$factory = $factory->completed();
}
if (($attributes['status'] ?? null) === 'cancelled') {
$factory = $factory->cancelled();
}
unset(
$attributes['workspace'],
$attributes['tenant'],
$attributes['started_by'],
$attributes['updated_by'],
$attributes['status'],
);
return $factory->create($attributes);
}
/**
* @return list<TenantActionDescriptor>
*/
function tenantActionCatalog(ManagedEnvironment $tenant, TenantActionSurface $surface, ?User $user = null): array
{
return app(TenantActionPolicySurface::class)->catalogForTenant($tenant, $surface, $user);
}
/**
* @param list<TenantActionDescriptor> $actions
* @return list<string>
*/
function tenantActionKeys(array $actions): array
{
return array_values(array_map(
static fn (TenantActionDescriptor $action): string => $action->key,
$actions,
));
}
function ensureDefaultPlatformProviderConnection(ManagedEnvironment $tenant, string $provider = 'microsoft'): ProviderConnection
{
return ensureDefaultProviderConnection($tenant, $provider, ProviderConnectionType::Platform->value);
}
function ensureDefaultDedicatedProviderConnection(ManagedEnvironment $tenant, string $provider = 'microsoft'): ProviderConnection
{
return ensureDefaultProviderConnection($tenant, $provider, ProviderConnectionType::Dedicated->value);
}
/**
* @param array<string, mixed> $snapshot
* @param array<int, array<string, mixed>> $assignments
* @param array<string, mixed> $scopeTags
* @param array<string, array<string, string>> $secretFingerprints
*/
function expectedPolicyVersionContentHash(
array $snapshot,
string $policyType,
?string $platform = null,
array $assignments = [],
array $scopeTags = [],
array $secretFingerprints = [],
?int $redactionVersion = 1,
): string {
return app(\App\Services\Drift\DriftHasher::class)->hashNormalized([
'settings' => app(\App\Services\Drift\Normalizers\SettingsNormalizer::class)->normalizeForDiff(
$snapshot,
$policyType,
$platform,
),
'assignments' => app(\App\Services\Drift\Normalizers\AssignmentsNormalizer::class)->normalizeForDiff($assignments),
'scope_tag_ids' => app(\App\Services\Drift\Normalizers\ScopeTagsNormalizer::class)->normalizeIds($scopeTags),
'secret_fingerprints' => [
'snapshot' => is_array($secretFingerprints['snapshot'] ?? null) ? $secretFingerprints['snapshot'] : [],
'assignments' => is_array($secretFingerprints['assignments'] ?? null) ? $secretFingerprints['assignments'] : [],
'scope_tags' => is_array($secretFingerprints['scope_tags'] ?? null) ? $secretFingerprints['scope_tags'] : [],
],
'redaction_version' => $redactionVersion,
]);
}