fix: persist scope tags on restore versions

This commit is contained in:
Ahmed Darrazi 2025-12-29 23:59:47 +01:00
parent b0c0ebe5ec
commit cf1cd04740
2 changed files with 146 additions and 1 deletions

View File

@ -151,6 +151,7 @@ public function execute(
$foundationSkipped = (int) ($foundationOutcome['skipped'] ?? 0);
$foundationMappingByType = $this->buildFoundationMappingByType($foundationEntries);
$scopeTagMapping = $foundationMappingByType['roleScopeTag'] ?? [];
$scopeTagNamesById = $this->buildScopeTagNameLookup($foundationEntries);
if (! $dryRun) {
$this->auditFoundationMapping(
@ -610,6 +611,13 @@ public function execute(
->first();
if ($policy && $itemStatus === 'applied') {
$scopeTagsForVersion = $this->buildScopeTagsForVersion(
scopeTagIds: $mappedScopeTagIds ?? null,
backupItemMetadata: $item->metadata ?? [],
scopeTagMapping: $scopeTagMapping,
scopeTagNamesById: $scopeTagNamesById,
);
$this->versionService->captureVersion(
policy: $policy,
payload: $item->payload,
@ -620,6 +628,7 @@ public function execute(
'backup_item_id' => $item->id,
],
assignments: $restoredAssignments,
scopeTags: $scopeTagsForVersion,
);
}
}
@ -2192,6 +2201,128 @@ private function sanitizeGroupPolicyDefinitionValue(array $definitionValue): arr
return $clean;
}
/**
* @param array<int, array<string, mixed>> $foundationEntries
* @return array<string, string>
*/
private function buildScopeTagNameLookup(array $foundationEntries): array
{
$names = [];
foreach ($foundationEntries as $entry) {
if (! is_array($entry)) {
continue;
}
if (($entry['type'] ?? null) !== 'roleScopeTag') {
continue;
}
$targetId = $entry['targetId'] ?? null;
$targetName = $entry['targetName'] ?? null;
if (! is_string($targetId) || $targetId === '') {
continue;
}
if (! is_string($targetName) || $targetName === '') {
continue;
}
$names[$targetId] = $targetName;
}
return $names;
}
/**
* @param array<int, mixed>|null $scopeTagIds
* @param array<string, mixed> $backupItemMetadata
* @param array<string, string> $scopeTagMapping
* @param array<string, string> $scopeTagNamesById
* @return array{ids: array<int, string>, names: array<int, string>}|null
*/
private function buildScopeTagsForVersion(
?array $scopeTagIds,
array $backupItemMetadata,
array $scopeTagMapping,
array $scopeTagNamesById,
): ?array {
if ($scopeTagIds === null) {
return null;
}
$ids = [];
foreach ($scopeTagIds as $id) {
if (! is_string($id) && ! is_int($id)) {
continue;
}
$id = (string) $id;
if ($id === '') {
continue;
}
$ids[] = $id;
}
$ids = array_values(array_unique($ids));
if ($ids === []) {
return null;
}
$namesById = $scopeTagNamesById;
$metaScopeTagIds = $backupItemMetadata['scope_tag_ids'] ?? null;
$metaScopeTagNames = $backupItemMetadata['scope_tag_names'] ?? null;
if (is_array($metaScopeTagIds) && is_array($metaScopeTagNames)) {
foreach ($metaScopeTagIds as $index => $sourceId) {
if (! is_string($sourceId) && ! is_int($sourceId)) {
continue;
}
$sourceId = (string) $sourceId;
if ($sourceId === '') {
continue;
}
$name = $metaScopeTagNames[$index] ?? null;
if (! is_string($name) || $name === '') {
continue;
}
$targetId = $scopeTagMapping[$sourceId] ?? $sourceId;
if ($targetId !== '' && ! array_key_exists($targetId, $namesById)) {
$namesById[$targetId] = $name;
}
}
}
$names = [];
foreach ($ids as $id) {
if ($id === '0') {
$names[] = 'Default';
continue;
}
$names[] = $namesById[$id] ?? "Unknown (ID: {$id})";
}
return [
'ids' => $ids,
'names' => $names,
];
}
private function assertActiveContext(Tenant $tenant, BackupSet $backupSet): void
{
if (! $tenant->isActive()) {

View File

@ -77,7 +77,14 @@ public function getServicePrincipalPermissions(array $options = []): GraphRespon
'policy_identifier' => $policy->external_id,
'policy_type' => $policy->policy_type,
'platform' => $policy->platform,
'payload' => ['foo' => 'bar'],
'payload' => [
'foo' => 'bar',
'roleScopeTagIds' => ['0', 'scope-1'],
],
'metadata' => [
'scope_tag_ids' => ['0', 'scope-1'],
'scope_tag_names' => ['Default', 'Verbund-1'],
],
]);
$user = User::factory()->create(['email' => 'tester@example.com']);
@ -102,6 +109,13 @@ public function getServicePrincipalPermissions(array $options = []): GraphRespon
]);
expect(PolicyVersion::where('policy_id', $policy->id)->count())->toBe(1);
$version = PolicyVersion::where('policy_id', $policy->id)->first();
expect($version)->not->toBeNull();
expect($version->scope_tags)->toBe([
'ids' => ['0', 'scope-1'],
'names' => ['Default', 'Verbund-1'],
]);
});
test('restore execution records foundation mappings', function () {