protect-mcp 0.2.2 → 0.3.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/README.md +11 -1
- package/dist/bundle-TXOTFJIJ.mjs +8 -0
- package/dist/chunk-5JXFV37Y.mjs +53 -0
- package/dist/chunk-U7TMVD3E.mjs +1105 -0
- package/dist/cli.js +1176 -172
- package/dist/cli.mjs +462 -5
- package/dist/demo-server.d.mts +1 -0
- package/dist/demo-server.d.ts +1 -0
- package/dist/demo-server.js +137 -0
- package/dist/demo-server.mjs +136 -0
- package/dist/index.d.mts +83 -61
- package/dist/index.d.ts +83 -61
- package/dist/index.js +637 -271
- package/dist/index.mjs +7 -172
- package/package.json +3 -3
- package/dist/chunk-ZCKNFULF.mjs +0 -613
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProtectGateway,
|
|
3
|
+
buildDecisionContext,
|
|
3
4
|
checkRateLimit,
|
|
4
5
|
evaluateTier,
|
|
5
6
|
getSignerInfo,
|
|
@@ -10,181 +11,15 @@ import {
|
|
|
10
11
|
loadPolicy,
|
|
11
12
|
meetsMinTier,
|
|
12
13
|
parseRateLimit,
|
|
14
|
+
queryExternalPDP,
|
|
13
15
|
resolveCredential,
|
|
14
16
|
signDecision,
|
|
15
17
|
validateCredentials
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const controller = new AbortController();
|
|
22
|
-
const timer = setTimeout(() => controller.abort(), timeout);
|
|
23
|
-
try {
|
|
24
|
-
const body = formatRequest(context, config.format || "generic");
|
|
25
|
-
const response = await fetch(config.endpoint, {
|
|
26
|
-
method: "POST",
|
|
27
|
-
headers: { "Content-Type": "application/json" },
|
|
28
|
-
body: JSON.stringify(body),
|
|
29
|
-
signal: controller.signal
|
|
30
|
-
});
|
|
31
|
-
clearTimeout(timer);
|
|
32
|
-
if (!response.ok) {
|
|
33
|
-
return fallbackDecision(config, `PDP returned HTTP ${response.status}`);
|
|
34
|
-
}
|
|
35
|
-
const result = await response.json();
|
|
36
|
-
return parseResponse(result, config.format || "generic");
|
|
37
|
-
} catch (err) {
|
|
38
|
-
clearTimeout(timer);
|
|
39
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
40
|
-
return fallbackDecision(config, `PDP timeout after ${timeout}ms`);
|
|
41
|
-
}
|
|
42
|
-
return fallbackDecision(config, `PDP error: ${err instanceof Error ? err.message : "unknown"}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function formatRequest(context, format) {
|
|
46
|
-
switch (format) {
|
|
47
|
-
case "opa":
|
|
48
|
-
return {
|
|
49
|
-
input: {
|
|
50
|
-
actor: context.actor,
|
|
51
|
-
action: context.action,
|
|
52
|
-
target: context.target,
|
|
53
|
-
credential_ref: context.credential_ref,
|
|
54
|
-
mode: context.mode,
|
|
55
|
-
metadata: context.request_metadata
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
case "cerbos":
|
|
59
|
-
return {
|
|
60
|
-
principal: {
|
|
61
|
-
id: context.actor.id || "unknown",
|
|
62
|
-
roles: [context.actor.tier],
|
|
63
|
-
attr: {
|
|
64
|
-
manifest_hash: context.actor.manifest_hash
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
resource: {
|
|
68
|
-
kind: "tool",
|
|
69
|
-
id: context.action.tool,
|
|
70
|
-
attr: context.target
|
|
71
|
-
},
|
|
72
|
-
actions: [context.action.operation || "call"]
|
|
73
|
-
};
|
|
74
|
-
case "generic":
|
|
75
|
-
default:
|
|
76
|
-
return context;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function parseResponse(result, format) {
|
|
80
|
-
switch (format) {
|
|
81
|
-
case "opa":
|
|
82
|
-
if (typeof result.result === "boolean") {
|
|
83
|
-
return { allowed: result.result };
|
|
84
|
-
}
|
|
85
|
-
if (result.result && typeof result.result === "object") {
|
|
86
|
-
const r = result.result;
|
|
87
|
-
return {
|
|
88
|
-
allowed: Boolean(r.allow),
|
|
89
|
-
reason: r.reason,
|
|
90
|
-
metadata: r
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
return { allowed: false, reason: "unrecognized OPA response" };
|
|
94
|
-
case "cerbos":
|
|
95
|
-
if (Array.isArray(result.results) && result.results.length > 0) {
|
|
96
|
-
const actions = result.results[0].actions;
|
|
97
|
-
if (actions) {
|
|
98
|
-
const effect = Object.values(actions)[0];
|
|
99
|
-
return { allowed: effect === "EFFECT_ALLOW" };
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return { allowed: false, reason: "unrecognized Cerbos response" };
|
|
103
|
-
case "generic":
|
|
104
|
-
default:
|
|
105
|
-
return {
|
|
106
|
-
allowed: Boolean(result.allowed),
|
|
107
|
-
reason: result.reason,
|
|
108
|
-
metadata: result.metadata
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
function fallbackDecision(config, reason) {
|
|
113
|
-
const fallback = config.fallback || "deny";
|
|
114
|
-
return {
|
|
115
|
-
allowed: fallback === "allow",
|
|
116
|
-
reason: `fallback_${fallback}: ${reason}`
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function buildDecisionContext(toolName, tier, opts) {
|
|
120
|
-
return {
|
|
121
|
-
v: 1,
|
|
122
|
-
actor: {
|
|
123
|
-
id: opts.agentId,
|
|
124
|
-
tier,
|
|
125
|
-
manifest_hash: opts.manifestHash
|
|
126
|
-
},
|
|
127
|
-
action: {
|
|
128
|
-
tool: toolName,
|
|
129
|
-
operation: "call"
|
|
130
|
-
},
|
|
131
|
-
target: {
|
|
132
|
-
service: opts.slug || "default"
|
|
133
|
-
},
|
|
134
|
-
credential_ref: opts.credentialRef,
|
|
135
|
-
mode: opts.mode,
|
|
136
|
-
request_metadata: opts.requestMetadata || {}
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// src/bundle.ts
|
|
141
|
-
function createAuditBundle(opts) {
|
|
142
|
-
const receipts = opts.receipts.filter(
|
|
143
|
-
(r) => r && typeof r === "object" && typeof r.signature === "string"
|
|
144
|
-
);
|
|
145
|
-
if (receipts.length === 0) {
|
|
146
|
-
throw new Error("Audit bundle requires at least one signed receipt");
|
|
147
|
-
}
|
|
148
|
-
const keyMap = /* @__PURE__ */ new Map();
|
|
149
|
-
for (const key of opts.signingKeys) {
|
|
150
|
-
if (!keyMap.has(key.kid)) {
|
|
151
|
-
keyMap.set(key.kid, key);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
let timeRange = opts.timeRange || null;
|
|
155
|
-
if (!timeRange) {
|
|
156
|
-
const timestamps = receipts.map((r) => r.issued_at || r.timestamp).filter(Boolean).sort();
|
|
157
|
-
if (timestamps.length > 0) {
|
|
158
|
-
timeRange = {
|
|
159
|
-
from: timestamps[0],
|
|
160
|
-
to: timestamps[timestamps.length - 1]
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return {
|
|
165
|
-
format: "scopeblind:audit-bundle",
|
|
166
|
-
version: 1,
|
|
167
|
-
exported_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
168
|
-
tenant: opts.tenant,
|
|
169
|
-
time_range: timeRange,
|
|
170
|
-
receipts,
|
|
171
|
-
anchors: opts.anchors || [],
|
|
172
|
-
verification: {
|
|
173
|
-
algorithm: "ed25519",
|
|
174
|
-
signing_keys: Array.from(keyMap.values()),
|
|
175
|
-
instructions: `Verify each receipt by: (1) remove the "signature" field, (2) canonicalize the remaining object with JCS (sorted keys at every level), (3) encode as UTF-8 bytes, (4) verify the Ed25519 signature using the signing key matching the receipt's "kid" field. CLI: npx @veritasacta/verify bundle.json --bundle`
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
function collectSignedReceipts(logs) {
|
|
180
|
-
return logs.filter((log) => log.v === 2).map((log) => {
|
|
181
|
-
const logRecord = log;
|
|
182
|
-
if (logRecord.receipt) {
|
|
183
|
-
return logRecord.receipt;
|
|
184
|
-
}
|
|
185
|
-
return logRecord;
|
|
186
|
-
}).filter((r) => typeof r.signature === "string");
|
|
187
|
-
}
|
|
18
|
+
} from "./chunk-U7TMVD3E.mjs";
|
|
19
|
+
import {
|
|
20
|
+
collectSignedReceipts,
|
|
21
|
+
createAuditBundle
|
|
22
|
+
} from "./chunk-5JXFV37Y.mjs";
|
|
188
23
|
|
|
189
24
|
// src/manifest.ts
|
|
190
25
|
function isAgentId(s) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "protect-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Security gateway for MCP servers. Shadow-mode logs
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Security gateway for MCP servers. Shadow-mode logs, per-tool policies, optional local Ed25519-signed receipts. Programmatic hooks for trust tiers, credential config, and external policy engines.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --clean",
|
|
19
|
+
"build": "tsup src/index.ts src/cli.ts src/demo-server.ts --format cjs,esm --dts --clean",
|
|
20
20
|
"test": "vitest run",
|
|
21
21
|
"prepublishOnly": "npm run build"
|
|
22
22
|
},
|