Files
aza/AzA march 2026 - Kopie (10)/deploy/authorized_test.ps1

238 lines
7.6 KiB
PowerShell
Raw Normal View History

2026-04-16 13:32:32 +02:00
<#
AZA Step 12: Authorized Smoke-Test (PowerShell)
What it does:
- Loads MEDWORK_API_TOKENS (preferred) or MEDWORK_API_TOKEN (legacy) from deploy/.env
- Picks the first token (NEW) from a comma-separated list
- Calls GET /license/status with header: X-API-Token: <token>
- Optionally sends X-Device-Id (stable per run unless you override)
Run:
powershell -ExecutionPolicy Bypass -File .\deploy\authorized_test.ps1
Optional:
powershell -ExecutionPolicy Bypass -File .\deploy\authorized_test.ps1 -BaseUrl http://127.0.0.1:8000
powershell -ExecutionPolicy Bypass -File .\deploy\authorized_test.ps1 -DeviceId "test-device-123"
Expected:
200 + JSON: {"valid": true/false, "valid_until": 1774553596 or null}
#>
[CmdletBinding()]
param(
[string]$BaseUrl = "http://127.0.0.1:8000",
# default: .env next to this script (deploy\.env)
[string]$EnvFile = "",
[string]$DeviceId = ""
)
function Get-ScriptDir {
# Prefer PSScriptRoot when available, otherwise fall back to MyInvocation (works in Windows PowerShell).
if ($PSScriptRoot -and $PSScriptRoot.Trim().Length -gt 0) { return $PSScriptRoot }
$p = $MyInvocation.MyCommand.Path
if (-not $p) { throw "Cannot determine script directory (PSScriptRoot/MyInvocation empty)." }
return (Split-Path -Parent $p)
}
function Load-DotEnv([string]$Path) {
if (-not (Test-Path -LiteralPath $Path)) {
throw "Missing .env file at: $Path"
}
$map = @{}
Get-Content -LiteralPath $Path | ForEach-Object {
$line = $_.Trim()
if ($line.Length -eq 0) { return }
if ($line.StartsWith("#")) { return }
$idx = $line.IndexOf("=")
if ($idx -lt 1) { return }
$k = $line.Substring(0, $idx).Trim()
$v = $line.Substring($idx + 1).Trim()
# strip optional wrapping quotes
if (($v.StartsWith('"') -and $v.EndsWith('"')) -or ($v.StartsWith("'") -and $v.EndsWith("'"))) {
$v = $v.Substring(1, $v.Length - 2)
}
$map[$k] = $v
}
return $map
}
function First-TokenFromValue([string]$value) {
if (-not $value) { return "" }
# supports "NEW,OLD" and multi-line/space separated variants
$value = $value.Trim()
$parts = $value -split "[,\r\n]+" | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" }
if ($parts.Count -ge 1) { return $parts[0] }
return ""
}
function All-TokensFromValue([string]$value) {
if (-not $value) { return @() }
$value = $value.Trim()
return ($value -split "[,\r\n]+" | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" })
}
try {
if (-not $EnvFile -or $EnvFile.Trim().Length -eq 0) {
$scriptDir = Get-ScriptDir
$EnvFile = Join-Path $scriptDir ".env"
}
$envMap = Load-DotEnv -Path $EnvFile
} catch {
Write-Host "$($_.Exception.Message)"
exit 1
}
$tokenValue = ""
$tokenSource = ""
if ($envMap.ContainsKey("MEDWORK_API_TOKENS")) { $tokenValue = $envMap["MEDWORK_API_TOKENS"] }
elseif ($envMap.ContainsKey("MEDWORK_API_TOKEN")) { $tokenValue = $envMap["MEDWORK_API_TOKEN"] }
$tokens = @()
if ($envMap.ContainsKey("MEDWORK_API_TOKENS")) {
$tokenSource = "MEDWORK_API_TOKENS"
$tokens = All-TokensFromValue -value $envMap["MEDWORK_API_TOKENS"]
} elseif ($envMap.ContainsKey("MEDWORK_API_TOKEN")) {
$tokenSource = "MEDWORK_API_TOKEN"
$tokens = All-TokensFromValue -value $envMap["MEDWORK_API_TOKEN"]
}
if (-not $tokens -or $tokens.Count -lt 1) {
Write-Host "❌ No token found in $EnvFile (expected MEDWORK_API_TOKENS or MEDWORK_API_TOKEN)."
exit 1
}
if (-not $DeviceId) {
# deterministic-ish per machine/user; override via -DeviceId when needed
$DeviceId = "ps-" + $env:COMPUTERNAME + "-" + $env:USERNAME
}
$base = $BaseUrl.TrimEnd("/")
$url = "$base/license/status"
Write-Host "[AZA] Authorized Smoke-Test"
Write-Host " BaseUrl: $base"
Write-Host " Endpoint: /license/status"
Write-Host " TokenSrc: $tokenSource"
Write-Host " Tokens: $($tokens.Count) (will try in order)"
Write-Host " TokenLen: $($tokens[0].Length) (first token length only)"
Write-Host " DeviceId: $DeviceId"
Write-Host ""
function Invoke-GetJson([string]$u, [hashtable]$h) {
try {
$resp = Invoke-RestMethod -Method GET -Uri $u -Headers $h -TimeoutSec 15
return @{ ok=$true; status=200; body=$resp }
} catch {
$e = $_.Exception
$status = $null
$body = ""
if ($e.Response -and $e.Response.StatusCode) {
$status = [int]$e.Response.StatusCode
try {
$stream = $e.Response.GetResponseStream()
if ($stream) {
$reader = New-Object System.IO.StreamReader($stream)
$body = $reader.ReadToEnd()
}
} catch { }
}
return @{ ok=$false; status=$status; body=$body; message=$e.Message }
}
}
$base = $BaseUrl.TrimEnd("/")
function Invoke-GetJsonNoAuth([string]$u) {
try {
$resp = Invoke-RestMethod -Method GET -Uri $u -TimeoutSec 15
return @{ ok=$true; status=200; body=$resp }
} catch {
$e = $_.Exception
$status = $null
if ($e.Response -and $e.Response.StatusCode) { $status = [int]$e.Response.StatusCode }
return @{ ok=$false; status=$status; message=$e.Message }
}
}
function Discover-LicenseStatusPath([string]$baseUrl) {
$openapiUrl = "$baseUrl/openapi.json"
$r = Invoke-GetJsonNoAuth $openapiUrl
if (-not $r.ok) { return @{ ok=$false; reason="openapi_unavailable"; path=$null } }
try {
$paths = $r.body.paths.PSObject.Properties.Name
$hits = @()
foreach ($p in $paths) {
$pl = $p.ToLowerInvariant()
if ($pl -like "*license*" -and $pl -like "*status*") { $hits += $p }
}
if ($hits.Count -ge 1) {
return @{ ok=$true; reason="openapi_match"; path=$hits[0]; all=$hits }
}
return @{ ok=$false; reason="openapi_no_match"; path=$null }
} catch {
return @{ ok=$false; reason="openapi_parse_failed"; path=$null }
}
}
$lastStatus = $null
# First: sanity check health so we know we're talking to the correct server
$health = Invoke-GetJsonNoAuth "$base/health"
if ($health.ok) {
Write-Host "Health: OK (GET /health)"
} else {
Write-Host "Health: not OK (GET /health) status=$($health.status)"
}
Write-Host ""
# Discover correct license/status path via OpenAPI if available
$disc = Discover-LicenseStatusPath $base
$pathsToTry = @()
if ($disc.ok -and $disc.path) {
$pathsToTry += $disc.path
if ($disc.all -and $disc.all.Count -gt 1) {
foreach ($p in $disc.all) { if ($p -ne $disc.path) { $pathsToTry += $p } }
}
Write-Host "Discovered path(s) via /openapi.json:"
$pathsToTry | ForEach-Object { Write-Host " - $_" }
} else {
# Fallback candidates (do not change server behavior, just try likely paths)
$pathsToTry = @("/license/status", "/api/license/status", "/v1/license/status", "/license/status/")
Write-Host "OpenAPI discovery not usable ($($disc.reason)). Trying common candidates:"
$pathsToTry | ForEach-Object { Write-Host " - $_" }
}
Write-Host ""
foreach ($path in $pathsToTry) {
$testUrl = "$base$path"
foreach ($t in $tokens) {
$headers = @{
"X-API-Token" = $t
"X-Device-Id" = $DeviceId
"Accept" = "application/json"
}
$res = Invoke-GetJson -u $testUrl -h $headers
if ($res.ok) {
Write-Host "OK HTTP 200 ($path)"
$json = $res.body | ConvertTo-Json -Depth 10 -Compress
Write-Host $json
exit 0
}
$lastStatus = $res.status
if ($res.status -eq 404) {
# try next path
break
}
if ($res.status -eq 401 -or $res.status -eq 403) {
# try next token
continue
}
Write-Host "FAIL HTTP $($res.status) ($path)"
if ($res.body) { Write-Host $res.body } else { Write-Host $res.message }
exit 1
}
}
Write-Host "FAIL (no matching license/status endpoint found, or all tokens unauthorized)"
Write-Host "LastStatus: $lastStatus"
exit 1