#!/usr/bin/env bash # Run ON a prod/beta box (via `ssh 'bash -s' < this`), after the encrypted vault # file has been scp'd to /tmp/tg-.yaml. NON-DESTRUCTIVE go/no-go for the cutover: # renders the vault and diffs the KEY=VALUE set against the live /etc/thermograph.env. # Prints only PASS/FAIL and any differing key NAMES — never secret values. No git, no # writes; touches nothing. (The encrypted file is safe to ship; only ciphertext.) set -euo pipefail key=/etc/thermograph/age.key env_name="$(sudo cat /etc/thermograph/secrets-env)" host="/tmp/tg-${env_name}.yaml" common="/tmp/tg-common.yaml" command -v sops >/dev/null || { echo "FAIL: sops not installed"; exit 1; } [ -f "$host" ] || { echo "FAIL: $host not found — scp the encrypted vault file first"; exit 1; } keymat="$(sudo grep '^AGE-SECRET-KEY-' "$key")" tmp="$(mktemp)"; live="$(mktemp)"; trap 'rm -f "$tmp" "$live"' EXIT : > "$tmp" [ -f "$common" ] && SOPS_AGE_KEY="$keymat" sops -d --input-type yaml --output-type dotenv "$common" >> "$tmp" SOPS_AGE_KEY="$keymat" sops -d --input-type yaml --output-type dotenv "$host" >> "$tmp" sudo cat /etc/thermograph.env > "$live" python3 - "$live" "$tmp" <<'PY' import sys def load(p): out={} for line in open(p, encoding="utf-8"): s=line.rstrip("\n").strip() if not s or s.startswith("#") or "=" not in s: continue k,_,v=s.partition("="); out[k.strip()]=v return out live,rend=load(sys.argv[1]),load(sys.argv[2]) lost=sorted(set(live)-set(rend)); added=sorted(set(rend)-set(live)) changed=sorted(k for k in live if k in rend and live[k]!=rend[k]) if lost or added or changed: print("FAIL — the render would NOT match the live env") if lost: print(" lost keys:", lost) if added: print(" extra keys:", added) if changed: print(" value-changed keys:", changed) sys.exit(1) print(f"PASS — all {len(live)} keys render byte-identical to the live /etc/thermograph.env") PY