merge: agent session work
This commit is contained in:
commit
711e012827
@ -397,11 +397,7 @@ public static function getWizardSteps(): array
|
|||||||
|
|
||||||
$selectedItemIds = is_array($selectedItemIds) ? $selectedItemIds : null;
|
$selectedItemIds = is_array($selectedItemIds) ? $selectedItemIds : null;
|
||||||
|
|
||||||
$groupMapping = $get('group_mapping') ?? [];
|
$groupMapping = static::normalizeGroupMapping($get('group_mapping'));
|
||||||
$groupMapping = is_array($groupMapping) ? $groupMapping : [];
|
|
||||||
$groupMapping = collect($groupMapping)
|
|
||||||
->map(fn ($value) => is_string($value) ? $value : null)
|
|
||||||
->all();
|
|
||||||
|
|
||||||
$checker = app(RestoreRiskChecker::class);
|
$checker = app(RestoreRiskChecker::class);
|
||||||
$outcome = $checker->check(
|
$outcome = $checker->check(
|
||||||
@ -1143,7 +1139,7 @@ public static function createRestoreRun(array $data): RestoreRun
|
|||||||
$actorEmail = auth()->user()?->email;
|
$actorEmail = auth()->user()?->email;
|
||||||
$actorName = auth()->user()?->name;
|
$actorName = auth()->user()?->name;
|
||||||
$isDryRun = (bool) ($data['is_dry_run'] ?? true);
|
$isDryRun = (bool) ($data['is_dry_run'] ?? true);
|
||||||
$groupMapping = $data['group_mapping'] ?? [];
|
$groupMapping = static::normalizeGroupMapping($data['group_mapping'] ?? null);
|
||||||
|
|
||||||
$checkSummary = $data['check_summary'] ?? null;
|
$checkSummary = $data['check_summary'] ?? null;
|
||||||
$checkResults = $data['check_results'] ?? null;
|
$checkResults = $data['check_results'] ?? null;
|
||||||
@ -1386,6 +1382,76 @@ private static function unresolvedGroups(?int $backupSetId, ?array $selectedItem
|
|||||||
return $unresolved;
|
return $unresolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string|null>
|
||||||
|
*/
|
||||||
|
private static function normalizeGroupMapping(mixed $mapping): array
|
||||||
|
{
|
||||||
|
if ($mapping instanceof \Illuminate\Contracts\Support\Arrayable) {
|
||||||
|
$mapping = $mapping->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mapping instanceof \stdClass) {
|
||||||
|
$mapping = (array) $mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_array($mapping)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
if (array_key_exists('group_mapping', $mapping)) {
|
||||||
|
$nested = $mapping['group_mapping'];
|
||||||
|
|
||||||
|
if ($nested instanceof \Illuminate\Contracts\Support\Arrayable) {
|
||||||
|
$nested = $nested->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($nested instanceof \stdClass) {
|
||||||
|
$nested = (array) $nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($nested)) {
|
||||||
|
$mapping = $nested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($mapping as $key => $value) {
|
||||||
|
if (! is_string($key) || $key === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceGroupId = str_starts_with($key, 'group_mapping.')
|
||||||
|
? substr($key, strlen('group_mapping.'))
|
||||||
|
: $key;
|
||||||
|
|
||||||
|
if ($sourceGroupId === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($value instanceof BackedEnum) {
|
||||||
|
$value = $value->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($value) || $value instanceof \stdClass) {
|
||||||
|
$value = (array) $value;
|
||||||
|
$value = $value['value'] ?? $value['id'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($value)) {
|
||||||
|
$value = trim($value);
|
||||||
|
$result[$sourceGroupId] = $value !== '' ? $value : null;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[$sourceGroupId] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string, string>
|
* @return array<string, string>
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -129,3 +129,94 @@
|
|||||||
]);
|
]);
|
||||||
expect($run->metadata['check_summary']['blocking'] ?? null)->toBe(1);
|
expect($run->metadata['check_summary']['blocking'] ?? null)->toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('restore wizard treats skipped orphaned groups as a warning instead of a blocker', function () {
|
||||||
|
$tenant = Tenant::create([
|
||||||
|
'tenant_id' => 'tenant-1',
|
||||||
|
'name' => 'Tenant One',
|
||||||
|
'metadata' => [],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$tenant->makeCurrent();
|
||||||
|
|
||||||
|
$policy = Policy::create([
|
||||||
|
'tenant_id' => $tenant->id,
|
||||||
|
'external_id' => 'policy-1',
|
||||||
|
'policy_type' => 'settingsCatalogPolicy',
|
||||||
|
'display_name' => 'Settings Catalog',
|
||||||
|
'platform' => 'windows',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$backupSet = BackupSet::create([
|
||||||
|
'tenant_id' => $tenant->id,
|
||||||
|
'name' => 'Backup',
|
||||||
|
'status' => 'completed',
|
||||||
|
'item_count' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$backupItem = BackupItem::create([
|
||||||
|
'tenant_id' => $tenant->id,
|
||||||
|
'backup_set_id' => $backupSet->id,
|
||||||
|
'policy_id' => $policy->id,
|
||||||
|
'policy_identifier' => $policy->external_id,
|
||||||
|
'policy_type' => $policy->policy_type,
|
||||||
|
'platform' => $policy->platform,
|
||||||
|
'captured_at' => now(),
|
||||||
|
'payload' => ['id' => $policy->external_id],
|
||||||
|
'assignments' => [[
|
||||||
|
'target' => [
|
||||||
|
'@odata.type' => '#microsoft.graph.groupAssignmentTarget',
|
||||||
|
'groupId' => 'source-group-1',
|
||||||
|
'group_display_name' => 'Source Group',
|
||||||
|
],
|
||||||
|
'intent' => 'apply',
|
||||||
|
]],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->mock(GroupResolver::class, function (MockInterface $mock) {
|
||||||
|
$mock->shouldReceive('resolveGroupIds')
|
||||||
|
->andReturnUsing(function (array $groupIds): array {
|
||||||
|
return collect($groupIds)
|
||||||
|
->mapWithKeys(fn (string $id) => [$id => [
|
||||||
|
'id' => $id,
|
||||||
|
'displayName' => null,
|
||||||
|
'orphaned' => true,
|
||||||
|
]])
|
||||||
|
->all();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$this->actingAs($user);
|
||||||
|
|
||||||
|
$component = Livewire::test(CreateRestoreRun::class)
|
||||||
|
->fillForm([
|
||||||
|
'backup_set_id' => $backupSet->id,
|
||||||
|
])
|
||||||
|
->goToNextWizardStep()
|
||||||
|
->fillForm([
|
||||||
|
'scope_mode' => 'selected',
|
||||||
|
'backup_item_ids' => [$backupItem->id],
|
||||||
|
])
|
||||||
|
->goToNextWizardStep()
|
||||||
|
->set('data.group_mapping', (object) [
|
||||||
|
'source-group-1' => 'SKIP',
|
||||||
|
])
|
||||||
|
->callFormComponentAction('check_results', 'run_restore_checks');
|
||||||
|
|
||||||
|
$summary = $component->get('data.check_summary');
|
||||||
|
$results = $component->get('data.check_results');
|
||||||
|
|
||||||
|
expect($summary)->toBeArray();
|
||||||
|
expect($summary['blocking'] ?? null)->toBe(0);
|
||||||
|
expect($summary['has_blockers'] ?? null)->toBeFalse();
|
||||||
|
expect($summary['warning'] ?? null)->toBe(1);
|
||||||
|
|
||||||
|
$assignmentCheck = collect($results)->firstWhere('code', 'assignment_groups');
|
||||||
|
expect($assignmentCheck)->toBeArray();
|
||||||
|
expect($assignmentCheck['severity'] ?? null)->toBe('warning');
|
||||||
|
|
||||||
|
$skippedGroups = $assignmentCheck['meta']['skipped'] ?? [];
|
||||||
|
expect($skippedGroups)->toBeArray();
|
||||||
|
expect($skippedGroups[0]['id'] ?? null)->toBe('source-group-1');
|
||||||
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user