@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;
@@ -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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-semicolon/semicolony-cli",
3
- "version": "4.18.76",
3
+ "version": "4.18.78",
4
4
  "description": "SemiColony CLI - AI operations and agent orchestration installer",
5
5
  "main": "dist/bundle.js",
6
6
  "bin": {