Files
Omika/infra/deploy/tests/Test-DeployScripts.ps1
T
2026-10-23 18:46:50 +02:00

144 lines
8.7 KiB
PowerShell

# ============================================================
# Omika Diagnostic Center - Tests NON invasifs des scripts de deploiement
# (Phase 5B2B.3). AUCUN changement systeme : aucune creation de service,
# aucune connexion PostgreSQL, aucun psql execute, aucun fichier serveur.
# ============================================================
# Valide :
# 1. Syntaxe PowerShell 5.1 (0 erreur) des 3 scripts.
# 2. Resolution des chemins par defaut ($PSScriptRoot corrige).
# 3. Detection psql (explicite / PATH / installation standard / absent).
# 4. Garanties install-phase5b2.ps1 : aucun service cree, aucun demarrage.
# ============================================================
$ErrorActionPreference = 'Stop'
$repo = 'D:\Avalonia\Omika'
$deploySrc = Join-Path $repo 'infra\deploy'
$deployPkg = Join-Path $repo 'artifacts\phase5b2\Deploy'
$tests = 0
$fails = 0
function Assert([bool]$condition, [string]$label) {
$script:tests++
if ($condition) {
Write-Host ("PASS {0}" -f $label) -ForegroundColor Green
} else {
$script:fails++
Write-Host ("FAIL {0}" -f $label) -ForegroundColor Red
}
}
Write-Host "=== 1. Syntaxe PowerShell 5.1 (0 erreur) ==="
$scripts = @(
(Join-Path $deploySrc 'Install-DatabaseSchema.ps1'),
(Join-Path $deploySrc 'install-phase5b2.ps1'),
(Join-Path $deploySrc 'Harden-DatabaseRoles.ps1')
)
foreach ($s in $scripts) {
$tokens = $null; $errors = $null
[System.Management.Automation.Language.Parser]::ParseFile($s, [ref]$tokens, [ref]$errors) | Out-Null
Assert (($errors -eq $null) -or ($errors.Count -eq 0)) ("Syntaxe OK : " + (Split-Path $s -Leaf))
}
Write-Host ""
Write-Host "=== 2. Resolution des chemins par defaut (bug PSScriptRoot corrige) ==="
# Miroir EXACT des expressions des scripts (calculees APRES le bloc param).
$packageRoot = Split-Path -Parent $deployPkg # phase5b2 (parent de Deploy)
$databaseDir = Join-Path $packageRoot 'Database'
Assert (Test-Path -LiteralPath $packageRoot) "PackageRoot par defaut resout vers le package existant"
Assert (Test-Path -LiteralPath $databaseDir) "DatabaseDir par defaut resout vers ..\Database existant"
Assert (Test-Path -LiteralPath (Join-Path $packageRoot 'DiagnosticsWorker')) "Package contient DiagnosticsWorker"
Assert (Test-Path -LiteralPath (Join-Path $packageRoot 'DiagnosticsWeb')) "Package contient DiagnosticsWeb"
Write-Host ""
Write-Host "=== 3. Detection psql (resolver) ==="
function Resolve-PsqlPath {
param([string]$ExplicitPath)
if ($ExplicitPath) {
if (-not (Test-Path -LiteralPath $ExplicitPath)) { return $null }
return (Resolve-Path -LiteralPath $ExplicitPath).Path
}
$inPath = Get-Command psql.exe -ErrorAction SilentlyContinue
if ($inPath) { return $inPath.Source }
$candidates = @(Get-ChildItem -Path 'C:\Program Files\PostgreSQL\*\bin\psql.exe' -ErrorAction SilentlyContinue)
if ($candidates.Count -gt 0) {
$best = $candidates | ForEach-Object {
$version = 0
$verDir = $_.Directory.Parent.Name
if ($verDir -match '^\d+$') { $version = [int]$verDir }
[PSCustomObject]@{ Path = $_.FullName; Version = $version }
} | Sort-Object -Property Version -Descending | Select-Object -First 1
return $best.Path
}
return $null
}
# A. chemin explicite existant -> retourne ce chemin (le resolver ne verifie
# que Test-Path, donc tout fichier existant sert ici de jeton de test).
$explicitProbe = Join-Path $deploySrc 'Install-DatabaseSchema.ps1'
Assert ((Resolve-PsqlPath -ExplicitPath $explicitProbe) -eq (Resolve-Path -LiteralPath $explicitProbe).Path) "PsqlPath explicite existant -> utilise tel quel"
# B. chemin explicite inexistant -> le script doit s'arreter avec erreur claire
# (on verifie ici que le resolver retourne null, et plus bas que le script
# contient bien Write-Error + exit 1).
Assert ((Resolve-PsqlPath -ExplicitPath 'C:\inexistant\psql.exe') -eq $null) "PsqlPath explicite inexistant -> non resolvable (arret clair du script)"
# C. installation standard PostgreSQL -> detectee (si presente sur ce poste) ;
# sinon le fallback retourne null (comportement documente).
$std = Get-ChildItem -Path 'C:\Program Files\PostgreSQL\*\bin\psql.exe' -ErrorAction SilentlyContinue
Assert ($std -ne $null) "Installation standard PostgreSQL detectee (ou absente : fallback null attendu)"
Write-Host (" (poste dev : {0} psql.exe trouve(s) sous C:\Program Files\PostgreSQL)" -f @($std).Count)
Write-Host ""
Write-Host "=== 4. Garanties install-phase5b2.ps1 (aucun service, aucun demarrage) ==="
$installContent = Get-Content -LiteralPath (Join-Path $deploySrc 'install-phase5b2.ps1') -Raw
Assert ($installContent -notmatch 'New-Service') "Aucun New-Service (creation differee a Phase 5C)"
Assert ($installContent -notmatch 'Start-Service') "Aucun Start-Service (jamais de demarrage)"
Assert ($installContent -notmatch '-StartupType\s+Automatic') "Aucun StartupType Automatic"
Assert ($installContent -match 'Set-Service\s+-Name\s+\$ServiceName\s+-StartupType\s+Manual') "Service existant force en Manual"
Assert ($installContent -match 'Stop-Service') "Service existant force en Stopped"
Assert ($installContent -match 'A_DETERMINER_EN_PHASE_5C') "Compte de service non fige (A_DETERMINER_EN_PHASE_5C)"
Write-Host ""
Write-Host "=== 5. Migration 003 (SQL statique, aucun PostgreSQL requis) ==="
$sql003 = Get-Content -LiteralPath (Join-Path $repo 'infra\postgresql\003_diagnostics_roles.sql') -Raw
# 0 commande ALTER INDEX (les commentaires ne comptent pas : ancrage en debut de ligne).
$alterIndexCmds = @([regex]::Matches($sql003, '(?m)^\s*ALTER\s+INDEX\b') | ForEach-Object { $_.Value })
Assert ($alterIndexCmds.Count -eq 0) "Aucune commande ALTER INDEX OWNER (0 occurrence)"
Assert ($sql003 -match 'ALTER\s+TABLE\s+diagnostic_event\s+OWNER\s+TO\s+omika_diagnostics_owner') "ALTER TABLE OWNER diagnostic_event"
Assert ($sql003 -match 'ALTER\s+TABLE\s+telemetry_metric_hourly\s+OWNER\s+TO\s+omika_diagnostics_owner') "ALTER TABLE OWNER telemetry_metric_hourly"
Assert ($sql003 -match 'ALTER\s+SEQUENCE\s+diagnostic_event_id_seq\s+OWNER\s+TO\s+omika_diagnostics_owner') "ALTER SEQUENCE OWNER diagnostic_event_id_seq"
Assert ($sql003 -match 'ALTER\s+SEQUENCE\s+telemetry_metric_hourly_id_seq\s+OWNER\s+TO\s+omika_diagnostics_owner') "ALTER SEQUENCE OWNER telemetry_metric_hourly_id_seq"
Assert ($sql003 -notmatch '(?m)^\s*REASSIGN\s+OWNED') "Aucun REASSIGN OWNED"
Assert ($sql003 -notmatch '(?m)^\s*DROP\b') "Aucun DROP"
Assert ($sql003 -notmatch '(?m)^\s*TRUNCATE\b') "Aucun TRUNCATE"
Assert ($sql003 -notmatch '(?m)^\s*DELETE\s+FROM') "Aucun DELETE"
Assert ($sql003 -notmatch "(?i)\bPASSWORD\s+'") "Aucun mot de passe en dur"
Assert ($sql003 -match 'GRANT\s+CONNECT\s+ON\s+DATABASE\s+omika_diagnostics\s+TO\s+omika_diagnostics_worker') "Worker : CONNECT database"
Assert ($sql003 -match 'GRANT\s+USAGE\s+ON\s+SCHEMA\s+public\s+TO\s+omika_diagnostics_worker') "Worker : USAGE schema public"
Assert ($sql003 -match 'GRANT\s+INSERT\s+ON\s+TABLE\s+diagnostic_event\s+TO\s+omika_diagnostics_worker') "Worker : INSERT diagnostic_event"
Assert ($sql003 -match 'GRANT\s+USAGE\s+ON\s+SEQUENCE\s+diagnostic_event_id_seq\s+TO\s+omika_diagnostics_worker') "Worker : USAGE sequence"
Assert ($sql003 -notmatch 'GRANT\s+(SELECT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER)\s+ON\s+TABLE\s+diagnostic_event\s+TO\s+omika_diagnostics_worker') "Worker : aucun SELECT/UPDATE/DELETE/TRUNCATE/REFERENCES/TRIGGER"
Assert ($sql003 -match 'GRANT\s+CONNECT\s+ON\s+DATABASE\s+omika_diagnostics\s+TO\s+[^;]*omika_diagnostics_web') "Web : CONNECT database"
Assert ($sql003 -match 'GRANT\s+USAGE\s+ON\s+SCHEMA\s+public\s+TO\s+[^;]*omika_diagnostics_web') "Web : USAGE schema public"
Assert ($sql003 -match 'GRANT\s+SELECT\s+ON\s+TABLE\s+diagnostic_event\s+TO\s+omika_diagnostics_web') "Web : SELECT diagnostic_event"
Assert ($sql003 -notmatch 'GRANT\s+(INSERT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER)\s+ON\s+TABLE\s+diagnostic_event\s+TO\s+omika_diagnostics_web') "Web : aucun INSERT/UPDATE/DELETE/TRUNCATE/REFERENCES/TRIGGER"
Assert ($sql003 -notmatch 'GRANT\s+\w+\s+ON\s+(TABLE\s+)?telemetry_metric_hourly') "Aucun droit sur telemetry_metric_hourly"
Assert ($sql003 -match 'ALTER\s+ROLE\s+omika_diagnostics_owner\s+.*NOLOGIN') "owner : NOLOGIN"
Assert ($sql003 -match 'ALTER\s+ROLE\s+omika_diagnostics_worker\s+.*LOGIN') "worker : LOGIN"
Assert ($sql003 -match 'ALTER\s+ROLE\s+omika_diagnostics_web\s+.*LOGIN') "web : LOGIN"
Assert ($sql003 -notmatch 'DROP\s+ROLE\s+omika_diagnostics_app') "Ancien role : aucun DROP ROLE"
Assert ($sql003 -notmatch 'ALTER\s+ROLE\s+omika_diagnostics_app\s+NOLOGIN') "Ancien role : aucun NOLOGIN automatique"
Write-Host ""
Write-Host ("=== RESULTAT : {0} tests, {1} echec(s) ===" -f $tests, $fails)
if ($fails -gt 0) { exit 1 } else { exit 0 }