@synapsor/runner 1.4.12 → 1.4.122
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 +65 -0
- package/README.md +63 -60
- package/THREAT_MODEL.md +6 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/runner.mjs +29227 -2475
- package/docs/README.md +11 -0
- package/docs/aggregate-reads.md +49 -0
- package/docs/bounded-set-writeback.md +9 -4
- package/docs/capability-authoring.md +43 -1
- package/docs/cloud-cli.md +248 -0
- package/docs/cloud-mode.md +88 -6
- package/docs/cloud-push.md +22 -5
- package/docs/compliance-reports.md +42 -0
- package/docs/conformance.md +15 -0
- package/docs/contract-review.md +57 -0
- package/docs/contract-testing.md +76 -0
- package/docs/dsl-reference.md +50 -6
- package/docs/graduated-trust.md +64 -0
- package/docs/hosted-cloud-linked-verification.md +97 -0
- package/docs/limitations.md +10 -0
- package/docs/oss-vs-cloud.md +13 -6
- package/docs/release-notes.md +65 -0
- package/docs/rfcs/007-trusted-principal-row-scope.md +75 -0
- package/docs/runner-bundles.md +24 -0
- package/docs/runner-config-reference.md +16 -0
- package/docs/running-a-runner-fleet.md +8 -0
- package/docs/security-boundary.md +28 -1
- package/examples/runner-fleet/seed/mysql.sql +5 -1
- package/examples/runner-fleet/seed/postgres.sql +5 -1
- package/examples/support-plan-credit/README.md +8 -6
- package/examples/support-plan-credit/synapsor.contract-tests.json +53 -0
- package/fixtures/dsl/aggregate-read.synapsor.sql +21 -0
- package/fixtures/dsl/bounded-set-multi-term.synapsor.sql +30 -0
- package/fixtures/dsl/principal-row-scope.synapsor.sql +23 -0
- package/fixtures/protocol/MANIFEST.json +10 -10
- package/package.json +4 -1
- package/schemas/change-set.v1.schema.json +14 -0
- package/schemas/change-set.v2.schema.json +14 -0
- package/schemas/change-set.v3.schema.json +2 -0
- package/schemas/compensation-change-set.v1.schema.json +3 -2
- package/schemas/inverse-descriptor.v1.schema.json +2 -0
- package/schemas/synapsor.contract-tests.schema.json +54 -0
- package/schemas/synapsor.runner.schema.json +92 -4
- package/schemas/writeback-job.v1.schema.json +14 -0
- package/schemas/writeback-job.v2.schema.json +14 -0
- package/schemas/writeback-job.v3.schema.json +2 -0
- package/schemas/writeback-job.v4.schema.json +2 -2
|
@@ -38,6 +38,7 @@ Unknown keys fail when `strict` is true (the default).
|
|
|
38
38
|
| `session_auth` | HTTP claims | HS256 development or asymmetric RS256/ES256 session-token verification. |
|
|
39
39
|
| `rate_limits` | No | Operational fixed-window limits; fleet-wide only with shared `runtime_store`. |
|
|
40
40
|
| `metrics` | No | Separately authorized scrapeable HTTP metrics. Disabled by default. |
|
|
41
|
+
| `graduated_trust` | No | Off-by-default, operator-only policy recommendation criteria and kill switch. |
|
|
41
42
|
| `executors` | No | App-owned writeback wiring. |
|
|
42
43
|
| `cloud` | Cloud mode | Scoped Cloud adapter configuration. |
|
|
43
44
|
|
|
@@ -375,6 +376,21 @@ metrics token; the MCP bearer does not authorize metrics. Labels are bounded to
|
|
|
375
376
|
trusted tenant, capability, source, engine, and readiness component. Object
|
|
376
377
|
IDs, principals, URLs, tokens, and raw errors are never labels.
|
|
377
378
|
|
|
379
|
+
## Graduated trust
|
|
380
|
+
|
|
381
|
+
`graduated_trust` is runtime/operator policy, not model-facing authority. It is
|
|
382
|
+
disabled unless `enabled` is exactly `true`; `kill_switch: true` stops all
|
|
383
|
+
evaluation. Each criterion fixes one capability, approval policy, numeric
|
|
384
|
+
field, minimum human-reviewed sample (10..10000), window (1..365 days), maximum
|
|
385
|
+
rejection/conflict/failure/revert rates, maximum threshold increment, and
|
|
386
|
+
absolute ceiling. Optional `workspace_id` and `project_id` further scope stored
|
|
387
|
+
recommendations.
|
|
388
|
+
|
|
389
|
+
Auto-approved outcomes never count as human evidence. Recommendation decisions
|
|
390
|
+
require verified operator identity. Approval only permits exporting a new
|
|
391
|
+
contract artifact bound to the current digest/version; Runner never activates
|
|
392
|
+
it. See [Graduated Trust Recommendations](graduated-trust.md).
|
|
393
|
+
|
|
378
394
|
## Operator identity
|
|
379
395
|
|
|
380
396
|
Local development compatibility uses an explicitly unverified environment
|
|
@@ -132,6 +132,14 @@ Every served capability context must bind tenant and principal from
|
|
|
132
132
|
`HTTP_CLAIM`. Runner rejects an environment-bound contract mixed into this
|
|
133
133
|
server with `TRUSTED_CONTEXT_PROVIDER_CONFLICT` before tools are served.
|
|
134
134
|
|
|
135
|
+
For same-tenant per-user rows, declare `PRINCIPAL SCOPE KEY assigned_to` (or
|
|
136
|
+
the corresponding canonical `principal_scope_key`) on the capability. The
|
|
137
|
+
signed `sub` claim then becomes a bound SQL predicate composed with the signed
|
|
138
|
+
tenant claim. Session token fingerprint pinning prevents swapping identities
|
|
139
|
+
within an MCP session. `tools preview` displays both locks, and
|
|
140
|
+
`corepack pnpm test:principal-scope` proves two concurrent principals cannot
|
|
141
|
+
read each other's rows or evidence handles on Postgres and MySQL.
|
|
142
|
+
|
|
135
143
|
Use an HTTPS JWKS URL from an allowlisted identity system. Runner rejects
|
|
136
144
|
redirects, oversized responses, unknown algorithms, `none`, missing/unknown
|
|
137
145
|
`kid`, bad issuer/audience, expired/not-yet-valid tokens, and private JWK
|
|
@@ -40,10 +40,30 @@ The model does not receive:
|
|
|
40
40
|
- commit/writeback tools;
|
|
41
41
|
- trusted tenant or principal authority as ordinary model arguments.
|
|
42
42
|
|
|
43
|
+
Reviewed aggregate tools expose one scalar only. Their function, column,
|
|
44
|
+
tenant key, optional equality selection, and minimum-group threshold are fixed
|
|
45
|
+
in the contract; the model receives no predicate arguments or member rows.
|
|
46
|
+
Suppression reduces single-record inference but does not replace statistical
|
|
47
|
+
privacy review. See [Bounded Aggregate Reads](aggregate-reads.md).
|
|
48
|
+
|
|
43
49
|
Trusted context comes from local configuration, environment bindings, or Cloud
|
|
44
50
|
session context in Cloud mode. Tenant, principal, and authorization scope must
|
|
45
51
|
not be accepted from the model as authority.
|
|
46
52
|
|
|
53
|
+
A capability may declare `principal_scope_key` (DSL: `PRINCIPAL SCOPE KEY`) to
|
|
54
|
+
narrow rows inside a tenant. Runner then adds both fixed, parameterized guards:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
tenant_key = verified tenant AND principal_scope_key = verified principal
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This applies to single-row reads and writes, aggregates, bounded sets, inserts,
|
|
61
|
+
deletes, executor envelopes, and reviewed compensation. Missing principal
|
|
62
|
+
context fails closed. A principal lock never replaces tenant scope and has no
|
|
63
|
+
dynamic supervisor bypass. Use a separately reviewed tenant-wide capability
|
|
64
|
+
for broader roles. RLS and restricted database roles remain valuable defense in
|
|
65
|
+
depth; the contract does not replace them.
|
|
66
|
+
|
|
47
67
|
Proposal, evidence, and replay handles are references, not bearer credentials.
|
|
48
68
|
Before returning a local MCP resource, Runner resolves the resource's owning
|
|
49
69
|
capability context again and requires both tenant and principal to match the
|
|
@@ -70,7 +90,7 @@ outside the model-facing MCP server and verifies:
|
|
|
70
90
|
- local approval state;
|
|
71
91
|
- proposal and job digests;
|
|
72
92
|
- target schema/table;
|
|
73
|
-
- primary-key and
|
|
93
|
+
- primary-key, tenant, and declared principal-row guards;
|
|
74
94
|
- allowed mutable columns;
|
|
75
95
|
- conflict/version guard;
|
|
76
96
|
- idempotency key;
|
|
@@ -121,6 +141,13 @@ approve/reject actions. It does not expose raw SQL, database URLs, write
|
|
|
121
141
|
credentials, approval tools, commit tools, or controls that widen reviewed
|
|
122
142
|
tables/columns.
|
|
123
143
|
|
|
144
|
+
Contract lint and tests are review aids rather than a proof of complete
|
|
145
|
+
security. Scoped report exports omit evidence rows and kept-out values and are
|
|
146
|
+
tamper-evident when their digest/signature verifies; local SQLite is not an
|
|
147
|
+
immutable compliance service. Graduated-trust evaluation is operator-only,
|
|
148
|
+
disabled by default, and can recommend/export a separate artifact but cannot
|
|
149
|
+
approve itself or activate policy.
|
|
150
|
+
|
|
124
151
|
Synapsor Runner supports reviewed single-row CRUD and the narrowly bounded set
|
|
125
152
|
path documented above. It does not support arbitrary SQL, DDL, UPSERT,
|
|
126
153
|
model-generated predicates, unbounded sets, or cross-table direct writeback.
|
|
@@ -4,6 +4,7 @@ CREATE TABLE invoices (
|
|
|
4
4
|
status varchar(64) NOT NULL,
|
|
5
5
|
late_fee_cents integer NOT NULL,
|
|
6
6
|
waiver_reason varchar(500),
|
|
7
|
+
assigned_to varchar(128) NOT NULL DEFAULT 'case_manager_a',
|
|
7
8
|
updated_at datetime(6) NOT NULL
|
|
8
9
|
);
|
|
9
10
|
|
|
@@ -41,7 +42,10 @@ INSERT INTO guard_crud_items (id, tenant_id, request_id, value_cents, version) V
|
|
|
41
42
|
ALTER TABLE guard_crud_items AUTO_INCREMENT = 2001;
|
|
42
43
|
|
|
43
44
|
INSERT INTO invoices (id, tenant_id, status, late_fee_cents, waiver_reason, updated_at) VALUES
|
|
44
|
-
('MYSQL-ACME', 'acme', 'overdue', 700, NULL, '2026-07-12 12:00:00.000000')
|
|
45
|
+
('MYSQL-ACME', 'acme', 'overdue', 700, NULL, '2026-07-12 12:00:00.000000'),
|
|
46
|
+
('MYSQL-PRINCIPAL-A', 'hospital_a', 'principal_fixture', 100, NULL, '2026-07-12 12:00:00.000000'),
|
|
47
|
+
('MYSQL-PRINCIPAL-B', 'hospital_a', 'principal_fixture', 200, NULL, '2026-07-12 12:00:00.000000');
|
|
48
|
+
UPDATE invoices SET assigned_to = 'case_manager_b' WHERE id = 'MYSQL-PRINCIPAL-B';
|
|
45
49
|
|
|
46
50
|
CREATE VIEW slow_invoices AS
|
|
47
51
|
SELECT invoices.*, SLEEP(0.35) AS synthetic_delay
|
|
@@ -4,6 +4,7 @@ CREATE TABLE public.invoices (
|
|
|
4
4
|
status text NOT NULL,
|
|
5
5
|
late_fee_cents integer NOT NULL,
|
|
6
6
|
waiver_reason text,
|
|
7
|
+
assigned_to text NOT NULL DEFAULT 'case_manager_a',
|
|
7
8
|
updated_at timestamptz NOT NULL
|
|
8
9
|
);
|
|
9
10
|
|
|
@@ -73,7 +74,10 @@ INSERT INTO public.invoices (id, tenant_id, status, late_fee_cents, waiver_reaso
|
|
|
73
74
|
('INV-DEAD-DISCARD', 'acme', 'overdue', 1750, NULL, '2026-07-12T12:00:00Z'),
|
|
74
75
|
('INV-KILL-BEFORE', 'acme', 'overdue', 1200, NULL, '2026-07-12T12:00:00Z'),
|
|
75
76
|
('INV-KILL-DURING', 'acme', 'overdue', 1500, NULL, '2026-07-12T12:00:00Z'),
|
|
76
|
-
('INV-KILL-AFTER', 'acme', 'overdue', 1800, NULL, '2026-07-12T12:00:00Z')
|
|
77
|
+
('INV-KILL-AFTER', 'acme', 'overdue', 1800, NULL, '2026-07-12T12:00:00Z'),
|
|
78
|
+
('INV-PRINCIPAL-A', 'hospital_a', 'principal_fixture', 100, NULL, '2026-07-12T12:00:00Z'),
|
|
79
|
+
('INV-PRINCIPAL-B', 'hospital_a', 'principal_fixture', 200, NULL, '2026-07-12T12:00:00Z');
|
|
80
|
+
UPDATE public.invoices SET assigned_to = 'case_manager_b' WHERE id = 'INV-PRINCIPAL-B';
|
|
77
81
|
|
|
78
82
|
CREATE FUNCTION public.synthetic_pool_delay() RETURNS integer
|
|
79
83
|
LANGUAGE plpgsql VOLATILE AS $$
|
|
@@ -272,10 +272,12 @@ Real push uses your Cloud env vars:
|
|
|
272
272
|
|
|
273
273
|
```bash
|
|
274
274
|
export SYNAPSOR_CLOUD_BASE_URL="https://api.synapsor.ai"
|
|
275
|
-
export
|
|
276
|
-
export
|
|
275
|
+
export SYNAPSOR_API_KEY="<contracts-write-service-key>"
|
|
276
|
+
export SYNAPSOR_PROJECT_ID="<project_id>"
|
|
277
|
+
export SYNAPSOR_SOURCE_ID="<cloud_source_id>"
|
|
277
278
|
|
|
278
279
|
synapsor-runner cloud push examples/support-plan-credit/synapsor.contract.json \
|
|
280
|
+
--workspace "$SYNAPSOR_PROJECT_ID" \
|
|
279
281
|
--name support-plan-credit
|
|
280
282
|
```
|
|
281
283
|
|
|
@@ -283,11 +285,11 @@ After push, Cloud can return the registered version and a runner bundle with
|
|
|
283
285
|
placeholder env names:
|
|
284
286
|
|
|
285
287
|
```bash
|
|
286
|
-
curl -H "Authorization: Bearer $
|
|
287
|
-
"$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$
|
|
288
|
+
curl -H "Authorization: Bearer $SYNAPSOR_API_KEY" \
|
|
289
|
+
"$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$SYNAPSOR_PROJECT_ID/agent-contracts/<contract_id>/versions/<version_id>"
|
|
288
290
|
|
|
289
|
-
curl -H "Authorization: Bearer $
|
|
290
|
-
"$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$
|
|
291
|
+
curl -H "Authorization: Bearer $SYNAPSOR_API_KEY" \
|
|
292
|
+
"$SYNAPSOR_CLOUD_BASE_URL/v1/control/projects/$SYNAPSOR_PROJECT_ID/agent-contracts/<contract_id>/versions/<version_id>/runner-bundle?download=1&source_id=$SYNAPSOR_SOURCE_ID" \
|
|
291
293
|
-o support-plan-credit-runner-bundle.zip
|
|
292
294
|
```
|
|
293
295
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../schemas/synapsor.contract-tests.schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"name": "support-plan-credit contract boundary",
|
|
5
|
+
"tests": [
|
|
6
|
+
{
|
|
7
|
+
"id": "operator-controls-stay-outside-mcp",
|
|
8
|
+
"kind": "operator_boundary",
|
|
9
|
+
"capability": "support.propose_plan_credit"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "private-customer-fields-stay-hidden",
|
|
13
|
+
"kind": "hide_fields",
|
|
14
|
+
"capability": "support.inspect_customer",
|
|
15
|
+
"args": { "customer_id": "CUS-3001" },
|
|
16
|
+
"trusted_context": { "tenant_id": "acme", "principal": "contract_test" },
|
|
17
|
+
"fields": ["card_token", "raw_payment_method", "internal_risk_score", "private_notes"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "credit-amount-is-bounded",
|
|
21
|
+
"kind": "argument_constraint",
|
|
22
|
+
"capability": "support.propose_plan_credit_record",
|
|
23
|
+
"argument": "credit_cents",
|
|
24
|
+
"expected": { "minimum": 1, "maximum": 50000 }
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "trusted-tenant-can-read-own-customer",
|
|
28
|
+
"kind": "tool_allow",
|
|
29
|
+
"capability": "support.inspect_customer",
|
|
30
|
+
"args": { "customer_id": "CUS-3001" },
|
|
31
|
+
"trusted_context": { "tenant_id": "acme", "principal": "contract_test" }
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "trusted-tenant-cannot-read-other-customer",
|
|
35
|
+
"kind": "tool_deny",
|
|
36
|
+
"capability": "support.inspect_customer",
|
|
37
|
+
"args": { "customer_id": "CUS-9001" },
|
|
38
|
+
"trusted_context": { "tenant_id": "acme", "principal": "contract_test" },
|
|
39
|
+
"expected_code": "NOT_FOUND_IN_TENANT"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "proposal-does-not-write-before-approval",
|
|
43
|
+
"kind": "source_unchanged_before_approval",
|
|
44
|
+
"capability": "support.propose_plan_credit",
|
|
45
|
+
"args": {
|
|
46
|
+
"customer_id": "CUS-3001",
|
|
47
|
+
"credit_cents": 10000,
|
|
48
|
+
"reason": "synthetic conformance check"
|
|
49
|
+
},
|
|
50
|
+
"trusted_context": { "tenant_id": "acme", "principal": "contract_test" }
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
CREATE AGENT CONTEXT finance_operator
|
|
2
|
+
BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
|
|
3
|
+
BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
|
|
4
|
+
TENANT BINDING tenant_id
|
|
5
|
+
PRINCIPAL BINDING principal
|
|
6
|
+
END
|
|
7
|
+
|
|
8
|
+
CREATE CAPABILITY billing.overdue_balance_total
|
|
9
|
+
DESCRIPTION 'Return one suppressed overdue-balance aggregate for the trusted tenant.'
|
|
10
|
+
RETURNS HINT 'Returns one scalar or a suppression result; never member rows.'
|
|
11
|
+
USING CONTEXT finance_operator
|
|
12
|
+
SOURCE local_postgres
|
|
13
|
+
ON public.invoices
|
|
14
|
+
PRIMARY KEY id
|
|
15
|
+
TENANT KEY tenant_id
|
|
16
|
+
AGGREGATE READ SUM balance_cents
|
|
17
|
+
SELECT WHERE status = 'overdue'
|
|
18
|
+
MIN GROUP SIZE 5
|
|
19
|
+
KEEP OUT customer_email, private_notes
|
|
20
|
+
REQUIRE EVIDENCE
|
|
21
|
+
END
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
CREATE AGENT CONTEXT local_operator
|
|
2
|
+
BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
|
|
3
|
+
BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
|
|
4
|
+
TENANT BINDING tenant_id
|
|
5
|
+
PRINCIPAL BINDING principal
|
|
6
|
+
END
|
|
7
|
+
|
|
8
|
+
CREATE CAPABILITY cases.close_high_risk
|
|
9
|
+
DESCRIPTION 'Close active high-risk support cases within reviewed row and value caps.'
|
|
10
|
+
RETURNS HINT 'Returns a proposal for the exact reviewed set; source rows remain unchanged.'
|
|
11
|
+
USING CONTEXT local_operator
|
|
12
|
+
SOURCE support_db
|
|
13
|
+
ON public.support_cases
|
|
14
|
+
PRIMARY KEY id
|
|
15
|
+
TENANT KEY tenant_id
|
|
16
|
+
CONFLICT GUARD version
|
|
17
|
+
LOOKUP reason BY id
|
|
18
|
+
ARG reason STRING REQUIRED MAX LENGTH 100
|
|
19
|
+
ALLOW READ id, tenant_id, risk_level, case_status, exposure_cents, version
|
|
20
|
+
REQUIRE EVIDENCE
|
|
21
|
+
PROPOSE ACTION close_high_risk UPDATE SET
|
|
22
|
+
SELECT WHERE risk_level = 'high' AND case_status = 'active'
|
|
23
|
+
MAX ROWS 10
|
|
24
|
+
MAX TOTAL exposure_cents BEFORE 50000
|
|
25
|
+
ALLOW WRITE case_status
|
|
26
|
+
PATCH case_status = 'closed'
|
|
27
|
+
ADVANCE VERSION version USING INTEGER INCREMENT
|
|
28
|
+
APPROVAL ROLE support_manager
|
|
29
|
+
WRITEBACK DIRECT SQL
|
|
30
|
+
END
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
CREATE AGENT CONTEXT care_session
|
|
2
|
+
BIND hospital_id FROM HTTP_CLAIM hospital_id REQUIRED
|
|
3
|
+
BIND principal FROM HTTP_CLAIM sub REQUIRED
|
|
4
|
+
TENANT BINDING hospital_id
|
|
5
|
+
PRINCIPAL BINDING principal
|
|
6
|
+
END
|
|
7
|
+
|
|
8
|
+
CREATE CAPABILITY care.inspect_assigned_patient
|
|
9
|
+
DESCRIPTION 'Inspect one patient assigned to the authenticated case manager within the trusted hospital.'
|
|
10
|
+
RETURNS HINT 'Returns reviewed patient fields and evidence only when both tenant and assignee locks match.'
|
|
11
|
+
USING CONTEXT care_session
|
|
12
|
+
SOURCE local_postgres
|
|
13
|
+
ON public.patients
|
|
14
|
+
PRIMARY KEY id
|
|
15
|
+
TENANT KEY hospital_id
|
|
16
|
+
PRINCIPAL SCOPE KEY assigned_to
|
|
17
|
+
LOOKUP patient_id BY id
|
|
18
|
+
ARG patient_id STRING REQUIRED MAX LENGTH 128 DESCRIPTION 'Reviewed patient identifier.'
|
|
19
|
+
ALLOW READ id, hospital_id, display_name, care_status, updated_at
|
|
20
|
+
KEEP OUT assigned_to, diagnosis_notes, insurance_member_id
|
|
21
|
+
REQUIRE EVIDENCE
|
|
22
|
+
MAX ROWS 1
|
|
23
|
+
END
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "synapsor.protocol-manifest.v1",
|
|
3
3
|
"protocol_set": "database-mcp-writeback",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.1",
|
|
5
5
|
"hash_algorithm": "sha256",
|
|
6
6
|
"note": "This manifest is copied in Synapsor main protocol/MANIFEST.json and synapsor-runner fixtures/protocol/MANIFEST.json. Hashes are over the checked-in JSON artifact bytes.",
|
|
7
7
|
"artifacts": [
|
|
@@ -113,22 +113,22 @@
|
|
|
113
113
|
{
|
|
114
114
|
"kind": "schema",
|
|
115
115
|
"name": "change-set.v1.schema.json",
|
|
116
|
-
"sha256": "
|
|
116
|
+
"sha256": "18f76efd97424efab986b6fb0af87ad0eeafd4314393ed7f83f14afe09d625eb"
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
"kind": "schema",
|
|
120
120
|
"name": "change-set.v2.schema.json",
|
|
121
|
-
"sha256": "
|
|
121
|
+
"sha256": "bd9999361258c5554ffa2791d7c6469beffc5b875e775f5f0c80cea36132eaa4"
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
"kind": "schema",
|
|
125
125
|
"name": "change-set.v3.schema.json",
|
|
126
|
-
"sha256": "
|
|
126
|
+
"sha256": "24a45eb4d9f29ab4cfe408bedeb0216dc29544fe39b515918d0c0f9742bba9cb"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"kind": "schema",
|
|
130
130
|
"name": "compensation-change-set.v1.schema.json",
|
|
131
|
-
"sha256": "
|
|
131
|
+
"sha256": "6353ddd1a030d0cd25c1663c96794d5420bc1002f46aacdef58c346238a90450"
|
|
132
132
|
},
|
|
133
133
|
{
|
|
134
134
|
"kind": "schema",
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
{
|
|
154
154
|
"kind": "schema",
|
|
155
155
|
"name": "inverse-descriptor.v1.schema.json",
|
|
156
|
-
"sha256": "
|
|
156
|
+
"sha256": "6f310b11946196cf8c829bcf5be39864d5e3bd85181ae2a3a277bfa6fd72a553"
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
159
|
"kind": "schema",
|
|
@@ -163,22 +163,22 @@
|
|
|
163
163
|
{
|
|
164
164
|
"kind": "schema",
|
|
165
165
|
"name": "writeback-job.v1.schema.json",
|
|
166
|
-
"sha256": "
|
|
166
|
+
"sha256": "64238559297805e13c04cb8bf71be433e6fb1241594ca021415b1efb95214a01"
|
|
167
167
|
},
|
|
168
168
|
{
|
|
169
169
|
"kind": "schema",
|
|
170
170
|
"name": "writeback-job.v2.schema.json",
|
|
171
|
-
"sha256": "
|
|
171
|
+
"sha256": "68110a5ed5b7867522cf86db8d177d2df3f96a458a4343bb77537bdcf304279b"
|
|
172
172
|
},
|
|
173
173
|
{
|
|
174
174
|
"kind": "schema",
|
|
175
175
|
"name": "writeback-job.v3.schema.json",
|
|
176
|
-
"sha256": "
|
|
176
|
+
"sha256": "3bd46747e737e79bff90dc0496c270bc93d6a913db750ea00486be9a45714831"
|
|
177
177
|
},
|
|
178
178
|
{
|
|
179
179
|
"kind": "schema",
|
|
180
180
|
"name": "writeback-job.v4.schema.json",
|
|
181
|
-
"sha256": "
|
|
181
|
+
"sha256": "2c0d23cdf12f6a0d70c5f38fb4fcc5842f2b6c184ee1a195344ae42f58baf4ca"
|
|
182
182
|
}
|
|
183
183
|
]
|
|
184
184
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synapsor/runner",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.122",
|
|
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",
|
|
@@ -62,7 +62,10 @@
|
|
|
62
62
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
63
63
|
"jose": "6.2.3",
|
|
64
64
|
"mysql2": "^3.11.0",
|
|
65
|
+
"pdf-lib": "1.17.1",
|
|
65
66
|
"pg": "^8.13.0",
|
|
67
|
+
"vscode-languageserver": "9.0.1",
|
|
68
|
+
"vscode-languageserver-textdocument": "1.0.12",
|
|
66
69
|
"zod": "^3.25.0"
|
|
67
70
|
},
|
|
68
71
|
"devDependencies": {
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"required": ["tenant", "allowed_columns", "expected_version"],
|
|
71
71
|
"properties": {
|
|
72
72
|
"tenant": { "$ref": "#/$defs/columnValue" },
|
|
73
|
+
"principal_scope": { "$ref": "#/$defs/principalScope" },
|
|
73
74
|
"allowed_columns": {
|
|
74
75
|
"type": "array",
|
|
75
76
|
"items": { "$ref": "#/$defs/safeIdentifier" },
|
|
@@ -136,6 +137,19 @@
|
|
|
136
137
|
"column": { "$ref": "#/$defs/safeIdentifier" },
|
|
137
138
|
"value": { "$ref": "#/$defs/scalar" }
|
|
138
139
|
}
|
|
140
|
+
},
|
|
141
|
+
"principalScope": {
|
|
142
|
+
"type": "object",
|
|
143
|
+
"additionalProperties": false,
|
|
144
|
+
"required": ["schema_version", "column", "binding", "provider", "value_fingerprint"],
|
|
145
|
+
"properties": {
|
|
146
|
+
"schema_version": { "const": "synapsor.principal-scope.v1" },
|
|
147
|
+
"column": { "$ref": "#/$defs/safeIdentifier" },
|
|
148
|
+
"binding": { "$ref": "#/$defs/safeIdentifier" },
|
|
149
|
+
"provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] },
|
|
150
|
+
"value_fingerprint": { "type": "string", "pattern": "^sha256:.+" },
|
|
151
|
+
"value": { "$ref": "#/$defs/scalar" }
|
|
152
|
+
}
|
|
139
153
|
}
|
|
140
154
|
}
|
|
141
155
|
}
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
"required": ["tenant", "allowed_columns"],
|
|
81
81
|
"properties": {
|
|
82
82
|
"tenant": { "$ref": "#/$defs/columnValue" },
|
|
83
|
+
"principal_scope": { "$ref": "#/$defs/principalScope" },
|
|
83
84
|
"allowed_columns": {
|
|
84
85
|
"type": "array",
|
|
85
86
|
"items": { "$ref": "#/$defs/safeIdentifier" },
|
|
@@ -209,6 +210,19 @@
|
|
|
209
210
|
"value": { "$ref": "#/$defs/scalar" }
|
|
210
211
|
}
|
|
211
212
|
},
|
|
213
|
+
"principalScope": {
|
|
214
|
+
"type": "object",
|
|
215
|
+
"additionalProperties": false,
|
|
216
|
+
"required": ["schema_version", "column", "binding", "provider", "value_fingerprint"],
|
|
217
|
+
"properties": {
|
|
218
|
+
"schema_version": { "const": "synapsor.principal-scope.v1" },
|
|
219
|
+
"column": { "$ref": "#/$defs/safeIdentifier" },
|
|
220
|
+
"binding": { "$ref": "#/$defs/safeIdentifier" },
|
|
221
|
+
"provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] },
|
|
222
|
+
"value_fingerprint": { "$ref": "#/$defs/sha256" },
|
|
223
|
+
"value": { "$ref": "#/$defs/scalar" }
|
|
224
|
+
}
|
|
225
|
+
},
|
|
212
226
|
"versionAdvance": {
|
|
213
227
|
"type": "object",
|
|
214
228
|
"additionalProperties": false,
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"type": "object", "additionalProperties": false, "required": ["tenant", "allowed_columns"],
|
|
38
38
|
"properties": {
|
|
39
39
|
"tenant": { "$ref": "#/$defs/columnValue" },
|
|
40
|
+
"principal_scope": { "$ref": "#/$defs/principalScope" },
|
|
40
41
|
"allowed_columns": { "type": "array", "items": { "$ref": "#/$defs/safeIdentifier" }, "maxItems": 256, "uniqueItems": true },
|
|
41
42
|
"version_advance": { "$ref": "#/$defs/versionAdvance" }
|
|
42
43
|
}
|
|
@@ -96,6 +97,7 @@
|
|
|
96
97
|
"scalarRecord": { "type": "object", "propertyNames": { "$ref": "#/$defs/safeIdentifier" }, "additionalProperties": { "$ref": "#/$defs/scalar" }, "maxProperties": 256 },
|
|
97
98
|
"setOperation": { "enum": ["set_update", "set_delete", "batch_insert"] },
|
|
98
99
|
"columnValue": { "type": "object", "additionalProperties": false, "required": ["column", "value"], "properties": { "column": { "$ref": "#/$defs/safeIdentifier" }, "value": { "$ref": "#/$defs/scalar" } } },
|
|
100
|
+
"principalScope": { "type": "object", "additionalProperties": false, "required": ["schema_version", "column", "binding", "provider", "value_fingerprint"], "properties": { "schema_version": { "const": "synapsor.principal-scope.v1" }, "column": { "$ref": "#/$defs/safeIdentifier" }, "binding": { "$ref": "#/$defs/safeIdentifier" }, "provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] }, "value_fingerprint": { "$ref": "#/$defs/sha256" }, "value": { "$ref": "#/$defs/scalar" } } },
|
|
99
101
|
"versionAdvance": { "type": "object", "additionalProperties": false, "required": ["column", "strategy"], "properties": { "column": { "$ref": "#/$defs/safeIdentifier" }, "strategy": { "enum": ["integer_increment", "database_generated"] } } },
|
|
100
102
|
"deduplicationComponent": { "type": "object", "additionalProperties": false, "required": ["column", "value", "source"], "properties": { "column": { "$ref": "#/$defs/safeIdentifier" }, "value": { "$ref": "#/$defs/scalar" }, "source": { "enum": ["proposal_id", "trusted_tenant", "fixed"] } } },
|
|
101
103
|
"deduplication": { "type": "object", "additionalProperties": false, "required": ["components"], "properties": { "components": { "type": "array", "items": { "$ref": "#/$defs/deduplicationComponent" }, "minItems": 1, "maxItems": 8 } } },
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"source": { "type": "object", "additionalProperties": false, "required": ["kind", "source_id", "schema", "table", "primary_key"], "properties": { "kind": { "enum": ["external_postgres", "external_mysql"] }, "source_id": { "type": "string", "minLength": 1 }, "schema": { "$ref": "#/$defs/identifier" }, "table": { "$ref": "#/$defs/identifier" }, "primary_key": { "type": "object", "additionalProperties": false, "required": ["column"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "value": { "$ref": "#/$defs/scalar" } } } } },
|
|
17
17
|
"before": { "$ref": "#/$defs/record" }, "patch": { "$ref": "#/$defs/record" }, "after": { "$ref": "#/$defs/record" },
|
|
18
18
|
"compensation": { "type": "object", "additionalProperties": false, "required": ["descriptor", "forward_receipt_hash"], "properties": { "descriptor": { "$ref": "inverse-descriptor.v1.schema.json" }, "forward_receipt_hash": { "$ref": "#/$defs/sha256" } } },
|
|
19
|
-
"guards": { "type": "object", "additionalProperties": false, "required": ["tenant", "allowed_columns"], "properties": { "tenant": { "$ref": "#/$defs/columnValue" }, "allowed_columns": { "type": "array", "items": { "$ref": "#/$defs/identifier" }, "maxItems": 256, "uniqueItems": true } } },
|
|
19
|
+
"guards": { "type": "object", "additionalProperties": false, "required": ["tenant", "allowed_columns"], "properties": { "tenant": { "$ref": "#/$defs/columnValue" }, "principal_scope": { "$ref": "#/$defs/principalScope" }, "allowed_columns": { "type": "array", "items": { "$ref": "#/$defs/identifier" }, "maxItems": 256, "uniqueItems": true } } },
|
|
20
20
|
"evidence": { "type": "object", "required": ["bundle_id", "query_fingerprint", "items"], "properties": { "bundle_id": { "type": "string", "minLength": 1 }, "query_fingerprint": { "$ref": "#/$defs/sha256" }, "items": { "type": "array", "maxItems": 100 } } },
|
|
21
21
|
"approval": { "type": "object", "required": ["status", "mode"], "properties": { "status": { "enum": ["pending", "approved", "rejected", "canceled"] }, "mode": { "enum": ["human", "operator"] }, "required_role": { "type": "string", "minLength": 1 }, "required_approvals": { "type": "integer", "minimum": 1, "maximum": 10 } } },
|
|
22
22
|
"writeback": { "type": "object", "additionalProperties": false, "required": ["status", "mode", "executor"], "properties": { "status": { "const": "not_applied" }, "mode": { "const": "trusted_worker_required" }, "executor": { "const": "sql_update" } } },
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"$defs": {
|
|
28
28
|
"identifier": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }, "sha256": { "type": "string", "pattern": "^sha256:.+" }, "scalar": { "type": ["string", "number", "boolean", "null"] },
|
|
29
29
|
"record": { "type": "object", "propertyNames": { "$ref": "#/$defs/identifier" }, "additionalProperties": { "$ref": "#/$defs/scalar" }, "maxProperties": 256 },
|
|
30
|
-
"columnValue": { "type": "object", "additionalProperties": false, "required": ["column", "value"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "value": { "$ref": "#/$defs/scalar" } } }
|
|
30
|
+
"columnValue": { "type": "object", "additionalProperties": false, "required": ["column", "value"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "value": { "$ref": "#/$defs/scalar" } } },
|
|
31
|
+
"principalScope": { "type": "object", "additionalProperties": false, "required": ["schema_version", "column", "binding", "provider", "value_fingerprint"], "properties": { "schema_version": { "const": "synapsor.principal-scope.v1" }, "column": { "$ref": "#/$defs/identifier" }, "binding": { "$ref": "#/$defs/identifier" }, "provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] }, "value_fingerprint": { "$ref": "#/$defs/sha256" }, "value": { "$ref": "#/$defs/scalar" } } }
|
|
31
32
|
}
|
|
32
33
|
}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"properties": { "source_id": { "type": "string", "minLength": 1 }, "schema": { "$ref": "#/$defs/identifier" }, "table": { "$ref": "#/$defs/identifier" }, "primary_key_column": { "$ref": "#/$defs/identifier" } }
|
|
20
20
|
},
|
|
21
21
|
"tenant_guard": { "$ref": "#/$defs/columnValue" },
|
|
22
|
+
"principal_scope": { "$ref": "#/$defs/principalScope" },
|
|
22
23
|
"allowed_columns": { "type": "array", "items": { "$ref": "#/$defs/identifier" }, "maxItems": 256, "uniqueItems": true },
|
|
23
24
|
"members": { "type": "array", "minItems": 1, "maxItems": 100, "items": { "$ref": "#/$defs/member" } },
|
|
24
25
|
"max_rows": { "type": "integer", "minimum": 1, "maximum": 100 },
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
"scalar": { "type": ["string", "number", "boolean", "null"] },
|
|
39
40
|
"record": { "type": "object", "propertyNames": { "$ref": "#/$defs/identifier" }, "additionalProperties": { "$ref": "#/$defs/scalar" }, "maxProperties": 256 },
|
|
40
41
|
"columnValue": { "type": "object", "additionalProperties": false, "required": ["column", "value"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "value": { "$ref": "#/$defs/scalar" } } },
|
|
42
|
+
"principalScope": { "type": "object", "additionalProperties": false, "required": ["schema_version", "column", "binding", "provider", "value_fingerprint"], "properties": { "schema_version": { "const": "synapsor.principal-scope.v1" }, "column": { "$ref": "#/$defs/identifier" }, "binding": { "$ref": "#/$defs/identifier" }, "provider": { "enum": ["environment", "http_claims", "cloud_session", "static_dev"] }, "value_fingerprint": { "type": "string", "pattern": "^sha256:.+" }, "value": { "$ref": "#/$defs/scalar" } } },
|
|
41
43
|
"member": { "type": "object", "additionalProperties": false, "required": ["primary_key", "expected_state"], "properties": { "primary_key": { "$ref": "#/$defs/columnValue" }, "expected_state": { "$ref": "#/$defs/record" }, "restore_values": { "$ref": "#/$defs/record" } } },
|
|
42
44
|
"versionAdvance": { "type": "object", "additionalProperties": false, "required": ["column", "strategy"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "strategy": { "enum": ["integer_increment", "database_generated"] } } },
|
|
43
45
|
"aggregateBound": { "type": "object", "additionalProperties": false, "required": ["column", "measure", "maximum", "actual"], "properties": { "column": { "$ref": "#/$defs/identifier" }, "measure": { "enum": ["before", "after", "absolute_delta"] }, "maximum": { "type": "number", "minimum": 0 }, "actual": { "type": "number", "minimum": 0 } } },
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://schemas.synapsor.ai/synapsor.contract-tests.schema.json",
|
|
4
|
+
"title": "Synapsor adopter contract conformance manifest",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["version", "tests"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": { "type": "string", "minLength": 1 },
|
|
10
|
+
"version": { "const": 1 },
|
|
11
|
+
"name": { "type": "string", "minLength": 1 },
|
|
12
|
+
"tests": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"minItems": 1,
|
|
15
|
+
"items": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"required": ["id", "kind", "capability"],
|
|
19
|
+
"properties": {
|
|
20
|
+
"id": { "type": "string", "minLength": 1 },
|
|
21
|
+
"kind": {
|
|
22
|
+
"enum": ["tool_allow", "tool_deny", "cross_principal_deny", "hide_fields", "argument_constraint", "transition_guard", "set_cap", "source_unchanged_before_approval", "operator_boundary"]
|
|
23
|
+
},
|
|
24
|
+
"capability": { "type": "string", "minLength": 1 },
|
|
25
|
+
"args": { "type": "object" },
|
|
26
|
+
"trusted_context": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"required": ["tenant_id", "principal"],
|
|
30
|
+
"properties": {
|
|
31
|
+
"tenant_id": { "type": "string", "minLength": 1 },
|
|
32
|
+
"principal": { "type": "string", "minLength": 1 },
|
|
33
|
+
"provenance": { "enum": ["environment", "static_dev", "http_claims", "cloud_session"] }
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"other_trusted_context": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"required": ["tenant_id", "principal"],
|
|
40
|
+
"properties": {
|
|
41
|
+
"tenant_id": { "type": "string", "minLength": 1 },
|
|
42
|
+
"principal": { "type": "string", "minLength": 1 },
|
|
43
|
+
"provenance": { "enum": ["environment", "static_dev", "http_claims", "cloud_session"] }
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"expected_code": { "type": "string", "minLength": 1 },
|
|
47
|
+
"fields": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 }, "uniqueItems": true },
|
|
48
|
+
"argument": { "type": "string", "minLength": 1 },
|
|
49
|
+
"expected": { "type": "object" }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|