Harden workspace sync quarantine and updater recovery
Managed validation / full (pull_request) Successful in 31s
Managed validation / full (pull_request) Successful in 31s
This commit is contained in:
@@ -63,16 +63,24 @@ function Get-Sha256([string]$Path) {
|
||||
}
|
||||
}
|
||||
|
||||
function Start-ForgeFlowAndVerify([string]$Executable) {
|
||||
$process = Start-Process -FilePath $Executable -WorkingDirectory (Split-Path -Parent $Executable) -PassThru
|
||||
Start-Sleep -Milliseconds 1500
|
||||
if (-not $process -or $process.HasExited) { throw "ForgeFlow restart process exited before the application could stay running." }
|
||||
return $process
|
||||
}
|
||||
|
||||
try {
|
||||
Write-UpdateState -State "started" -Message "Binary updater owns the update request."
|
||||
Write-Log "Validating ForgeFlow $ExpectedVersion binary update."
|
||||
if ($HandshakeOnly) {
|
||||
Write-UpdateState -State "started" -Message "Binary updater owns the update request."
|
||||
Write-Log "Handshake-only verification completed successfully."
|
||||
exit 0
|
||||
}
|
||||
$actualSha256 = Get-Sha256 -Path $BinaryPath
|
||||
if ($actualSha256 -ne $ExpectedSha256.ToLowerInvariant()) { throw "Binary update SHA-256 verification failed." }
|
||||
if (-not (Test-Path -LiteralPath $CurrentExecutable -PathType Leaf)) { throw "Current ForgeFlow executable was not found." }
|
||||
Write-UpdateState -State "started" -Message "Binary preflight passed; updater owns the update request."
|
||||
if ($VerifyOnly) {
|
||||
Write-Log "Verification-only SHA-256 check completed successfully."
|
||||
exit 0
|
||||
@@ -90,9 +98,16 @@ try {
|
||||
try {
|
||||
Copy-Item -LiteralPath $BinaryPath -Destination $CurrentExecutable -Force
|
||||
} catch {
|
||||
Copy-Item -LiteralPath $backupPath -Destination $CurrentExecutable -Force
|
||||
Write-UpdateState -State "rolled-back" -Message $_.Exception.Message
|
||||
throw
|
||||
$copyFailure = $_.Exception.Message
|
||||
try {
|
||||
Copy-Item -LiteralPath $backupPath -Destination $CurrentExecutable -Force
|
||||
$rollbackRestart = Start-ForgeFlowAndVerify -Executable $CurrentExecutable
|
||||
Write-Log "Portable replacement failed; previous ForgeFlow restored and restarted as PID $($rollbackRestart.Id)."
|
||||
Write-UpdateState -State "rolled-back" -Message $copyFailure -RestartLaunched $true
|
||||
} catch {
|
||||
Write-UpdateState -State "failed" -Message "$copyFailure Rollback also failed: $($_.Exception.Message)" -RestartLaunched $false
|
||||
}
|
||||
throw $copyFailure
|
||||
}
|
||||
} else {
|
||||
Write-UpdateState -State "applying" -Message "Running the verified ForgeFlow installer."
|
||||
@@ -100,13 +115,31 @@ try {
|
||||
if ($installer.ExitCode -ne 0) { throw "ForgeFlow installer exited with code $($installer.ExitCode)." }
|
||||
}
|
||||
|
||||
$restart = Start-Process -FilePath $CurrentExecutable -WorkingDirectory (Split-Path -Parent $CurrentExecutable) -PassThru
|
||||
Write-Log "ForgeFlow $ExpectedVersion installed; restart PID $($restart.Id)."
|
||||
Write-UpdateState -State "success" -Message "ForgeFlow $ExpectedVersion installed successfully." -RestartLaunched $true
|
||||
try {
|
||||
$restart = Start-ForgeFlowAndVerify -Executable $CurrentExecutable
|
||||
Write-Log "ForgeFlow $ExpectedVersion installed; verified restart PID $($restart.Id)."
|
||||
Write-UpdateState -State "success" -Message "ForgeFlow $ExpectedVersion installed successfully." -RestartLaunched $true
|
||||
} catch {
|
||||
$restartFailure = $_.Exception.Message
|
||||
if ($isPortable -and $backupPath -and (Test-Path -LiteralPath $backupPath -PathType Leaf)) {
|
||||
Write-Log "Updated portable executable failed its restart probe; restoring the previous executable."
|
||||
try {
|
||||
Copy-Item -LiteralPath $backupPath -Destination $CurrentExecutable -Force
|
||||
$rollbackRestart = Start-ForgeFlowAndVerify -Executable $CurrentExecutable
|
||||
Write-Log "Previous ForgeFlow restored and restarted as PID $($rollbackRestart.Id)."
|
||||
Write-UpdateState -State "rolled-back" -Message $restartFailure -RestartLaunched $true
|
||||
} catch {
|
||||
Write-UpdateState -State "failed" -Message "$restartFailure Rollback also failed: $($_.Exception.Message)" -RestartLaunched $false
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
Write-Log "ForgeFlow $ExpectedVersion installed, but automatic restart failed: $restartFailure"
|
||||
Write-UpdateState -State "success" -Message "ForgeFlow $ExpectedVersion installed successfully, but must be started manually." -RestartLaunched $false
|
||||
}
|
||||
} catch {
|
||||
Write-Log $_.Exception.Message
|
||||
$current = $null
|
||||
try { $current = Get-Content -LiteralPath $StatusPath -Raw | ConvertFrom-Json } catch {}
|
||||
if ($current.state -ne "rolled-back") { Write-UpdateState -State "failed" -Message $_.Exception.Message }
|
||||
if ($current.state -notin @("rolled-back", "failed")) { Write-UpdateState -State "failed" -Message $_.Exception.Message }
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -117,13 +117,20 @@ function Start-ForgeFlow {
|
||||
|
||||
try {
|
||||
Write-UpdateLog "ForgeFlow source update helper started for version $ExpectedVersion."
|
||||
Write-UpdateState -State "started" -Message "The external update helper started successfully." -Extra @{ helperPid = $PID; startedAt = (Get-Date).ToUniversalTime().ToString("o") }
|
||||
|
||||
if ($HandshakeOnly) {
|
||||
Write-UpdateState -State "started" -Message "The external update helper started successfully." -Extra @{ helperPid = $PID; startedAt = (Get-Date).ToUniversalTime().ToString("o") }
|
||||
Write-UpdateLog "Handshake-only verification completed successfully."
|
||||
exit 0
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath (Join-Path $SourcePath ".git")) {
|
||||
throw "Integrated source update refuses to overwrite a Git working tree. Use normal Git/ForgeFlow workspace sync so local commits and dirty files remain reviewable."
|
||||
}
|
||||
$actualHash = Get-Sha256 -Path $ArchivePath
|
||||
if ($actualHash -ne $ExpectedSha256.ToLowerInvariant()) { throw "Update archive checksum mismatch." }
|
||||
Write-UpdateState -State "started" -Message "Source update preflight passed; the external helper owns the request." -Extra @{ helperPid = $PID; startedAt = (Get-Date).ToUniversalTime().ToString("o") }
|
||||
|
||||
Write-UpdateState -State "waiting-for-exit" -Message "Waiting for the running ForgeFlow process to exit."
|
||||
$deadline = (Get-Date).AddMinutes(2)
|
||||
while (Get-Process -Id $ParentPid -ErrorAction SilentlyContinue) {
|
||||
@@ -131,9 +138,6 @@ try {
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
|
||||
$actualHash = Get-Sha256 -Path $ArchivePath
|
||||
if ($actualHash -ne $ExpectedSha256.ToLowerInvariant()) { throw "Update archive checksum mismatch." }
|
||||
|
||||
$working = Join-Path ([IO.Path]::GetTempPath()) ("forgeflow-update-" + [guid]::NewGuid().ToString("N"))
|
||||
$extract = Join-Path $working "extract"
|
||||
$backup = Join-Path $working "backup"
|
||||
|
||||
Reference in New Issue
Block a user