修复: 换装校验改安装器确定性判据

This commit is contained in:
lxy
2026-10-07 18:33:42 +08:00
parent c2382325cb
commit a2c69be4a2
+25 -18
View File
@@ -57,26 +57,22 @@ function Wait-HandleReleased {
return $false return $false
} }
# 静默安装并校验新 exe, 返回换装是否成功 # 静默安装并校验新 exe, 返回安装后哈希($null=失败)
# 基准说明: NSIS 打包器会重写主 exe 资源, 包内哈希原理上不等于磁盘构建产物,
# 故哈希比对只作参考, 本质判据=安装器确定性输出(两次装出同一哈希且实变)
function Invoke-SwapInstall { function Invoke-SwapInstall {
param([string]$Attempt) param([string]$Attempt)
$p = Start-Process $installer -ArgumentList '/S' -Wait -PassThru $p = Start-Process $installer -ArgumentList '/S' -Wait -PassThru
"[$(Get-Date -Format 'HH:mm:ss')] installer exit=$($p.ExitCode) (attempt $Attempt)" | Add-Content $log "[$(Get-Date -Format 'HH:mm:ss')] installer exit=$($p.ExitCode) (attempt $Attempt)" | Add-Content $log
if ($p.ExitCode -ne 0) { return $false } if ($p.ExitCode -ne 0) { return $null }
if (-not (Test-Path $target)) { if (-not (Test-Path $target)) {
"[$(Get-Date -Format 'HH:mm:ss')] FAIL: target missing after install" | Add-Content $log "[$(Get-Date -Format 'HH:mm:ss')] FAIL: target missing after install" | Add-Content $log
return $false return $null
} }
$afterHash = (Get-FileHash $target -Algorithm SHA256).Hash $afterHash = (Get-FileHash $target -Algorithm SHA256).Hash
$afterSize = (Get-Item $target).Length $afterSize = (Get-Item $target).Length
"[$(Get-Date -Format 'HH:mm:ss')] installed size=$afterSize hash=$($afterHash.Substring(0, 12))" | Add-Content $log "[$(Get-Date -Format 'HH:mm:ss')] installed size=$afterSize hash=$($afterHash.Substring(0, 12))" | Add-Content $log
if ($hashWant) { return $afterHash
if ($afterHash -ne $hashWant) { return $false }
} else {
"[$(Get-Date -Format 'HH:mm:ss')] weak check: built exe absent, compare with pre-install hash" | Add-Content $log
if ($afterHash -eq $before.hash) { return $false }
}
return $true
} }
try { try {
@@ -110,19 +106,30 @@ try {
if ($beforeHashShort.Length -gt 12) { $beforeHashShort = $beforeHashShort.Substring(0, 12) } if ($beforeHashShort.Length -gt 12) { $beforeHashShort = $beforeHashShort.Substring(0, 12) }
"[$(Get-Date -Format 'HH:mm:ss')] before size=$($before.size) hash=$beforeHashShort" | Add-Content $log "[$(Get-Date -Format 'HH:mm:ss')] before size=$($before.size) hash=$beforeHashShort" | Add-Content $log
# 4. 静默安装 + 校验, 校验失败重试一次 # 4. 静默安装 + 校验, 判据三级: 等磁盘快照强过; 两次装出同一哈希且实变为安装器确定性输出; 其余 FAIL
if (Invoke-SwapInstall 'first') { $firstHash = Invoke-SwapInstall 'first'
"[$(Get-Date -Format 'HH:mm:ss')] verify pass (first attempt)" | Add-Content $log $pass = $false
if ($firstHash) {
if ($hashWant -and $firstHash -eq $hashWant) {
"[$(Get-Date -Format 'HH:mm:ss')] verify pass (match disk build)" | Add-Content $log
$pass = $true
} elseif (-not $hashWant -and $firstHash -ne $before.hash) {
"[$(Get-Date -Format 'HH:mm:ss')] verify pass (weak check, changed from before)" | Add-Content $log
$pass = $true
} else { } else {
"[$(Get-Date -Format 'HH:mm:ss')] verify fail, retry once" | Add-Content $log "[$(Get-Date -Format 'HH:mm:ss')] verify mismatch disk baseline, retry once" | Add-Content $log
Wait-HandleReleased | Out-Null Wait-HandleReleased | Out-Null
if (Invoke-SwapInstall 'retry') { $retryHash = Invoke-SwapInstall 'retry'
"[$(Get-Date -Format 'HH:mm:ss')] verify pass (retry)" | Add-Content $log if ($retryHash -and $firstHash -eq $retryHash -and $retryHash -ne $before.hash) {
} else { "[$(Get-Date -Format 'HH:mm:ss')] verify pass (installer deterministic output $($retryHash.Substring(0, 12)))" | Add-Content $log
$pass = $true
}
}
}
if (-not $pass) {
"[$(Get-Date -Format 'HH:mm:ss')] FAIL: verify failed twice" | Add-Content $log "[$(Get-Date -Format 'HH:mm:ss')] FAIL: verify failed twice" | Add-Content $log
exit 1 exit 1
} }
}
# 5. 重启并验证; GUI 必须起在交互用户会话才可见 # 5. 重启并验证; GUI 必须起在交互用户会话才可见
Start-Process $target Start-Process $target