fix(desktop): preserve Windows process exit evidence
Signed-off-by: Haozhe Wu <haozhe_wu@connect.hku.hk>
This commit is contained in:
1 parent
bc846ebaef
commit
8a0e90b840
5 files changed
+108
-32
No files matched your search
@@ -38,6 +38,7 @@ cd ..\desktop\electron
|
||||
npm ci
|
||||
npm run prepare:electron
|
||||
npm run smoke:credentials
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/test-process-utils.ps1
|
||||
npm run runtime:win -- -Clean
|
||||
npm run smoke:lifecycle
|
||||
npm run installer:win:review
|
||||
|
||||
@@ -25,6 +25,8 @@ $gtkInstallerUrl = "https://github.com/tschoonj/GTK-for-Windows-Runtime-Environm
|
||||
$gtkInstallerSha256 = 'd05e1488ca0e6ffaabb579bbeb82113c099152ca4260ebc63084b0dd174d4558'
|
||||
$gtkExtractRoot = Join-Path $gtkCacheRoot 'archive-runtime-v1'
|
||||
|
||||
. (Join-Path $PSScriptRoot 'process-utils.ps1')
|
||||
|
||||
function Get-VerifiedDownload {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$Uri,
|
||||
@@ -92,38 +94,6 @@ function Resolve-SevenZip {
|
||||
throw '7z.exe is required to extract the checksum-pinned GTK archive without executing its legacy installer.'
|
||||
}
|
||||
|
||||
function Invoke-BoundedProcess {
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$FilePath,
|
||||
[Parameter(Mandatory)][string]$Arguments,
|
||||
[Parameter(Mandatory)][int]$TimeoutSeconds,
|
||||
[Parameter(Mandatory)][string]$Label
|
||||
)
|
||||
|
||||
$process = $null
|
||||
try {
|
||||
$process = Start-Process `
|
||||
-FilePath $FilePath `
|
||||
-ArgumentList $Arguments `
|
||||
-NoNewWindow `
|
||||
-PassThru
|
||||
if (-not $process.WaitForExit($TimeoutSeconds * 1000)) {
|
||||
$taskkill = Join-Path $env:SystemRoot 'System32\taskkill.exe'
|
||||
& $taskkill /PID $process.Id /T /F | Out-Null
|
||||
$process.WaitForExit(10000) | Out-Null
|
||||
throw "$Label timed out after $TimeoutSeconds seconds."
|
||||
}
|
||||
if ($process.ExitCode -ne 0) {
|
||||
throw "$Label failed (exit code $($process.ExitCode))."
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ($process) {
|
||||
$process.Dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $BuildPython) {
|
||||
$repoVenvPython = Join-Path $repoRoot '.venv\Scripts\python.exe'
|
||||
if (Test-Path -LiteralPath $repoVenvPython) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
function Invoke-BoundedProcess {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$FilePath,
|
||||
[Parameter(Mandatory)][string]$Arguments,
|
||||
[Parameter(Mandatory)][ValidateRange(1, 2147483)][int]$TimeoutSeconds,
|
||||
[Parameter(Mandatory)][string]$Label
|
||||
)
|
||||
|
||||
# Windows PowerShell 5.1 can return a Process object with a null ExitCode
|
||||
# for Start-Process -PassThru -NoNewWindow (PowerShell/PowerShell#20400).
|
||||
# Use the .NET process API directly so timeout and exit-code evidence both
|
||||
# come from the same live process handle on every supported Windows image.
|
||||
$startInfo = [Diagnostics.ProcessStartInfo]::new()
|
||||
$startInfo.FileName = $FilePath
|
||||
$startInfo.Arguments = $Arguments
|
||||
$startInfo.UseShellExecute = $false
|
||||
$startInfo.CreateNoWindow = $true
|
||||
|
||||
$process = [Diagnostics.Process]::new()
|
||||
$process.StartInfo = $startInfo
|
||||
try {
|
||||
if (-not $process.Start()) {
|
||||
throw "$Label failed to start."
|
||||
}
|
||||
if (-not $process.WaitForExit($TimeoutSeconds * 1000)) {
|
||||
$taskkill = Join-Path $env:SystemRoot 'System32\taskkill.exe'
|
||||
& $taskkill /PID $process.Id /T /F | Out-Null
|
||||
$process.WaitForExit(10000) | Out-Null
|
||||
throw "$Label timed out after $TimeoutSeconds seconds."
|
||||
}
|
||||
|
||||
# The parameterless wait flushes final process state before ExitCode is
|
||||
# read. It returns immediately because the bounded wait already ended.
|
||||
$process.WaitForExit()
|
||||
$exitCode = [int]$process.ExitCode
|
||||
if ($exitCode -ne 0) {
|
||||
throw "$Label failed (exit code $exitCode)."
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$process.Dispose()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
. (Join-Path $PSScriptRoot 'process-utils.ps1')
|
||||
|
||||
$commandPrompt = Join-Path $env:SystemRoot 'System32\cmd.exe'
|
||||
|
||||
Invoke-BoundedProcess `
|
||||
-FilePath $commandPrompt `
|
||||
-Arguments '/d /s /c "exit 0"' `
|
||||
-TimeoutSeconds 5 `
|
||||
-Label 'zero-exit probe'
|
||||
|
||||
$nonZeroObserved = $false
|
||||
try {
|
||||
Invoke-BoundedProcess `
|
||||
-FilePath $commandPrompt `
|
||||
-Arguments '/d /s /c "exit 7"' `
|
||||
-TimeoutSeconds 5 `
|
||||
-Label 'non-zero probe'
|
||||
}
|
||||
catch {
|
||||
if ($_.Exception.Message -ne 'non-zero probe failed (exit code 7).') {
|
||||
throw
|
||||
}
|
||||
$nonZeroObserved = $true
|
||||
}
|
||||
if (-not $nonZeroObserved) {
|
||||
throw 'The bounded process adapter accepted a non-zero exit code.'
|
||||
}
|
||||
|
||||
$timeoutObserved = $false
|
||||
$stopwatch = [Diagnostics.Stopwatch]::StartNew()
|
||||
try {
|
||||
Invoke-BoundedProcess `
|
||||
-FilePath $commandPrompt `
|
||||
-Arguments '/d /s /c "ping.exe -n 6 127.0.0.1 >NUL"' `
|
||||
-TimeoutSeconds 1 `
|
||||
-Label 'timeout probe'
|
||||
}
|
||||
catch {
|
||||
if ($_.Exception.Message -ne 'timeout probe timed out after 1 seconds.') {
|
||||
throw
|
||||
}
|
||||
$timeoutObserved = $true
|
||||
}
|
||||
finally {
|
||||
$stopwatch.Stop()
|
||||
}
|
||||
if (-not $timeoutObserved) {
|
||||
throw 'The bounded process adapter accepted a process that exceeded its timeout.'
|
||||
}
|
||||
if ($stopwatch.Elapsed.TotalSeconds -ge 12) {
|
||||
throw "The timeout probe took too long to terminate: $($stopwatch.Elapsed.TotalSeconds) seconds."
|
||||
}
|
||||
|
||||
Write-Host 'Bounded native process exit-code and timeout handling: OK'
|
||||
Reference in new issue
Block a user