feat(sprint3): Invoke-VmrunBounded, Get-GuestIPAddress, transport and concurrency hardening

H4: Invoke-VmrunBounded added to _Common.psm1 (Start-Process + Wait-Process + taskkill on
    timeout, returns {ExitCode;Output;TimedOut;ElapsedSeconds}). Wired in Invoke-CIJob.ps1
    for vmrun start (180s) and Remove-BuildVM.ps1 for stop/deleteVM (60s/90s).
H5: Cleanup-OrphanedBuildVMs.ps1 removes stale vm-start.lock (>30 min). ValidateRange
    lowered to 0 to allow emergency -MaxAgeHours 0. Invoke-RetentionPolicy.ps1 same.
H8: _Transport.psm1 SSH hardening: StrictHostKeyChecking=accept-new, F:\CI\State\known_hosts.
H9: Validate-DeployState.ps1 Linux branch added: checks ci-report-ip.service enabled,
    ci-report-ip.sh executable via SSH. New params: -GuestOS, -SshKeyPath, -SshUser.
H12: Get-GuestIPAddress extracted into _Common.psm1 (guestinfo.ci-ip primary, getGuestIPAddress
     fallback). Invoke-CIJob.ps1 Phase 3b replaced with single call. Measure-CIBenchmark.ps1
     updated to match.
Also: _Common.psm1 adds Write-CIRedactedCommand and ConvertTo-SafeShellSingleQuotedString.
     Pester suite updated: 30/30 pass.
This commit is contained in:
Simone
2026-05-12 21:12:33 +02:00
parent 7dff7d3dba
commit 509d1fc284
8 changed files with 668 additions and 100 deletions
+26 -7
View File
@@ -40,6 +40,12 @@ function Invoke-SshCommand {
[int] $ConnectTimeout = 10,
# Persistent known_hosts file for CI jobs.
# When non-empty: StrictHostKeyChecking=accept-new + this file.
# When empty (default): permissive mode (StrictHostKeyChecking=no, UserKnownHostsFile=NUL)
# — used during template provisioning when host key is not yet known.
[string] $KnownHostsFile = '',
# Capture + return stdout/stderr instead of printing to console.
[switch] $PassThru,
@@ -47,10 +53,14 @@ function Invoke-SshCommand {
[switch] $AllowFail
)
if ($KnownHostsFile -ne '') {
$sshHostKeyOpts = @('-o', 'StrictHostKeyChecking=accept-new', '-o', "UserKnownHostsFile=$KnownHostsFile")
} else {
$sshHostKeyOpts = @('-o', 'StrictHostKeyChecking=no', '-o', 'UserKnownHostsFile=NUL')
}
$sshArgs = @(
'-i', $KeyPath,
'-o', 'StrictHostKeyChecking=no',
'-o', 'UserKnownHostsFile=NUL',
'-i', $KeyPath
) + $sshHostKeyOpts + @(
'-o', "ConnectTimeout=$ConnectTimeout",
'-o', 'BatchMode=yes',
"$User@$IP",
@@ -104,7 +114,12 @@ function Copy-SshItem {
# Pass -r to scp (recursive copy).
[switch] $Recurse,
[int] $ConnectTimeout = 10
[int] $ConnectTimeout = 10,
# Persistent known_hosts file for CI jobs.
# When non-empty: StrictHostKeyChecking=accept-new + this file.
# When empty (default): permissive mode — used during template provisioning.
[string] $KnownHostsFile = ''
)
if ($Direction -eq 'ToGuest') {
@@ -115,10 +130,14 @@ function Copy-SshItem {
}
# Direction = 'Direct': use Source + Destination as-is
if ($KnownHostsFile -ne '') {
$scpHostKeyOpts = @('-o', 'StrictHostKeyChecking=accept-new', '-o', "UserKnownHostsFile=$KnownHostsFile")
} else {
$scpHostKeyOpts = @('-o', 'StrictHostKeyChecking=no', '-o', 'UserKnownHostsFile=NUL')
}
$scpArgs = @(
'-i', $KeyPath,
'-o', 'StrictHostKeyChecking=no',
'-o', 'UserKnownHostsFile=NUL',
'-i', $KeyPath
) + $scpHostKeyOpts + @(
'-o', "ConnectTimeout=$ConnectTimeout"
)
if ($Recurse) { $scpArgs += '-r' }