protect-mcp 0.9.2 → 0.9.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/dist/index.js CHANGED
@@ -35540,7 +35540,13 @@ function signDecision(entry) {
35540
35540
  // - scopeblind:verified = issued via ScopeBlind VOPRF backend (paid tier)
35541
35541
  // - self-signed = signed with local Ed25519 key (free tier, protect-mcp default)
35542
35542
  // - uncertified = unsigned receipt (shadow mode, no signing configured)
35543
- issuer_certification: signerState ? "self-signed" : "uncertified"
35543
+ issuer_certification: signerState ? "self-signed" : "uncertified",
35544
+ // The signer's PUBLIC key, inside the signed payload, so a receipt is
35545
+ // self-contained: any verifier (including the record viewer, in-browser)
35546
+ // can check the signature without a side channel. Binding the key inside
35547
+ // the signature means it cannot be swapped without breaking the signature;
35548
+ // authenticity (that the key is YOUR gate's) still comes from pinning it.
35549
+ public_key: signerState.publicKey
35544
35550
  };
35545
35551
  if (entry.tier) payload.tier = entry.tier;
35546
35552
  if (entry.credential_ref) payload.credential_ref = entry.credential_ref;
@@ -40362,7 +40368,7 @@ function forwardReceipt(signedReceipt) {
40362
40368
  }
40363
40369
 
40364
40370
  // src/receipt-enrichment.ts
40365
- var ENRICHMENT_VERSION = 1;
40371
+ var ENRICHMENT_VERSION = 2;
40366
40372
  function canonicalJson(value) {
40367
40373
  const seen = /* @__PURE__ */ new WeakSet();
40368
40374
  const enc = (v) => {
@@ -40399,7 +40405,11 @@ var RULES = [
40399
40405
  { cap: "secret.adjacent", text: /\.env\b|secret|credential|passwd|password|api[_-]?key|private[_-]?key|\.pem\b|\.key\b|id_rsa|bearer\s|aws_(access|secret)|authorization/ },
40400
40406
  { cap: "destructive", text: /rm\s+-[a-z]*[rf]|\brmdir\b|drop\s+table|truncate\s+table|delete\s+from|reset\s+--hard|--force\b|\bmkfs\b|\bdd\s+if=|shutdown|reboot|kill\s+-9|>\s*\/dev\/sd/ },
40401
40407
  { cap: "financial", text: /\b(order|trade|buy|sell|transfer|wire|payment|withdraw|deposit|swap|invoice|charge|refund|settle)\b/ },
40402
- { cap: "data.query", text: /\bselect\s+[\s\S]+\bfrom\b|\binsert\s+into\b|\bupdate\s+[\s\S]+\bset\b|\bdelete\s+from\b/ }
40408
+ { cap: "data.query", text: /\bselect\s+[\s\S]+\bfrom\b|\binsert\s+into\b|\bupdate\s+[\s\S]+\bset\b|\bdelete\s+from\b/ },
40409
+ // Agent payments (x402 / value transfer). Deliberately BROAD: a false positive
40410
+ // only makes a `claim --no payment` harder to assert (conservative); a false
40411
+ // negative would let a real payment escape the record's payment claims.
40412
+ { cap: "payment", tool: /(^|[_.-])(pay|payment|x402|checkout)($|[_.-])|wallet.*send|send.*payment/, text: /x402|x-payment|paymentrequirements|maxamountrequired|payto|"pay_to"|eip-3009|transferwithauthorization|payment_intent|send_payment|create_payment/ }
40403
40413
  ];
40404
40414
  function deriveCapabilities(tool, input) {
40405
40415
  const t = String(tool || "").toLowerCase();
@@ -40433,6 +40443,33 @@ function deriveResource(input) {
40433
40443
  }
40434
40444
  return void 0;
40435
40445
  }
40446
+ function findField(input, names, depth = 0) {
40447
+ if (depth > 4 || input === null || typeof input !== "object") return void 0;
40448
+ const o = input;
40449
+ const keys = Object.keys(o).sort();
40450
+ for (const k of keys) {
40451
+ if (names.indexOf(k.toLowerCase()) >= 0 && o[k] !== void 0 && o[k] !== null) return o[k];
40452
+ }
40453
+ for (const k of keys) {
40454
+ const v = findField(o[k], names, depth + 1);
40455
+ if (v !== void 0) return v;
40456
+ }
40457
+ return void 0;
40458
+ }
40459
+ function derivePayment(tool, input) {
40460
+ if (deriveCapabilities(tool, input).indexOf("payment") < 0) return void 0;
40461
+ const p = { amount: null, asset: null, recipient_digest: null };
40462
+ const amt = findField(input, ["amount"]);
40463
+ if (typeof amt === "number" && Number.isFinite(amt) && amt >= 0) p.amount = amt;
40464
+ else if (typeof amt === "string" && /^\d{1,15}(\.\d{1,18})?$/.test(amt.trim()) && amt.indexOf(".") >= 0) p.amount = parseFloat(amt);
40465
+ const asset = findField(input, ["asset", "currency", "token"]);
40466
+ if (typeof asset === "string" && asset.trim()) p.asset = asset.trim().slice(0, 64);
40467
+ const to = findField(input, ["payto", "pay_to", "recipient", "destination", "to"]);
40468
+ if (typeof to === "string" && to.trim()) p.recipient_digest = sha256Hex(to.trim().toLowerCase());
40469
+ const scheme = findField(input, ["scheme"]);
40470
+ if (typeof scheme === "string" && scheme.trim()) p.scheme = scheme.trim().slice(0, 32);
40471
+ return p;
40472
+ }
40436
40473
  function buildEnrichment(tool, input) {
40437
40474
  const e = {
40438
40475
  v: ENRICHMENT_VERSION,
@@ -40441,6 +40478,8 @@ function buildEnrichment(tool, input) {
40441
40478
  };
40442
40479
  const resource = deriveResource(input);
40443
40480
  if (resource) e.resource = resource;
40481
+ const payment = derivePayment(tool, input);
40482
+ if (payment) e.payment = payment;
40444
40483
  return e;
40445
40484
  }
40446
40485
 
package/dist/index.mjs CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  readInstalledConnectorPilots,
28
28
  simulate,
29
29
  writeConnectorPilots
30
- } from "./chunk-CXW2EIRM.mjs";
30
+ } from "./chunk-7MHK5RF4.mjs";
31
31
  import {
32
32
  ProtectGateway,
33
33
  buildDecisionContext,
@@ -39,7 +39,7 @@ import {
39
39
  resolveCredential,
40
40
  sendApprovalNotification,
41
41
  validateCredentials
42
- } from "./chunk-GHR65WVD.mjs";
42
+ } from "./chunk-PB3TC7E3.mjs";
43
43
  import {
44
44
  createSandboxServer
45
45
  } from "./chunk-SETXVE2K.mjs";
@@ -54,8 +54,8 @@ import {
54
54
  forwardReceipt,
55
55
  getScopeBlindBridge,
56
56
  startHookServer
57
- } from "./chunk-744JMCY4.mjs";
58
- import "./chunk-KMNXHGGT.mjs";
57
+ } from "./chunk-H332ZNJ6.mjs";
58
+ import "./chunk-WWPQNIVF.mjs";
59
59
  import {
60
60
  sha256 as sha2562
61
61
  } from "./chunk-AYNQIEN7.mjs";
@@ -73,7 +73,7 @@ import {
73
73
  policySetFromSource,
74
74
  runEvaluatorSelfTest,
75
75
  signDecision
76
- } from "./chunk-IDUH2O4Q.mjs";
76
+ } from "./chunk-XLJUZ4WO.mjs";
77
77
  import {
78
78
  Field,
79
79
  _abool2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "protect-mcp",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "mcpName": "com.scopeblind/protect-mcp",
5
5
  "description": "Fail-closed Cedar policy gate + Ed25519 signed receipts for AI agent tool calls. Denies on any policy error, proves the gate is live with a startup self-test, and turns every decision into a local searchable record you own. The open gate behind Legate by ScopeBlind. scopeblind.com",
6
6
  "main": "dist/index.js",