Files
devolutions--unigetui/scripts/verify-integrity-tree.ps1
T
wehub-resource-sync 643e9f9fcb
.NET Tests / test-codebase (push) Waiting to run
Translation Validation / validate-translations (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:01:52 +08:00

104 lines
3.1 KiB
PowerShell

#!/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"