protect-mcp 0.11.0 → 0.11.1
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/{chunk-3FSKOGGK.mjs → chunk-UBTX3A3D.mjs} +37 -1
- package/dist/cli.js +43 -1
- package/dist/cli.mjs +1 -1
- package/dist/{coverage-NB55FTYL.mjs → coverage-IHN7MUBH.mjs} +10 -2
- package/dist/hook-server.js +65 -0
- package/dist/hook-server.mjs +1 -1
- package/dist/index.js +35 -0
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
evaluateCedar,
|
|
20
20
|
isCedarAvailable,
|
|
21
|
-
loadCedarPolicies
|
|
21
|
+
loadCedarPolicies,
|
|
22
|
+
runEvaluatorSelfTest
|
|
22
23
|
} from "./chunk-FGCNKEEW.mjs";
|
|
23
24
|
import {
|
|
24
25
|
receiptHash
|
|
@@ -826,6 +827,41 @@ async function startHookServer(options = {}) {
|
|
|
826
827
|
}
|
|
827
828
|
}
|
|
828
829
|
}
|
|
830
|
+
if (enforce) {
|
|
831
|
+
const selfTest = await runEvaluatorSelfTest();
|
|
832
|
+
for (const c of selfTest.cases) {
|
|
833
|
+
if (!c.pass) {
|
|
834
|
+
process.stderr.write(
|
|
835
|
+
`[PROTECT_MCP] SELF-TEST FAIL: ${c.name} (expected ${c.expected}, got ${c.actual})
|
|
836
|
+
`
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (!selfTest.passed) {
|
|
841
|
+
throw new Error(
|
|
842
|
+
"enforce mode refused to start: the restraint self-test failed. A gate that cannot prove it denies must not arm."
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
const receiptProbe = signDecision({
|
|
846
|
+
v: 2,
|
|
847
|
+
tool: "__protect_mcp_startup_selftest__",
|
|
848
|
+
decision: "deny",
|
|
849
|
+
reason_code: "startup_selftest",
|
|
850
|
+
policy_digest: policyDigest,
|
|
851
|
+
request_id: `selftest-${Date.now()}`,
|
|
852
|
+
mode: "enforce",
|
|
853
|
+
timestamp: Date.now()
|
|
854
|
+
});
|
|
855
|
+
if (receiptProbe.error) {
|
|
856
|
+
throw new Error(
|
|
857
|
+
`enforce mode refused to start: signing is configured but a denial receipt could not be produced (${receiptProbe.error}). An enforcing gate that cannot evidence a denial must not arm.`
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
process.stderr.write(
|
|
861
|
+
`[PROTECT_MCP] Restraint self-test passed (${selfTest.cases.length} vectors${selfTest.wasmAvailable ? "" : "; Cedar WASM absent, fail-closed invariant verified"})${receiptProbe.ok ? "; denial receipt signing verified" : ""}. Arming enforce mode.
|
|
862
|
+
`
|
|
863
|
+
);
|
|
864
|
+
}
|
|
829
865
|
const state = {
|
|
830
866
|
cedarPolicies,
|
|
831
867
|
cedarDir: cedarDir || null,
|
package/dist/cli.js
CHANGED
|
@@ -4930,6 +4930,41 @@ async function startHookServer(options = {}) {
|
|
|
4930
4930
|
}
|
|
4931
4931
|
}
|
|
4932
4932
|
}
|
|
4933
|
+
if (enforce) {
|
|
4934
|
+
const selfTest = await runEvaluatorSelfTest();
|
|
4935
|
+
for (const c of selfTest.cases) {
|
|
4936
|
+
if (!c.pass) {
|
|
4937
|
+
process.stderr.write(
|
|
4938
|
+
`[PROTECT_MCP] SELF-TEST FAIL: ${c.name} (expected ${c.expected}, got ${c.actual})
|
|
4939
|
+
`
|
|
4940
|
+
);
|
|
4941
|
+
}
|
|
4942
|
+
}
|
|
4943
|
+
if (!selfTest.passed) {
|
|
4944
|
+
throw new Error(
|
|
4945
|
+
"enforce mode refused to start: the restraint self-test failed. A gate that cannot prove it denies must not arm."
|
|
4946
|
+
);
|
|
4947
|
+
}
|
|
4948
|
+
const receiptProbe = signDecision({
|
|
4949
|
+
v: 2,
|
|
4950
|
+
tool: "__protect_mcp_startup_selftest__",
|
|
4951
|
+
decision: "deny",
|
|
4952
|
+
reason_code: "startup_selftest",
|
|
4953
|
+
policy_digest: policyDigest,
|
|
4954
|
+
request_id: `selftest-${Date.now()}`,
|
|
4955
|
+
mode: "enforce",
|
|
4956
|
+
timestamp: Date.now()
|
|
4957
|
+
});
|
|
4958
|
+
if (receiptProbe.error) {
|
|
4959
|
+
throw new Error(
|
|
4960
|
+
`enforce mode refused to start: signing is configured but a denial receipt could not be produced (${receiptProbe.error}). An enforcing gate that cannot evidence a denial must not arm.`
|
|
4961
|
+
);
|
|
4962
|
+
}
|
|
4963
|
+
process.stderr.write(
|
|
4964
|
+
`[PROTECT_MCP] Restraint self-test passed (${selfTest.cases.length} vectors${selfTest.wasmAvailable ? "" : "; Cedar WASM absent, fail-closed invariant verified"})${receiptProbe.ok ? "; denial receipt signing verified" : ""}. Arming enforce mode.
|
|
4965
|
+
`
|
|
4966
|
+
);
|
|
4967
|
+
}
|
|
4933
4968
|
const state = {
|
|
4934
4969
|
cedarPolicies,
|
|
4935
4970
|
cedarDir: cedarDir || null,
|
|
@@ -5281,6 +5316,8 @@ function buildCoverageStatement(input) {
|
|
|
5281
5316
|
not_governed: [...DEFAULT_NOT_GOVERNED, ...extras],
|
|
5282
5317
|
residual_bypass_routes: RESIDUAL_BYPASS_ROUTES,
|
|
5283
5318
|
self_test: input.probe,
|
|
5319
|
+
...input.evaluatorSelfTest !== void 0 ? { evaluator_self_test: input.evaluatorSelfTest } : {},
|
|
5320
|
+
basis: "configuration-at-generation-time",
|
|
5284
5321
|
attestation_note: ATTESTATION_NOTE
|
|
5285
5322
|
};
|
|
5286
5323
|
}
|
|
@@ -5337,6 +5374,7 @@ async function handleCoverage(args) {
|
|
|
5337
5374
|
return;
|
|
5338
5375
|
}
|
|
5339
5376
|
const version = process.env.PROTECT_MCP_VERSION || "unknown";
|
|
5377
|
+
const evaluatorSelfTest = await runEvaluatorSelfTest();
|
|
5340
5378
|
let statement;
|
|
5341
5379
|
let signingConfig;
|
|
5342
5380
|
if (opts.cedarDir) {
|
|
@@ -5357,6 +5395,7 @@ async function handleCoverage(args) {
|
|
|
5357
5395
|
reason: "cedar policies are evaluated per-request; a static probe would not exercise the WASM evaluation path. Run the gate with --enforce to exercise live evaluation."
|
|
5358
5396
|
},
|
|
5359
5397
|
extraNotGoverned: opts.extraNotGoverned,
|
|
5398
|
+
evaluatorSelfTest,
|
|
5360
5399
|
packageVersion: version
|
|
5361
5400
|
});
|
|
5362
5401
|
} else if (opts.policyPath) {
|
|
@@ -5374,6 +5413,7 @@ async function handleCoverage(args) {
|
|
|
5374
5413
|
wildcardRule: analyzed.wildcardRule,
|
|
5375
5414
|
probe: analyzed.probe,
|
|
5376
5415
|
extraNotGoverned: opts.extraNotGoverned,
|
|
5416
|
+
evaluatorSelfTest,
|
|
5377
5417
|
packageVersion: version
|
|
5378
5418
|
});
|
|
5379
5419
|
} else {
|
|
@@ -5387,6 +5427,7 @@ async function handleCoverage(args) {
|
|
|
5387
5427
|
blockedTools: [],
|
|
5388
5428
|
probe: { method: "none", reason: "no policy loaded; the gate would allow all tool calls" },
|
|
5389
5429
|
extraNotGoverned: opts.extraNotGoverned,
|
|
5430
|
+
evaluatorSelfTest,
|
|
5390
5431
|
packageVersion: version
|
|
5391
5432
|
});
|
|
5392
5433
|
}
|
|
@@ -5428,6 +5469,7 @@ async function handleCoverage(args) {
|
|
|
5428
5469
|
governed : ${statement.governed.tools_with_explicit_rules.length} tools with explicit rules${statement.governed.explicitly_blocked_tools.length ? `, ${statement.governed.explicitly_blocked_tools.length} explicitly blocked` : ""}
|
|
5429
5470
|
not governed: ${statement.not_governed.length} declared items (defaults cannot be removed)
|
|
5430
5471
|
self test : ${statement.self_test.method}${statement.self_test.would_deny !== void 0 ? ` (would_deny=${statement.self_test.would_deny})` : ""}
|
|
5472
|
+
evaluator : live self-test ${evaluatorSelfTest.passed ? "passed" : "FAILED"} (${evaluatorSelfTest.cases.length} vectors)
|
|
5431
5473
|
signed : ${signer ? `yes (kid ${signer.kid})` : "no (unsigned declaration)"}
|
|
5432
5474
|
`
|
|
5433
5475
|
);
|
|
@@ -5473,7 +5515,7 @@ var init_coverage = __esm({
|
|
|
5473
5515
|
residual_risk: "downstream system behavior (not this layer)"
|
|
5474
5516
|
}
|
|
5475
5517
|
];
|
|
5476
|
-
ATTESTATION_NOTE = "This statement enumerates what the gate is configured to govern and declares what it does not see. It is a scope declaration, not a proof of the absence of other action paths: making the gate the only path is a deployment property (single-endpoint configuration, or egress lockdown for a hard guarantee). Shadow enforcement observes and receipts but does not block.";
|
|
5518
|
+
ATTESTATION_NOTE = "This statement enumerates what the gate is configured to govern and declares what it does not see. It is a scope declaration, not a proof of the absence of other action paths: making the gate the only path is a deployment property (single-endpoint configuration, or egress lockdown for a hard guarantee). Shadow enforcement observes and receipts but does not block. The statement reflects configuration at generation time; a statement emitted by the running gateway (observed coverage, with intended-versus-observed mismatch flagging) is on the roadmap. In enforce mode the gate refuses to arm unless the live restraint self-test passes.";
|
|
5477
5519
|
CHANNEL_DESCRIPTION = {
|
|
5478
5520
|
hook: "every tool call the agent harness routes through the pre-tool-call hook",
|
|
5479
5521
|
proxy: "every call made to the gate HTTP endpoint wrapping the tool server"
|
package/dist/cli.mjs
CHANGED
|
@@ -4529,7 +4529,7 @@ async function main() {
|
|
|
4529
4529
|
return;
|
|
4530
4530
|
}
|
|
4531
4531
|
if (args[0] === "coverage") {
|
|
4532
|
-
const { handleCoverage } = await import("./coverage-
|
|
4532
|
+
const { handleCoverage } = await import("./coverage-IHN7MUBH.mjs");
|
|
4533
4533
|
await handleCoverage(args.slice(1));
|
|
4534
4534
|
process.exit(process.exitCode || 0);
|
|
4535
4535
|
}
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
signGenericArtifact
|
|
8
8
|
} from "./chunk-WMIWQ6TS.mjs";
|
|
9
9
|
import {
|
|
10
|
-
loadCedarPolicies
|
|
10
|
+
loadCedarPolicies,
|
|
11
|
+
runEvaluatorSelfTest
|
|
11
12
|
} from "./chunk-FGCNKEEW.mjs";
|
|
12
13
|
import "./chunk-XOP3PEBM.mjs";
|
|
13
14
|
import "./chunk-PQJP2ZCI.mjs";
|
|
@@ -47,7 +48,7 @@ var RESIDUAL_BYPASS_ROUTES = [
|
|
|
47
48
|
residual_risk: "downstream system behavior (not this layer)"
|
|
48
49
|
}
|
|
49
50
|
];
|
|
50
|
-
var ATTESTATION_NOTE = "This statement enumerates what the gate is configured to govern and declares what it does not see. It is a scope declaration, not a proof of the absence of other action paths: making the gate the only path is a deployment property (single-endpoint configuration, or egress lockdown for a hard guarantee). Shadow enforcement observes and receipts but does not block.";
|
|
51
|
+
var ATTESTATION_NOTE = "This statement enumerates what the gate is configured to govern and declares what it does not see. It is a scope declaration, not a proof of the absence of other action paths: making the gate the only path is a deployment property (single-endpoint configuration, or egress lockdown for a hard guarantee). Shadow enforcement observes and receipts but does not block. The statement reflects configuration at generation time; a statement emitted by the running gateway (observed coverage, with intended-versus-observed mismatch flagging) is on the roadmap. In enforce mode the gate refuses to arm unless the live restraint self-test passes.";
|
|
51
52
|
var CHANNEL_DESCRIPTION = {
|
|
52
53
|
hook: "every tool call the agent harness routes through the pre-tool-call hook",
|
|
53
54
|
proxy: "every call made to the gate HTTP endpoint wrapping the tool server"
|
|
@@ -77,6 +78,8 @@ function buildCoverageStatement(input) {
|
|
|
77
78
|
not_governed: [...DEFAULT_NOT_GOVERNED, ...extras],
|
|
78
79
|
residual_bypass_routes: RESIDUAL_BYPASS_ROUTES,
|
|
79
80
|
self_test: input.probe,
|
|
81
|
+
...input.evaluatorSelfTest !== void 0 ? { evaluator_self_test: input.evaluatorSelfTest } : {},
|
|
82
|
+
basis: "configuration-at-generation-time",
|
|
80
83
|
attestation_note: ATTESTATION_NOTE
|
|
81
84
|
};
|
|
82
85
|
}
|
|
@@ -133,6 +136,7 @@ async function handleCoverage(args) {
|
|
|
133
136
|
return;
|
|
134
137
|
}
|
|
135
138
|
const version = process.env.PROTECT_MCP_VERSION || "unknown";
|
|
139
|
+
const evaluatorSelfTest = await runEvaluatorSelfTest();
|
|
136
140
|
let statement;
|
|
137
141
|
let signingConfig;
|
|
138
142
|
if (opts.cedarDir) {
|
|
@@ -153,6 +157,7 @@ async function handleCoverage(args) {
|
|
|
153
157
|
reason: "cedar policies are evaluated per-request; a static probe would not exercise the WASM evaluation path. Run the gate with --enforce to exercise live evaluation."
|
|
154
158
|
},
|
|
155
159
|
extraNotGoverned: opts.extraNotGoverned,
|
|
160
|
+
evaluatorSelfTest,
|
|
156
161
|
packageVersion: version
|
|
157
162
|
});
|
|
158
163
|
} else if (opts.policyPath) {
|
|
@@ -170,6 +175,7 @@ async function handleCoverage(args) {
|
|
|
170
175
|
wildcardRule: analyzed.wildcardRule,
|
|
171
176
|
probe: analyzed.probe,
|
|
172
177
|
extraNotGoverned: opts.extraNotGoverned,
|
|
178
|
+
evaluatorSelfTest,
|
|
173
179
|
packageVersion: version
|
|
174
180
|
});
|
|
175
181
|
} else {
|
|
@@ -183,6 +189,7 @@ async function handleCoverage(args) {
|
|
|
183
189
|
blockedTools: [],
|
|
184
190
|
probe: { method: "none", reason: "no policy loaded; the gate would allow all tool calls" },
|
|
185
191
|
extraNotGoverned: opts.extraNotGoverned,
|
|
192
|
+
evaluatorSelfTest,
|
|
186
193
|
packageVersion: version
|
|
187
194
|
});
|
|
188
195
|
}
|
|
@@ -224,6 +231,7 @@ async function handleCoverage(args) {
|
|
|
224
231
|
governed : ${statement.governed.tools_with_explicit_rules.length} tools with explicit rules${statement.governed.explicitly_blocked_tools.length ? `, ${statement.governed.explicitly_blocked_tools.length} explicitly blocked` : ""}
|
|
225
232
|
not governed: ${statement.not_governed.length} declared items (defaults cannot be removed)
|
|
226
233
|
self test : ${statement.self_test.method}${statement.self_test.would_deny !== void 0 ? ` (would_deny=${statement.self_test.would_deny})` : ""}
|
|
234
|
+
evaluator : live self-test ${evaluatorSelfTest.passed ? "passed" : "FAILED"} (${evaluatorSelfTest.cases.length} vectors)
|
|
227
235
|
signed : ${signer ? `yes (kid ${signer.kid})` : "no (unsigned declaration)"}
|
|
228
236
|
`
|
|
229
237
|
);
|
package/dist/hook-server.js
CHANGED
|
@@ -109,6 +109,9 @@ function digestPolicyFiles(engine, files) {
|
|
|
109
109
|
files: entries
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
|
+
function digestCedarSource(source) {
|
|
113
|
+
return digestPolicyFiles("cedar", [{ name: "policy.cedar", content: source }]);
|
|
114
|
+
}
|
|
112
115
|
function digestBuiltinPolicy(policy) {
|
|
113
116
|
return digestPolicyFiles("builtin", [{ name: "policy.json", content: canonicalize(policy) }]);
|
|
114
117
|
}
|
|
@@ -284,6 +287,33 @@ function extractPolicyErrors(result) {
|
|
|
284
287
|
async function isCedarAvailable() {
|
|
285
288
|
return ensureCedarWasm();
|
|
286
289
|
}
|
|
290
|
+
function policySetFromSource(source, name = "inline") {
|
|
291
|
+
const digest = digestCedarSource(source).policy_digest;
|
|
292
|
+
return { source, digest, fileCount: 1, files: [name] };
|
|
293
|
+
}
|
|
294
|
+
async function runEvaluatorSelfTest() {
|
|
295
|
+
const wasmAvailable = await isCedarAvailable();
|
|
296
|
+
const cases = [];
|
|
297
|
+
const run = async (name, expected, policy, context) => {
|
|
298
|
+
const d = await evaluateCedar(policy, { tool: "Bash", tier: "unknown", context }, void 0, { failClosed: true });
|
|
299
|
+
const actual = d.allowed ? "ALLOW" : "DENY";
|
|
300
|
+
cases.push({ name, expected, actual, pass: actual === expected, reason: d.reason });
|
|
301
|
+
};
|
|
302
|
+
if (!wasmAvailable) {
|
|
303
|
+
await run("engine unavailable denies", "DENY", policySetFromSource("permit(principal, action, resource);"), {});
|
|
304
|
+
return { wasmAvailable, passed: cases.every((c) => c.pass), cases };
|
|
305
|
+
}
|
|
306
|
+
const correct = policySetFromSource(
|
|
307
|
+
'forbid(principal, action, resource) when { ["rm", "dd", "mkfs"].contains(context.command) };\npermit(principal, action, resource);'
|
|
308
|
+
);
|
|
309
|
+
await run("forbid denies rm", "DENY", correct, { command: "rm" });
|
|
310
|
+
await run("permit allows ls", "ALLOW", correct, { command: "ls" });
|
|
311
|
+
const broken = policySetFromSource(
|
|
312
|
+
'forbid(principal, action, resource) when { context.command in ["rm", "dd"] };\npermit(principal, action, resource);'
|
|
313
|
+
);
|
|
314
|
+
await run("in-on-String forbid does not permit-all", "DENY", broken, { command: "rm" });
|
|
315
|
+
return { wasmAvailable, passed: cases.every((c) => c.pass), cases };
|
|
316
|
+
}
|
|
287
317
|
|
|
288
318
|
// src/signing.ts
|
|
289
319
|
var import_node_fs3 = require("fs");
|
|
@@ -1536,6 +1566,41 @@ async function startHookServer(options = {}) {
|
|
|
1536
1566
|
}
|
|
1537
1567
|
}
|
|
1538
1568
|
}
|
|
1569
|
+
if (enforce) {
|
|
1570
|
+
const selfTest = await runEvaluatorSelfTest();
|
|
1571
|
+
for (const c of selfTest.cases) {
|
|
1572
|
+
if (!c.pass) {
|
|
1573
|
+
process.stderr.write(
|
|
1574
|
+
`[PROTECT_MCP] SELF-TEST FAIL: ${c.name} (expected ${c.expected}, got ${c.actual})
|
|
1575
|
+
`
|
|
1576
|
+
);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
if (!selfTest.passed) {
|
|
1580
|
+
throw new Error(
|
|
1581
|
+
"enforce mode refused to start: the restraint self-test failed. A gate that cannot prove it denies must not arm."
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
const receiptProbe = signDecision({
|
|
1585
|
+
v: 2,
|
|
1586
|
+
tool: "__protect_mcp_startup_selftest__",
|
|
1587
|
+
decision: "deny",
|
|
1588
|
+
reason_code: "startup_selftest",
|
|
1589
|
+
policy_digest: policyDigest,
|
|
1590
|
+
request_id: `selftest-${Date.now()}`,
|
|
1591
|
+
mode: "enforce",
|
|
1592
|
+
timestamp: Date.now()
|
|
1593
|
+
});
|
|
1594
|
+
if (receiptProbe.error) {
|
|
1595
|
+
throw new Error(
|
|
1596
|
+
`enforce mode refused to start: signing is configured but a denial receipt could not be produced (${receiptProbe.error}). An enforcing gate that cannot evidence a denial must not arm.`
|
|
1597
|
+
);
|
|
1598
|
+
}
|
|
1599
|
+
process.stderr.write(
|
|
1600
|
+
`[PROTECT_MCP] Restraint self-test passed (${selfTest.cases.length} vectors${selfTest.wasmAvailable ? "" : "; Cedar WASM absent, fail-closed invariant verified"})${receiptProbe.ok ? "; denial receipt signing verified" : ""}. Arming enforce mode.
|
|
1601
|
+
`
|
|
1602
|
+
);
|
|
1603
|
+
}
|
|
1539
1604
|
const state = {
|
|
1540
1605
|
cedarPolicies,
|
|
1541
1606
|
cedarDir: cedarDir || null,
|
package/dist/hook-server.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -38947,6 +38947,41 @@ async function startHookServer(options = {}) {
|
|
|
38947
38947
|
}
|
|
38948
38948
|
}
|
|
38949
38949
|
}
|
|
38950
|
+
if (enforce) {
|
|
38951
|
+
const selfTest = await runEvaluatorSelfTest();
|
|
38952
|
+
for (const c of selfTest.cases) {
|
|
38953
|
+
if (!c.pass) {
|
|
38954
|
+
process.stderr.write(
|
|
38955
|
+
`[PROTECT_MCP] SELF-TEST FAIL: ${c.name} (expected ${c.expected}, got ${c.actual})
|
|
38956
|
+
`
|
|
38957
|
+
);
|
|
38958
|
+
}
|
|
38959
|
+
}
|
|
38960
|
+
if (!selfTest.passed) {
|
|
38961
|
+
throw new Error(
|
|
38962
|
+
"enforce mode refused to start: the restraint self-test failed. A gate that cannot prove it denies must not arm."
|
|
38963
|
+
);
|
|
38964
|
+
}
|
|
38965
|
+
const receiptProbe = signDecision({
|
|
38966
|
+
v: 2,
|
|
38967
|
+
tool: "__protect_mcp_startup_selftest__",
|
|
38968
|
+
decision: "deny",
|
|
38969
|
+
reason_code: "startup_selftest",
|
|
38970
|
+
policy_digest: policyDigest,
|
|
38971
|
+
request_id: `selftest-${Date.now()}`,
|
|
38972
|
+
mode: "enforce",
|
|
38973
|
+
timestamp: Date.now()
|
|
38974
|
+
});
|
|
38975
|
+
if (receiptProbe.error) {
|
|
38976
|
+
throw new Error(
|
|
38977
|
+
`enforce mode refused to start: signing is configured but a denial receipt could not be produced (${receiptProbe.error}). An enforcing gate that cannot evidence a denial must not arm.`
|
|
38978
|
+
);
|
|
38979
|
+
}
|
|
38980
|
+
process.stderr.write(
|
|
38981
|
+
`[PROTECT_MCP] Restraint self-test passed (${selfTest.cases.length} vectors${selfTest.wasmAvailable ? "" : "; Cedar WASM absent, fail-closed invariant verified"})${receiptProbe.ok ? "; denial receipt signing verified" : ""}. Arming enforce mode.
|
|
38982
|
+
`
|
|
38983
|
+
);
|
|
38984
|
+
}
|
|
38950
38985
|
const state = {
|
|
38951
38986
|
cedarPolicies,
|
|
38952
38987
|
cedarDir: cedarDir || null,
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "protect-mcp",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
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",
|