chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env pwsh
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Validates a generated IntegrityTree.json against the files in a directory.
|
||||
|
||||
.DESCRIPTION
|
||||
This mirrors UniGetUI runtime integrity verification and can optionally fail
|
||||
if the directory contains files that are not listed in IntegrityTree.json.
|
||||
|
||||
.PARAMETER Path
|
||||
The directory containing IntegrityTree.json and the files to validate.
|
||||
|
||||
.PARAMETER FailOnUnexpectedFiles
|
||||
Fail validation if files exist in the directory tree but are not present in
|
||||
IntegrityTree.json.
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory, Position = 0)]
|
||||
[string] $Path,
|
||||
|
||||
[switch] $FailOnUnexpectedFiles
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if (-not (Test-Path $Path -PathType Container)) {
|
||||
throw "The directory '$Path' does not exist."
|
||||
}
|
||||
|
||||
$Path = (Resolve-Path $Path).Path
|
||||
$IntegrityTreePath = Join-Path $Path 'IntegrityTree.json'
|
||||
|
||||
if (-not (Test-Path $IntegrityTreePath -PathType Leaf)) {
|
||||
throw "IntegrityTree.json was not found in '$Path'."
|
||||
}
|
||||
|
||||
$rawData = Get-Content $IntegrityTreePath -Raw
|
||||
|
||||
try {
|
||||
$data = ConvertFrom-Json $rawData -AsHashtable
|
||||
}
|
||||
catch {
|
||||
throw "IntegrityTree.json is not valid JSON: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
if ($null -eq $data) {
|
||||
throw 'IntegrityTree.json did not deserialize into a JSON object.'
|
||||
}
|
||||
|
||||
$missingFiles = New-Object System.Collections.Generic.List[string]
|
||||
$mismatchedFiles = New-Object System.Collections.Generic.List[string]
|
||||
$unexpectedFiles = New-Object System.Collections.Generic.List[string]
|
||||
|
||||
$expectedFiles = @{}
|
||||
foreach ($entry in $data.GetEnumerator()) {
|
||||
$relativePath = [string] $entry.Key
|
||||
$expectedHash = [string] $entry.Value
|
||||
$expectedFiles[$relativePath] = $true
|
||||
|
||||
$fullPath = Join-Path $Path $relativePath
|
||||
if (-not (Test-Path $fullPath -PathType Leaf)) {
|
||||
$missingFiles.Add($relativePath)
|
||||
continue
|
||||
}
|
||||
|
||||
$currentHash = (Get-FileHash $fullPath -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
if ($currentHash -ne $expectedHash.ToLowerInvariant()) {
|
||||
$mismatchedFiles.Add("$relativePath|expected=$expectedHash|got=$currentHash")
|
||||
}
|
||||
}
|
||||
|
||||
if ($FailOnUnexpectedFiles) {
|
||||
Get-ChildItem $Path -Recurse -File | ForEach-Object {
|
||||
$relativePath = $_.FullName.Substring($Path.Length).TrimStart('\', '/') -replace '\\', '/'
|
||||
if ($relativePath -eq 'IntegrityTree.json') {
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $expectedFiles.ContainsKey($relativePath)) {
|
||||
$unexpectedFiles.Add($relativePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($missingFiles.Count -or $mismatchedFiles.Count -or $unexpectedFiles.Count) {
|
||||
if ($missingFiles.Count) {
|
||||
Write-Error "Missing files listed in IntegrityTree.json:`n - $($missingFiles -join "`n - ")"
|
||||
}
|
||||
|
||||
if ($mismatchedFiles.Count) {
|
||||
Write-Error "Files with mismatched SHA256 values:`n - $($mismatchedFiles -join "`n - ")"
|
||||
}
|
||||
|
||||
if ($unexpectedFiles.Count) {
|
||||
Write-Error "Unexpected files not present in IntegrityTree.json:`n - $($unexpectedFiles -join "`n - ")"
|
||||
}
|
||||
|
||||
throw 'Integrity tree validation failed.'
|
||||
}
|
||||
|
||||
$validatedFileCount = $data.Count
|
||||
Write-Host "Integrity tree validation succeeded for $validatedFileCount file(s) in $Path"
|
||||
Reference in New Issue
Block a user