fix(coolify): validate the dump bindings, and stop printing $EDITOR #10

Merged
dan-claude-bot merged 1 commit from fix/backup-bindings-validation into main 2026-07-12 19:59:21 +00:00
dan-claude-bot commented 2026-07-12 19:55:42 +00:00 (Migrated from github.com)

Follow-up to #9, from running it on a real control-plane box for the first time. Both bugs
were invisible to the argument-parsing tests — they only exist once the thing actually
executes.

1. $EDITOR is unset on a fresh server

rig printed $EDITOR /etc/coolify-dump.env as the next step. On a freshly-bootstrapped Debian
box — rig's entire target environment$EDITOR is unset, so that expands to just the
path, bash tries to execute the 0600 file, and you get:

-bash: /etc/coolify-dump.env: Permission denied

Which reads like a permissions bug and isn't one. Now prints nano.

2. Malformed bindings failed deep, and opaquely

S3_BUCKET=my-bucket (no s3://) reads to aws as a local path, so the run died with:

usage: aws s3 cp <LocalPath> <S3Uri> or <S3Uri> <LocalPath> or <S3Uri> <S3Uri>
Error: Invalid argument type

after pg_dump had run and age had encrypted 14 MB, and with nothing in the error
pointing at the actual mistake. The script now validates up front, before spending a dump:

  • S3_BUCKET must be an s3:// URI
  • S3_ENDPOINT must carry a scheme

Both fail with the offending value quoted and the reason stated.

What still cannot be validated — and now says so

age's X25519 header does not reveal its recipient. A valid-but-wrong key (staging's
instead of prod's) produces a flawless backup that nobody can open, forever, silently. No check
in rig can catch that. Only decrypting an artifact can.

So the printed next-steps now walk through the read-back explicitly — stream the newest object
down and decrypt it from a machine holding the private key, never the box — and the script
carries a comment saying why that step is not optional. A backup you have never read back is
not yet a backup.

Testing

The dump script ships as an embedded heredoc, so a syntax error in it would be invisible to
CI and would first surface at 04:00 on a live control plane. test/cli.sh now extracts it and
asserts it is valid bash, and that both new guards fire.

bash test/cli.sh39 passed, 0 failed (35 → 39). shellcheck clean.

Verified on the real box: dump → age → Hetzner Object Storage → streamed back → decrypted
with the prod key → PostgreSQL SQL. The full path works; these are the two rough edges it hit
getting there.

🤖 Generated with Claude Code

Follow-up to #9, from running it on a real control-plane box for the first time. Both bugs were invisible to the argument-parsing tests — they only exist once the thing actually executes. ## 1. `$EDITOR` is unset on a fresh server rig printed `$EDITOR /etc/coolify-dump.env` as the next step. On a freshly-bootstrapped Debian box — *rig's entire target environment* — `$EDITOR` is unset, so that expands to just the path, bash tries to **execute** the `0600` file, and you get: ``` -bash: /etc/coolify-dump.env: Permission denied ``` Which reads like a permissions bug and isn't one. Now prints `nano`. ## 2. Malformed bindings failed deep, and opaquely `S3_BUCKET=my-bucket` (no `s3://`) reads to `aws` as a **local path**, so the run died with: ``` usage: aws s3 cp <LocalPath> <S3Uri> or <S3Uri> <LocalPath> or <S3Uri> <S3Uri> Error: Invalid argument type ``` — *after* `pg_dump` had run and `age` had encrypted 14 MB, and with nothing in the error pointing at the actual mistake. The script now validates up front, before spending a dump: - `S3_BUCKET` must be an `s3://` URI - `S3_ENDPOINT` must carry a scheme Both fail with the offending value quoted and the reason stated. ## What still cannot be validated — and now says so age's X25519 header **does not reveal its recipient**. A valid-but-*wrong* key (staging's instead of prod's) produces a flawless backup that nobody can open, forever, silently. No check in rig can catch that. Only decrypting an artifact can. So the printed next-steps now walk through the read-back explicitly — stream the newest object down and decrypt it **from a machine holding the private key, never the box** — and the script carries a comment saying why that step is not optional. *A backup you have never read back is not yet a backup.* ## Testing The dump script ships as an **embedded heredoc**, so a syntax error in it would be invisible to CI and would first surface at 04:00 on a live control plane. `test/cli.sh` now extracts it and asserts it is valid bash, and that both new guards fire. `bash test/cli.sh` → **39 passed, 0 failed** (35 → 39). shellcheck clean. Verified on the real box: dump → `age` → Hetzner Object Storage → streamed back → decrypted with the prod key → PostgreSQL SQL. The full path works; these are the two rough edges it hit getting there. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/rig#10
No description provided.