Public tool, private state. cast holds no hostnames, no bindings, no secrets: it joins a product repo's .infra/ manifest with a state directory you point it at, and makes Coolify match. Extracted from heavy-duty/infra, which was half tool and half state — the inconsistency that made it impossible to say whether "infra" named a CLI or a runbook. rig builds the boxes; cast fills them; infra is what they are filled with. Two changes were required to make it genuinely stateless and publishable: - The implicit cwd contract (environments.yaml / secrets/ / .coolify.env resolved against the working directory, silently reading the wrong file from the wrong place) is now an explicit --state <dir> / $CAST_STATE. - BANNED_IN_PROD — a hardcoded list of one product's ALLOW_* flags, the only product knowledge in the executor — becomes the generic, operator- owned environments.<env>.forbidden_var_patterns. The guard now lives in private state, so a product-side change cannot lower its own guard, and it is a pattern rather than a list, so it catches unforeseen siblings. Age identities resolve as $CAST_AGE_KEY_FILE_<ENV> then ~/.config/cast/age-<env>.key — which is the entire attended-vs-unattended apply mechanism, with no environment names known to the tool. Instance identity (org names, the GitHub App name, founder domains) is out of the fixtures and out of register-github-app.sh, which took APP_NAME and ORG as arguments rather than baking them in. 69 tests green; bin/cast + curl installer mirror rig's shape. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
12 lines
644 B
Bash
Executable file
12 lines
644 B
Bash
Executable file
#!/usr/bin/env bash
|
|
# Nightly on the coolify box: dump Coolify's own Postgres, age-encrypt
|
|
# client-side (dump holds GitHub App key, server SSH keys, all env values),
|
|
# ship to S3. Forensics only — a fresh instance is recreated, never restored.
|
|
set -euo pipefail
|
|
: "${AGE_RECIPIENT:?age public key for the backup identity}"
|
|
: "${S3_BUCKET:?s3 bucket, e.g. s3://my-backups/coolify-db}"
|
|
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
|
|
OUT="/tmp/coolify-db-${STAMP}.sql.age"
|
|
docker exec coolify-db pg_dump -U coolify coolify | age -r "$AGE_RECIPIENT" -o "$OUT"
|
|
aws s3 cp "$OUT" "${S3_BUCKET}/" --endpoint-url "${S3_ENDPOINT:?hetzner s3 endpoint}"
|
|
rm -f "$OUT"
|