fix(cli): harden tht installer replacement
This commit is contained in:
@@ -9,7 +9,7 @@ if (-not (Test-Path -LiteralPath $installer)) {
|
||||
$isWindowsHost = $env:OS -eq 'Windows_NT'
|
||||
if (-not $isWindowsHost) {
|
||||
$installerText = Get-Content -LiteralPath $installer -Raw
|
||||
foreach ($requiredText in @('THT_INSTALL_DIRECTORY', 'LOCALAPPDATA', 'SetEnvironmentVariable', 'build-tht.sh', 'Move-Item')) {
|
||||
foreach ($requiredText in @('THT_INSTALL_DIRECTORY', 'LOCALAPPDATA', 'SetEnvironmentVariable', 'build-tht.sh', 'File]::Replace')) {
|
||||
if (-not $installerText.Contains($requiredText)) {
|
||||
throw "Windows installer is missing required behavior: $requiredText"
|
||||
}
|
||||
@@ -20,37 +20,57 @@ if (-not $isWindowsHost) {
|
||||
|
||||
$temporaryRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("tht installer test {0}" -f [guid]::NewGuid())
|
||||
$installDirectory = Join-Path $temporaryRoot 'command directory'
|
||||
$artifact = Join-Path $temporaryRoot 'tht.exe'
|
||||
$artifactOne = Join-Path $temporaryRoot 'tht-one.exe'
|
||||
$artifactTwo = Join-Path $temporaryRoot 'tht-two.exe'
|
||||
$brokenArtifact = Join-Path $temporaryRoot 'tht-broken.exe'
|
||||
$userPathStore = Join-Path $temporaryRoot 'user-path.txt'
|
||||
New-Item -ItemType Directory -Path $temporaryRoot -Force | Out-Null
|
||||
try {
|
||||
$program = @'
|
||||
$programOne = @'
|
||||
using System;
|
||||
public static class Program {
|
||||
public static class ProgramOne {
|
||||
public static void Main(string[] args) {
|
||||
if (args.Length == 1 && args[0] == "--help") { Console.WriteLine("Usage: tht"); return; }
|
||||
if (args.Length == 1 && args[0] == "version") { Console.WriteLine("tht test version"); return; }
|
||||
if (args.Length == 1 && args[0] == "version") { Console.WriteLine("tht test version one"); return; }
|
||||
Environment.Exit(2);
|
||||
}
|
||||
}
|
||||
'@
|
||||
Add-Type -TypeDefinition $program -OutputAssembly $artifact -OutputType ConsoleApplication
|
||||
$programTwo = $programOne.Replace('ProgramOne', 'ProgramTwo').Replace('tht test version one', 'tht test version two')
|
||||
$brokenProgram = $programOne.Replace('ProgramOne', 'BrokenProgram').Replace('Console.WriteLine("Usage: tht"); return;', 'Environment.Exit(9);')
|
||||
Add-Type -TypeDefinition $programOne -OutputAssembly $artifactOne -OutputType ConsoleApplication
|
||||
Add-Type -TypeDefinition $programTwo -OutputAssembly $artifactTwo -OutputType ConsoleApplication
|
||||
Add-Type -TypeDefinition $brokenProgram -OutputAssembly $brokenArtifact -OutputType ConsoleApplication
|
||||
[System.IO.File]::WriteAllText($userPathStore, 'C:\Existing Bin')
|
||||
|
||||
$env:THT_INSTALL_DIRECTORY = $installDirectory
|
||||
$env:THT_BUILD_ARTIFACT = $artifact
|
||||
$env:THT_BUILD_ARTIFACT_SHA256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $artifact).Hash.ToLowerInvariant()
|
||||
$env:THT_BUILD_ARTIFACT = $artifactOne
|
||||
$env:THT_BUILD_ARTIFACT_SHA256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $artifactOne).Hash.ToLowerInvariant()
|
||||
$env:THT_USER_PATH_FILE = $userPathStore
|
||||
& $installer
|
||||
|
||||
$installed = Join-Path $installDirectory 'tht.exe'
|
||||
if (-not (Test-Path -LiteralPath $installed)) { throw 'installer did not create tht.exe' }
|
||||
if ((& $installed version) -ne 'tht test version') { throw 'installed tht.exe did not return version' }
|
||||
$firstBytes = [System.IO.File]::ReadAllBytes($installed)
|
||||
if ((& $installed version) -ne 'tht test version one') { throw 'installed tht.exe did not return version one' }
|
||||
|
||||
$env:THT_BUILD_ARTIFACT = $brokenArtifact
|
||||
$env:THT_BUILD_ARTIFACT_SHA256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $brokenArtifact).Hash.ToLowerInvariant()
|
||||
$brokenInstallFailed = $false
|
||||
try {
|
||||
& $installer
|
||||
} catch {
|
||||
$brokenInstallFailed = $true
|
||||
}
|
||||
if (-not $brokenInstallFailed) { throw 'installer accepted an invalid staged executable' }
|
||||
if ((& $installed version) -ne 'tht test version one') { throw 'invalid staged executable replaced the existing command' }
|
||||
|
||||
$env:THT_BUILD_ARTIFACT = $artifactTwo
|
||||
$env:THT_BUILD_ARTIFACT_SHA256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $artifactTwo).Hash.ToLowerInvariant()
|
||||
& $installer
|
||||
if ((& $installed version) -ne 'tht test version two') { throw 'installer did not replace the existing command' }
|
||||
|
||||
& $installer
|
||||
if ((& $installed version) -ne 'tht test version') { throw 'installer was not idempotent' }
|
||||
if (-not ([System.IO.File]::ReadAllBytes($installed).Length -eq $firstBytes.Length)) { throw 'replacement changed the unexpected binary' }
|
||||
if ((& $installed version) -ne 'tht test version two') { throw 'installer was not idempotent' }
|
||||
|
||||
$storedPath = [System.IO.File]::ReadAllText($userPathStore)
|
||||
$segments = $storedPath -split ';' | Where-Object { $_ -ne '' }
|
||||
|
||||
Reference in New Issue
Block a user