Files
Simone 0b0d5486f0 chore(scripts): archive PowerShell scripts superseded by the Python CLI
Move 16 .ps1 files to scripts/archived/ — they have no live caller:

- 10 pure shims (New-BuildVM, Remove-BuildVM, Cleanup-OrphanedBuildVMs,
  Wait-VMReady, Invoke-RemoteBuild, Get-BuildArtifacts, Watch-DiskSpace,
  Watch-RunnerHealth, Get-CIJobSummary, Invoke-CIJob) that only forwarded
  to `ci_orchestrator`; the live Gitea composite action now calls
  `python -m ci_orchestrator job` directly.
- 6 Phase-C host tools reimplemented natively in Python (Start-BurnInTest
  [+ -Linux], Test-CapacityBurnIn → bench; Test-Smoke → smoke run;
  Validate-HostState → validate host; Set-CIGuestCredential → creds set).

Add scripts/archived/README.md mapping each file to its `ci` replacement,
and exempt scripts/archived/ from the PSScriptAnalyzer lint job.

Kept (still used / not yet ported): Register-CIScheduledTasks,
Backup-CITemplate, Invoke-RetentionPolicy, Set-TemplateSharedFolders,
Test-CIGuestWinRM, the e2e build harnesses, and all template/ guest
provisioning scripts.
2026-06-08 21:15:05 +02:00

191 lines
6.3 KiB
PowerShell

#Requires -Version 5.1
<#
.SYNOPSIS
Validates host-side security prerequisites for the CI system.
.DESCRIPTION
Checks that:
1. The SSH private key for Linux guest access exists and has restrictive ACLs
(only the current user and SYSTEM/Administrators may read it).
2. The Windows Credential Manager target used by CI guest sessions is accessible.
3. The CI key directories exist with expected permissions.
Run after `Setup-Host.ps1` and any time credentials or keys are rotated.
Exits with code 0 on all-pass, non-zero if any check fails.
.PARAMETER SshKeyPath
Path to the SSH private key used for Linux guest access.
Default: F:\CI\keys\ci_linux
.PARAMETER GuestCredTarget
Windows Credential Manager target name for Windows guest credentials.
Default: BuildVMGuest
.PARAMETER CIRootDir
Root CI directory to verify existence.
Default: F:\CI
.EXAMPLE
.\Validate-HostState.ps1
.EXAMPLE
.\Validate-HostState.ps1 -SshKeyPath 'F:\CI\keys\ci_linux' -Verbose
#>
[CmdletBinding()]
param(
[string] $SshKeyPath = 'F:\CI\keys\ci_linux',
[string] $GuestCredTarget = 'BuildVMGuest',
[string] $CIRootDir = 'F:\CI'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
# ── Helpers ───────────────────────────────────────────────────────────────────
$script:passCount = 0
$script:failCount = 0
function Write-Check {
param([string]$Label, [scriptblock]$Test)
try {
$result = & $Test
if ($result) {
Write-Host " [OK] $Label"
$script:passCount++
} else {
Write-Host " [FAIL] $Label"
$script:failCount++
}
} catch {
Write-Host " [FAIL] $Label — $_"
$script:failCount++
}
}
# ── Check 1: SSH key file exists ──────────────────────────────────────────────
Write-Host "`n=== SSH Key ($SshKeyPath) ==="
Write-Check "SSH private key file exists" {
Test-Path $SshKeyPath -PathType Leaf
}
Write-Check "SSH public key file exists" {
Test-Path "${SshKeyPath}.pub" -PathType Leaf
}
# Check ACLs: only SYSTEM, Administrators, and the current user should have access
Write-Check "SSH key ACL — no unexpected identities" {
if (-not (Test-Path $SshKeyPath -PathType Leaf)) { return $false }
$acl = Get-Acl -Path $SshKeyPath
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
# Allowed identities (case-insensitive prefix matching)
$allowedPatterns = @(
'NT AUTHORITY\SYSTEM',
'BUILTIN\Administrators',
$currentUser
)
$unexpected = @()
foreach ($ace in $acl.Access) {
$identity = $ace.IdentityReference.Value
$matched = $false
foreach ($pattern in $allowedPatterns) {
if ($identity -ieq $pattern) { $matched = $true; break }
}
if (-not $matched) {
$unexpected += $identity
}
}
if ($unexpected.Count -gt 0) {
Write-Verbose "[ACL] Unexpected identities on SSH key: $($unexpected -join ', ')"
return $false
}
return $true
}
Write-Check "SSH key not world-readable (Everyone/Users absent)" {
if (-not (Test-Path $SshKeyPath -PathType Leaf)) { return $false }
$acl = Get-Acl -Path $SshKeyPath
$broad = $acl.Access | Where-Object {
$id = $_.IdentityReference.Value
$id -ilike '*Everyone*' -or $id -ilike 'BUILTIN\Users'
}
return ($null -eq $broad -or @($broad).Count -eq 0)
}
# ── Check 2: Credential Manager target ────────────────────────────────────────
Write-Host "`n=== Credential Manager (target: $GuestCredTarget) ==="
Write-Check "CredentialManager module available" {
$null -ne (Get-Module -Name CredentialManager -ListAvailable -ErrorAction SilentlyContinue)
}
Write-Check "Credential target '$GuestCredTarget' accessible" {
# Use cmdkey.exe as a fallback — avoids requiring CredentialManager module
$cmdkeyOut = & cmdkey.exe /list:$GuestCredTarget 2>&1 | Out-String
if ($cmdkeyOut -imatch [regex]::Escape($GuestCredTarget)) {
return $true
}
# Try via CredentialManager module if available
if ($null -ne (Get-Module -Name CredentialManager -ListAvailable -ErrorAction SilentlyContinue)) {
Import-Module CredentialManager -ErrorAction SilentlyContinue
$cred = Get-StoredCredential -Target $GuestCredTarget -ErrorAction SilentlyContinue
return ($null -ne $cred)
}
return $false
}
# ── Check 3: CI directory structure ───────────────────────────────────────────
Write-Host "`n=== CI Directory Structure ($CIRootDir) ==="
$requiredDirs = @(
'BuildVMs',
'Artifacts',
'Logs',
'State',
'keys',
'Cache\NuGet',
'Cache\pip',
'Templates'
)
foreach ($rel in $requiredDirs) {
$full = Join-Path $CIRootDir $rel
Write-Check "Directory exists: $rel" { Test-Path $full -PathType Container }
}
# ── Check 4: vmrun.exe reachable ──────────────────────────────────────────────
Write-Host "`n=== VMware ==="
Write-Check "vmrun.exe found in PATH or default location" {
$vmrunDefault = 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe'
$inPath = $null -ne (Get-Command 'vmrun.exe' -ErrorAction SilentlyContinue)
$atDefault = Test-Path $vmrunDefault -PathType Leaf
$inPath -or $atDefault
}
# ── Summary ───────────────────────────────────────────────────────────────────
Write-Host "`n=== Summary ==="
Write-Host " Passed : $($script:passCount)"
Write-Host " Failed : $($script:failCount)"
if ($script:failCount -gt 0) {
Write-Host "`n[Validate-HostState] $($script:failCount) check(s) failed. Review output above." -ForegroundColor Red
exit 1
} else {
Write-Host "`n[Validate-HostState] All checks passed." -ForegroundColor Green
exit 0
}