>, warnings: array} */ public function normalize(?array $snapshot, string $policyType, ?string $platform = null): array { $snapshot = is_array($snapshot) ? $snapshot : []; if ($snapshot === []) { return [ 'status' => 'warning', 'settings' => [], 'warnings' => ['No snapshot available.'], ]; } $warnings = []; $settings = []; $roleDefinition = Arr::get($snapshot, 'roleDefinition'); $roleDefinition = is_array($roleDefinition) ? $roleDefinition : []; $roleDefinitionDisplay = $this->formatRoleDefinition($roleDefinition); if ($roleDefinitionDisplay === null) { $warnings[] = 'Role definition details were not expanded; using identifier fallback where possible.'; } elseif (($roleDefinition['displayName'] ?? null) === null && ($roleDefinition['id'] ?? null) !== null) { $warnings[] = 'Role definition display name unavailable; using identifier fallback.'; } $members = $this->normalizeSubjects(Arr::get($snapshot, 'members', [])); $scopeMembers = $this->normalizeSubjects(Arr::get($snapshot, 'scopeMembers', [])); $resourceScopes = $this->normalizedStringList(Arr::get($snapshot, 'resourceScopes', [])); $summaryEntries = []; $this->pushEntry($summaryEntries, 'Assignment name', Arr::get($snapshot, 'displayName')); $this->pushEntry($summaryEntries, 'Description', Arr::get($snapshot, 'description')); $this->pushEntry($summaryEntries, 'Role definition', $roleDefinitionDisplay); $this->pushEntry($summaryEntries, 'Scope type', Arr::get($snapshot, 'scopeType')); $this->pushEntry($summaryEntries, 'Members count', count($members)); $this->pushEntry($summaryEntries, 'Scope members count', count($scopeMembers)); $this->pushEntry($summaryEntries, 'Resource scopes count', count($resourceScopes)); if ($summaryEntries !== []) { $settings[] = [ 'type' => 'keyValue', 'title' => 'Role assignment', 'entries' => $summaryEntries, ]; } if ($members !== []) { $settings[] = [ 'type' => 'keyValue', 'title' => 'Members', 'entries' => [ [ 'key' => 'Resolved members', 'value' => $members, ], ], ]; } if ($scopeMembers !== []) { $settings[] = [ 'type' => 'keyValue', 'title' => 'Scope members', 'entries' => [ [ 'key' => 'Resolved scope members', 'value' => $scopeMembers, ], ], ]; } if ($resourceScopes !== []) { $settings[] = [ 'type' => 'keyValue', 'title' => 'Resource scopes', 'entries' => [ [ 'key' => 'Scopes', 'value' => $resourceScopes, ], ], ]; } if ($settings === []) { return [ 'status' => 'warning', 'settings' => [], 'warnings' => array_values(array_unique(array_merge($warnings, ['Role assignment snapshot contains no readable fields.']))), ]; } return [ 'status' => $warnings === [] ? 'ok' : 'warning', 'settings' => $settings, 'warnings' => array_values(array_unique($warnings)), ]; } /** * @return array */ public function flattenForDiff(?array $snapshot, string $policyType, ?string $platform = null): array { return $this->defaultNormalizer->flattenNormalizedForDiff( $this->normalize($snapshot, $policyType, $platform), ); } /** * @param array $entries */ private function pushEntry(array &$entries, string $key, mixed $value): void { if ($value === null) { return; } if (is_string($value) && $value === '') { return; } if (is_array($value) && $value === []) { return; } $entries[] = [ 'key' => $key, 'value' => $value, ]; } private function formatRoleDefinition(array $roleDefinition): ?string { $displayName = Arr::get($roleDefinition, 'displayName'); $id = Arr::get($roleDefinition, 'id'); if (is_string($displayName) && $displayName !== '' && is_string($id) && $id !== '') { return sprintf('%s (%s)', $displayName, $id); } if (is_string($displayName) && $displayName !== '') { return $displayName; } if (is_string($id) && $id !== '') { return $id; } return null; } /** * @return array */ private function normalizeSubjects(mixed $subjects): array { if (! is_array($subjects)) { return []; } $normalized = []; foreach ($subjects as $subject) { if (is_string($subject) && $subject !== '') { $normalized[] = $subject; continue; } if (! is_array($subject)) { continue; } $display = Arr::get($subject, 'displayName') ?? Arr::get($subject, 'userPrincipalName') ?? Arr::get($subject, 'mail') ?? Arr::get($subject, 'name'); $identifier = Arr::get($subject, 'id') ?? Arr::get($subject, 'principalId') ?? Arr::get($subject, 'groupId'); if (is_string($display) && $display !== '' && is_string($identifier) && $identifier !== '' && $display !== $identifier) { $normalized[] = sprintf('%s (%s)', $display, $identifier); continue; } if (is_string($display) && $display !== '') { $normalized[] = $display; continue; } if (is_string($identifier) && $identifier !== '') { $normalized[] = $identifier; } } $normalized = array_values(array_unique($normalized)); sort($normalized); return $normalized; } /** * @return array */ private function normalizedStringList(mixed $values): array { if (! is_array($values)) { return []; } $normalized = array_values(array_filter( array_map( static fn (mixed $value): ?string => is_string($value) && $value !== '' ? $value : null, $values, ), static fn (?string $value): bool => $value !== null, )); $normalized = array_values(array_unique($normalized)); sort($normalized); return $normalized; } }