create-quorum-router 0.1.5 → 0.1.7

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,125 @@
1
+ create extension if not exists pgcrypto with schema extensions;
2
+
3
+ create table if not exists public.workflow_access_audit (
4
+ id uuid primary key default extensions.gen_random_uuid(),
5
+ org_id text not null,
6
+ actor_id uuid not null,
7
+ actor_type text not null default 'ai_assistant'
8
+ check (actor_type in ('ai_assistant', 'user', 'system')),
9
+ event_type text not null check (length(event_type) > 0),
10
+ workflow_id text,
11
+ route text,
12
+ decision text not null check (decision in ('allow', 'deny', 'error')),
13
+ reason text,
14
+ metadata jsonb not null default '{}'::jsonb,
15
+ created_at timestamptz not null default now()
16
+ );
17
+
18
+ alter table public.workflow_access_audit enable row level security;
19
+
20
+ revoke all privileges on table public.workflow_access_audit from public;
21
+ revoke all privileges on table public.workflow_access_audit from anon;
22
+ revoke all privileges on table public.workflow_access_audit from authenticated;
23
+
24
+ create or replace function public.prevent_workflow_access_audit_mutation()
25
+ returns trigger
26
+ language plpgsql
27
+ set search_path = public, pg_temp
28
+ as $$
29
+ begin
30
+ raise exception 'workflow_access_audit is append-only';
31
+ end;
32
+ $$;
33
+
34
+ revoke all privileges on function public.prevent_workflow_access_audit_mutation()
35
+ from public;
36
+
37
+ drop trigger if exists workflow_access_audit_no_update_delete
38
+ on public.workflow_access_audit;
39
+ create trigger workflow_access_audit_no_update_delete
40
+ before update or delete on public.workflow_access_audit
41
+ for each row
42
+ execute function public.prevent_workflow_access_audit_mutation();
43
+
44
+ create or replace function public.insert_workflow_access_audit_batch(records jsonb)
45
+ returns void
46
+ language plpgsql
47
+ security definer
48
+ set search_path = public, pg_temp
49
+ as $$
50
+ declare
51
+ rec jsonb;
52
+ claim_org_id text;
53
+ claim_actor_id uuid;
54
+ event_type text;
55
+ decision text;
56
+ begin
57
+ claim_actor_id := auth.uid();
58
+ if claim_actor_id is null then
59
+ raise exception 'missing authenticated user'
60
+ using errcode = '28000';
61
+ end if;
62
+
63
+ claim_org_id := nullif(auth.jwt() ->> 'org_id', '');
64
+ if claim_org_id is null then
65
+ raise exception 'missing org_id claim'
66
+ using errcode = '28000';
67
+ end if;
68
+
69
+ if records is null or jsonb_typeof(records) <> 'array' then
70
+ raise exception 'records must be a JSON array'
71
+ using errcode = '22023';
72
+ end if;
73
+
74
+ for rec in select value from jsonb_array_elements(records) as entry(value) loop
75
+ event_type := nullif(rec ->> 'event_type', '');
76
+ decision := nullif(rec ->> 'decision', '');
77
+
78
+ if event_type is null then
79
+ raise exception 'audit event_type is required'
80
+ using errcode = '22023';
81
+ end if;
82
+
83
+ if decision is null then
84
+ raise exception 'audit decision is required'
85
+ using errcode = '22023';
86
+ end if;
87
+
88
+ insert into public.workflow_access_audit (
89
+ org_id,
90
+ actor_id,
91
+ actor_type,
92
+ event_type,
93
+ workflow_id,
94
+ route,
95
+ decision,
96
+ reason,
97
+ metadata,
98
+ created_at
99
+ ) values (
100
+ claim_org_id,
101
+ claim_actor_id,
102
+ coalesce(nullif(rec ->> 'actor_type', ''), 'ai_assistant'),
103
+ event_type,
104
+ nullif(rec ->> 'workflow_id', ''),
105
+ nullif(rec ->> 'route', ''),
106
+ decision,
107
+ nullif(rec ->> 'reason', ''),
108
+ case
109
+ when jsonb_typeof(rec -> 'metadata') = 'object' then rec -> 'metadata'
110
+ else '{}'::jsonb
111
+ end,
112
+ now()
113
+ );
114
+ end loop;
115
+ end;
116
+ $$;
117
+
118
+ revoke all privileges on function public.insert_workflow_access_audit_batch(jsonb)
119
+ from public;
120
+ revoke all privileges on function public.insert_workflow_access_audit_batch(jsonb)
121
+ from anon;
122
+ revoke all privileges on function public.insert_workflow_access_audit_batch(jsonb)
123
+ from authenticated;
124
+ grant execute on function public.insert_workflow_access_audit_batch(jsonb)
125
+ to authenticated;
@@ -0,0 +1,94 @@
1
+ -- Harden the BYO audit RPC for both existing and fresh projects.
2
+ -- Every user owns their own Supabase project; no central database or shared
3
+ -- tenant-routing claim is used. Runtime callers remain authenticated JWT users.
4
+
5
+ create or replace function public.insert_workflow_access_audit_batch(records jsonb)
6
+ returns void
7
+ language plpgsql
8
+ security definer
9
+ set search_path = public, pg_temp
10
+ as $$
11
+ declare
12
+ rec jsonb;
13
+ claim_actor_id uuid;
14
+ workflow_id text;
15
+ route text;
16
+ decision text;
17
+ metadata jsonb;
18
+ begin
19
+ claim_actor_id := auth.uid();
20
+ if claim_actor_id is null then
21
+ raise exception 'missing authenticated user' using errcode = '28000';
22
+ end if;
23
+
24
+ if records is null or jsonb_typeof(records) <> 'array' then
25
+ raise exception 'records must be a JSON array' using errcode = '22023';
26
+ end if;
27
+ if jsonb_array_length(records) < 1 or jsonb_array_length(records) > 100 then
28
+ raise exception 'records batch size must be between 1 and 100' using errcode = '22023';
29
+ end if;
30
+ if pg_column_size(records) > 262144 then
31
+ raise exception 'records payload exceeds 256 KiB' using errcode = '22023';
32
+ end if;
33
+
34
+ for rec in select value from jsonb_array_elements(records) as entry(value) loop
35
+ if jsonb_typeof(rec) <> 'object' then
36
+ raise exception 'each audit record must be an object' using errcode = '22023';
37
+ end if;
38
+ if exists (
39
+ select 1 from jsonb_object_keys(rec) as key
40
+ where key not in ('workflow_id', 'route', 'decision', 'metadata')
41
+ ) then
42
+ raise exception 'audit record contains unsupported fields' using errcode = '22023';
43
+ end if;
44
+
45
+ workflow_id := nullif(rec ->> 'workflow_id', '');
46
+ route := nullif(rec ->> 'route', '');
47
+ decision := nullif(rec ->> 'decision', '');
48
+ metadata := coalesce(rec -> 'metadata', '{}'::jsonb);
49
+
50
+ if workflow_id is null or length(workflow_id) > 256 then
51
+ raise exception 'audit workflow_id is required and limited to 256 characters' using errcode = '22023';
52
+ end if;
53
+ if route is not null and length(route) > 256 then
54
+ raise exception 'audit route exceeds 256 characters' using errcode = '22023';
55
+ end if;
56
+ if decision not in ('allow', 'error') then
57
+ raise exception 'invalid route outcome decision' using errcode = '22023';
58
+ end if;
59
+ if jsonb_typeof(metadata) <> 'object' or pg_column_size(metadata) > 16384 then
60
+ raise exception 'audit metadata must be an object no larger than 16 KiB' using errcode = '22023';
61
+ end if;
62
+ if exists (
63
+ select 1 from jsonb_object_keys(metadata) as key
64
+ where key not in (
65
+ 'command', 'mode', 'auth_mode', 'provider_selection_honored',
66
+ 'fallback_used', 'schema_valid'
67
+ )
68
+ ) then
69
+ raise exception 'audit metadata contains unsupported fields' using errcode = '22023';
70
+ end if;
71
+
72
+ insert into public.workflow_access_audit (
73
+ org_id, actor_id, actor_type, event_type, workflow_id, route,
74
+ decision, reason, metadata, created_at
75
+ ) values (
76
+ claim_actor_id::text,
77
+ claim_actor_id,
78
+ 'ai_assistant',
79
+ 'route.outcome',
80
+ workflow_id,
81
+ route,
82
+ decision,
83
+ case when decision = 'allow' then 'route completed' else 'route validation failed' end,
84
+ metadata,
85
+ now()
86
+ );
87
+ end loop;
88
+ end;
89
+ $$;
90
+
91
+ revoke all privileges on function public.insert_workflow_access_audit_batch(jsonb) from public;
92
+ revoke all privileges on function public.insert_workflow_access_audit_batch(jsonb) from anon;
93
+ revoke all privileges on function public.insert_workflow_access_audit_batch(jsonb) from authenticated;
94
+ grant execute on function public.insert_workflow_access_audit_batch(jsonb) to authenticated;