sovr-mcp-proxy 6.0.1 → 7.0.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/LICENSE +54 -19
- package/README.md +387 -164
- package/dist/cli.js +1553 -24
- package/dist/cli.mjs +185 -18
- package/dist/commandNormalizer.d.mts +95 -0
- package/dist/commandNormalizer.d.ts +95 -0
- package/dist/commandNormalizer.js +365 -0
- package/dist/commandNormalizer.mjs +336 -0
- package/dist/hooksAdapter.d.mts +122 -0
- package/dist/hooksAdapter.d.ts +122 -0
- package/dist/hooksAdapter.js +321 -0
- package/dist/hooksAdapter.mjs +291 -0
- package/dist/index.js +1065 -2
- package/dist/index.mjs +98 -2
- package/dist/toolReplacement.d.mts +108 -0
- package/dist/toolReplacement.d.ts +108 -0
- package/dist/toolReplacement.js +234 -0
- package/dist/toolReplacement.mjs +204 -0
- package/dist/whitelistEngine.d.mts +167 -0
- package/dist/whitelistEngine.d.ts +167 -0
- package/dist/whitelistEngine.js +435 -0
- package/dist/whitelistEngine.mjs +403 -0
- package/package.json +46 -41
- package/server.json +0 -14
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// src/toolReplacement.ts
|
|
2
|
+
var DEFAULT_TARGET_TOOLS = [
|
|
3
|
+
// Claude Code native tools
|
|
4
|
+
"Bash",
|
|
5
|
+
"bash",
|
|
6
|
+
"shell",
|
|
7
|
+
"execute_command",
|
|
8
|
+
"run_command",
|
|
9
|
+
"terminal",
|
|
10
|
+
// Cursor / Windsurf / Continue
|
|
11
|
+
"run_terminal_command",
|
|
12
|
+
"execute_shell",
|
|
13
|
+
"shell_exec",
|
|
14
|
+
// Generic patterns
|
|
15
|
+
"exec",
|
|
16
|
+
"system",
|
|
17
|
+
"subprocess"
|
|
18
|
+
];
|
|
19
|
+
var SOVR_EXEC_TOOL = {
|
|
20
|
+
name: "sovr_exec",
|
|
21
|
+
description: "Execute a shell command through the SOVR Responsibility Layer. All commands are evaluated against security policies before execution. Dangerous commands (rm -rf, DROP TABLE, etc.) will be blocked. This is the ONLY way to execute commands \u2014 use this for ALL shell operations.",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
command: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "The shell command to execute. Will be policy-checked before running."
|
|
28
|
+
},
|
|
29
|
+
workdir: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "Working directory for the command (optional)."
|
|
32
|
+
},
|
|
33
|
+
timeout: {
|
|
34
|
+
type: "number",
|
|
35
|
+
description: "Timeout in milliseconds (default: 300000 = 5 min)."
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
required: ["command"]
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var SOVR_STATUS_TOOL = {
|
|
42
|
+
name: "sovr_status",
|
|
43
|
+
description: "Check the current SOVR security status, including active policies, recent decisions, and system health. Use this to understand what commands are allowed or blocked.",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
verbose: {
|
|
48
|
+
type: "boolean",
|
|
49
|
+
description: "Include detailed policy information (default: false)."
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var SOVR_AUDIT_TOOL = {
|
|
55
|
+
name: "sovr_audit",
|
|
56
|
+
description: "View the SOVR audit log of recent command evaluations. Shows what was allowed, blocked, or escalated.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
limit: {
|
|
61
|
+
type: "number",
|
|
62
|
+
description: "Number of recent entries to show (default: 10)."
|
|
63
|
+
},
|
|
64
|
+
filter: {
|
|
65
|
+
type: "string",
|
|
66
|
+
enum: ["all", "allowed", "blocked", "escalated"],
|
|
67
|
+
description: "Filter by decision type (default: all)."
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var DEFAULT_TOOL_REPLACEMENT_CONFIG = {
|
|
73
|
+
mode: "enforce",
|
|
74
|
+
targetTools: DEFAULT_TARGET_TOOLS,
|
|
75
|
+
addStatusTool: true,
|
|
76
|
+
addAuditTool: true
|
|
77
|
+
};
|
|
78
|
+
function transformToolList(upstreamTools, config) {
|
|
79
|
+
const removedTools = [];
|
|
80
|
+
const addedTools = [];
|
|
81
|
+
const wrappedTools = [];
|
|
82
|
+
let resultTools = [];
|
|
83
|
+
switch (config.mode) {
|
|
84
|
+
case "exclusive": {
|
|
85
|
+
for (const tool of upstreamTools) {
|
|
86
|
+
if (isTargetTool(tool.name, config.targetTools)) {
|
|
87
|
+
removedTools.push(tool.name);
|
|
88
|
+
} else {
|
|
89
|
+
resultTools.push(tool);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
resultTools.push(SOVR_EXEC_TOOL);
|
|
93
|
+
addedTools.push(SOVR_EXEC_TOOL.name);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case "enforce": {
|
|
97
|
+
for (const tool of upstreamTools) {
|
|
98
|
+
if (isTargetTool(tool.name, config.targetTools)) {
|
|
99
|
+
resultTools.push({
|
|
100
|
+
...tool,
|
|
101
|
+
description: `[SOVR-ENFORCED] ${tool.description || ""} \u2014 All calls are policy-checked by SOVR before execution.`
|
|
102
|
+
});
|
|
103
|
+
wrappedTools.push(tool.name);
|
|
104
|
+
} else {
|
|
105
|
+
resultTools.push(tool);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
resultTools.push(SOVR_EXEC_TOOL);
|
|
109
|
+
addedTools.push(SOVR_EXEC_TOOL.name);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case "advisory": {
|
|
113
|
+
resultTools = [...upstreamTools];
|
|
114
|
+
resultTools.push(SOVR_EXEC_TOOL);
|
|
115
|
+
addedTools.push(SOVR_EXEC_TOOL.name);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
case "monitor":
|
|
119
|
+
default: {
|
|
120
|
+
resultTools = [...upstreamTools];
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (config.addStatusTool) {
|
|
125
|
+
resultTools.push(SOVR_STATUS_TOOL);
|
|
126
|
+
addedTools.push(SOVR_STATUS_TOOL.name);
|
|
127
|
+
}
|
|
128
|
+
if (config.addAuditTool) {
|
|
129
|
+
resultTools.push(SOVR_AUDIT_TOOL);
|
|
130
|
+
addedTools.push(SOVR_AUDIT_TOOL.name);
|
|
131
|
+
}
|
|
132
|
+
return { tools: resultTools, removedTools, addedTools, wrappedTools };
|
|
133
|
+
}
|
|
134
|
+
function isTargetTool(toolName, targets) {
|
|
135
|
+
const lowerName = toolName.toLowerCase();
|
|
136
|
+
return targets.some((target) => {
|
|
137
|
+
const lowerTarget = target.toLowerCase();
|
|
138
|
+
if (lowerName === lowerTarget) return true;
|
|
139
|
+
if (lowerTarget.includes("*")) {
|
|
140
|
+
const regex = new RegExp(
|
|
141
|
+
"^" + lowerTarget.replace(/\*/g, ".*").replace(/\?/g, ".") + "$"
|
|
142
|
+
);
|
|
143
|
+
return regex.test(lowerName);
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function shouldIntercept(toolName, config) {
|
|
149
|
+
switch (config.mode) {
|
|
150
|
+
case "exclusive":
|
|
151
|
+
if (toolName === "sovr_exec") {
|
|
152
|
+
return { intercept: true, reason: "exclusive-mode: all exec calls routed through SOVR" };
|
|
153
|
+
}
|
|
154
|
+
if (isTargetTool(toolName, config.targetTools)) {
|
|
155
|
+
return { intercept: true, reason: "exclusive-mode: native tool blocked, use sovr_exec" };
|
|
156
|
+
}
|
|
157
|
+
return { intercept: false, reason: "non-exec tool, passthrough" };
|
|
158
|
+
case "enforce":
|
|
159
|
+
if (toolName === "sovr_exec" || isTargetTool(toolName, config.targetTools)) {
|
|
160
|
+
return { intercept: true, reason: "enforce-mode: policy check required" };
|
|
161
|
+
}
|
|
162
|
+
return { intercept: false, reason: "non-exec tool, passthrough" };
|
|
163
|
+
case "advisory":
|
|
164
|
+
if (toolName === "sovr_exec") {
|
|
165
|
+
return { intercept: true, reason: "advisory-mode: SOVR exec call" };
|
|
166
|
+
}
|
|
167
|
+
if (isTargetTool(toolName, config.targetTools)) {
|
|
168
|
+
return { intercept: false, reason: "advisory-mode: native tool allowed with warning" };
|
|
169
|
+
}
|
|
170
|
+
return { intercept: false, reason: "non-exec tool, passthrough" };
|
|
171
|
+
case "monitor":
|
|
172
|
+
default:
|
|
173
|
+
return { intercept: false, reason: "monitor-mode: all tools passthrough" };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function describeMode(config) {
|
|
177
|
+
switch (config.mode) {
|
|
178
|
+
case "exclusive":
|
|
179
|
+
return `EXCLUSIVE MODE: Native execution tools (${config.targetTools.join(", ")}) are REMOVED. The LLM can ONLY execute commands through sovr_exec. Bypass is impossible.`;
|
|
180
|
+
case "enforce":
|
|
181
|
+
return `ENFORCE MODE: Native execution tools are wrapped with SOVR policy checks. All command executions are evaluated before running. Dangerous commands are blocked.`;
|
|
182
|
+
case "advisory":
|
|
183
|
+
return `ADVISORY MODE: Native tools remain available. SOVR tools are added alongside. Warnings are logged for risky commands but execution is not blocked.`;
|
|
184
|
+
case "monitor":
|
|
185
|
+
return `MONITOR MODE: All tools pass through unchanged. SOVR only logs activity. No enforcement or blocking.`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function parseMode(input) {
|
|
189
|
+
const normalized = input.toLowerCase().trim();
|
|
190
|
+
if (["exclusive", "enforce", "advisory", "monitor"].includes(normalized)) {
|
|
191
|
+
return normalized;
|
|
192
|
+
}
|
|
193
|
+
throw new Error(
|
|
194
|
+
`Invalid mode: "${input}". Valid modes: exclusive, enforce, advisory, monitor`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
export {
|
|
198
|
+
DEFAULT_TARGET_TOOLS,
|
|
199
|
+
DEFAULT_TOOL_REPLACEMENT_CONFIG,
|
|
200
|
+
describeMode,
|
|
201
|
+
parseMode,
|
|
202
|
+
shouldIntercept,
|
|
203
|
+
transformToolList
|
|
204
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sovr/proxy-mcp — Whitelist Policy Engine
|
|
3
|
+
*
|
|
4
|
+
* Solves the critical Reddit feedback:
|
|
5
|
+
* "A whitelist is much safer than a blacklist" — rvistro (9↑)
|
|
6
|
+
* "If you ban that, I can just spin up a shell with -c" — coloradical5280 (2↑)
|
|
7
|
+
*
|
|
8
|
+
* Philosophy: DEFAULT DENY.
|
|
9
|
+
* Instead of trying to enumerate every dangerous command (impossible),
|
|
10
|
+
* we enumerate the SAFE commands and block everything else.
|
|
11
|
+
*
|
|
12
|
+
* The whitelist is project-scoped: each project declares what commands
|
|
13
|
+
* its AI agent needs, and SOVR enforces that boundary.
|
|
14
|
+
*
|
|
15
|
+
* Three policy modes:
|
|
16
|
+
* - "whitelist" — Only explicitly allowed commands can execute (recommended)
|
|
17
|
+
* - "blacklist" — Legacy mode, block known-dangerous patterns
|
|
18
|
+
* - "hybrid" — Whitelist + blacklist (whitelist takes priority)
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```yaml
|
|
22
|
+
* # .sovr/policy.yaml
|
|
23
|
+
* version: "1.0"
|
|
24
|
+
* mode: whitelist
|
|
25
|
+
* rules:
|
|
26
|
+
* - pattern: "ls *"
|
|
27
|
+
* allow: true
|
|
28
|
+
* description: "List directory contents"
|
|
29
|
+
* - pattern: "cat *"
|
|
30
|
+
* allow: true
|
|
31
|
+
* description: "Read file contents"
|
|
32
|
+
* - pattern: "npm run *"
|
|
33
|
+
* allow: true
|
|
34
|
+
* description: "Run npm scripts"
|
|
35
|
+
* - pattern: "git status"
|
|
36
|
+
* allow: true
|
|
37
|
+
* - pattern: "git add *"
|
|
38
|
+
* allow: true
|
|
39
|
+
* - pattern: "git commit *"
|
|
40
|
+
* allow: true
|
|
41
|
+
* - pattern: "git push *"
|
|
42
|
+
* allow: true
|
|
43
|
+
* require_approval: true # Human must approve pushes
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
type PolicyMode = 'whitelist' | 'blacklist' | 'hybrid';
|
|
47
|
+
/** A single whitelist/blacklist rule */
|
|
48
|
+
interface WhitelistRule {
|
|
49
|
+
/** Glob-style pattern for the command (e.g., "ls *", "npm run *") */
|
|
50
|
+
pattern: string;
|
|
51
|
+
/** Whether this pattern is allowed (true) or blocked (false) */
|
|
52
|
+
allow: boolean;
|
|
53
|
+
/** Human-readable description */
|
|
54
|
+
description?: string;
|
|
55
|
+
/** Whether this command requires human approval even if allowed */
|
|
56
|
+
require_approval?: boolean;
|
|
57
|
+
/** Maximum arguments allowed (prevents injection via long args) */
|
|
58
|
+
max_args?: number;
|
|
59
|
+
/** Allowed working directories (glob patterns) */
|
|
60
|
+
allowed_dirs?: string[];
|
|
61
|
+
/** Priority (higher = evaluated first, default: 0) */
|
|
62
|
+
priority?: number;
|
|
63
|
+
/** Whether this rule is enabled */
|
|
64
|
+
enabled?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** Complete policy configuration */
|
|
67
|
+
interface WhitelistPolicy {
|
|
68
|
+
/** Policy version */
|
|
69
|
+
version: string;
|
|
70
|
+
/** Policy mode */
|
|
71
|
+
mode: PolicyMode;
|
|
72
|
+
/** Policy rules */
|
|
73
|
+
rules: WhitelistRule[];
|
|
74
|
+
/** Default action when no rule matches (only for hybrid mode) */
|
|
75
|
+
default_action?: 'allow' | 'deny' | 'escalate';
|
|
76
|
+
/** Global settings */
|
|
77
|
+
settings?: {
|
|
78
|
+
/** Maximum command length in characters */
|
|
79
|
+
max_command_length?: number;
|
|
80
|
+
/** Whether to allow environment variable expansion */
|
|
81
|
+
allow_env_expansion?: boolean;
|
|
82
|
+
/** Whether to allow subshell execution ($(cmd) or `cmd`) */
|
|
83
|
+
allow_subshell?: boolean;
|
|
84
|
+
/** Whether to allow pipe chains */
|
|
85
|
+
allow_pipes?: boolean;
|
|
86
|
+
/** Whether to allow command chaining (&&, ||, ;) */
|
|
87
|
+
allow_chains?: boolean;
|
|
88
|
+
/** Whether to allow output redirection (>, >>) */
|
|
89
|
+
allow_redirects?: boolean;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Result of whitelist evaluation */
|
|
93
|
+
interface WhitelistEvalResult {
|
|
94
|
+
/** Whether the command is allowed */
|
|
95
|
+
allowed: boolean;
|
|
96
|
+
/** Whether human approval is required */
|
|
97
|
+
require_approval: boolean;
|
|
98
|
+
/** The matching rule (if any) */
|
|
99
|
+
matched_rule?: WhitelistRule;
|
|
100
|
+
/** Reason for the decision */
|
|
101
|
+
reason: string;
|
|
102
|
+
/** Risk level */
|
|
103
|
+
risk: 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
104
|
+
/** Structural violations detected */
|
|
105
|
+
violations: string[];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Minimal whitelist for read-only operations.
|
|
109
|
+
* Suitable for AI agents that should only read, not write.
|
|
110
|
+
*/
|
|
111
|
+
declare const PRESET_READONLY: WhitelistPolicy;
|
|
112
|
+
/**
|
|
113
|
+
* Developer whitelist for coding agents.
|
|
114
|
+
* Allows common dev operations but blocks destructive ones.
|
|
115
|
+
*/
|
|
116
|
+
declare const PRESET_DEVELOPER: WhitelistPolicy;
|
|
117
|
+
/**
|
|
118
|
+
* Strict whitelist for production environments.
|
|
119
|
+
* Only allows pre-defined deployment commands.
|
|
120
|
+
*/
|
|
121
|
+
declare const PRESET_PRODUCTION: WhitelistPolicy;
|
|
122
|
+
/** Map of preset names to policies */
|
|
123
|
+
declare const PRESETS: Record<string, WhitelistPolicy>;
|
|
124
|
+
declare class WhitelistEngine {
|
|
125
|
+
private policy;
|
|
126
|
+
constructor(policy: WhitelistPolicy);
|
|
127
|
+
/**
|
|
128
|
+
* Evaluate a command against the whitelist policy.
|
|
129
|
+
*/
|
|
130
|
+
evaluate(command: string): WhitelistEvalResult;
|
|
131
|
+
/**
|
|
132
|
+
* Check structural constraints (pipes, chains, subshells, etc.)
|
|
133
|
+
*/
|
|
134
|
+
private checkStructural;
|
|
135
|
+
/**
|
|
136
|
+
* Get the current policy.
|
|
137
|
+
*/
|
|
138
|
+
getPolicy(): WhitelistPolicy;
|
|
139
|
+
/**
|
|
140
|
+
* Add a rule dynamically.
|
|
141
|
+
*/
|
|
142
|
+
addRule(rule: WhitelistRule): void;
|
|
143
|
+
/**
|
|
144
|
+
* Remove a rule by pattern.
|
|
145
|
+
*/
|
|
146
|
+
removeRule(pattern: string): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* List all rules.
|
|
149
|
+
*/
|
|
150
|
+
listRules(): WhitelistRule[];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Load a whitelist policy from a YAML-like file.
|
|
154
|
+
* Supports simplified YAML format (JSON subset).
|
|
155
|
+
*/
|
|
156
|
+
declare function loadPolicy(filePath: string): WhitelistPolicy;
|
|
157
|
+
/**
|
|
158
|
+
* Auto-detect and load policy from project directory.
|
|
159
|
+
* Looks for .sovr/policy.json or .sovr/policy.yaml
|
|
160
|
+
*/
|
|
161
|
+
declare function autoLoadPolicy(projectDir: string): WhitelistPolicy | null;
|
|
162
|
+
/**
|
|
163
|
+
* Generate a sample policy file for a given preset.
|
|
164
|
+
*/
|
|
165
|
+
declare function generatePolicyFile(preset: string, format?: 'json' | 'yaml'): string;
|
|
166
|
+
|
|
167
|
+
export { PRESETS, PRESET_DEVELOPER, PRESET_PRODUCTION, PRESET_READONLY, type PolicyMode, WhitelistEngine, type WhitelistEvalResult, type WhitelistPolicy, type WhitelistRule, autoLoadPolicy, generatePolicyFile, loadPolicy };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sovr/proxy-mcp — Whitelist Policy Engine
|
|
3
|
+
*
|
|
4
|
+
* Solves the critical Reddit feedback:
|
|
5
|
+
* "A whitelist is much safer than a blacklist" — rvistro (9↑)
|
|
6
|
+
* "If you ban that, I can just spin up a shell with -c" — coloradical5280 (2↑)
|
|
7
|
+
*
|
|
8
|
+
* Philosophy: DEFAULT DENY.
|
|
9
|
+
* Instead of trying to enumerate every dangerous command (impossible),
|
|
10
|
+
* we enumerate the SAFE commands and block everything else.
|
|
11
|
+
*
|
|
12
|
+
* The whitelist is project-scoped: each project declares what commands
|
|
13
|
+
* its AI agent needs, and SOVR enforces that boundary.
|
|
14
|
+
*
|
|
15
|
+
* Three policy modes:
|
|
16
|
+
* - "whitelist" — Only explicitly allowed commands can execute (recommended)
|
|
17
|
+
* - "blacklist" — Legacy mode, block known-dangerous patterns
|
|
18
|
+
* - "hybrid" — Whitelist + blacklist (whitelist takes priority)
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```yaml
|
|
22
|
+
* # .sovr/policy.yaml
|
|
23
|
+
* version: "1.0"
|
|
24
|
+
* mode: whitelist
|
|
25
|
+
* rules:
|
|
26
|
+
* - pattern: "ls *"
|
|
27
|
+
* allow: true
|
|
28
|
+
* description: "List directory contents"
|
|
29
|
+
* - pattern: "cat *"
|
|
30
|
+
* allow: true
|
|
31
|
+
* description: "Read file contents"
|
|
32
|
+
* - pattern: "npm run *"
|
|
33
|
+
* allow: true
|
|
34
|
+
* description: "Run npm scripts"
|
|
35
|
+
* - pattern: "git status"
|
|
36
|
+
* allow: true
|
|
37
|
+
* - pattern: "git add *"
|
|
38
|
+
* allow: true
|
|
39
|
+
* - pattern: "git commit *"
|
|
40
|
+
* allow: true
|
|
41
|
+
* - pattern: "git push *"
|
|
42
|
+
* allow: true
|
|
43
|
+
* require_approval: true # Human must approve pushes
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
type PolicyMode = 'whitelist' | 'blacklist' | 'hybrid';
|
|
47
|
+
/** A single whitelist/blacklist rule */
|
|
48
|
+
interface WhitelistRule {
|
|
49
|
+
/** Glob-style pattern for the command (e.g., "ls *", "npm run *") */
|
|
50
|
+
pattern: string;
|
|
51
|
+
/** Whether this pattern is allowed (true) or blocked (false) */
|
|
52
|
+
allow: boolean;
|
|
53
|
+
/** Human-readable description */
|
|
54
|
+
description?: string;
|
|
55
|
+
/** Whether this command requires human approval even if allowed */
|
|
56
|
+
require_approval?: boolean;
|
|
57
|
+
/** Maximum arguments allowed (prevents injection via long args) */
|
|
58
|
+
max_args?: number;
|
|
59
|
+
/** Allowed working directories (glob patterns) */
|
|
60
|
+
allowed_dirs?: string[];
|
|
61
|
+
/** Priority (higher = evaluated first, default: 0) */
|
|
62
|
+
priority?: number;
|
|
63
|
+
/** Whether this rule is enabled */
|
|
64
|
+
enabled?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** Complete policy configuration */
|
|
67
|
+
interface WhitelistPolicy {
|
|
68
|
+
/** Policy version */
|
|
69
|
+
version: string;
|
|
70
|
+
/** Policy mode */
|
|
71
|
+
mode: PolicyMode;
|
|
72
|
+
/** Policy rules */
|
|
73
|
+
rules: WhitelistRule[];
|
|
74
|
+
/** Default action when no rule matches (only for hybrid mode) */
|
|
75
|
+
default_action?: 'allow' | 'deny' | 'escalate';
|
|
76
|
+
/** Global settings */
|
|
77
|
+
settings?: {
|
|
78
|
+
/** Maximum command length in characters */
|
|
79
|
+
max_command_length?: number;
|
|
80
|
+
/** Whether to allow environment variable expansion */
|
|
81
|
+
allow_env_expansion?: boolean;
|
|
82
|
+
/** Whether to allow subshell execution ($(cmd) or `cmd`) */
|
|
83
|
+
allow_subshell?: boolean;
|
|
84
|
+
/** Whether to allow pipe chains */
|
|
85
|
+
allow_pipes?: boolean;
|
|
86
|
+
/** Whether to allow command chaining (&&, ||, ;) */
|
|
87
|
+
allow_chains?: boolean;
|
|
88
|
+
/** Whether to allow output redirection (>, >>) */
|
|
89
|
+
allow_redirects?: boolean;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Result of whitelist evaluation */
|
|
93
|
+
interface WhitelistEvalResult {
|
|
94
|
+
/** Whether the command is allowed */
|
|
95
|
+
allowed: boolean;
|
|
96
|
+
/** Whether human approval is required */
|
|
97
|
+
require_approval: boolean;
|
|
98
|
+
/** The matching rule (if any) */
|
|
99
|
+
matched_rule?: WhitelistRule;
|
|
100
|
+
/** Reason for the decision */
|
|
101
|
+
reason: string;
|
|
102
|
+
/** Risk level */
|
|
103
|
+
risk: 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
104
|
+
/** Structural violations detected */
|
|
105
|
+
violations: string[];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Minimal whitelist for read-only operations.
|
|
109
|
+
* Suitable for AI agents that should only read, not write.
|
|
110
|
+
*/
|
|
111
|
+
declare const PRESET_READONLY: WhitelistPolicy;
|
|
112
|
+
/**
|
|
113
|
+
* Developer whitelist for coding agents.
|
|
114
|
+
* Allows common dev operations but blocks destructive ones.
|
|
115
|
+
*/
|
|
116
|
+
declare const PRESET_DEVELOPER: WhitelistPolicy;
|
|
117
|
+
/**
|
|
118
|
+
* Strict whitelist for production environments.
|
|
119
|
+
* Only allows pre-defined deployment commands.
|
|
120
|
+
*/
|
|
121
|
+
declare const PRESET_PRODUCTION: WhitelistPolicy;
|
|
122
|
+
/** Map of preset names to policies */
|
|
123
|
+
declare const PRESETS: Record<string, WhitelistPolicy>;
|
|
124
|
+
declare class WhitelistEngine {
|
|
125
|
+
private policy;
|
|
126
|
+
constructor(policy: WhitelistPolicy);
|
|
127
|
+
/**
|
|
128
|
+
* Evaluate a command against the whitelist policy.
|
|
129
|
+
*/
|
|
130
|
+
evaluate(command: string): WhitelistEvalResult;
|
|
131
|
+
/**
|
|
132
|
+
* Check structural constraints (pipes, chains, subshells, etc.)
|
|
133
|
+
*/
|
|
134
|
+
private checkStructural;
|
|
135
|
+
/**
|
|
136
|
+
* Get the current policy.
|
|
137
|
+
*/
|
|
138
|
+
getPolicy(): WhitelistPolicy;
|
|
139
|
+
/**
|
|
140
|
+
* Add a rule dynamically.
|
|
141
|
+
*/
|
|
142
|
+
addRule(rule: WhitelistRule): void;
|
|
143
|
+
/**
|
|
144
|
+
* Remove a rule by pattern.
|
|
145
|
+
*/
|
|
146
|
+
removeRule(pattern: string): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* List all rules.
|
|
149
|
+
*/
|
|
150
|
+
listRules(): WhitelistRule[];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Load a whitelist policy from a YAML-like file.
|
|
154
|
+
* Supports simplified YAML format (JSON subset).
|
|
155
|
+
*/
|
|
156
|
+
declare function loadPolicy(filePath: string): WhitelistPolicy;
|
|
157
|
+
/**
|
|
158
|
+
* Auto-detect and load policy from project directory.
|
|
159
|
+
* Looks for .sovr/policy.json or .sovr/policy.yaml
|
|
160
|
+
*/
|
|
161
|
+
declare function autoLoadPolicy(projectDir: string): WhitelistPolicy | null;
|
|
162
|
+
/**
|
|
163
|
+
* Generate a sample policy file for a given preset.
|
|
164
|
+
*/
|
|
165
|
+
declare function generatePolicyFile(preset: string, format?: 'json' | 'yaml'): string;
|
|
166
|
+
|
|
167
|
+
export { PRESETS, PRESET_DEVELOPER, PRESET_PRODUCTION, PRESET_READONLY, type PolicyMode, WhitelistEngine, type WhitelistEvalResult, type WhitelistPolicy, type WhitelistRule, autoLoadPolicy, generatePolicyFile, loadPolicy };
|