@permission-protocol/mcp-guard 0.1.0
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 +224 -0
- package/assets/demo.gif +0 -0
- package/bin/mcp-guard +2 -0
- package/demo/_demo-scenario.sh +43 -0
- package/dist/example/server.d.ts +1 -0
- package/dist/example/server.js +54 -0
- package/dist/example/server.js.map +1 -0
- package/dist/src/approval-server.d.ts +4 -0
- package/dist/src/approval-server.js +128 -0
- package/dist/src/approval-server.js.map +1 -0
- package/dist/src/approval-ui.d.ts +1 -0
- package/dist/src/approval-ui.js +158 -0
- package/dist/src/approval-ui.js.map +1 -0
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +82 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.d.ts +13 -0
- package/dist/src/config.js +48 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/engine.d.ts +7 -0
- package/dist/src/engine.js +25 -0
- package/dist/src/engine.js.map +1 -0
- package/dist/src/pending.d.ts +20 -0
- package/dist/src/pending.js +44 -0
- package/dist/src/pending.js.map +1 -0
- package/dist/src/proxy.d.ts +2 -0
- package/dist/src/proxy.js +147 -0
- package/dist/src/proxy.js.map +1 -0
- package/dist/src/receipt.d.ts +15 -0
- package/dist/src/receipt.js +34 -0
- package/dist/src/receipt.js.map +1 -0
- package/dist/src/tests/config.test.d.ts +1 -0
- package/dist/src/tests/config.test.js +63 -0
- package/dist/src/tests/config.test.js.map +1 -0
- package/dist/src/tests/engine.test.d.ts +1 -0
- package/dist/src/tests/engine.test.js +46 -0
- package/dist/src/tests/engine.test.js.map +1 -0
- package/dist/src/tests/receipt.test.d.ts +1 -0
- package/dist/src/tests/receipt.test.js +44 -0
- package/dist/src/tests/receipt.test.js.map +1 -0
- package/docs/index.html +771 -0
- package/example/README.md +38 -0
- package/example/pp.config.yaml +15 -0
- package/example/server.ts +52 -0
- package/example/test.sh +64 -0
- package/package.json +29 -0
- package/permission-protocol-mcp-guard-0.1.0.tgz +0 -0
- package/src/approval-server.ts +136 -0
- package/src/approval-ui.ts +154 -0
- package/src/cli.ts +84 -0
- package/src/config.ts +68 -0
- package/src/engine.ts +31 -0
- package/src/pending.ts +65 -0
- package/src/proxy.ts +173 -0
- package/src/receipt.ts +52 -0
- package/src/tests/config.test.ts +61 -0
- package/src/tests/engine.test.ts +47 -0
- package/src/tests/receipt.test.ts +44 -0
- package/tsconfig.json +16 -0
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
const config_js_1 = require("./config.js");
|
|
5
|
+
const proxy_js_1 = require("./proxy.js");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
function main() {
|
|
9
|
+
const args = process.argv.slice(2);
|
|
10
|
+
if (args[0] === 'demo') {
|
|
11
|
+
// When running via npx @permission-protocol/mcp-guard demo
|
|
12
|
+
const scriptPath = (0, node_path_1.join)(__dirname, '../../example/test.sh');
|
|
13
|
+
const result = (0, node_child_process_1.spawnSync)('bash', [scriptPath], { stdio: 'inherit' });
|
|
14
|
+
process.exit(result.status ?? 0);
|
|
15
|
+
}
|
|
16
|
+
let configPath = './pp.config.yaml';
|
|
17
|
+
let agentId = 'unknown';
|
|
18
|
+
let modeOverride;
|
|
19
|
+
let approvalPort;
|
|
20
|
+
let serverCommand = [];
|
|
21
|
+
const dashDashIndex = args.indexOf('--');
|
|
22
|
+
const cliArgs = dashDashIndex >= 0 ? args.slice(0, dashDashIndex) : args;
|
|
23
|
+
serverCommand = dashDashIndex >= 0 ? args.slice(dashDashIndex + 1) : [];
|
|
24
|
+
for (let i = 0; i < cliArgs.length; i++) {
|
|
25
|
+
if (cliArgs[i] === '--config' && cliArgs[i + 1]) {
|
|
26
|
+
configPath = cliArgs[++i];
|
|
27
|
+
}
|
|
28
|
+
else if (cliArgs[i] === '--agent-id' && cliArgs[i + 1]) {
|
|
29
|
+
agentId = cliArgs[++i];
|
|
30
|
+
}
|
|
31
|
+
else if (cliArgs[i] === '--mode' && cliArgs[i + 1]) {
|
|
32
|
+
const m = cliArgs[++i];
|
|
33
|
+
if (m === 'enforce' || m === 'observe')
|
|
34
|
+
modeOverride = m;
|
|
35
|
+
}
|
|
36
|
+
else if (cliArgs[i] === '--approval-port' && cliArgs[i + 1]) {
|
|
37
|
+
approvalPort = parseInt(cliArgs[++i], 10);
|
|
38
|
+
if (isNaN(approvalPort)) {
|
|
39
|
+
process.stderr.write('[mcp-guard] Error: --approval-port must be a number\n');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else if (cliArgs[i] === '--help' || cliArgs[i] === '-h') {
|
|
44
|
+
printHelp();
|
|
45
|
+
process.exit(0);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (serverCommand.length === 0) {
|
|
49
|
+
process.stderr.write('[mcp-guard] Error: No server command. Use: mcp-guard [options] -- <server command>\n');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const config = (0, config_js_1.loadConfig)(configPath);
|
|
53
|
+
if (modeOverride)
|
|
54
|
+
config.mode = modeOverride;
|
|
55
|
+
process.stderr.write(`[mcp-guard] Loaded ${config.rules.length} rules (default: ${config.default_action}, mode: ${config.mode})\n`);
|
|
56
|
+
process.stderr.write(`[mcp-guard] Starting server: ${serverCommand.join(' ')}\n`);
|
|
57
|
+
(0, proxy_js_1.startProxy)(config, agentId, serverCommand, approvalPort);
|
|
58
|
+
}
|
|
59
|
+
function printHelp() {
|
|
60
|
+
const help = `
|
|
61
|
+
mcp-guard — MCP tool-call policy proxy
|
|
62
|
+
|
|
63
|
+
Usage:
|
|
64
|
+
mcp-guard [options] -- <server command>
|
|
65
|
+
|
|
66
|
+
Options:
|
|
67
|
+
--config <path> Path to config file (default: ./pp.config.yaml)
|
|
68
|
+
--agent-id <id> Agent identifier for receipts (default: "unknown")
|
|
69
|
+
--mode <mode> enforce or observe (overrides config; default: enforce)
|
|
70
|
+
--approval-port <port> Enable approval UI on this port (e.g. 3100)
|
|
71
|
+
-h, --help Show this help
|
|
72
|
+
|
|
73
|
+
Example:
|
|
74
|
+
mcp-guard --config pp.config.yaml -- node my-mcp-server.js
|
|
75
|
+
|
|
76
|
+
# With approval UI:
|
|
77
|
+
mcp-guard --config pp.config.yaml --approval-port 3100 -- node my-mcp-server.js
|
|
78
|
+
`.trim();
|
|
79
|
+
console.log(help);
|
|
80
|
+
}
|
|
81
|
+
main();
|
|
82
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Action = 'allow' | 'block' | 'require_approval';
|
|
2
|
+
export interface Rule {
|
|
3
|
+
id: string;
|
|
4
|
+
tool: string;
|
|
5
|
+
action: Action;
|
|
6
|
+
}
|
|
7
|
+
export type Mode = 'enforce' | 'observe';
|
|
8
|
+
export interface Config {
|
|
9
|
+
default_action: Action;
|
|
10
|
+
mode: Mode;
|
|
11
|
+
rules: Rule[];
|
|
12
|
+
}
|
|
13
|
+
export declare function loadConfig(configPath: string): Config;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadConfig = loadConfig;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const yaml_1 = require("yaml");
|
|
6
|
+
const VALID_ACTIONS = ['allow', 'block', 'require_approval'];
|
|
7
|
+
function loadConfig(configPath) {
|
|
8
|
+
let raw;
|
|
9
|
+
try {
|
|
10
|
+
raw = (0, node_fs_1.readFileSync)(configPath, 'utf-8');
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
throw new Error(`Failed to read config file: ${configPath} (${err.code ?? err.message})`);
|
|
14
|
+
}
|
|
15
|
+
const parsed = (0, yaml_1.parse)(raw);
|
|
16
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
17
|
+
throw new Error('Config must be a YAML object');
|
|
18
|
+
}
|
|
19
|
+
if (!VALID_ACTIONS.includes(parsed.default_action)) {
|
|
20
|
+
throw new Error(`Invalid default_action: "${parsed.default_action}". Must be one of: ${VALID_ACTIONS.join(', ')}`);
|
|
21
|
+
}
|
|
22
|
+
const VALID_MODES = ['enforce', 'observe'];
|
|
23
|
+
const mode = parsed.mode ?? 'enforce';
|
|
24
|
+
if (!VALID_MODES.includes(mode)) {
|
|
25
|
+
throw new Error(`Invalid mode: "${parsed.mode}". Must be one of: ${VALID_MODES.join(', ')}`);
|
|
26
|
+
}
|
|
27
|
+
if (!Array.isArray(parsed.rules)) {
|
|
28
|
+
throw new Error('Config must include a "rules" array');
|
|
29
|
+
}
|
|
30
|
+
const rules = parsed.rules.map((r, i) => {
|
|
31
|
+
if (!r.id || typeof r.id !== 'string') {
|
|
32
|
+
throw new Error(`Rule ${i} missing valid "id"`);
|
|
33
|
+
}
|
|
34
|
+
if (!r.tool || typeof r.tool !== 'string') {
|
|
35
|
+
throw new Error(`Rule ${i} missing valid "tool"`);
|
|
36
|
+
}
|
|
37
|
+
if (!VALID_ACTIONS.includes(r.action)) {
|
|
38
|
+
throw new Error(`Rule ${i} has invalid action: "${r.action}"`);
|
|
39
|
+
}
|
|
40
|
+
return { id: r.id, tool: r.tool, action: r.action };
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
default_action: parsed.default_action,
|
|
44
|
+
mode,
|
|
45
|
+
rules,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;AAqBA,gCA8CC;AAnED,qCAAuC;AACvC,+BAA6B;AAkB7B,MAAM,aAAa,GAAa,CAAC,OAAO,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;AAEvE,SAAgB,UAAU,CAAC,UAAkB;IAC3C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,IAAA,sBAAY,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,+BAA+B,UAAU,KAAK,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,YAAK,EAAC,GAAG,CAAC,CAAC;IAE1B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,CAAC,cAAc,sBAAsB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrH,CAAC;IAED,MAAM,WAAW,GAAW,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,IAAI,GAAS,MAAM,CAAC,IAAI,IAAI,SAAS,CAAC;IAC5C,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,kBAAkB,MAAM,CAAC,IAAI,sBAAsB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,KAAK,GAAW,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,CAAS,EAAE,EAAE;QAC3D,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QACjE,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAgB,EAAE,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,cAAc,EAAE,MAAM,CAAC,cAAwB;QAC/C,IAAI;QACJ,KAAK;KACN,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Config } from './config.js';
|
|
2
|
+
export interface Decision {
|
|
3
|
+
decision: 'allowed' | 'blocked' | 'held_for_approval';
|
|
4
|
+
rule_id: string | null;
|
|
5
|
+
reason: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function evaluate(toolName: string, _toolArgs: Record<string, unknown> | undefined, config: Config): Decision;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.evaluate = evaluate;
|
|
4
|
+
const ACTION_TO_DECISION = {
|
|
5
|
+
allow: 'allowed',
|
|
6
|
+
block: 'blocked',
|
|
7
|
+
require_approval: 'held_for_approval',
|
|
8
|
+
};
|
|
9
|
+
function evaluate(toolName, _toolArgs, config) {
|
|
10
|
+
for (const rule of config.rules) {
|
|
11
|
+
if (rule.tool === toolName) {
|
|
12
|
+
return {
|
|
13
|
+
decision: ACTION_TO_DECISION[rule.action],
|
|
14
|
+
rule_id: rule.id,
|
|
15
|
+
reason: `Matched rule "${rule.id}"`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
decision: ACTION_TO_DECISION[config.default_action],
|
|
21
|
+
rule_id: null,
|
|
22
|
+
reason: `No matching rule; default action "${config.default_action}"`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/engine.ts"],"names":[],"mappings":";;AAcA,4BAgBC;AAtBD,MAAM,kBAAkB,GAAG;IACzB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;IAChB,gBAAgB,EAAE,mBAAmB;CAC7B,CAAC;AAEX,SAAgB,QAAQ,CAAC,QAAgB,EAAE,SAA8C,EAAE,MAAc;IACvG,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,OAAO;gBACL,QAAQ,EAAE,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC;gBACzC,OAAO,EAAE,IAAI,CAAC,EAAE;gBAChB,MAAM,EAAE,iBAAiB,IAAI,CAAC,EAAE,GAAG;aACpC,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,kBAAkB,CAAC,MAAM,CAAC,cAAc,CAAC;QACnD,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,qCAAqC,MAAM,CAAC,cAAc,GAAG;KACtE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface PendingAction {
|
|
2
|
+
id: string;
|
|
3
|
+
timestamp: string;
|
|
4
|
+
tool_name: string;
|
|
5
|
+
tool_args: any;
|
|
6
|
+
agent_id: string;
|
|
7
|
+
rule_id: string;
|
|
8
|
+
status: 'pending' | 'approved' | 'denied';
|
|
9
|
+
/** The original JSON-RPC line to forward on approval */
|
|
10
|
+
originalLine: string;
|
|
11
|
+
/** The JSON-RPC request id for matching child responses */
|
|
12
|
+
jsonrpcId: string | number | null;
|
|
13
|
+
/** Resolver — call with the response line (or error JSON) to unblock the proxy */
|
|
14
|
+
resolve: (responseLine: string) => void;
|
|
15
|
+
}
|
|
16
|
+
export declare function addPending(toolName: string, toolArgs: any, agentId: string, ruleId: string, originalLine: string, jsonrpcId: string | number | null, resolve: (responseLine: string) => void): PendingAction;
|
|
17
|
+
export declare function getPending(): PendingAction[];
|
|
18
|
+
export declare function getAction(id: string): PendingAction | undefined;
|
|
19
|
+
export declare function resolveAction(id: string, status: 'approved' | 'denied'): PendingAction | undefined;
|
|
20
|
+
export declare function recentResolved(limit?: number): PendingAction[];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addPending = addPending;
|
|
4
|
+
exports.getPending = getPending;
|
|
5
|
+
exports.getAction = getAction;
|
|
6
|
+
exports.resolveAction = resolveAction;
|
|
7
|
+
exports.recentResolved = recentResolved;
|
|
8
|
+
const uuid_1 = require("uuid");
|
|
9
|
+
const queue = new Map();
|
|
10
|
+
function addPending(toolName, toolArgs, agentId, ruleId, originalLine, jsonrpcId, resolve) {
|
|
11
|
+
const action = {
|
|
12
|
+
id: (0, uuid_1.v4)(),
|
|
13
|
+
timestamp: new Date().toISOString(),
|
|
14
|
+
tool_name: toolName,
|
|
15
|
+
tool_args: toolArgs,
|
|
16
|
+
agent_id: agentId,
|
|
17
|
+
rule_id: ruleId,
|
|
18
|
+
status: 'pending',
|
|
19
|
+
originalLine,
|
|
20
|
+
jsonrpcId,
|
|
21
|
+
resolve,
|
|
22
|
+
};
|
|
23
|
+
queue.set(action.id, action);
|
|
24
|
+
return action;
|
|
25
|
+
}
|
|
26
|
+
function getPending() {
|
|
27
|
+
return Array.from(queue.values()).filter(a => a.status === 'pending');
|
|
28
|
+
}
|
|
29
|
+
function getAction(id) {
|
|
30
|
+
return queue.get(id);
|
|
31
|
+
}
|
|
32
|
+
function resolveAction(id, status) {
|
|
33
|
+
const action = queue.get(id);
|
|
34
|
+
if (!action || action.status !== 'pending')
|
|
35
|
+
return undefined;
|
|
36
|
+
action.status = status;
|
|
37
|
+
return action;
|
|
38
|
+
}
|
|
39
|
+
function recentResolved(limit = 50) {
|
|
40
|
+
return Array.from(queue.values())
|
|
41
|
+
.filter(a => a.status !== 'pending')
|
|
42
|
+
.slice(-limit);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=pending.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending.js","sourceRoot":"","sources":["../../src/pending.ts"],"names":[],"mappings":";;AAoBA,gCAuBC;AAED,gCAEC;AAED,8BAEC;AAED,sCAKC;AAED,wCAIC;AAhED,+BAAoC;AAkBpC,MAAM,KAAK,GAA+B,IAAI,GAAG,EAAE,CAAC;AAEpD,SAAgB,UAAU,CACxB,QAAgB,EAChB,QAAa,EACb,OAAe,EACf,MAAc,EACd,YAAoB,EACpB,SAAiC,EACjC,OAAuC;IAEvC,MAAM,MAAM,GAAkB;QAC5B,EAAE,EAAE,IAAA,SAAM,GAAE;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,SAAS,EAAE,QAAQ;QACnB,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,SAAS;QACjB,YAAY;QACZ,SAAS;QACT,OAAO;KACR,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,UAAU;IACxB,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACxE,CAAC;AAED,SAAgB,SAAS,CAAC,EAAU;IAClC,OAAO,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACvB,CAAC;AAED,SAAgB,aAAa,CAAC,EAAU,EAAE,MAA6B;IACrE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC7D,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,cAAc,CAAC,QAAgB,EAAE;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;SAC9B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;SACnC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startProxy = startProxy;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_readline_1 = require("node:readline");
|
|
6
|
+
const engine_js_1 = require("./engine.js");
|
|
7
|
+
const receipt_js_1 = require("./receipt.js");
|
|
8
|
+
const pending_js_1 = require("./pending.js");
|
|
9
|
+
const approval_server_js_1 = require("./approval-server.js");
|
|
10
|
+
function startProxy(config, agentId, serverCommand, approvalPort) {
|
|
11
|
+
if (serverCommand.length === 0) {
|
|
12
|
+
process.stderr.write('[mcp-guard] Error: no server command provided after --\n');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const approvalEnabled = approvalPort !== undefined;
|
|
16
|
+
// Start approval server if enabled
|
|
17
|
+
if (approvalEnabled) {
|
|
18
|
+
(0, approval_server_js_1.startApprovalServer)(approvalPort);
|
|
19
|
+
}
|
|
20
|
+
const child = (0, node_child_process_1.spawn)(serverCommand[0], serverCommand.slice(1), {
|
|
21
|
+
stdio: ['pipe', 'pipe', 'inherit'],
|
|
22
|
+
});
|
|
23
|
+
child.on('error', (err) => {
|
|
24
|
+
process.stderr.write(`[mcp-guard] Failed to start server: ${err.message}\n`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
27
|
+
child.on('exit', (code) => {
|
|
28
|
+
process.stderr.write(`[mcp-guard] Server exited with code ${code}\n`);
|
|
29
|
+
process.exit(code ?? 1);
|
|
30
|
+
});
|
|
31
|
+
// Track pending approval responses waiting for child stdout
|
|
32
|
+
const pendingChildResponses = new Map();
|
|
33
|
+
// Forward child stdout → our stdout (or to pending resolver)
|
|
34
|
+
const childOut = (0, node_readline_1.createInterface)({ input: child.stdout });
|
|
35
|
+
childOut.on('line', (line) => {
|
|
36
|
+
// Check if this is a response to a forwarded approval
|
|
37
|
+
try {
|
|
38
|
+
const parsed = JSON.parse(line);
|
|
39
|
+
const id = parsed.id;
|
|
40
|
+
if (id != null && pendingChildResponses.has(id)) {
|
|
41
|
+
const resolver = pendingChildResponses.get(id);
|
|
42
|
+
pendingChildResponses.delete(id);
|
|
43
|
+
resolver(line);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// not JSON, pass through
|
|
49
|
+
}
|
|
50
|
+
process.stdout.write(line + '\n');
|
|
51
|
+
});
|
|
52
|
+
// Set up approval callback — when UI approves, forward original request to child
|
|
53
|
+
if (approvalEnabled) {
|
|
54
|
+
(0, approval_server_js_1.setOnApprove)((actionId) => {
|
|
55
|
+
const action = (0, pending_js_1.getAction)(actionId);
|
|
56
|
+
if (!action)
|
|
57
|
+
return;
|
|
58
|
+
// Register a listener for the child's response
|
|
59
|
+
if (action.jsonrpcId != null) {
|
|
60
|
+
pendingChildResponses.set(action.jsonrpcId, (responseLine) => {
|
|
61
|
+
action.resolve(responseLine);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// Forward the original request to the child server
|
|
65
|
+
child.stdin.write(action.originalLine + '\n');
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// Read our stdin, inspect, and forward or reject
|
|
69
|
+
const stdinRL = (0, node_readline_1.createInterface)({ input: process.stdin });
|
|
70
|
+
stdinRL.on('line', (line) => {
|
|
71
|
+
if (!line.trim())
|
|
72
|
+
return;
|
|
73
|
+
let msg;
|
|
74
|
+
try {
|
|
75
|
+
msg = JSON.parse(line);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Not valid JSON — forward as-is
|
|
79
|
+
child.stdin.write(line + '\n');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (msg.method === 'tools/call') {
|
|
83
|
+
const toolName = msg.params?.name ?? 'unknown';
|
|
84
|
+
const toolArgs = msg.params?.arguments;
|
|
85
|
+
const decision = (0, engine_js_1.evaluate)(toolName, toolArgs, config);
|
|
86
|
+
const serverName = serverCommand.join(' ');
|
|
87
|
+
const receipt = (0, receipt_js_1.createReceipt)(agentId, toolName, decision, msg.params, serverName, config.mode);
|
|
88
|
+
(0, receipt_js_1.emitReceipt)(receipt);
|
|
89
|
+
if (approvalEnabled)
|
|
90
|
+
(0, approval_server_js_1.pushReceipt)(receipt);
|
|
91
|
+
// In observe mode, always forward (log only, don't block)
|
|
92
|
+
if (config.mode === 'observe') {
|
|
93
|
+
if (decision.decision !== 'allowed') {
|
|
94
|
+
process.stderr.write(`[mcp-guard] OBSERVE: would ${decision.decision === 'blocked' ? 'block' : 'hold'} "${toolName}" but forwarding (observe mode)\n`);
|
|
95
|
+
}
|
|
96
|
+
child.stdin.write(line + '\n');
|
|
97
|
+
}
|
|
98
|
+
else if (decision.decision === 'allowed') {
|
|
99
|
+
child.stdin.write(line + '\n');
|
|
100
|
+
}
|
|
101
|
+
else if (decision.decision === 'blocked') {
|
|
102
|
+
const errResp = {
|
|
103
|
+
jsonrpc: '2.0',
|
|
104
|
+
id: msg.id ?? null,
|
|
105
|
+
error: {
|
|
106
|
+
code: -32001,
|
|
107
|
+
message: `Blocked: ${decision.reason}`,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
process.stdout.write(JSON.stringify(errResp) + '\n');
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// held_for_approval
|
|
114
|
+
if (approvalEnabled) {
|
|
115
|
+
// Hold the response — add to pending queue
|
|
116
|
+
const pending = (0, pending_js_1.addPending)(toolName, toolArgs, agentId, decision.rule_id ?? 'unknown', line, msg.id ?? null, (responseLine) => {
|
|
117
|
+
process.stdout.write(responseLine + '\n');
|
|
118
|
+
});
|
|
119
|
+
process.stderr.write(`[mcp-guard] Held "${toolName}" for approval (${pending.id}) — approve at UI\n`);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// No approval server — return error immediately (original behavior)
|
|
123
|
+
const errResp = {
|
|
124
|
+
jsonrpc: '2.0',
|
|
125
|
+
id: msg.id ?? null,
|
|
126
|
+
error: {
|
|
127
|
+
code: -32002,
|
|
128
|
+
message: `Held for approval: ${decision.reason}`,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
process.stdout.write(JSON.stringify(errResp) + '\n');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Pass through all non-tools/call methods
|
|
137
|
+
child.stdin.write(line + '\n');
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
stdinRL.on('close', () => {
|
|
141
|
+
child.stdin.end();
|
|
142
|
+
});
|
|
143
|
+
// Handle signals gracefully
|
|
144
|
+
process.on('SIGINT', () => child.kill('SIGINT'));
|
|
145
|
+
process.on('SIGTERM', () => child.kill('SIGTERM'));
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Decision } from './engine.js';
|
|
2
|
+
export interface Receipt {
|
|
3
|
+
receipt_id: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
agent_id: string;
|
|
6
|
+
tool_name: string;
|
|
7
|
+
decision: Decision['decision'];
|
|
8
|
+
reason: string;
|
|
9
|
+
rule_id: string | null;
|
|
10
|
+
request_payload_hash: string;
|
|
11
|
+
target_server: string;
|
|
12
|
+
mode: 'enforce' | 'observe';
|
|
13
|
+
}
|
|
14
|
+
export declare function createReceipt(agentId: string, toolName: string, decision: Decision, requestPayload: unknown, targetServer?: string, mode?: 'enforce' | 'observe'): Receipt;
|
|
15
|
+
export declare function emitReceipt(receipt: Receipt, receiptsPath?: string): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createReceipt = createReceipt;
|
|
4
|
+
exports.emitReceipt = emitReceipt;
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
function createReceipt(agentId, toolName, decision, requestPayload, targetServer = 'unknown', mode = 'enforce') {
|
|
9
|
+
const payloadStr = JSON.stringify(requestPayload ?? {});
|
|
10
|
+
const hash = (0, node_crypto_1.createHash)('sha256').update(payloadStr).digest('hex');
|
|
11
|
+
return {
|
|
12
|
+
receipt_id: (0, uuid_1.v4)(),
|
|
13
|
+
timestamp: new Date().toISOString(),
|
|
14
|
+
agent_id: agentId,
|
|
15
|
+
tool_name: toolName,
|
|
16
|
+
decision: decision.decision,
|
|
17
|
+
reason: decision.reason,
|
|
18
|
+
rule_id: decision.rule_id,
|
|
19
|
+
request_payload_hash: hash,
|
|
20
|
+
target_server: targetServer,
|
|
21
|
+
mode,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function emitReceipt(receipt, receiptsPath = 'pp-receipts.jsonl') {
|
|
25
|
+
const json = JSON.stringify(receipt);
|
|
26
|
+
process.stderr.write(`[mcp-guard] receipt: ${json}\n`);
|
|
27
|
+
try {
|
|
28
|
+
(0, node_fs_1.appendFileSync)(receiptsPath, json + '\n');
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Best effort — don't crash the proxy if file write fails
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receipt.js","sourceRoot":"","sources":["../../src/receipt.ts"],"names":[],"mappings":";;AAkBA,sCAuBC;AAED,kCAQC;AAnDD,6CAAyC;AACzC,qCAAyC;AACzC,+BAAoC;AAgBpC,SAAgB,aAAa,CAC3B,OAAe,EACf,QAAgB,EAChB,QAAkB,EAClB,cAAuB,EACvB,eAAuB,SAAS,EAChC,OAA8B,SAAS;IAEvC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEnE,OAAO;QACL,UAAU,EAAE,IAAA,SAAM,GAAE;QACpB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,oBAAoB,EAAE,IAAI;QAC1B,aAAa,EAAE,YAAY;QAC3B,IAAI;KACL,CAAC;AACJ,CAAC;AAED,SAAgB,WAAW,CAAC,OAAgB,EAAE,eAAuB,mBAAmB;IACtF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,IAAI,IAAI,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,IAAA,wBAAc,EAAC,YAAY,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;IAC5D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const node_os_1 = require("node:os");
|
|
11
|
+
const config_js_1 = require("../config.js");
|
|
12
|
+
(0, node_test_1.describe)('Config Parser', () => {
|
|
13
|
+
(0, node_test_1.it)('parses a valid config', () => {
|
|
14
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'mcp-guard-test-'));
|
|
15
|
+
const path = (0, node_path_1.join)(dir, 'config.yaml');
|
|
16
|
+
(0, node_fs_1.writeFileSync)(path, `
|
|
17
|
+
default_action: allow
|
|
18
|
+
rules:
|
|
19
|
+
- id: block-delete
|
|
20
|
+
tool: delete_user_data
|
|
21
|
+
action: block
|
|
22
|
+
- id: hold-deploy
|
|
23
|
+
tool: deploy_production
|
|
24
|
+
action: require_approval
|
|
25
|
+
`);
|
|
26
|
+
const config = (0, config_js_1.loadConfig)(path);
|
|
27
|
+
strict_1.default.equal(config.default_action, 'allow');
|
|
28
|
+
strict_1.default.equal(config.rules.length, 2);
|
|
29
|
+
strict_1.default.equal(config.rules[0].id, 'block-delete');
|
|
30
|
+
strict_1.default.equal(config.rules[0].tool, 'delete_user_data');
|
|
31
|
+
strict_1.default.equal(config.rules[0].action, 'block');
|
|
32
|
+
strict_1.default.equal(config.rules[1].action, 'require_approval');
|
|
33
|
+
strict_1.default.equal(config.mode, 'enforce'); // default
|
|
34
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
35
|
+
});
|
|
36
|
+
(0, node_test_1.it)('rejects invalid config (bad action)', () => {
|
|
37
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'mcp-guard-test-'));
|
|
38
|
+
const path = (0, node_path_1.join)(dir, 'config.yaml');
|
|
39
|
+
(0, node_fs_1.writeFileSync)(path, `
|
|
40
|
+
default_action: allow
|
|
41
|
+
rules:
|
|
42
|
+
- id: bad
|
|
43
|
+
tool: foo
|
|
44
|
+
action: nuke_it
|
|
45
|
+
`);
|
|
46
|
+
strict_1.default.throws(() => (0, config_js_1.loadConfig)(path), /invalid action/i);
|
|
47
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
48
|
+
});
|
|
49
|
+
(0, node_test_1.it)('throws on missing file', () => {
|
|
50
|
+
strict_1.default.throws(() => (0, config_js_1.loadConfig)('/tmp/nonexistent-mcp-guard-config.yaml'), /Failed to read config/);
|
|
51
|
+
});
|
|
52
|
+
(0, node_test_1.it)('rejects config with invalid default_action', () => {
|
|
53
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'mcp-guard-test-'));
|
|
54
|
+
const path = (0, node_path_1.join)(dir, 'config.yaml');
|
|
55
|
+
(0, node_fs_1.writeFileSync)(path, `
|
|
56
|
+
default_action: yolo
|
|
57
|
+
rules: []
|
|
58
|
+
`);
|
|
59
|
+
strict_1.default.throws(() => (0, config_js_1.loadConfig)(path), /Invalid default_action/);
|
|
60
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=config.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../../src/tests/config.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = require("node:test");
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const engine_js_1 = require("../engine.js");
|
|
9
|
+
(0, node_test_1.describe)('Decision Engine', () => {
|
|
10
|
+
const config = {
|
|
11
|
+
default_action: 'allow',
|
|
12
|
+
mode: 'enforce',
|
|
13
|
+
rules: [
|
|
14
|
+
{ id: 'block-delete', tool: 'delete_user_data', action: 'block' },
|
|
15
|
+
{ id: 'hold-deploy', tool: 'deploy_production', action: 'require_approval' },
|
|
16
|
+
{ id: 'allow-email', tool: 'send_email', action: 'allow' },
|
|
17
|
+
],
|
|
18
|
+
};
|
|
19
|
+
(0, node_test_1.it)('matches a block rule', () => {
|
|
20
|
+
const d = (0, engine_js_1.evaluate)('delete_user_data', undefined, config);
|
|
21
|
+
strict_1.default.equal(d.decision, 'blocked');
|
|
22
|
+
strict_1.default.equal(d.rule_id, 'block-delete');
|
|
23
|
+
});
|
|
24
|
+
(0, node_test_1.it)('matches a require_approval rule', () => {
|
|
25
|
+
const d = (0, engine_js_1.evaluate)('deploy_production', undefined, config);
|
|
26
|
+
strict_1.default.equal(d.decision, 'held_for_approval');
|
|
27
|
+
strict_1.default.equal(d.rule_id, 'hold-deploy');
|
|
28
|
+
});
|
|
29
|
+
(0, node_test_1.it)('matches an allow rule', () => {
|
|
30
|
+
const d = (0, engine_js_1.evaluate)('send_email', undefined, config);
|
|
31
|
+
strict_1.default.equal(d.decision, 'allowed');
|
|
32
|
+
strict_1.default.equal(d.rule_id, 'allow-email');
|
|
33
|
+
});
|
|
34
|
+
(0, node_test_1.it)('falls back to default_action: allow', () => {
|
|
35
|
+
const d = (0, engine_js_1.evaluate)('unknown_tool', undefined, config);
|
|
36
|
+
strict_1.default.equal(d.decision, 'allowed');
|
|
37
|
+
strict_1.default.equal(d.rule_id, null);
|
|
38
|
+
});
|
|
39
|
+
(0, node_test_1.it)('falls back to default_action: block', () => {
|
|
40
|
+
const blockConfig = { default_action: 'block', mode: 'enforce', rules: [] };
|
|
41
|
+
const d = (0, engine_js_1.evaluate)('any_tool', undefined, blockConfig);
|
|
42
|
+
strict_1.default.equal(d.decision, 'blocked');
|
|
43
|
+
strict_1.default.equal(d.rule_id, null);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=engine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.test.js","sourceRoot":"","sources":["../../../src/tests/engine.test.ts"],"names":[],"mappings":";;;;;AAAA,yCAAyC;AACzC,gEAAwC;AACxC,4CAAwC;AAGxC,IAAA,oBAAQ,EAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,MAAM,MAAM,GAAW;QACrB,cAAc,EAAE,OAAO;QACvB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE;YACL,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,OAAO,EAAE;YACjE,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,kBAAkB,EAAE;YAC5E,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE;SAC3D;KACF,CAAC;IAEF,IAAA,cAAE,EAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,GAAG,IAAA,oBAAQ,EAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC1D,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpC,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,GAAG,IAAA,oBAAQ,EAAC,mBAAmB,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC3D,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;QAC9C,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,GAAG,IAAA,oBAAQ,EAAC,YAAY,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACpD,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpC,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,GAAG,IAAA,oBAAQ,EAAC,cAAc,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACtD,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpC,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,IAAA,cAAE,EAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,WAAW,GAAW,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QACpF,MAAM,CAAC,GAAG,IAAA,oBAAQ,EAAC,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;QACvD,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpC,gBAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|