functions/Test-ALZSyncRegression.ps1
|
function Test-ALZSyncRegression { Param( [Parameter(Mandatory = $true)] [string] $DefinitionsRootFolder, [Parameter(Mandatory = $true)] [string] $PacEnvironmentSelector, [string] $LibraryPath, [ValidateSet("ALZ", "AMBA", "FSI", "SLZ")] [string[]] $Types = @("ALZ", "AMBA", "SLZ"), [string] $BaselineDefinitionsRootFolder, [switch] $CleanOutput ) $ErrorActionPreference = "Continue" function New-ParameterSet { param( [string] $Type, [switch] $IncludeSyncAssignmentsOnly ) $params = @{ DefinitionsRootFolder = $DefinitionsRootFolder PacEnvironmentSelector = $PacEnvironmentSelector Type = $Type } if (-not [string]::IsNullOrWhiteSpace($LibraryPath)) { $params.LibraryPath = $LibraryPath } if ($IncludeSyncAssignmentsOnly) { $params.SyncAssignmentsOnly = $true } return $params } function Add-Failure { param( [string] $Type, [string] $Message ) $script:Failures += [PSCustomObject]@{ Type = $Type Message = $Message } } function Test-Assignments { param( [string] $Type ) $assignmentRoot = Join-Path $DefinitionsRootFolder ("policyAssignments/{0}/{1}" -f $Type, $PacEnvironmentSelector) if (-not (Test-Path -Path $assignmentRoot)) { Add-Failure -Type $Type -Message ("Assignment folder not found: {0}" -f $assignmentRoot) return } $assignmentFiles = Get-ChildItem -Path $assignmentRoot -Recurse -File -Include *.jsonc -ErrorAction SilentlyContinue if (($assignmentFiles | Measure-Object).Count -eq 0) { Add-Failure -Type $Type -Message "No assignment files were generated." return } foreach ($assignmentFile in $assignmentFiles) { $assignment = Get-Content -Path $assignmentFile.FullName -Raw | ConvertFrom-Json $scopePropertyNames = @($assignment.scope.PSObject.Properties.Name) if ($scopePropertyNames -notcontains $PacEnvironmentSelector) { Add-Failure -Type $Type -Message ("Missing scope selector '{0}' in {1}" -f $PacEnvironmentSelector, $assignmentFile.FullName) continue } $scopeValues = @($assignment.scope.$PacEnvironmentSelector) if (($scopeValues | Measure-Object).Count -eq 0) { Add-Failure -Type $Type -Message ("Empty scope array in {0}" -f $assignmentFile.FullName) continue } $invalidScopeValues = @($scopeValues | Where-Object { $null -eq $_ -or [string]::IsNullOrWhiteSpace("$_") }) if (($invalidScopeValues | Measure-Object).Count -gt 0) { Add-Failure -Type $Type -Message ("Null/empty scope value in {0}" -f $assignmentFile.FullName) } } } function Test-Structure { param( [string] $Type ) $structureFile = Join-Path $DefinitionsRootFolder ("policyStructures/{0}.policy_default_structure.{1}.jsonc" -f $Type.ToLower(), $PacEnvironmentSelector) if (-not (Test-Path -Path $structureFile)) { Add-Failure -Type $Type -Message ("Structure file not found: {0}" -f $structureFile) return } $structure = Get-Content -Path $structureFile -Raw | ConvertFrom-Json $propertyNames = @($structure.PSObject.Properties.Name) $hasArchetypeScopeMappings = $propertyNames -contains "archetypeScopeMappings" if ($Type -eq "SLZ") { if (-not $hasArchetypeScopeMappings) { Add-Failure -Type $Type -Message "Missing archetypeScopeMappings in SLZ structure output." return } $mappingProperties = @($structure.archetypeScopeMappings.PSObject.Properties.Name) if (($mappingProperties | Measure-Object).Count -eq 0) { Add-Failure -Type $Type -Message "archetypeScopeMappings exists but is empty for SLZ." return } if ($mappingProperties -notcontains "sovereign_l2_controls") { Add-Failure -Type $Type -Message "Expected SLZ mapping entry 'sovereign_l2_controls' not found." } } elseif ($Type -in @("ALZ", "AMBA")) { if ($hasArchetypeScopeMappings) { Add-Failure -Type $Type -Message "Unexpected archetypeScopeMappings found; ALZ/AMBA output should remain unchanged." } } } function Get-FileHashMap { param( [string] $RootPath ) $hashMap = @{} if (-not (Test-Path -Path $RootPath)) { return $hashMap } foreach ($file in Get-ChildItem -Path $RootPath -Recurse -File) { $relativePath = $file.FullName.Substring($RootPath.Length).TrimStart('\\', '/') $hashMap[$relativePath] = (Get-FileHash -Path $file.FullName -Algorithm SHA256).Hash } return $hashMap } function Test-Baseline { param( [string] $Type ) if ([string]::IsNullOrWhiteSpace($BaselineDefinitionsRootFolder)) { return } $currentStructurePath = Join-Path $DefinitionsRootFolder "policyStructures" $baselineStructurePath = Join-Path $BaselineDefinitionsRootFolder "policyStructures" $currentAssignmentsPath = Join-Path $DefinitionsRootFolder ("policyAssignments/{0}/{1}" -f $Type, $PacEnvironmentSelector) $baselineAssignmentsPath = Join-Path $BaselineDefinitionsRootFolder ("policyAssignments/{0}/{1}" -f $Type, $PacEnvironmentSelector) $currentStructureFile = Join-Path $currentStructurePath ("{0}.policy_default_structure.{1}.jsonc" -f $Type.ToLower(), $PacEnvironmentSelector) $baselineStructureFile = Join-Path $baselineStructurePath ("{0}.policy_default_structure.{1}.jsonc" -f $Type.ToLower(), $PacEnvironmentSelector) if ((Test-Path -Path $currentStructureFile) -and (Test-Path -Path $baselineStructureFile)) { $currentStructureHash = (Get-FileHash -Path $currentStructureFile -Algorithm SHA256).Hash $baselineStructureHash = (Get-FileHash -Path $baselineStructureFile -Algorithm SHA256).Hash if ($currentStructureHash -ne $baselineStructureHash) { Add-Failure -Type $Type -Message "Structure file hash differs from baseline." } } else { Add-Failure -Type $Type -Message "Unable to compare structure against baseline; one or both files are missing." } $currentHashMap = Get-FileHashMap -RootPath $currentAssignmentsPath $baselineHashMap = Get-FileHashMap -RootPath $baselineAssignmentsPath foreach ($path in $currentHashMap.Keys) { if (-not $baselineHashMap.ContainsKey($path)) { Add-Failure -Type $Type -Message ("Generated file not found in baseline: {0}" -f $path) continue } if ($currentHashMap[$path] -ne $baselineHashMap[$path]) { Add-Failure -Type $Type -Message ("Generated file content differs from baseline: {0}" -f $path) } } foreach ($path in $baselineHashMap.Keys) { if (-not $currentHashMap.ContainsKey($path)) { Add-Failure -Type $Type -Message ("Baseline file missing in generated output: {0}" -f $path) } } } $Failures = @() if ($CleanOutput) { foreach ($type in $Types) { $structureFile = Join-Path $DefinitionsRootFolder ("policyStructures/{0}.policy_default_structure.{1}.jsonc" -f $type.ToLower(), $PacEnvironmentSelector) if (Test-Path -Path $structureFile) { Remove-Item -Path $structureFile -Force -ErrorAction SilentlyContinue } $assignmentFolder = Join-Path $DefinitionsRootFolder ("policyAssignments/{0}/{1}" -f $type, $PacEnvironmentSelector) if (Test-Path -Path $assignmentFolder) { Remove-Item -Path $assignmentFolder -Recurse -Force -ErrorAction SilentlyContinue } } } $newStructureScript = Join-Path $PSScriptRoot "New-ALZPolicyDefaultStructure.ps1" $syncScript = Join-Path $PSScriptRoot "Sync-ALZPolicyFromLibrary.ps1" foreach ($type in $Types) { Write-Host ("[RUN] Type={0} - generating structure" -f $type) $newParams = New-ParameterSet -Type $type $canContinueType = $true try { & $newStructureScript @newParams } catch { Add-Failure -Type $type -Message ("Structure generation failed: {0}" -f $_.Exception.Message) $canContinueType = $false } if (-not $?) { Add-Failure -Type $type -Message "Structure generation returned a non-success status." $canContinueType = $false } if (-not $canContinueType) { continue } Write-Host ("[RUN] Type={0} - syncing assignments" -f $type) $syncParams = New-ParameterSet -Type $type -IncludeSyncAssignmentsOnly try { & $syncScript @syncParams } catch { Add-Failure -Type $type -Message ("Assignment sync failed: {0}" -f $_.Exception.Message) continue } if (-not $?) { Add-Failure -Type $type -Message "Assignment sync returned a non-success status." continue } Write-Host ("[TEST] Type={0} - validating structure" -f $type) Test-Structure -Type $type Write-Host ("[TEST] Type={0} - validating assignment scopes" -f $type) Test-Assignments -Type $type if ($type -in @("ALZ", "AMBA")) { Write-Host ("[TEST] Type={0} - baseline comparison" -f $type) Test-Baseline -Type $type } } if (($Failures | Measure-Object).Count -gt 0) { Write-Host "" Write-Host "Regression validation failed:" -ForegroundColor Red foreach ($failure in $Failures) { Write-Host (" - [{0}] {1}" -f $failure.Type, $failure.Message) -ForegroundColor Red } exit 1 } Write-Host "" Write-Host "Regression validation passed for all requested types." -ForegroundColor Green exit 0 } |