@team-semicolon/semicolony-cli 4.18.76 → 4.18.78
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,277 @@
|
|
|
1
|
+
-- 183_worker_agent_gateway_credentials.sql
|
|
2
|
+
--
|
|
3
|
+
-- Bind the fixed Hermes installation to one release-only host credential and
|
|
4
|
+
-- two KB-read-only actor credentials. Plaintext bearer material is never
|
|
5
|
+
-- stored in this schema; callers provide only a SHA-256 hash and short prefix.
|
|
6
|
+
|
|
7
|
+
CREATE TABLE semicolony.worker_agent_actor_bindings (
|
|
8
|
+
installation_id text NOT NULL
|
|
9
|
+
REFERENCES semicolony.worker_devices(device_id) ON DELETE CASCADE,
|
|
10
|
+
actor_id text NOT NULL CHECK (actor_id IN ('semi', 'colony')),
|
|
11
|
+
runtime_profile text NOT NULL,
|
|
12
|
+
profile_id text NOT NULL DEFAULT 'semo-ops-worker-agent',
|
|
13
|
+
runtime_kind text NOT NULL DEFAULT 'hermes-cli',
|
|
14
|
+
gateway_credential_id uuid NOT NULL UNIQUE
|
|
15
|
+
REFERENCES semicolony.gateway_credentials(id),
|
|
16
|
+
status text NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'revoked')),
|
|
17
|
+
issued_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
18
|
+
rotated_at timestamptz,
|
|
19
|
+
updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
20
|
+
PRIMARY KEY (installation_id, actor_id),
|
|
21
|
+
CONSTRAINT worker_agent_actor_fixed_installation_check CHECK (
|
|
22
|
+
installation_id = 'hermes-principals@hermes'
|
|
23
|
+
AND profile_id = 'semo-ops-worker-agent'
|
|
24
|
+
AND runtime_kind = 'hermes-cli'
|
|
25
|
+
),
|
|
26
|
+
CONSTRAINT worker_agent_actor_runtime_profile_check CHECK (
|
|
27
|
+
(actor_id = 'semi' AND runtime_profile = 'semo-semi')
|
|
28
|
+
OR (actor_id = 'colony' AND runtime_profile = 'semo-colony')
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
CREATE INDEX idx_worker_agent_actor_bindings_credential
|
|
33
|
+
ON semicolony.worker_agent_actor_bindings (gateway_credential_id, status);
|
|
34
|
+
|
|
35
|
+
COMMENT ON TABLE semicolony.worker_agent_actor_bindings IS
|
|
36
|
+
'Server-side binding for the fixed SEMO Ops Hermes actors; contains no bearer material.';
|
|
37
|
+
|
|
38
|
+
CREATE OR REPLACE FUNCTION semicolony.issue_worker_agent_host_credential(
|
|
39
|
+
p_team_tenant_id uuid,
|
|
40
|
+
p_token_hash text,
|
|
41
|
+
p_token_prefix text,
|
|
42
|
+
p_issued_by text,
|
|
43
|
+
p_expires_days integer
|
|
44
|
+
)
|
|
45
|
+
RETURNS uuid
|
|
46
|
+
LANGUAGE plpgsql
|
|
47
|
+
SECURITY DEFINER
|
|
48
|
+
SET search_path = pg_catalog
|
|
49
|
+
AS $function$
|
|
50
|
+
DECLARE
|
|
51
|
+
v_credential_id uuid;
|
|
52
|
+
v_previous_credential_id uuid;
|
|
53
|
+
v_worker_id text;
|
|
54
|
+
BEGIN
|
|
55
|
+
IF p_token_hash IS NULL OR p_token_hash !~ '^[0-9a-f]{64}$' THEN
|
|
56
|
+
RAISE EXCEPTION 'invalid worker-agent host credential token hash' USING ERRCODE = '22023';
|
|
57
|
+
END IF;
|
|
58
|
+
IF p_token_prefix IS NULL OR p_token_prefix !~ '^wck_hermes-host_[A-Za-z0-9_-]{6}$' THEN
|
|
59
|
+
RAISE EXCEPTION 'invalid worker-agent host credential token prefix' USING ERRCODE = '22023';
|
|
60
|
+
END IF;
|
|
61
|
+
IF p_issued_by IS NULL OR p_issued_by <> btrim(p_issued_by)
|
|
62
|
+
OR btrim(p_issued_by) = '' OR char_length(p_issued_by) > 128
|
|
63
|
+
OR p_issued_by ~ '[[:cntrl:]]' THEN
|
|
64
|
+
RAISE EXCEPTION 'invalid credential issuer' USING ERRCODE = '22023';
|
|
65
|
+
END IF;
|
|
66
|
+
IF p_expires_days IS NULL OR p_expires_days < 1 OR p_expires_days > 90 THEN
|
|
67
|
+
RAISE EXCEPTION 'worker-agent credential expiry must be between 1 and 90 days'
|
|
68
|
+
USING ERRCODE = '22023';
|
|
69
|
+
END IF;
|
|
70
|
+
|
|
71
|
+
PERFORM t.id
|
|
72
|
+
FROM public.tenants AS t
|
|
73
|
+
WHERE t.id = p_team_tenant_id
|
|
74
|
+
AND t.slug = 'team-semicolon'
|
|
75
|
+
AND t.tenant_type = 'team'
|
|
76
|
+
AND coalesce(t.metadata ->> 'status', 'active') = 'active';
|
|
77
|
+
IF NOT FOUND THEN
|
|
78
|
+
RAISE EXCEPTION 'active team-semicolon tenant not found' USING ERRCODE = 'P0002';
|
|
79
|
+
END IF;
|
|
80
|
+
|
|
81
|
+
SELECT wd.worker_id, wd.gateway_credential_id
|
|
82
|
+
INTO v_worker_id, v_previous_credential_id
|
|
83
|
+
FROM semicolony.worker_devices AS wd
|
|
84
|
+
WHERE wd.device_id = 'hermes-principals@hermes'
|
|
85
|
+
AND wd.installation_kind = 'agent-runtime'
|
|
86
|
+
AND wd.installed_profile_id = 'semo-ops-worker-agent'
|
|
87
|
+
AND wd.kb_access_mode = 'worker-gateway'
|
|
88
|
+
AND wd.status = 'active'
|
|
89
|
+
FOR UPDATE;
|
|
90
|
+
IF NOT FOUND THEN
|
|
91
|
+
RAISE EXCEPTION 'active Worker-agent installation not found' USING ERRCODE = 'P0002';
|
|
92
|
+
END IF;
|
|
93
|
+
|
|
94
|
+
INSERT INTO semicolony.gateway_credentials (
|
|
95
|
+
tenant_id, tenant_slug, token_hash, token_prefix, scopes, issued_by, expires_at, metadata
|
|
96
|
+
) VALUES (
|
|
97
|
+
p_team_tenant_id,
|
|
98
|
+
'team-semicolon',
|
|
99
|
+
p_token_hash,
|
|
100
|
+
p_token_prefix,
|
|
101
|
+
ARRAY['worker:release:read', 'worker:release:report']::text[],
|
|
102
|
+
p_issued_by,
|
|
103
|
+
clock_timestamp() + make_interval(days => p_expires_days),
|
|
104
|
+
jsonb_build_object(
|
|
105
|
+
'credential_kind', 'worker-agent-host',
|
|
106
|
+
'installation_id', 'hermes-principals@hermes',
|
|
107
|
+
'profile_id', 'semo-ops-worker-agent',
|
|
108
|
+
'runtime_kind', 'hermes-cli',
|
|
109
|
+
'tenant_anchor', 'team-semicolon',
|
|
110
|
+
'lineage_status', 'active'
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
RETURNING id INTO v_credential_id;
|
|
114
|
+
|
|
115
|
+
UPDATE semicolony.worker_devices
|
|
116
|
+
SET gateway_credential_id = v_credential_id
|
|
117
|
+
WHERE device_id = 'hermes-principals@hermes'
|
|
118
|
+
AND worker_id = v_worker_id;
|
|
119
|
+
|
|
120
|
+
IF v_previous_credential_id IS NOT NULL AND v_previous_credential_id <> v_credential_id THEN
|
|
121
|
+
UPDATE semicolony.gateway_credentials
|
|
122
|
+
SET status = 'revoked',
|
|
123
|
+
revoked_at = clock_timestamp(),
|
|
124
|
+
revoked_reason = 'worker-agent host credential rotated'
|
|
125
|
+
WHERE id = v_previous_credential_id
|
|
126
|
+
AND status = 'active';
|
|
127
|
+
END IF;
|
|
128
|
+
|
|
129
|
+
RETURN v_credential_id;
|
|
130
|
+
END;
|
|
131
|
+
$function$;
|
|
132
|
+
|
|
133
|
+
CREATE OR REPLACE FUNCTION semicolony.issue_worker_agent_actor_credential(
|
|
134
|
+
p_team_tenant_id uuid,
|
|
135
|
+
p_actor_id text,
|
|
136
|
+
p_token_hash text,
|
|
137
|
+
p_token_prefix text,
|
|
138
|
+
p_issued_by text,
|
|
139
|
+
p_expires_days integer
|
|
140
|
+
)
|
|
141
|
+
RETURNS uuid
|
|
142
|
+
LANGUAGE plpgsql
|
|
143
|
+
SECURITY DEFINER
|
|
144
|
+
SET search_path = pg_catalog
|
|
145
|
+
AS $function$
|
|
146
|
+
DECLARE
|
|
147
|
+
v_credential_id uuid;
|
|
148
|
+
v_previous_credential_id uuid;
|
|
149
|
+
v_runtime_profile text;
|
|
150
|
+
BEGIN
|
|
151
|
+
IF p_actor_id NOT IN ('semi', 'colony') THEN
|
|
152
|
+
RAISE EXCEPTION 'invalid Worker-agent actor' USING ERRCODE = '22023';
|
|
153
|
+
END IF;
|
|
154
|
+
v_runtime_profile := CASE p_actor_id WHEN 'semi' THEN 'semo-semi' ELSE 'semo-colony' END;
|
|
155
|
+
IF p_token_hash IS NULL OR p_token_hash !~ '^[0-9a-f]{64}$' THEN
|
|
156
|
+
RAISE EXCEPTION 'invalid worker-agent actor credential token hash' USING ERRCODE = '22023';
|
|
157
|
+
END IF;
|
|
158
|
+
IF p_token_prefix IS NULL
|
|
159
|
+
OR p_token_prefix !~ ('^wck_' || p_actor_id || '_[A-Za-z0-9_-]{6}$') THEN
|
|
160
|
+
RAISE EXCEPTION 'invalid worker-agent actor credential token prefix' USING ERRCODE = '22023';
|
|
161
|
+
END IF;
|
|
162
|
+
IF p_issued_by IS NULL OR p_issued_by <> btrim(p_issued_by)
|
|
163
|
+
OR btrim(p_issued_by) = '' OR char_length(p_issued_by) > 128
|
|
164
|
+
OR p_issued_by ~ '[[:cntrl:]]' THEN
|
|
165
|
+
RAISE EXCEPTION 'invalid credential issuer' USING ERRCODE = '22023';
|
|
166
|
+
END IF;
|
|
167
|
+
IF p_expires_days IS NULL OR p_expires_days < 1 OR p_expires_days > 90 THEN
|
|
168
|
+
RAISE EXCEPTION 'worker-agent credential expiry must be between 1 and 90 days'
|
|
169
|
+
USING ERRCODE = '22023';
|
|
170
|
+
END IF;
|
|
171
|
+
|
|
172
|
+
PERFORM t.id
|
|
173
|
+
FROM public.tenants AS t
|
|
174
|
+
WHERE t.id = p_team_tenant_id
|
|
175
|
+
AND t.slug = 'team-semicolon'
|
|
176
|
+
AND t.tenant_type = 'team'
|
|
177
|
+
AND coalesce(t.metadata ->> 'status', 'active') = 'active';
|
|
178
|
+
IF NOT FOUND THEN
|
|
179
|
+
RAISE EXCEPTION 'active team-semicolon tenant not found' USING ERRCODE = 'P0002';
|
|
180
|
+
END IF;
|
|
181
|
+
|
|
182
|
+
PERFORM wd.device_id
|
|
183
|
+
FROM semicolony.worker_devices AS wd
|
|
184
|
+
WHERE wd.device_id = 'hermes-principals@hermes'
|
|
185
|
+
AND wd.installation_kind = 'agent-runtime'
|
|
186
|
+
AND wd.installed_profile_id = 'semo-ops-worker-agent'
|
|
187
|
+
AND wd.kb_access_mode = 'worker-gateway'
|
|
188
|
+
AND wd.status = 'active'
|
|
189
|
+
FOR UPDATE;
|
|
190
|
+
IF NOT FOUND THEN
|
|
191
|
+
RAISE EXCEPTION 'active Worker-agent installation not found' USING ERRCODE = 'P0002';
|
|
192
|
+
END IF;
|
|
193
|
+
|
|
194
|
+
SELECT binding.gateway_credential_id
|
|
195
|
+
INTO v_previous_credential_id
|
|
196
|
+
FROM semicolony.worker_agent_actor_bindings AS binding
|
|
197
|
+
WHERE binding.installation_id = 'hermes-principals@hermes'
|
|
198
|
+
AND binding.actor_id = p_actor_id
|
|
199
|
+
FOR UPDATE;
|
|
200
|
+
|
|
201
|
+
INSERT INTO semicolony.gateway_credentials (
|
|
202
|
+
tenant_id, tenant_slug, token_hash, token_prefix, scopes, issued_by, expires_at, metadata
|
|
203
|
+
) VALUES (
|
|
204
|
+
p_team_tenant_id,
|
|
205
|
+
'team-semicolon',
|
|
206
|
+
p_token_hash,
|
|
207
|
+
p_token_prefix,
|
|
208
|
+
ARRAY['kb:read']::text[],
|
|
209
|
+
p_issued_by,
|
|
210
|
+
clock_timestamp() + make_interval(days => p_expires_days),
|
|
211
|
+
jsonb_build_object(
|
|
212
|
+
'credential_kind', 'worker-agent-actor',
|
|
213
|
+
'actor_id', p_actor_id,
|
|
214
|
+
'installation_id', 'hermes-principals@hermes',
|
|
215
|
+
'profile_id', 'semo-ops-worker-agent',
|
|
216
|
+
'runtime_kind', 'hermes-cli',
|
|
217
|
+
'runtime_profile', v_runtime_profile,
|
|
218
|
+
'tenant_anchor', 'team-semicolon',
|
|
219
|
+
'lineage_status', 'active'
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
RETURNING id INTO v_credential_id;
|
|
223
|
+
|
|
224
|
+
INSERT INTO semicolony.worker_agent_actor_bindings (
|
|
225
|
+
installation_id, actor_id, runtime_profile, profile_id, runtime_kind,
|
|
226
|
+
gateway_credential_id, status, issued_at, rotated_at, updated_at
|
|
227
|
+
) VALUES (
|
|
228
|
+
'hermes-principals@hermes', p_actor_id, v_runtime_profile,
|
|
229
|
+
'semo-ops-worker-agent', 'hermes-cli', v_credential_id, 'active',
|
|
230
|
+
clock_timestamp(), CASE WHEN v_previous_credential_id IS NULL THEN NULL ELSE clock_timestamp() END,
|
|
231
|
+
clock_timestamp()
|
|
232
|
+
)
|
|
233
|
+
ON CONFLICT (installation_id, actor_id) DO UPDATE
|
|
234
|
+
SET runtime_profile = EXCLUDED.runtime_profile,
|
|
235
|
+
profile_id = EXCLUDED.profile_id,
|
|
236
|
+
runtime_kind = EXCLUDED.runtime_kind,
|
|
237
|
+
gateway_credential_id = EXCLUDED.gateway_credential_id,
|
|
238
|
+
status = 'active',
|
|
239
|
+
rotated_at = clock_timestamp(),
|
|
240
|
+
updated_at = clock_timestamp();
|
|
241
|
+
|
|
242
|
+
IF v_previous_credential_id IS NOT NULL AND v_previous_credential_id <> v_credential_id THEN
|
|
243
|
+
UPDATE semicolony.gateway_credentials
|
|
244
|
+
SET status = 'revoked',
|
|
245
|
+
revoked_at = clock_timestamp(),
|
|
246
|
+
revoked_reason = 'worker-agent actor credential rotated'
|
|
247
|
+
WHERE id = v_previous_credential_id
|
|
248
|
+
AND status = 'active';
|
|
249
|
+
END IF;
|
|
250
|
+
|
|
251
|
+
RETURN v_credential_id;
|
|
252
|
+
END;
|
|
253
|
+
$function$;
|
|
254
|
+
|
|
255
|
+
REVOKE ALL ON FUNCTION semicolony.issue_worker_agent_host_credential(
|
|
256
|
+
uuid, text, text, text, integer
|
|
257
|
+
) FROM PUBLIC, sc_app, sc_provider;
|
|
258
|
+
GRANT EXECUTE ON FUNCTION semicolony.issue_worker_agent_host_credential(
|
|
259
|
+
uuid, text, text, text, integer
|
|
260
|
+
) TO sc_app;
|
|
261
|
+
|
|
262
|
+
REVOKE ALL ON FUNCTION semicolony.issue_worker_agent_actor_credential(
|
|
263
|
+
uuid, text, text, text, text, integer
|
|
264
|
+
) FROM PUBLIC, sc_app, sc_provider;
|
|
265
|
+
GRANT EXECUTE ON FUNCTION semicolony.issue_worker_agent_actor_credential(
|
|
266
|
+
uuid, text, text, text, text, integer
|
|
267
|
+
) TO sc_app;
|
|
268
|
+
|
|
269
|
+
GRANT SELECT (
|
|
270
|
+
installation_id, actor_id, runtime_profile, profile_id, runtime_kind,
|
|
271
|
+
gateway_credential_id, status
|
|
272
|
+
) ON TABLE semicolony.worker_agent_actor_bindings TO sc_app;
|
|
273
|
+
|
|
274
|
+
GRANT SELECT (
|
|
275
|
+
device_id, worker_id, gateway_credential_id, installation_kind,
|
|
276
|
+
installed_profile_id, status
|
|
277
|
+
) ON TABLE semicolony.worker_devices TO sc_app;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
-- 184_worker_agent_workspace_profile.sql
|
|
2
|
+
--
|
|
3
|
+
-- Seed the DB-authoritative SEMO Ops Worker-agent workspace profile required
|
|
4
|
+
-- before its first immutable release can be staged. This row is desired-state
|
|
5
|
+
-- metadata only; it contains no host or actor credential material.
|
|
6
|
+
|
|
7
|
+
INSERT INTO semicolony.workspace_profiles (
|
|
8
|
+
profile_id,
|
|
9
|
+
version,
|
|
10
|
+
status,
|
|
11
|
+
kb_gateway_url,
|
|
12
|
+
repo_provider,
|
|
13
|
+
repo_remotes,
|
|
14
|
+
default_workspace_root,
|
|
15
|
+
tool_adapters,
|
|
16
|
+
guidance_template_version,
|
|
17
|
+
required_smokes,
|
|
18
|
+
metadata
|
|
19
|
+
)
|
|
20
|
+
VALUES (
|
|
21
|
+
'semo-ops-worker-agent',
|
|
22
|
+
'2026-08-01.3',
|
|
23
|
+
'active',
|
|
24
|
+
'https://semicolony.semi-colon.space/kb-gateway',
|
|
25
|
+
'gitlab',
|
|
26
|
+
'{"semo-ops":"https://gitlab.semi-colon.space/semicolon-devteam/semo-ops.git"}'::jsonb,
|
|
27
|
+
'/home/ubuntu',
|
|
28
|
+
ARRAY['hermes-native-tools'],
|
|
29
|
+
'2026-08-01.3',
|
|
30
|
+
'[
|
|
31
|
+
{"id":"agent:installation-state","label":"Agent installation state"},
|
|
32
|
+
{"id":"agent:release-state","label":"Agent release state"},
|
|
33
|
+
{"id":"agent:gateway-release-auth","label":"Gateway release authentication"},
|
|
34
|
+
{"id":"agent:profile:semi","label":"Semi runtime profile"},
|
|
35
|
+
{"id":"agent:profile:colony","label":"Colony runtime profile"},
|
|
36
|
+
{"id":"agent:context-digest:semi","label":"Semi managed context digest"},
|
|
37
|
+
{"id":"agent:context-digest:colony","label":"Colony managed context digest"},
|
|
38
|
+
{"id":"agent:skill-digests:semi","label":"Semi managed skill digests"},
|
|
39
|
+
{"id":"agent:skill-digests:colony","label":"Colony managed skill digests"},
|
|
40
|
+
{"id":"agent:tools:semi","label":"Semi native tools"},
|
|
41
|
+
{"id":"agent:tools:colony","label":"Colony native tools"},
|
|
42
|
+
{"id":"agent:kb-read:semi","label":"Semi KB read smoke"},
|
|
43
|
+
{"id":"agent:kb-read:colony","label":"Colony KB read smoke"},
|
|
44
|
+
{"id":"agent:no-token-in-profile","label":"No token in managed profile"}
|
|
45
|
+
]'::jsonb,
|
|
46
|
+
'{
|
|
47
|
+
"scope":"service-hive",
|
|
48
|
+
"tenant_anchor":"team-semicolon",
|
|
49
|
+
"owner":"SEMO Ops",
|
|
50
|
+
"worker_kind":"agent",
|
|
51
|
+
"runtime_kind":"hermes-cli",
|
|
52
|
+
"installation_id":"hermes-principals@hermes",
|
|
53
|
+
"actors":[
|
|
54
|
+
{"actor_id":"semi","runtime_profile":"semo-semi"},
|
|
55
|
+
{"actor_id":"colony","runtime_profile":"semo-colony"}
|
|
56
|
+
],
|
|
57
|
+
"lineage_status":"active"
|
|
58
|
+
}'::jsonb
|
|
59
|
+
)
|
|
60
|
+
ON CONFLICT (profile_id) DO UPDATE
|
|
61
|
+
SET version = EXCLUDED.version,
|
|
62
|
+
status = EXCLUDED.status,
|
|
63
|
+
kb_gateway_url = EXCLUDED.kb_gateway_url,
|
|
64
|
+
repo_provider = EXCLUDED.repo_provider,
|
|
65
|
+
repo_remotes = EXCLUDED.repo_remotes,
|
|
66
|
+
default_workspace_root = EXCLUDED.default_workspace_root,
|
|
67
|
+
tool_adapters = EXCLUDED.tool_adapters,
|
|
68
|
+
guidance_template_version = EXCLUDED.guidance_template_version,
|
|
69
|
+
required_smokes = EXCLUDED.required_smokes,
|
|
70
|
+
metadata = semicolony.workspace_profiles.metadata || EXCLUDED.metadata;
|
package/migrations/README.md
CHANGED
|
@@ -21,6 +21,8 @@ SEMICOLONY CLI의 PostgreSQL 마이그레이션 파일들.
|
|
|
21
21
|
| `174_worker_fleet_board_grants.sql` | 플릿 상황판 전용 롤 `sc_fleet_board` + 오퍼레이터 액션 감사 테이블 |
|
|
22
22
|
| `178_feedback_capture_capability.sql` | `sc_app` 일반 DML 없이 KB+액션아이템을 원자 기록하는 `record_feedback` capability |
|
|
23
23
|
| `179_worker_feedback_credential_scope.sql` | 워커 자격증명 `feedback:write` 허용 및 활성 디바이스 바인딩에 범위 백필 |
|
|
24
|
+
| `183_worker_agent_gateway_credentials.sql` | Hermes Agent host release credential과 Semi/Colony actor KB-read credential의 서버 바인딩 및 회전 |
|
|
25
|
+
| `184_worker_agent_workspace_profile.sql` | Hermes Agent immutable release가 참조하는 `semo-ops-worker-agent` DB 정본 프로필 시드 |
|
|
24
26
|
|
|
25
27
|
## 007: Flat Skill Naming
|
|
26
28
|
|