修复异机备份凭证与中断恢复(07-27-offhost-backup-final-fixes)
这个提交包含在:
@@ -952,6 +952,12 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
|
||||
destination match. Do not split human-formatted Go-template output on tabs or
|
||||
spaces: `println` inserts argument spacing that can make a visually correct
|
||||
line fail exact path comparison on a real daemon.
|
||||
- Database connection values used by the automatic wrapper must be exported in
|
||||
an isolated child shell before `capture_command`; do not invoke `env` with a
|
||||
complete `DATABASE_URL` or password assignment in its argv. Docker backup and
|
||||
shadow-restore commands inherit `PGPASSWORD` with
|
||||
`PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD ...`; never use a
|
||||
value-bearing `-e PGPASSWORD=...` Docker argument.
|
||||
- Transfer only a complete `auto-<UTC timestamp>` three-file batch to ARM
|
||||
inbox. The forced key allows write-only `rrsync` or an exact finalize command;
|
||||
it rejects shell, sender/read and destructive rsync options.
|
||||
@@ -962,6 +968,22 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
|
||||
point to a same-filesystem rollback name, publish the candidate, rebuild that
|
||||
ISO week's hard-link checkpoint, then remove the rollback. Any publication or
|
||||
weekly-checkpoint failure restores the prior daily point.
|
||||
- After taking the finalize lock and before reading the incoming partial, ARM
|
||||
reconciles interrupted same-filesystem transactions. A valid
|
||||
`.daily-replacement-<UTC-day>.*` is deleted only when one valid canonical
|
||||
archive for that day exists; when the canonical is absent it is renamed back
|
||||
from its own verified manifest identity. Invalid, linked, duplicate or
|
||||
otherwise ambiguous daily state fails closed and preserves every object.
|
||||
- Weekly `.rollback.*` is authoritative only after full batch validation and is
|
||||
restored when the canonical checkpoint is absent. Weekly `.new.*` is never an
|
||||
authoritative source; it may be removed only after a valid canonical,
|
||||
rollback or unique valid daily source is established. Invalid canonical,
|
||||
rollback, duplicate candidate, week mismatch or non-unique rebuild source
|
||||
fails closed without deleting evidence. A reconciled daily point forces its
|
||||
ISO-week checkpoint to be rebuilt before finalize continues. When a valid
|
||||
canonical daily point and its old rollback coexist, defer deleting that daily
|
||||
rollback until every required weekly reconciliation has succeeded; a weekly
|
||||
validation or rebuild failure must leave the daily rollback in place.
|
||||
- Write production `last-success.json` and prune source copies only after ARM
|
||||
finalize succeeds. Keep seven automatic source/ARM daily points and four ARM
|
||||
weekly checkpoints; unrelated manual batches are outside automatic retention.
|
||||
@@ -995,6 +1017,14 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
|
||||
diagnostic. A corrupt same-day candidate leaves the previous archive intact.
|
||||
- Valid same-day retry -> replace only that UTC day's point and rebuild its ISO
|
||||
weekly checkpoint; concurrent finalize -> `flock` rejection.
|
||||
- Interrupted daily replacement with valid canonical -> remove the verified old
|
||||
rollback only after rebuilding the weekly point; canonical missing -> restore
|
||||
the verified rollback; canonical invalid, weekly rebuild failure or candidates
|
||||
ambiguous -> preserve the remaining rollback evidence and fail.
|
||||
- Interrupted weekly replacement with valid canonical -> remove safe staging
|
||||
and verified rollback; canonical missing + valid rollback -> restore it;
|
||||
staging-only + one valid daily source -> rebuild; any invalid or ambiguous
|
||||
authority -> preserve all objects and fail.
|
||||
- Missing, corrupt, stale, future or project-mismatched success record -> hard
|
||||
watchdog failure. Fresh build mismatch -> one finding without a failing exit.
|
||||
- Missing/non-regular/symlink/non-`0600` Webhook file -> fail closed without
|
||||
@@ -1025,9 +1055,15 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
|
||||
runner. A simplified tab-delimited mock is not valid evidence for real mount
|
||||
parsing.
|
||||
- Contract assertions for same-day replacement, corrupt-candidate preservation,
|
||||
weekly hard-link rebuild, source diagnostic mode, build mismatch finding,
|
||||
Webhook mode/symlink rejection and group alert behavior without a server
|
||||
container. Test transport must be explicitly gated and local-only.
|
||||
weekly hard-link rebuild, daily/weekly interrupted-transaction recovery,
|
||||
rollback preservation when weekly reconciliation fails, ambiguous-state
|
||||
preservation, source diagnostic mode, build mismatch finding, Webhook
|
||||
mode/symlink rejection and group alert behavior without a server container.
|
||||
Test transport must be explicitly gated and local-only.
|
||||
- Mock Docker assertions must prove synthetic connection values are absent from
|
||||
wrapper/backup/restore argv while an inherited `PGPASSWORD` reaches the
|
||||
mocked container command. Test-fixture `env KEY=value` launch arrays do not
|
||||
need mechanical rewriting because they contain only synthetic values.
|
||||
- Environment contract assertions for both helpers, both installers, production
|
||||
timers, ARM dead-man timer, explicit project/data/build/SSH/Webhook-file
|
||||
binding, disabled-by-default installation and absence of a literal complete
|
||||
@@ -1044,6 +1080,7 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
|
||||
```bash
|
||||
compose exec server send-alert --recipient=<personal-employee-number>
|
||||
rsync -a <batch>/ backup-host:<archive>/
|
||||
docker exec -e PGPASSWORD="$POSTGRES_PASSWORD" db pg_dump ...
|
||||
```
|
||||
|
||||
#### Correct
|
||||
@@ -1057,4 +1094,6 @@ rsync -a <batch>/ backup-host:<archive>/
|
||||
python3 scripts/check-offhost-backup-deadman.py <explicit-safe-path-arguments>
|
||||
# The runner writes success and prunes only after restricted target finalize.
|
||||
bash scripts/run-automatic-backup.sh run
|
||||
# The Docker CLI inherits the value without placing it in argv.
|
||||
PGPASSWORD="$POSTGRES_PASSWORD" docker exec -e PGPASSWORD db pg_dump ...
|
||||
```
|
||||
|
||||
在新工单中引用
屏蔽一个用户