Skip to content

Commit 34a0aeb

Browse files
committed
fix(library): show security_invoker views so tenant row security applies through curated views
1 parent 60a7422 commit 34a0aeb

1 file changed

Lines changed: 16 additions & 3 deletions

File tree

  • apps/sim/content/library/postgres-mcp-server-ai-agents

‎apps/sim/content/library/postgres-mcp-server-ai-agents/index.mdx‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,14 +208,27 @@ USING (tenant_id = app_current_tenant_id());
208208

209209
The helper returns `NULL` when the setting is missing, empty, or not a UUID, so the policy matches no rows instead of raising a cast error.
210210

211+
A view normally reads its base tables with its owner's privileges and row-security context, not the caller's, so a policy scoped to `agent_reader` does not protect a curated view owned by an administrator. On PostgreSQL 15 or later, create agent-facing views with `security_invoker` so the policy applies to the querying role, and grant that role `SELECT` only on the base-table columns each view exposes:
212+
213+
```sql
214+
CREATE VIEW agent_api.agent_memory_summary
215+
WITH (security_invoker = true) AS
216+
SELECT tenant_id, memory_id, summary, created_at
217+
FROM agent_memory;
218+
219+
GRANT SELECT (tenant_id, memory_id, summary, created_at) ON agent_memory TO agent_reader;
220+
GRANT SELECT ON agent_api.agent_memory_summary TO agent_reader;
221+
```
222+
211223
Use this tenant-isolation checklist:
212224

213225
1. Derive tenant identity from authenticated server-side context, never from a model argument.
214226
2. Set tenant context locally inside the same transaction as the query when using connection pooling.
215227
3. Connect through a non-owner role without superuser or `BYPASSRLS` privileges.
216-
4. Enable and force row-level security on every tenant-scoped table the role can query.
217-
5. Make missing or invalid tenant context return no rows.
218-
6. Test with at least two tenants and confirm that neither can read or infer the other's records.
228+
4. Create every agent-facing view with `security_invoker = true` so row-level security evaluates the querying role.
229+
5. Enable and force row-level security on every tenant-scoped table the role can query.
230+
6. Make missing or invalid tenant context return no rows.
231+
7. Test with at least two tenants and confirm that neither can read or infer the other's records.
219232

220233
PostgreSQL explains policy behavior and role exceptions in its [row security documentation](https://www.postgresql.org/docs/current/ddl-rowsecurity.html). Views and MCP tool filters can narrow the interface further, but PostgreSQL should make the final row-level access decision.
221234

0 commit comments

Comments
 (0)