@crediolabs/policy-synth 0.1.18 → 0.3.0
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/README.md +6 -5
- package/dist/adapters/interpreter/adapter.d.ts +19 -25
- package/dist/adapters/interpreter/adapter.js +54 -487
- package/dist/adapters/interpreter/index.d.ts +1 -1
- package/dist/adapters/interpreter/index.js +1 -1
- package/dist/adapters/oz/adapter.js +1 -15
- package/dist/errors.d.ts +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.js +1 -4
- package/dist/install/build-add-context-rule.d.ts +3 -11
- package/dist/install/build-add-context-rule.js +2 -97
- package/dist/install/build-install-policy.d.ts +4 -53
- package/dist/install/build-install-policy.js +44 -123
- package/dist/ir/index.d.ts +1 -1
- package/dist/ir/types.d.ts +7 -76
- package/dist/ir/types.js +0 -2
- package/dist/predicate/decode.d.ts +1 -1
- package/dist/predicate/decode.js +2 -70
- package/dist/predicate/encode.js +45 -229
- package/dist/predicate/from-json.js +1 -42
- package/dist/record/decode.js +3 -8
- package/dist/review-card/builder.d.ts +4 -3
- package/dist/review-card/builder.js +18 -162
- package/dist/review-card/cross-check.js +2 -105
- package/dist/review-card/render-leaf.d.ts +4 -0
- package/dist/review-card/render-leaf.js +47 -0
- package/dist/run/index.d.ts +35 -53
- package/dist/run/index.js +115 -156
- package/dist/run/schemas.d.ts +168 -1650
- package/dist/run/schemas.js +36 -199
- package/dist/seams/types.d.ts +0 -2
- package/dist/simulate/deny-cases.d.ts +26 -0
- package/dist/simulate/deny-cases.js +282 -0
- package/dist/simulate/evaluate.d.ts +18 -0
- package/dist/simulate/evaluate.js +271 -0
- package/dist/simulate/index.d.ts +4 -0
- package/dist/simulate/index.js +8 -0
- package/dist/synth/compose-from-recording.d.ts +24 -51
- package/dist/synth/compose-from-recording.js +120 -282
- package/dist/synth/deny-cases.d.ts +5 -7
- package/dist/synth/deny-cases.js +23 -373
- package/dist/synth/evaluate.d.ts +0 -21
- package/dist/synth/evaluate.js +56 -336
- package/dist/synth/index.d.ts +0 -5
- package/dist/synth/index.js +0 -5
- package/dist/synth/permit-context.d.ts +2 -9
- package/dist/synth/permit-context.js +1 -82
- package/dist/synth/synthesize-from-recording.d.ts +1 -29
- package/dist/synth/synthesize-from-recording.js +41 -356
- package/dist/types.d.ts +8 -60
- package/dist/types.js +5 -2
- package/dist/verify/simulate.d.ts +1 -14
- package/dist/verify/simulate.js +2 -88
- package/dist/verify/verify.d.ts +1 -7
- package/dist/verify/verify.js +0 -8
- package/dist-cjs/adapters/interpreter/adapter.d.ts +19 -25
- package/dist-cjs/adapters/interpreter/adapter.js +56 -489
- package/dist-cjs/adapters/interpreter/index.d.ts +1 -1
- package/dist-cjs/adapters/interpreter/index.js +1 -2
- package/dist-cjs/adapters/oz/adapter.js +1 -15
- package/dist-cjs/errors.d.ts +1 -1
- package/dist-cjs/index.d.ts +1 -4
- package/dist-cjs/index.js +1 -4
- package/dist-cjs/install/build-add-context-rule.d.ts +3 -11
- package/dist-cjs/install/build-add-context-rule.js +1 -96
- package/dist-cjs/install/build-install-policy.d.ts +4 -53
- package/dist-cjs/install/build-install-policy.js +44 -122
- package/dist-cjs/ir/index.d.ts +1 -1
- package/dist-cjs/ir/types.d.ts +7 -76
- package/dist-cjs/ir/types.js +0 -2
- package/dist-cjs/predicate/decode.d.ts +1 -1
- package/dist-cjs/predicate/decode.js +2 -70
- package/dist-cjs/predicate/encode.js +45 -229
- package/dist-cjs/predicate/from-json.js +1 -42
- package/dist-cjs/record/decode.js +3 -8
- package/dist-cjs/review-card/builder.d.ts +4 -3
- package/dist-cjs/review-card/builder.js +23 -167
- package/dist-cjs/review-card/cross-check.js +7 -110
- package/dist-cjs/review-card/render-leaf.d.ts +4 -0
- package/dist-cjs/review-card/render-leaf.js +52 -0
- package/dist-cjs/run/index.d.ts +35 -53
- package/dist-cjs/run/index.js +116 -162
- package/dist-cjs/run/schemas.d.ts +168 -1650
- package/dist-cjs/run/schemas.js +37 -200
- package/dist-cjs/seams/types.d.ts +0 -2
- package/dist-cjs/simulate/deny-cases.d.ts +26 -0
- package/dist-cjs/simulate/deny-cases.js +286 -0
- package/dist-cjs/simulate/evaluate.d.ts +18 -0
- package/dist-cjs/simulate/evaluate.js +274 -0
- package/dist-cjs/simulate/index.d.ts +4 -0
- package/dist-cjs/simulate/index.js +13 -0
- package/dist-cjs/synth/compose-from-recording.d.ts +24 -51
- package/dist-cjs/synth/compose-from-recording.js +120 -282
- package/dist-cjs/synth/deny-cases.d.ts +5 -7
- package/dist-cjs/synth/deny-cases.js +23 -374
- package/dist-cjs/synth/evaluate.d.ts +0 -21
- package/dist-cjs/synth/evaluate.js +57 -337
- package/dist-cjs/synth/index.d.ts +0 -5
- package/dist-cjs/synth/index.js +1 -11
- package/dist-cjs/synth/permit-context.d.ts +2 -9
- package/dist-cjs/synth/permit-context.js +1 -82
- package/dist-cjs/synth/synthesize-from-recording.d.ts +1 -29
- package/dist-cjs/synth/synthesize-from-recording.js +39 -354
- package/dist-cjs/types.d.ts +8 -60
- package/dist-cjs/types.js +6 -3
- package/dist-cjs/verify/simulate.d.ts +1 -14
- package/dist-cjs/verify/simulate.js +2 -88
- package/dist-cjs/verify/verify.d.ts +1 -7
- package/dist-cjs/verify/verify.js +0 -8
- package/package.json +4 -4
- package/src/adapters/interpreter/adapter.ts +76 -572
- package/src/errors.ts +0 -19
- package/src/index.ts +1 -4
- package/src/install/build-add-context-rule.ts +4 -127
- package/src/install/build-install-policy.ts +93 -214
- package/src/predicate/decode.ts +2 -70
- package/src/predicate/encode.ts +49 -261
- package/src/predicate/from-json.ts +1 -43
- package/src/record/decode.ts +3 -8
- package/src/review-card/builder.ts +19 -168
- package/src/review-card/cross-check.ts +3 -105
- package/src/review-card/render-leaf.ts +48 -0
- package/src/run/index.ts +130 -186
- package/src/run/schemas.ts +38 -214
- package/src/simulate/deny-cases.ts +334 -0
- package/src/simulate/evaluate.ts +284 -0
- package/src/simulate/index.ts +11 -0
- package/src/synth/compose-from-recording.ts +148 -347
- package/src/synth/index.ts +0 -13
- package/src/synth/synthesize-from-recording.ts +43 -456
- package/src/types.ts +13 -49
- package/dist/install/build-install-predicate.d.ts +0 -96
- package/dist/install/build-install-predicate.js +0 -444
- package/dist-cjs/install/build-install-predicate.d.ts +0 -96
- package/dist-cjs/install/build-install-predicate.js +0 -479
- package/src/adapters/interpreter/index.ts +0 -8
- package/src/adapters/oz/adapter.ts +0 -376
- package/src/adapters/oz/index.ts +0 -9
- package/src/codegen/compile-gate.ts +0 -167
- package/src/codegen/index.ts +0 -17
- package/src/codegen/template.ts +0 -165
- package/src/ir/index.ts +0 -13
- package/src/ir/types.ts +0 -132
- package/src/mandate/index.ts +0 -4
- package/src/mandate/to-ir.ts +0 -71
- package/src/mandate/types.ts +0 -21
- package/src/seams/index.ts +0 -11
- package/src/seams/types.ts +0 -81
- package/src/synth/deny-cases.ts +0 -663
- package/src/synth/evaluate.ts +0 -613
- package/src/synth/harness.ts +0 -68
- package/src/synth/minimize.ts +0 -48
- package/src/synth/permit-context.ts +0 -136
- package/src/synth/predicate-literals.ts +0 -27
- package/src/synth/synthesize-from-mandate.ts +0 -82
- package/src/verify/envelope.ts +0 -28
- package/src/verify/index.ts +0 -5
- package/src/verify/simulate.ts +0 -311
- package/src/verify/verify.ts +0 -243
package/dist-cjs/run/index.js
CHANGED
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
// No business logic. No retries. No session state. The same call shape can
|
|
19
19
|
// drive the CLI (which calls into the same core directly without MCP).
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.
|
|
21
|
+
exports.ToolErrorSchema = exports.TESTNET_RPC_URL = exports.SynthesizePolicyInputSchema = exports.RPC_URL_BY_NETWORK = exports.RevokePolicyInputSchema = exports.RecordTransactionInputSchema = exports.RecordedTransactionSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.PINNED_INTERPRETER_MAINNET_ADDRESS = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = exports.NetworkSchema = exports.MAINNET_RPC_URL = exports.InterpreterOptionsSchema = exports.InstallPolicyInputSchema = exports.GetInterpreterInfoInputSchema = exports.ComposeUserResponsesSchema = void 0;
|
|
22
22
|
exports.runRecordTransaction = runRecordTransaction;
|
|
23
23
|
exports.runSynthesizePolicy = runSynthesizePolicy;
|
|
24
|
-
exports.runSimulatePolicy = runSimulatePolicy;
|
|
25
|
-
exports.runVerifyPolicy = runVerifyPolicy;
|
|
26
24
|
exports.runInstallPolicy = runInstallPolicy;
|
|
27
25
|
exports.runRevokePolicy = runRevokePolicy;
|
|
26
|
+
exports.runSimulatePolicy = runSimulatePolicy;
|
|
27
|
+
exports.runVerifyPolicy = runVerifyPolicy;
|
|
28
28
|
exports.runGetInterpreterInfo = runGetInterpreterInfo;
|
|
29
29
|
exports.caughtError = caughtError;
|
|
30
30
|
const node_crypto_1 = require("node:crypto");
|
|
@@ -32,7 +32,7 @@ const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
|
32
32
|
const index_ts_1 = require("../index.js");
|
|
33
33
|
const build_install_policy_ts_1 = require("../install/build-install-policy.js");
|
|
34
34
|
const get_interpreter_info_ts_1 = require("../install/get-interpreter-info.js");
|
|
35
|
-
const index_ts_2 = require("../
|
|
35
|
+
const index_ts_2 = require("../simulate/index.js");
|
|
36
36
|
const schemas_ts_1 = require("./schemas.js");
|
|
37
37
|
// Re-export the underlying Zod schemas so the MCP package (and any other
|
|
38
38
|
// downstream consumer) can import the canonical input shapes from the same
|
|
@@ -44,10 +44,7 @@ Object.defineProperty(exports, "GetInterpreterInfoInputSchema", { enumerable: tr
|
|
|
44
44
|
Object.defineProperty(exports, "InstallPolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.InstallPolicyInputSchema; } });
|
|
45
45
|
Object.defineProperty(exports, "InterpreterOptionsSchema", { enumerable: true, get: function () { return schemas_ts_2.InterpreterOptionsSchema; } });
|
|
46
46
|
Object.defineProperty(exports, "MAINNET_RPC_URL", { enumerable: true, get: function () { return schemas_ts_2.MAINNET_RPC_URL; } });
|
|
47
|
-
Object.defineProperty(exports, "MandateSpecSchema", { enumerable: true, get: function () { return schemas_ts_2.MandateSpecSchema; } });
|
|
48
47
|
Object.defineProperty(exports, "NetworkSchema", { enumerable: true, get: function () { return schemas_ts_2.NetworkSchema; } });
|
|
49
|
-
Object.defineProperty(exports, "OraclePriceFixtureSchema", { enumerable: true, get: function () { return schemas_ts_2.OraclePriceFixtureSchema; } });
|
|
50
|
-
Object.defineProperty(exports, "OzAdapterConfigSchema", { enumerable: true, get: function () { return schemas_ts_2.OzAdapterConfigSchema; } });
|
|
51
48
|
Object.defineProperty(exports, "PINNED_INTERPRETER_ADDRESS_BY_NETWORK", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_ADDRESS_BY_NETWORK; } });
|
|
52
49
|
Object.defineProperty(exports, "PINNED_INTERPRETER_GRAMMAR_VERSION", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_GRAMMAR_VERSION; } });
|
|
53
50
|
Object.defineProperty(exports, "PINNED_INTERPRETER_MAINNET_ADDRESS", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_MAINNET_ADDRESS; } });
|
|
@@ -59,11 +56,9 @@ Object.defineProperty(exports, "RecordedTransactionSchema", { enumerable: true,
|
|
|
59
56
|
Object.defineProperty(exports, "RecordTransactionInputSchema", { enumerable: true, get: function () { return schemas_ts_2.RecordTransactionInputSchema; } });
|
|
60
57
|
Object.defineProperty(exports, "RevokePolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.RevokePolicyInputSchema; } });
|
|
61
58
|
Object.defineProperty(exports, "RPC_URL_BY_NETWORK", { enumerable: true, get: function () { return schemas_ts_2.RPC_URL_BY_NETWORK; } });
|
|
62
|
-
Object.defineProperty(exports, "SimulatePolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.SimulatePolicyInputSchema; } });
|
|
63
59
|
Object.defineProperty(exports, "SynthesizePolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.SynthesizePolicyInputSchema; } });
|
|
64
60
|
Object.defineProperty(exports, "TESTNET_RPC_URL", { enumerable: true, get: function () { return schemas_ts_2.TESTNET_RPC_URL; } });
|
|
65
61
|
Object.defineProperty(exports, "ToolErrorSchema", { enumerable: true, get: function () { return schemas_ts_2.ToolErrorSchema; } });
|
|
66
|
-
Object.defineProperty(exports, "VerifyPolicyInputSchema", { enumerable: true, get: function () { return schemas_ts_2.VerifyPolicyInputSchema; } });
|
|
67
62
|
/** Map every tool name to its canonical domain error code. Replaces a 7-way
|
|
68
63
|
* if/else so adding a tool adds one line here rather than a new branch in
|
|
69
64
|
* each envelope call. */
|
|
@@ -90,10 +85,7 @@ const TOOL_ERROR_CODE = {
|
|
|
90
85
|
async function runRecordTransaction(raw) {
|
|
91
86
|
const parsed = schemas_ts_1.RecordTransactionInputSchema.safeParse(raw);
|
|
92
87
|
if (!parsed.success) {
|
|
93
|
-
return {
|
|
94
|
-
ok: false,
|
|
95
|
-
error: validationError('record_transaction', parsed.error.issues),
|
|
96
|
-
};
|
|
88
|
+
return { ok: false, error: validationError('record_transaction', parsed.error.issues) };
|
|
97
89
|
}
|
|
98
90
|
const input = parsed.data;
|
|
99
91
|
// Strip the wire-only `confidenceOverride` and pass the rest straight through.
|
|
@@ -109,14 +101,10 @@ async function runRecordTransaction(raw) {
|
|
|
109
101
|
return await (0, index_ts_1.recordTransaction)(coreInput);
|
|
110
102
|
}
|
|
111
103
|
catch (e) {
|
|
112
|
-
return
|
|
113
|
-
ok: false,
|
|
114
|
-
error: caughtError('record_transaction', 'RECORDING_FAILED', e),
|
|
115
|
-
};
|
|
104
|
+
return toolFailure('record_transaction', e);
|
|
116
105
|
}
|
|
117
106
|
}
|
|
118
107
|
/** `synthesize_policy` body - discriminated union on `source`:
|
|
119
|
-
* - `mandate` -> synthesizeFromMandate
|
|
120
108
|
* - `recording` -> synthesizeFromRecording
|
|
121
109
|
* Exposing BOTH front-ends through ONE tool keeps the MCP surface tiny while
|
|
122
110
|
* letting the agent pick the deterministic or the inferred path. The CLI
|
|
@@ -130,21 +118,10 @@ async function runRecordTransaction(raw) {
|
|
|
130
118
|
async function runSynthesizePolicy(raw) {
|
|
131
119
|
const parsed = schemas_ts_1.SynthesizePolicyInputSchema.safeParse(raw);
|
|
132
120
|
if (!parsed.success) {
|
|
133
|
-
return {
|
|
134
|
-
ok: false,
|
|
135
|
-
error: validationError('synthesize_policy', parsed.error.issues),
|
|
136
|
-
};
|
|
121
|
+
return { ok: false, error: validationError('synthesize_policy', parsed.error.issues) };
|
|
137
122
|
}
|
|
138
123
|
const input = parsed.data;
|
|
139
|
-
const ozConfig = resolveOzConfig(input);
|
|
140
124
|
try {
|
|
141
|
-
if (input.source === 'mandate') {
|
|
142
|
-
// Zod's optional fields widen to `T | undefined`, which the core's
|
|
143
|
-
// exact-optional MandateSpec rejects; the schema already validated the
|
|
144
|
-
// shape, so assert it (same pattern as the recordedTx cast below).
|
|
145
|
-
return await (0, index_ts_1.synthesizeFromMandate)(input.mandate, ozConfig, input.explain === true ? { explain: true } : {});
|
|
146
|
-
}
|
|
147
|
-
// recording source
|
|
148
125
|
const recorded = input.recordedTx;
|
|
149
126
|
return await (0, index_ts_1.synthesizeFromRecording)(recorded, {
|
|
150
127
|
network: input.network,
|
|
@@ -154,112 +131,16 @@ async function runSynthesizePolicy(raw) {
|
|
|
154
131
|
: {}),
|
|
155
132
|
...(input.interpreter !== undefined ? { interpreter: input.interpreter } : {}),
|
|
156
133
|
...(input.explain === true ? { explain: true } : {}),
|
|
157
|
-
}, ozConfig);
|
|
158
|
-
}
|
|
159
|
-
catch (e) {
|
|
160
|
-
return {
|
|
161
|
-
ok: false,
|
|
162
|
-
error: caughtError('synthesize_policy', 'SYNTHESIS_ERROR', e),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
function resolveOzConfig(input) {
|
|
167
|
-
if (input.ozConfig)
|
|
168
|
-
return input.ozConfig;
|
|
169
|
-
// The mandate path is network-agnostic; fall back to mainnet so the
|
|
170
|
-
// placeholder OZ instance addresses are deterministic.
|
|
171
|
-
return (0, index_ts_1.placeholderOzConfig)('mainnet');
|
|
172
|
-
}
|
|
173
|
-
/** `simulate_policy` body - thin wrapper over `simulatePolicy`. The engine
|
|
174
|
-
* already returns fail-closed `{ok:false, error}` for runtime failures
|
|
175
|
-
* (SIMULATION_ERROR), so the try/catch envelope is for raw SDK throws
|
|
176
|
-
* only - same pattern as the other two wrappers. The predicate is
|
|
177
|
-
* passed inline (stateless by design; no `proposed_policy_id` lookup). */
|
|
178
|
-
async function runSimulatePolicy(raw) {
|
|
179
|
-
const parsed = schemas_ts_1.SimulatePolicyInputSchema.safeParse(raw);
|
|
180
|
-
if (!parsed.success) {
|
|
181
|
-
return {
|
|
182
|
-
ok: false,
|
|
183
|
-
error: validationError('simulate_policy', parsed.error.issues),
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
const input = parsed.data;
|
|
187
|
-
try {
|
|
188
|
-
// The recursive PredicateNodeSchema + ContractInvocationSchema are
|
|
189
|
-
// typed `z.ZodType<unknown>` to survive TS's circular inference; the
|
|
190
|
-
// engine wants typed `PredicateNode | null` + `RecordedTransaction`.
|
|
191
|
-
// The schema already validated the shape, so assert through the
|
|
192
|
-
// unknown back to the core types. Same pattern as the recordedTx
|
|
193
|
-
// cast in `runSynthesizePolicy`.
|
|
194
|
-
return (0, index_ts_2.simulatePolicy)(input.predicate, input.permitTx, {
|
|
195
|
-
...(input.validUntilLedger !== undefined
|
|
196
|
-
? { validUntilLedger: input.validUntilLedger }
|
|
197
|
-
: {}),
|
|
198
|
-
...(input.oraclePricesByAsset !== undefined
|
|
199
|
-
? { oraclePricesByAsset: input.oraclePricesByAsset }
|
|
200
|
-
: {}),
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
catch (e) {
|
|
204
|
-
return {
|
|
205
|
-
ok: false,
|
|
206
|
-
error: caughtError('simulate_policy', 'SIMULATION_ERROR', e),
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
/** `verify_policy` body - thin wrapper over `verifyPolicy`. The engine
|
|
211
|
-
* already returns `{ok:false, error}` with code VERIFICATION_FAILED when
|
|
212
|
-
* the minimality check fails; the try/catch envelope is for raw SDK
|
|
213
|
-
* throws only. Mirrors `runSimulatePolicy` exactly. */
|
|
214
|
-
async function runVerifyPolicy(raw) {
|
|
215
|
-
const parsed = schemas_ts_1.VerifyPolicyInputSchema.safeParse(raw);
|
|
216
|
-
if (!parsed.success) {
|
|
217
|
-
return {
|
|
218
|
-
ok: false,
|
|
219
|
-
error: validationError('verify_policy', parsed.error.issues),
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
const input = parsed.data;
|
|
223
|
-
try {
|
|
224
|
-
// Same cast as runSimulatePolicy: the recursive schemas are typed
|
|
225
|
-
// `unknown`; the engine wants typed `PredicateNode` +
|
|
226
|
-
// `RecordedTransaction`. The schema already validated the shape.
|
|
227
|
-
return (0, index_ts_2.verifyPolicy)(input.predicate, input.permitTx, {
|
|
228
|
-
...(input.validUntilLedger !== undefined ? { validUntilLedger: input.validUntilLedger } : {}),
|
|
229
|
-
...(input.oraclePricesByAsset !== undefined
|
|
230
|
-
? { oraclePricesByAsset: input.oraclePricesByAsset }
|
|
231
|
-
: {}),
|
|
232
134
|
});
|
|
233
135
|
}
|
|
234
136
|
catch (e) {
|
|
235
|
-
return
|
|
236
|
-
ok: false,
|
|
237
|
-
error: caughtError('verify_policy', 'VERIFICATION_FAILED', e),
|
|
238
|
-
};
|
|
137
|
+
return toolFailure('synthesize_policy', e);
|
|
239
138
|
}
|
|
240
139
|
}
|
|
241
|
-
/** `install_policy` body - thin wrapper over `buildInstallPolicyXdr`.
|
|
242
|
-
* Returns the unsigned Soroban transaction envelope (base64 XDR) the
|
|
243
|
-
* wallet signs. The wallet signature IS the user-confirmation step - no
|
|
244
|
-
* `action_id` two-call pair (the server is stateless, see server.ts:10-12).
|
|
245
|
-
* One call installs the policy outright: `add_context_rule` carries the
|
|
246
|
-
* predicate to the interpreter in its `policies` install_param, so no
|
|
247
|
-
* separate `interpreter.install` call is needed or possible.
|
|
248
|
-
*
|
|
249
|
-
* Default-deny: an interpreter policy address other than the pinned
|
|
250
|
-
* interpreter for the selected network is REFUSED (the smart account
|
|
251
|
-
* would delegate to an interpreter the caller controls); the same
|
|
252
|
-
* applies to a non-pinned RPC URL (the auth nonce the wallet signs
|
|
253
|
-
* comes from the RPC). Both gates accept an explicit opt-in flag.
|
|
254
|
-
* Pin selection follows `input.network` (defaults to `testnet` so the
|
|
255
|
-
* pre-mainnet callers keep working unchanged). */
|
|
256
140
|
async function runInstallPolicy(raw) {
|
|
257
141
|
const parsed = schemas_ts_1.InstallPolicyInputSchema.safeParse(raw);
|
|
258
142
|
if (!parsed.success) {
|
|
259
|
-
return {
|
|
260
|
-
ok: false,
|
|
261
|
-
error: validationError('install_policy', parsed.error.issues),
|
|
262
|
-
};
|
|
143
|
+
return { ok: false, error: validationError('install_policy', parsed.error.issues) };
|
|
263
144
|
}
|
|
264
145
|
const input = parsed.data;
|
|
265
146
|
const network = input.network ?? 'testnet';
|
|
@@ -279,10 +160,7 @@ async function runInstallPolicy(raw) {
|
|
|
279
160
|
rpcClient = buildRpcClientFromInput(input.rpcUrl, network);
|
|
280
161
|
}
|
|
281
162
|
catch (e) {
|
|
282
|
-
return
|
|
283
|
-
ok: false,
|
|
284
|
-
error: caughtError('install_policy', 'INSTALL_BUILD_FAILED', e),
|
|
285
|
-
};
|
|
163
|
+
return toolFailure('install_policy', e);
|
|
286
164
|
}
|
|
287
165
|
try {
|
|
288
166
|
const interpreterPolicy = input.rule.policies.find((p) => p.kind === 'interpreter');
|
|
@@ -304,10 +182,7 @@ async function runInstallPolicy(raw) {
|
|
|
304
182
|
return { ok: true, data: result };
|
|
305
183
|
}
|
|
306
184
|
catch (e) {
|
|
307
|
-
return
|
|
308
|
-
ok: false,
|
|
309
|
-
error: caughtError('install_policy', 'INSTALL_BUILD_FAILED', e),
|
|
310
|
-
};
|
|
185
|
+
return toolFailure('install_policy', e);
|
|
311
186
|
}
|
|
312
187
|
}
|
|
313
188
|
/** `revoke_policy` body - thin wrapper over `buildRevokePolicyXdr`.
|
|
@@ -322,10 +197,7 @@ async function runInstallPolicy(raw) {
|
|
|
322
197
|
async function runRevokePolicy(raw) {
|
|
323
198
|
const parsed = schemas_ts_1.RevokePolicyInputSchema.safeParse(raw);
|
|
324
199
|
if (!parsed.success) {
|
|
325
|
-
return {
|
|
326
|
-
ok: false,
|
|
327
|
-
error: validationError('revoke_policy', parsed.error.issues),
|
|
328
|
-
};
|
|
200
|
+
return { ok: false, error: validationError('revoke_policy', parsed.error.issues) };
|
|
329
201
|
}
|
|
330
202
|
const input = parsed.data;
|
|
331
203
|
const network = input.network ?? 'testnet';
|
|
@@ -339,10 +211,7 @@ async function runRevokePolicy(raw) {
|
|
|
339
211
|
rpcClient = buildRpcClientFromInput(input.rpcUrl, network);
|
|
340
212
|
}
|
|
341
213
|
catch (e) {
|
|
342
|
-
return
|
|
343
|
-
ok: false,
|
|
344
|
-
error: caughtError('revoke_policy', 'REVOKE_BUILD_FAILED', e),
|
|
345
|
-
};
|
|
214
|
+
return toolFailure('revoke_policy', e);
|
|
346
215
|
}
|
|
347
216
|
try {
|
|
348
217
|
const result = await (0, build_install_policy_ts_1.buildRevokePolicyXdr)({
|
|
@@ -356,10 +225,7 @@ async function runRevokePolicy(raw) {
|
|
|
356
225
|
return { ok: true, data: result };
|
|
357
226
|
}
|
|
358
227
|
catch (e) {
|
|
359
|
-
return
|
|
360
|
-
ok: false,
|
|
361
|
-
error: caughtError('revoke_policy', 'REVOKE_BUILD_FAILED', e),
|
|
362
|
-
};
|
|
228
|
+
return toolFailure('revoke_policy', e);
|
|
363
229
|
}
|
|
364
230
|
}
|
|
365
231
|
/** `get_interpreter_info` body - thin wrapper over `getInterpreterInfo`.
|
|
@@ -381,14 +247,105 @@ async function runRevokePolicy(raw) {
|
|
|
381
247
|
* a non-pinned `rpcUrl` would silently bind the caller to a host they
|
|
382
248
|
* picked. The pin is enforced here too, with the same `allowUnpinnedRpcUrl`
|
|
383
249
|
* opt-in as install/revoke. */
|
|
384
|
-
|
|
385
|
-
|
|
250
|
+
/** The call a predicate is evaluated against: the single top-level invocation
|
|
251
|
+
* the smart account authorises. `Policy::enforce` receives one `Context`, not
|
|
252
|
+
* a sub-invocation tree, so simulating anything deeper would claim a
|
|
253
|
+
* guarantee the contract does not make. */
|
|
254
|
+
function evalContextFromRecording(tx) {
|
|
255
|
+
const top = tx.invocations[0];
|
|
256
|
+
if (!top)
|
|
257
|
+
return null;
|
|
258
|
+
return { contract: top.contract, fn: top.fn, args: top.args };
|
|
259
|
+
}
|
|
260
|
+
/** Both `simulate_policy` and `verify_policy` evaluate against a context derived
|
|
261
|
+
* from `permitTx`; neither has anything to evaluate when the recording carries
|
|
262
|
+
* no top-level invocation. */
|
|
263
|
+
function noInvocationError(toolName) {
|
|
264
|
+
return {
|
|
265
|
+
code: TOOL_ERROR_CODE[toolName],
|
|
266
|
+
message: `${toolName}: permitTx carries no invocation to evaluate`,
|
|
267
|
+
severity: 'error',
|
|
268
|
+
retryable: false,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
/** `simulate_policy` body - evaluate a predicate against one recorded call.
|
|
272
|
+
*
|
|
273
|
+
* The evaluator is a second implementation of the on-chain semantics, and the
|
|
274
|
+
* conformance harness asserts it agrees with the Rust interpreter case for
|
|
275
|
+
* case. A verdict here is therefore a claim about what the contract would do,
|
|
276
|
+
* not a guess. */
|
|
277
|
+
function runSimulatePolicy(raw) {
|
|
278
|
+
const parsed = schemas_ts_1.SimulatePolicyInputSchema.safeParse(raw);
|
|
279
|
+
if (!parsed.success) {
|
|
280
|
+
return { ok: false, error: validationError('simulate_policy', parsed.error.issues) };
|
|
281
|
+
}
|
|
282
|
+
const input = parsed.data;
|
|
283
|
+
const ctx = evalContextFromRecording(input.permitTx);
|
|
284
|
+
if (!ctx)
|
|
285
|
+
return { ok: false, error: noInvocationError('simulate_policy') };
|
|
286
|
+
try {
|
|
287
|
+
const res = (0, index_ts_2.evaluate)(input.predicate, ctx);
|
|
288
|
+
return {
|
|
289
|
+
ok: true,
|
|
290
|
+
data: {
|
|
291
|
+
permitted: res.permit,
|
|
292
|
+
reason: res.permit ? null : res.reason,
|
|
293
|
+
call: { contract: ctx.contract, fn: ctx.fn, argCount: ctx.args.length },
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
catch (e) {
|
|
298
|
+
return toolFailure('simulate_policy', e);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/** `verify_policy` body - the permit case plus a generated deny case per
|
|
302
|
+
* dimension.
|
|
303
|
+
*
|
|
304
|
+
* Two failure modes are being checked, and they are not the same thing. A
|
|
305
|
+
* permit case that denies means the policy is too STRICT: it would refuse the
|
|
306
|
+
* very transaction it was synthesised from. A deny case that permits means it
|
|
307
|
+
* is too LOOSE: some mutation of that transaction still gets through. `ok` is
|
|
308
|
+
* true only when neither holds. */
|
|
309
|
+
function runVerifyPolicy(raw) {
|
|
310
|
+
const parsed = schemas_ts_1.VerifyPolicyInputSchema.safeParse(raw);
|
|
386
311
|
if (!parsed.success) {
|
|
312
|
+
return { ok: false, error: validationError('verify_policy', parsed.error.issues) };
|
|
313
|
+
}
|
|
314
|
+
const input = parsed.data;
|
|
315
|
+
const ctx = evalContextFromRecording(input.permitTx);
|
|
316
|
+
if (!ctx)
|
|
317
|
+
return { ok: false, error: noInvocationError('verify_policy') };
|
|
318
|
+
try {
|
|
319
|
+
const predicate = input.predicate;
|
|
320
|
+
const cases = (0, index_ts_2.generateCases)(predicate, ctx);
|
|
321
|
+
const permitRes = (0, index_ts_2.evaluate)(predicate, cases.permit);
|
|
322
|
+
const denies = cases.denies.map((d) => {
|
|
323
|
+
const r = (0, index_ts_2.evaluate)(predicate, d.ctx);
|
|
324
|
+
return {
|
|
325
|
+
dimension: d.dimension,
|
|
326
|
+
denied: !r.permit,
|
|
327
|
+
reason: r.permit ? null : r.reason,
|
|
328
|
+
};
|
|
329
|
+
});
|
|
387
330
|
return {
|
|
388
|
-
ok:
|
|
389
|
-
|
|
331
|
+
ok: true,
|
|
332
|
+
data: {
|
|
333
|
+
ok: permitRes.permit && denies.every((d) => d.denied),
|
|
334
|
+
permit: { permitted: permitRes.permit, reason: permitRes.permit ? null : permitRes.reason },
|
|
335
|
+
denies,
|
|
336
|
+
dimensionsCovered: denies.length,
|
|
337
|
+
},
|
|
390
338
|
};
|
|
391
339
|
}
|
|
340
|
+
catch (e) {
|
|
341
|
+
return toolFailure('verify_policy', e);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
async function runGetInterpreterInfo(raw) {
|
|
345
|
+
const parsed = schemas_ts_1.GetInterpreterInfoInputSchema.safeParse(raw);
|
|
346
|
+
if (!parsed.success) {
|
|
347
|
+
return { ok: false, error: validationError('get_interpreter_info', parsed.error.issues) };
|
|
348
|
+
}
|
|
392
349
|
const input = parsed.data;
|
|
393
350
|
const network = input.network ?? 'testnet';
|
|
394
351
|
const expectedRpc = schemas_ts_1.RPC_URL_BY_NETWORK[network];
|
|
@@ -421,10 +378,7 @@ async function runGetInterpreterInfo(raw) {
|
|
|
421
378
|
return { ok: true, data: info };
|
|
422
379
|
}
|
|
423
380
|
catch (e) {
|
|
424
|
-
return
|
|
425
|
-
ok: false,
|
|
426
|
-
error: caughtError('get_interpreter_info', 'RECORDING_FAILED', e),
|
|
427
|
-
};
|
|
381
|
+
return toolFailure('get_interpreter_info', e);
|
|
428
382
|
}
|
|
429
383
|
}
|
|
430
384
|
/** Build an InstallRpcClient from an optional URL override + selected
|
|
@@ -478,13 +432,8 @@ function enforceInterpreterPin(policies, allowUnpinned, expectedInterpreterAddre
|
|
|
478
432
|
function enforceRpcPin(toolName, rpcUrl, allowUnpinned, expectedRpc, network) {
|
|
479
433
|
if (!rpcUrl || rpcUrl === expectedRpc || allowUnpinned === true)
|
|
480
434
|
return null;
|
|
481
|
-
const code = toolName === 'install_policy'
|
|
482
|
-
? 'INSTALL_BUILD_FAILED'
|
|
483
|
-
: toolName === 'revoke_policy'
|
|
484
|
-
? 'REVOKE_BUILD_FAILED'
|
|
485
|
-
: 'RECORDING_FAILED';
|
|
486
435
|
return {
|
|
487
|
-
code,
|
|
436
|
+
code: TOOL_ERROR_CODE[toolName],
|
|
488
437
|
message: `${toolName}: rpcUrl must equal the pinned ${expectedRpc} (${network}); set allowUnpinnedRpcUrl: true to opt in to a custom endpoint`,
|
|
489
438
|
severity: 'error',
|
|
490
439
|
retryable: false,
|
|
@@ -511,6 +460,11 @@ function validationError(toolName, issues) {
|
|
|
511
460
|
* error in `details` for the agent to inspect. Exported as a test-only seam
|
|
512
461
|
* so the suite in run/index.test.ts can drive the envelope path without
|
|
513
462
|
* standing up a full recordTransaction pipeline. */
|
|
463
|
+
/** The fail-closed return every tool body uses in its `catch`. Taking only the
|
|
464
|
+
* tool name keeps the tool -> error-code mapping in TOOL_ERROR_CODE alone. */
|
|
465
|
+
function toolFailure(toolName, e) {
|
|
466
|
+
return { ok: false, error: caughtError(toolName, TOOL_ERROR_CODE[toolName], e) };
|
|
467
|
+
}
|
|
514
468
|
function caughtError(toolName, code, e) {
|
|
515
469
|
return {
|
|
516
470
|
code,
|