@team-semicolon/semicolony-cli 4.18.51 → 4.18.52
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/bundle.js +1524 -1046
- package/migrations/149_hive_cron_capability_templates.sql +44 -0
- package/migrations/150_hive_cron_action_contract.sql +38 -0
- package/migrations/151_hive_cron_occurrence_leases.sql +150 -0
- package/migrations/152_hive_cron_relay_outbox.sql +243 -0
- package/migrations/153_hive_cron_evidence_uniqueness.sql +9 -0
- package/migrations/154_hive_cron_evidence_provider_grants.sql +816 -0
- package/migrations/155_hive_cron_occurrence_lease_provider_grants.sql +44 -0
- package/migrations/156_hive_cron_relay_outbox_provider_grants.sql +47 -0
- package/migrations/157_hive_cron_trusted_config_revisions.sql +243 -0
- package/migrations/158_hive_cron_typed_dispatch_outbox.sql +1406 -0
- package/migrations/159_hive_cron_shadow_cursor.sql +600 -0
- package/migrations/160_hive_cron_failure_alert_outbox.sql +406 -0
- package/migrations/161_skill_governance.sql +529 -0
- package/migrations/161_workspace_projection_grants.sql +39 -0
- package/migrations/162_sc_app_kb_history_trigger_hardening.sql +96 -0
- package/package.json +4 -2
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
-- @schema-retarget: off
|
|
2
|
+
-- Hive cron v2 occurrence lease mutation privileges for the provider role.
|
|
3
|
+
-- Migration 154 remains the evidence-writer privilege boundary; this migration is
|
|
4
|
+
-- narrowly additive for lease acquisition and failed-occurrence release.
|
|
5
|
+
-- The migration runner supplies the transaction boundary; do not add one here.
|
|
6
|
+
|
|
7
|
+
DO $$
|
|
8
|
+
DECLARE
|
|
9
|
+
role_state record;
|
|
10
|
+
BEGIN
|
|
11
|
+
SELECT rolcanlogin, rolsuper, rolcreatedb, rolcreaterole,
|
|
12
|
+
rolinherit, rolreplication, rolbypassrls
|
|
13
|
+
INTO role_state
|
|
14
|
+
FROM pg_roles
|
|
15
|
+
WHERE rolname = 'sc_provider';
|
|
16
|
+
|
|
17
|
+
IF NOT FOUND THEN
|
|
18
|
+
RAISE EXCEPTION 'sc_provider role missing; migration 135 required';
|
|
19
|
+
END IF;
|
|
20
|
+
|
|
21
|
+
IF NOT role_state.rolcanlogin
|
|
22
|
+
OR role_state.rolsuper
|
|
23
|
+
OR role_state.rolcreatedb
|
|
24
|
+
OR role_state.rolcreaterole
|
|
25
|
+
OR role_state.rolinherit
|
|
26
|
+
OR role_state.rolreplication
|
|
27
|
+
OR role_state.rolbypassrls THEN
|
|
28
|
+
RAISE EXCEPTION 'sc_provider role attributes are unsafe';
|
|
29
|
+
END IF;
|
|
30
|
+
END $$;
|
|
31
|
+
|
|
32
|
+
REVOKE ALL PRIVILEGES
|
|
33
|
+
ON TABLE semicolony.cron_read_action_occurrence_leases
|
|
34
|
+
FROM sc_provider;
|
|
35
|
+
|
|
36
|
+
REVOKE ALL
|
|
37
|
+
ON FUNCTION semicolony.hive_cron_acquire_lease(text, text, text)
|
|
38
|
+
FROM PUBLIC, sc_app, sc_provider;
|
|
39
|
+
REVOKE ALL
|
|
40
|
+
ON FUNCTION semicolony.hive_cron_release_failed(text, text, text)
|
|
41
|
+
FROM PUBLIC, sc_app, sc_provider;
|
|
42
|
+
|
|
43
|
+
GRANT EXECUTE ON FUNCTION semicolony.hive_cron_acquire_lease(text, text, text) TO sc_provider;
|
|
44
|
+
GRANT EXECUTE ON FUNCTION semicolony.hive_cron_release_failed(text, text, text) TO sc_provider;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
-- @schema-retarget: off
|
|
2
|
+
-- Hive cron v2 relay outbox mutation privilege for the provider role.
|
|
3
|
+
-- The migration runner supplies the transaction boundary; do not add one here.
|
|
4
|
+
|
|
5
|
+
DO $$
|
|
6
|
+
DECLARE
|
|
7
|
+
role_state record;
|
|
8
|
+
BEGIN
|
|
9
|
+
SELECT rolcanlogin, rolsuper, rolcreatedb, rolcreaterole,
|
|
10
|
+
rolinherit, rolreplication, rolbypassrls
|
|
11
|
+
INTO role_state
|
|
12
|
+
FROM pg_roles
|
|
13
|
+
WHERE rolname = 'sc_provider';
|
|
14
|
+
|
|
15
|
+
IF NOT FOUND THEN
|
|
16
|
+
RAISE EXCEPTION 'sc_provider role missing; migration 135 required';
|
|
17
|
+
END IF;
|
|
18
|
+
|
|
19
|
+
IF NOT role_state.rolcanlogin
|
|
20
|
+
OR role_state.rolsuper
|
|
21
|
+
OR role_state.rolcreatedb
|
|
22
|
+
OR role_state.rolcreaterole
|
|
23
|
+
OR role_state.rolinherit
|
|
24
|
+
OR role_state.rolreplication
|
|
25
|
+
OR role_state.rolbypassrls THEN
|
|
26
|
+
RAISE EXCEPTION 'sc_provider role attributes are unsafe';
|
|
27
|
+
END IF;
|
|
28
|
+
END $$;
|
|
29
|
+
|
|
30
|
+
REVOKE ALL PRIVILEGES
|
|
31
|
+
ON TABLE semicolony.cron_read_action_relay_outbox
|
|
32
|
+
FROM sc_provider;
|
|
33
|
+
|
|
34
|
+
REVOKE ALL
|
|
35
|
+
ON FUNCTION semicolony.hive_cron_put_outbox(text, text, text)
|
|
36
|
+
FROM PUBLIC, sc_app, sc_provider;
|
|
37
|
+
REVOKE ALL
|
|
38
|
+
ON FUNCTION semicolony.hive_cron_get_outbox(text, text, text)
|
|
39
|
+
FROM PUBLIC, sc_app, sc_provider;
|
|
40
|
+
REVOKE ALL
|
|
41
|
+
ON FUNCTION semicolony.hive_cron_complete_outbox(text, text, text, text, text)
|
|
42
|
+
FROM PUBLIC, sc_app, sc_provider;
|
|
43
|
+
|
|
44
|
+
GRANT EXECUTE ON FUNCTION semicolony.hive_cron_put_outbox(text, text, text) TO sc_provider;
|
|
45
|
+
GRANT EXECUTE ON FUNCTION semicolony.hive_cron_get_outbox(text, text, text) TO sc_provider;
|
|
46
|
+
GRANT EXECUTE ON FUNCTION semicolony.hive_cron_complete_outbox(text, text, text, text, text)
|
|
47
|
+
TO sc_provider;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
-- @schema-retarget: off
|
|
2
|
+
-- Hive cron v2 append-only trusted configuration revisions.
|
|
3
|
+
-- This migration creates no configuration row and enables no cron job.
|
|
4
|
+
-- The migration runner supplies the transaction boundary; do not add one here.
|
|
5
|
+
|
|
6
|
+
CREATE OR REPLACE FUNCTION semicolony.hive_cron_valid_trusted_config_shape(p_action_kind text, p_payload jsonb)
|
|
7
|
+
RETURNS boolean
|
|
8
|
+
LANGUAGE plpgsql
|
|
9
|
+
IMMUTABLE
|
|
10
|
+
STRICT
|
|
11
|
+
SET search_path = pg_catalog
|
|
12
|
+
AS $$
|
|
13
|
+
DECLARE
|
|
14
|
+
endpoint jsonb;
|
|
15
|
+
endpoint_service_id text;
|
|
16
|
+
endpoint_origin text;
|
|
17
|
+
endpoint_service_ids text[] := ARRAY[]::text[];
|
|
18
|
+
endpoint_origins text[] := ARRAY[]::text[];
|
|
19
|
+
previous_endpoint_service_id text;
|
|
20
|
+
project_entry jsonb;
|
|
21
|
+
project_id text;
|
|
22
|
+
project_ids text[] := ARRAY[]::text[];
|
|
23
|
+
previous_project_id text;
|
|
24
|
+
BEGIN
|
|
25
|
+
IF pg_catalog.jsonb_typeof(p_payload) IS DISTINCT FROM 'object'
|
|
26
|
+
OR pg_catalog.octet_length(p_payload::text) > 65536
|
|
27
|
+
OR (p_payload::text COLLATE "C") ~* '(token|secret|password|authorization|credential)'
|
|
28
|
+
OR (p_payload::text COLLATE "C") ~* '-----BEGIN [^-]*(PRIVATE KEY|OPENSSH PRIVATE KEY)-----' THEN
|
|
29
|
+
RETURN false;
|
|
30
|
+
END IF;
|
|
31
|
+
|
|
32
|
+
IF p_action_kind = 'service-health-check' THEN
|
|
33
|
+
IF NOT (p_payload ? 'endpoints')
|
|
34
|
+
OR (p_payload - 'endpoints') <> '{}'::jsonb
|
|
35
|
+
OR pg_catalog.jsonb_typeof(p_payload->'endpoints') IS DISTINCT FROM 'array' THEN
|
|
36
|
+
RETURN false;
|
|
37
|
+
END IF;
|
|
38
|
+
IF pg_catalog.jsonb_array_length(p_payload->'endpoints') <> 4 THEN
|
|
39
|
+
RETURN false;
|
|
40
|
+
END IF;
|
|
41
|
+
|
|
42
|
+
FOR endpoint IN
|
|
43
|
+
SELECT value FROM pg_catalog.jsonb_array_elements(p_payload->'endpoints')
|
|
44
|
+
LOOP
|
|
45
|
+
IF pg_catalog.jsonb_typeof(endpoint) IS DISTINCT FROM 'object' THEN
|
|
46
|
+
RETURN false;
|
|
47
|
+
END IF;
|
|
48
|
+
IF NOT (endpoint ? 'serviceId')
|
|
49
|
+
OR NOT (endpoint ? 'origin')
|
|
50
|
+
OR (endpoint - 'serviceId' - 'origin') <> '{}'::jsonb
|
|
51
|
+
OR pg_catalog.jsonb_typeof(endpoint->'serviceId') IS DISTINCT FROM 'string'
|
|
52
|
+
OR pg_catalog.jsonb_typeof(endpoint->'origin') IS DISTINCT FROM 'string' THEN
|
|
53
|
+
RETURN false;
|
|
54
|
+
END IF;
|
|
55
|
+
|
|
56
|
+
endpoint_service_id := endpoint->>'serviceId';
|
|
57
|
+
endpoint_origin := endpoint->>'origin';
|
|
58
|
+
IF pg_catalog.char_length(endpoint_service_id) > 64
|
|
59
|
+
OR (endpoint_service_id COLLATE "C") !~ '^[a-z][a-z0-9]*(-[a-z0-9]+)*$'
|
|
60
|
+
OR endpoint_service_id = ANY(endpoint_service_ids)
|
|
61
|
+
OR (previous_endpoint_service_id IS NOT NULL
|
|
62
|
+
AND (endpoint_service_id COLLATE "C")
|
|
63
|
+
<= (previous_endpoint_service_id COLLATE "C"))
|
|
64
|
+
OR pg_catalog.char_length(endpoint_origin) > 261
|
|
65
|
+
OR (endpoint_origin COLLATE "C") !~ '^https://[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*\.[a-z]{2,63}$'
|
|
66
|
+
OR (endpoint_origin COLLATE "C") ~ '^https://([0-9]{1,3}\.){3}[0-9]{1,3}$'
|
|
67
|
+
OR (endpoint_origin COLLATE "C") ~ '(^https://|\.)xn--'
|
|
68
|
+
OR (endpoint_origin COLLATE "C") ~ '^https://(localhost|local|internal)$'
|
|
69
|
+
OR (endpoint_origin COLLATE "C") ~ '\.(localhost|local|internal)$'
|
|
70
|
+
OR endpoint_origin = ANY(endpoint_origins) THEN
|
|
71
|
+
RETURN false;
|
|
72
|
+
END IF;
|
|
73
|
+
previous_endpoint_service_id := endpoint_service_id;
|
|
74
|
+
endpoint_service_ids := pg_catalog.array_append(endpoint_service_ids, endpoint_service_id);
|
|
75
|
+
endpoint_origins := pg_catalog.array_append(endpoint_origins, endpoint_origin);
|
|
76
|
+
END LOOP;
|
|
77
|
+
RETURN true;
|
|
78
|
+
END IF;
|
|
79
|
+
|
|
80
|
+
IF p_action_kind = 'weekly-code-quality-scan' THEN
|
|
81
|
+
IF NOT (p_payload ? 'projectIds')
|
|
82
|
+
OR (p_payload - 'projectIds') <> '{}'::jsonb
|
|
83
|
+
OR pg_catalog.jsonb_typeof(p_payload->'projectIds') IS DISTINCT FROM 'array' THEN
|
|
84
|
+
RETURN false;
|
|
85
|
+
END IF;
|
|
86
|
+
IF pg_catalog.jsonb_array_length(p_payload->'projectIds') NOT BETWEEN 1 AND 32 THEN
|
|
87
|
+
RETURN false;
|
|
88
|
+
END IF;
|
|
89
|
+
|
|
90
|
+
FOR project_entry IN
|
|
91
|
+
SELECT value FROM pg_catalog.jsonb_array_elements(p_payload->'projectIds')
|
|
92
|
+
LOOP
|
|
93
|
+
IF pg_catalog.jsonb_typeof(project_entry) IS DISTINCT FROM 'string' THEN
|
|
94
|
+
RETURN false;
|
|
95
|
+
END IF;
|
|
96
|
+
project_id := project_entry #>> '{}';
|
|
97
|
+
IF pg_catalog.char_length(project_id) > 255
|
|
98
|
+
OR (project_id COLLATE "C") !~ '^[a-z0-9]([a-z0-9._-]{0,62}[a-z0-9])?(/[a-z0-9]([a-z0-9._-]{0,62}[a-z0-9])?)+$'
|
|
99
|
+
OR pg_catalog.lower(pg_catalog.right(project_id, 4)) = '.git'
|
|
100
|
+
OR pg_catalog.lower(pg_catalog.right(project_id, 5)) = '.atom'
|
|
101
|
+
OR 'land' = ANY(pg_catalog.regexp_split_to_array(project_id, '[/._-]'))
|
|
102
|
+
OR project_id = ANY(project_ids) THEN
|
|
103
|
+
RETURN false;
|
|
104
|
+
END IF;
|
|
105
|
+
IF previous_project_id IS NOT NULL
|
|
106
|
+
AND (project_id COLLATE "C") <= (previous_project_id COLLATE "C") THEN
|
|
107
|
+
RETURN false;
|
|
108
|
+
END IF;
|
|
109
|
+
previous_project_id := project_id;
|
|
110
|
+
project_ids := pg_catalog.array_append(project_ids, project_id);
|
|
111
|
+
END LOOP;
|
|
112
|
+
RETURN true;
|
|
113
|
+
END IF;
|
|
114
|
+
|
|
115
|
+
RETURN false;
|
|
116
|
+
END;
|
|
117
|
+
$$;
|
|
118
|
+
|
|
119
|
+
REVOKE ALL ON FUNCTION semicolony.hive_cron_valid_trusted_config_shape(text, jsonb)
|
|
120
|
+
FROM PUBLIC, sc_app, sc_provider;
|
|
121
|
+
|
|
122
|
+
CREATE TABLE IF NOT EXISTS semicolony.cron_read_action_trusted_config_revisions (
|
|
123
|
+
bot_id TEXT NOT NULL CHECK (bot_id = 'semi'),
|
|
124
|
+
job_id TEXT NOT NULL,
|
|
125
|
+
runtime_source TEXT NOT NULL CHECK (runtime_source = 'hive-cron-v2'),
|
|
126
|
+
action_kind TEXT NOT NULL CHECK (
|
|
127
|
+
btrim(action_kind) = action_kind
|
|
128
|
+
AND char_length(action_kind) BETWEEN 1 AND 128
|
|
129
|
+
AND action_kind !~ '[[:cntrl:]]'
|
|
130
|
+
),
|
|
131
|
+
action_version INTEGER NOT NULL CHECK (action_version > 0),
|
|
132
|
+
action_contract_digest TEXT NOT NULL CHECK (
|
|
133
|
+
action_contract_digest ~ '^[a-f0-9]{64}$'
|
|
134
|
+
),
|
|
135
|
+
config_revision INTEGER NOT NULL CHECK (config_revision > 0),
|
|
136
|
+
source_ref TEXT NOT NULL CHECK (
|
|
137
|
+
(source_ref COLLATE "C") ~ '^kb:[a-z0-9]([a-z0-9._-]{0,126}[a-z0-9])?/[a-z0-9]([a-z0-9._-]{0,126}[a-z0-9])?/[a-z0-9]([a-z0-9._-]{0,126}[a-z0-9])?$'
|
|
138
|
+
),
|
|
139
|
+
config_payload JSONB NOT NULL CHECK (
|
|
140
|
+
jsonb_typeof(config_payload) = 'object'
|
|
141
|
+
AND octet_length(config_payload::text) <= 65536
|
|
142
|
+
),
|
|
143
|
+
config_digest TEXT NOT NULL CHECK (
|
|
144
|
+
config_digest ~ '^sha256:[a-f0-9]{64}$'
|
|
145
|
+
),
|
|
146
|
+
approved_by TEXT NOT NULL CHECK (
|
|
147
|
+
(approved_by COLLATE "C") ~ '^[a-z0-9]([a-z0-9._-]{0,126}[a-z0-9])?$'
|
|
148
|
+
),
|
|
149
|
+
approved_at TIMESTAMPTZ NOT NULL,
|
|
150
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
151
|
+
PRIMARY KEY (bot_id, job_id, runtime_source, config_revision),
|
|
152
|
+
FOREIGN KEY (bot_id, job_id, runtime_source)
|
|
153
|
+
REFERENCES semicolony.cron_capability_templates (bot_id, job_id, runtime_source),
|
|
154
|
+
CHECK (semicolony.hive_cron_valid_trusted_config_shape(action_kind, config_payload))
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
COMMENT ON TABLE semicolony.cron_read_action_trusted_config_revisions IS
|
|
158
|
+
'Reviewed inert configuration revisions for Hive cron typed read actions; contains no credentials.';
|
|
159
|
+
|
|
160
|
+
COMMENT ON COLUMN semicolony.cron_read_action_trusted_config_revisions.action_contract_digest IS
|
|
161
|
+
'Action contract reviewed with this revision; the loader compares it to the mutable current template.';
|
|
162
|
+
|
|
163
|
+
COMMENT ON COLUMN semicolony.cron_read_action_trusted_config_revisions.config_digest IS
|
|
164
|
+
'SHA-256 of the canonical identity, action contract, revision, source reference, and payload envelope.';
|
|
165
|
+
|
|
166
|
+
CREATE OR REPLACE FUNCTION semicolony.hive_cron_get_trusted_config(p_job_id text)
|
|
167
|
+
RETURNS TABLE (
|
|
168
|
+
bot_id text,
|
|
169
|
+
job_id text,
|
|
170
|
+
runtime_source text,
|
|
171
|
+
action_kind text,
|
|
172
|
+
action_version integer,
|
|
173
|
+
action_contract_digest text,
|
|
174
|
+
config_revision integer,
|
|
175
|
+
source_ref text,
|
|
176
|
+
config_payload jsonb,
|
|
177
|
+
config_digest text,
|
|
178
|
+
approved_by text,
|
|
179
|
+
approved_at timestamptz,
|
|
180
|
+
created_at timestamptz,
|
|
181
|
+
current_action_kind text,
|
|
182
|
+
current_action_version integer,
|
|
183
|
+
current_action_contract_digest text
|
|
184
|
+
)
|
|
185
|
+
LANGUAGE sql
|
|
186
|
+
SECURITY DEFINER
|
|
187
|
+
SET search_path = pg_catalog
|
|
188
|
+
AS $$
|
|
189
|
+
SELECT config.bot_id,
|
|
190
|
+
config.job_id,
|
|
191
|
+
config.runtime_source,
|
|
192
|
+
config.action_kind,
|
|
193
|
+
config.action_version,
|
|
194
|
+
config.action_contract_digest,
|
|
195
|
+
config.config_revision,
|
|
196
|
+
config.source_ref,
|
|
197
|
+
config.config_payload,
|
|
198
|
+
config.config_digest,
|
|
199
|
+
config.approved_by,
|
|
200
|
+
config.approved_at,
|
|
201
|
+
config.created_at,
|
|
202
|
+
template.action_kind,
|
|
203
|
+
template.action_version,
|
|
204
|
+
template.action_contract_digest
|
|
205
|
+
FROM semicolony.cron_capability_templates AS template
|
|
206
|
+
JOIN LATERAL (
|
|
207
|
+
SELECT revision.bot_id,
|
|
208
|
+
revision.job_id,
|
|
209
|
+
revision.runtime_source,
|
|
210
|
+
revision.action_kind,
|
|
211
|
+
revision.action_version,
|
|
212
|
+
revision.action_contract_digest,
|
|
213
|
+
revision.config_revision,
|
|
214
|
+
revision.source_ref,
|
|
215
|
+
revision.config_payload,
|
|
216
|
+
revision.config_digest,
|
|
217
|
+
revision.approved_by,
|
|
218
|
+
revision.approved_at,
|
|
219
|
+
revision.created_at
|
|
220
|
+
FROM semicolony.cron_read_action_trusted_config_revisions AS revision
|
|
221
|
+
WHERE revision.bot_id = template.bot_id
|
|
222
|
+
AND revision.job_id = template.job_id
|
|
223
|
+
AND revision.runtime_source = template.runtime_source
|
|
224
|
+
ORDER BY revision.config_revision DESC
|
|
225
|
+
LIMIT 1
|
|
226
|
+
) AS config ON true
|
|
227
|
+
WHERE template.bot_id = 'semi'
|
|
228
|
+
AND template.job_id = p_job_id
|
|
229
|
+
AND template.runtime_source = 'hive-cron-v2'
|
|
230
|
+
AND template.action_kind IS NOT NULL
|
|
231
|
+
AND template.action_version IS NOT NULL
|
|
232
|
+
AND template.action_contract_digest IS NOT NULL;
|
|
233
|
+
$$;
|
|
234
|
+
|
|
235
|
+
REVOKE ALL PRIVILEGES ON TABLE
|
|
236
|
+
semicolony.cron_read_action_trusted_config_revisions
|
|
237
|
+
FROM PUBLIC, sc_app, sc_provider;
|
|
238
|
+
|
|
239
|
+
REVOKE ALL ON FUNCTION semicolony.hive_cron_get_trusted_config(text)
|
|
240
|
+
FROM PUBLIC, sc_app, sc_provider;
|
|
241
|
+
|
|
242
|
+
GRANT EXECUTE ON FUNCTION semicolony.hive_cron_get_trusted_config(text)
|
|
243
|
+
TO sc_provider;
|