From 1617b73a9d60d7445abcfeb3f1b2a48346a0534e Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 12 May 2026 20:55:40 +0800 Subject: [PATCH] =?UTF-8?q?docs(rls):=20=E8=A8=98=E9=8C=84=20canary=20wave?= =?UTF-8?q?1=20production=20apply?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/LOGBOOK.md | 48 ++++++++++++++++++++++++ docs/runbooks/AWOOOP-RLS-CANARY-WAVE1.md | 29 +++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 8309bb75..b424c1ed 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,51 @@ +## 2026-05-12 | RLS Canary Wave1 已套用 + +**背景**:上一輪已產出 `scripts/ops/awooop-rls-canary-wave1-empty-tables.sql` 與 rollback SQL;使用者批准後,本輪只套用六張 live preflight 顯示為空表的 Wave1 canary policy,不碰 `incidents` / `knowledge_entries` / `playbooks` / `audit_logs` 等高流量或非空表。 + +**套用前 gate**: +- `python3 scripts/ops/awooop-rls-access-audit.py` → `BLOCKED=0 ALLOW=10`。 +- `python3 scripts/ops/awooop-rls-manual-script-audit.py` → `BLOCKED=0 REVIEW=5 PASS=13`。 +- `scripts/ops/awooop-rls-preflight.sh --exact-counts` → `PASS=7 WARN=0 BLOCKED=1`;唯一 blocker 為尚未啟用 policy。 +- 六張 Wave1 target 仍為 `total_rows=0 null_project_id_rows=0`: + - `awooop_contract_revisions` + - `awooop_conversation_event` + - `awooop_mcp_credential_refs` + - `awooop_mcp_gateway_audit` + - `awooop_mcp_grants` + - `budget_ledger` + +**production apply**: +- 已同步到 188: + - `/home/ollama/awoooi-ops/awooop-rls-canary-wave1-empty-tables.sql` + - `/home/ollama/awoooi-ops/awooop-rls-canary-wave1-empty-tables-rollback.sql` +- 以 postgres/operator socket path 執行: + - Docker image:`pgvector/pgvector:pg14` + - UID/GID:`115:121` (`postgres:postgres`) + - DB:`awoooi_prod` +- Apply result:`COMMIT`,六張 target table 均 `ENABLE ROW LEVEL SECURITY` + `FORCE ROW LEVEL SECURITY` + fail-closed `FOR ALL TO awooop_app` policy。 + +**套用後驗證**: +- `scripts/ops/awooop-rls-preflight.sh --exact-counts`: + - Wave1 六張表皆為 `rls=True force=True policies=1 fail_open_null=False fail_open_empty=False`。 + - 全域 preflight 仍為 `PASS=7 WARN=0 BLOCKED=1`,剩餘 blocker 只列未套用的非空/後續 wave 表:`audit_logs`、`awooop_mcp_tool_registry`、`awooop_outbound_message`、`awooop_projects`、`awooop_run_state`、`incidents`、`knowledge_entries`、`playbooks`。 +- production health `/api/v1/health` → 200 healthy。 +- runtime/manual audits 仍為: + - runtime access audit:`BLOCKED=0 ALLOW=10` + - manual script audit:`BLOCKED=0 REVIEW=5 PASS=13` +- RLS 行為 rollback-only 測試(API pod / current app DB user): + - 未設 `app.project_id` 寫 `budget_ledger` → `InsufficientPrivilegeError`,符合 fail-closed。 + - 設 `app.project_id='awoooi'` 後寫 `budget_ledger` → allowed,隨即 rollback。 + - `budget_ledger_count_after=0`,未留下測試資料。 + +**整體進度**: +- Wave 0:MOMO PostgreSQL backup → AwoooP 失敗通知接線完成並已推 Gitea。 +- Wave 1:Claude P0 紅燈驗證已完成多項:GitHub production deploy disabled、RLS production 0 policy 已證實、RLS role bootstrap 已套用、API runtime access path 已收斂、manual script gate 已建立、Wave1 空表 canary RLS 已套用。 +- 尚未完成:token rotation(需外部輪換)、188 certbot 正式修復、剩餘 RLS waves、高流量表 canary/rollout、188 local Ollama stop window。 + +**下一步**: +- Wave1.1:選擇下一批低行數但非空表 canary(候選:`awooop_projects` 2 rows、`awooop_mcp_tool_registry` 4 rows),先做 explicit read/write rollback tests,再產出 apply/rollback SQL。 +- 高流量表 (`incidents` / `knowledge_entries` / `playbooks` / `audit_logs`) 暫不熱開,需另做 query-path 與 rollback rehearsal。 + ## 2026-05-12 | RLS Manual Script Gate 與 Canary Wave1 套件 **背景**:API runtime DB access path 已收斂後,下一個風險是人工腳本在 RLS fail-closed 後直接用 `DATABASE_URL` 讀寫 tenant tables;同時需要第一批低風險 RLS policy 套件,但不可直接熱開高流量表。 diff --git a/docs/runbooks/AWOOOP-RLS-CANARY-WAVE1.md b/docs/runbooks/AWOOOP-RLS-CANARY-WAVE1.md index 7d59ce88..69e6c20e 100644 --- a/docs/runbooks/AWOOOP-RLS-CANARY-WAVE1.md +++ b/docs/runbooks/AWOOOP-RLS-CANARY-WAVE1.md @@ -1,7 +1,9 @@ # AwoooP RLS Canary Wave 1 -This wave is a staged apply package only. It enables fail-closed RLS on tables -that were empty in the latest production preflight. +This wave enables fail-closed RLS on tables that were empty in the production +preflight. + +Status: applied to production on 2026-05-12. Apply script: @@ -67,6 +69,29 @@ The global preflight will still be blocked until later waves cover the remaining tables. The six wave1 tables should show `rls=true`, `force=true`, and `policies=1`, with no fail-open policy expression. +## 2026-05-12 Production Evidence + +Apply completed with `COMMIT` through the 188 postgres/operator socket path. + +Post-apply preflight: + +- `awooop_contract_revisions`: `rls=true`, `force=true`, `policies=1` +- `awooop_conversation_event`: `rls=true`, `force=true`, `policies=1` +- `awooop_mcp_credential_refs`: `rls=true`, `force=true`, `policies=1` +- `awooop_mcp_gateway_audit`: `rls=true`, `force=true`, `policies=1` +- `awooop_mcp_grants`: `rls=true`, `force=true`, `policies=1` +- `budget_ledger`: `rls=true`, `force=true`, `policies=1` + +All six showed `fail_open_null=false` and `fail_open_empty=false`. + +Rollback-only behavior test from the API pod: + +```text +budget_ledger_no_context=InsufficientPrivilegeError +budget_ledger_with_context=allowed_and_rolled_back +budget_ledger_count_after=0 +``` + ## Rollback ```bash