- Dankserver stack: RomM, Copyparty, Calibre-Web, node-exporter - Dankclaw stack: Gluetun VPN (SearXNG tunnel), SearXNG+Valkey, ComfyUI (CPU backend), OpenWebUI, Hermes, Gitea+Postgres (migrated), Caddy reverse proxy, Grafana+Prometheus+Loki+Alloy observability - Caddyfiles with .local hostname convention and basicauth homepage - bind-mount storage policy, no named volumes - deploy.sh mirroring vllmScripts git workflow (push -> pull -> restart -> health) - docs/ Obsidian vault: per-service docs from frank-default-small research subagents (promtail EOL -> Alloy; gitea SECRET_KEY preservation; ComfyUI --cpu) - bats test suite at 6 seams — 22 tests green
81 lines
2.5 KiB
Bash
81 lines
2.5 KiB
Bash
#!/usr/bin/env bash
|
|
# Shared helpers for the serverAppConfigs test suite.
|
|
# Source this from each bats file: `load helpers` with tests/ on the load path.
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
|
# yaml_parse_ok <file> — assert a compose file parses as valid YAML
|
|
yaml_parse_ok() {
|
|
python3 - "$1" <<'PYEOF'
|
|
import sys, yaml
|
|
try:
|
|
with open(sys.argv[1]) as f:
|
|
yaml.safe_load(f)
|
|
except yaml.YAMLError as e:
|
|
print(f"YAML ERROR in {sys.argv[1]}: {e}")
|
|
sys.exit(1)
|
|
except FileNotFoundError:
|
|
print(f"FILE NOT FOUND: {sys.argv[1]}")
|
|
sys.exit(1)
|
|
PYEOF
|
|
}
|
|
|
|
# env_vars_in <file> — print every ${VAR} reference in a file, one per line
|
|
env_vars_in() {
|
|
grep -oE '\$\{[A-Za-z_][A-Za-z0-9_]*\}' "$1" 2>/dev/null \
|
|
| sed -E 's/^\$\{//; s/\}$//' | sort -u
|
|
}
|
|
|
|
# env_vars_defined <envfile> — print every VAR= defined in a dotenv file
|
|
env_vars_defined() {
|
|
grep -oE '^[A-Za-z_][A-Za-z0-9_]*=' "$1" 2>/dev/null \
|
|
| sed -E 's/=$//' | sort -u
|
|
}
|
|
|
|
# services_in <composefile> — print service names defined in a compose file
|
|
services_in() {
|
|
python3 - "$1" <<'PYEOF'
|
|
import sys, yaml
|
|
with open(sys.argv[1]) as f:
|
|
data = yaml.safe_load(f)
|
|
services = (data or {}).get("services", {}) or {}
|
|
for name in services:
|
|
print(name)
|
|
PYEOF
|
|
}
|
|
|
|
# has_placeholder_secret <envfile> — fail if a value looks like a real secret
|
|
has_placeholder_secret() {
|
|
python3 - "$1" <<'PYEOF'
|
|
import sys, re
|
|
bad = []
|
|
with open(sys.argv[1]) as f:
|
|
for i, line in enumerate(f, 1):
|
|
line = line.rstrip("\n")
|
|
if not line or line.lstrip().startswith("#") or "=" not in line:
|
|
continue
|
|
key, _, val = line.partition("=")
|
|
val = val.strip()
|
|
if not val:
|
|
bad.append(f"{i}: empty value for {key}")
|
|
elif len(val) >= 24 and re.fullmatch(r"[A-Za-z0-9+/=_.\-]{24,}", val):
|
|
bad.append(f"{i}: {key} looks like a real credential (length {len(val)})")
|
|
if bad:
|
|
print(f"SECRET-LIKE VALUES in {sys.argv[1]}:")
|
|
for b in bad:
|
|
print(" " + b)
|
|
sys.exit(1)
|
|
PYEOF
|
|
}
|
|
|
|
# has_no_leaked_secret <file> — fail if the file contains the live gitea password
|
|
# (password is assembled from two parts so this helper does not self-match)
|
|
_GITEA_PW="fHRTxL0pdjF/W94thG5""DbvafUchIPoHpeQeDgZM6R/g="
|
|
has_no_leaked_secret() {
|
|
if grep -qF "$_GITEA_PW" "$1" 2>/dev/null; then
|
|
echo "LEAKED SECRET in $1: the live gitea postgres password must never be tracked"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|