修复自动备份运行身份漂移(07-28-automatic-backup-runtime-identity-failure)

这个提交包含在:
2026-07-28 07:54:37 +08:00
父节点 4e3c6c4376
当前提交 cba74cf97d
共修改 9 个文件,包含 198 行新增和 1 行删除
+30 -1
查看文件
@@ -1005,6 +1005,13 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
Compose-project-mismatched state. A fresh recovery point with a different
build SHA is `PASS_WITH_FINDINGS`, because deploy-time code identity and
recoverable data freshness are separate facts.
- Automatic-backup units freeze the active Compose project, build, PGDATA and
storage mount when installed. After any deployment, rollback or direct
container rebuild that changes the active container identity or host mounts,
compare all frozen values with the unique running server/database pair. If
the units are already installed and any value differs, rerun the existing
installer with the complete current contract and recheck all identities
before declaring the deployment complete; do not patch one unit in place.
- Installer `install` is disabled-by-default; `enable`, real transfer, real
WeCom alert and all server/account/key changes remain `EXTERNAL_GATED`.
@@ -1027,6 +1034,10 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
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.
- `phase_stale_check_failed` can also mean the watchdog failed its runtime
identity precheck before reading the success record. Diagnose the nested safe
category and active-unit identity first; do not infer that the last archive is
stale or corrupt from this outer phase alone.
- Missing/non-regular/symlink/non-`0600` Webhook file -> fail closed without
printing the file value. Identical alert state -> update/evaluate without send.
- Ordinary shell, rsync sender/read/delete or archive overwrite -> receiver
@@ -1040,12 +1051,16 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
resumes inside inbox, ARM finalize verifies and archives it, then production
writes success and prunes old automatic source points. If production later
stops, ARM independently raises one dead-man alert and one recovery notice.
- Good: a deployment rebuilds the server with a different storage mount, then
refreshes the installed backup units through the installer and proves every
frozen identity matches before closing the deployment.
- Base: local implementation and synthetic contracts pass while both server
installers remain disabled and explicitly externally gated.
- Bad: send through `compose exec server`, hard-code a personal employee number,
persist a robot URL in `.env`/unit/repository, give production a normal ARM
login key, put archive below inbox, accept a new host fingerprint automatically,
or prune local points before target-side finalize.
prune local points before target-side finalize, or leave installed backup
units bound to a pre-deployment mount until the next scheduled alert.
### 6. Tests Required
@@ -1068,6 +1083,10 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
timers, ARM dead-man timer, explicit project/data/build/SSH/Webhook-file
binding, disabled-by-default installation and absence of a literal complete
robot URL in tracked or untracked repository files.
- Deployment and rebuild review must assert that installed production units
still match the unique active project, build, PGDATA and storage mount. A
changed mount with otherwise healthy `/ready` is not a completed deployment
until installer refresh, timer state and runtime identity all pass.
- Real ARM setup, first paired batch, deliberate source-timer stop or transfer
failure, dead-man first/repeated/recovery behavior and quarterly shadow restore
are separately approved operational evidence. A direct robot send test alone
@@ -1078,6 +1097,10 @@ test "$(printf '%s\n' "$actual" | LC_ALL=C sort)" = \
#### Wrong
```bash
# Rebuild the application, observe /ready, but leave installed backup units
# frozen to the pre-deployment runtime identity.
docker-compose <approved-compose-arguments> up -d --build server
compose exec server send-alert --recipient=<personal-employee-number>
rsync -a <batch>/ backup-host:<archive>/
docker exec -e PGPASSWORD="$POSTGRES_PASSWORD" db pg_dump ...
@@ -1086,6 +1109,12 @@ docker exec -e PGPASSWORD="$POSTGRES_PASSWORD" db pg_dump ...
#### Correct
```bash
# After a deployment/rebuild, compare the installed unit contract with the
# unique active server/database pair. If any frozen identity changed, refresh
# all units through the installer before verifying timers and identity again.
<complete-current-contract-env> \
bash deploy/trialrun/install-automatic-backup-timer.sh enable
# Install only with explicit active identity and a root-only Webhook file path;
# default remains disabled.
<explicit-project-data-build-ssh-and-webhook-file-env> \