完成(08-09-production-admin-break-glass-reset): 恢复管理员认证
这个提交包含在:
@@ -1924,3 +1924,68 @@ node scripts/qa/payment-batch-flag-snapshot.mjs restore --snapshot-file "$REPORT
|
||||
```tsx
|
||||
<Link to="/mobile/payment-batches">进入付款</Link>
|
||||
```
|
||||
|
||||
## Scenario: Unique Production Administrator Break-Glass Reset
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: the only active production administrator cannot authenticate, self-service reset is unavailable, and a separately approved task restores access with the existing break-glass script.
|
||||
- Purpose: make the single irreversible reset attempt observable without exposing credentials or treating historical audit rows as proof of the current run.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Read-only commands: `--preflight`, `--verify`, `--verify-password-changed`, `--diagnose-wecom-binding` on `server/src/scripts/reset-active-admin-password.js`.
|
||||
- Single write command: `node src/scripts/reset-active-admin-password.js --apply ACTIVE_ADMIN_BREAK_GLASS`, with the temporary password on stdin only.
|
||||
- Browser lifecycle: `/login` -> `/change-password` -> `/portal`, one login submission and one password-change submission.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- Compare the running-container script SHA with the reviewed deployed candidate before selecting a target. A workspace copy must never be pushed into the container to make the check pass.
|
||||
- Create a local apply-attempt sentinel before opening the SSH/container channel. Missing output, non-zero transport status or invalid JSON enters `APPLY_UNCERTAIN`; only `--verify` may classify the result, and apply is never retried.
|
||||
- Capture the break-glass audit count before apply and require an increment of exactly one afterward. `auditPresent=true` alone is insufficient because a historical reset may already satisfy that boolean.
|
||||
- `--verify` immediately after apply must prove the unique target, must-change=true, cleared locks, zero active sessions, zero active password-reset codes, zero active email-login codes and a break-glass audit.
|
||||
- Atomically replace the repository-external smoke secret first with the temporary credential and later with the final credential. Before consuming the one allowed login, read the file back in-process and compare both identifier and password to the controlled source; a successful rename without content agreement is not readiness.
|
||||
- The browser runner receives credentials through controlled file descriptors/stdin, blocks non-authentication business APIs, submits each form once, clears browser state and does not enter business pages.
|
||||
- A prior hash may be kept only as approved `0700/0600` short-lived recovery material. Destroy it and all temporary credentials after `--verify-password-changed` passes; evidence stores booleans/counts, never values or paths.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Running script SHA mismatch, target count other than one or binding conflict -> stop before recovery material and apply.
|
||||
- Active session with recent activity -> stop and confirm operator ownership; an old inactive session may be revoked only when that side effect is already approved.
|
||||
- Apply channel/result uncertain -> write no second password; run `--verify` only.
|
||||
- Apply PASS but `--verify` fails -> do not log in; retain controlled materials until a new decision or the custody deadline.
|
||||
- Secret update content mismatch -> do not consume the login attempt; fix the local atomic update and re-verify without another apply.
|
||||
- Login or change-password submission fails -> zero retry; preserve the known credential state and request a new decision.
|
||||
- Recovery-material deletion fails -> task remains incomplete even when the final password works.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: audit baseline 1 becomes 2 after one apply, immediate verify passes, one login completes forced change, final verify passes, and all temporary material is destroyed.
|
||||
- Base: audit baseline 0 becomes 1 with the same state-machine checks.
|
||||
- Bad: accept `auditPresent=true` when the baseline was already positive, blindly retry after an SSH interruption, or attempt login before proving the temporary secret contains the new credential.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- Source review must trace every session/challenge update to `where.employee_id=target.id`. When this script's write behavior changes, focused unit tests must additionally assert those exact `where` arguments; call-count assertions alone do not prove target scoping.
|
||||
- Unit tests cover non-unique target refusal, transaction-time target change, apply side effects and both verify modes.
|
||||
- Execution evidence asserts runtime-script SHA match, apply-attempt count 1, audit delta exactly 1, the complete post-apply verify fields, login/change submit counts 1/1 and cleanup booleans.
|
||||
- Run focused script tests, Node syntax, task/process/governance/sensitive gates and `git diff --check`; an authentication-state-machine task additionally receives a read-only reviewer.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```text
|
||||
apply output missing -> retry apply
|
||||
verify.auditPresent=true -> current audit write proved
|
||||
atomic rename succeeded -> consume the only login attempt
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```text
|
||||
create attempt sentinel -> apply once -> uncertain output means verify only
|
||||
capture audit baseline -> require baseline + 1
|
||||
atomic rename -> compare identifier/password in-process -> login once
|
||||
-> change password once -> final verify -> destroy temporary material
|
||||
```
|
||||
|
||||
在新工单中引用
屏蔽一个用户