Validate server compose env fragments

This commit is contained in:
Курнат Андрей
2026-06-12 23:02:01 +03:00
parent 709a38cae1
commit 9fad6b1595
2 changed files with 40 additions and 2 deletions
+2 -2
View File
@@ -50,8 +50,8 @@ Date: 2026-06-08.
- Server `qsfera_full` compose files now require explicit admin, Keycloak, and S3/MinIO secrets instead of demo defaults.
- Server `qsfera_full/env.production.example` provides a tracked production-safe starting point with TLS validation enabled and demo users disabled.
- Server `qsfera_full/validate-production-env.sh` checks production `.env` invariants before compose validation: TLS validation enabled, demo users disabled, pinned production image, required domains, required secrets, and no public-production MinIO.
- Added `scripts/validate-server-production-env.ps1` with the same `qsfera_full` production `.env` checks for the local Windows/PowerShell workflow; it validates required domains, release image pinning, disabled demo/insecure modes, required secrets, optional Keycloak/S3 blocks, and backup-friendly config/data path warnings without printing secret values.
- `scripts/validate-server-production-env.ps1` was verified on 2026-06-12: it rejects `Server/devtools/deployments/qsfera_full/env.production.example` with placeholder values and accepts a temporary filled production-shaped env file with `0 warning(s)`.
- Added `scripts/validate-server-production-env.ps1` with the same `qsfera_full` production `.env` checks for the local Windows/PowerShell workflow; it validates required domains, release image pinning, disabled demo/insecure modes, required secrets, optional Keycloak/S3 blocks, `COMPOSE_PATH_SEPARATOR`, selected `COMPOSE_FILE` fragments, and backup-friendly config/data path warnings without printing secret values.
- `scripts/validate-server-production-env.ps1` was verified on 2026-06-12: it rejects `Server/devtools/deployments/qsfera_full/env.production.example` with placeholder values, accepts a temporary filled production-shaped env file with `0 warning(s)`, and rejects a temporary env file where `COMPOSE_FILE` omits the required `qsfera.yml` fragment.
- Server now has a Raspberry Pi 5 Docker path matching the Ikar/Argus deployment style: `Server/docker-compose.rpi5.yml`, `Server/.env.example`, and `Server/docs/raspberry-pi-5-docker.md`.
- Server Docker builds now accept explicit production metadata for `QSFERA_VERSION`, `QSFERA_EDITION`, and `QSFERA_BUILD_DATE`, and the Raspberry Pi 5 compose path defaults to pinned image `qsfera-cloud-server:7.0.0-rpi5-stable`.
- Windows/Desktop update channel defaults now match the build channel: stable builds default to `stable`, beta builds default to `beta`.
@@ -87,6 +87,21 @@ function Require-Secret([hashtable]$Values, [string]$Key) {
}
}
function Require-ExactValue([hashtable]$Values, [string]$Key, [string]$ExpectedValue) {
$value = Get-EnvValue $Values $Key
if ($value -ne $ExpectedValue) {
Add-Error "$Key must be $ExpectedValue."
}
}
function Test-ComposeFileIncludes([string]$ComposeFile, [string]$EnvKey, [string]$Fragment) {
if ([string]::IsNullOrWhiteSpace($ComposeFile)) {
return $false
}
return $ComposeFile.Contains($Fragment) -or $ComposeFile.Contains('${' + $EnvKey + ':-}')
}
$resolvedEnvPath = (Resolve-Path -LiteralPath $EnvPath -ErrorAction Stop).Path
$values = Read-EnvFile $resolvedEnvPath
@@ -113,11 +128,27 @@ if ([string]::IsNullOrWhiteSpace($dockerTag) -or $dockerTag -eq "latest" -or ($d
Add-Error "OC_DOCKER_TAG must pin a concrete production release tag."
}
Require-ExactValue $values "COMPOSE_PATH_SEPARATOR" ":"
$composeFile = Get-EnvValue $values "COMPOSE_FILE"
if ([string]::IsNullOrWhiteSpace($composeFile) -or -not $composeFile.Contains("docker-compose.yml")) {
Add-Error "COMPOSE_FILE must include docker-compose.yml."
}
if (-not (Test-Enabled $values "QSFERA")) {
Add-Error "QSFERA=:qsfera.yml must be enabled."
} else {
Require-ExactValue $values "QSFERA" ":qsfera.yml"
if (-not (Test-ComposeFileIncludes $composeFile "QSFERA" "qsfera.yml")) {
Add-Error "COMPOSE_FILE must include qsfera.yml or the `${QSFERA:-} expansion."
}
}
if (Test-Enabled $values "DECOMPOSEDS3") {
Require-ExactValue $values "DECOMPOSEDS3" ":decomposeds3.yml"
if (-not (Test-ComposeFileIncludes $composeFile "DECOMPOSEDS3" "decomposeds3.yml")) {
Add-Error "COMPOSE_FILE must include decomposeds3.yml or the `${DECOMPOSEDS3:-} expansion when DECOMPOSEDS3 is enabled."
}
Require-Value $values "DECOMPOSEDS3_ENDPOINT"
Require-Value $values "DECOMPOSEDS3_REGION"
Require-Secret $values "DECOMPOSEDS3_ACCESS_KEY"
@@ -127,9 +158,16 @@ if (Test-Enabled $values "DECOMPOSEDS3") {
if (Test-Enabled $values "DECOMPOSEDS3_MINIO") {
Add-Error "DECOMPOSEDS3_MINIO is for test/lab installs and must not be enabled for public production."
if (-not (Test-ComposeFileIncludes $composeFile "DECOMPOSEDS3_MINIO" "minio.yml")) {
Add-Error "COMPOSE_FILE must include minio.yml or the `${DECOMPOSEDS3_MINIO:-} expansion when DECOMPOSEDS3_MINIO is enabled."
}
}
if (Test-Enabled $values "KEYCLOAK") {
Require-ExactValue $values "KEYCLOAK" ":keycloak.yml"
if (-not (Test-ComposeFileIncludes $composeFile "KEYCLOAK" "keycloak.yml")) {
Add-Error "COMPOSE_FILE must include keycloak.yml or the `${KEYCLOAK:-} expansion when KEYCLOAK is enabled."
}
Require-Value $values "KEYCLOAK_DOMAIN"
Require-Value $values "KEYCLOAK_REALM"
Require-Secret $values "KEYCLOAK_POSTGRES_PASSWORD"