diff --git a/docs/LOGBOOK.md b/docs/LOGBOOK.md index 72f2f831..aab98997 100644 --- a/docs/LOGBOOK.md +++ b/docs/LOGBOOK.md @@ -1,3 +1,40 @@ +## 2026-05-12 | RLS Role Bootstrap 已套用 + +**背景**:上一輪已新增 `scripts/ops/awooop-rls-role-bootstrap.sql`,但尚未執行;使用者批准後,本輪只執行 role bootstrap,不啟用 RLS policy。 + +**執行方式**: +- 沒有使用 `sudo`,也沒有走 K8s app `DATABASE_URL`。 +- 188 `ollama` 使用者可用 Docker;使用 host PostgreSQL socket 與 host `postgres` UID `115:121` 連線。 +- 驗證連線為 `current_user=postgres`、`rolsuper=true` 後,透過 stdin 執行 `scripts/ops/awooop-rls-role-bootstrap.sql`。 +- SQL 成功 `COMMIT`,未建立任何密碼、未修改 K8s Secret、未啟用任何 RLS policy。 + +**role 結果**: +- `awooop_app`:`NOLOGIN`,非 superuser,非 `BYPASSRLS`。 +- `awooop_platform_admin`:`NOLOGIN`,`BYPASSRLS=true`。 +- `awooop_migration`:`NOLOGIN`,`BYPASSRLS=true`。 +- `awoooi` 仍是 production API DB user,並已成為 `awooop_app` member。 +- `awoooi_migrator` 存在,並已授權 `awooop_migration` group;未變更其 password / login secret。 + +**post-bootstrap RLS preflight**: +- `bash scripts/ops/awooop-rls-preflight.sh --exact-counts` → exit `2`,符合預期,因 policy 尚未啟用。 +- `PASS=7 WARN=0 BLOCKED=1`。 +- 新增轉綠: + - `required_roles` → PASS。 + - `app_role_membership` → PASS。 +- 唯一 BLOCKED: + - `rls_enabled_forced_policy`:target tables 尚未 RLS enabled / forced / policied。 +- exact counts 仍顯示 target tables `NULL project_id = 0`。 + +**production smoke**: +- `https://awoooi.wooo.work/api/v1/health` → 200,PostgreSQL / Redis / Ollama / OpenClaw / SignOz 均 up。 +- `/api/v1/platform/runs/list?per_page=1` → 200,`total=126`。 +- `awoooi-api` pods 2/2 running;近 10 分鐘 log 未見 DB permission / RLS / SQLAlchemy / asyncpg error。 + +**下一步**: +- 不要直接全表熱開 RLS。 +- 先做 DB access path audit,確認所有 production read/write 入口皆會設定 `app.project_id`。 +- 再產出 staged policy enablement:先 staging / canary,再 production batch。 + ## 2026-05-12 | 188 Ollama Gate 綠燈與 RLS Role Bootstrap 設計 **背景**:Wave 1 尚有兩個可收斂點:188 local Ollama 是否仍有 direct caller,以及 RLS roles 缺失如何安全補上。原則維持:只驗證與準備,不直接 uninstall 188 Ollama,不直接 production 熱開 RLS。 diff --git a/docs/runbooks/AWOOOP-RLS-PREFLIGHT.md b/docs/runbooks/AWOOOP-RLS-PREFLIGHT.md index 01be7b90..8cb2a184 100644 --- a/docs/runbooks/AWOOOP-RLS-PREFLIGHT.md +++ b/docs/runbooks/AWOOOP-RLS-PREFLIGHT.md @@ -28,7 +28,7 @@ AWOOOP_RLS_SSH_TARGET=wooo@192.168.0.120 bash scripts/ops/awooop-rls-preflight.s Exit code `2` means the gate is blocked and RLS must not be enabled yet. -## 2026-05-12 Production Result +## 2026-05-12 Initial Production Result `--exact-counts` returned: @@ -61,28 +61,58 @@ Important exact counts from the same run: | `knowledge_entries` | 2102 | 0 | | `playbooks` | 220 | 0 | +## 2026-05-12 Role Bootstrap Applied + +At `19:33 CST`, the manual role bootstrap was applied through the host +PostgreSQL socket as `postgres`. It did not enable RLS policies. + +Post-bootstrap `--exact-counts` returned: + +- `PASS current_role_rls_enforced`: current DB user is still `awoooi`, not + superuser and not `BYPASSRLS`. +- `PASS project_context_set_config`: `set_config('app.project_id', 'awoooi', TRUE)` works. +- `PASS required_roles`: `awooop_app`, `awooop_platform_admin`, and + `awooop_migration` now exist. +- `PASS app_role_membership`: current API DB user is a member of `awooop_app`. +- `PASS project_id_columns`: every existing target table has `project_id`. +- `BLOCKED rls_enabled_forced_policy`: target tables are still not RLS enabled, + forced, or policied. +- `PASS fail_open_policies`: no fail-open policy expressions detected. +- `PASS project_id_backfill`: exact counts found zero `NULL project_id` rows in + counted target tables. + +Current blocker summary: + +```text +PASS=7 WARN=0 BLOCKED=1 +``` + +Updated exact counts: + +| Table | Rows | NULL project_id | +| --- | ---: | ---: | +| `audit_logs` | 686 | 0 | +| `awooop_mcp_tool_registry` | 4 | 0 | +| `awooop_outbound_message` | 248 | 0 | +| `awooop_projects` | 2 | 0 | +| `awooop_run_state` | 126 | 0 | +| `incidents` | 1524 | 0 | +| `knowledge_entries` | 2103 | 0 | +| `playbooks` | 220 | 0 | + ## Remediation Order -1. Create or reconcile RLS roles. - - Current production app user is `awoooi`; policy design must either grant it - membership in `awooop_app` or update the application connection role before - policies are enforced. - - Do not create passworded LOGIN roles in a migration unless the K8s Secret - rotation path is ready. - - Use `scripts/ops/awooop-rls-role-bootstrap.sql` only after review, and run - it manually as `postgres` or a `CREATEROLE` operator. It is intentionally - outside `apps/api/migrations/` so Gitea auto-migration will not run it. -2. Verify all DB access paths use `get_db()` / `get_db_context()` or otherwise set +1. Verify all DB access paths use `get_db()` / `get_db_context()` or otherwise set `app.project_id` before queries. -3. Apply policies first in staging or a canary DB. -4. In production, enable one batch at a time. -5. After each batch, run: +2. Apply policies first in staging or a canary DB. +3. In production, enable one batch at a time. +4. After each batch, run: ```bash bash scripts/ops/awooop-rls-preflight.sh --exact-counts ``` -6. Validate AwoooP Runs, Approvals, Monitoring, Tickets, Cost, alert ingestion, +5. Validate AwoooP Runs, Approvals, Monitoring, Tickets, Cost, alert ingestion, background workers, and TelegramGateway mirror paths. ## Do Not