test: add portainer stack env guard
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$StacksRoot = (Join-Path $PSScriptRoot "..\stacks"),
|
||||
[string]$ExemptionsPath = (Join-Path $PSScriptRoot "portainer-stack-env-exemptions.json")
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$failures = New-Object System.Collections.Generic.List[string]
|
||||
$exemptions = @{}
|
||||
|
||||
if (Test-Path $ExemptionsPath) {
|
||||
$raw = Get-Content -Raw -LiteralPath $ExemptionsPath | ConvertFrom-Json
|
||||
foreach ($property in $raw.PSObject.Properties) {
|
||||
$exemptions[$property.Name] = @($property.Value)
|
||||
}
|
||||
}
|
||||
|
||||
function Get-ServiceBlocks {
|
||||
param([string[]]$Lines)
|
||||
|
||||
$inServices = $false
|
||||
$currentName = $null
|
||||
$currentLines = New-Object System.Collections.Generic.List[string]
|
||||
$blocks = New-Object System.Collections.Generic.List[object]
|
||||
|
||||
foreach ($line in $Lines) {
|
||||
if ($line -match '^services:\s*$') {
|
||||
$inServices = $true
|
||||
continue
|
||||
}
|
||||
|
||||
if (-not $inServices) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ($line -match '^[A-Za-z0-9_-]+:\s*$') {
|
||||
break
|
||||
}
|
||||
|
||||
if ($line -match '^ ([A-Za-z0-9_-]+):\s*$') {
|
||||
if ($null -ne $currentName) {
|
||||
$blocks.Add([pscustomobject]@{
|
||||
Name = $currentName
|
||||
Lines = @($currentLines)
|
||||
})
|
||||
}
|
||||
$currentName = $Matches[1]
|
||||
$currentLines = New-Object System.Collections.Generic.List[string]
|
||||
continue
|
||||
}
|
||||
|
||||
if ($null -ne $currentName) {
|
||||
$currentLines.Add($line)
|
||||
}
|
||||
}
|
||||
|
||||
if ($null -ne $currentName) {
|
||||
$blocks.Add([pscustomobject]@{
|
||||
Name = $currentName
|
||||
Lines = @($currentLines)
|
||||
})
|
||||
}
|
||||
|
||||
return $blocks
|
||||
}
|
||||
|
||||
Get-ChildItem -LiteralPath $StacksRoot -Directory | Sort-Object Name | ForEach-Object {
|
||||
$stackName = $_.Name
|
||||
$composePath = Join-Path $_.FullName "docker-compose.yml"
|
||||
$stackEnvPath = Join-Path $_.FullName "stack.env"
|
||||
|
||||
if (-not (Test-Path $composePath)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (-not (Test-Path $stackEnvPath)) {
|
||||
$failures.Add("${stackName}: missing stack.env")
|
||||
}
|
||||
|
||||
$lines = Get-Content -LiteralPath $composePath
|
||||
$interpolations = Select-String -LiteralPath $composePath -Pattern '\$\{' |
|
||||
Where-Object { $_.Line -notmatch '^\s*#' }
|
||||
|
||||
foreach ($match in $interpolations) {
|
||||
$failures.Add("${stackName}: compose interpolation at $($match.Path):$($match.LineNumber): $($match.Line.Trim())")
|
||||
}
|
||||
|
||||
$allowedMissing = @()
|
||||
if ($exemptions.ContainsKey($stackName)) {
|
||||
$allowedMissing = @($exemptions[$stackName])
|
||||
}
|
||||
|
||||
foreach ($service in Get-ServiceBlocks -Lines $lines) {
|
||||
$hasEnvFile = $service.Lines | Where-Object { $_ -match '^\s+env_file:\s*$' -or $_ -match '^\s+- stack\.env\s*$' }
|
||||
if (-not $hasEnvFile -and $allowedMissing -notcontains $service.Name) {
|
||||
$failures.Add("${stackName}/${service.Name}: missing env_file: stack.env")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($failures.Count -gt 0) {
|
||||
$failures | ForEach-Object { Write-Error $_ }
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Portainer stack env checks passed."
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"authentik": ["authentik-redis"],
|
||||
"dev": ["dbx", "redis_plane"],
|
||||
"foundry": ["5etools"],
|
||||
"monitoring": ["uptime-kuma"],
|
||||
"owncloud": ["redis"]
|
||||
}
|
||||
Reference in New Issue
Block a user