Skip to content

Fix the remaining known bugs from the end-to-end suite - #36

Merged
itbm merged 1 commit into
masterfrom
claude/vibrant-newton-4n6mke
Oct 21, 2026
Merged

itbm merged 1 commit into
masterfrom
claude/vibrant-newton-4n6mke

Conversation

@itbm

@itbm itbm commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Fixes the known bugs that #34 left open. Each one has an end-to-end test marked xfail; this PR removes the last of those markers, so the suite now checks every bug it found.

#34 (merged) fixes 31 of the 41 known bugs. This PR fixes the other 10, and finishes one that #34 fixes only in part. It was opened against #34's branch and is now based on master, which holds #34; the diff is the same single commit.

Fixes

Area Bug Fix
Backup A database name starting with - is read as pg_dump options, so another database is backed up under that name The name goes to pg_dump, psql and pg_restore as -d "dbname='…'", and restore.sh no longer runs basename on BACKUP_FILE
Backup A database name containing =, or a POSTGRES_USER containing a space, breaks the dump As above, and the user reaches libpq as PGUSER
Encryption AES-CBC has no integrity check, so a wrong key "decrypts" about 1 time in 256: about 1 legacy backup in 256 can't be restored, and a wrong password with DROP_DATABASE=yes can drop the database before the restore fails A decryption counts only if the result is a readable backup (it decompresses, or pg_restore --list reads it). Otherwise the legacy key derivation is tried, then the restore stops before it touches the database and says why
Restore A custom-format restore into PostgreSQL 16 or older exits 1 although the data is restored (pg_restore 18 sends SET transaction_timeout) When those are the only errors and pg_restore carried on past them, the restore succeeds
Retention Keys with leading, trailing or repeated spaces are mixed up, and a key containing PRE is never deleted Keys are read from the aws s3 ls line as they are; only sub-prefix lines are skipped. BACKUP_FILE=latest uses the same parser
Retention A future threshold (DELETE_OLDER_THAN="7 days", missing "ago") deletes everything else in the prefix and exits 0. #34 already keeps the new backup Rejected before the backup starts
Hooks HOOK_INHERIT_ENV=yes drops HOOK_EVENT and HOOK_EXIT_CODE Both are passed, as with the default allowlist

Behaviour changes

  • POSTGRES_USER reaches libpq as PGUSER instead of -U. Leading and trailing spaces are still dropped, and -U in POSTGRES_EXTRA_OPTS still overrides it. Host and port stay on the command line. Hooks run with HOOK_INHERIT_ENV=yes now also see PGUSER; they already saw PGPASSWORD.
  • A DELETE_OLDER_THAN in the future now fails the run before the backup, as an invalid date already does.
  • An encrypted backup that decrypts but isn't readable, for example a damaged one, is now reported before the database is dropped, instead of failing part-way through the restore.

Review

An independent review of this PR and of my commits on #34 found these problems, and they're fixed here or on #34:

  • On Fix backup bugs, harden runtime and add essential features #34:
    • the PostgreSQL 16 fix could also drop a matching line from function bodies;
    • it ignored POSTGRES_EXTRA_OPTS=-x;
    • DELETE_MATCH_DATABASE=yes also deleted app_archive_… backups for a database named app;
    • an empty ENCRYPTION_PASSWORD_FILE uploaded an unencrypted backup.
  • In this PR, an earlier version:
    • ran psql before every custom-format restore, which broke pg_restore-only options such as --no-owner in POSTGRES_EXTRA_OPTS;
    • let a key starting with - break basename.

Tests

  • End-to-end:

    • CI ran the full suite on 2a8cf9d, and all 11 case-file jobs pass. The suite now has no xfail markers.
    • A local full run of an earlier version of this branch passed 231 tests, with 0 failures and 0 expected failures. The review fixes made after it are covered by the 22 tests I reran locally on the final image.
  • New end-to-end tests:

    • backing up and restoring a database named like an option and a connection string (-d…_src=x'y\z): plain, custom format with one and two jobs, and BACKUP_FILE=latest from the bucket root;
    • a custom-format restore with --no-owner --no-privileges in POSTGRES_EXTRA_OPTS;
    • a future DELETE_OLDER_THAN deleting nothing.

    The harness's own psql calls now pass database names as connection strings too.

  • Unit tests (test/hooks_test.sh, 172): new checks cover:

    • retention and BACKUP_FILE=latest key parsing;
    • a future threshold;
    • option-like database names and PGUSER;
    • hook variables with HOOK_INHERIT_ENV=yes;
    • the pg_restore compatibility rule, including --single-transaction, where pg_restore stops at the first error and the restore must fail.

    They pass under dash, bash and the image's BusyBox sh.

  • ShellCheck 0.11, as pinned in CI, is clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UdSRPLaq3mTA6Djdzte7C5

Fixes the 10 bugs the end-to-end suite still marks as xfail on the
bug-fix branch, and removes their markers:

- POSTGRES_USER reaches libpq as PGUSER, so a role name with a space
  works; surrounding whitespace is still dropped, as before. The
  database name is passed as "-d dbname='...'", so a name starting with
  "-" is no longer read as pg_dump options (which backed up a different
  database) and a name containing "=" is no longer read as a connection
  string. This applies to pg_dump, psql and pg_restore, and restore.sh
  no longer runs basename on BACKUP_FILE, which read a key starting
  with "-" as options.
- Restores of encrypted backups check that the decrypted file is a
  readable backup (it decompresses, or pg_restore --list reads it).
  AES-CBC has no integrity check, so about 1 decryption in 256 with the
  wrong key "succeeds". Before, about 1 legacy backup in 256 could not
  be restored, and a wrong password with DROP_DATABASE=yes could drop
  the database before the restore failed. When no decryption is
  readable, the log says why.
- Retention and BACKUP_FILE=latest read each key from the 'aws s3 ls'
  line as it is, instead of rebuilding it with awk. Keys with leading,
  trailing or repeated spaces or tabs are no longer mixed up with other
  keys, and a key containing " PRE " is no longer skipped.
- A DELETE_OLDER_THAN in the future, such as "7 days" without "ago", is
  rejected before the backup starts. Before, it deleted everything else
  in the prefix and reported success.
- HOOK_INHERIT_ENV=yes passes HOOK_EVENT, and HOOK_EXIT_CODE to error
  hooks, like the default allowlist does.
- A custom-format restore into PostgreSQL 16 or older no longer fails
  when its only errors come from SET transaction_timeout, which
  pg_restore 17 and later send on every connection. pg_restore's
  messages are still shown as they come.

The e2e harness now passes database names to psql as connection
strings too. New tests cover backing up and restoring such names (plain
and custom format, one and two jobs, BACKUP_FILE=latest at the bucket
root), BACKUP_FILE=latest for names with repeated spaces or " PRE ", a
future DELETE_OLDER_THAN deleting nothing, and a custom-format restore
with pg_restore-only options in POSTGRES_EXTRA_OPTS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UdSRPLaq3mTA6Djdzte7C5
@itbm
itbm deleted the branch claude/wizardly-lovelace-70vymp October 21, 2026 06:56
@itbm itbm closed this Oct 21, 2026
@itbm itbm reopened this Oct 21, 2026
@itbm
itbm changed the base branch from claude/wizardly-lovelace-70vymp to master October 21, 2026 06:58
@itbm
itbm merged commit 53af108 into master Oct 21, 2026
34 checks passed
@itbm
itbm deleted the claude/vibrant-newton-4n6mke branch October 21, 2026 07:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants