# ============================================================ # 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 }