protect-mcp 0.7.6 → 0.9.2
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 +64 -0
- package/README.md +2 -2
- package/dist/{chunk-6E2DHBAR.mjs → chunk-744JMCY4.mjs} +9 -1
- package/dist/chunk-AYNQIEN7.mjs +10 -0
- package/dist/{chunk-JCMDLN5I.mjs → chunk-CXW2EIRM.mjs} +2 -2
- package/dist/{chunk-LJQOALYR.mjs → chunk-FFVJL3KQ.mjs} +5 -564
- package/dist/{chunk-VTPZ4G5I.mjs → chunk-GHR65WVD.mjs} +1 -1
- package/dist/{chunk-WIPWNWMJ.mjs → chunk-IDUH2O4Q.mjs} +1 -0
- package/dist/chunk-JIDDQUSQ.mjs +568 -0
- package/dist/chunk-KMNXHGGT.mjs +94 -0
- package/dist/{chunk-WV4DKYE4.mjs → chunk-UWB5ALVO.mjs} +10 -12
- package/dist/claim-TUDH2WPB.mjs +201 -0
- package/dist/cli.js +610 -31
- package/dist/cli.mjs +308 -24
- package/dist/{ed25519-BSHMMVNX.mjs → ed25519-SQA3S2RV.mjs} +2 -1
- package/dist/hook-server.js +428 -0
- package/dist/hook-server.mjs +6 -2
- package/dist/{http-transport-JBORN27G.mjs → http-transport-D7C64PIA.mjs} +2 -2
- package/dist/index.d.mts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +107 -18
- package/dist/index.mjs +14 -9
- package/dist/{signing-committed-QXCW24RF.mjs → signing-committed-TGWXSLAO.mjs} +4 -2
- package/package.json +1 -1
- package/policies/agent.cedar +0 -50
package/dist/index.js
CHANGED
|
@@ -27339,11 +27339,11 @@ var require_util3 = __commonJS({
|
|
|
27339
27339
|
return false;
|
|
27340
27340
|
}
|
|
27341
27341
|
exports2.schemaHasRules = schemaHasRules;
|
|
27342
|
-
function schemaHasRulesButRef(schema,
|
|
27342
|
+
function schemaHasRulesButRef(schema, RULES2) {
|
|
27343
27343
|
if (typeof schema == "boolean")
|
|
27344
27344
|
return !schema;
|
|
27345
27345
|
for (const key in schema)
|
|
27346
|
-
if (key !== "$ref" &&
|
|
27346
|
+
if (key !== "$ref" && RULES2.all[key])
|
|
27347
27347
|
return true;
|
|
27348
27348
|
return false;
|
|
27349
27349
|
}
|
|
@@ -28737,17 +28737,17 @@ var require_validate = __commonJS({
|
|
|
28737
28737
|
}
|
|
28738
28738
|
function schemaKeywords(it, types, typeErrors, errsCount) {
|
|
28739
28739
|
const { gen, schema, data, allErrors, opts, self } = it;
|
|
28740
|
-
const { RULES } = self;
|
|
28741
|
-
if (schema.$ref && (opts.ignoreKeywordsWithRef || !(0, util_1.schemaHasRulesButRef)(schema,
|
|
28742
|
-
gen.block(() => keywordCode(it, "$ref",
|
|
28740
|
+
const { RULES: RULES2 } = self;
|
|
28741
|
+
if (schema.$ref && (opts.ignoreKeywordsWithRef || !(0, util_1.schemaHasRulesButRef)(schema, RULES2))) {
|
|
28742
|
+
gen.block(() => keywordCode(it, "$ref", RULES2.all.$ref.definition));
|
|
28743
28743
|
return;
|
|
28744
28744
|
}
|
|
28745
28745
|
if (!opts.jtd)
|
|
28746
28746
|
checkStrictTypes(it, types);
|
|
28747
28747
|
gen.block(() => {
|
|
28748
|
-
for (const group of
|
|
28748
|
+
for (const group of RULES2.rules)
|
|
28749
28749
|
groupKeywords(group);
|
|
28750
|
-
groupKeywords(
|
|
28750
|
+
groupKeywords(RULES2.post);
|
|
28751
28751
|
});
|
|
28752
28752
|
function groupKeywords(group) {
|
|
28753
28753
|
if (!(0, applicability_1.shouldUseGroup)(schema, group))
|
|
@@ -30449,10 +30449,10 @@ var require_core3 = __commonJS({
|
|
|
30449
30449
|
}
|
|
30450
30450
|
// Remove keyword
|
|
30451
30451
|
removeKeyword(keyword) {
|
|
30452
|
-
const { RULES } = this;
|
|
30453
|
-
delete
|
|
30454
|
-
delete
|
|
30455
|
-
for (const group of
|
|
30452
|
+
const { RULES: RULES2 } = this;
|
|
30453
|
+
delete RULES2.keywords[keyword];
|
|
30454
|
+
delete RULES2.all[keyword];
|
|
30455
|
+
for (const group of RULES2.rules) {
|
|
30456
30456
|
const i = group.rules.findIndex((rule) => rule.keyword === keyword);
|
|
30457
30457
|
if (i >= 0)
|
|
30458
30458
|
group.rules.splice(i, 1);
|
|
@@ -30620,9 +30620,9 @@ var require_core3 = __commonJS({
|
|
|
30620
30620
|
}
|
|
30621
30621
|
var KEYWORD_NAME = /^[a-z_$][a-z0-9_$:-]*$/i;
|
|
30622
30622
|
function checkKeyword(keyword, def) {
|
|
30623
|
-
const { RULES } = this;
|
|
30623
|
+
const { RULES: RULES2 } = this;
|
|
30624
30624
|
(0, util_1.eachItem)(keyword, (kwd) => {
|
|
30625
|
-
if (
|
|
30625
|
+
if (RULES2.keywords[kwd])
|
|
30626
30626
|
throw new Error(`Keyword ${kwd} is already defined`);
|
|
30627
30627
|
if (!KEYWORD_NAME.test(kwd))
|
|
30628
30628
|
throw new Error(`Keyword ${kwd} has invalid name`);
|
|
@@ -30638,13 +30638,13 @@ var require_core3 = __commonJS({
|
|
|
30638
30638
|
const post = definition === null || definition === void 0 ? void 0 : definition.post;
|
|
30639
30639
|
if (dataType && post)
|
|
30640
30640
|
throw new Error('keyword with "post" flag cannot have "type"');
|
|
30641
|
-
const { RULES } = this;
|
|
30642
|
-
let ruleGroup = post ?
|
|
30641
|
+
const { RULES: RULES2 } = this;
|
|
30642
|
+
let ruleGroup = post ? RULES2.post : RULES2.rules.find(({ type: t }) => t === dataType);
|
|
30643
30643
|
if (!ruleGroup) {
|
|
30644
30644
|
ruleGroup = { type: dataType, rules: [] };
|
|
30645
|
-
|
|
30645
|
+
RULES2.rules.push(ruleGroup);
|
|
30646
30646
|
}
|
|
30647
|
-
|
|
30647
|
+
RULES2.keywords[keyword] = true;
|
|
30648
30648
|
if (!definition)
|
|
30649
30649
|
return;
|
|
30650
30650
|
const rule = {
|
|
@@ -30659,7 +30659,7 @@ var require_core3 = __commonJS({
|
|
|
30659
30659
|
addBeforeRule.call(this, ruleGroup, rule, definition.before);
|
|
30660
30660
|
else
|
|
30661
30661
|
ruleGroup.rules.push(rule);
|
|
30662
|
-
|
|
30662
|
+
RULES2.all[keyword] = rule;
|
|
30663
30663
|
(_a = definition.implements) === null || _a === void 0 ? void 0 : _a.forEach((kwd) => this.addKeyword(kwd));
|
|
30664
30664
|
}
|
|
30665
30665
|
function addBeforeRule(ruleGroup, rule, before) {
|
|
@@ -35553,6 +35553,7 @@ function signDecision(entry) {
|
|
|
35553
35553
|
if (entry.timing) payload.timing = entry.timing;
|
|
35554
35554
|
if (entry.swarm) payload.swarm = entry.swarm;
|
|
35555
35555
|
if (entry.payload_digest) payload.payload_digest = entry.payload_digest;
|
|
35556
|
+
if (entry.enrichment) payload.enrichment = entry.enrichment;
|
|
35556
35557
|
if (entry.action_readback) payload.action_readback = entry.action_readback;
|
|
35557
35558
|
if (entry.deny_iteration) payload.deny_iteration = entry.deny_iteration;
|
|
35558
35559
|
const result = artifactsModule.createSignedArtifact(
|
|
@@ -40360,6 +40361,89 @@ function forwardReceipt(signedReceipt) {
|
|
|
40360
40361
|
getScopeBlindBridge().forward(signedReceipt);
|
|
40361
40362
|
}
|
|
40362
40363
|
|
|
40364
|
+
// src/receipt-enrichment.ts
|
|
40365
|
+
var ENRICHMENT_VERSION = 1;
|
|
40366
|
+
function canonicalJson(value) {
|
|
40367
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
40368
|
+
const enc = (v) => {
|
|
40369
|
+
if (v === null || v === void 0) return "null";
|
|
40370
|
+
const t = typeof v;
|
|
40371
|
+
if (t === "number") return Number.isFinite(v) ? JSON.stringify(v) : "null";
|
|
40372
|
+
if (t === "boolean" || t === "string") return JSON.stringify(v);
|
|
40373
|
+
if (t === "bigint") return JSON.stringify(v.toString());
|
|
40374
|
+
if (t === "function" || t === "symbol") return "null";
|
|
40375
|
+
if (Array.isArray(v)) return "[" + v.map(enc).join(",") + "]";
|
|
40376
|
+
if (t === "object") {
|
|
40377
|
+
const o = v;
|
|
40378
|
+
if (seen.has(o)) return '"[circular]"';
|
|
40379
|
+
seen.add(o);
|
|
40380
|
+
const body = Object.keys(o).sort().map((k) => JSON.stringify(k) + ":" + enc(o[k])).join(",");
|
|
40381
|
+
seen.delete(o);
|
|
40382
|
+
return "{" + body + "}";
|
|
40383
|
+
}
|
|
40384
|
+
return "null";
|
|
40385
|
+
};
|
|
40386
|
+
return enc(value);
|
|
40387
|
+
}
|
|
40388
|
+
function sha256Hex(s) {
|
|
40389
|
+
return bytesToHex(sha2562(new TextEncoder().encode(s)));
|
|
40390
|
+
}
|
|
40391
|
+
var RULES = [
|
|
40392
|
+
{ cap: "exec.shell", tool: /bash|shell|exec|terminal|run_command|command/ },
|
|
40393
|
+
{ cap: "fs.read", tool: /(^|[_.])(read|cat|glob|grep|search|ls|view|list_files|open)/ },
|
|
40394
|
+
{ cap: "fs.write", tool: /write|create_file|save|append|edit|patch|replace|update_file|multiedit|notebook/ },
|
|
40395
|
+
{ cap: "fs.delete", tool: /delete|remove|unlink|trash|(^|[_.])rm/ },
|
|
40396
|
+
{ cap: "net.egress", tool: /fetch|http|curl|wget|request|download|browse|navigate|webfetch|web_search|scrape/ },
|
|
40397
|
+
{ cap: "vcs", tool: /(^|[_.])git/, text: /\bgit\s+(commit|push|pull|clone|reset|checkout|branch|rebase|merge|tag)\b/ },
|
|
40398
|
+
{ cap: "package.install", text: /\b(npm|pnpm|yarn)\s+(i|install|add)\b|\bpip3?\s+install\b|\bgo\s+get\b|\bcargo\s+add\b|\bbrew\s+install\b|\bapt(-get)?\s+install\b|\bgem\s+install\b/ },
|
|
40399
|
+
{ 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
|
+
{ 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
|
+
{ 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/ }
|
|
40403
|
+
];
|
|
40404
|
+
function deriveCapabilities(tool, input) {
|
|
40405
|
+
const t = String(tool || "").toLowerCase();
|
|
40406
|
+
let text = "";
|
|
40407
|
+
try {
|
|
40408
|
+
text = canonicalJson(input).toLowerCase();
|
|
40409
|
+
} catch {
|
|
40410
|
+
}
|
|
40411
|
+
const caps = /* @__PURE__ */ new Set();
|
|
40412
|
+
for (const r of RULES) {
|
|
40413
|
+
if (r.tool && r.tool.test(t)) caps.add(r.cap);
|
|
40414
|
+
if (r.text && r.text.test(text)) caps.add(r.cap);
|
|
40415
|
+
}
|
|
40416
|
+
return Array.from(caps).sort();
|
|
40417
|
+
}
|
|
40418
|
+
function deriveResource(input) {
|
|
40419
|
+
const o = input && typeof input === "object" ? input : {};
|
|
40420
|
+
const path = o.file_path ?? o.path ?? o.filePath ?? o.notebook_path ?? o.filename;
|
|
40421
|
+
if (typeof path === "string" && path.trim()) return { kind: "path", digest: sha256Hex(path.replace(/\\/g, "/")) };
|
|
40422
|
+
const url = o.url ?? o.uri ?? o.endpoint ?? o.href;
|
|
40423
|
+
if (typeof url === "string" && url.trim()) {
|
|
40424
|
+
try {
|
|
40425
|
+
return { kind: "host", digest: sha256Hex(new URL(url).host.toLowerCase()) };
|
|
40426
|
+
} catch {
|
|
40427
|
+
}
|
|
40428
|
+
}
|
|
40429
|
+
const cmd = o.command ?? o.cmd ?? o.script;
|
|
40430
|
+
if (typeof cmd === "string" && cmd.trim()) {
|
|
40431
|
+
const first = cmd.trim().split(/\s+/)[0];
|
|
40432
|
+
if (first) return { kind: "command", digest: sha256Hex(first) };
|
|
40433
|
+
}
|
|
40434
|
+
return void 0;
|
|
40435
|
+
}
|
|
40436
|
+
function buildEnrichment(tool, input) {
|
|
40437
|
+
const e = {
|
|
40438
|
+
v: ENRICHMENT_VERSION,
|
|
40439
|
+
input_digest: sha256Hex(canonicalJson(input ?? {})),
|
|
40440
|
+
capabilities: deriveCapabilities(tool, input)
|
|
40441
|
+
};
|
|
40442
|
+
const resource = deriveResource(input);
|
|
40443
|
+
if (resource) e.resource = resource;
|
|
40444
|
+
return e;
|
|
40445
|
+
}
|
|
40446
|
+
|
|
40363
40447
|
// src/hook-server.ts
|
|
40364
40448
|
var DEFAULT_PORT = 9377;
|
|
40365
40449
|
var LOG_FILE3 = ".protect-mcp-log.jsonl";
|
|
@@ -40432,6 +40516,9 @@ async function handlePreToolUse(input, state) {
|
|
|
40432
40516
|
});
|
|
40433
40517
|
const payloadDigest = computePayloadDigest(input.toolInput);
|
|
40434
40518
|
const actionReadback = buildActionReadback(toolName, input.toolInput || {});
|
|
40519
|
+
const enrichment = buildEnrichment(toolName, input.toolInput || {});
|
|
40520
|
+
const inflightRec = state.inflightTools.get(requestId);
|
|
40521
|
+
if (inflightRec) inflightRec.enrichment = enrichment;
|
|
40435
40522
|
const swarm = {
|
|
40436
40523
|
...state.swarmContext,
|
|
40437
40524
|
...input.agentId && { agent_id: input.agentId },
|
|
@@ -40851,6 +40938,8 @@ function emitDecisionLog(state, entry) {
|
|
|
40851
40938
|
...entry.sandbox_state && { sandbox_state: entry.sandbox_state },
|
|
40852
40939
|
...entry.plan_receipt_id && { plan_receipt_id: entry.plan_receipt_id }
|
|
40853
40940
|
};
|
|
40941
|
+
const enr = state.inflightTools.get(log.request_id)?.enrichment;
|
|
40942
|
+
if (enr) log.enrichment = enr;
|
|
40854
40943
|
process.stderr.write(`[PROTECT_MCP] ${JSON.stringify(log)}
|
|
40855
40944
|
`);
|
|
40856
40945
|
try {
|
package/dist/index.mjs
CHANGED
|
@@ -6,10 +6,9 @@ import {
|
|
|
6
6
|
createSelectiveDisclosurePackage,
|
|
7
7
|
discloseField,
|
|
8
8
|
hmac,
|
|
9
|
-
sha256 as sha2562,
|
|
10
9
|
signCommittedDecision,
|
|
11
10
|
verifySelectiveDisclosurePackage
|
|
12
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-UWB5ALVO.mjs";
|
|
13
12
|
import {
|
|
14
13
|
formatReportMarkdown,
|
|
15
14
|
generateReport
|
|
@@ -28,7 +27,7 @@ import {
|
|
|
28
27
|
readInstalledConnectorPilots,
|
|
29
28
|
simulate,
|
|
30
29
|
writeConnectorPilots
|
|
31
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-CXW2EIRM.mjs";
|
|
32
31
|
import {
|
|
33
32
|
ProtectGateway,
|
|
34
33
|
buildDecisionContext,
|
|
@@ -40,7 +39,7 @@ import {
|
|
|
40
39
|
resolveCredential,
|
|
41
40
|
sendApprovalNotification,
|
|
42
41
|
validateCredentials
|
|
43
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-GHR65WVD.mjs";
|
|
44
43
|
import {
|
|
45
44
|
createSandboxServer
|
|
46
45
|
} from "./chunk-SETXVE2K.mjs";
|
|
@@ -55,7 +54,11 @@ import {
|
|
|
55
54
|
forwardReceipt,
|
|
56
55
|
getScopeBlindBridge,
|
|
57
56
|
startHookServer
|
|
58
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-744JMCY4.mjs";
|
|
58
|
+
import "./chunk-KMNXHGGT.mjs";
|
|
59
|
+
import {
|
|
60
|
+
sha256 as sha2562
|
|
61
|
+
} from "./chunk-AYNQIEN7.mjs";
|
|
59
62
|
import {
|
|
60
63
|
checkRateLimit,
|
|
61
64
|
evaluateCedar,
|
|
@@ -70,7 +73,7 @@ import {
|
|
|
70
73
|
policySetFromSource,
|
|
71
74
|
runEvaluatorSelfTest,
|
|
72
75
|
signDecision
|
|
73
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-IDUH2O4Q.mjs";
|
|
74
77
|
import {
|
|
75
78
|
Field,
|
|
76
79
|
_abool2,
|
|
@@ -93,11 +96,13 @@ import {
|
|
|
93
96
|
normalizeZ,
|
|
94
97
|
numberToHexUnpadded,
|
|
95
98
|
pippenger,
|
|
99
|
+
wNAF
|
|
100
|
+
} from "./chunk-FFVJL3KQ.mjs";
|
|
101
|
+
import {
|
|
96
102
|
sha256,
|
|
97
103
|
sha384,
|
|
98
|
-
sha512
|
|
99
|
-
|
|
100
|
-
} from "./chunk-LJQOALYR.mjs";
|
|
104
|
+
sha512
|
|
105
|
+
} from "./chunk-JIDDQUSQ.mjs";
|
|
101
106
|
import {
|
|
102
107
|
ahash,
|
|
103
108
|
bytesToHex,
|
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
discloseField,
|
|
4
4
|
signCommittedDecision,
|
|
5
5
|
verifySelectiveDisclosurePackage
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-UWB5ALVO.mjs";
|
|
7
|
+
import "./chunk-AYNQIEN7.mjs";
|
|
8
|
+
import "./chunk-FFVJL3KQ.mjs";
|
|
9
|
+
import "./chunk-JIDDQUSQ.mjs";
|
|
8
10
|
import "./chunk-D733KAPG.mjs";
|
|
9
11
|
import "./chunk-PQJP2ZCI.mjs";
|
|
10
12
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "protect-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.2",
|
|
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",
|
package/policies/agent.cedar
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// Generated by protect-mcp init-hooks
|
|
2
|
-
// Customize these policies to match your security requirements.
|
|
3
|
-
// Cedar deny decisions are AUTHORITATIVE — they cannot be overridden.
|
|
4
|
-
|
|
5
|
-
// Allow all read-only tools by default
|
|
6
|
-
permit(
|
|
7
|
-
principal,
|
|
8
|
-
action == Action::"MCP::Tool::call",
|
|
9
|
-
resource == Tool::"Read"
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
permit(
|
|
13
|
-
principal,
|
|
14
|
-
action == Action::"MCP::Tool::call",
|
|
15
|
-
resource == Tool::"Glob"
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
permit(
|
|
19
|
-
principal,
|
|
20
|
-
action == Action::"MCP::Tool::call",
|
|
21
|
-
resource == Tool::"Grep"
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
// Allow write/edit tools (remove these to require explicit approval)
|
|
25
|
-
permit(
|
|
26
|
-
principal,
|
|
27
|
-
action == Action::"MCP::Tool::call",
|
|
28
|
-
resource == Tool::"Write"
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
permit(
|
|
32
|
-
principal,
|
|
33
|
-
action == Action::"MCP::Tool::call",
|
|
34
|
-
resource == Tool::"Edit"
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
// Allow Bash with caution (Cedar evaluates before hook patterns)
|
|
38
|
-
permit(
|
|
39
|
-
principal,
|
|
40
|
-
action == Action::"MCP::Tool::call",
|
|
41
|
-
resource == Tool::"Bash"
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
// Block dangerous tools entirely
|
|
45
|
-
// Uncomment any of these to block specific tools:
|
|
46
|
-
// forbid(
|
|
47
|
-
// principal,
|
|
48
|
-
// action == Action::"MCP::Tool::call",
|
|
49
|
-
// resource == Tool::"delete_file"
|
|
50
|
-
// );
|