@pgpm/verify 0.4.0
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.
- package/LICENSE +22 -0
- package/Makefile +6 -0
- package/README.md +5 -0
- package/__tests__/ext-verify.test.ts +490 -0
- package/deploy/procedures/get_entity_from_str.sql +21 -0
- package/deploy/procedures/get_schema_from_str.sql +21 -0
- package/deploy/procedures/list_indexes.sql +29 -0
- package/deploy/procedures/list_memberships.sql +31 -0
- package/deploy/procedures/verify_constraint.sql +27 -0
- package/deploy/procedures/verify_domain.sql +32 -0
- package/deploy/procedures/verify_extension.sql +24 -0
- package/deploy/procedures/verify_function.sql +37 -0
- package/deploy/procedures/verify_index.sql +23 -0
- package/deploy/procedures/verify_membership.sql +27 -0
- package/deploy/procedures/verify_policy.sql +35 -0
- package/deploy/procedures/verify_role.sql +24 -0
- package/deploy/procedures/verify_schema.sql +24 -0
- package/deploy/procedures/verify_security.sql +33 -0
- package/deploy/procedures/verify_table.sql +30 -0
- package/deploy/procedures/verify_table_grant.sql +32 -0
- package/deploy/procedures/verify_trigger.sql +32 -0
- package/deploy/procedures/verify_type.sql +32 -0
- package/deploy/procedures/verify_view.sql +30 -0
- package/jest.config.js +15 -0
- package/launchql-verify.control +8 -0
- package/launchql.plan +24 -0
- package/package.json +25 -0
- package/revert/procedures/get_entity_from_str.sql +7 -0
- package/revert/procedures/get_schema_from_str.sql +7 -0
- package/revert/procedures/list_indexes.sql +7 -0
- package/revert/procedures/list_memberships.sql +7 -0
- package/revert/procedures/verify_constraint.sql +7 -0
- package/revert/procedures/verify_domain.sql +7 -0
- package/revert/procedures/verify_extension.sql +7 -0
- package/revert/procedures/verify_function.sql +7 -0
- package/revert/procedures/verify_index.sql +7 -0
- package/revert/procedures/verify_membership.sql +7 -0
- package/revert/procedures/verify_policy.sql +7 -0
- package/revert/procedures/verify_role.sql +7 -0
- package/revert/procedures/verify_schema.sql +7 -0
- package/revert/procedures/verify_security.sql +7 -0
- package/revert/procedures/verify_table.sql +7 -0
- package/revert/procedures/verify_table_grant.sql +7 -0
- package/revert/procedures/verify_trigger.sql +7 -0
- package/revert/procedures/verify_type.sql +7 -0
- package/revert/procedures/verify_view.sql +7 -0
- package/sql/launchql-verify--0.4.6.sql +358 -0
- package/verify/procedures/get_entity_from_str.sql +7 -0
- package/verify/procedures/get_schema_from_str.sql +7 -0
- package/verify/procedures/list_indexes.sql +7 -0
- package/verify/procedures/list_memberships.sql +7 -0
- package/verify/procedures/verify_constraint.sql +7 -0
- package/verify/procedures/verify_domain.sql +7 -0
- package/verify/procedures/verify_extension.sql +7 -0
- package/verify/procedures/verify_function.sql +7 -0
- package/verify/procedures/verify_index.sql +7 -0
- package/verify/procedures/verify_membership.sql +7 -0
- package/verify/procedures/verify_policy.sql +7 -0
- package/verify/procedures/verify_role.sql +7 -0
- package/verify/procedures/verify_schema.sql +7 -0
- package/verify/procedures/verify_security.sql +7 -0
- package/verify/procedures/verify_table.sql +7 -0
- package/verify/procedures/verify_table_grant.sql +7 -0
- package/verify/procedures/verify_trigger.sql +7 -0
- package/verify/procedures/verify_type.sql +7 -0
- package/verify/procedures/verify_view.sql +7 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
\echo Use "CREATE EXTENSION launchql-verify" to load this file. \quit
|
|
2
|
+
CREATE FUNCTION get_entity_from_str(qualified_name text) RETURNS text AS $EOFCODE$
|
|
3
|
+
DECLARE
|
|
4
|
+
parts text[];
|
|
5
|
+
BEGIN
|
|
6
|
+
SELECT
|
|
7
|
+
parse_ident(qualified_name) INTO parts;
|
|
8
|
+
IF cardinality(parts) > 1 THEN
|
|
9
|
+
RETURN parts[2];
|
|
10
|
+
ELSE
|
|
11
|
+
RETURN parts[1];
|
|
12
|
+
END IF;
|
|
13
|
+
END;
|
|
14
|
+
$EOFCODE$ LANGUAGE plpgsql STRICT;
|
|
15
|
+
|
|
16
|
+
CREATE FUNCTION get_schema_from_str(qualified_name text) RETURNS text AS $EOFCODE$
|
|
17
|
+
DECLARE
|
|
18
|
+
parts text[];
|
|
19
|
+
BEGIN
|
|
20
|
+
SELECT
|
|
21
|
+
parse_ident(qualified_name) INTO parts;
|
|
22
|
+
IF cardinality(parts) > 1 THEN
|
|
23
|
+
RETURN parts[1];
|
|
24
|
+
ELSE
|
|
25
|
+
RETURN 'public';
|
|
26
|
+
END IF;
|
|
27
|
+
END;
|
|
28
|
+
$EOFCODE$ LANGUAGE plpgsql STRICT;
|
|
29
|
+
|
|
30
|
+
CREATE FUNCTION list_indexes(_table text, _index text) RETURNS TABLE ( schema_name text, table_name text, index_name text ) AS $EOFCODE$
|
|
31
|
+
SELECT
|
|
32
|
+
n.nspname::text AS schema_name,
|
|
33
|
+
t.relname::text AS table_name,
|
|
34
|
+
i.relname::text AS index_name
|
|
35
|
+
FROM
|
|
36
|
+
pg_class t,
|
|
37
|
+
pg_class i,
|
|
38
|
+
pg_index ix,
|
|
39
|
+
pg_catalog.pg_namespace n
|
|
40
|
+
WHERE
|
|
41
|
+
t.oid = ix.indrelid
|
|
42
|
+
AND i.oid = ix.indexrelid
|
|
43
|
+
AND n.oid = i.relnamespace
|
|
44
|
+
AND n.nspname = get_schema_from_str(_table)
|
|
45
|
+
AND i.relname = _index
|
|
46
|
+
AND t.relname = get_entity_from_str(_table);
|
|
47
|
+
$EOFCODE$ LANGUAGE sql IMMUTABLE;
|
|
48
|
+
|
|
49
|
+
CREATE FUNCTION list_memberships(_user text) RETURNS TABLE ( rolname text ) AS $EOFCODE$ WITH RECURSIVE cte AS (
|
|
50
|
+
SELECT
|
|
51
|
+
oid
|
|
52
|
+
FROM
|
|
53
|
+
pg_roles
|
|
54
|
+
WHERE
|
|
55
|
+
rolname = _user
|
|
56
|
+
UNION ALL
|
|
57
|
+
SELECT
|
|
58
|
+
m.roleid
|
|
59
|
+
FROM
|
|
60
|
+
cte
|
|
61
|
+
JOIN pg_auth_members m ON m.member = cte.oid
|
|
62
|
+
)
|
|
63
|
+
SELECT
|
|
64
|
+
pg_roles.rolname::text AS rolname
|
|
65
|
+
FROM
|
|
66
|
+
cte c,
|
|
67
|
+
pg_roles
|
|
68
|
+
WHERE
|
|
69
|
+
pg_roles.oid = c.oid;
|
|
70
|
+
$EOFCODE$ LANGUAGE sql IMMUTABLE;
|
|
71
|
+
|
|
72
|
+
CREATE FUNCTION verify_constraint(_table text, _name text) RETURNS boolean AS $EOFCODE$
|
|
73
|
+
BEGIN
|
|
74
|
+
IF EXISTS (
|
|
75
|
+
SELECT
|
|
76
|
+
c.conname,
|
|
77
|
+
pg_get_constraintdef(c.oid)
|
|
78
|
+
FROM
|
|
79
|
+
pg_constraint c
|
|
80
|
+
WHERE
|
|
81
|
+
conname = _name
|
|
82
|
+
AND c.conrelid = _table::regclass) THEN
|
|
83
|
+
RETURN TRUE;
|
|
84
|
+
ELSE
|
|
85
|
+
RAISE EXCEPTION 'Nonexistent constraint --> %', _name
|
|
86
|
+
USING HINT = 'Please check';
|
|
87
|
+
END IF;
|
|
88
|
+
END;
|
|
89
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
90
|
+
|
|
91
|
+
CREATE FUNCTION verify_domain(_type text) RETURNS boolean AS $EOFCODE$
|
|
92
|
+
BEGIN
|
|
93
|
+
IF EXISTS (
|
|
94
|
+
SELECT
|
|
95
|
+
pg_type.typname,
|
|
96
|
+
n.nspname
|
|
97
|
+
FROM
|
|
98
|
+
pg_type,
|
|
99
|
+
pg_catalog.pg_namespace n
|
|
100
|
+
WHERE
|
|
101
|
+
typtype = 'd'
|
|
102
|
+
AND typname = get_entity_from_str (_type)
|
|
103
|
+
AND nspname = get_schema_from_str (_type)) THEN
|
|
104
|
+
RETURN TRUE;
|
|
105
|
+
ELSE
|
|
106
|
+
RAISE EXCEPTION 'Nonexistent type --> %', _type
|
|
107
|
+
USING HINT = 'Please check';
|
|
108
|
+
END IF;
|
|
109
|
+
END;
|
|
110
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
111
|
+
|
|
112
|
+
CREATE FUNCTION verify_extension(_extname text) RETURNS boolean AS $EOFCODE$
|
|
113
|
+
BEGIN
|
|
114
|
+
IF EXISTS (
|
|
115
|
+
SELECT
|
|
116
|
+
1
|
|
117
|
+
FROM
|
|
118
|
+
pg_available_extensions
|
|
119
|
+
WHERE
|
|
120
|
+
name = _extname) THEN
|
|
121
|
+
RETURN TRUE;
|
|
122
|
+
ELSE
|
|
123
|
+
RAISE EXCEPTION 'Nonexistent extension --> %', _extname
|
|
124
|
+
USING HINT = 'Please check';
|
|
125
|
+
END IF;
|
|
126
|
+
END;
|
|
127
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
128
|
+
|
|
129
|
+
CREATE FUNCTION verify_function(_name text, _user text DEFAULT NULL) RETURNS boolean AS $EOFCODE$
|
|
130
|
+
DECLARE
|
|
131
|
+
check_user text;
|
|
132
|
+
BEGIN
|
|
133
|
+
IF (_user IS NOT NULL) THEN
|
|
134
|
+
check_user = _user;
|
|
135
|
+
ELSE
|
|
136
|
+
check_user = CURRENT_USER;
|
|
137
|
+
END IF;
|
|
138
|
+
IF EXISTS (
|
|
139
|
+
SELECT
|
|
140
|
+
has_function_privilege(check_user, p.oid, 'execute')
|
|
141
|
+
FROM
|
|
142
|
+
pg_catalog.pg_proc p
|
|
143
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
|
|
144
|
+
WHERE
|
|
145
|
+
n.nspname = get_schema_from_str (_name)
|
|
146
|
+
AND p.proname = get_entity_from_str (_name)) THEN
|
|
147
|
+
RETURN TRUE;
|
|
148
|
+
ELSE
|
|
149
|
+
RAISE EXCEPTION 'Nonexistent function --> %', _name
|
|
150
|
+
USING HINT = 'Please check';
|
|
151
|
+
END IF;
|
|
152
|
+
END;
|
|
153
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
154
|
+
|
|
155
|
+
CREATE FUNCTION verify_index(_table text, _index text) RETURNS boolean AS $EOFCODE$
|
|
156
|
+
BEGIN
|
|
157
|
+
IF EXISTS (
|
|
158
|
+
SELECT
|
|
159
|
+
list_indexes (_table, _index)) THEN
|
|
160
|
+
RETURN TRUE;
|
|
161
|
+
ELSE
|
|
162
|
+
RAISE EXCEPTION 'Nonexistent index --> %', _index
|
|
163
|
+
USING HINT = 'Please check';
|
|
164
|
+
END IF;
|
|
165
|
+
END;
|
|
166
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
167
|
+
|
|
168
|
+
CREATE FUNCTION verify_membership(_user text, _role text) RETURNS boolean AS $EOFCODE$
|
|
169
|
+
BEGIN
|
|
170
|
+
IF EXISTS (
|
|
171
|
+
SELECT
|
|
172
|
+
1
|
|
173
|
+
FROM
|
|
174
|
+
list_memberships (_user)
|
|
175
|
+
WHERE
|
|
176
|
+
rolname = _role) THEN
|
|
177
|
+
RETURN TRUE;
|
|
178
|
+
ELSE
|
|
179
|
+
RAISE EXCEPTION 'Nonexistent member --> %', _user
|
|
180
|
+
USING HINT = 'Please check';
|
|
181
|
+
END IF;
|
|
182
|
+
END;
|
|
183
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
184
|
+
|
|
185
|
+
CREATE FUNCTION verify_policy(_policy text, _table text) RETURNS boolean AS $EOFCODE$
|
|
186
|
+
BEGIN
|
|
187
|
+
IF EXISTS (
|
|
188
|
+
SELECT
|
|
189
|
+
1
|
|
190
|
+
FROM
|
|
191
|
+
pg_class p
|
|
192
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = p.relnamespace
|
|
193
|
+
JOIN pg_policy pol ON pol.polrelid = p.relfilenode
|
|
194
|
+
WHERE
|
|
195
|
+
pol.polname = _policy
|
|
196
|
+
AND relrowsecurity = 'true'
|
|
197
|
+
AND relname = get_entity_from_str (_table)
|
|
198
|
+
AND nspname = get_schema_from_str (_table)) THEN
|
|
199
|
+
RETURN TRUE;
|
|
200
|
+
ELSE
|
|
201
|
+
RAISE EXCEPTION 'Nonexistent policy or missing relrowsecurity --> %', _policy
|
|
202
|
+
USING HINT = 'Please check';
|
|
203
|
+
END IF;
|
|
204
|
+
END;
|
|
205
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
206
|
+
|
|
207
|
+
CREATE FUNCTION verify_role(_user text) RETURNS boolean AS $EOFCODE$
|
|
208
|
+
BEGIN
|
|
209
|
+
IF EXISTS (
|
|
210
|
+
SELECT
|
|
211
|
+
1
|
|
212
|
+
FROM
|
|
213
|
+
pg_roles
|
|
214
|
+
WHERE
|
|
215
|
+
rolname = _user) THEN
|
|
216
|
+
RETURN TRUE;
|
|
217
|
+
ELSE
|
|
218
|
+
RAISE EXCEPTION 'Nonexistent user --> %', _user
|
|
219
|
+
USING HINT = 'Please check';
|
|
220
|
+
END IF;
|
|
221
|
+
END;
|
|
222
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
223
|
+
|
|
224
|
+
CREATE FUNCTION verify_schema(_schema text) RETURNS boolean AS $EOFCODE$
|
|
225
|
+
BEGIN
|
|
226
|
+
IF EXISTS (
|
|
227
|
+
SELECT
|
|
228
|
+
*
|
|
229
|
+
FROM
|
|
230
|
+
pg_catalog.pg_namespace
|
|
231
|
+
WHERE
|
|
232
|
+
nspname = _schema) THEN
|
|
233
|
+
RETURN TRUE;
|
|
234
|
+
ELSE
|
|
235
|
+
RAISE EXCEPTION 'Nonexistent schema --> %', _schema
|
|
236
|
+
USING HINT = 'Please check';
|
|
237
|
+
END IF;
|
|
238
|
+
END;
|
|
239
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
240
|
+
|
|
241
|
+
CREATE FUNCTION verify_security(_table text) RETURNS boolean AS $EOFCODE$
|
|
242
|
+
BEGIN
|
|
243
|
+
IF EXISTS (
|
|
244
|
+
SELECT
|
|
245
|
+
n.oid,
|
|
246
|
+
relname,
|
|
247
|
+
n.nspname
|
|
248
|
+
FROM
|
|
249
|
+
pg_class p
|
|
250
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = p.relnamespace
|
|
251
|
+
WHERE
|
|
252
|
+
relrowsecurity = 'true'
|
|
253
|
+
AND relname = get_entity_from_str (_table)
|
|
254
|
+
AND nspname = get_schema_from_str (_table)) THEN
|
|
255
|
+
RETURN TRUE;
|
|
256
|
+
ELSE
|
|
257
|
+
RAISE EXCEPTION 'Nonexistent security --> %', _name
|
|
258
|
+
USING HINT = 'Please check';
|
|
259
|
+
END IF;
|
|
260
|
+
END;
|
|
261
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
262
|
+
|
|
263
|
+
CREATE FUNCTION verify_table_grant(_table text, _privilege text, _role text) RETURNS boolean AS $EOFCODE$
|
|
264
|
+
BEGIN
|
|
265
|
+
IF EXISTS (
|
|
266
|
+
SELECT
|
|
267
|
+
grantee,
|
|
268
|
+
privilege_type
|
|
269
|
+
FROM
|
|
270
|
+
information_schema.role_table_grants
|
|
271
|
+
WHERE
|
|
272
|
+
table_schema = get_schema_from_str (_table)
|
|
273
|
+
AND table_name = get_entity_from_str (_table)
|
|
274
|
+
AND privilege_type = _privilege
|
|
275
|
+
AND grantee = _role) THEN
|
|
276
|
+
RETURN TRUE;
|
|
277
|
+
ELSE
|
|
278
|
+
RAISE EXCEPTION 'Nonexistent table grant --> %', _privilege
|
|
279
|
+
USING HINT = 'Please check';
|
|
280
|
+
END IF;
|
|
281
|
+
END;
|
|
282
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
283
|
+
|
|
284
|
+
CREATE FUNCTION verify_table(_table text) RETURNS boolean AS $EOFCODE$
|
|
285
|
+
BEGIN
|
|
286
|
+
IF EXISTS (
|
|
287
|
+
SELECT
|
|
288
|
+
*
|
|
289
|
+
FROM
|
|
290
|
+
information_schema.tables
|
|
291
|
+
WHERE
|
|
292
|
+
table_schema = get_schema_from_str (_table)
|
|
293
|
+
AND table_name = get_entity_from_str (_table)) THEN
|
|
294
|
+
RETURN TRUE;
|
|
295
|
+
ELSE
|
|
296
|
+
RAISE EXCEPTION 'Nonexistent table --> %', _table
|
|
297
|
+
USING HINT = 'Please check';
|
|
298
|
+
END IF;
|
|
299
|
+
END;
|
|
300
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
301
|
+
|
|
302
|
+
CREATE FUNCTION verify_trigger(_trigger text) RETURNS boolean AS $EOFCODE$
|
|
303
|
+
BEGIN
|
|
304
|
+
IF EXISTS (
|
|
305
|
+
SELECT
|
|
306
|
+
pg_trigger.tgname,
|
|
307
|
+
n.nspname
|
|
308
|
+
FROM
|
|
309
|
+
pg_trigger,
|
|
310
|
+
pg_catalog.pg_namespace n
|
|
311
|
+
WHERE
|
|
312
|
+
tgname = get_entity_from_str (_trigger)
|
|
313
|
+
AND nspname = get_schema_from_str (_trigger)) THEN
|
|
314
|
+
RETURN TRUE;
|
|
315
|
+
ELSE
|
|
316
|
+
RAISE EXCEPTION 'Nonexistent trigger --> %', _trigger
|
|
317
|
+
USING HINT = 'Please check';
|
|
318
|
+
END IF;
|
|
319
|
+
END;
|
|
320
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
321
|
+
|
|
322
|
+
CREATE FUNCTION verify_type(_type text) RETURNS boolean AS $EOFCODE$
|
|
323
|
+
BEGIN
|
|
324
|
+
IF EXISTS (
|
|
325
|
+
SELECT
|
|
326
|
+
pg_type.typname,
|
|
327
|
+
n.nspname
|
|
328
|
+
FROM
|
|
329
|
+
pg_type,
|
|
330
|
+
pg_catalog.pg_namespace n
|
|
331
|
+
WHERE
|
|
332
|
+
typname = get_entity_from_str (_type)
|
|
333
|
+
AND nspname = get_schema_from_str (_type)) THEN
|
|
334
|
+
RETURN TRUE;
|
|
335
|
+
ELSE
|
|
336
|
+
RAISE EXCEPTION 'Nonexistent type --> %', _type
|
|
337
|
+
USING HINT = 'Please check';
|
|
338
|
+
END IF;
|
|
339
|
+
END;
|
|
340
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|
|
341
|
+
|
|
342
|
+
CREATE FUNCTION verify_view(_view text) RETURNS boolean AS $EOFCODE$
|
|
343
|
+
BEGIN
|
|
344
|
+
IF EXISTS (
|
|
345
|
+
SELECT
|
|
346
|
+
*
|
|
347
|
+
FROM
|
|
348
|
+
information_schema.views
|
|
349
|
+
WHERE
|
|
350
|
+
table_schema = get_schema_from_str (_view)
|
|
351
|
+
AND table_name = get_entity_from_str (_view)) THEN
|
|
352
|
+
RETURN TRUE;
|
|
353
|
+
ELSE
|
|
354
|
+
RAISE EXCEPTION 'Nonexistent view --> %', _view
|
|
355
|
+
USING HINT = 'Please check';
|
|
356
|
+
END IF;
|
|
357
|
+
END;
|
|
358
|
+
$EOFCODE$ LANGUAGE plpgsql IMMUTABLE;
|