@supabase/pg-delta 1.0.0-alpha.21 → 1.0.0-alpha.23
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/dist/core/catalog.diff.js +4 -3
- package/dist/core/catalog.model.d.ts +8 -1
- package/dist/core/catalog.model.js +10 -8
- package/dist/core/expand-replace-dependencies.js +23 -0
- package/dist/core/integrations/filter/flatten.js +13 -0
- package/dist/core/objects/aggregate/aggregate.diff.js +16 -0
- package/dist/core/objects/aggregate/aggregate.model.d.ts +10 -0
- package/dist/core/objects/aggregate/aggregate.model.js +19 -1
- package/dist/core/objects/aggregate/changes/aggregate.base.d.ts +1 -1
- package/dist/core/objects/aggregate/changes/aggregate.security-label.d.ts +28 -0
- package/dist/core/objects/aggregate/changes/aggregate.security-label.js +64 -0
- package/dist/core/objects/aggregate/changes/aggregate.types.d.ts +2 -1
- package/dist/core/objects/base.model.d.ts +8 -0
- package/dist/core/objects/base.model.js +2 -0
- package/dist/core/objects/domain/changes/domain.base.d.ts +1 -1
- package/dist/core/objects/domain/changes/domain.security-label.d.ts +28 -0
- package/dist/core/objects/domain/changes/domain.security-label.js +61 -0
- package/dist/core/objects/domain/changes/domain.types.d.ts +2 -1
- package/dist/core/objects/domain/domain.diff.js +16 -0
- package/dist/core/objects/domain/domain.model.d.ts +10 -0
- package/dist/core/objects/domain/domain.model.js +19 -1
- package/dist/core/objects/event-trigger/changes/event-trigger.base.d.ts +1 -1
- package/dist/core/objects/event-trigger/changes/event-trigger.security-label.d.ts +28 -0
- package/dist/core/objects/event-trigger/changes/event-trigger.security-label.js +61 -0
- package/dist/core/objects/event-trigger/changes/event-trigger.types.d.ts +2 -1
- package/dist/core/objects/event-trigger/event-trigger.diff.js +16 -0
- package/dist/core/objects/event-trigger/event-trigger.model.d.ts +10 -0
- package/dist/core/objects/event-trigger/event-trigger.model.js +19 -1
- package/dist/core/objects/extract-with-retry.d.ts +36 -0
- package/dist/core/objects/extract-with-retry.js +51 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.d.ts +1 -1
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.d.ts +28 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.js +61 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.d.ts +2 -1
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.js +16 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.d.ts +22 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.js +20 -1
- package/dist/core/objects/index/index.diff.js +0 -1
- package/dist/core/objects/index/index.model.d.ts +2 -3
- package/dist/core/objects/index/index.model.js +17 -6
- package/dist/core/objects/materialized-view/changes/materialized-view.base.d.ts +1 -1
- package/dist/core/objects/materialized-view/changes/materialized-view.security-label.d.ts +28 -0
- package/dist/core/objects/materialized-view/changes/materialized-view.security-label.js +61 -0
- package/dist/core/objects/materialized-view/changes/materialized-view.types.d.ts +2 -1
- package/dist/core/objects/materialized-view/materialized-view.diff.js +18 -0
- package/dist/core/objects/materialized-view/materialized-view.model.d.ts +24 -1
- package/dist/core/objects/materialized-view/materialized-view.model.js +40 -5
- package/dist/core/objects/procedure/changes/procedure.base.d.ts +1 -1
- package/dist/core/objects/procedure/changes/procedure.security-label.d.ts +28 -0
- package/dist/core/objects/procedure/changes/procedure.security-label.js +69 -0
- package/dist/core/objects/procedure/changes/procedure.types.d.ts +2 -1
- package/dist/core/objects/procedure/procedure.diff.js +16 -0
- package/dist/core/objects/procedure/procedure.model.d.ts +12 -1
- package/dist/core/objects/procedure/procedure.model.js +39 -5
- package/dist/core/objects/publication/changes/publication.base.d.ts +1 -1
- package/dist/core/objects/publication/changes/publication.security-label.d.ts +28 -0
- package/dist/core/objects/publication/changes/publication.security-label.js +61 -0
- package/dist/core/objects/publication/changes/publication.types.d.ts +2 -1
- package/dist/core/objects/publication/publication.diff.js +16 -0
- package/dist/core/objects/publication/publication.model.d.ts +14 -0
- package/dist/core/objects/publication/publication.model.js +20 -1
- package/dist/core/objects/rls-policy/rls-policy.diff.js +13 -1
- package/dist/core/objects/role/changes/role.base.d.ts +1 -1
- package/dist/core/objects/role/changes/role.security-label.d.ts +28 -0
- package/dist/core/objects/role/changes/role.security-label.js +61 -0
- package/dist/core/objects/role/changes/role.types.d.ts +2 -1
- package/dist/core/objects/role/role.diff.js +16 -0
- package/dist/core/objects/role/role.model.d.ts +10 -0
- package/dist/core/objects/role/role.model.js +29 -0
- package/dist/core/objects/rule/rule.model.d.ts +2 -1
- package/dist/core/objects/rule/rule.model.js +20 -3
- package/dist/core/objects/schema/changes/schema.base.d.ts +1 -1
- package/dist/core/objects/schema/changes/schema.security-label.d.ts +28 -0
- package/dist/core/objects/schema/changes/schema.security-label.js +61 -0
- package/dist/core/objects/schema/changes/schema.types.d.ts +2 -1
- package/dist/core/objects/schema/schema.diff.js +24 -1
- package/dist/core/objects/schema/schema.model.d.ts +10 -0
- package/dist/core/objects/schema/schema.model.js +18 -1
- package/dist/core/objects/security-label.types.d.ts +20 -0
- package/dist/core/objects/security-label.types.js +46 -0
- package/dist/core/objects/sequence/changes/sequence.base.d.ts +1 -1
- package/dist/core/objects/sequence/changes/sequence.security-label.d.ts +28 -0
- package/dist/core/objects/sequence/changes/sequence.security-label.js +61 -0
- package/dist/core/objects/sequence/changes/sequence.types.d.ts +2 -1
- package/dist/core/objects/sequence/sequence.diff.d.ts +2 -1
- package/dist/core/objects/sequence/sequence.diff.js +44 -4
- package/dist/core/objects/sequence/sequence.model.d.ts +10 -0
- package/dist/core/objects/sequence/sequence.model.js +19 -1
- package/dist/core/objects/subscription/changes/subscription.base.d.ts +1 -1
- package/dist/core/objects/subscription/changes/subscription.security-label.d.ts +28 -0
- package/dist/core/objects/subscription/changes/subscription.security-label.js +61 -0
- package/dist/core/objects/subscription/changes/subscription.types.d.ts +2 -1
- package/dist/core/objects/subscription/subscription.diff.js +16 -0
- package/dist/core/objects/subscription/subscription.model.d.ts +10 -0
- package/dist/core/objects/subscription/subscription.model.js +19 -1
- package/dist/core/objects/table/changes/table.alter.d.ts +12 -1
- package/dist/core/objects/table/changes/table.alter.js +20 -2
- package/dist/core/objects/table/changes/table.base.d.ts +1 -1
- package/dist/core/objects/table/changes/table.security-label.d.ts +63 -0
- package/dist/core/objects/table/changes/table.security-label.js +134 -0
- package/dist/core/objects/table/changes/table.types.d.ts +2 -1
- package/dist/core/objects/table/table.diff.js +68 -15
- package/dist/core/objects/table/table.model.d.ts +36 -1
- package/dist/core/objects/table/table.model.js +74 -7
- package/dist/core/objects/trigger/trigger.model.d.ts +2 -1
- package/dist/core/objects/trigger/trigger.model.js +20 -4
- package/dist/core/objects/type/composite-type/changes/composite-type.base.d.ts +1 -1
- package/dist/core/objects/type/composite-type/changes/composite-type.security-label.d.ts +28 -0
- package/dist/core/objects/type/composite-type/changes/composite-type.security-label.js +61 -0
- package/dist/core/objects/type/composite-type/changes/composite-type.types.d.ts +2 -1
- package/dist/core/objects/type/composite-type/composite-type.diff.js +16 -0
- package/dist/core/objects/type/composite-type/composite-type.model.d.ts +22 -0
- package/dist/core/objects/type/composite-type/composite-type.model.js +22 -2
- package/dist/core/objects/type/enum/changes/enum.base.d.ts +1 -1
- package/dist/core/objects/type/enum/changes/enum.security-label.d.ts +28 -0
- package/dist/core/objects/type/enum/changes/enum.security-label.js +61 -0
- package/dist/core/objects/type/enum/changes/enum.types.d.ts +2 -1
- package/dist/core/objects/type/enum/enum.diff.js +16 -0
- package/dist/core/objects/type/enum/enum.model.d.ts +10 -0
- package/dist/core/objects/type/enum/enum.model.js +20 -1
- package/dist/core/objects/type/range/changes/range.base.d.ts +1 -1
- package/dist/core/objects/type/range/changes/range.security-label.d.ts +28 -0
- package/dist/core/objects/type/range/changes/range.security-label.js +61 -0
- package/dist/core/objects/type/range/changes/range.types.d.ts +2 -1
- package/dist/core/objects/type/range/range.diff.js +16 -0
- package/dist/core/objects/type/range/range.model.d.ts +10 -0
- package/dist/core/objects/type/range/range.model.js +19 -1
- package/dist/core/objects/utils.d.ts +2 -0
- package/dist/core/objects/utils.js +6 -0
- package/dist/core/objects/view/changes/view.base.d.ts +1 -1
- package/dist/core/objects/view/changes/view.security-label.d.ts +28 -0
- package/dist/core/objects/view/changes/view.security-label.js +61 -0
- package/dist/core/objects/view/changes/view.types.d.ts +2 -1
- package/dist/core/objects/view/view.diff.js +13 -0
- package/dist/core/objects/view/view.model.d.ts +28 -1
- package/dist/core/objects/view/view.model.js +40 -5
- package/dist/core/plan/create.js +3 -1
- package/dist/core/plan/sql-format/fixtures.js +1 -0
- package/dist/core/plan/types.d.ts +8 -0
- package/dist/core/{post-diff-cycle-breaking.d.ts → post-diff-normalization.d.ts} +8 -1
- package/dist/core/post-diff-normalization.js +202 -0
- package/dist/core/sort/cycle-breakers.js +1 -1
- package/dist/core/sort/utils.d.ts +10 -0
- package/dist/core/sort/utils.js +28 -0
- package/package.json +1 -1
- package/src/core/catalog.diff.ts +4 -2
- package/src/core/catalog.model.ts +21 -8
- package/src/core/expand-replace-dependencies.test.ts +131 -0
- package/src/core/expand-replace-dependencies.ts +24 -0
- package/src/core/integrations/filter/dsl.test.ts +27 -0
- package/src/core/integrations/filter/flatten.ts +16 -0
- package/src/core/objects/aggregate/aggregate.diff.ts +33 -0
- package/src/core/objects/aggregate/aggregate.model.ts +22 -1
- package/src/core/objects/aggregate/changes/aggregate.base.ts +5 -1
- package/src/core/objects/aggregate/changes/aggregate.security-label.ts +99 -0
- package/src/core/objects/aggregate/changes/aggregate.types.ts +3 -1
- package/src/core/objects/base.model.ts +2 -0
- package/src/core/objects/domain/changes/domain.base.ts +5 -1
- package/src/core/objects/domain/changes/domain.security-label.test.ts +56 -0
- package/src/core/objects/domain/changes/domain.security-label.ts +77 -0
- package/src/core/objects/domain/changes/domain.types.ts +3 -1
- package/src/core/objects/domain/domain.diff.ts +33 -0
- package/src/core/objects/domain/domain.model.ts +22 -1
- package/src/core/objects/event-trigger/changes/event-trigger.base.ts +1 -1
- package/src/core/objects/event-trigger/changes/event-trigger.security-label.ts +95 -0
- package/src/core/objects/event-trigger/changes/event-trigger.types.ts +3 -1
- package/src/core/objects/event-trigger/event-trigger.diff.ts +33 -0
- package/src/core/objects/event-trigger/event-trigger.model.ts +22 -1
- package/src/core/objects/extract-with-retry.test.ts +143 -0
- package/src/core/objects/extract-with-retry.ts +87 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +5 -1
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.ts +95 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +3 -1
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +33 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +24 -1
- package/src/core/objects/index/index.diff.ts +0 -1
- package/src/core/objects/index/index.model.test.ts +37 -1
- package/src/core/objects/index/index.model.ts +25 -6
- package/src/core/objects/materialized-view/changes/materialized-view.base.ts +5 -1
- package/src/core/objects/materialized-view/changes/materialized-view.security-label.test.ts +63 -0
- package/src/core/objects/materialized-view/changes/materialized-view.security-label.ts +95 -0
- package/src/core/objects/materialized-view/changes/materialized-view.types.ts +3 -1
- package/src/core/objects/materialized-view/materialized-view.diff.ts +37 -0
- package/src/core/objects/materialized-view/materialized-view.model.test.ts +93 -0
- package/src/core/objects/materialized-view/materialized-view.model.ts +52 -8
- package/src/core/objects/procedure/changes/procedure.base.ts +5 -1
- package/src/core/objects/procedure/changes/procedure.security-label.ts +105 -0
- package/src/core/objects/procedure/changes/procedure.types.ts +3 -1
- package/src/core/objects/procedure/procedure.diff.ts +33 -0
- package/src/core/objects/procedure/procedure.model.test.ts +117 -0
- package/src/core/objects/procedure/procedure.model.ts +51 -7
- package/src/core/objects/publication/changes/publication.base.ts +1 -1
- package/src/core/objects/publication/changes/publication.security-label.ts +95 -0
- package/src/core/objects/publication/changes/publication.types.ts +3 -1
- package/src/core/objects/publication/publication.diff.ts +33 -0
- package/src/core/objects/publication/publication.model.ts +24 -1
- package/src/core/objects/rls-policy/rls-policy.diff.ts +19 -1
- package/src/core/objects/role/changes/role.base.ts +2 -1
- package/src/core/objects/role/changes/role.security-label.ts +77 -0
- package/src/core/objects/role/changes/role.types.ts +3 -1
- package/src/core/objects/role/role.diff.ts +33 -0
- package/src/core/objects/role/role.model.ts +32 -0
- package/src/core/objects/rule/rule.model.test.ts +99 -0
- package/src/core/objects/rule/rule.model.ts +28 -4
- package/src/core/objects/schema/changes/schema.alter.test.ts +1 -0
- package/src/core/objects/schema/changes/schema.base.ts +5 -1
- package/src/core/objects/schema/changes/schema.create.test.ts +1 -0
- package/src/core/objects/schema/changes/schema.drop.test.ts +1 -0
- package/src/core/objects/schema/changes/schema.security-label.test.ts +76 -0
- package/src/core/objects/schema/changes/schema.security-label.ts +77 -0
- package/src/core/objects/schema/changes/schema.types.ts +3 -1
- package/src/core/objects/schema/schema.diff.test.ts +1 -0
- package/src/core/objects/schema/schema.diff.ts +43 -1
- package/src/core/objects/schema/schema.model.ts +21 -1
- package/src/core/objects/security-label.types.test.ts +106 -0
- package/src/core/objects/security-label.types.ts +61 -0
- package/src/core/objects/sequence/changes/sequence.base.ts +5 -1
- package/src/core/objects/sequence/changes/sequence.security-label.test.ts +58 -0
- package/src/core/objects/sequence/changes/sequence.security-label.ts +92 -0
- package/src/core/objects/sequence/changes/sequence.types.ts +3 -1
- package/src/core/objects/sequence/sequence.diff.test.ts +87 -0
- package/src/core/objects/sequence/sequence.diff.ts +64 -6
- package/src/core/objects/sequence/sequence.model.ts +22 -1
- package/src/core/objects/subscription/changes/subscription.base.ts +1 -1
- package/src/core/objects/subscription/changes/subscription.security-label.ts +95 -0
- package/src/core/objects/subscription/changes/subscription.types.ts +3 -1
- package/src/core/objects/subscription/subscription.diff.ts +33 -0
- package/src/core/objects/subscription/subscription.model.ts +22 -1
- package/src/core/objects/table/changes/table.alter.test.ts +13 -21
- package/src/core/objects/table/changes/table.alter.ts +30 -3
- package/src/core/objects/table/changes/table.base.ts +5 -1
- package/src/core/objects/table/changes/table.security-label.test.ts +140 -0
- package/src/core/objects/table/changes/table.security-label.ts +183 -0
- package/src/core/objects/table/changes/table.types.ts +3 -1
- package/src/core/objects/table/table.diff.ts +111 -19
- package/src/core/objects/table/table.model.test.ts +209 -0
- package/src/core/objects/table/table.model.ts +94 -9
- package/src/core/objects/trigger/trigger.model.test.ts +113 -0
- package/src/core/objects/trigger/trigger.model.ts +28 -5
- package/src/core/objects/type/composite-type/changes/composite-type.base.ts +5 -1
- package/src/core/objects/type/composite-type/changes/composite-type.security-label.ts +95 -0
- package/src/core/objects/type/composite-type/changes/composite-type.types.ts +3 -1
- package/src/core/objects/type/composite-type/composite-type.diff.ts +33 -0
- package/src/core/objects/type/composite-type/composite-type.model.ts +26 -2
- package/src/core/objects/type/enum/changes/enum.base.ts +5 -1
- package/src/core/objects/type/enum/changes/enum.security-label.ts +77 -0
- package/src/core/objects/type/enum/changes/enum.types.ts +3 -1
- package/src/core/objects/type/enum/enum.diff.ts +33 -0
- package/src/core/objects/type/enum/enum.model.ts +25 -1
- package/src/core/objects/type/range/changes/range.base.ts +5 -1
- package/src/core/objects/type/range/changes/range.security-label.ts +77 -0
- package/src/core/objects/type/range/changes/range.types.ts +3 -1
- package/src/core/objects/type/range/range.diff.ts +33 -0
- package/src/core/objects/type/range/range.model.ts +22 -1
- package/src/core/objects/utils.ts +6 -0
- package/src/core/objects/view/changes/view.base.ts +5 -1
- package/src/core/objects/view/changes/view.security-label.test.ts +64 -0
- package/src/core/objects/view/changes/view.security-label.ts +77 -0
- package/src/core/objects/view/changes/view.types.ts +3 -1
- package/src/core/objects/view/view.diff.ts +31 -0
- package/src/core/objects/view/view.model.test.ts +90 -0
- package/src/core/objects/view/view.model.ts +53 -7
- package/src/core/plan/create.ts +3 -1
- package/src/core/plan/sql-format/fixtures.ts +1 -0
- package/src/core/plan/types.ts +8 -0
- package/src/core/{post-diff-cycle-breaking.test.ts → post-diff-normalization.test.ts} +168 -4
- package/src/core/post-diff-normalization.ts +260 -0
- package/src/core/sort/cycle-breakers.ts +1 -1
- package/src/core/sort/utils.ts +38 -0
- package/dist/core/post-diff-cycle-breaking.js +0 -100
- package/src/core/post-diff-cycle-breaking.ts +0 -138
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { Pool } from "pg";
|
|
3
|
+
import { extractProcedures, Procedure } from "./procedure.model.ts";
|
|
4
|
+
|
|
5
|
+
const baseRow = {
|
|
6
|
+
schema: "public",
|
|
7
|
+
kind: "f" as const,
|
|
8
|
+
return_type: "integer",
|
|
9
|
+
return_type_schema: "pg_catalog",
|
|
10
|
+
language: "sql",
|
|
11
|
+
security_definer: false,
|
|
12
|
+
volatility: "v" as const,
|
|
13
|
+
parallel_safety: "u" as const,
|
|
14
|
+
execution_cost: 100,
|
|
15
|
+
result_rows: 0,
|
|
16
|
+
is_strict: false,
|
|
17
|
+
leakproof: false,
|
|
18
|
+
returns_set: false,
|
|
19
|
+
argument_count: 0,
|
|
20
|
+
argument_default_count: 0,
|
|
21
|
+
argument_names: null,
|
|
22
|
+
argument_types: null,
|
|
23
|
+
all_argument_types: null,
|
|
24
|
+
argument_modes: null,
|
|
25
|
+
argument_defaults: null,
|
|
26
|
+
source_code: "select 1",
|
|
27
|
+
binary_path: null,
|
|
28
|
+
sql_body: null,
|
|
29
|
+
config: null,
|
|
30
|
+
owner: "postgres",
|
|
31
|
+
comment: null,
|
|
32
|
+
privileges: [],
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const mockPool = (rows: unknown[]): Pool =>
|
|
36
|
+
({ query: async () => ({ rows }) }) as unknown as Pool;
|
|
37
|
+
|
|
38
|
+
const mockPoolSequence = (...attempts: unknown[][]): Pool => {
|
|
39
|
+
let i = 0;
|
|
40
|
+
return {
|
|
41
|
+
query: async () => ({
|
|
42
|
+
rows: attempts[Math.min(i++, attempts.length - 1)],
|
|
43
|
+
}),
|
|
44
|
+
} as unknown as Pool;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const NO_BACKOFF = { backoffMs: 0 } as const;
|
|
48
|
+
|
|
49
|
+
describe("extractProcedures", () => {
|
|
50
|
+
test("skips rows where pg_get_functiondef returned NULL after exhausting retries", async () => {
|
|
51
|
+
const procs = await extractProcedures(
|
|
52
|
+
mockPool([
|
|
53
|
+
{
|
|
54
|
+
...baseRow,
|
|
55
|
+
name: '"good_fn"',
|
|
56
|
+
definition:
|
|
57
|
+
"CREATE OR REPLACE FUNCTION good_fn() RETURNS integer AS $$ select 1 $$ LANGUAGE sql;",
|
|
58
|
+
},
|
|
59
|
+
{ ...baseRow, name: '"orphan_fn"', definition: null },
|
|
60
|
+
]),
|
|
61
|
+
NO_BACKOFF,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
expect(procs).toHaveLength(1);
|
|
65
|
+
expect(procs[0]).toBeInstanceOf(Procedure);
|
|
66
|
+
expect(procs[0]?.name).toBe('"good_fn"');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("does not throw ZodError when the only row has a null definition", async () => {
|
|
70
|
+
await expect(
|
|
71
|
+
extractProcedures(
|
|
72
|
+
mockPool([{ ...baseRow, name: '"orphan"', definition: null }]),
|
|
73
|
+
NO_BACKOFF,
|
|
74
|
+
),
|
|
75
|
+
).resolves.toEqual([]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("returns all procedures when every row has a valid definition", async () => {
|
|
79
|
+
const procs = await extractProcedures(
|
|
80
|
+
mockPool([
|
|
81
|
+
{
|
|
82
|
+
...baseRow,
|
|
83
|
+
name: '"a"',
|
|
84
|
+
definition:
|
|
85
|
+
"CREATE OR REPLACE FUNCTION a() RETURNS integer AS $$ select 1 $$ LANGUAGE sql;",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
...baseRow,
|
|
89
|
+
name: '"b"',
|
|
90
|
+
definition:
|
|
91
|
+
"CREATE OR REPLACE FUNCTION b() RETURNS integer AS $$ select 2 $$ LANGUAGE sql;",
|
|
92
|
+
},
|
|
93
|
+
]),
|
|
94
|
+
NO_BACKOFF,
|
|
95
|
+
);
|
|
96
|
+
expect(procs.map((p) => p.name)).toEqual(['"a"', '"b"']);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("recovers when pg_get_functiondef is NULL on first attempt but resolved on retry", async () => {
|
|
100
|
+
const procs = await extractProcedures(
|
|
101
|
+
mockPoolSequence(
|
|
102
|
+
[{ ...baseRow, name: '"racy_fn"', definition: null }],
|
|
103
|
+
[
|
|
104
|
+
{
|
|
105
|
+
...baseRow,
|
|
106
|
+
name: '"racy_fn"',
|
|
107
|
+
definition:
|
|
108
|
+
"CREATE OR REPLACE FUNCTION racy_fn() RETURNS integer AS $$ select 1 $$ LANGUAGE sql;",
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
),
|
|
112
|
+
{ retries: 2, backoffMs: 0 },
|
|
113
|
+
);
|
|
114
|
+
expect(procs).toHaveLength(1);
|
|
115
|
+
expect(procs[0]?.name).toBe('"racy_fn"');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -6,6 +6,14 @@ import {
|
|
|
6
6
|
type PrivilegeProps,
|
|
7
7
|
privilegePropsSchema,
|
|
8
8
|
} from "../base.privilege-diff.ts";
|
|
9
|
+
import {
|
|
10
|
+
type ExtractRetryOptions,
|
|
11
|
+
extractWithDefinitionRetry,
|
|
12
|
+
} from "../extract-with-retry.ts";
|
|
13
|
+
import {
|
|
14
|
+
type SecurityLabelProps,
|
|
15
|
+
securityLabelPropsSchema,
|
|
16
|
+
} from "../security-label.types.ts";
|
|
9
17
|
|
|
10
18
|
const FunctionKindSchema = z.enum([
|
|
11
19
|
"f", // function
|
|
@@ -64,6 +72,16 @@ const procedurePropsSchema = z.object({
|
|
|
64
72
|
owner: z.string(),
|
|
65
73
|
comment: z.string().nullable(),
|
|
66
74
|
privileges: z.array(privilegePropsSchema),
|
|
75
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// pg_get_functiondef(oid) can return NULL when the function (its pg_proc
|
|
79
|
+
// row) is dropped between catalog scan and resolution, or under transient
|
|
80
|
+
// catalog state. An unreadable function cannot be diffed, so we accept NULL
|
|
81
|
+
// here and filter the row out at extraction time rather than crashing the
|
|
82
|
+
// whole catalog parse with a ZodError.
|
|
83
|
+
const procedureRowSchema = procedurePropsSchema.extend({
|
|
84
|
+
definition: z.string().nullable(),
|
|
67
85
|
});
|
|
68
86
|
|
|
69
87
|
type ProcedurePrivilegeProps = PrivilegeProps;
|
|
@@ -99,6 +117,7 @@ export class Procedure extends BasePgModel {
|
|
|
99
117
|
public readonly owner: ProcedureProps["owner"];
|
|
100
118
|
public readonly comment: ProcedureProps["comment"];
|
|
101
119
|
public readonly privileges: ProcedurePrivilegeProps[];
|
|
120
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
102
121
|
|
|
103
122
|
constructor(props: ProcedureProps) {
|
|
104
123
|
super();
|
|
@@ -135,6 +154,7 @@ export class Procedure extends BasePgModel {
|
|
|
135
154
|
this.owner = props.owner;
|
|
136
155
|
this.comment = props.comment;
|
|
137
156
|
this.privileges = props.privileges;
|
|
157
|
+
this.security_labels = props.security_labels ?? [];
|
|
138
158
|
}
|
|
139
159
|
|
|
140
160
|
get stableId(): `procedure:${string}` {
|
|
@@ -179,12 +199,21 @@ export class Procedure extends BasePgModel {
|
|
|
179
199
|
owner: this.owner,
|
|
180
200
|
comment: this.comment,
|
|
181
201
|
privileges: this.privileges,
|
|
202
|
+
security_labels: this.security_labels,
|
|
182
203
|
};
|
|
183
204
|
}
|
|
184
205
|
}
|
|
185
206
|
|
|
186
|
-
export async function extractProcedures(
|
|
187
|
-
|
|
207
|
+
export async function extractProcedures(
|
|
208
|
+
pool: Pool,
|
|
209
|
+
options?: ExtractRetryOptions,
|
|
210
|
+
): Promise<Procedure[]> {
|
|
211
|
+
const procedureRows = await extractWithDefinitionRetry({
|
|
212
|
+
label: "procedures",
|
|
213
|
+
options,
|
|
214
|
+
hasNullDefinition: (row) => row.definition === null,
|
|
215
|
+
query: async () => {
|
|
216
|
+
const result = await pool.query<ProcedureProps>(sql`
|
|
188
217
|
with extension_oids as (
|
|
189
218
|
select
|
|
190
219
|
objid
|
|
@@ -244,7 +273,20 @@ select
|
|
|
244
273
|
)
|
|
245
274
|
from lateral aclexplode(COALESCE(p.proacl, acldefault('f', p.proowner))) as x(grantor, grantee, privilege_type, is_grantable)
|
|
246
275
|
), '[]'
|
|
247
|
-
) as privileges
|
|
276
|
+
) as privileges,
|
|
277
|
+
coalesce(
|
|
278
|
+
(
|
|
279
|
+
select json_agg(
|
|
280
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
281
|
+
order by sl.provider
|
|
282
|
+
)
|
|
283
|
+
from pg_catalog.pg_seclabel sl
|
|
284
|
+
where sl.objoid = p.oid
|
|
285
|
+
and sl.classoid = 'pg_proc'::regclass
|
|
286
|
+
and sl.objsubid = 0
|
|
287
|
+
),
|
|
288
|
+
'[]'::json
|
|
289
|
+
) as security_labels
|
|
248
290
|
from
|
|
249
291
|
pg_catalog.pg_proc p
|
|
250
292
|
inner join pg_catalog.pg_language l on l.oid = p.prolang
|
|
@@ -256,9 +298,11 @@ from
|
|
|
256
298
|
order by
|
|
257
299
|
1, 2
|
|
258
300
|
`);
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
301
|
+
return result.rows.map((row: unknown) => procedureRowSchema.parse(row));
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
const validatedRows = procedureRows.filter(
|
|
305
|
+
(row): row is ProcedureProps => row.definition !== null,
|
|
262
306
|
);
|
|
263
|
-
return validatedRows.map((row
|
|
307
|
+
return validatedRows.map((row) => new Procedure(row));
|
|
264
308
|
}
|
|
@@ -3,7 +3,7 @@ import type { Publication } from "../publication.model.ts";
|
|
|
3
3
|
|
|
4
4
|
abstract class BasePublicationChange extends BaseChange {
|
|
5
5
|
abstract readonly publication: Publication;
|
|
6
|
-
abstract readonly scope: "object" | "comment";
|
|
6
|
+
abstract readonly scope: "object" | "comment" | "security_label";
|
|
7
7
|
readonly objectType = "publication" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { quoteLiteral } from "../../base.change.ts";
|
|
2
|
+
import type { SecurityLabelProps } from "../../security-label.types.ts";
|
|
3
|
+
import { stableId } from "../../utils.ts";
|
|
4
|
+
import type { Publication } from "../publication.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
CreatePublicationChange,
|
|
7
|
+
DropPublicationChange,
|
|
8
|
+
} from "./publication.base.ts";
|
|
9
|
+
|
|
10
|
+
export type SecurityLabelPublication =
|
|
11
|
+
| CreateSecurityLabelOnPublication
|
|
12
|
+
| DropSecurityLabelOnPublication;
|
|
13
|
+
|
|
14
|
+
export class CreateSecurityLabelOnPublication extends CreatePublicationChange {
|
|
15
|
+
public readonly publication: Publication;
|
|
16
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
17
|
+
public readonly scope = "security_label" as const;
|
|
18
|
+
|
|
19
|
+
constructor(props: {
|
|
20
|
+
publication: Publication;
|
|
21
|
+
securityLabel: SecurityLabelProps;
|
|
22
|
+
}) {
|
|
23
|
+
super();
|
|
24
|
+
this.publication = props.publication;
|
|
25
|
+
this.securityLabel = props.securityLabel;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get creates() {
|
|
29
|
+
return [
|
|
30
|
+
stableId.securityLabel(
|
|
31
|
+
this.publication.stableId,
|
|
32
|
+
this.securityLabel.provider,
|
|
33
|
+
),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get requires() {
|
|
38
|
+
return [this.publication.stableId];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
serialize(): string {
|
|
42
|
+
return [
|
|
43
|
+
"SECURITY LABEL FOR",
|
|
44
|
+
this.securityLabel.provider,
|
|
45
|
+
"ON PUBLICATION",
|
|
46
|
+
this.publication.name,
|
|
47
|
+
"IS",
|
|
48
|
+
quoteLiteral(this.securityLabel.label),
|
|
49
|
+
].join(" ");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class DropSecurityLabelOnPublication extends DropPublicationChange {
|
|
54
|
+
public readonly publication: Publication;
|
|
55
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
56
|
+
public readonly scope = "security_label" as const;
|
|
57
|
+
|
|
58
|
+
constructor(props: {
|
|
59
|
+
publication: Publication;
|
|
60
|
+
securityLabel: SecurityLabelProps;
|
|
61
|
+
}) {
|
|
62
|
+
super();
|
|
63
|
+
this.publication = props.publication;
|
|
64
|
+
this.securityLabel = props.securityLabel;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get drops() {
|
|
68
|
+
return [
|
|
69
|
+
stableId.securityLabel(
|
|
70
|
+
this.publication.stableId,
|
|
71
|
+
this.securityLabel.provider,
|
|
72
|
+
),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get requires() {
|
|
77
|
+
return [
|
|
78
|
+
stableId.securityLabel(
|
|
79
|
+
this.publication.stableId,
|
|
80
|
+
this.securityLabel.provider,
|
|
81
|
+
),
|
|
82
|
+
this.publication.stableId,
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
serialize(): string {
|
|
87
|
+
return [
|
|
88
|
+
"SECURITY LABEL FOR",
|
|
89
|
+
this.securityLabel.provider,
|
|
90
|
+
"ON PUBLICATION",
|
|
91
|
+
this.publication.name,
|
|
92
|
+
"IS NULL",
|
|
93
|
+
].join(" ");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
import type { CommentPublication } from "./publication.comment.ts";
|
|
11
11
|
import type { CreatePublication } from "./publication.create.ts";
|
|
12
12
|
import type { DropPublication } from "./publication.drop.ts";
|
|
13
|
+
import type { SecurityLabelPublication } from "./publication.security-label.ts";
|
|
13
14
|
|
|
14
15
|
/** Union of all publication-related change variants (`objectType: "publication"`). @category Change Types */
|
|
15
16
|
export type PublicationChange =
|
|
@@ -22,4 +23,5 @@ export type PublicationChange =
|
|
|
22
23
|
| AlterPublicationSetOwner
|
|
23
24
|
| CommentPublication
|
|
24
25
|
| CreatePublication
|
|
25
|
-
| DropPublication
|
|
26
|
+
| DropPublication
|
|
27
|
+
| SecurityLabelPublication;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { diffObjects } from "../base.diff.ts";
|
|
2
2
|
import type { ObjectDiffContext } from "../diff-context.ts";
|
|
3
|
+
import { diffSecurityLabels } from "../security-label.types.ts";
|
|
3
4
|
import { deepEqual } from "../utils.ts";
|
|
4
5
|
import {
|
|
5
6
|
AlterPublicationAddSchemas,
|
|
@@ -15,6 +16,10 @@ import {
|
|
|
15
16
|
} from "./changes/publication.comment.ts";
|
|
16
17
|
import { CreatePublication } from "./changes/publication.create.ts";
|
|
17
18
|
import { DropPublication } from "./changes/publication.drop.ts";
|
|
19
|
+
import {
|
|
20
|
+
CreateSecurityLabelOnPublication,
|
|
21
|
+
DropSecurityLabelOnPublication,
|
|
22
|
+
} from "./changes/publication.security-label.ts";
|
|
18
23
|
import type { PublicationChange } from "./changes/publication.types.ts";
|
|
19
24
|
import type {
|
|
20
25
|
Publication,
|
|
@@ -47,6 +52,14 @@ export function diffPublications(
|
|
|
47
52
|
if (publication.comment !== null) {
|
|
48
53
|
changes.push(new CreateCommentOnPublication({ publication }));
|
|
49
54
|
}
|
|
55
|
+
for (const label of publication.security_labels) {
|
|
56
|
+
changes.push(
|
|
57
|
+
new CreateSecurityLabelOnPublication({
|
|
58
|
+
publication,
|
|
59
|
+
securityLabel: label,
|
|
60
|
+
}),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
50
63
|
}
|
|
51
64
|
|
|
52
65
|
for (const id of dropped) {
|
|
@@ -172,6 +185,26 @@ export function diffPublications(
|
|
|
172
185
|
);
|
|
173
186
|
}
|
|
174
187
|
}
|
|
188
|
+
|
|
189
|
+
// SECURITY LABELS
|
|
190
|
+
changes.push(
|
|
191
|
+
...diffSecurityLabels<
|
|
192
|
+
CreateSecurityLabelOnPublication | DropSecurityLabelOnPublication
|
|
193
|
+
>(
|
|
194
|
+
mainPublication.security_labels,
|
|
195
|
+
branchPublication.security_labels,
|
|
196
|
+
(securityLabel) =>
|
|
197
|
+
new CreateSecurityLabelOnPublication({
|
|
198
|
+
publication: branchPublication,
|
|
199
|
+
securityLabel,
|
|
200
|
+
}),
|
|
201
|
+
(securityLabel) =>
|
|
202
|
+
new DropSecurityLabelOnPublication({
|
|
203
|
+
publication: mainPublication,
|
|
204
|
+
securityLabel,
|
|
205
|
+
}),
|
|
206
|
+
),
|
|
207
|
+
);
|
|
175
208
|
}
|
|
176
209
|
|
|
177
210
|
return changes;
|
|
@@ -2,6 +2,11 @@ import { sql } from "@ts-safeql/sql-tag";
|
|
|
2
2
|
import type { Pool } from "pg";
|
|
3
3
|
import z from "zod";
|
|
4
4
|
import { BasePgModel } from "../base.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
normalizeSecurityLabels,
|
|
7
|
+
type SecurityLabelProps,
|
|
8
|
+
securityLabelPropsSchema,
|
|
9
|
+
} from "../security-label.types.ts";
|
|
5
10
|
|
|
6
11
|
const publicationTablePropsSchema = z.object({
|
|
7
12
|
schema: z.string(),
|
|
@@ -22,6 +27,7 @@ const publicationPropsSchema = z.object({
|
|
|
22
27
|
publish_via_partition_root: z.boolean(),
|
|
23
28
|
tables: z.array(publicationTablePropsSchema),
|
|
24
29
|
schemas: z.array(z.string()),
|
|
30
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
25
31
|
});
|
|
26
32
|
|
|
27
33
|
export type PublicationTableProps = z.infer<typeof publicationTablePropsSchema>;
|
|
@@ -44,6 +50,7 @@ export class Publication extends BasePgModel {
|
|
|
44
50
|
public readonly publish_via_partition_root: PublicationProps["publish_via_partition_root"];
|
|
45
51
|
public readonly tables: PublicationTableProps[];
|
|
46
52
|
public readonly schemas: PublicationProps["schemas"];
|
|
53
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
47
54
|
|
|
48
55
|
constructor(props: PublicationProps) {
|
|
49
56
|
super();
|
|
@@ -72,6 +79,7 @@ export class Publication extends BasePgModel {
|
|
|
72
79
|
});
|
|
73
80
|
|
|
74
81
|
this.schemas = [...props.schemas].sort((a, b) => a.localeCompare(b));
|
|
82
|
+
this.security_labels = props.security_labels ?? [];
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
get stableId(): `publication:${string}` {
|
|
@@ -96,6 +104,7 @@ export class Publication extends BasePgModel {
|
|
|
96
104
|
publish_via_partition_root: this.publish_via_partition_root,
|
|
97
105
|
tables: this.tables,
|
|
98
106
|
schemas: this.schemas,
|
|
107
|
+
security_labels: this.security_labels,
|
|
99
108
|
};
|
|
100
109
|
}
|
|
101
110
|
|
|
@@ -118,6 +127,7 @@ export class Publication extends BasePgModel {
|
|
|
118
127
|
a.schema.localeCompare(b.schema) || a.name.localeCompare(b.name),
|
|
119
128
|
),
|
|
120
129
|
schemas: [...this.schemas].sort((a, b) => a.localeCompare(b)),
|
|
130
|
+
security_labels: normalizeSecurityLabels(this.security_labels),
|
|
121
131
|
},
|
|
122
132
|
};
|
|
123
133
|
}
|
|
@@ -194,7 +204,20 @@ export async function extractPublications(pool: Pool): Promise<Publication[]> {
|
|
|
194
204
|
where s.pnpubid = p.oid
|
|
195
205
|
),
|
|
196
206
|
'[]'::json
|
|
197
|
-
) as schemas
|
|
207
|
+
) as schemas,
|
|
208
|
+
coalesce(
|
|
209
|
+
(
|
|
210
|
+
select json_agg(
|
|
211
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
212
|
+
order by sl.provider
|
|
213
|
+
)
|
|
214
|
+
from pg_catalog.pg_seclabel sl
|
|
215
|
+
where sl.objoid = p.oid
|
|
216
|
+
and sl.classoid = 'pg_publication'::regclass
|
|
217
|
+
and sl.objsubid = 0
|
|
218
|
+
),
|
|
219
|
+
'[]'::json
|
|
220
|
+
) as security_labels
|
|
198
221
|
from pg_publication p
|
|
199
222
|
left join extension_oids e on e.objid = p.oid
|
|
200
223
|
where e.objid is null
|
|
@@ -59,7 +59,25 @@ export function diffRlsPolicies(
|
|
|
59
59
|
{},
|
|
60
60
|
);
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
// The set of relations and procedures that the policy's USING / WITH
|
|
63
|
+
// CHECK expressions reference is recorded by PostgreSQL in pg_depend
|
|
64
|
+
// (recordDependencyOnExpr at policy creation). When that set changes
|
|
65
|
+
// it is unsafe to ALTER POLICY in place: the old reference target may
|
|
66
|
+
// be dropped in the same plan, and the new reference target may only
|
|
67
|
+
// exist after the create phase. Drop+create lets the sort phase order
|
|
68
|
+
// the policy's drop before the referenced object's drop and the
|
|
69
|
+
// policy's recreate after the referenced object's create.
|
|
70
|
+
const referencedDependenciesChanged = hasNonAlterableChanges(
|
|
71
|
+
mainRlsPolicy,
|
|
72
|
+
branchRlsPolicy,
|
|
73
|
+
["referenced_procedures", "referenced_relations"] as const,
|
|
74
|
+
{
|
|
75
|
+
referenced_procedures: deepEqual,
|
|
76
|
+
referenced_relations: deepEqual,
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (nonAlterablePropsChanged || referencedDependenciesChanged) {
|
|
63
81
|
// Replace the entire RLS policy (drop + create)
|
|
64
82
|
changes.push(
|
|
65
83
|
new DropRlsPolicy({ policy: mainRlsPolicy }),
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { quoteLiteral } from "../../base.change.ts";
|
|
2
|
+
import type { SecurityLabelProps } from "../../security-label.types.ts";
|
|
3
|
+
import { stableId } from "../../utils.ts";
|
|
4
|
+
import type { Role } from "../role.model.ts";
|
|
5
|
+
import { CreateRoleChange, DropRoleChange } from "./role.base.ts";
|
|
6
|
+
|
|
7
|
+
export type SecurityLabelRole =
|
|
8
|
+
| CreateSecurityLabelOnRole
|
|
9
|
+
| DropSecurityLabelOnRole;
|
|
10
|
+
|
|
11
|
+
export class CreateSecurityLabelOnRole extends CreateRoleChange {
|
|
12
|
+
public readonly role: Role;
|
|
13
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
14
|
+
public readonly scope = "security_label" as const;
|
|
15
|
+
|
|
16
|
+
constructor(props: { role: Role; securityLabel: SecurityLabelProps }) {
|
|
17
|
+
super();
|
|
18
|
+
this.role = props.role;
|
|
19
|
+
this.securityLabel = props.securityLabel;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get creates() {
|
|
23
|
+
return [
|
|
24
|
+
stableId.securityLabel(this.role.stableId, this.securityLabel.provider),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get requires() {
|
|
29
|
+
return [this.role.stableId];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
serialize(): string {
|
|
33
|
+
return [
|
|
34
|
+
"SECURITY LABEL FOR",
|
|
35
|
+
this.securityLabel.provider,
|
|
36
|
+
"ON ROLE",
|
|
37
|
+
this.role.name,
|
|
38
|
+
"IS",
|
|
39
|
+
quoteLiteral(this.securityLabel.label),
|
|
40
|
+
].join(" ");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class DropSecurityLabelOnRole extends DropRoleChange {
|
|
45
|
+
public readonly role: Role;
|
|
46
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
47
|
+
public readonly scope = "security_label" as const;
|
|
48
|
+
|
|
49
|
+
constructor(props: { role: Role; securityLabel: SecurityLabelProps }) {
|
|
50
|
+
super();
|
|
51
|
+
this.role = props.role;
|
|
52
|
+
this.securityLabel = props.securityLabel;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get drops() {
|
|
56
|
+
return [
|
|
57
|
+
stableId.securityLabel(this.role.stableId, this.securityLabel.provider),
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get requires() {
|
|
62
|
+
return [
|
|
63
|
+
stableId.securityLabel(this.role.stableId, this.securityLabel.provider),
|
|
64
|
+
this.role.stableId,
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
serialize(): string {
|
|
69
|
+
return [
|
|
70
|
+
"SECURITY LABEL FOR",
|
|
71
|
+
this.securityLabel.provider,
|
|
72
|
+
"ON ROLE",
|
|
73
|
+
this.role.name,
|
|
74
|
+
"IS NULL",
|
|
75
|
+
].join(" ");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { CommentRole } from "./role.comment.ts";
|
|
|
3
3
|
import type { CreateRole } from "./role.create.ts";
|
|
4
4
|
import type { DropRole } from "./role.drop.ts";
|
|
5
5
|
import type { RolePrivilege } from "./role.privilege.ts";
|
|
6
|
+
import type { SecurityLabelRole } from "./role.security-label.ts";
|
|
6
7
|
|
|
7
8
|
/** Union of all role-related change variants (`objectType: "role"`). @category Change Types */
|
|
8
9
|
export type RoleChange =
|
|
@@ -10,4 +11,5 @@ export type RoleChange =
|
|
|
10
11
|
| CommentRole
|
|
11
12
|
| CreateRole
|
|
12
13
|
| DropRole
|
|
13
|
-
| RolePrivilege
|
|
14
|
+
| RolePrivilege
|
|
15
|
+
| SecurityLabelRole;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { diffObjects } from "../base.diff.ts";
|
|
2
|
+
import { diffSecurityLabels } from "../security-label.types.ts";
|
|
2
3
|
import {
|
|
3
4
|
AlterRoleSetConfig,
|
|
4
5
|
AlterRoleSetOptions,
|
|
@@ -16,6 +17,10 @@ import {
|
|
|
16
17
|
RevokeRoleMembership,
|
|
17
18
|
RevokeRoleMembershipOptions,
|
|
18
19
|
} from "./changes/role.privilege.ts";
|
|
20
|
+
import {
|
|
21
|
+
CreateSecurityLabelOnRole,
|
|
22
|
+
DropSecurityLabelOnRole,
|
|
23
|
+
} from "./changes/role.security-label.ts";
|
|
19
24
|
import type { RoleChange } from "./changes/role.types.ts";
|
|
20
25
|
import type { Role } from "./role.model.ts";
|
|
21
26
|
|
|
@@ -51,6 +56,14 @@ export function diffRoles(
|
|
|
51
56
|
if (role.comment !== null) {
|
|
52
57
|
changes.push(new CreateCommentOnRole({ role }));
|
|
53
58
|
}
|
|
59
|
+
for (const label of role.security_labels) {
|
|
60
|
+
changes.push(
|
|
61
|
+
new CreateSecurityLabelOnRole({
|
|
62
|
+
role,
|
|
63
|
+
securityLabel: label,
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
54
67
|
// MEMBERSHIPS: Grant memberships immediately after role creation.
|
|
55
68
|
// Members are already deduplicated by the Role model constructor.
|
|
56
69
|
for (const membership of role.members) {
|
|
@@ -215,6 +228,26 @@ export function diffRoles(
|
|
|
215
228
|
}
|
|
216
229
|
}
|
|
217
230
|
|
|
231
|
+
// SECURITY LABELS
|
|
232
|
+
changes.push(
|
|
233
|
+
...diffSecurityLabels<
|
|
234
|
+
CreateSecurityLabelOnRole | DropSecurityLabelOnRole
|
|
235
|
+
>(
|
|
236
|
+
mainRole.security_labels,
|
|
237
|
+
branchRole.security_labels,
|
|
238
|
+
(securityLabel) =>
|
|
239
|
+
new CreateSecurityLabelOnRole({
|
|
240
|
+
role: branchRole,
|
|
241
|
+
securityLabel,
|
|
242
|
+
}),
|
|
243
|
+
(securityLabel) =>
|
|
244
|
+
new DropSecurityLabelOnRole({
|
|
245
|
+
role: mainRole,
|
|
246
|
+
securityLabel,
|
|
247
|
+
}),
|
|
248
|
+
),
|
|
249
|
+
);
|
|
250
|
+
|
|
218
251
|
// MEMBERSHIPS
|
|
219
252
|
// Members are already deduplicated by the Role model constructor.
|
|
220
253
|
const mainMembers = new Map(mainRole.members.map((m) => [m.member, m]));
|