@synapsor/runner 1.5.0 → 1.5.4
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 +134 -3
- package/README.md +108 -113
- package/dist/authoring.d.ts +23 -0
- package/dist/authoring.d.ts.map +1 -0
- package/dist/authoring.mjs +1318 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -5
- package/dist/local-ui.d.ts +14 -0
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +12334 -5256
- package/dist/runtime.mjs +817 -149
- package/dist/shadow.d.ts +36 -0
- package/dist/shadow.d.ts.map +1 -0
- package/dist/shadow.mjs +5362 -0
- package/docs/README.md +25 -2
- package/docs/alternatives.md +122 -0
- package/docs/capability-authoring.md +49 -1
- package/docs/client-recipes.md +218 -0
- package/docs/cloud-mode.md +18 -0
- package/docs/contract-testing.md +9 -7
- package/docs/cursor-plugin.md +78 -0
- package/docs/database-enforced-scope.md +8 -0
- package/docs/dsl-reference.md +45 -4
- package/docs/effect-regression.md +39 -2
- package/docs/fresh-developer-usability.md +110 -0
- package/docs/getting-started-own-database.md +102 -5
- package/docs/guarded-crud-writeback.md +10 -1
- package/docs/host-compatibility.md +59 -0
- package/docs/http-mcp.md +222 -207
- package/docs/limitations.md +9 -2
- package/docs/local-mode.md +11 -7
- package/docs/mcp-audit.md +166 -2
- package/docs/mcp-client-setup.md +28 -11
- package/docs/mcp-clients.md +43 -8
- package/docs/openai-agents-sdk.md +16 -2
- package/docs/oss-vs-cloud.md +3 -0
- package/docs/production.md +72 -7
- package/docs/release-notes.md +131 -4
- package/docs/runner-bundles.md +7 -2
- package/docs/runner-config-reference.md +96 -6
- package/docs/running-a-runner-fleet.md +42 -13
- package/docs/security-boundary.md +58 -8
- package/docs/shadow-studies.md +47 -4
- package/docs/store-lifecycle.md +93 -5
- package/docs/troubleshooting-first-run.md +46 -0
- package/examples/openai-agents-http/README.md +10 -4
- package/examples/openai-agents-http/agent.py +2 -2
- package/examples/runner-fleet/Dockerfile +7 -2
- package/examples/runner-fleet/README.md +11 -7
- package/examples/runner-fleet/docker-compose.yml +4 -4
- package/examples/runner-fleet/mint-dev-token.mjs +1 -1
- package/examples/runner-fleet/start-tls-runner.sh +21 -0
- package/examples/runner-fleet/synapsor.runner.json +27 -1
- package/examples/support-billing-agent/README.md +18 -0
- package/examples/support-billing-agent/app/README.md +6 -0
- package/examples/support-billing-agent/app/contract.ts +28 -0
- package/examples/support-billing-agent/app/effect-adapter.mjs +23 -0
- package/examples/support-billing-agent/app/record-shadow-outcomes.mjs +44 -0
- package/examples/support-billing-agent/scripts/run-evaluation.sh +6 -5
- package/examples/support-plan-credit/README.md +54 -3
- package/examples/support-plan-credit/mcp-client-examples/README.md +23 -0
- package/examples/support-plan-credit/mcp-client-examples/claude-code.sh +34 -0
- package/examples/support-plan-credit/mcp-client-examples/codex.config.toml +24 -0
- package/examples/support-plan-credit/mcp-client-examples/generic-stdio.mjs +35 -0
- package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.json +4 -1
- package/examples/support-plan-credit/mcp-client-examples/generic-streamable-http.mjs +31 -0
- package/examples/support-plan-credit/mcp-client-examples/google-adk.py +40 -0
- package/examples/support-plan-credit/mcp-client-examples/langchain.mjs +29 -0
- package/examples/support-plan-credit/mcp-client-examples/llamaindex.py +36 -0
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-stdio.ts +1 -1
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-streamable-http.ts +5 -1
- package/examples/support-plan-credit/mcp-client-examples/vscode.mcp.json +20 -0
- package/examples/support-plan-credit/synapsor/actions/support.propose_plan_credit.contract-tests.generated.json +221 -0
- package/examples/support-plan-credit/synapsor/actions/support.propose_plan_credit.ts +34 -0
- package/examples/support-plan-credit/synapsor.contract.json +0 -3
- package/fixtures/mcp-audit/README.md +14 -0
- package/fixtures/mcp-audit/cursor-bypass-config.json +38 -0
- package/fixtures/mcp-audit/dangerous-tools-list.json +33 -0
- package/fixtures/mcp-audit/reviewed-proposal-tools-list.json +60 -0
- package/package.json +18 -3
- package/schemas/mcp-audit-report.schema.json +100 -1
- package/schemas/synapsor.contract-tests.schema.json +1 -1
- package/schemas/synapsor.runner.schema.json +80 -0
package/docs/release-notes.md
CHANGED
|
@@ -10,7 +10,134 @@ npx -y -p @synapsor/runner synapsor-runner demo --quick
|
|
|
10
10
|
The OSS runner command is `synapsor-runner`. The `synapsor` command is reserved
|
|
11
11
|
for the Synapsor Cloud CLI.
|
|
12
12
|
|
|
13
|
-
## 1.5.
|
|
13
|
+
## 1.5.4 (prepared, not published)
|
|
14
|
+
|
|
15
|
+
### Networked MCP authentication hardening
|
|
16
|
+
|
|
17
|
+
- Local stdio still opens no network listener and needs no HTTP credential.
|
|
18
|
+
Loopback HTTP remains authenticated by default with an operator-provisioned
|
|
19
|
+
opaque token.
|
|
20
|
+
- Remote HTTP now refuses to bind over an undeclared cleartext channel. Operators
|
|
21
|
+
must use Runner-owned TLS, explicitly declare a trusted TLS proxy, or select an
|
|
22
|
+
authenticated and prominently diagnosed break-glass posture.
|
|
23
|
+
- Opaque endpoint tokens are constrained to local or explicit single-tenant use.
|
|
24
|
+
Remote use requires adequate entropy; one active and one previous env-provided
|
|
25
|
+
value support bounded rotation without logging either value.
|
|
26
|
+
- Shared deployments require signed per-session identity and `http_claims`
|
|
27
|
+
trusted context. Runner revalidates issuer, audience/resource, time, scope,
|
|
28
|
+
tenant, principal, signature, and algorithm on every request and rejects token
|
|
29
|
+
or identity swaps inside an MCP session.
|
|
30
|
+
- RFC 9728 protected-resource metadata and Bearer challenges let compatible MCP
|
|
31
|
+
clients discover the configured external authorization server. Runner verifies
|
|
32
|
+
access tokens but does not implement user login or token issuance.
|
|
33
|
+
- TLS/mTLS preflight, public-only bounded JWKS handling, exact Origin/Host checks,
|
|
34
|
+
request/session bounds, doctor diagnostics, client recipes, and fleet examples
|
|
35
|
+
now share one documented deployment ladder.
|
|
36
|
+
- `lifecycle`, `lifecycle show`, and `lifecycle show latest` now inspect the
|
|
37
|
+
newest complete proposal lifecycle without an id. Filters and known
|
|
38
|
+
proposal/evidence/replay/job/intent/receipt/audit handles resolve a stable,
|
|
39
|
+
read-only `synapsor.lifecycle-view.v1` domain document across local SQLite
|
|
40
|
+
and shared PostgreSQL runtime stores.
|
|
41
|
+
- DSL UPDATE authoring now requires an exact `CONFLICT GUARD <column>` instead
|
|
42
|
+
of silently choosing projection hashing. A reviewer-visible weak compatibility
|
|
43
|
+
clause remains only for ordinary single-row source-DB UPDATE and is rejected
|
|
44
|
+
for the stronger operation modes.
|
|
45
|
+
- Runner rejects canonical `FROM SESSION` with
|
|
46
|
+
`SESSION_BINDING_UNSUPPORTED` rather than treating its key as a process
|
|
47
|
+
environment variable. Explicit ENVIRONMENT, verified HTTP_CLAIM, verified
|
|
48
|
+
CLOUD_SESSION, and STATIC_DEV behavior remains distinct.
|
|
49
|
+
|
|
50
|
+
Prepared package versions: `@synapsor/runner@1.5.4` and
|
|
51
|
+
`@synapsor/dsl@1.4.4`. `@synapsor/spec@1.4.2` and the Cloud CLI are
|
|
52
|
+
unchanged. Nothing has been published by this repository change.
|
|
53
|
+
|
|
54
|
+
## 1.5.3 (published 2026-07-21)
|
|
55
|
+
|
|
56
|
+
### Intent to Safe Action
|
|
57
|
+
|
|
58
|
+
- `start --action <name> --description <intent>` creates one inert TypeScript
|
|
59
|
+
Safe Action scaffold from an existing reviewed read boundary. Project-scoped
|
|
60
|
+
instructions let a coding agent complete and validate only the draft.
|
|
61
|
+
- `action validate` statically parses the restricted object and emits a
|
|
62
|
+
digest-addressed disabled canonical draft, explanation, and deterministic
|
|
63
|
+
allow/deny/effect tests. It does not import adopter code, activate the action,
|
|
64
|
+
or alter the active MCP tool catalog.
|
|
65
|
+
- The secured Workbench runs one real source-unchanged staging Data PR before
|
|
66
|
+
activation and requires `ACTIVATE` plus the complete digest. Cloud-linked
|
|
67
|
+
projects use governed Cloud activation. Existing proposals remain bound to
|
|
68
|
+
the exact active contract digest they were created under.
|
|
69
|
+
- The package includes a current-format Cursor plugin with
|
|
70
|
+
`/synapsor-protect`, diagnostics, deterministic package verification, and
|
|
71
|
+
project-safe MCP wiring. Cursor host claims remain evidence-labeled; a stable
|
|
72
|
+
UI pass and Marketplace submission are owner gates.
|
|
73
|
+
- MCP audit now renders a model-authority map and opt-in bypass evidence as
|
|
74
|
+
text, JSON, Markdown, or SARIF. A checked-in GitHub Actions workflow and Safe
|
|
75
|
+
Action team CI are deterministic and non-mutating.
|
|
76
|
+
- Proposal-only integration recipes cover Claude Code, Codex, VS Code, OpenAI
|
|
77
|
+
Agents, LangChain/LangGraph, Google ADK, LlamaIndex, and generic MCP clients.
|
|
78
|
+
- The first two README screens, public website, article, discovery routes, and
|
|
79
|
+
36-second evidence-backed demo now lead with the own-project Data PR path.
|
|
80
|
+
|
|
81
|
+
Published package version: `@synapsor/runner@1.5.3`. Spec, DSL, and Cloud CLI
|
|
82
|
+
packages were unchanged.
|
|
83
|
+
|
|
84
|
+
## 1.5.2 (prepared, not published)
|
|
85
|
+
|
|
86
|
+
### First safe action in an existing application
|
|
87
|
+
|
|
88
|
+
- `start --from-env DATABASE_URL` and
|
|
89
|
+
`try --prove --from-env DATABASE_URL` now converge on one own-data
|
|
90
|
+
onboarding path. It inspects a staging database read-only, asks the developer
|
|
91
|
+
to choose trusted scope and one reviewed action, emits canonical files, and
|
|
92
|
+
never substitutes synthetic data after an own-data failure.
|
|
93
|
+
- The localhost workbench presents Project, Data source, Trust scope, Action,
|
|
94
|
+
Agent, Test, and Review plus an exact proposal Data PR. Test is complete only
|
|
95
|
+
after a scoped tool call records query audit, not after config validation.
|
|
96
|
+
- Project-scoped Cursor install/status/uninstall previews and owns only its MCP
|
|
97
|
+
entry, preserves other entries, and launches the exact Runner version.
|
|
98
|
+
Approval, apply, revert, credentials, and trusted identity stay outside MCP.
|
|
99
|
+
- Local activation reports measure proof, onboarding, Cursor, first read, and
|
|
100
|
+
first proposal without telemetry or business identifiers. Product time
|
|
101
|
+
excludes initial package download; cold `npx` time is reported separately
|
|
102
|
+
as an observed environment-specific measurement.
|
|
103
|
+
- Optional TypeScript authoring emits the same canonical Spec contract. Shadow
|
|
104
|
+
trust progression and provider-neutral effect regression remain
|
|
105
|
+
non-activating and preserve deterministic/external-model provenance.
|
|
106
|
+
- MCP audit candidates can open directly in the secured workbench, and the
|
|
107
|
+
release includes the host-compatibility matrix and support/billing reference
|
|
108
|
+
workflow.
|
|
109
|
+
- The package now requires Node 22.13.0 or newer, the first Node 22 release
|
|
110
|
+
where Runner's `node:sqlite` dependency is available without an experimental
|
|
111
|
+
runtime flag. Older Node versions fail immediately with an actionable error.
|
|
112
|
+
|
|
113
|
+
Prepared package version: `@synapsor/runner@1.5.2`. Spec, DSL, and Cloud CLI
|
|
114
|
+
packages are unchanged. Nothing has been published by this repository change.
|
|
115
|
+
|
|
116
|
+
## 1.5.1 (prepared, not published)
|
|
117
|
+
|
|
118
|
+
### Safe disposable state ownership
|
|
119
|
+
|
|
120
|
+
- `try --state-dir` no longer treats the supplied directory as disposable.
|
|
121
|
+
The supplied path is a caller-owned container and Runner uses a marked
|
|
122
|
+
managed child beneath it.
|
|
123
|
+
- Cleanup removes only known direct try-state files. Unrelated files remain in
|
|
124
|
+
place, and roots, home/cwd/repository paths, traversal, symlink escapes,
|
|
125
|
+
unmarked lookalikes, and linked managed files fail closed.
|
|
126
|
+
- An atomic state lease prevents concurrent runs from corrupting each other and
|
|
127
|
+
permits recovery from a valid lease whose process is no longer alive.
|
|
128
|
+
- `demo inspect --state-dir` resolves the same managed child. The default
|
|
129
|
+
`.synapsor/try` path safely adopts only the recognized legacy file layout.
|
|
130
|
+
- Explicit `--force` replacement of generated schema and MCP-audit candidate
|
|
131
|
+
directories now rejects protected paths, symlinked ancestors, and linked or
|
|
132
|
+
invalid ownership markers.
|
|
133
|
+
- The embedded `try` data source is consistently identified as synthetic.
|
|
134
|
+
- The packaged YAML parser is updated to `2.8.3` to include the upstream fix
|
|
135
|
+
for deeply nested collection denial of service.
|
|
136
|
+
|
|
137
|
+
Prepared package version: `@synapsor/runner@1.5.1`. Spec, DSL, and Cloud CLI
|
|
138
|
+
packages are unchanged. Nothing has been published by this repository change.
|
|
139
|
+
|
|
140
|
+
## 1.5.0 (published 2026-07-20)
|
|
14
141
|
|
|
15
142
|
### Complete guarded-action developer proof
|
|
16
143
|
|
|
@@ -45,8 +172,8 @@ for the Synapsor Cloud CLI.
|
|
|
45
172
|
immediately second, and distinguishes application scope, PostgreSQL RLS, and
|
|
46
173
|
tenant-bound isolation without overstating any of them.
|
|
47
174
|
|
|
48
|
-
|
|
49
|
-
packages
|
|
175
|
+
Published package version: `@synapsor/runner@1.5.0`. Spec, DSL, and Cloud CLI
|
|
176
|
+
packages were unchanged.
|
|
50
177
|
|
|
51
178
|
## 1.4.123 (2026-07-17)
|
|
52
179
|
|
|
@@ -744,7 +871,7 @@ not change and must not be republished for this release.
|
|
|
744
871
|
CDC, managed runner fleets, compliance exports, production SLA, or C++ DBMS
|
|
745
872
|
internals.
|
|
746
873
|
- The local store is single-node SQLite for local/dev/staging usage.
|
|
747
|
-
- Node >= 22.
|
|
874
|
+
- Node >= 22.13.0 is required because the local ledger uses Node's unflagged
|
|
748
875
|
`node:sqlite` runtime. Use a supported Node runtime or the Docker-backed
|
|
749
876
|
source demo path.
|
|
750
877
|
|
package/docs/runner-bundles.md
CHANGED
|
@@ -67,8 +67,13 @@ npx -y -p @synapsor/runner synapsor-runner cloud sync latest \
|
|
|
67
67
|
|
|
68
68
|
For the OpenAI Agents SDK, use the included TypeScript examples. Their stdio
|
|
69
69
|
command enables `--alias-mode openai`; the Streamable HTTP example includes the
|
|
70
|
-
matching server command
|
|
71
|
-
|
|
70
|
+
matching server command and reads its Bearer credential from
|
|
71
|
+
`SYNAPSOR_RUNNER_HTTP_TOKEN`. The generic HTTP template uses the same environment
|
|
72
|
+
reference. Neither file embeds a credential value. An operator generates and
|
|
73
|
+
provisions the opaque token to the Runner process and authorized client; use a
|
|
74
|
+
signed identity-provider token instead for shared multi-user deployments. See
|
|
75
|
+
[HTTP MCP](http-mcp.md). Claude, Cursor, and generic stdio templates use
|
|
76
|
+
canonical dotted capability names and need no HTTP credential.
|
|
72
77
|
|
|
73
78
|
Approval and writeback remain outside the model-facing MCP tool surface. Use
|
|
74
79
|
`proposals`, `apply`, `receipts`, and `replay` from a trusted operator shell.
|
|
@@ -36,6 +36,7 @@ Unknown keys fail when `strict` is true (the default).
|
|
|
36
36
|
| `approvals` | No | Local approval overrides. |
|
|
37
37
|
| `operator_identity` | No | Verified operator identity and apply-role wiring for approve/reject/apply. |
|
|
38
38
|
| `session_auth` | HTTP claims | HS256 development or asymmetric RS256/ES256 session-token verification. |
|
|
39
|
+
| `http_security` | Networked HTTP | Deployment profile, protected channel, endpoint-token env names, OAuth protected-resource metadata, exact Origin/Host policy, and request/session bounds. |
|
|
39
40
|
| `rate_limits` | No | Operational fixed-window limits; fleet-wide only with shared `runtime_store`. |
|
|
40
41
|
| `metrics` | No | Separately authorized scrapeable HTTP metrics. Disabled by default. |
|
|
41
42
|
| `graduated_trust` | No | Off-by-default, operator-only policy recommendation criteria and kill switch. |
|
|
@@ -212,8 +213,16 @@ Providers are `environment`, `static_dev`, `http_claims`, and `cloud_session`.
|
|
|
212
213
|
Capabilities may reference a context by name. The model never receives tenant
|
|
213
214
|
or principal as an overridable argument.
|
|
214
215
|
|
|
215
|
-
|
|
216
|
-
session
|
|
216
|
+
The language-neutral canonical contract can preserve a `session` binding for
|
|
217
|
+
implementations such as C++/Cloud that own a typed session boundary. Runner has
|
|
218
|
+
no generic web-session provider and rejects it with
|
|
219
|
+
`SESSION_BINDING_UNSUPPORTED`; it never treats the key as an environment
|
|
220
|
+
variable. Use `environment` for local stdio, verified `http_claims` for shared
|
|
221
|
+
Streamable HTTP, or verified `cloud_session` for Cloud embedding.
|
|
222
|
+
|
|
223
|
+
For controlled loopback development, `http_claims` can use an HS256 session
|
|
224
|
+
token. Runner holds the symmetric signing/verification secret in this mode, so
|
|
225
|
+
it is not the recommended shared production profile:
|
|
217
226
|
|
|
218
227
|
```json
|
|
219
228
|
{
|
|
@@ -229,7 +238,7 @@ session auth:
|
|
|
229
238
|
"secret_env": "SYNAPSOR_SESSION_JWT_SECRET",
|
|
230
239
|
"previous_secret_env": "SYNAPSOR_PREVIOUS_SESSION_JWT_SECRET",
|
|
231
240
|
"issuer": "https://identity.example",
|
|
232
|
-
"audience": "
|
|
241
|
+
"audience": "https://runner.example/mcp"
|
|
233
242
|
}
|
|
234
243
|
}
|
|
235
244
|
```
|
|
@@ -239,16 +248,24 @@ the active secret first, then the previous secret. Existing MCP sessions remain
|
|
|
239
248
|
bound to the exact token fingerprint, so clients cannot swap tenant/principal
|
|
240
249
|
identity inside an initialized session.
|
|
241
250
|
|
|
242
|
-
For networked
|
|
251
|
+
For a shared networked deployment, use asymmetric public-key verification and
|
|
252
|
+
declare the protected resource and channel explicitly:
|
|
243
253
|
|
|
244
254
|
```json
|
|
245
255
|
{
|
|
256
|
+
"trusted_context": {
|
|
257
|
+
"provider": "http_claims",
|
|
258
|
+
"values": {
|
|
259
|
+
"tenant_id_key": "tenant_id",
|
|
260
|
+
"principal_key": "sub"
|
|
261
|
+
}
|
|
262
|
+
},
|
|
246
263
|
"session_auth": {
|
|
247
264
|
"provider": "jwt_asymmetric",
|
|
248
|
-
"algorithms": ["RS256"],
|
|
265
|
+
"algorithms": ["RS256", "ES256"],
|
|
249
266
|
"jwks_url_env": "SYNAPSOR_SESSION_JWKS_URL",
|
|
250
267
|
"issuer": "https://identity.example",
|
|
251
|
-
"audience": "
|
|
268
|
+
"audience": "https://runner.example/mcp",
|
|
252
269
|
"tenant_claim": "tenant_id",
|
|
253
270
|
"principal_claim": "sub",
|
|
254
271
|
"clock_skew_seconds": 30,
|
|
@@ -256,6 +273,19 @@ For networked deployments prefer asymmetric public-key verification:
|
|
|
256
273
|
"jwks_cooldown_seconds": 30,
|
|
257
274
|
"fetch_timeout_ms": 3000,
|
|
258
275
|
"max_response_bytes": 1048576
|
|
276
|
+
},
|
|
277
|
+
"http_security": {
|
|
278
|
+
"deployment": "shared",
|
|
279
|
+
"channel": "trusted_tls_proxy",
|
|
280
|
+
"oauth_resource": {
|
|
281
|
+
"resource": "https://runner.example/mcp",
|
|
282
|
+
"authorization_servers": ["https://identity.example"],
|
|
283
|
+
"scopes_supported": ["synapsor:mcp"],
|
|
284
|
+
"required_scopes": ["synapsor:mcp"],
|
|
285
|
+
"resource_name": "Synapsor Runner"
|
|
286
|
+
},
|
|
287
|
+
"allowed_origins": ["https://agent-console.example"],
|
|
288
|
+
"allowed_hosts": ["runner.example"]
|
|
259
289
|
}
|
|
260
290
|
}
|
|
261
291
|
```
|
|
@@ -268,6 +298,66 @@ rejected. Every effective named context in an `http_claims` server must bind
|
|
|
268
298
|
tenant and principal from claims; environment/static contradictions fail with
|
|
269
299
|
`TRUSTED_CONTEXT_PROVIDER_CONFLICT` before serving.
|
|
270
300
|
|
|
301
|
+
`session_auth` verifies identity; it does not issue access tokens. The external
|
|
302
|
+
identity provider identified by `issuer` issues a short-lived token whose
|
|
303
|
+
audience is the exact protected-resource URL. Runner fetches only public JWKS
|
|
304
|
+
material and validates the configured claims on every request. Required OAuth
|
|
305
|
+
scopes are declared under `http_security.oauth_resource`.
|
|
306
|
+
|
|
307
|
+
## HTTP security
|
|
308
|
+
|
|
309
|
+
`http_security` is Runner deployment wiring, not part of a portable contract:
|
|
310
|
+
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"http_security": {
|
|
314
|
+
"deployment": "single_tenant",
|
|
315
|
+
"channel": "trusted_tls_proxy",
|
|
316
|
+
"static_token": {
|
|
317
|
+
"active_env": "SYNAPSOR_RUNNER_HTTP_TOKEN",
|
|
318
|
+
"previous_env": "SYNAPSOR_RUNNER_HTTP_TOKEN_PREVIOUS"
|
|
319
|
+
},
|
|
320
|
+
"allowed_origins": ["https://agent-console.example"],
|
|
321
|
+
"allowed_hosts": ["runner.internal.example"],
|
|
322
|
+
"limits": {
|
|
323
|
+
"max_request_bytes": 65536,
|
|
324
|
+
"max_header_bytes": 8192,
|
|
325
|
+
"max_sessions": 500,
|
|
326
|
+
"session_idle_timeout_seconds": 300,
|
|
327
|
+
"request_timeout_ms": 15000,
|
|
328
|
+
"headers_timeout_ms": 5000,
|
|
329
|
+
"keep_alive_timeout_ms": 5000,
|
|
330
|
+
"max_connections": 1000
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
- `deployment` is `loopback`, `single_tenant`, or `shared`. Shared requires
|
|
337
|
+
verified signed `http_claims`, exact issuer/audience, and RFC 9728
|
|
338
|
+
`oauth_resource` metadata.
|
|
339
|
+
- `channel` is `direct_tls`, `trusted_tls_proxy`, or the explicitly unsafe
|
|
340
|
+
`insecure_http_break_glass`. A non-loopback listener without one refuses to
|
|
341
|
+
bind. Break glass remains authenticated.
|
|
342
|
+
- `static_token` names one active and optionally one previous environment
|
|
343
|
+
variable. It is opaque service access for loopback/single-tenant use, not
|
|
344
|
+
tenant identity. Values never belong in config.
|
|
345
|
+
- `oauth_resource.resource` is the exact HTTPS MCP endpoint and must equal
|
|
346
|
+
`session_auth.audience`. `authorization_servers` names external issuers;
|
|
347
|
+
Runner does not implement login or token refresh.
|
|
348
|
+
- `allowed_origins` contains exact browser origins; an omitted browser Origin
|
|
349
|
+
remains valid for native clients. Wildcards are forbidden.
|
|
350
|
+
- `allowed_hosts` contains exact direct/public Host authorities. Forwarded Host
|
|
351
|
+
and forwarded identity headers are not trusted automatically.
|
|
352
|
+
- `limits` bounds bodies, headers, concurrent sessions/connections, idle
|
|
353
|
+
sessions, and HTTP timing. Defaults are documented in [HTTP MCP](http-mcp.md).
|
|
354
|
+
|
|
355
|
+
Runner-owned TLS certificate, key, and optional client-CA PEM values are passed
|
|
356
|
+
by environment references on the serve command (`--tls-cert-env`,
|
|
357
|
+
`--tls-key-env`, `--tls-ca-env`, `--require-client-cert`). Private TLS material
|
|
358
|
+
does not go in this JSON file. A trusted-proxy channel assumes firewall/private
|
|
359
|
+
network controls prevent clients from bypassing that proxy.
|
|
360
|
+
|
|
271
361
|
## Contracts and embedded capabilities
|
|
272
362
|
|
|
273
363
|
```json
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Running A Small Runner Fleet
|
|
2
2
|
|
|
3
|
-
Synapsor Runner
|
|
3
|
+
Synapsor Runner supports a bounded small-fleet deployment. It does not
|
|
4
4
|
turn the OSS package into Synapsor Cloud and it does not promise an unbounded,
|
|
5
5
|
multi-region, or SLA-backed control plane.
|
|
6
6
|
|
|
@@ -32,7 +32,7 @@ model-facing approval/apply tools as blockers. Audit is a static review, not a
|
|
|
32
32
|
security proof; follow it with `tools preview`, `doctor`, and the live fleet
|
|
33
33
|
verification.
|
|
34
34
|
|
|
35
|
-
## What
|
|
35
|
+
## What The Bounded Fleet Guarantees
|
|
36
36
|
|
|
37
37
|
With `storage.shared_postgres.mode = "runtime_store"`:
|
|
38
38
|
|
|
@@ -116,7 +116,7 @@ Use asymmetric verification for a networked fleet:
|
|
|
116
116
|
"algorithms": ["RS256"],
|
|
117
117
|
"jwks_url_env": "SYNAPSOR_SESSION_JWKS_URL",
|
|
118
118
|
"issuer": "https://identity.example",
|
|
119
|
-
"audience": "
|
|
119
|
+
"audience": "https://runner.example/mcp",
|
|
120
120
|
"tenant_claim": "tenant_id",
|
|
121
121
|
"principal_claim": "sub",
|
|
122
122
|
"clock_skew_seconds": 30,
|
|
@@ -124,10 +124,28 @@ Use asymmetric verification for a networked fleet:
|
|
|
124
124
|
"jwks_cooldown_seconds": 30,
|
|
125
125
|
"fetch_timeout_ms": 3000,
|
|
126
126
|
"max_response_bytes": 1048576
|
|
127
|
+
},
|
|
128
|
+
"http_security": {
|
|
129
|
+
"deployment": "shared",
|
|
130
|
+
"channel": "trusted_tls_proxy",
|
|
131
|
+
"oauth_resource": {
|
|
132
|
+
"resource": "https://runner.example/mcp",
|
|
133
|
+
"authorization_servers": ["https://identity.example"],
|
|
134
|
+
"scopes_supported": ["synapsor:mcp"],
|
|
135
|
+
"required_scopes": ["synapsor:mcp"]
|
|
136
|
+
},
|
|
137
|
+
"allowed_hosts": ["runner.example"],
|
|
138
|
+
"allowed_origins": ["https://agent-console.example"]
|
|
127
139
|
}
|
|
128
140
|
}
|
|
129
141
|
```
|
|
130
142
|
|
|
143
|
+
The external identity provider issues the short-lived client JWT for resource
|
|
144
|
+
`https://runner.example/mcp`; Runner only verifies it. The load balancer must
|
|
145
|
+
terminate TLS and prevent direct access to the private Runner listeners. If
|
|
146
|
+
Runner owns TLS instead, use protected certificate/key env references and set
|
|
147
|
+
`channel` to `direct_tls`.
|
|
148
|
+
|
|
131
149
|
Every served capability context must bind tenant and principal from
|
|
132
150
|
`HTTP_CLAIM`. Runner rejects an environment-bound contract mixed into this
|
|
133
151
|
server with `TRUSTED_CONTEXT_PROVIDER_CONFLICT` before tools are served.
|
|
@@ -147,6 +165,12 @@ material. Unknown `kid` triggers at most one controlled refresh. For offline
|
|
|
147
165
|
deployments, configure one public PEM through `public_key_env` or
|
|
148
166
|
`public_key_path`; never place a private key in Runner config.
|
|
149
167
|
|
|
168
|
+
Runner publishes RFC 9728 protected-resource metadata at the path derived from
|
|
169
|
+
the public resource and returns scope-aware Bearer challenges. The identity
|
|
170
|
+
provider, not Runner, owns user login, client registration, token issuance, and
|
|
171
|
+
refresh. An MCP session ID is only protocol state; every request is
|
|
172
|
+
reauthenticated and remains pinned to the initialized credential identity.
|
|
173
|
+
|
|
150
174
|
## Ledger And Source Pools
|
|
151
175
|
|
|
152
176
|
```json
|
|
@@ -329,12 +353,13 @@ configured handler timeout. A hard kill is recoverable through leases and
|
|
|
329
353
|
source-side idempotency receipts, but should remain an incident signal.
|
|
330
354
|
|
|
331
355
|
Rotate JWKS keys by publishing the new `kid`, waiting at least the configured
|
|
332
|
-
cache lifetime
|
|
333
|
-
|
|
334
|
-
|
|
356
|
+
cache lifetime while issuers sign with the new key, then retiring the old key.
|
|
357
|
+
Do not casually change the issuer or protected-resource audience during a key
|
|
358
|
+
rotation. Rotate TLS/mTLS, metrics, handler, database, and ledger credentials
|
|
359
|
+
independently through their named environment variables.
|
|
335
360
|
|
|
336
|
-
Only homogeneous Runner
|
|
337
|
-
|
|
361
|
+
Only homogeneous Runner instances at the release under test are verified by
|
|
362
|
+
`test:fleet`. Mixed-version operation is not claimed. For rolling upgrades:
|
|
338
363
|
|
|
339
364
|
1. back up and verify the ledger;
|
|
340
365
|
2. run schema/config validation with the target version;
|
|
@@ -351,8 +376,12 @@ roll back the full fleet. Never mix versions merely because both are `1.x`.
|
|
|
351
376
|
|
|
352
377
|
## TLS Boundary
|
|
353
378
|
|
|
354
|
-
Terminate public TLS or mTLS at a trusted load balancer
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
379
|
+
Terminate public TLS or mTLS at a trusted load balancer and declare
|
|
380
|
+
`channel: trusted_tls_proxy`, or configure Runner's tested TLS/mTLS options
|
|
381
|
+
directly. A proxy declaration is a security assertion: firewall the private
|
|
382
|
+
listener so clients cannot bypass the proxy, protect the private hop, and
|
|
383
|
+
preserve an allowed Host. Keep Runner-to-database TLS verification on, use
|
|
384
|
+
private networking where possible, and restrict `/metrics` separately. The
|
|
385
|
+
verified Bearer JWT itself, not a proxy-added tenant/principal header, is the
|
|
386
|
+
session authority. See [HTTP MCP](http-mcp.md) for channel flags, limits, and
|
|
387
|
+
doctor checks.
|
|
@@ -36,19 +36,55 @@ The model does not receive:
|
|
|
36
36
|
- a generic `execute_sql` tool;
|
|
37
37
|
- arbitrary table, schema, or column names;
|
|
38
38
|
- database URLs or credentials;
|
|
39
|
+
- contract activation tools;
|
|
39
40
|
- approval tools;
|
|
40
41
|
- commit/writeback tools;
|
|
42
|
+
- MCP endpoint tokens, JWTs, refresh tokens, client secrets, or TLS keys;
|
|
41
43
|
- trusted tenant or principal authority as ordinary model arguments.
|
|
42
44
|
|
|
45
|
+
## Network transport and identity
|
|
46
|
+
|
|
47
|
+
Local stdio is the preferred one-client path. The MCP client launches Runner and
|
|
48
|
+
communicates over the child process's standard input/output, so Runner opens no
|
|
49
|
+
network listener and HTTP authentication does not apply.
|
|
50
|
+
|
|
51
|
+
A listening HTTP endpoint has no inherent client identity. Runner therefore
|
|
52
|
+
requires Bearer authentication by default. On loopback or an explicitly
|
|
53
|
+
single-tenant service, Bearer may carry one high-entropy opaque endpoint token;
|
|
54
|
+
that token only answers "may this service call the endpoint?" and is not a user
|
|
55
|
+
or tenant identity. Shared services require signed per-session JWTs, preferably
|
|
56
|
+
RS256/ES256 from an external identity provider, with exact issuer,
|
|
57
|
+
audience/resource, time, scope, tenant, and principal validation on every
|
|
58
|
+
request. An MCP session ID only routes protocol state and never authenticates a
|
|
59
|
+
caller.
|
|
60
|
+
|
|
61
|
+
Non-loopback HTTP refuses to bind unless Runner owns TLS, an explicitly trusted
|
|
62
|
+
TLS proxy protects the public and private hops, or an authenticated emergency
|
|
63
|
+
cleartext break-glass mode is selected. TLS protects the channel; mTLS also
|
|
64
|
+
authenticates a workload certificate but does not replace per-user/tenant claims
|
|
65
|
+
in a shared service. Exact Origin and Host policy, request/session limits, and
|
|
66
|
+
credential-pinned MCP sessions narrow browser, DNS-rebinding, exhaustion, and
|
|
67
|
+
session-swap attacks.
|
|
68
|
+
|
|
69
|
+
These controls remain independent: transport authentication permits endpoint
|
|
70
|
+
access; verified session claims provide tenant/principal context; the contract
|
|
71
|
+
authorizes semantic capabilities; database roles/RLS constrain the connection;
|
|
72
|
+
operator identity authorizes activation, approval, apply, reconcile, and
|
|
73
|
+
revert. See [HTTP MCP](http-mcp.md).
|
|
74
|
+
|
|
43
75
|
Reviewed aggregate tools expose one scalar only. Their function, column,
|
|
44
76
|
tenant key, optional equality selection, and minimum-group threshold are fixed
|
|
45
77
|
in the contract; the model receives no predicate arguments or member rows.
|
|
46
78
|
Suppression reduces single-record inference but does not replace statistical
|
|
47
79
|
privacy review. See [Bounded Aggregate Reads](aggregate-reads.md).
|
|
48
80
|
|
|
49
|
-
Trusted context comes from
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
Trusted context comes from operator-controlled process bindings for local or
|
|
82
|
+
explicitly single-tenant use, verified signed HTTP claims for a shared service,
|
|
83
|
+
or verified Cloud session context in Cloud mode. Tenant, principal, and
|
|
84
|
+
authorization scope must not be accepted from the model as authority.
|
|
85
|
+
Canonical `SESSION` content is rejected by Runner with
|
|
86
|
+
`SESSION_BINDING_UNSUPPORTED`; Runner never aliases it to environment values,
|
|
87
|
+
arbitrary headers, MCP metadata, or model arguments.
|
|
52
88
|
|
|
53
89
|
With a shared credential, these checks are application-level enforcement and
|
|
54
90
|
depend on Runner's fixed predicate implementation. Optional PostgreSQL RLS mode
|
|
@@ -84,6 +120,18 @@ explicit host-level administrative boundary.
|
|
|
84
120
|
Proposal tools read the current row through the read credential, store evidence
|
|
85
121
|
and an exact before/after diff, and leave the source database unchanged.
|
|
86
122
|
|
|
123
|
+
Code-first Safe Actions do not create authority when a file is edited. Runner
|
|
124
|
+
parses the restricted TypeScript object without importing or executing it,
|
|
125
|
+
compiles it into a digest-addressed disabled canonical draft, and keeps the
|
|
126
|
+
active contract pointer unchanged. Activation is available only in the
|
|
127
|
+
session-token/CSRF-protected localhost Workbench after a matching real staging
|
|
128
|
+
proposal proves `source_database_changed:false`; the operator must confirm the
|
|
129
|
+
complete digest. A proposal remains pinned to the active contract digest it was
|
|
130
|
+
created under, so later activation cannot reinterpret an old approval. Cloud-
|
|
131
|
+
linked projects route activation through Cloud governance instead of the local
|
|
132
|
+
control. No model-facing MCP tool can validate-and-activate, approve, apply, or
|
|
133
|
+
revert.
|
|
134
|
+
|
|
87
135
|
The local proposal store rejects obvious credential material before persistence:
|
|
88
136
|
database URLs, bearer tokens, Synapsor runner tokens, private-key blocks, and
|
|
89
137
|
secret-like fields such as password, token, API key, private key, cookie,
|
|
@@ -145,11 +193,13 @@ database identifiers such as `../private`, `id/../../tenant_id`, or
|
|
|
145
193
|
`status; DROP TABLE tickets` before adapter execution. Local CLI file paths
|
|
146
194
|
remain explicit user-provided paths; they are not model-facing authority.
|
|
147
195
|
|
|
148
|
-
Local review can happen through the CLI or `synapsor-runner ui`. The UI is a
|
|
149
|
-
review surface with a per-run session token and CSRF protection for
|
|
150
|
-
approve/reject
|
|
151
|
-
|
|
152
|
-
|
|
196
|
+
Local review can happen through the CLI or `synapsor-runner ui`. The UI is a
|
|
197
|
+
localhost review surface with a per-run session token and CSRF protection for
|
|
198
|
+
approve/reject and Safe Action draft controls. Activation additionally requires
|
|
199
|
+
a matching source-unchanged preview plus the complete digest. These operator
|
|
200
|
+
controls are not MCP tools. The UI does not expose raw SQL, database URLs, or
|
|
201
|
+
write credentials, and it does not let a model widen reviewed tables, columns,
|
|
202
|
+
scope, policy, or executor authority.
|
|
153
203
|
|
|
154
204
|
Contract lint and tests are review aids rather than a proof of complete
|
|
155
205
|
security. Capability breadth can still drift as narrow tools accumulate;
|
package/docs/shadow-studies.md
CHANGED
|
@@ -142,6 +142,41 @@ synapsor-runner shadow outcome import \
|
|
|
142
142
|
--store ./.synapsor/local.db
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
+
For the normal application path, record the trusted outcome directly instead
|
|
146
|
+
of assembling JSONL. `@synapsor/runner/shadow` writes through the same scope,
|
|
147
|
+
effect-shape, and secret checks as the import command:
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
import { createShadowOutcomeRecorder } from "@synapsor/runner/shadow";
|
|
151
|
+
|
|
152
|
+
const recorder = createShadowOutcomeRecorder({
|
|
153
|
+
storePath: "./.synapsor/local.db",
|
|
154
|
+
studyId: "sst_support_pilot",
|
|
155
|
+
actor: "support_application",
|
|
156
|
+
source: "support-audit-log",
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
recorder.record({
|
|
161
|
+
requestId: "request_123",
|
|
162
|
+
tenantId: "acme",
|
|
163
|
+
businessObject: "invoice",
|
|
164
|
+
objectId: "INV-3001",
|
|
165
|
+
disposition: "applied",
|
|
166
|
+
actualEffect: {
|
|
167
|
+
before: { late_fee_cents: 5500 },
|
|
168
|
+
after: { late_fee_cents: 0 },
|
|
169
|
+
patch: { late_fee_cents: 0 },
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
} finally {
|
|
173
|
+
recorder.close();
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The application owns the truth of this outcome. The helper does not read or
|
|
178
|
+
mutate the source database and cannot approve a shadow proposal.
|
|
179
|
+
|
|
145
180
|
## Review The Report
|
|
146
181
|
|
|
147
182
|
```bash
|
|
@@ -161,6 +196,16 @@ denial, unable-to-propose, stale/conflict, unmatched, and unsafe-scope cases.
|
|
|
161
196
|
It also includes amount distributions, capability/reason breakdowns, and
|
|
162
197
|
risk-ranked disagreements.
|
|
163
198
|
|
|
199
|
+
The report also shows the explicit trust progression:
|
|
200
|
+
|
|
201
|
+
```text
|
|
202
|
+
Observe -> Compare -> Manual review -> Suggested bounded policy
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
It reports an insufficient sample size until the minimum comparable evidence
|
|
206
|
+
exists. A suggested policy remains an inactive review artifact; the report
|
|
207
|
+
never widens or activates the contract.
|
|
208
|
+
|
|
164
209
|
Close a completed study:
|
|
165
210
|
|
|
166
211
|
```bash
|
|
@@ -187,10 +232,8 @@ synapsor-runner shadow case import \
|
|
|
187
232
|
--input ./examples/support-billing-agent/shadow-study/cases.jsonl \
|
|
188
233
|
--store ./.synapsor/shadow-reference.db
|
|
189
234
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
--input ./examples/support-billing-agent/shadow-study/outcomes.jsonl \
|
|
193
|
-
--store ./.synapsor/shadow-reference.db
|
|
235
|
+
node ./examples/support-billing-agent/app/record-shadow-outcomes.mjs \
|
|
236
|
+
./.synapsor/shadow-reference.db sst_support_reference
|
|
194
237
|
|
|
195
238
|
synapsor-runner shadow report \
|
|
196
239
|
--study sst_support_reference \
|