104 lines
3.1 KiB
PowerShell
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" |