create-metamynd-agent 0.7.4 → 0.7.7

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.
Files changed (3) hide show
  1. package/README.md +18 -4
  2. package/index.mjs +35 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -150,9 +150,9 @@ What actually stops that bypass is that `bookFlight()` doesn't exist in the agen
150
150
  It exists only in `gateway/server.mjs` — a separate process, started separately, holding any real
151
151
  tool credentials the agent process never sees — which independently re-verifies every request
152
152
  against the agent's own published policy bundle before running it, **binds that request to the
153
- actual body being executed** (`@metamynd/agentsafe-http-gateway` ≥ 0.2.0), and requires the
153
+ actual body being executed** (`@metamynd/agentsafe-http-gateway` ≥ 0.4.0), and requires the
154
154
  agent's `authorizationId` to atomically claim single-use execution against the real stateful gate
155
- (`requireAuthorization`, `@metamynd/agentsafe-mcp-guard` ≥ 0.2.0) — closing a confused-deputy gap
155
+ (`requireAuthorization`, `@metamynd/agentsafe-mcp-guard` ≥ 0.3.0) — closing a confused-deputy gap
156
156
  and a replay/cumulative-spend gap, both found during independent testing. Same shape as the mutual
157
157
  counterparty check in [`@metamynd/agentsafe-mcp-guard`](https://www.npmjs.com/package/@metamynd/agentsafe-mcp-guard),
158
158
  built with [`@metamynd/agentsafe-http-gateway`](https://www.npmjs.com/package/@metamynd/agentsafe-http-gateway).
@@ -167,13 +167,27 @@ Named precisely, not left implicit:
167
167
 
168
168
  - **Direct call.** `bookFlight()` doesn't exist in the agent's process.
169
169
  - **Confused deputy (payload).** Signing a cheap request while executing an expensive one (a
170
- different amount/currency/merchant in the body than what was signed) is refused before the tool
171
- runs payload binding.
170
+ different amount/merchant in the body than what was signed) is refused before the tool runs —
171
+ payload binding (`@metamynd/agentsafe-http-gateway` ≥ 0.4.0). The default binder requires
172
+ `amount`/`merchant` to actually be found in the body whenever the signed request names a real
173
+ value for them — not just "did the body offer at least one correct-looking field." A first
174
+ attempt at this (0.3.0) checked the weaker version and was re-tested and closed the same day: a
175
+ correct decoy in one field (e.g. a matching `merchant`) let the OTHER field hide anywhere —
176
+ nested, renamed, an array, or an entirely empty/non-JSON body.
172
177
  - **Replay.** A captured, resent request fails to atomically claim single-use execution the second
173
178
  time — `requireAuthorization`.
174
179
  - **Cumulative spend.** The claimed authorization only exists because the real stateful gate
175
180
  already checked it against the mandate's TOTAL budget when minted, not just this one request's
176
181
  amount — so many small legal-looking calls can't add up past the cap this way.
182
+ - **Amount unknown.** Two separate places this matters, both actually authored, not just
183
+ available: the platform's own custodial-signing tools (`@metamynd/agentsafe-guard` ≥ 0.6.0,
184
+ `@metamynd/agentsafe-mcp-guard` ≥ 0.3.0) block by default when a signed-transaction tool's raw
185
+ bytes or a nested x402 payload hide the amount from a naive spend cap — AND this agent's own
186
+ starter SOP puts the same `amount-unknown` check ahead of its per-transaction cap (both the
187
+ hosted default and `--harness`'s local one). The atom existing was not the gap: for a while
188
+ this SOP still only ever authored `amount-over`, which silently does not fire on a missing or
189
+ string amount (`typeof c.amount === 'number'` is false either way) — a real, live-confirmed way
190
+ to slip a booking's cap untested. Fixed at the template, not just the atom registry.
177
191
 
178
192
  The claim above also checks `agentDid`/`amount`/`currency`/`merchant` together against the
179
193
  request being executed (`@metamynd/agentsafe-mcp-guard` ≥ 0.2.1) — a same-amount, same-currency
package/index.mjs CHANGED
@@ -23,16 +23,25 @@ const GUARD_PKG = '@metamynd/agentsafe-guard';
23
23
  // Must track the guard's MINOR line, not just its major. On a 0.x package `^0.4.0` means
24
24
  // >=0.4.0 <0.5.0, so leaving this at ^0.4.0 would scaffold an agent whose `npm test` runs
25
25
  // `agentsafe-guard verify` against a guard that has no such command.
26
- const GUARD_VERSION = '^0.5.0';
26
+ // 0.6.0 adds the amount-unknown atom (deny-by-default when a value-moving action's amount
27
+ // can't be determined) — this was already missed once (this constant sat at ^0.5.0 through the
28
+ // whole 0.6.0 release), silently scaffolding every new project without that protection.
29
+ const GUARD_VERSION = '^0.6.0';
27
30
  // The default hosted scaffold's SECOND process — the tool gateway (see scaffoldProject).
28
31
  const MCP_GUARD_PKG = '@metamynd/agentsafe-mcp-guard';
29
32
  // 0.2.0 adds requireAuthorization (closes replay + cumulative spend) — this scaffold sets that
30
33
  // option, so a range that could resolve below 0.2.0 would silently scaffold a no-op.
31
- const MCP_GUARD_VERSION = '^0.2.0';
34
+ // 0.3.0 adds the same amount-unknown atom as the guard, above — same reasoning, same miss.
35
+ const MCP_GUARD_VERSION = '^0.3.0';
32
36
  const GATEWAY_PKG = '@metamynd/agentsafe-http-gateway';
33
37
  // 0.2.0 fixes a confused-deputy gap (payload not bound to the signed request) — the CLI must
34
38
  // never scaffold a range that could resolve below it.
35
- const GATEWAY_VERSION = '^0.2.0';
39
+ // 0.3.0 was a first, INCOMPLETE attempt at the follow-on gap (checked only "did the body offer
40
+ // NONE of the three fields" — a correct decoy in one field let the other hide anywhere). 0.4.0
41
+ // is the actual fix: requires amount/merchant specifically, whenever the signature names a real
42
+ // value for them. Re-tested live and closed same day; ^0.3.0 here would still resolve to the
43
+ // broken version.
44
+ const GATEWAY_VERSION = '^0.4.0';
36
45
  const DEFAULT_API = 'https://metamynd.ai/api/v1';
37
46
  const DEFAULT_GATEWAY_PORT = 4401; // distinct from --harness's dashboard (4400)
38
47
 
@@ -908,8 +917,13 @@ own code, or a network attacker) might attempt:
908
917
  - **Direct call.** \`bookFlight()\` doesn't exist in the agent's process. There's nothing to call.
909
918
  - **Confused deputy (payload).** The gateway re-verifies the signed request against this agent's
910
919
  own policy AND binds it to the actual request body (payload binding,
911
- \`@metamynd/agentsafe-http-gateway\` ≥ 0.2.0) — signing a cheap request while executing an
912
- expensive one is refused before the tool ever runs.
920
+ \`@metamynd/agentsafe-http-gateway\` ≥ 0.4.0) — signing a cheap request while executing an
921
+ expensive one is refused before the tool ever runs. The default binder requires \`amount\`/
922
+ \`merchant\` to actually be found in the body whenever the signature names a real value for
923
+ them — not just "did the body offer at least one correct-looking field." A first attempt at
924
+ this (0.3.0) checked the weaker version and was re-tested and closed the same day: a correct
925
+ decoy in one field let the OTHER field hide anywhere — nested, renamed, an array, or an
926
+ entirely empty/non-JSON body.
913
927
  - **Replay.** \`requireAuthorization: true\` (set in \`server.mjs\`) requires the agent's
914
928
  \`authorizationId\` — from a REAL \`guard.authorize()\` call, which \`index.mjs\` already makes for
915
929
  any value-bearing action by default — to atomically claim single-use execution against the
@@ -918,6 +932,13 @@ own code, or a network attacker) might attempt:
918
932
  already checked it against the mandate's TOTAL budget when it was minted — not just this one
919
933
  request's amount. Many small legal-looking calls can't add up past the mandate cap this way,
920
934
  because each needed its own real authorization first.
935
+ - **Amount unknown.** \`amount-unknown\` (\`@metamynd/agentsafe-mcp-guard\` ≥ 0.3.0) blocks a
936
+ platform tool by default when its raw bytes or a nested payload hide the amount from a naive
937
+ spend cap — AND this agent's OWN starter SOP (see \`agent.metamynd.json\` /
938
+ \`harness-rules.json\`) puts the same check ahead of its per-transaction cap. That second part
939
+ didn't used to be true: the SOP only ever authored \`amount-over\`, which silently does not fire
940
+ on a missing or string amount, so either one slipped the cap untested — the atom existing
941
+ wasn't the gap, this template never authoring it was.
921
942
 
922
943
  The claim above also checks the claimed authorization's own \`agentDid\`/\`amount\`/\`currency\`/
923
944
  \`merchant\` against the request actually being executed (\`@metamynd/agentsafe-mcp-guard\` ≥ 0.2.1)
@@ -1047,10 +1068,17 @@ async function runSandbox(args) {
1047
1068
 
1048
1069
  /** Mirrors defaultSopDocument() in backend/src/features/onboarding/onboarding.provision.ts —
1049
1070
  * same starter rules the hosted platform issues, so a harness project behaves identically
1050
- * to a freshly-provisioned one before anyone edits either. */
1071
+ * to a freshly-provisioned one before anyone edits either.
1072
+ *
1073
+ * `amount-unknown` first matters MORE here than on the hosted path: evaluateLocally() runs
1074
+ * entirely client-side with no schema boundary in front of it, so nothing stops a caller from
1075
+ * passing amount: "5000" (a string) or omitting amount entirely — `amount-over` silently does
1076
+ * not fire on either (`typeof c.amount === 'number'` is false), so the cap passes untested,
1077
+ * not safe. Ordering amount-unknown first blocks that instead of letting it through. */
1051
1078
  function harnessDefaultSop(perTxnMax) {
1052
1079
  return {
1053
1080
  molecules: [
1081
+ { id: 'amount-known', name: 'Amount must be determinable', combinator: 'any', atoms: [{ id: 'a0', predicate: 'amount-unknown' }], decision: 'block', reasonCode: 'AMOUNT_NOT_DETERMINABLE' },
1054
1082
  { id: 'cap', name: 'Per-transaction cap', combinator: 'any', atoms: [{ id: 'a1', predicate: 'amount-over', config: { limit: perTxnMax } }], decision: 'block', reasonCode: 'SOP_SPEND_CAP' },
1055
1083
  { id: 'review', name: 'High-risk review', combinator: 'any', atoms: [{ id: 'a2', predicate: 'risk-at-or-above', config: { level: 'high' } }], decision: 'escalate', reasonCode: 'RISK_REVIEW' },
1056
1084
  ],
@@ -1122,6 +1150,7 @@ function renderConstraint(c) {
1122
1150
  function renderAtom(a) {
1123
1151
  const c = a.config || {};
1124
1152
  switch (a.predicate) {
1153
+ case 'amount-unknown': return \`transaction amount must be a real, determinable number\`;
1125
1154
  case 'amount-over': return \`transaction amount must not exceed \${c.limit}\`;
1126
1155
  case 'cumulative-over': return \`cumulative spend must not exceed \${c.limit}\`;
1127
1156
  case 'jurisdiction-not-allowed': return \`jurisdiction must be one of [\${(c.allowed || []).join(', ')}]\`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-metamynd-agent",
3
- "version": "0.7.4",
3
+ "version": "0.7.7",
4
4
  "description": "Scaffold a MetaMynd/AgentSafe-governed AI agent in one command — logs in, provisions the agent (identity + mandate + SOP + Standards) in a single call, writes agent.metamynd.json plus a runnable agent + separate tool-gateway process that closes direct-call, confused-deputy, replay, and cumulative-spend bypasses. --harness scaffolds a free, local, zero-network governance harness instead.",
5
5
  "type": "module",
6
6
  "bin": {