Private/Start-ApplyWatcher.ps1
|
# Internal helper -- spawn the apply-watcher background process from # @kagdaci/repo-switcher. Writes the watcher PID to disk for later health-check. function Start-ApplyWatcher { param( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$ApplyWatcherScript, [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$WatcherPidFile, [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$LogFile, [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$PwshPath, [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$RepoSwitcherRoot ) if (-not (Test-Path $ApplyWatcherScript)) { Write-LogLine -Message "apply-watcher script missing at $ApplyWatcherScript -- Telegram apply will be disabled" -Level 'WARN' -LogFile $LogFile return } # [G4] security F5: defense in depth -- confirm the watcher script resolves # INSIDE the declared RepoSwitcherRoot (catches TOCTOU between Test-Path # and Start-Process where an attacker could replace apply-watcher.ps1 with # a malicious file outside the trusted dir via a symlink/junction). try { $canonScript = [System.IO.Path]::GetFullPath($ApplyWatcherScript) $canonRoot = [System.IO.Path]::GetFullPath($RepoSwitcherRoot.TrimEnd('\').TrimEnd('/')) } catch { Write-LogLine -Message "apply-watcher path canonicalization failed: $($_.Exception.Message) -- aborting watcher spawn" -Level 'WARN' -LogFile $LogFile return } if (-not $canonScript.StartsWith($canonRoot + [IO.Path]::DirectorySeparatorChar, [System.StringComparison]::OrdinalIgnoreCase)) { Write-LogLine -Message "apply-watcher path '$canonScript' escapes RepoSwitcherRoot '$canonRoot' -- aborting watcher spawn" -Level 'WARN' -LogFile $LogFile return } # Use the explicit pwsh executable path inherited from the supervisor's own # process ([G4] devops T2-2). Falling back to PATH-resolved 'pwsh' would # break on multi-install systems where the watcher could pick up a different # PS7 (e.g. user-scoped vs system-scoped install). $proc = Start-Process $PwshPath ` -ArgumentList '-NoProfile', '-WindowStyle', 'Hidden', '-File', $ApplyWatcherScript ` -WindowStyle Hidden -PassThru Write-FileAtomic -Path $WatcherPidFile -Content $proc.Id Write-LogLine -Message "Spawned apply-watcher PID=$($proc.Id) via $PwshPath" -Level 'INFO' -LogFile $LogFile } |