Public/Test-KritPax8Secrets.ps1
|
function Test-KritPax8Secrets { <# .SYNOPSIS Preflight gate — verifies Kritical secrets folder + token file are in place BEFORE any agent config is touched. Use as the first check in every wrapper. .DESCRIPTION Read-only. Returns a structured result with `Ok` + per-check details. Throws by default when -Strict and any check fails (so callers can use it as a guard: `Test-KritPax8Secrets -Strict | Out-Null` before mutation). Checks performed: S1 OneDrive Kritical folder present S2 Secrets folder present S3 Token file present + non-empty + sane length S4 Banner asset present (warning only — falls back to bundled) S5 Secrets folder not under any git repo (paranoia check — refuses to operate when secrets ended up inside a tracked folder) .EXAMPLE Test-KritPax8Secrets -Strict # throws on any failure Test-KritPax8Secrets # returns object, host-friendly summary .NOTES Author: Joshua Finley - Kritical Pty Ltd #> [CmdletBinding()] [OutputType([pscustomobject])] param( [string] $SecretsDir, [string] $TokenFileName, [switch] $Strict, [switch] $NoBanner ) if (-not $NoBanner.IsPresent) { Write-KritPax8Banner -Title 'Secrets Preflight' -Compact } $secretsDirPath = if ($SecretsDir) { $SecretsDir } else { Join-Path $env:USERPROFILE 'OneDrive - Kritical Pty Ltd\Github-SecretsOutsideOfGitRepos' } $oneDriveRoot = Join-Path $env:USERPROFILE 'OneDrive - Kritical Pty Ltd' $tokenFile = if ($TokenFileName) { $TokenFileName } else { 'pax8-mcpServer-auth.txt' } $tokenPath = Join-Path $secretsDirPath $tokenFile $bannerPath = Join-Path $secretsDirPath 'KriticalLogo.txt' $checks = [System.Collections.Generic.List[pscustomobject]]::new() $add = { param($n,$p,$d) $checks.Add([pscustomobject]@{ Check=$n; Pass=[bool]$p; Detail=$d }) } # S1 $s1 = Test-Path -LiteralPath $oneDriveRoot & $add 'S1.OneDriveSynced' $s1 $oneDriveRoot # S2 $s2 = Test-Path -LiteralPath $secretsDirPath & $add 'S2.SecretsFolder' $s2 $secretsDirPath # S3 $s3 = $false $s3detail = '' if ($s2 -and (Test-Path -LiteralPath $tokenPath)) { try { $tok = (Get-Content -LiteralPath $tokenPath -Raw -ErrorAction Stop).Trim() if ($tok.Length -ge 16 -and ($tok -notmatch '\s')) { $s3 = $true $s3detail = "length=$($tok.Length)" } else { $s3detail = "length=$($tok.Length) — fails sanity" } } catch { $s3detail = "read failed: $($_.Exception.Message)" } } else { $s3detail = "MISSING: $tokenPath" } & $add 'S3.TokenSane' $s3 $s3detail # S4 — warning only $s4 = Test-Path -LiteralPath $bannerPath $s4Detail = if ($s4) { $bannerPath } else { "not found at $bannerPath (will use bundled fallback)" } & $add 'S4.BannerAsset' $s4 $s4Detail # S5 — secrets folder must NOT be inside a git repo (catastrophic-leak guard) $s5 = $true $s5detail = 'OK' if ($s2) { $probe = $secretsDirPath $upwards = @() for ($i = 0; $i -lt 10 -and $probe -and $probe.Length -gt 3; $i++) { $upwards += $probe $gitDir = Join-Path $probe '.git' if (Test-Path -LiteralPath $gitDir) { $s5 = $false $s5detail = "FAIL — secrets folder is inside a git repo at $probe (.git found). Move the secrets folder OUT of any tracked path immediately." break } $probe = Split-Path -Parent $probe } } & $add 'S5.SecretsNotInRepo' $s5 $s5detail $failed = @($checks | Where-Object { -not $_.Pass -and $_.Check -ne 'S4.BannerAsset' }) $ok = ($failed.Count -eq 0) if (-not $NoBanner.IsPresent) { $checks | Format-Table -AutoSize | Out-String | Write-Host if ($ok) { Write-Host 'Secrets preflight PASS - safe to proceed.' -ForegroundColor Green } else { Write-Host ("Secrets preflight FAIL - " + $failed.Count + ' check(s) failed.') -ForegroundColor Red } } $result = [pscustomobject]@{ Ok = $ok Checks = @($checks) TokenPath = $tokenPath BannerPath = $bannerPath SecretsDir = $secretsDirPath FailedCount = $failed.Count } if ($Strict.IsPresent -and -not $ok) { throw "Secrets preflight failed ($($failed.Count) of $($checks.Count) checks). Fix and retry; no agent configs touched." } return $result } |