@frontmcp/plugin-codecall 1.7.1 → 1.8.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/esm/index.mjs +150 -2
- package/esm/package.json +5 -5
- package/index.js +150 -2
- package/package.json +5 -5
- package/security/codecall-tool-policy.d.ts +89 -0
- package/security/codecall-tool-policy.d.ts.map +1 -0
- package/security/index.d.ts +1 -0
- package/security/index.d.ts.map +1 -1
- package/security/tool-access-control.service.d.ts +12 -2
- package/security/tool-access-control.service.d.ts.map +1 -1
- package/tools/execute.tool.d.ts +9 -0
- package/tools/execute.tool.d.ts.map +1 -1
- package/tools/invoke.tool.d.ts +2 -0
- package/tools/invoke.tool.d.ts.map +1 -1
- package/utils/build-tool-namespaces.d.ts +3 -1
- package/utils/build-tool-namespaces.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -1882,6 +1882,125 @@ SearchKnowledgeTool = __decorateClass([
|
|
|
1882
1882
|
import { toJSONSchema, z as z6, ZodType } from "@frontmcp/lazy-zod";
|
|
1883
1883
|
import { Tool as Tool4, ToolContext as ToolContext4 } from "@frontmcp/sdk";
|
|
1884
1884
|
|
|
1885
|
+
// plugins/plugin-codecall/src/security/codecall-tool-policy.ts
|
|
1886
|
+
var BLOCKED_NAMESPACE_PATTERNS = Object.freeze([/^system:/, /^internal:/, /^__/]);
|
|
1887
|
+
var ALLOWED = { allowed: true };
|
|
1888
|
+
function deny(reason) {
|
|
1889
|
+
return { allowed: false, reason };
|
|
1890
|
+
}
|
|
1891
|
+
function checkCodeCallToolPolicy(tool, config) {
|
|
1892
|
+
const { name } = tool;
|
|
1893
|
+
const names = [name, ...tool.aliases ?? []].filter((candidate) => !!candidate);
|
|
1894
|
+
if (names.some((candidate) => candidate.startsWith("codecall:"))) {
|
|
1895
|
+
return deny("CodeCall meta-tools are not callable from CodeCall");
|
|
1896
|
+
}
|
|
1897
|
+
for (const candidate of names) {
|
|
1898
|
+
if (BLOCKED_NAMESPACE_PATTERNS.some((pattern) => pattern.test(candidate))) {
|
|
1899
|
+
return deny(`Tool "${candidate}" is in a namespace CodeCall never calls`);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
if (tool.hideFromDiscovery === true) {
|
|
1903
|
+
return deny(`Tool "${name}" is hidden from discovery`);
|
|
1904
|
+
}
|
|
1905
|
+
const enabled = tool.codecall?.enabledInCodeCall;
|
|
1906
|
+
switch (config.mode) {
|
|
1907
|
+
case "codecall_only":
|
|
1908
|
+
case "metadata_driven":
|
|
1909
|
+
if (enabled === false) {
|
|
1910
|
+
return deny(`Tool "${name}" sets enabledInCodeCall: false`);
|
|
1911
|
+
}
|
|
1912
|
+
break;
|
|
1913
|
+
case "codecall_opt_in":
|
|
1914
|
+
if (enabled !== true) {
|
|
1915
|
+
return deny(`Tool "${name}" has not opted in to CodeCall`);
|
|
1916
|
+
}
|
|
1917
|
+
break;
|
|
1918
|
+
default:
|
|
1919
|
+
return deny(`Unknown CodeCall mode: ${String(config.mode)}`);
|
|
1920
|
+
}
|
|
1921
|
+
if (config.includeTools) {
|
|
1922
|
+
const included = config.includeTools({
|
|
1923
|
+
name,
|
|
1924
|
+
appId: tool.appId,
|
|
1925
|
+
source: tool.codecall?.source,
|
|
1926
|
+
description: tool.description,
|
|
1927
|
+
tags: tool.codecall?.tags ?? tool.tags
|
|
1928
|
+
});
|
|
1929
|
+
if (!included) {
|
|
1930
|
+
return deny(`Tool "${name}" is excluded by the includeTools filter`);
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
return ALLOWED;
|
|
1934
|
+
}
|
|
1935
|
+
function denyUnknownTool(name) {
|
|
1936
|
+
return deny(`Tool "${name}" is not available through CodeCall`);
|
|
1937
|
+
}
|
|
1938
|
+
function resolveCodeCallTool(scope, name) {
|
|
1939
|
+
const typedScope = scope;
|
|
1940
|
+
const alias = /[-_]/.test(name) ? name.includes("_") ? name.replace(/_/g, "-") : name.replace(/-/g, "_") : void 0;
|
|
1941
|
+
const candidates = alias ? [name, alias] : [name];
|
|
1942
|
+
const matches = (entry) => candidates.includes(entry.fullName) || candidates.includes(entry.name);
|
|
1943
|
+
const local = typedScope.tools?.getTools(true)?.find(matches);
|
|
1944
|
+
if (local) return local;
|
|
1945
|
+
const registries = typedScope.providers?.getRegistries?.("AppRegistry") ?? [];
|
|
1946
|
+
for (const registry of registries) {
|
|
1947
|
+
for (const app of registry.getApps()) {
|
|
1948
|
+
if (!app.isRemote) continue;
|
|
1949
|
+
const remote = app.tools.getTools(true).find(matches);
|
|
1950
|
+
if (remote) return remote;
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
return void 0;
|
|
1954
|
+
}
|
|
1955
|
+
function checkDirectCallPolicy(tool, directCalls) {
|
|
1956
|
+
if (!directCalls) return ALLOWED;
|
|
1957
|
+
if (directCalls.enabled === false) {
|
|
1958
|
+
return deny("Direct tool invocation is disabled");
|
|
1959
|
+
}
|
|
1960
|
+
if (directCalls.allowedTools && !directCalls.allowedTools.includes(tool.name)) {
|
|
1961
|
+
return deny(`Tool "${tool.name}" is not in the direct-call allowlist`);
|
|
1962
|
+
}
|
|
1963
|
+
if (directCalls.filter) {
|
|
1964
|
+
const permitted = directCalls.filter({
|
|
1965
|
+
name: tool.name,
|
|
1966
|
+
appId: tool.appId,
|
|
1967
|
+
source: tool.codecall?.source,
|
|
1968
|
+
tags: tool.codecall?.tags ?? tool.tags
|
|
1969
|
+
});
|
|
1970
|
+
if (!permitted) {
|
|
1971
|
+
return deny(`Tool "${tool.name}" is excluded by the directCalls filter`);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
return ALLOWED;
|
|
1975
|
+
}
|
|
1976
|
+
function checkCodeCallToolAccess(scope, config, name, options = {}) {
|
|
1977
|
+
const entry = resolveCodeCallTool(scope, name);
|
|
1978
|
+
if (!entry) return denyUnknownTool(name);
|
|
1979
|
+
const metadata = entry.metadata;
|
|
1980
|
+
const owner = entry.owner;
|
|
1981
|
+
const policyTool = {
|
|
1982
|
+
// The qualified name is the subject: `call-tool.flow.ts` dispatches `fullName`, so the
|
|
1983
|
+
// policy has to judge the same string the flow will run.
|
|
1984
|
+
name: entry.fullName || entry.name,
|
|
1985
|
+
aliases: [entry.name, name],
|
|
1986
|
+
appId: owner?.kind === "app" ? owner.id : void 0,
|
|
1987
|
+
description: metadata?.description,
|
|
1988
|
+
tags: metadata?.tags,
|
|
1989
|
+
hideFromDiscovery: metadata?.hideFromDiscovery,
|
|
1990
|
+
codecall: metadata?.codecall
|
|
1991
|
+
};
|
|
1992
|
+
const baseDecision = checkCodeCallToolPolicy(policyTool, {
|
|
1993
|
+
// An absent mode means an unparsed/partial config, not a hostile one: fall back to the
|
|
1994
|
+
// schema's own documented default rather than denying every call. An unrecognised mode
|
|
1995
|
+
// still fails closed inside the policy's switch.
|
|
1996
|
+
mode: config.get("mode") ?? "codecall_only",
|
|
1997
|
+
includeTools: config.get("includeTools")
|
|
1998
|
+
});
|
|
1999
|
+
if (!baseDecision.allowed) return baseDecision;
|
|
2000
|
+
if (!options.directCall) return ALLOWED;
|
|
2001
|
+
return checkDirectCallPolicy(policyTool, config.get("directCalls"));
|
|
2002
|
+
}
|
|
2003
|
+
|
|
1885
2004
|
// plugins/plugin-codecall/src/errors/tool-call.errors.ts
|
|
1886
2005
|
var TOOL_CALL_ERROR_CODES = {
|
|
1887
2006
|
NOT_FOUND: "NOT_FOUND",
|
|
@@ -1962,6 +2081,7 @@ function assertNotSelfReference(toolName) {
|
|
|
1962
2081
|
|
|
1963
2082
|
// plugins/plugin-codecall/src/utils/build-tool-namespaces.ts
|
|
1964
2083
|
var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
2084
|
+
var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1965
2085
|
var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
1966
2086
|
"console",
|
|
1967
2087
|
"Math",
|
|
@@ -1994,7 +2114,7 @@ var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
|
1994
2114
|
"mcpNotify"
|
|
1995
2115
|
]);
|
|
1996
2116
|
function buildToolNamespaces(tools, callTool) {
|
|
1997
|
-
const namespaces =
|
|
2117
|
+
const namespaces = /* @__PURE__ */ Object.create(null);
|
|
1998
2118
|
const skipped = [];
|
|
1999
2119
|
for (const tool of tools) {
|
|
2000
2120
|
const name = tool?.name;
|
|
@@ -2010,11 +2130,15 @@ function buildToolNamespaces(tools, callTool) {
|
|
|
2010
2130
|
skipped.push({ name, reason: "invalid-identifier" });
|
|
2011
2131
|
continue;
|
|
2012
2132
|
}
|
|
2133
|
+
if (PROTOTYPE_KEYS.has(ns)) {
|
|
2134
|
+
skipped.push({ name, reason: "prototype-key" });
|
|
2135
|
+
continue;
|
|
2136
|
+
}
|
|
2013
2137
|
if (RESERVED_NAMESPACES.has(ns)) {
|
|
2014
2138
|
skipped.push({ name, reason: "reserved-namespace" });
|
|
2015
2139
|
continue;
|
|
2016
2140
|
}
|
|
2017
|
-
const bucket = namespaces[ns] ?? (namespaces[ns] =
|
|
2141
|
+
const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
|
|
2018
2142
|
if (Object.prototype.hasOwnProperty.call(bucket, method)) {
|
|
2019
2143
|
skipped.push({ name, reason: "duplicate-method" });
|
|
2020
2144
|
continue;
|
|
@@ -2662,6 +2786,17 @@ function getErrorCode(error) {
|
|
|
2662
2786
|
return TOOL_CALL_ERROR_CODES.EXECUTION;
|
|
2663
2787
|
}
|
|
2664
2788
|
var ExecuteTool = class extends ToolContext5 {
|
|
2789
|
+
/**
|
|
2790
|
+
* Resolve the server-side CodeCall policy for a tool name (GHSA-6w3j-82v5-6qrr).
|
|
2791
|
+
*
|
|
2792
|
+
* Shares its decision with discovery and with `codecall:invoke`, so the three cannot
|
|
2793
|
+
* diverge. A name matching no registered tool is denied rather than passed through —
|
|
2794
|
+
* otherwise it would skip every metadata-driven check and reach `tools:call-tool`
|
|
2795
|
+
* unexamined.
|
|
2796
|
+
*/
|
|
2797
|
+
checkToolPolicy(name) {
|
|
2798
|
+
return checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), name);
|
|
2799
|
+
}
|
|
2665
2800
|
async execute(input) {
|
|
2666
2801
|
const { script, allowedTools } = input;
|
|
2667
2802
|
const allowedToolSet = allowedTools ? new Set(allowedTools) : null;
|
|
@@ -2669,6 +2804,14 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
2669
2804
|
callTool: async (name, toolInput, options) => {
|
|
2670
2805
|
const throwOnError = options?.throwOnError !== false;
|
|
2671
2806
|
assertNotSelfReference(name);
|
|
2807
|
+
const decision = this.checkToolPolicy(name);
|
|
2808
|
+
if (!decision.allowed) {
|
|
2809
|
+
const error = createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED, name, decision.reason);
|
|
2810
|
+
if (throwOnError) {
|
|
2811
|
+
throw error;
|
|
2812
|
+
}
|
|
2813
|
+
return { success: false, error };
|
|
2814
|
+
}
|
|
2672
2815
|
if (allowedToolSet && !allowedToolSet.has(name)) {
|
|
2673
2816
|
const error = createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED, name);
|
|
2674
2817
|
if (throwOnError) {
|
|
@@ -2713,6 +2856,7 @@ var ExecuteTool = class extends ToolContext5 {
|
|
|
2713
2856
|
getTool: (name) => {
|
|
2714
2857
|
try {
|
|
2715
2858
|
if (isBlockedSelfReference(name)) return void 0;
|
|
2859
|
+
if (!this.checkToolPolicy(name).allowed) return void 0;
|
|
2716
2860
|
if (allowedToolSet && !allowedToolSet.has(name)) return void 0;
|
|
2717
2861
|
const tools = this.scope.tools.getTools(true);
|
|
2718
2862
|
const tool = tools.find((t) => t.name === name || t.fullName === name);
|
|
@@ -2887,6 +3031,10 @@ var InvokeTool = class extends ToolContext6 {
|
|
|
2887
3031
|
`Tool "${toolName}" cannot be invoked directly. CodeCall tools are internal and not accessible via codecall:invoke.`
|
|
2888
3032
|
);
|
|
2889
3033
|
}
|
|
3034
|
+
const decision = checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), toolName, { directCall: true });
|
|
3035
|
+
if (!decision.allowed) {
|
|
3036
|
+
return buildErrorResult(`Tool "${toolName}" is not available. Use codecall:search to discover available tools.`);
|
|
3037
|
+
}
|
|
2890
3038
|
const request = {
|
|
2891
3039
|
method: "tools/call",
|
|
2892
3040
|
params: {
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-codecall",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "CodeCall plugin for FrontMCP - AgentScript-based meta-tools for orchestrating MCP tools",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@enclave-vm/core": "^2.15.2",
|
|
52
|
-
"@frontmcp/protocol": "1.
|
|
53
|
-
"@frontmcp/sdk": "1.
|
|
52
|
+
"@frontmcp/protocol": "1.8.0",
|
|
53
|
+
"@frontmcp/sdk": "1.8.0",
|
|
54
54
|
"vectoriadb": "^2.3.2"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.
|
|
58
|
-
"@frontmcp/plugin-cache": "1.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.8.0",
|
|
58
|
+
"@frontmcp/plugin-cache": "1.8.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"reflect-metadata": "^0.2.2"
|
package/index.js
CHANGED
|
@@ -1919,6 +1919,125 @@ SearchKnowledgeTool = __decorateClass([
|
|
|
1919
1919
|
var import_lazy_zod6 = require("@frontmcp/lazy-zod");
|
|
1920
1920
|
var import_sdk6 = require("@frontmcp/sdk");
|
|
1921
1921
|
|
|
1922
|
+
// plugins/plugin-codecall/src/security/codecall-tool-policy.ts
|
|
1923
|
+
var BLOCKED_NAMESPACE_PATTERNS = Object.freeze([/^system:/, /^internal:/, /^__/]);
|
|
1924
|
+
var ALLOWED = { allowed: true };
|
|
1925
|
+
function deny(reason) {
|
|
1926
|
+
return { allowed: false, reason };
|
|
1927
|
+
}
|
|
1928
|
+
function checkCodeCallToolPolicy(tool, config) {
|
|
1929
|
+
const { name } = tool;
|
|
1930
|
+
const names = [name, ...tool.aliases ?? []].filter((candidate) => !!candidate);
|
|
1931
|
+
if (names.some((candidate) => candidate.startsWith("codecall:"))) {
|
|
1932
|
+
return deny("CodeCall meta-tools are not callable from CodeCall");
|
|
1933
|
+
}
|
|
1934
|
+
for (const candidate of names) {
|
|
1935
|
+
if (BLOCKED_NAMESPACE_PATTERNS.some((pattern) => pattern.test(candidate))) {
|
|
1936
|
+
return deny(`Tool "${candidate}" is in a namespace CodeCall never calls`);
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
if (tool.hideFromDiscovery === true) {
|
|
1940
|
+
return deny(`Tool "${name}" is hidden from discovery`);
|
|
1941
|
+
}
|
|
1942
|
+
const enabled = tool.codecall?.enabledInCodeCall;
|
|
1943
|
+
switch (config.mode) {
|
|
1944
|
+
case "codecall_only":
|
|
1945
|
+
case "metadata_driven":
|
|
1946
|
+
if (enabled === false) {
|
|
1947
|
+
return deny(`Tool "${name}" sets enabledInCodeCall: false`);
|
|
1948
|
+
}
|
|
1949
|
+
break;
|
|
1950
|
+
case "codecall_opt_in":
|
|
1951
|
+
if (enabled !== true) {
|
|
1952
|
+
return deny(`Tool "${name}" has not opted in to CodeCall`);
|
|
1953
|
+
}
|
|
1954
|
+
break;
|
|
1955
|
+
default:
|
|
1956
|
+
return deny(`Unknown CodeCall mode: ${String(config.mode)}`);
|
|
1957
|
+
}
|
|
1958
|
+
if (config.includeTools) {
|
|
1959
|
+
const included = config.includeTools({
|
|
1960
|
+
name,
|
|
1961
|
+
appId: tool.appId,
|
|
1962
|
+
source: tool.codecall?.source,
|
|
1963
|
+
description: tool.description,
|
|
1964
|
+
tags: tool.codecall?.tags ?? tool.tags
|
|
1965
|
+
});
|
|
1966
|
+
if (!included) {
|
|
1967
|
+
return deny(`Tool "${name}" is excluded by the includeTools filter`);
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
return ALLOWED;
|
|
1971
|
+
}
|
|
1972
|
+
function denyUnknownTool(name) {
|
|
1973
|
+
return deny(`Tool "${name}" is not available through CodeCall`);
|
|
1974
|
+
}
|
|
1975
|
+
function resolveCodeCallTool(scope, name) {
|
|
1976
|
+
const typedScope = scope;
|
|
1977
|
+
const alias = /[-_]/.test(name) ? name.includes("_") ? name.replace(/_/g, "-") : name.replace(/-/g, "_") : void 0;
|
|
1978
|
+
const candidates = alias ? [name, alias] : [name];
|
|
1979
|
+
const matches = (entry) => candidates.includes(entry.fullName) || candidates.includes(entry.name);
|
|
1980
|
+
const local = typedScope.tools?.getTools(true)?.find(matches);
|
|
1981
|
+
if (local) return local;
|
|
1982
|
+
const registries = typedScope.providers?.getRegistries?.("AppRegistry") ?? [];
|
|
1983
|
+
for (const registry of registries) {
|
|
1984
|
+
for (const app of registry.getApps()) {
|
|
1985
|
+
if (!app.isRemote) continue;
|
|
1986
|
+
const remote = app.tools.getTools(true).find(matches);
|
|
1987
|
+
if (remote) return remote;
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
return void 0;
|
|
1991
|
+
}
|
|
1992
|
+
function checkDirectCallPolicy(tool, directCalls) {
|
|
1993
|
+
if (!directCalls) return ALLOWED;
|
|
1994
|
+
if (directCalls.enabled === false) {
|
|
1995
|
+
return deny("Direct tool invocation is disabled");
|
|
1996
|
+
}
|
|
1997
|
+
if (directCalls.allowedTools && !directCalls.allowedTools.includes(tool.name)) {
|
|
1998
|
+
return deny(`Tool "${tool.name}" is not in the direct-call allowlist`);
|
|
1999
|
+
}
|
|
2000
|
+
if (directCalls.filter) {
|
|
2001
|
+
const permitted = directCalls.filter({
|
|
2002
|
+
name: tool.name,
|
|
2003
|
+
appId: tool.appId,
|
|
2004
|
+
source: tool.codecall?.source,
|
|
2005
|
+
tags: tool.codecall?.tags ?? tool.tags
|
|
2006
|
+
});
|
|
2007
|
+
if (!permitted) {
|
|
2008
|
+
return deny(`Tool "${tool.name}" is excluded by the directCalls filter`);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
return ALLOWED;
|
|
2012
|
+
}
|
|
2013
|
+
function checkCodeCallToolAccess(scope, config, name, options = {}) {
|
|
2014
|
+
const entry = resolveCodeCallTool(scope, name);
|
|
2015
|
+
if (!entry) return denyUnknownTool(name);
|
|
2016
|
+
const metadata = entry.metadata;
|
|
2017
|
+
const owner = entry.owner;
|
|
2018
|
+
const policyTool = {
|
|
2019
|
+
// The qualified name is the subject: `call-tool.flow.ts` dispatches `fullName`, so the
|
|
2020
|
+
// policy has to judge the same string the flow will run.
|
|
2021
|
+
name: entry.fullName || entry.name,
|
|
2022
|
+
aliases: [entry.name, name],
|
|
2023
|
+
appId: owner?.kind === "app" ? owner.id : void 0,
|
|
2024
|
+
description: metadata?.description,
|
|
2025
|
+
tags: metadata?.tags,
|
|
2026
|
+
hideFromDiscovery: metadata?.hideFromDiscovery,
|
|
2027
|
+
codecall: metadata?.codecall
|
|
2028
|
+
};
|
|
2029
|
+
const baseDecision = checkCodeCallToolPolicy(policyTool, {
|
|
2030
|
+
// An absent mode means an unparsed/partial config, not a hostile one: fall back to the
|
|
2031
|
+
// schema's own documented default rather than denying every call. An unrecognised mode
|
|
2032
|
+
// still fails closed inside the policy's switch.
|
|
2033
|
+
mode: config.get("mode") ?? "codecall_only",
|
|
2034
|
+
includeTools: config.get("includeTools")
|
|
2035
|
+
});
|
|
2036
|
+
if (!baseDecision.allowed) return baseDecision;
|
|
2037
|
+
if (!options.directCall) return ALLOWED;
|
|
2038
|
+
return checkDirectCallPolicy(policyTool, config.get("directCalls"));
|
|
2039
|
+
}
|
|
2040
|
+
|
|
1922
2041
|
// plugins/plugin-codecall/src/errors/tool-call.errors.ts
|
|
1923
2042
|
var TOOL_CALL_ERROR_CODES = {
|
|
1924
2043
|
NOT_FOUND: "NOT_FOUND",
|
|
@@ -1999,6 +2118,7 @@ function assertNotSelfReference(toolName) {
|
|
|
1999
2118
|
|
|
2000
2119
|
// plugins/plugin-codecall/src/utils/build-tool-namespaces.ts
|
|
2001
2120
|
var IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
2121
|
+
var PROTOTYPE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2002
2122
|
var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
2003
2123
|
"console",
|
|
2004
2124
|
"Math",
|
|
@@ -2031,7 +2151,7 @@ var RESERVED_NAMESPACES = /* @__PURE__ */ new Set([
|
|
|
2031
2151
|
"mcpNotify"
|
|
2032
2152
|
]);
|
|
2033
2153
|
function buildToolNamespaces(tools, callTool) {
|
|
2034
|
-
const namespaces =
|
|
2154
|
+
const namespaces = /* @__PURE__ */ Object.create(null);
|
|
2035
2155
|
const skipped = [];
|
|
2036
2156
|
for (const tool of tools) {
|
|
2037
2157
|
const name = tool?.name;
|
|
@@ -2047,11 +2167,15 @@ function buildToolNamespaces(tools, callTool) {
|
|
|
2047
2167
|
skipped.push({ name, reason: "invalid-identifier" });
|
|
2048
2168
|
continue;
|
|
2049
2169
|
}
|
|
2170
|
+
if (PROTOTYPE_KEYS.has(ns)) {
|
|
2171
|
+
skipped.push({ name, reason: "prototype-key" });
|
|
2172
|
+
continue;
|
|
2173
|
+
}
|
|
2050
2174
|
if (RESERVED_NAMESPACES.has(ns)) {
|
|
2051
2175
|
skipped.push({ name, reason: "reserved-namespace" });
|
|
2052
2176
|
continue;
|
|
2053
2177
|
}
|
|
2054
|
-
const bucket = namespaces[ns] ?? (namespaces[ns] =
|
|
2178
|
+
const bucket = namespaces[ns] ?? (namespaces[ns] = /* @__PURE__ */ Object.create(null));
|
|
2055
2179
|
if (Object.prototype.hasOwnProperty.call(bucket, method)) {
|
|
2056
2180
|
skipped.push({ name, reason: "duplicate-method" });
|
|
2057
2181
|
continue;
|
|
@@ -2699,6 +2823,17 @@ function getErrorCode(error) {
|
|
|
2699
2823
|
return TOOL_CALL_ERROR_CODES.EXECUTION;
|
|
2700
2824
|
}
|
|
2701
2825
|
var ExecuteTool = class extends import_sdk7.ToolContext {
|
|
2826
|
+
/**
|
|
2827
|
+
* Resolve the server-side CodeCall policy for a tool name (GHSA-6w3j-82v5-6qrr).
|
|
2828
|
+
*
|
|
2829
|
+
* Shares its decision with discovery and with `codecall:invoke`, so the three cannot
|
|
2830
|
+
* diverge. A name matching no registered tool is denied rather than passed through —
|
|
2831
|
+
* otherwise it would skip every metadata-driven check and reach `tools:call-tool`
|
|
2832
|
+
* unexamined.
|
|
2833
|
+
*/
|
|
2834
|
+
checkToolPolicy(name) {
|
|
2835
|
+
return checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), name);
|
|
2836
|
+
}
|
|
2702
2837
|
async execute(input) {
|
|
2703
2838
|
const { script, allowedTools } = input;
|
|
2704
2839
|
const allowedToolSet = allowedTools ? new Set(allowedTools) : null;
|
|
@@ -2706,6 +2841,14 @@ var ExecuteTool = class extends import_sdk7.ToolContext {
|
|
|
2706
2841
|
callTool: async (name, toolInput, options) => {
|
|
2707
2842
|
const throwOnError = options?.throwOnError !== false;
|
|
2708
2843
|
assertNotSelfReference(name);
|
|
2844
|
+
const decision = this.checkToolPolicy(name);
|
|
2845
|
+
if (!decision.allowed) {
|
|
2846
|
+
const error = createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED, name, decision.reason);
|
|
2847
|
+
if (throwOnError) {
|
|
2848
|
+
throw error;
|
|
2849
|
+
}
|
|
2850
|
+
return { success: false, error };
|
|
2851
|
+
}
|
|
2709
2852
|
if (allowedToolSet && !allowedToolSet.has(name)) {
|
|
2710
2853
|
const error = createToolCallError(TOOL_CALL_ERROR_CODES.ACCESS_DENIED, name);
|
|
2711
2854
|
if (throwOnError) {
|
|
@@ -2750,6 +2893,7 @@ var ExecuteTool = class extends import_sdk7.ToolContext {
|
|
|
2750
2893
|
getTool: (name) => {
|
|
2751
2894
|
try {
|
|
2752
2895
|
if (isBlockedSelfReference(name)) return void 0;
|
|
2896
|
+
if (!this.checkToolPolicy(name).allowed) return void 0;
|
|
2753
2897
|
if (allowedToolSet && !allowedToolSet.has(name)) return void 0;
|
|
2754
2898
|
const tools = this.scope.tools.getTools(true);
|
|
2755
2899
|
const tool = tools.find((t) => t.name === name || t.fullName === name);
|
|
@@ -2924,6 +3068,10 @@ var InvokeTool = class extends import_sdk8.ToolContext {
|
|
|
2924
3068
|
`Tool "${toolName}" cannot be invoked directly. CodeCall tools are internal and not accessible via codecall:invoke.`
|
|
2925
3069
|
);
|
|
2926
3070
|
}
|
|
3071
|
+
const decision = checkCodeCallToolAccess(this.scope, this.get(CodeCallConfig), toolName, { directCall: true });
|
|
3072
|
+
if (!decision.allowed) {
|
|
3073
|
+
return buildErrorResult(`Tool "${toolName}" is not available. Use codecall:search to discover available tools.`);
|
|
3074
|
+
}
|
|
2927
3075
|
const request = {
|
|
2928
3076
|
method: "tools/call",
|
|
2929
3077
|
params: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-codecall",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "CodeCall plugin for FrontMCP - AgentScript-based meta-tools for orchestrating MCP tools",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@enclave-vm/core": "^2.15.2",
|
|
52
|
-
"@frontmcp/protocol": "1.
|
|
53
|
-
"@frontmcp/sdk": "1.
|
|
52
|
+
"@frontmcp/protocol": "1.8.0",
|
|
53
|
+
"@frontmcp/sdk": "1.8.0",
|
|
54
54
|
"vectoriadb": "^2.3.2"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.
|
|
58
|
-
"@frontmcp/plugin-cache": "1.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.8.0",
|
|
58
|
+
"@frontmcp/plugin-cache": "1.8.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"reflect-metadata": "^0.2.2"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { CodeCallMode, CodeCallToolMetadata, DirectCallsFilterFn, IncludeToolsFilterFn } from '../codecall.types';
|
|
2
|
+
/** The subset of a ToolEntry this decision needs, so callers need not pass the whole entry. */
|
|
3
|
+
export interface CodeCallPolicyTool {
|
|
4
|
+
/** Canonical, most-qualified name — `fullName` where the entry has one. */
|
|
5
|
+
name: string;
|
|
6
|
+
/**
|
|
7
|
+
* Every other name this tool answers to, including the name the caller asked for.
|
|
8
|
+
*
|
|
9
|
+
* The namespace rules run over all of them. A tool can carry a bare `name` and a qualified
|
|
10
|
+
* `fullName` (`wipeConfig` / `system:wipeConfig`), and the flow dispatches the qualified
|
|
11
|
+
* one — so judging a single spelling lets the other one through.
|
|
12
|
+
*/
|
|
13
|
+
aliases?: string[];
|
|
14
|
+
appId?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
tags?: string[];
|
|
17
|
+
hideFromDiscovery?: boolean;
|
|
18
|
+
codecall?: CodeCallToolMetadata;
|
|
19
|
+
}
|
|
20
|
+
export interface CodeCallPolicyConfig {
|
|
21
|
+
mode: CodeCallMode;
|
|
22
|
+
includeTools?: IncludeToolsFilterFn;
|
|
23
|
+
}
|
|
24
|
+
/** The `directCalls` options, which narrow `codecall:invoke` beyond the base policy. */
|
|
25
|
+
export interface CodeCallDirectCallsConfig {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
allowedTools?: string[];
|
|
28
|
+
filter?: DirectCallsFilterFn;
|
|
29
|
+
}
|
|
30
|
+
export type CodeCallPolicyDecision = {
|
|
31
|
+
allowed: true;
|
|
32
|
+
} | {
|
|
33
|
+
allowed: false;
|
|
34
|
+
reason: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Decide whether CodeCall may reach `tool`.
|
|
38
|
+
*
|
|
39
|
+
* Discovery and execution both call this. A tool the policy denies must be absent from
|
|
40
|
+
* search results AND rejected at `callTool` — hiding it from search is not authorization.
|
|
41
|
+
*/
|
|
42
|
+
export declare function checkCodeCallToolPolicy(tool: CodeCallPolicyTool, config: CodeCallPolicyConfig): CodeCallPolicyDecision;
|
|
43
|
+
/**
|
|
44
|
+
* A tool the policy cannot evaluate is denied.
|
|
45
|
+
*
|
|
46
|
+
* `callTool` receives a bare string, so a name matching no resolvable tool would otherwise
|
|
47
|
+
* skip every metadata-driven check above and fall straight through to `tools:call-tool`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function denyUnknownTool(name: string): CodeCallPolicyDecision;
|
|
50
|
+
interface ResolvableEntry {
|
|
51
|
+
name: string;
|
|
52
|
+
fullName: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolve a tool name exactly as `call-tool.flow.ts` `findTool` does.
|
|
56
|
+
*
|
|
57
|
+
* MUST mirror that stage. The policy has to evaluate the same entry the flow will execute:
|
|
58
|
+
* resolve more narrowly and legitimate remote-app tools get denied; resolve more loosely and
|
|
59
|
+
* a tool reachable only through the flow's fallback escapes the policy entirely. The flow
|
|
60
|
+
* applies three steps, and so does this —
|
|
61
|
+
* 1. the scope registry,
|
|
62
|
+
* 2. a hyphen <-> underscore alias (issue #408),
|
|
63
|
+
* 3. remote app registries, for tools whose subscription has not yet propagated.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveCodeCallTool<T extends ResolvableEntry>(scope: unknown, name: string): T | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Apply the `directCalls` options to a `codecall:invoke` request.
|
|
68
|
+
*
|
|
69
|
+
* These options were declared in the plugin schema and read by nothing, so `codecall:invoke`
|
|
70
|
+
* proxied the entire registry regardless of how an operator configured it. They narrow the
|
|
71
|
+
* base policy; they never widen it.
|
|
72
|
+
*/
|
|
73
|
+
export declare function checkDirectCallPolicy(tool: CodeCallPolicyTool, directCalls: CodeCallDirectCallsConfig | undefined): CodeCallPolicyDecision;
|
|
74
|
+
interface PolicyConfigReader {
|
|
75
|
+
get(key: string): unknown;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a tool name and decide whether CodeCall may reach it.
|
|
79
|
+
*
|
|
80
|
+
* The one entry point for both meta-tools: `codecall:execute` calls it for every `callTool`
|
|
81
|
+
* and `getTool`, `codecall:invoke` for its single target with `directCall: true`. Sharing it
|
|
82
|
+
* is the point — the advisory existed because execution and discovery each had their own
|
|
83
|
+
* answer.
|
|
84
|
+
*/
|
|
85
|
+
export declare function checkCodeCallToolAccess(scope: unknown, config: PolicyConfigReader, name: string, options?: {
|
|
86
|
+
directCall?: boolean;
|
|
87
|
+
}): CodeCallPolicyDecision;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=codecall-tool-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codecall-tool-policy.d.ts","sourceRoot":"","sources":["../../src/security/codecall-tool-policy.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAKvH,+FAA+F;AAC/F,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AAED,wFAAwF;AACxF,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAED,MAAM,MAAM,sBAAsB,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAQ5F;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,oBAAoB,GAC3B,sBAAsB,CAwDxB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,CAEpE;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAWD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAwB1G;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,kBAAkB,EACxB,WAAW,EAAE,yBAAyB,GAAG,SAAS,GACjD,sBAAsB,CAyBxB;AAED,UAAU,kBAAkB;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GACrC,sBAAsB,CAmCxB"}
|
package/security/index.d.ts
CHANGED
package/security/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAEA,cAAc,wBAAwB,CAAC;AACvC,cAAc,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAEA,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,+BAA+B,CAAC"}
|
|
@@ -58,8 +58,18 @@ export interface ToolAccessDecision {
|
|
|
58
58
|
/**
|
|
59
59
|
* Tool Access Control Service
|
|
60
60
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
61
|
+
* NOT ON THE ENFORCEMENT PATH. Nothing constructs this service: the plugin declares
|
|
62
|
+
* `providers: []`, no `ToolAccessPolicy` can be supplied through the plugin options, and
|
|
63
|
+
* neither `codecall:execute` nor `codecall:invoke` consults it. Its unit tests pass by
|
|
64
|
+
* constructing it directly, which is exactly how GHSA-6w3j-82v5-6qrr stayed invisible — a
|
|
65
|
+
* green suite for a control that never ran.
|
|
66
|
+
*
|
|
67
|
+
* The policy CodeCall actually enforces lives in `codecall-tool-policy.ts`
|
|
68
|
+
* (`checkCodeCallToolAccess`), called by both meta-tools. This class is kept only so the
|
|
69
|
+
* exported types do not disappear from the package's public surface in a security patch;
|
|
70
|
+
* wiring it in, or removing it, is a follow-up with its own BC note.
|
|
71
|
+
*
|
|
72
|
+
* The richer model it offers, unused today:
|
|
63
73
|
*
|
|
64
74
|
* 1. Self-reference blocking (handled separately in self-reference-guard.ts)
|
|
65
75
|
* 2. Default blacklist (always enforced)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-access-control.service.d.ts","sourceRoot":"","sources":["../../src/security/tool-access-control.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tool-access-control.service.d.ts","sourceRoot":"","sources":["../../src/security/tool-access-control.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,IAAI,EAAE,cAAc,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE;QACT,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IAEF;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACzE;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAIa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAW;gBAE5B,MAAM,CAAC,EAAE,gBAAgB;IAWrC;;;;;;OAMG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;YAsCxF,kBAAkB;YAqBlB,kBAAkB;YAelB,gBAAgB;IAS9B;;OAEG;IACH,OAAO,CAAC,OAAO;IAmBf;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IAenB;;OAEG;IACH,SAAS,IAAI,QAAQ,CAAC,gBAAgB,CAAC;CAGxC;AAED,eAAe,wBAAwB,CAAC"}
|
package/tools/execute.tool.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { ToolContext } from '@frontmcp/sdk';
|
|
2
2
|
import { type CodeCallExecuteResult, type ExecuteToolInput } from './execute.schema';
|
|
3
3
|
export default class ExecuteTool extends ToolContext {
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the server-side CodeCall policy for a tool name (GHSA-6w3j-82v5-6qrr).
|
|
6
|
+
*
|
|
7
|
+
* Shares its decision with discovery and with `codecall:invoke`, so the three cannot
|
|
8
|
+
* diverge. A name matching no registered tool is denied rather than passed through —
|
|
9
|
+
* otherwise it would skip every metadata-driven check and reach `tools:call-tool`
|
|
10
|
+
* unexamined.
|
|
11
|
+
*/
|
|
12
|
+
private checkToolPolicy;
|
|
4
13
|
execute(input: ExecuteToolInput): Promise<CodeCallExecuteResult>;
|
|
5
14
|
}
|
|
6
15
|
//# sourceMappingURL=execute.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.tool.d.ts","sourceRoot":"","sources":["../../src/tools/execute.tool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"execute.tool.d.ts","sourceRoot":"","sources":["../../src/tools/execute.tool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,WAAW,EAAE,MAAM,eAAe,CAAC;AAmBlD,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAyC1B,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAIjB,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CA4QvE"}
|
package/tools/invoke.tool.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ import { InvokeToolInput, InvokeToolOutput } from './invoke.schema';
|
|
|
6
6
|
*
|
|
7
7
|
* Security Considerations:
|
|
8
8
|
* - Self-reference blocking: Cannot invoke codecall:* tools
|
|
9
|
+
* - Shares the CodeCall access policy with `codecall:execute`, so a tool withheld from
|
|
10
|
+
* scripts is not reachable by naming it here instead (GHSA-6w3j-82v5-6qrr)
|
|
9
11
|
* - All middleware (auth, PII, rate limiting) applies via normal tool execution
|
|
10
12
|
*/
|
|
11
13
|
export default class InvokeTool extends ToolContext {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke.tool.d.ts","sourceRoot":"","sources":["../../src/tools/invoke.tool.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"invoke.tool.d.ts","sourceRoot":"","sources":["../../src/tools/invoke.tool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,WAAW,EAAE,MAAM,eAAe,CAAC;AAIlD,OAAO,EAEL,eAAe,EAEf,gBAAgB,EAEjB,MAAM,iBAAiB,CAAC;AAYzB;;;;;;;;;GASG;AAeH,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;IAC3C,OAAO,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA4CjE"}
|
|
@@ -20,7 +20,7 @@ export type ToolNamespaces = Record<string, ToolNamespace>;
|
|
|
20
20
|
* Reasons a tool may be skipped during namespace generation. Returned so the
|
|
21
21
|
* caller can surface diagnostics without re-deriving the rules.
|
|
22
22
|
*/
|
|
23
|
-
export type NamespaceSkipReason = 'no-namespace-prefix' | 'invalid-identifier' | 'reserved-namespace' | 'duplicate-method';
|
|
23
|
+
export type NamespaceSkipReason = 'no-namespace-prefix' | 'invalid-identifier' | 'reserved-namespace' | 'prototype-key' | 'duplicate-method';
|
|
24
24
|
export interface BuildToolNamespacesResult {
|
|
25
25
|
/** The namespaces object to merge into the VM globals. */
|
|
26
26
|
namespaces: ToolNamespaces;
|
|
@@ -37,6 +37,8 @@ export interface BuildToolNamespacesResult {
|
|
|
37
37
|
* - Tools whose name has no `.` are skipped (still callable via `callTool`).
|
|
38
38
|
* - Tools whose prefix or suffix is not a valid JS identifier are skipped.
|
|
39
39
|
* - Tools whose prefix collides with a reserved global are skipped.
|
|
40
|
+
* - Tools whose PREFIX is a prototype key (`__proto__`, `constructor`,
|
|
41
|
+
* `prototype`) are skipped — they would write onto a JavaScript intrinsic.
|
|
40
42
|
* - First registration wins on duplicate `{ns}.{method}` (subsequent are reported as skipped).
|
|
41
43
|
*
|
|
42
44
|
* The returned methods are thin wrappers that delegate to `callTool` with the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-tool-namespaces.d.ts","sourceRoot":"","sources":["../../src/utils/build-tool-namespaces.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"build-tool-namespaces.d.ts","sourceRoot":"","sources":["../../src/utils/build-tool-namespaces.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AA2DjE;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,eAAe,KACtB,OAAO,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAE7G,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC3B,qBAAqB,GACrB,oBAAoB,GACpB,oBAAoB,GACpB,eAAe,GACf,kBAAkB,CAAC;AAEvB,MAAM,WAAW,yBAAyB;IACxC,0DAA0D;IAC1D,UAAU,EAAE,cAAc,CAAC;IAC3B,+EAA+E;IAC/E,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,mBAAmB,CAAA;KAAE,CAAC,CAAC;CAC/D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC,EACvC,QAAQ,EAAE,kBAAkB,GAC3B,yBAAyB,CAsD3B"}
|