@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.
@@ -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
+ }
@@ -33,7 +33,7 @@
33
33
  {
34
34
  "kind": "schema",
35
35
  "name": "change-set.v1.schema.json",
36
- "sha256": "4e52b369b0d3bea30b0ed7b61ec239fc67de3dc691ed4014d6d5eabc7d2be4de"
36
+ "sha256": "119ac84f7189e9433d4eaac4defb6ef7c459a14e55e1563aa7948b746d816af5"
37
37
  },
38
38
  {
39
39
  "kind": "schema",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapsor/runner",
3
- "version": "1.0.0",
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 possession of a registered private key; dev_env is local-development compatibility only.",
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. The HMAC secret stays in an environment variable.",
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", "secret_env"],
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": { "const": "jwt_hs256" },
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