56 lines
1.7 KiB
Markdown
56 lines
1.7 KiB
Markdown
# AwoooP RLS Manual Script Review
|
|
|
|
Manual scripts are not API runtime, but they can still break after fail-closed
|
|
RLS if they connect directly with `DATABASE_URL` and do not set
|
|
`app.project_id`.
|
|
|
|
Run:
|
|
|
|
```bash
|
|
python3 scripts/ops/awooop-rls-manual-script-audit.py --show-pass
|
|
```
|
|
|
|
Use strict mode for CI or pre-apply review:
|
|
|
|
```bash
|
|
python3 scripts/ops/awooop-rls-manual-script-audit.py --strict-review
|
|
```
|
|
|
|
## 2026-05-12 Result
|
|
|
|
```text
|
|
AwoooP RLS manual script audit: BLOCKED=0 REVIEW=5 PASS=13
|
|
```
|
|
|
|
`BLOCKED=0` means no hardcoded PostgreSQL URL with inline credentials was found
|
|
in the scanned manual scripts.
|
|
|
|
`REVIEW=5` are intentional operator paths:
|
|
|
|
- `apps/api/scripts/awooop_phase1_batch1_backfill.py`: RLS/project_id bootstrap
|
|
backfill; use migration/operator role.
|
|
- `apps/api/scripts/run_migration.py`: DDL migration script; use
|
|
migration/operator role.
|
|
- `scripts/ops/awooop-rls-role-bootstrap.sql`: role bootstrap; requires
|
|
postgres/CREATEROLE operator.
|
|
- `scripts/ops/awooop_rls_preflight.py`: read-only preflight inside API pod.
|
|
- `scripts/sync_dev_db.py`: dev schema sync; requires `DEV_DATABASE_URL` and
|
|
must not target production.
|
|
|
|
The common tenant-data manual scripts now set `app.project_id` or use
|
|
`get_db_context()`.
|
|
|
|
## Operator Rule
|
|
|
|
- Direct tenant table access must set `app.project_id` on every connection, or
|
|
use an approved migration/operator role with BYPASSRLS.
|
|
- Direct `asyncpg` scripts should use session-level context:
|
|
|
|
```python
|
|
await conn.execute("SELECT set_config('app.project_id', $1, FALSE)", project_id)
|
|
```
|
|
|
|
- SQLAlchemy runtime/service code should use `get_db_context()` or `get_db()`.
|
|
- Do not add PostgreSQL URLs with inline credentials to scripts, comments, or
|
|
examples.
|