KB-6B87
dot-iu-cutter v0.4 — Credential Risk & Rollback Plan
6 min read Revision 1
dot-iu-cutterv0.4credential-designrisk-rollbackdieu44
dot-iu-cutter v0.4 — Credential Risk & Rollback Plan
document_path: knowledge/dev/laws/dieu44-trien-khai/v0.4-credential-design/dot-iu-cutter-v0.4-credential-risk-and-rollback-plan-2026-05-16.md
revision: r1
date_authored: 2026-05-17
cycle_date_label: 2026-05-16
author: Agent (Claude Code CLI, Opus 4.7 1M)
phase: v0.4 — credential-cycle DESIGN (risk + rollback)
status: design_only_pending_gpt_review
⛔ DESIGN ONLY. Nothing here is executed. The rollback procedure is a TARGET runbook for the SEPARATE, GPT-gated credential execution cycle.
§1 — Risk Classification
this_design_cycle: NONE-to-production. Output = 8 KB documents. Zero DB /
role / secret / .env / Directus / RLS / deploy touch. Irreversible-action
risk = none.
future_credential_EXECUTION cycle (assessed for routing, not run here):
class: STANDARD (consistent with v0.2 P0-2 / v0.3 read-obs ratings).
basis_for_STANDARD_not_HIGH:
- operates in an EMPTY schema (all 12 tables 0 rows — v0.2/v0.3
inventory); no business data at risk;
- creates only 2 LOGIN roles + a bounded ENUMERATED grant set; no DDL
on data objects, no superuser, no CREATEROLE/DB, no BYPASSRLS, no RLS,
no trigger/CHECK/DEFAULT;
- fully reversible (REVOKE + DROP ROLE; roles memberless & own nothing);
- preceded by a mandatory isolated dry-run PASS + GPT review +
command-review (blockers B-1..B-6).
why_not_LOW: it introduces WRITE-CAPABLE production identities for the
first time in the cutter programme — a real privilege increase, hence
STANDARD with mandatory dry-run + command-review gating.
residual_risks_to_carry:
R-1 secret leakage → mitigated by SC-5 redaction + process isolation +
separate keys (secret-custody doc).
R-2 over-grant drift → mitigated by exact catalog verification (dry-run
D-4) + schema-qualified/structural assertions (P0-6/P0-5 lesson).
R-3 SoD erosion via verify→cut_change_set INSERT (CD-8/CD-10) → flagged,
GPT-decided, append-only/forward-only constrained.
R-4 column-scoped UPDATE cannot enforce write-once on superseded_by →
stays a code invariant (test-proven in skeleton); documented.
R-5 single shared dot_pair_signature table → lane separation is
code/crypto only (CD-11); accepted, no DDL split in v0.4.
§2 — Rollback Principles
- rollback NEVER touches a base table, a view, cutter_ro, Directus, or any
data — credentials rollback is a ROLE/GRANT-only operation.
- NO CASCADE anywhere (no DROP … CASCADE, no REVOKE … CASCADE) — explicit,
enumerated, reversible steps only (carries the v0.2/v0.3 no-CASCADE rule).
- rollback is the EXACT inverse of the enumerated grant set — never a
blanket REVOKE ALL that could catch unintended privileges.
- every rollback step is GATED (pre-condition asserted before it runs).
§3 — Rollback Procedure (target; gated; not executed)
RB-0 GATE: confirm scope = credential objects only; snapshot catalog
(roles, grants, memberships) before any change.
RB-1 e-stop first if needed: `ALTER ROLE cutter_exec NOLOGIN` /
`ALTER ROLE cutter_verify NOLOGIN` (halts auth without privilege/role
change; fully reversible) — fastest containment.
RB-2 terminate live backends for the writer roles
(pg_terminate_backend on matching pg_stat_activity rows) so REVOKE/
DROP is not blocked by an active session.
RB-3 REVOKE the enumerated grants — the exact inverse of matrix doc §2
(per-table S/I, the 2 column-scoped UPDATEs, schema USAGE). NO CASCADE.
RB-4 GATE before DROP: assert each role is
(a) MEMBERLESS — `pg_auth_members` has no row where roleid/member =
the writer (no one inherits it, it inherits no one), AND
(b) OWNS NOTHING — `pg_shdepend` / `pg_class`/`pg_namespace` owner
scan shows 0 objects owned by the role, AND
(c) holds NO remaining privilege (post-RB-3 catalog clean).
If ANY of (a)(b)(c) fails → STOP, do NOT drop, escalate (a role that
owns something or has members must not be force-dropped).
RB-5 only if RB-4 all-pass: `DROP ROLE cutter_exec` / `DROP ROLE
cutter_verify` (plain DROP, never DROP OWNED / never CASCADE).
RB-6 verify: catalog returns to the pre-credential baseline — no
cutter_exec/cutter_verify, cutter_ro UNCHANGED (still NOLOGIN, 13
view/schema grants, 0 base-table grant), 12 tables/12 views intact,
prod sysid unchanged, 0 rows anywhere.
RB-7 secret rollback: the corresponding .env keys (if they were created in
the execution cycle) are removed/zeroised by the same authorized
operator; no secret value is logged. (In THIS design cycle nothing
exists to remove.)
partial_state_rule: if execution aborted mid-grant, RB-3..RB-6 still apply
(REVOKE is idempotent per object; DROP gated by RB-4).
§4 — Explicit Rollback Gates (summary)
G-RB-1 scope = credentials only (no data/table/view/cutter_ro/Directus).
G-RB-2 no CASCADE on any REVOKE or DROP.
G-RB-3 DROP ROLE only if memberless AND owns nothing AND no privilege left.
G-RB-4 cutter_ro state byte-identical before and after (v0.3 inventory §4).
G-RB-5 prod sysid identical before and after; 0 rows unchanged.
G-RB-6 schema-qualified / structural catalog assertions (no bare-string
false-negative — feedback memory pg_get_constraintdef lesson).
§5 — Non-Scope
NOT here: any REVOKE, any DROP ROLE, any ALTER ROLE, any .env change, any
connection. Target runbook specification only; executed nowhere.
End of credential risk & rollback plan (design only; nothing executed).