@fayz-ai/db 0.22.2 → 0.22.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ -- The reach walk UNIONs (id, depth): a branch the person reaches directly AND
2
+ -- through its HQ came back twice, and every unit picker listed it twice.
3
+ -- Same body as 017, deduplicated on the way out.
4
+
5
+ CREATE OR REPLACE FUNCTION app.user_unit_ids_in(p_tenant uuid)
6
+ RETURNS SETOF uuid
7
+ LANGUAGE sql STABLE SECURITY DEFINER
8
+ SET search_path TO ''
9
+ AS $$
10
+ WITH RECURSIVE seed AS (
11
+ SELECT a.unit_id AS id, 0 AS depth
12
+ FROM app.user_unit_access a
13
+ WHERE a.user_id = (SELECT auth.uid())
14
+ AND a.tenant_id = p_tenant
15
+ ),
16
+ tree AS (
17
+ SELECT id, depth FROM seed
18
+ UNION
19
+ SELECT u.id, t.depth + 1
20
+ FROM app.units u
21
+ JOIN tree t ON u.parent_unit_id = t.id
22
+ WHERE u.tenant_id = p_tenant AND t.depth < 8
23
+ )
24
+ SELECT DISTINCT id FROM tree;
25
+ $$;
@@ -0,0 +1,87 @@
1
+ -- ---------------------------------------------------------------------------
2
+ -- 174 — a conta de quem recebe é dado do financeiro.
3
+ --
4
+ -- Three permissive policies that let any member of a tenant do what the gated
5
+ -- policies next to them refuse. Postgres ORs permissive policies, so a
6
+ -- tenant-only policy beside an `app.has_permission` one wins every time.
7
+ --
8
+ -- · payee_accounts (149): bank/PIX of whoever the house pays. Any member,
9
+ -- viewer and SDR included, could rewrite where a payout lands. Now read
10
+ -- needs financial.read; insert/update financial.edit; delete
11
+ -- financial.delete (financial.manage satisfies all three).
12
+ -- · fulfillments: `fulfillments_member_all` (FOR ALL) shadowed the
13
+ -- fulfillments_authz_* write policies. The write side goes; a tenant-wide
14
+ -- SELECT stays so shop screens and plg_shop_rep_orders keep reading as today.
15
+ -- Every writer outside the authz policies is SECURITY DEFINER or the
16
+ -- service role.
17
+ -- · audit_logs: any member could insert any action, backdate it, stamp
18
+ -- before/after and pick a unit. The CRUD trail (admin stores/audit.ts) is
19
+ -- the only client writer and only writes `record.*`; server namespaces are
20
+ -- written by SECURITY DEFINER functions owned by postgres, which bypass RLS.
21
+ -- audit_log() leaves the client surface for the same reason.
22
+ --
23
+ -- Additive and replay-safe: DROP POLICY IF EXISTS + CREATE POLICY.
24
+ -- ---------------------------------------------------------------------------
25
+
26
+ -- ── payee_accounts ──────────────────────────────────────────────────────
27
+ DROP POLICY IF EXISTS payee_accounts_member_all ON public.payee_accounts;
28
+
29
+ DROP POLICY IF EXISTS payee_accounts_authz_select ON public.payee_accounts;
30
+ CREATE POLICY payee_accounts_authz_select ON public.payee_accounts
31
+ FOR SELECT TO authenticated
32
+ USING (tenant_id = (SELECT app.current_tenant_id())
33
+ AND (SELECT app.has_permission('financial.read')));
34
+
35
+ DROP POLICY IF EXISTS payee_accounts_authz_insert ON public.payee_accounts;
36
+ CREATE POLICY payee_accounts_authz_insert ON public.payee_accounts
37
+ FOR INSERT TO authenticated
38
+ WITH CHECK (tenant_id = (SELECT app.current_tenant_id())
39
+ AND (SELECT app.has_permission('financial.edit')));
40
+
41
+ -- trg_payee_accounts_one_default is SECURITY INVOKER: its demote-the-old-default
42
+ -- UPDATE runs under this policy too, which is why insert also asks for edit.
43
+ DROP POLICY IF EXISTS payee_accounts_authz_update ON public.payee_accounts;
44
+ CREATE POLICY payee_accounts_authz_update ON public.payee_accounts
45
+ FOR UPDATE TO authenticated
46
+ USING (tenant_id = (SELECT app.current_tenant_id())
47
+ AND (SELECT app.has_permission('financial.edit')))
48
+ WITH CHECK (tenant_id = (SELECT app.current_tenant_id())
49
+ AND (SELECT app.has_permission('financial.edit')));
50
+
51
+ DROP POLICY IF EXISTS payee_accounts_authz_delete ON public.payee_accounts;
52
+ CREATE POLICY payee_accounts_authz_delete ON public.payee_accounts
53
+ FOR DELETE TO authenticated
54
+ USING (tenant_id = (SELECT app.current_tenant_id())
55
+ AND (SELECT app.has_permission('financial.delete')));
56
+
57
+ -- ── fulfillments ────────────────────────────────────────────────────────
58
+ DROP POLICY IF EXISTS fulfillments_member_all ON public.fulfillments;
59
+
60
+ DROP POLICY IF EXISTS fulfillments_member_read ON public.fulfillments;
61
+ CREATE POLICY fulfillments_member_read ON public.fulfillments
62
+ FOR SELECT TO authenticated
63
+ USING (tenant_id = (SELECT app.current_tenant_id()));
64
+
65
+ -- ── audit_logs ──────────────────────────────────────────────────────────
66
+ -- Checked after the BEFORE trigger (handle_audit_actor), so user_id and
67
+ -- tenant_id are already the session's here.
68
+ DROP POLICY IF EXISTS audit_insert ON public.audit_logs;
69
+ CREATE POLICY audit_insert ON public.audit_logs
70
+ FOR INSERT TO authenticated
71
+ WITH CHECK (
72
+ tenant_id = (SELECT app.current_tenant_id())
73
+ AND user_id = (SELECT auth.uid())
74
+ AND action LIKE 'record.%'
75
+ AND before IS NULL
76
+ AND after IS NULL
77
+ AND (unit_id IS NULL OR (SELECT app.has_unit(unit_id)))
78
+ AND created_at BETWEEN now() - interval '1 minute' AND now() + interval '1 minute'
79
+ );
80
+
81
+ -- audit_log() is SECURITY DEFINER and takes any action, before/after and unit:
82
+ -- open to members it is the same forgery by another door. Nothing calls it
83
+ -- from a client or another function; server code keeps it via service_role.
84
+ REVOKE EXECUTE ON FUNCTION public.audit_log(text, text, uuid, text, jsonb, jsonb, uuid, jsonb, uuid)
85
+ FROM PUBLIC, anon, authenticated;
86
+ GRANT EXECUTE ON FUNCTION public.audit_log(text, text, uuid, text, jsonb, jsonb, uuid, jsonb, uuid)
87
+ TO service_role;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "fayz": {
4
4
  "status": "beta"
5
5
  },
6
- "version": "0.22.2",
6
+ "version": "0.22.3",
7
7
  "description": "Fayz SDK database layer — Drizzle schema primitives, spine references, and migration helpers shared across plugins.",
8
8
  "type": "module",
9
9
  "sideEffects": false,