@vybestack/llxprt-code-core 0.5.0-nightly.251121.9dcb43714 → 0.5.0-nightly.251121.bd93fe760
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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/src/config/config.d.ts +9 -0
- package/dist/src/config/config.js +16 -0
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/confirmation-bus/index.d.ts +2 -0
- package/dist/src/confirmation-bus/index.js +3 -0
- package/dist/src/confirmation-bus/index.js.map +1 -0
- package/dist/src/confirmation-bus/message-bus.d.ts +60 -0
- package/dist/src/confirmation-bus/message-bus.js +141 -0
- package/dist/src/confirmation-bus/message-bus.js.map +1 -0
- package/dist/src/confirmation-bus/types.d.ts +59 -0
- package/dist/src/confirmation-bus/types.js +10 -0
- package/dist/src/confirmation-bus/types.js.map +1 -0
- package/dist/src/core/client.d.ts +1 -1
- package/dist/src/core/client.js +24 -11
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/coreToolScheduler.d.ts +18 -1
- package/dist/src/core/coreToolScheduler.js +133 -13
- package/dist/src/core/coreToolScheduler.js.map +1 -1
- package/dist/src/core/geminiChat.js +2 -0
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/ide/detect-ide.d.ts +44 -14
- package/dist/src/ide/detect-ide.js +35 -75
- package/dist/src/ide/detect-ide.js.map +1 -1
- package/dist/src/ide/ide-client.d.ts +4 -4
- package/dist/src/ide/ide-client.js +25 -24
- package/dist/src/ide/ide-client.js.map +1 -1
- package/dist/src/ide/ide-installer.d.ts +2 -2
- package/dist/src/ide/ide-installer.js +7 -9
- package/dist/src/ide/ide-installer.js.map +1 -1
- package/dist/src/index.d.ts +7 -1
- package/dist/src/index.js +9 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/oauth-provider.d.ts +4 -1
- package/dist/src/mcp/oauth-provider.js +30 -27
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/policy/config.d.ts +51 -0
- package/dist/src/policy/config.js +102 -0
- package/dist/src/policy/config.js.map +1 -0
- package/dist/src/policy/index.d.ts +5 -0
- package/dist/src/policy/index.js +6 -0
- package/dist/src/policy/index.js.map +1 -0
- package/dist/src/policy/policies/discovered.toml +9 -0
- package/dist/src/policy/policies/read-only.toml +68 -0
- package/dist/src/policy/policies/write.toml +69 -0
- package/dist/src/policy/policies/yolo.toml +8 -0
- package/dist/src/policy/policy-engine.d.ts +55 -0
- package/dist/src/policy/policy-engine.js +126 -0
- package/dist/src/policy/policy-engine.js.map +1 -0
- package/dist/src/policy/stable-stringify.d.ts +29 -0
- package/dist/src/policy/stable-stringify.js +111 -0
- package/dist/src/policy/stable-stringify.js.map +1 -0
- package/dist/src/policy/toml-loader.d.ts +37 -0
- package/dist/src/policy/toml-loader.js +183 -0
- package/dist/src/policy/toml-loader.js.map +1 -0
- package/dist/src/policy/types.d.ts +16 -0
- package/dist/src/policy/types.js +7 -0
- package/dist/src/policy/types.js.map +1 -0
- package/dist/src/telemetry/uiTelemetry.d.ts +1 -1
- package/dist/src/telemetry/uiTelemetry.js +2 -3
- package/dist/src/telemetry/uiTelemetry.js.map +1 -1
- package/dist/src/tools/edit.d.ts +3 -2
- package/dist/src/tools/edit.js +23 -10
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/glob.d.ts +3 -2
- package/dist/src/tools/glob.js +2 -2
- package/dist/src/tools/glob.js.map +1 -1
- package/dist/src/tools/grep.d.ts +3 -2
- package/dist/src/tools/grep.js +2 -2
- package/dist/src/tools/grep.js.map +1 -1
- package/dist/src/tools/ls.d.ts +3 -2
- package/dist/src/tools/ls.js +2 -2
- package/dist/src/tools/ls.js.map +1 -1
- package/dist/src/tools/mcp-tool.js +7 -1
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/memoryTool.d.ts +5 -2
- package/dist/src/tools/memoryTool.js +12 -4
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/read-file.d.ts +3 -2
- package/dist/src/tools/read-file.js +2 -2
- package/dist/src/tools/read-file.js.map +1 -1
- package/dist/src/tools/read-many-files.d.ts +3 -2
- package/dist/src/tools/read-many-files.js +2 -2
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/ripGrep.d.ts +3 -2
- package/dist/src/tools/ripGrep.js +2 -2
- package/dist/src/tools/ripGrep.js.map +1 -1
- package/dist/src/tools/shell.d.ts +3 -2
- package/dist/src/tools/shell.js +10 -6
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/smart-edit.d.ts +3 -2
- package/dist/src/tools/smart-edit.js +13 -9
- package/dist/src/tools/smart-edit.js.map +1 -1
- package/dist/src/tools/tool-confirmation-types.d.ts +20 -0
- package/dist/src/tools/tool-confirmation-types.js +15 -0
- package/dist/src/tools/tool-confirmation-types.js.map +1 -0
- package/dist/src/tools/tool-error.d.ts +1 -0
- package/dist/src/tools/tool-error.js +1 -0
- package/dist/src/tools/tool-error.js.map +1 -1
- package/dist/src/tools/tool-registry.d.ts +8 -1
- package/dist/src/tools/tool-registry.js +18 -4
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tools.d.ts +52 -14
- package/dist/src/tools/tools.js +71 -15
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/web-fetch.d.ts +3 -2
- package/dist/src/tools/web-fetch.js +11 -6
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-search-invocation.d.ts +3 -1
- package/dist/src/tools/web-search-invocation.js +5 -2
- package/dist/src/tools/web-search-invocation.js.map +1 -1
- package/dist/src/tools/web-search.d.ts +3 -2
- package/dist/src/tools/web-search.js +6 -4
- package/dist/src/tools/web-search.js.map +1 -1
- package/dist/src/tools/write-file.d.ts +3 -2
- package/dist/src/tools/write-file.js +11 -6
- package/dist/src/tools/write-file.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy Configuration
|
|
3
|
+
*
|
|
4
|
+
* Creates PolicyEngineConfig by merging:
|
|
5
|
+
* 1. Default TOML policy files (read-only, write)
|
|
6
|
+
* 2. Legacy ApprovalMode migration rules
|
|
7
|
+
* 3. User-defined TOML policies (if provided)
|
|
8
|
+
* 4. Runtime rules (e.g., "Always Allow" UI selections)
|
|
9
|
+
*
|
|
10
|
+
* Implements legacy migration from ApprovalMode and --allowed-tools to policy rules.
|
|
11
|
+
*/
|
|
12
|
+
import { type PolicyRule, type PolicyEngineConfig } from './types.js';
|
|
13
|
+
import { ApprovalMode } from '../config/config.js';
|
|
14
|
+
/**
|
|
15
|
+
* Minimal Config interface for policy creation
|
|
16
|
+
* Avoids circular dependency by only requiring the methods we need
|
|
17
|
+
*/
|
|
18
|
+
export interface PolicyConfigSource {
|
|
19
|
+
getApprovalMode(): ApprovalMode;
|
|
20
|
+
getAllowedTools(): string[] | undefined;
|
|
21
|
+
getNonInteractive(): boolean;
|
|
22
|
+
getUserPolicyPath?(): string | undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Converts legacy ApprovalMode and --allowed-tools to policy rules.
|
|
26
|
+
*
|
|
27
|
+
* Priority bands:
|
|
28
|
+
* - 1.999: YOLO mode allow-all (wildcard)
|
|
29
|
+
* - 1.015: AUTO_EDIT mode write tools
|
|
30
|
+
* - 2.3: --allowed-tools CLI flag
|
|
31
|
+
*
|
|
32
|
+
* @param config - Config object with approval mode and allowed tools
|
|
33
|
+
* @returns Array of PolicyRule objects representing legacy settings
|
|
34
|
+
*/
|
|
35
|
+
export declare function migrateLegacyApprovalMode(config: PolicyConfigSource): PolicyRule[];
|
|
36
|
+
/**
|
|
37
|
+
* Creates the full PolicyEngineConfig by merging:
|
|
38
|
+
* 1. Default TOML policy files (read-only.toml, write.toml)
|
|
39
|
+
* 2. Legacy ApprovalMode migration rules
|
|
40
|
+
* 3. User-defined TOML policies (if userPolicyPath provided)
|
|
41
|
+
* 4. Runtime rules (can be added later via PolicyEngine.addRule)
|
|
42
|
+
*
|
|
43
|
+
* Rules are evaluated by priority (highest wins), so:
|
|
44
|
+
* - User policies (Tier 2: 2.xxx) override defaults (Tier 1: 1.xxx)
|
|
45
|
+
* - Legacy migration rules slot into appropriate priority bands
|
|
46
|
+
* - Admin policies (Tier 3: 3.xxx, if added later) override all
|
|
47
|
+
*
|
|
48
|
+
* @param config - Config object with policy settings
|
|
49
|
+
* @returns PolicyEngineConfig ready for PolicyEngine construction
|
|
50
|
+
*/
|
|
51
|
+
export declare function createPolicyEngineConfig(config: PolicyConfigSource): Promise<PolicyEngineConfig>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy Configuration
|
|
3
|
+
*
|
|
4
|
+
* Creates PolicyEngineConfig by merging:
|
|
5
|
+
* 1. Default TOML policy files (read-only, write)
|
|
6
|
+
* 2. Legacy ApprovalMode migration rules
|
|
7
|
+
* 3. User-defined TOML policies (if provided)
|
|
8
|
+
* 4. Runtime rules (e.g., "Always Allow" UI selections)
|
|
9
|
+
*
|
|
10
|
+
* Implements legacy migration from ApprovalMode and --allowed-tools to policy rules.
|
|
11
|
+
*/
|
|
12
|
+
import { PolicyDecision, } from './types.js';
|
|
13
|
+
import { loadDefaultPolicies, loadPolicyFromToml } from './toml-loader.js';
|
|
14
|
+
import { ApprovalMode } from '../config/config.js';
|
|
15
|
+
/**
|
|
16
|
+
* Converts legacy ApprovalMode and --allowed-tools to policy rules.
|
|
17
|
+
*
|
|
18
|
+
* Priority bands:
|
|
19
|
+
* - 1.999: YOLO mode allow-all (wildcard)
|
|
20
|
+
* - 1.015: AUTO_EDIT mode write tools
|
|
21
|
+
* - 2.3: --allowed-tools CLI flag
|
|
22
|
+
*
|
|
23
|
+
* @param config - Config object with approval mode and allowed tools
|
|
24
|
+
* @returns Array of PolicyRule objects representing legacy settings
|
|
25
|
+
*/
|
|
26
|
+
export function migrateLegacyApprovalMode(config) {
|
|
27
|
+
const rules = [];
|
|
28
|
+
// Map ApprovalMode
|
|
29
|
+
const approvalMode = config.getApprovalMode();
|
|
30
|
+
if (approvalMode === ApprovalMode.YOLO) {
|
|
31
|
+
// YOLO mode: allow all tools with wildcard rule
|
|
32
|
+
rules.push({
|
|
33
|
+
// toolName: undefined means wildcard - matches all tools
|
|
34
|
+
decision: PolicyDecision.ALLOW,
|
|
35
|
+
priority: 1.999,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else if (approvalMode === ApprovalMode.AUTO_EDIT) {
|
|
39
|
+
// AUTO_EDIT mode: allow write tools at priority 1.015
|
|
40
|
+
const writeTools = ['edit', 'smart_edit', 'write_file', 'shell', 'memory'];
|
|
41
|
+
for (const tool of writeTools) {
|
|
42
|
+
rules.push({
|
|
43
|
+
toolName: tool,
|
|
44
|
+
decision: PolicyDecision.ALLOW,
|
|
45
|
+
priority: 1.015,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// ApprovalMode.DEFAULT doesn't add any rules - standard policy stack applies
|
|
50
|
+
// Map --allowed-tools
|
|
51
|
+
const allowedTools = config.getAllowedTools() ?? [];
|
|
52
|
+
for (const tool of allowedTools) {
|
|
53
|
+
rules.push({
|
|
54
|
+
toolName: tool,
|
|
55
|
+
decision: PolicyDecision.ALLOW,
|
|
56
|
+
priority: 2.3,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return rules;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Creates the full PolicyEngineConfig by merging:
|
|
63
|
+
* 1. Default TOML policy files (read-only.toml, write.toml)
|
|
64
|
+
* 2. Legacy ApprovalMode migration rules
|
|
65
|
+
* 3. User-defined TOML policies (if userPolicyPath provided)
|
|
66
|
+
* 4. Runtime rules (can be added later via PolicyEngine.addRule)
|
|
67
|
+
*
|
|
68
|
+
* Rules are evaluated by priority (highest wins), so:
|
|
69
|
+
* - User policies (Tier 2: 2.xxx) override defaults (Tier 1: 1.xxx)
|
|
70
|
+
* - Legacy migration rules slot into appropriate priority bands
|
|
71
|
+
* - Admin policies (Tier 3: 3.xxx, if added later) override all
|
|
72
|
+
*
|
|
73
|
+
* @param config - Config object with policy settings
|
|
74
|
+
* @returns PolicyEngineConfig ready for PolicyEngine construction
|
|
75
|
+
*/
|
|
76
|
+
export async function createPolicyEngineConfig(config) {
|
|
77
|
+
const rules = [];
|
|
78
|
+
// 1. Load default policies from TOML
|
|
79
|
+
const defaultRules = await loadDefaultPolicies();
|
|
80
|
+
rules.push(...defaultRules);
|
|
81
|
+
// 2. Migrate legacy settings (ApprovalMode, --allowed-tools)
|
|
82
|
+
const legacyRules = migrateLegacyApprovalMode(config);
|
|
83
|
+
rules.push(...legacyRules);
|
|
84
|
+
// 3. Load user-defined policies (if any)
|
|
85
|
+
const userPolicyPath = config.getUserPolicyPath?.();
|
|
86
|
+
if (userPolicyPath) {
|
|
87
|
+
try {
|
|
88
|
+
const userRules = await loadPolicyFromToml(userPolicyPath);
|
|
89
|
+
rules.push(...userRules);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
// Log warning but don't fail - user policies are optional
|
|
93
|
+
console.warn(`Failed to load user policy from ${userPolicyPath}:`, error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
rules,
|
|
98
|
+
defaultDecision: PolicyDecision.ASK_USER,
|
|
99
|
+
nonInteractive: config.getNonInteractive(),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/policy/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,cAAc,GAGf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAanD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAA0B;IAE1B,MAAM,KAAK,GAAiB,EAAE,CAAC;IAE/B,mBAAmB;IACnB,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,EAAE,CAAC;IAE9C,IAAI,YAAY,KAAK,YAAY,CAAC,IAAI,EAAE,CAAC;QACvC,gDAAgD;QAChD,KAAK,CAAC,IAAI,CAAC;YACT,yDAAyD;YACzD,QAAQ,EAAE,cAAc,CAAC,KAAK;YAC9B,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,YAAY,KAAK,YAAY,CAAC,SAAS,EAAE,CAAC;QACnD,sDAAsD;QACtD,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC3E,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC;gBACT,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,cAAc,CAAC,KAAK;gBAC9B,QAAQ,EAAE,KAAK;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,6EAA6E;IAE7E,sBAAsB;IACtB,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IACpD,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC;YACT,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,cAAc,CAAC,KAAK;YAC9B,QAAQ,EAAE,GAAG;SACd,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,MAA0B;IAE1B,MAAM,KAAK,GAAiB,EAAE,CAAC;IAE/B,qCAAqC;IACrC,MAAM,YAAY,GAAG,MAAM,mBAAmB,EAAE,CAAC;IACjD,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IAE5B,6DAA6D;IAC7D,MAAM,WAAW,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IACtD,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;IAE3B,yCAAyC;IACzC,MAAM,cAAc,GAAG,MAAM,CAAC,iBAAiB,EAAE,EAAE,CAAC;IACpD,IAAI,cAAc,EAAE,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,cAAc,CAAC,CAAC;YAC3D,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,0DAA0D;YAC1D,OAAO,CAAC,IAAI,CAAC,mCAAmC,cAAc,GAAG,EAAE,KAAK,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK;QACL,eAAe,EAAE,cAAc,CAAC,QAAQ;QACxC,cAAc,EAAE,MAAM,CAAC,iBAAiB,EAAE;KAC3C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/policy/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Default policy for discovered tools (MCP, extensions, etc.)
|
|
2
|
+
# Priority band: 1.01 (Tier 1 - Default)
|
|
3
|
+
# Discovered tools require user confirmation unless explicitly trusted
|
|
4
|
+
|
|
5
|
+
[[rule]]
|
|
6
|
+
# Match all discovered tools (tools with discovered_tool_ prefix will be added by ToolRegistry)
|
|
7
|
+
toolName = "discovered_tool_"
|
|
8
|
+
decision = "ask_user"
|
|
9
|
+
priority = 1.01
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Default read-only tool policy
|
|
2
|
+
# Priority band: 1.05 (Tier 1 - Default)
|
|
3
|
+
# These tools are considered safe for auto-approval
|
|
4
|
+
|
|
5
|
+
[[rule]]
|
|
6
|
+
toolName = "glob"
|
|
7
|
+
decision = "allow"
|
|
8
|
+
priority = 1.05
|
|
9
|
+
|
|
10
|
+
[[rule]]
|
|
11
|
+
toolName = "grep"
|
|
12
|
+
decision = "allow"
|
|
13
|
+
priority = 1.05
|
|
14
|
+
|
|
15
|
+
[[rule]]
|
|
16
|
+
toolName = "ls"
|
|
17
|
+
decision = "allow"
|
|
18
|
+
priority = 1.05
|
|
19
|
+
|
|
20
|
+
[[rule]]
|
|
21
|
+
toolName = "read_file"
|
|
22
|
+
decision = "allow"
|
|
23
|
+
priority = 1.05
|
|
24
|
+
|
|
25
|
+
[[rule]]
|
|
26
|
+
toolName = "read_many_files"
|
|
27
|
+
decision = "allow"
|
|
28
|
+
priority = 1.05
|
|
29
|
+
|
|
30
|
+
[[rule]]
|
|
31
|
+
toolName = "ripgrep"
|
|
32
|
+
decision = "allow"
|
|
33
|
+
priority = 1.05
|
|
34
|
+
|
|
35
|
+
[[rule]]
|
|
36
|
+
toolName = "web_search"
|
|
37
|
+
decision = "allow"
|
|
38
|
+
priority = 1.05
|
|
39
|
+
|
|
40
|
+
[[rule]]
|
|
41
|
+
toolName = "task"
|
|
42
|
+
decision = "allow"
|
|
43
|
+
priority = 1.05
|
|
44
|
+
|
|
45
|
+
[[rule]]
|
|
46
|
+
toolName = "write_todos"
|
|
47
|
+
decision = "allow"
|
|
48
|
+
priority = 1.05
|
|
49
|
+
|
|
50
|
+
[[rule]]
|
|
51
|
+
toolName = "list_subagents"
|
|
52
|
+
decision = "allow"
|
|
53
|
+
priority = 1.05
|
|
54
|
+
|
|
55
|
+
[[rule]]
|
|
56
|
+
toolName = "notebook_edit"
|
|
57
|
+
decision = "allow"
|
|
58
|
+
priority = 1.05
|
|
59
|
+
|
|
60
|
+
[[rule]]
|
|
61
|
+
toolName = "slash_command"
|
|
62
|
+
decision = "allow"
|
|
63
|
+
priority = 1.05
|
|
64
|
+
|
|
65
|
+
[[rule]]
|
|
66
|
+
toolName = "skill"
|
|
67
|
+
decision = "allow"
|
|
68
|
+
priority = 1.05
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Default write tool policy
|
|
2
|
+
# Priority band: 1.01 (Tier 1 - Default)
|
|
3
|
+
# These tools require user confirmation by default
|
|
4
|
+
|
|
5
|
+
[[rule]]
|
|
6
|
+
toolName = "edit"
|
|
7
|
+
decision = "ask_user"
|
|
8
|
+
priority = 1.01
|
|
9
|
+
|
|
10
|
+
[[rule]]
|
|
11
|
+
toolName = "smart_edit"
|
|
12
|
+
decision = "ask_user"
|
|
13
|
+
priority = 1.01
|
|
14
|
+
|
|
15
|
+
[[rule]]
|
|
16
|
+
toolName = "write_file"
|
|
17
|
+
decision = "ask_user"
|
|
18
|
+
priority = 1.01
|
|
19
|
+
|
|
20
|
+
[[rule]]
|
|
21
|
+
toolName = "shell"
|
|
22
|
+
decision = "ask_user"
|
|
23
|
+
priority = 1.01
|
|
24
|
+
|
|
25
|
+
[[rule]]
|
|
26
|
+
toolName = "memory"
|
|
27
|
+
decision = "ask_user"
|
|
28
|
+
priority = 1.01
|
|
29
|
+
|
|
30
|
+
[[rule]]
|
|
31
|
+
toolName = "web_fetch"
|
|
32
|
+
decision = "ask_user"
|
|
33
|
+
priority = 1.01
|
|
34
|
+
|
|
35
|
+
[[rule]]
|
|
36
|
+
toolName = "mcp_tool"
|
|
37
|
+
decision = "ask_user"
|
|
38
|
+
priority = 1.01
|
|
39
|
+
|
|
40
|
+
# Shell commands with dangerous patterns are denied
|
|
41
|
+
[[rule]]
|
|
42
|
+
toolName = "shell"
|
|
43
|
+
argsPattern = "rm\\s+-rf\\s+/"
|
|
44
|
+
decision = "deny"
|
|
45
|
+
priority = 2.0
|
|
46
|
+
|
|
47
|
+
[[rule]]
|
|
48
|
+
toolName = "shell"
|
|
49
|
+
argsPattern = "chmod\\s+777"
|
|
50
|
+
decision = "deny"
|
|
51
|
+
priority = 2.0
|
|
52
|
+
|
|
53
|
+
[[rule]]
|
|
54
|
+
toolName = "shell"
|
|
55
|
+
argsPattern = "dd\\s+if="
|
|
56
|
+
decision = "deny"
|
|
57
|
+
priority = 2.0
|
|
58
|
+
|
|
59
|
+
[[rule]]
|
|
60
|
+
toolName = "shell"
|
|
61
|
+
argsPattern = "mkfs\\."
|
|
62
|
+
decision = "deny"
|
|
63
|
+
priority = 2.0
|
|
64
|
+
|
|
65
|
+
[[rule]]
|
|
66
|
+
toolName = "shell"
|
|
67
|
+
argsPattern = ":(){ :|:& };:"
|
|
68
|
+
decision = "deny"
|
|
69
|
+
priority = 2.0
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# YOLO mode policy - allow everything
|
|
2
|
+
# Priority band: 1.999 (Tier 1 - Default, just below user settings)
|
|
3
|
+
# WARNING: This disables all safety checks. Use only in trusted environments.
|
|
4
|
+
|
|
5
|
+
[[rule]]
|
|
6
|
+
# No toolName specified = wildcard (matches all tools)
|
|
7
|
+
decision = "allow"
|
|
8
|
+
priority = 1.999
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { PolicyDecision, type PolicyEngineConfig, type PolicyRule } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* PolicyEngine evaluates tool execution requests against configured rules.
|
|
4
|
+
* Rules are matched in priority order, with the highest priority rule winning.
|
|
5
|
+
*/
|
|
6
|
+
export declare class PolicyEngine {
|
|
7
|
+
private readonly rules;
|
|
8
|
+
private readonly defaultDecision;
|
|
9
|
+
private readonly nonInteractive;
|
|
10
|
+
constructor(config?: PolicyEngineConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Evaluates a tool execution request and returns a policy decision.
|
|
13
|
+
*
|
|
14
|
+
* @param toolName - The name of the tool being executed
|
|
15
|
+
* @param args - The arguments passed to the tool
|
|
16
|
+
* @param serverName - Optional MCP server name (for spoofing prevention)
|
|
17
|
+
* @returns PolicyDecision (ALLOW, DENY, or ASK_USER)
|
|
18
|
+
*/
|
|
19
|
+
evaluate(toolName: string, args: Record<string, unknown>, serverName?: string): PolicyDecision;
|
|
20
|
+
/**
|
|
21
|
+
* Finds the highest priority rule matching the tool and args.
|
|
22
|
+
*
|
|
23
|
+
* @param toolName - The name of the tool
|
|
24
|
+
* @param args - The tool arguments
|
|
25
|
+
* @returns The matching rule, or undefined if none match
|
|
26
|
+
*/
|
|
27
|
+
private findMatchingRule;
|
|
28
|
+
/**
|
|
29
|
+
* Validates that a tool name matches its claimed server name.
|
|
30
|
+
* Returns null if spoofing is detected, otherwise returns the tool name.
|
|
31
|
+
*
|
|
32
|
+
* @param toolName - The tool name (may include server prefix)
|
|
33
|
+
* @param serverName - The claimed server name
|
|
34
|
+
* @returns The validated tool name, or null if spoofing detected
|
|
35
|
+
*/
|
|
36
|
+
private validateServerName;
|
|
37
|
+
/**
|
|
38
|
+
* Returns all configured rules (for debugging/inspection).
|
|
39
|
+
*
|
|
40
|
+
* @returns Array of policy rules
|
|
41
|
+
*/
|
|
42
|
+
getRules(): readonly PolicyRule[];
|
|
43
|
+
/**
|
|
44
|
+
* Returns the default decision used when no rules match.
|
|
45
|
+
*
|
|
46
|
+
* @returns PolicyDecision
|
|
47
|
+
*/
|
|
48
|
+
getDefaultDecision(): PolicyDecision;
|
|
49
|
+
/**
|
|
50
|
+
* Returns whether the engine is in non-interactive mode.
|
|
51
|
+
*
|
|
52
|
+
* @returns boolean
|
|
53
|
+
*/
|
|
54
|
+
isNonInteractive(): boolean;
|
|
55
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { PolicyDecision, } from './types.js';
|
|
2
|
+
import { stableStringify } from './stable-stringify.js';
|
|
3
|
+
/**
|
|
4
|
+
* PolicyEngine evaluates tool execution requests against configured rules.
|
|
5
|
+
* Rules are matched in priority order, with the highest priority rule winning.
|
|
6
|
+
*/
|
|
7
|
+
export class PolicyEngine {
|
|
8
|
+
rules;
|
|
9
|
+
defaultDecision;
|
|
10
|
+
nonInteractive;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.rules = config?.rules ?? [];
|
|
13
|
+
this.defaultDecision = config?.defaultDecision ?? PolicyDecision.ASK_USER;
|
|
14
|
+
this.nonInteractive = config?.nonInteractive ?? false;
|
|
15
|
+
// Sort rules by priority (highest first)
|
|
16
|
+
this.rules.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Evaluates a tool execution request and returns a policy decision.
|
|
20
|
+
*
|
|
21
|
+
* @param toolName - The name of the tool being executed
|
|
22
|
+
* @param args - The arguments passed to the tool
|
|
23
|
+
* @param serverName - Optional MCP server name (for spoofing prevention)
|
|
24
|
+
* @returns PolicyDecision (ALLOW, DENY, or ASK_USER)
|
|
25
|
+
*/
|
|
26
|
+
evaluate(toolName, args, serverName) {
|
|
27
|
+
// Validate serverName to prevent spoofing
|
|
28
|
+
if (serverName) {
|
|
29
|
+
const validatedToolName = this.validateServerName(toolName, serverName);
|
|
30
|
+
if (validatedToolName === null) {
|
|
31
|
+
// Server name spoofing detected - deny
|
|
32
|
+
return PolicyDecision.DENY;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Find the highest priority matching rule
|
|
36
|
+
const matchingRule = this.findMatchingRule(toolName, args);
|
|
37
|
+
if (matchingRule) {
|
|
38
|
+
const decision = matchingRule.decision;
|
|
39
|
+
// In non-interactive mode, ASK_USER becomes DENY
|
|
40
|
+
if (this.nonInteractive && decision === PolicyDecision.ASK_USER) {
|
|
41
|
+
return PolicyDecision.DENY;
|
|
42
|
+
}
|
|
43
|
+
return decision;
|
|
44
|
+
}
|
|
45
|
+
// No matching rule - use default decision
|
|
46
|
+
if (this.nonInteractive &&
|
|
47
|
+
this.defaultDecision === PolicyDecision.ASK_USER) {
|
|
48
|
+
return PolicyDecision.DENY;
|
|
49
|
+
}
|
|
50
|
+
return this.defaultDecision;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Finds the highest priority rule matching the tool and args.
|
|
54
|
+
*
|
|
55
|
+
* @param toolName - The name of the tool
|
|
56
|
+
* @param args - The tool arguments
|
|
57
|
+
* @returns The matching rule, or undefined if none match
|
|
58
|
+
*/
|
|
59
|
+
findMatchingRule(toolName, args) {
|
|
60
|
+
const argsString = stableStringify(args);
|
|
61
|
+
for (const rule of this.rules) {
|
|
62
|
+
// Check tool name match
|
|
63
|
+
const toolMatches = !rule.toolName || rule.toolName === toolName;
|
|
64
|
+
if (!toolMatches) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Check args pattern match
|
|
68
|
+
const argsMatch = !rule.argsPattern || rule.argsPattern.test(argsString);
|
|
69
|
+
if (!argsMatch) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// Both match - return this rule
|
|
73
|
+
return rule;
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validates that a tool name matches its claimed server name.
|
|
79
|
+
* Returns null if spoofing is detected, otherwise returns the tool name.
|
|
80
|
+
*
|
|
81
|
+
* @param toolName - The tool name (may include server prefix)
|
|
82
|
+
* @param serverName - The claimed server name
|
|
83
|
+
* @returns The validated tool name, or null if spoofing detected
|
|
84
|
+
*/
|
|
85
|
+
validateServerName(toolName, serverName) {
|
|
86
|
+
// For MCP tools, expect format: "serverName__toolName"
|
|
87
|
+
const expectedPrefix = `${serverName}__`;
|
|
88
|
+
if (toolName.startsWith(expectedPrefix)) {
|
|
89
|
+
return toolName;
|
|
90
|
+
}
|
|
91
|
+
// If tool name doesn't have the expected prefix, check if it's a non-MCP tool
|
|
92
|
+
// Non-MCP tools don't have a server prefix, so if a serverName is provided
|
|
93
|
+
// but the tool doesn't have the prefix, it's likely spoofing
|
|
94
|
+
if (!toolName.includes('__')) {
|
|
95
|
+
// This is a built-in tool, serverName should not be set
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
// Tool has a different server prefix - spoofing attempt
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Returns all configured rules (for debugging/inspection).
|
|
103
|
+
*
|
|
104
|
+
* @returns Array of policy rules
|
|
105
|
+
*/
|
|
106
|
+
getRules() {
|
|
107
|
+
return [...this.rules];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Returns the default decision used when no rules match.
|
|
111
|
+
*
|
|
112
|
+
* @returns PolicyDecision
|
|
113
|
+
*/
|
|
114
|
+
getDefaultDecision() {
|
|
115
|
+
return this.defaultDecision;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Returns whether the engine is in non-interactive mode.
|
|
119
|
+
*
|
|
120
|
+
* @returns boolean
|
|
121
|
+
*/
|
|
122
|
+
isNonInteractive() {
|
|
123
|
+
return this.nonInteractive;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=policy-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-engine.js","sourceRoot":"","sources":["../../../src/policy/policy-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides deterministic JSON stringification for pattern matching in policy rules.
|
|
3
|
+
* Ensures consistent ordering of object keys and handling of special values.
|
|
4
|
+
*/
|
|
5
|
+
type JSONValue = string | number | boolean | null | JSONValue[] | {
|
|
6
|
+
[key: string]: JSONValue;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Deterministically stringifies a value for use in pattern matching.
|
|
10
|
+
* - Object keys are sorted alphabetically
|
|
11
|
+
* - Arrays maintain their order
|
|
12
|
+
* - undefined values are omitted
|
|
13
|
+
* - Functions and symbols are converted to null
|
|
14
|
+
* - Circular references throw an error
|
|
15
|
+
*
|
|
16
|
+
* @param value - The value to stringify
|
|
17
|
+
* @param space - Optional spacing for readability (default: none)
|
|
18
|
+
* @returns Deterministic JSON string
|
|
19
|
+
*/
|
|
20
|
+
export declare function stableStringify(value: unknown, space?: string | number): string;
|
|
21
|
+
/**
|
|
22
|
+
* Parses a stable-stringified JSON string back into a value.
|
|
23
|
+
* This is just a wrapper around JSON.parse for consistency.
|
|
24
|
+
*
|
|
25
|
+
* @param text - The JSON string to parse
|
|
26
|
+
* @returns Parsed value
|
|
27
|
+
*/
|
|
28
|
+
export declare function stableParse(text: string): JSONValue;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides deterministic JSON stringification for pattern matching in policy rules.
|
|
3
|
+
* Ensures consistent ordering of object keys and handling of special values.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Deterministically stringifies a value for use in pattern matching.
|
|
7
|
+
* - Object keys are sorted alphabetically
|
|
8
|
+
* - Arrays maintain their order
|
|
9
|
+
* - undefined values are omitted
|
|
10
|
+
* - Functions and symbols are converted to null
|
|
11
|
+
* - Circular references throw an error
|
|
12
|
+
*
|
|
13
|
+
* @param value - The value to stringify
|
|
14
|
+
* @param space - Optional spacing for readability (default: none)
|
|
15
|
+
* @returns Deterministic JSON string
|
|
16
|
+
*/
|
|
17
|
+
export function stableStringify(value, space) {
|
|
18
|
+
const seen = new WeakSet();
|
|
19
|
+
function stringify(val, indent, currentDepth) {
|
|
20
|
+
// Handle primitives
|
|
21
|
+
if (val === null)
|
|
22
|
+
return 'null';
|
|
23
|
+
if (val === undefined)
|
|
24
|
+
return 'null';
|
|
25
|
+
if (typeof val === 'boolean')
|
|
26
|
+
return String(val);
|
|
27
|
+
if (typeof val === 'number') {
|
|
28
|
+
if (!Number.isFinite(val))
|
|
29
|
+
return 'null';
|
|
30
|
+
return String(val);
|
|
31
|
+
}
|
|
32
|
+
if (typeof val === 'string') {
|
|
33
|
+
return JSON.stringify(val);
|
|
34
|
+
}
|
|
35
|
+
// Handle functions and symbols
|
|
36
|
+
if (typeof val === 'function' || typeof val === 'symbol') {
|
|
37
|
+
return 'null';
|
|
38
|
+
}
|
|
39
|
+
// Handle objects and arrays
|
|
40
|
+
if (typeof val === 'object') {
|
|
41
|
+
// Circular reference check
|
|
42
|
+
if (seen.has(val)) {
|
|
43
|
+
throw new TypeError('Converting circular structure to JSON');
|
|
44
|
+
}
|
|
45
|
+
seen.add(val);
|
|
46
|
+
try {
|
|
47
|
+
// Handle arrays
|
|
48
|
+
if (Array.isArray(val)) {
|
|
49
|
+
const items = [];
|
|
50
|
+
const nextIndent = space ? indent + getIndentString(space) : '';
|
|
51
|
+
const separator = space ? '\n' : '';
|
|
52
|
+
for (let i = 0; i < val.length; i++) {
|
|
53
|
+
const item = stringify(val[i], nextIndent, currentDepth + 1);
|
|
54
|
+
items.push(space ? `${nextIndent}${item}` : item);
|
|
55
|
+
}
|
|
56
|
+
if (items.length === 0) {
|
|
57
|
+
return '[]';
|
|
58
|
+
}
|
|
59
|
+
return space
|
|
60
|
+
? `[${separator}${items.join(`,${separator}`)}${separator}${indent}]`
|
|
61
|
+
: `[${items.join(',')}]`;
|
|
62
|
+
}
|
|
63
|
+
// Handle objects
|
|
64
|
+
const keys = Object.keys(val).sort();
|
|
65
|
+
const pairs = [];
|
|
66
|
+
const nextIndent = space ? indent + getIndentString(space) : '';
|
|
67
|
+
const separator = space ? '\n' : '';
|
|
68
|
+
for (const key of keys) {
|
|
69
|
+
const value = val[key];
|
|
70
|
+
if (value !== undefined) {
|
|
71
|
+
const stringifiedKey = JSON.stringify(key);
|
|
72
|
+
const stringifiedValue = stringify(value, nextIndent, currentDepth + 1);
|
|
73
|
+
const pair = space
|
|
74
|
+
? `${nextIndent}${stringifiedKey}: ${stringifiedValue}`
|
|
75
|
+
: `${stringifiedKey}:${stringifiedValue}`;
|
|
76
|
+
pairs.push(pair);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (pairs.length === 0) {
|
|
80
|
+
return '{}';
|
|
81
|
+
}
|
|
82
|
+
return space
|
|
83
|
+
? `{${separator}${pairs.join(`,${separator}`)}${separator}${indent}}`
|
|
84
|
+
: `{${pairs.join(',')}}`;
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
seen.delete(val);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Fallback for unknown types
|
|
91
|
+
return 'null';
|
|
92
|
+
}
|
|
93
|
+
function getIndentString(space) {
|
|
94
|
+
if (typeof space === 'number') {
|
|
95
|
+
return ' '.repeat(Math.min(10, Math.max(0, Math.floor(space))));
|
|
96
|
+
}
|
|
97
|
+
return String(space).slice(0, 10);
|
|
98
|
+
}
|
|
99
|
+
return stringify(value, '', 0);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Parses a stable-stringified JSON string back into a value.
|
|
103
|
+
* This is just a wrapper around JSON.parse for consistency.
|
|
104
|
+
*
|
|
105
|
+
* @param text - The JSON string to parse
|
|
106
|
+
* @returns Parsed value
|
|
107
|
+
*/
|
|
108
|
+
export function stableParse(text) {
|
|
109
|
+
return JSON.parse(text);
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=stable-stringify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stable-stringify.js","sourceRoot":"","sources":["../../../src/policy/stable-stringify.ts"],"names":[],"mappings":"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"}
|