@synapsor/runner 1.0.0 → 1.1.1
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/CHANGELOG.md +37 -1
- package/README.md +45 -3
- package/THREAT_MODEL.md +35 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts +3 -0
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +3935 -863
- package/docs/README.md +16 -3
- package/docs/capability-authoring.md +2 -1
- package/docs/current-scope.md +5 -1
- package/docs/dsl-reference.md +7 -0
- package/docs/http-mcp.md +4 -1
- package/docs/limitations.md +20 -6
- package/docs/migrating-to-synapsor-spec.md +21 -0
- package/docs/oss-vs-cloud.md +1 -1
- package/docs/production.md +50 -8
- package/docs/release-notes.md +19 -1
- package/docs/release-policy.md +21 -0
- package/docs/runner-config-reference.md +101 -3
- package/docs/running-a-runner-fleet.md +349 -0
- package/docs/security-boundary.md +7 -0
- package/examples/runner-fleet/Dockerfile +11 -0
- package/examples/runner-fleet/README.md +52 -0
- package/examples/runner-fleet/docker-compose.yml +76 -0
- package/examples/runner-fleet/mint-dev-token.mjs +19 -0
- package/examples/runner-fleet/seed/mysql.sql +20 -0
- package/examples/runner-fleet/seed/postgres.sql +73 -0
- package/examples/runner-fleet/synapsor.runner.json +105 -0
- package/fixtures/protocol/MANIFEST.json +1 -1
- package/package.json +3 -1
- package/schemas/change-set.v1.schema.json +2 -1
- package/schemas/synapsor.runner.schema.json +115 -7
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"mode": "review",
|
|
4
|
+
"storage": {
|
|
5
|
+
"shared_postgres": {
|
|
6
|
+
"mode": "runtime_store",
|
|
7
|
+
"url_env": "SYNAPSOR_LEDGER_DATABASE_URL",
|
|
8
|
+
"schema": "synapsor_runner",
|
|
9
|
+
"lock_timeout_ms": 5000,
|
|
10
|
+
"max_entries": 5000
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"sources": {
|
|
14
|
+
"fleet_postgres": {
|
|
15
|
+
"engine": "postgres",
|
|
16
|
+
"read_url_env": "FLEET_POSTGRES_READ_URL",
|
|
17
|
+
"write_url_env": "FLEET_POSTGRES_WRITE_URL",
|
|
18
|
+
"statement_timeout_ms": 3000,
|
|
19
|
+
"pool": {
|
|
20
|
+
"max_connections": 2,
|
|
21
|
+
"connection_timeout_ms": 2000,
|
|
22
|
+
"idle_timeout_ms": 30000,
|
|
23
|
+
"queue_timeout_ms": 1000,
|
|
24
|
+
"queue_limit": 8
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"trusted_context": {
|
|
29
|
+
"provider": "http_claims",
|
|
30
|
+
"values": {
|
|
31
|
+
"tenant_id_key": "tenant_id",
|
|
32
|
+
"principal_key": "sub"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"session_auth": {
|
|
36
|
+
"provider": "jwt_hs256",
|
|
37
|
+
"secret_env": "SYNAPSOR_SESSION_JWT_SECRET",
|
|
38
|
+
"issuer": "https://fleet.example.invalid",
|
|
39
|
+
"audience": "synapsor-runner-fleet",
|
|
40
|
+
"tenant_claim": "tenant_id",
|
|
41
|
+
"principal_claim": "sub",
|
|
42
|
+
"clock_skew_seconds": 10
|
|
43
|
+
},
|
|
44
|
+
"rate_limits": {
|
|
45
|
+
"enabled": true,
|
|
46
|
+
"default": { "requests": 20, "window_seconds": 60 },
|
|
47
|
+
"capabilities": {
|
|
48
|
+
"billing.inspect_invoice": { "requests": 3, "window_seconds": 60 }
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"metrics": {
|
|
52
|
+
"enabled": true,
|
|
53
|
+
"token_env": "SYNAPSOR_METRICS_TOKEN"
|
|
54
|
+
},
|
|
55
|
+
"capabilities": [
|
|
56
|
+
{
|
|
57
|
+
"name": "billing.inspect_invoice",
|
|
58
|
+
"kind": "read",
|
|
59
|
+
"source": "fleet_postgres",
|
|
60
|
+
"target": {
|
|
61
|
+
"schema": "public",
|
|
62
|
+
"table": "invoices",
|
|
63
|
+
"primary_key": "id",
|
|
64
|
+
"tenant_key": "tenant_id"
|
|
65
|
+
},
|
|
66
|
+
"args": {
|
|
67
|
+
"invoice_id": { "type": "string", "required": true, "max_length": 128 }
|
|
68
|
+
},
|
|
69
|
+
"lookup": { "id_from_arg": "invoice_id" },
|
|
70
|
+
"visible_columns": ["id", "tenant_id", "status", "late_fee_cents", "waiver_reason", "updated_at"],
|
|
71
|
+
"evidence": "required",
|
|
72
|
+
"max_rows": 1
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "billing.propose_late_fee_waiver",
|
|
76
|
+
"kind": "proposal",
|
|
77
|
+
"source": "fleet_postgres",
|
|
78
|
+
"target": {
|
|
79
|
+
"schema": "public",
|
|
80
|
+
"table": "invoices",
|
|
81
|
+
"primary_key": "id",
|
|
82
|
+
"tenant_key": "tenant_id"
|
|
83
|
+
},
|
|
84
|
+
"args": {
|
|
85
|
+
"invoice_id": { "type": "string", "required": true, "max_length": 128 },
|
|
86
|
+
"reason": { "type": "string", "required": true, "max_length": 500 }
|
|
87
|
+
},
|
|
88
|
+
"lookup": { "id_from_arg": "invoice_id" },
|
|
89
|
+
"visible_columns": ["id", "tenant_id", "status", "late_fee_cents", "waiver_reason", "updated_at"],
|
|
90
|
+
"evidence": "required",
|
|
91
|
+
"max_rows": 1,
|
|
92
|
+
"patch": {
|
|
93
|
+
"late_fee_cents": { "fixed": 0 },
|
|
94
|
+
"waiver_reason": { "from_arg": "reason" }
|
|
95
|
+
},
|
|
96
|
+
"allowed_columns": ["late_fee_cents", "waiver_reason"],
|
|
97
|
+
"conflict_guard": { "column": "updated_at" },
|
|
98
|
+
"approval": {
|
|
99
|
+
"mode": "human",
|
|
100
|
+
"required_role": "billing_lead",
|
|
101
|
+
"required_approvals": 2
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synapsor/runner",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Stop giving AI agents execute_sql; expose reviewed Postgres/MySQL MCP actions with proposals, approval, writeback, and replay.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"examples/openai-agents-stdio/**",
|
|
26
26
|
"examples/raw-sql-vs-synapsor/**",
|
|
27
27
|
"examples/reference-support-billing-app/**",
|
|
28
|
+
"examples/runner-fleet/**",
|
|
28
29
|
"examples/support-plan-credit/**",
|
|
29
30
|
"examples/support-billing-agent/**",
|
|
30
31
|
"fixtures/**",
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
},
|
|
59
60
|
"dependencies": {
|
|
60
61
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
62
|
+
"jose": "6.2.3",
|
|
61
63
|
"mysql2": "^3.11.0",
|
|
62
64
|
"pg": "^8.13.0",
|
|
63
65
|
"zod": "^3.25.0"
|
|
@@ -95,7 +95,8 @@
|
|
|
95
95
|
"required": ["status"],
|
|
96
96
|
"properties": {
|
|
97
97
|
"status": { "enum": ["pending", "approved", "rejected", "canceled"] },
|
|
98
|
-
"required_role": { "type": "string" }
|
|
98
|
+
"required_role": { "type": "string" },
|
|
99
|
+
"required_approvals": { "type": "integer", "minimum": 1, "maximum": 10 }
|
|
99
100
|
}
|
|
100
101
|
},
|
|
101
102
|
"writeback": {
|
|
@@ -85,6 +85,13 @@
|
|
|
85
85
|
"type": "integer",
|
|
86
86
|
"minimum": 0,
|
|
87
87
|
"default": 10000
|
|
88
|
+
},
|
|
89
|
+
"max_entries": {
|
|
90
|
+
"description": "Safety bound for the bounded runtime-store bridge. Operations fail closed rather than copying an unbounded ledger.",
|
|
91
|
+
"type": "integer",
|
|
92
|
+
"minimum": 100,
|
|
93
|
+
"maximum": 100000,
|
|
94
|
+
"default": 10000
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
97
|
}
|
|
@@ -146,8 +153,31 @@
|
|
|
146
153
|
"disable_auto_approval": { "type": "boolean" }
|
|
147
154
|
}
|
|
148
155
|
},
|
|
156
|
+
"rate_limits": {
|
|
157
|
+
"description": "Operational fixed-window request limits keyed from verified tenant context and reviewed capability. These are deployment controls, not portable contract policy.",
|
|
158
|
+
"type": "object",
|
|
159
|
+
"additionalProperties": false,
|
|
160
|
+
"properties": {
|
|
161
|
+
"enabled": { "type": "boolean", "default": true },
|
|
162
|
+
"default": { "$ref": "#/$defs/rate_limit_rule" },
|
|
163
|
+
"capabilities": {
|
|
164
|
+
"type": "object",
|
|
165
|
+
"propertyNames": { "$ref": "#/$defs/qualified_name" },
|
|
166
|
+
"additionalProperties": { "$ref": "#/$defs/rate_limit_rule" }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"metrics": {
|
|
171
|
+
"description": "Scrapeable HTTP metrics. Disabled by default; non-loopback exposure requires a separate bearer token.",
|
|
172
|
+
"type": "object",
|
|
173
|
+
"additionalProperties": false,
|
|
174
|
+
"properties": {
|
|
175
|
+
"enabled": { "type": "boolean" },
|
|
176
|
+
"token_env": { "$ref": "#/$defs/env_name" }
|
|
177
|
+
}
|
|
178
|
+
},
|
|
149
179
|
"operator_identity": {
|
|
150
|
-
"description": "Operator identity used by approve, reject, and apply. signed_key verifies
|
|
180
|
+
"description": "Operator identity used by approve, reject, and apply. signed_key verifies a registered key; jwt_oidc verifies asymmetric JWT claims and Runner-attests the decision; dev_env is local-development compatibility only.",
|
|
151
181
|
"type": "object",
|
|
152
182
|
"additionalProperties": false,
|
|
153
183
|
"required": ["provider"],
|
|
@@ -155,10 +185,21 @@
|
|
|
155
185
|
{
|
|
156
186
|
"if": { "properties": { "provider": { "const": "signed_key" } }, "required": ["provider"] },
|
|
157
187
|
"then": { "required": ["operators"] }
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"if": { "properties": { "provider": { "const": "jwt_oidc" } }, "required": ["provider"] },
|
|
191
|
+
"then": {
|
|
192
|
+
"required": ["algorithms"],
|
|
193
|
+
"oneOf": [
|
|
194
|
+
{ "required": ["jwks_url_env"] },
|
|
195
|
+
{ "required": ["public_key_env"] },
|
|
196
|
+
{ "required": ["public_key_path"] }
|
|
197
|
+
]
|
|
198
|
+
}
|
|
158
199
|
}
|
|
159
200
|
],
|
|
160
201
|
"properties": {
|
|
161
|
-
"provider": { "enum": ["dev_env", "signed_key"] },
|
|
202
|
+
"provider": { "enum": ["dev_env", "signed_key", "jwt_oidc"] },
|
|
162
203
|
"actor_env": { "$ref": "#/$defs/env_name" },
|
|
163
204
|
"roles_env": { "$ref": "#/$defs/env_name" },
|
|
164
205
|
"apply_roles": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/identifier" } },
|
|
@@ -174,23 +215,65 @@
|
|
|
174
215
|
"roles": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/identifier" } }
|
|
175
216
|
}
|
|
176
217
|
}
|
|
177
|
-
}
|
|
218
|
+
},
|
|
219
|
+
"token_env": { "$ref": "#/$defs/env_name" },
|
|
220
|
+
"token_file_env": { "$ref": "#/$defs/env_name" },
|
|
221
|
+
"token_stdin": { "type": "boolean" },
|
|
222
|
+
"roles_claim": { "$ref": "#/$defs/identifier" },
|
|
223
|
+
"subject_claim": { "$ref": "#/$defs/identifier" },
|
|
224
|
+
"attestation_secret_env": { "$ref": "#/$defs/env_name" },
|
|
225
|
+
"algorithms": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": ["RS256", "ES256"] } },
|
|
226
|
+
"jwks_url_env": { "$ref": "#/$defs/env_name" },
|
|
227
|
+
"public_key_env": { "$ref": "#/$defs/env_name" },
|
|
228
|
+
"public_key_path": { "type": "string", "minLength": 1 },
|
|
229
|
+
"issuer": { "type": "string", "minLength": 1 },
|
|
230
|
+
"audience": { "type": "string", "minLength": 1 },
|
|
231
|
+
"clock_skew_seconds": { "type": "integer", "minimum": 0, "maximum": 300 },
|
|
232
|
+
"jwks_cache_seconds": { "type": "integer", "minimum": 1, "maximum": 86400 },
|
|
233
|
+
"jwks_cooldown_seconds": { "type": "integer", "minimum": 1, "maximum": 3600 },
|
|
234
|
+
"fetch_timeout_ms": { "type": "integer", "minimum": 100, "maximum": 30000 },
|
|
235
|
+
"max_response_bytes": { "type": "integer", "minimum": 1024, "maximum": 10485760 }
|
|
178
236
|
}
|
|
179
237
|
},
|
|
180
238
|
"session_auth": {
|
|
181
|
-
"description": "Signed per-session identity for Streamable HTTP http_claims contexts.
|
|
239
|
+
"description": "Signed per-session identity for Streamable HTTP http_claims contexts. HS256 is retained for development; asymmetric verification uses only JWKS or public PEM material.",
|
|
182
240
|
"type": "object",
|
|
183
241
|
"additionalProperties": false,
|
|
184
|
-
"required": ["provider"
|
|
242
|
+
"required": ["provider"],
|
|
243
|
+
"allOf": [
|
|
244
|
+
{
|
|
245
|
+
"if": { "properties": { "provider": { "const": "jwt_hs256" } }, "required": ["provider"] },
|
|
246
|
+
"then": { "required": ["secret_env"] }
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
"if": { "properties": { "provider": { "const": "jwt_asymmetric" } }, "required": ["provider"] },
|
|
250
|
+
"then": {
|
|
251
|
+
"required": ["algorithms"],
|
|
252
|
+
"oneOf": [
|
|
253
|
+
{ "required": ["jwks_url_env"] },
|
|
254
|
+
{ "required": ["public_key_env"] },
|
|
255
|
+
{ "required": ["public_key_path"] }
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
],
|
|
185
260
|
"properties": {
|
|
186
|
-
"provider": { "
|
|
261
|
+
"provider": { "enum": ["jwt_hs256", "jwt_asymmetric"] },
|
|
187
262
|
"secret_env": { "$ref": "#/$defs/env_name" },
|
|
188
263
|
"previous_secret_env": { "$ref": "#/$defs/env_name" },
|
|
264
|
+
"algorithms": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": ["HS256", "RS256", "ES256"] } },
|
|
265
|
+
"jwks_url_env": { "$ref": "#/$defs/env_name" },
|
|
266
|
+
"public_key_env": { "$ref": "#/$defs/env_name" },
|
|
267
|
+
"public_key_path": { "type": "string", "minLength": 1 },
|
|
189
268
|
"issuer": { "type": "string", "minLength": 1 },
|
|
190
269
|
"audience": { "type": "string", "minLength": 1 },
|
|
191
270
|
"tenant_claim": { "$ref": "#/$defs/identifier" },
|
|
192
271
|
"principal_claim": { "$ref": "#/$defs/identifier" },
|
|
193
|
-
"clock_skew_seconds": { "type": "integer", "minimum": 0, "maximum": 300 }
|
|
272
|
+
"clock_skew_seconds": { "type": "integer", "minimum": 0, "maximum": 300 },
|
|
273
|
+
"jwks_cache_seconds": { "type": "integer", "minimum": 1, "maximum": 86400 },
|
|
274
|
+
"jwks_cooldown_seconds": { "type": "integer", "minimum": 1, "maximum": 3600 },
|
|
275
|
+
"fetch_timeout_ms": { "type": "integer", "minimum": 100, "maximum": 30000 },
|
|
276
|
+
"max_response_bytes": { "type": "integer", "minimum": 1024, "maximum": 10485760 }
|
|
194
277
|
}
|
|
195
278
|
},
|
|
196
279
|
"cloud": {
|
|
@@ -212,6 +295,15 @@
|
|
|
212
295
|
}
|
|
213
296
|
},
|
|
214
297
|
"$defs": {
|
|
298
|
+
"rate_limit_rule": {
|
|
299
|
+
"type": "object",
|
|
300
|
+
"additionalProperties": false,
|
|
301
|
+
"required": ["requests", "window_seconds"],
|
|
302
|
+
"properties": {
|
|
303
|
+
"requests": { "type": "integer", "minimum": 1, "maximum": 1000000 },
|
|
304
|
+
"window_seconds": { "type": "integer", "minimum": 1, "maximum": 86400 }
|
|
305
|
+
}
|
|
306
|
+
},
|
|
215
307
|
"env_name": {
|
|
216
308
|
"type": "string",
|
|
217
309
|
"pattern": "^[A-Z_][A-Z0-9_]*$"
|
|
@@ -252,6 +344,17 @@
|
|
|
252
344
|
"type": "integer",
|
|
253
345
|
"minimum": 1
|
|
254
346
|
},
|
|
347
|
+
"pool": {
|
|
348
|
+
"type": "object",
|
|
349
|
+
"additionalProperties": false,
|
|
350
|
+
"properties": {
|
|
351
|
+
"max_connections": { "type": "integer", "minimum": 1, "maximum": 1000 },
|
|
352
|
+
"connection_timeout_ms": { "type": "integer", "minimum": 100, "maximum": 300000 },
|
|
353
|
+
"idle_timeout_ms": { "type": "integer", "minimum": 100, "maximum": 3600000 },
|
|
354
|
+
"queue_timeout_ms": { "type": "integer", "minimum": 100, "maximum": 300000 },
|
|
355
|
+
"queue_limit": { "type": "integer", "minimum": 0, "maximum": 100000 }
|
|
356
|
+
}
|
|
357
|
+
},
|
|
255
358
|
"ssl": {
|
|
256
359
|
"type": "object",
|
|
257
360
|
"additionalProperties": true
|
|
@@ -442,6 +545,11 @@
|
|
|
442
545
|
"required_role": {
|
|
443
546
|
"type": "string"
|
|
444
547
|
},
|
|
548
|
+
"required_approvals": {
|
|
549
|
+
"type": "integer",
|
|
550
|
+
"minimum": 1,
|
|
551
|
+
"maximum": 10
|
|
552
|
+
},
|
|
445
553
|
"policy": {
|
|
446
554
|
"type": "string",
|
|
447
555
|
"minLength": 1
|