实现(08-08-production-deployment-execution): 校准生产身份只读门禁
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-08-08 17:33:25 +08:00
父节点 6ccb9cd5e3
当前提交 f11e2f2c25
共修改 11 个文件,包含 666 行新增和 30 行删除
@@ -19,6 +19,69 @@ operations require explicit approval and evidence.
- Do not execute real payments, import bank statements, connect payment
providers or write ERP without a separate approved Trellis task.
## Scenario: Exact Production Identity Bootstrap Before Migration Status
### 1. Scope / Trigger
- Trigger: the public environment has a legacy name that resembles a trial or staging environment, or the production database identity is intentionally absent from the repository.
- Purpose: identify the one approved deployment by independent exact values without treating a name token as proof for or against production.
### 2. Signatures
- Bootstrap entry: `node deploy/trialrun/production-identity-bootstrap.mjs`.
- Read-only stop: `PRODUCTION_READ_ONLY_PREFLIGHT=1 node deploy/trialrun/production-identity-bootstrap.mjs`.
- Exact local inputs passed to the existing wrapper: `EXPECTED_DEPLOY_SERVER`, `EXPECTED_REMOTE_DIR`, `EXPECTED_COMPOSE_PROJECT_NAME`, `EXPECTED_PRODUCTION_ORIGIN` and `EXPECTED_PRODUCTION_DB_NAME_SHA256`.
### 3. Contracts
- Recover deployment target, repository root and Compose project from reviewed Git history; when values come from different commits, require their shared identity fields to agree.
- Select the refresh identity only when exactly one concrete SSH candidate returns the exact forced-command probe token. Do not print candidate aliases.
- Compare target, directory and project independently. Missing or empty expected values are errors, not reasons to skip a comparison.
- A legacy token such as `trialrun` is neutral. Continue to reject loopback/zero addresses, local regression, staging, shadow and placeholder identities.
- Read `POSTGRES_DB` only after history, systemd contract and public origin agree. Keep the database name remote; pass only a hash comparison baseline to the preflight.
- Read-only mode must exit after target/pre-status and rollback-window checks and before `deploy.sh`, rsync, migration or application switching.
### 4. Validation & Error Matrix
- Zero refresh probe matches -> `REFRESH_IDENTITY_NOT_FOUND`; stop before target gate.
- Multiple exact probe matches -> `REFRESH_IDENTITY_NOT_UNIQUE`; do not select the first candidate.
- Historical target/directory/project disagreement -> an explicit `HISTORICAL_*` or `SYSTEMD_*_MISMATCH`; stop before database identity read.
- Any expected exact value missing/empty -> `EXPECTED_*_MISSING`; no SSH preflight fallback.
- Env origin or running-container origin differs from the approved origin -> `PROD_TARGET_*_ORIGIN_MISMATCH`; do not read migration status.
- Read-only mode reaches `deploy.sh` -> contract failure; tests and env validation must reject the ordering.
### 5. Good/Base/Bad Cases
- Good: a legacy-named deployment passes because all independent identity values match exactly, then read-only mode records status/window and exits before writes.
- Base: an explicitly supplied, unambiguous production identity passes the same exact comparisons.
- Bad: reject or accept solely because the alias/project contains or omits `trialrun`.
- Bad: database name lookup fails and the wrapper continues without comparing database identity.
### 6. Tests Required
- Positive fixture for the approved legacy naming pattern.
- Separate negative assertions and stable error codes for deploy target, remote directory and Compose project mismatches.
- Missing-value tests proving exact comparison cannot be skipped.
- Zero/multiple refresh-probe fixtures.
- Ordering assertion: identity/DB bootstrap -> target/pre-status/window -> read-only exit -> `deploy.sh` only when read-only mode is off.
- Evidence assertions proving target/path/database values are absent from stdout and committed reports.
### 7. Wrong vs Correct
#### Wrong
```text
name does not contain staging -> assume production -> run migrate deploy
```
#### Correct
```text
reviewed history + unique refresh probe + exact systemd contract + exact origin
-> remote-only DB identity hash -> target/pre-status/window
-> explicit read-only stop or separately approved deploy
```
## Scenario: Existing Deployment SSH Identity Disambiguation
### 1. Scope / Trigger