@solongate/proxy 0.35.0 → 0.37.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/dist/index.js CHANGED
@@ -536,7 +536,7 @@ function isAlreadyProtected(server) {
536
536
  }
537
537
  return false;
538
538
  }
539
- function wrapServer(serverName, server, policy, agentName, aiJudge) {
539
+ function wrapServer(serverName, server, policy, agentName) {
540
540
  const env = { ...server.env ?? {} };
541
541
  env.SOLONGATE_API_KEY = "${SOLONGATE_API_KEY}";
542
542
  const proxyArgs = ["-y", "@solongate/proxy@latest"];
@@ -546,9 +546,6 @@ function wrapServer(serverName, server, policy, agentName, aiJudge) {
546
546
  if (agentName) {
547
547
  proxyArgs.push("--agent-name", agentName);
548
548
  }
549
- if (aiJudge) {
550
- proxyArgs.push("--ai-judge");
551
- }
552
549
  proxyArgs.push("--verbose", "--", server.command, ...server.args ?? []);
553
550
  return {
554
551
  command: "npx",
@@ -569,8 +566,7 @@ function parseInitArgs(argv) {
569
566
  const args = argv.slice(2);
570
567
  const options = {
571
568
  all: false,
572
- tools: [],
573
- aiJudge: false
569
+ tools: []
574
570
  };
575
571
  for (let i = 0; i < args.length; i++) {
576
572
  switch (args[i]) {
@@ -595,9 +591,6 @@ function parseInitArgs(argv) {
595
591
  case "--openclaw":
596
592
  options.tools.push("openclaw");
597
593
  break;
598
- case "--ai-judge":
599
- options.aiJudge = true;
600
- break;
601
594
  case "--help":
602
595
  case "-h":
603
596
  printHelp();
@@ -625,13 +618,8 @@ AI TOOL HOOKS (default: all)
625
618
  --gemini Install hooks for Gemini CLI
626
619
  --openclaw Install hooks for OpenClaw
627
620
 
628
- SECURITY LAYERS
629
- --ai-judge Enable AI Judge (semantic intent analysis via LLM)
630
- Requires GROQ_API_KEY in .env (free at https://console.groq.com/keys)
631
-
632
621
  EXAMPLES
633
622
  npx @solongate/proxy init --all # Protect everything, all tools
634
- npx @solongate/proxy init --all --ai-judge # With AI Judge enabled
635
623
  npx @solongate/proxy init --all --claude-code --gemini # Only Claude Code + Gemini hooks
636
624
  npx @solongate/proxy init --all --policy policy.json # With custom policy
637
625
  `;
@@ -1061,7 +1049,7 @@ async function main() {
1061
1049
  const newConfig = { mcpServers: {} };
1062
1050
  for (const name of serverNames) {
1063
1051
  if (toProtect.includes(name)) {
1064
- newConfig.mcpServers[name] = wrapServer(name, config.mcpServers[name], policyValue, void 0, options.aiJudge);
1052
+ newConfig.mcpServers[name] = wrapServer(name, config.mcpServers[name], policyValue);
1065
1053
  } else {
1066
1054
  newConfig.mcpServers[name] = config.mcpServers[name];
1067
1055
  }
@@ -5652,39 +5640,34 @@ var PolicySyncManager = class {
5652
5640
  };
5653
5641
 
5654
5642
  // src/ai-judge.ts
5655
- var SYSTEM_PROMPT = `You are a security judge for an AI coding tool. You evaluate tool calls and decide if they should be ALLOWED or DENIED.
5643
+ var SYSTEM_PROMPT = `You are a security judge for an AI coding tool. Your ONLY job is to check if a tool call accesses files or paths that are in the protected lists. Nothing else.
5656
5644
 
5657
5645
  You will receive a JSON object with:
5658
5646
  - "tool": the tool name being called
5659
5647
  - "arguments": the tool's arguments
5660
- - "protected_files": EXACT list of files that must NEVER be accessed. ONLY these specific files are protected \u2014 nothing else.
5661
- - "protected_paths": EXACT list of directories that must NEVER be accessed. ONLY these specific paths are protected \u2014 nothing else.
5662
- - "denied_actions": list of actions that are never allowed
5663
-
5664
- IMPORTANT: You must ONLY protect files and paths that are EXPLICITLY listed in protected_files and protected_paths. If a file is NOT in the list, it is NOT protected and access should be ALLOWED. Do NOT invent or assume additional protected files.
5665
-
5666
- DENY if the tool call could, directly or indirectly, access a file from the protected_files list \u2014 even through:
5667
- - Shell glob patterns (e.g., "cred*" could match "credentials.json" IF credentials.json is in protected_files)
5668
- - Command substitution ($(...), backticks)
5669
- - Process substitution (<(cat file)) \u2014 check inside <(...) for protected files
5670
- - Variable interpolation (e.g., f=".en"; cat \${f}v builds ".env" \u2014 DENY only if .env is in protected_files)
5671
- - Input redirection (< file)
5672
- - Multi-stage operations: tar/cp a protected file then read the copy \u2014 DENY the entire chain
5673
- - Any utility that reads file content (cat, head, tail, less, perl, awk, sed, xxd, od, strings, dd, etc.)
5648
+ - "protected_files": the EXACT and COMPLETE list of protected files from the user's policy
5649
+ - "protected_paths": the EXACT and COMPLETE list of protected directories from the user's policy
5674
5650
 
5675
- Also DENY if:
5676
- - The command sends data to external URLs (curl -d, wget --post)
5677
- - The command leaks environment variables (printenv, env, process.env)
5678
- - The command executes remotely downloaded code (curl|bash)
5651
+ RULES:
5652
+ 1. DENY ONLY if the tool call could access a file or path that is in protected_files or protected_paths.
5653
+ 2. ALLOW everything else. You must NOT invent your own security rules.
5654
+ 3. If a file is NOT in protected_files, it is NOT protected \u2014 even if the filename looks sensitive.
5655
+ 4. "cat test.txt" is ALLOWED if test.txt is not in protected_files.
5656
+ 5. "curl https://example.com" is ALLOWED unless it sends protected file content.
5657
+ 6. "printenv" is ALLOWED unless the policy explicitly protects it.
5679
5658
 
5680
- ALLOW if:
5681
- - The file is NOT in protected_files \u2014 even if cat, head, etc. is used. Reading non-protected files is normal.
5682
- - The action is a normal development operation (ls, git status, npm build, cat app.js, etc.)
5683
- - The action does not touch any protected file or path
5659
+ BYPASS DETECTION \u2014 DENY if the command accesses a protected file through:
5660
+ - Shell glob patterns: "cat cred*" could match "credentials.json" IF it is in protected_files
5661
+ - Command substitution: "cat $(echo .env)" builds ".env"
5662
+ - Variable interpolation: f=".en"; cat \${f}v builds ".env"
5663
+ - Process substitution: <(cat .env)
5664
+ - Multi-stage: cp protected_file /tmp/x && cat /tmp/x
5665
+ - Input redirection: < .env
5666
+ - Any file-reading utility (cat, head, tail, less, perl, awk, sed, xxd, etc.)
5684
5667
 
5685
- CRITICAL: Only DENY access to files EXPLICITLY in the protected_files list. "cat app.js" is ALLOWED if app.js is not in protected_files. Do NOT over-block.
5668
+ CRITICAL: You have NO security opinions of your own. You ONLY enforce the protected_files and protected_paths lists. If something is not in those lists, it is ALLOWED. Do NOT over-block.
5686
5669
 
5687
- Respond with ONLY valid JSON, no markdown, no explanation outside the JSON:
5670
+ Respond with ONLY valid JSON:
5688
5671
  {"decision": "ALLOW" or "DENY", "reason": "brief one-line explanation", "confidence": 0.0 to 1.0}`;
5689
5672
  var AuthError = class extends Error {
5690
5673
  constructor(message) {
@@ -5696,24 +5679,16 @@ var AiJudge = class _AiJudge {
5696
5679
  config;
5697
5680
  protectedFiles;
5698
5681
  protectedPaths;
5699
- deniedActions;
5700
5682
  isOllamaEndpoint;
5701
5683
  // Circuit breaker: after 3 consecutive failures in 60s, skip AI Judge
5702
5684
  consecutiveFailures = 0;
5703
5685
  lastFailureTime = 0;
5704
5686
  static CIRCUIT_BREAKER_THRESHOLD = 3;
5705
5687
  static CIRCUIT_BREAKER_RESET_MS = 6e4;
5706
- constructor(config, protectedFiles, protectedPaths, deniedActions = [
5707
- "file deletion",
5708
- "data exfiltration",
5709
- "remote code execution",
5710
- "environment variable leak",
5711
- "security control bypass"
5712
- ]) {
5688
+ constructor(config, protectedFiles, protectedPaths) {
5713
5689
  this.config = config;
5714
5690
  this.protectedFiles = protectedFiles;
5715
5691
  this.protectedPaths = protectedPaths;
5716
- this.deniedActions = deniedActions;
5717
5692
  this.isOllamaEndpoint = config.endpoint.includes("11434") || config.endpoint.includes("ollama");
5718
5693
  }
5719
5694
  /**
@@ -5737,8 +5712,7 @@ var AiJudge = class _AiJudge {
5737
5712
  tool: toolName,
5738
5713
  arguments: sanitizedArgs,
5739
5714
  protected_files: this.protectedFiles,
5740
- protected_paths: this.protectedPaths,
5741
- denied_actions: this.deniedActions
5715
+ protected_paths: this.protectedPaths
5742
5716
  });
5743
5717
  try {
5744
5718
  const response = await this.callLLM(userMessage);
package/dist/init.js CHANGED
@@ -117,7 +117,7 @@ function isAlreadyProtected(server) {
117
117
  }
118
118
  return false;
119
119
  }
120
- function wrapServer(serverName, server, policy, agentName, aiJudge) {
120
+ function wrapServer(serverName, server, policy, agentName) {
121
121
  const env = { ...server.env ?? {} };
122
122
  env.SOLONGATE_API_KEY = "${SOLONGATE_API_KEY}";
123
123
  const proxyArgs = ["-y", "@solongate/proxy@latest"];
@@ -127,9 +127,6 @@ function wrapServer(serverName, server, policy, agentName, aiJudge) {
127
127
  if (agentName) {
128
128
  proxyArgs.push("--agent-name", agentName);
129
129
  }
130
- if (aiJudge) {
131
- proxyArgs.push("--ai-judge");
132
- }
133
130
  proxyArgs.push("--verbose", "--", server.command, ...server.args ?? []);
134
131
  return {
135
132
  command: "npx",
@@ -150,8 +147,7 @@ function parseInitArgs(argv) {
150
147
  const args = argv.slice(2);
151
148
  const options = {
152
149
  all: false,
153
- tools: [],
154
- aiJudge: false
150
+ tools: []
155
151
  };
156
152
  for (let i = 0; i < args.length; i++) {
157
153
  switch (args[i]) {
@@ -176,9 +172,6 @@ function parseInitArgs(argv) {
176
172
  case "--openclaw":
177
173
  options.tools.push("openclaw");
178
174
  break;
179
- case "--ai-judge":
180
- options.aiJudge = true;
181
- break;
182
175
  case "--help":
183
176
  case "-h":
184
177
  printHelp();
@@ -206,13 +199,8 @@ AI TOOL HOOKS (default: all)
206
199
  --gemini Install hooks for Gemini CLI
207
200
  --openclaw Install hooks for OpenClaw
208
201
 
209
- SECURITY LAYERS
210
- --ai-judge Enable AI Judge (semantic intent analysis via LLM)
211
- Requires GROQ_API_KEY in .env (free at https://console.groq.com/keys)
212
-
213
202
  EXAMPLES
214
203
  npx @solongate/proxy init --all # Protect everything, all tools
215
- npx @solongate/proxy init --all --ai-judge # With AI Judge enabled
216
204
  npx @solongate/proxy init --all --claude-code --gemini # Only Claude Code + Gemini hooks
217
205
  npx @solongate/proxy init --all --policy policy.json # With custom policy
218
206
  `;
@@ -644,7 +632,7 @@ async function main() {
644
632
  const newConfig = { mcpServers: {} };
645
633
  for (const name of serverNames) {
646
634
  if (toProtect.includes(name)) {
647
- newConfig.mcpServers[name] = wrapServer(name, config.mcpServers[name], policyValue, void 0, options.aiJudge);
635
+ newConfig.mcpServers[name] = wrapServer(name, config.mcpServers[name], policyValue);
648
636
  } else {
649
637
  newConfig.mcpServers[name] = config.mcpServers[name];
650
638
  }
package/dist/lib.js CHANGED
@@ -3939,39 +3939,34 @@ var PolicySyncManager = class {
3939
3939
  };
3940
3940
 
3941
3941
  // src/ai-judge.ts
3942
- var SYSTEM_PROMPT = `You are a security judge for an AI coding tool. You evaluate tool calls and decide if they should be ALLOWED or DENIED.
3942
+ var SYSTEM_PROMPT = `You are a security judge for an AI coding tool. Your ONLY job is to check if a tool call accesses files or paths that are in the protected lists. Nothing else.
3943
3943
 
3944
3944
  You will receive a JSON object with:
3945
3945
  - "tool": the tool name being called
3946
3946
  - "arguments": the tool's arguments
3947
- - "protected_files": EXACT list of files that must NEVER be accessed. ONLY these specific files are protected \u2014 nothing else.
3948
- - "protected_paths": EXACT list of directories that must NEVER be accessed. ONLY these specific paths are protected \u2014 nothing else.
3949
- - "denied_actions": list of actions that are never allowed
3947
+ - "protected_files": the EXACT and COMPLETE list of protected files from the user's policy
3948
+ - "protected_paths": the EXACT and COMPLETE list of protected directories from the user's policy
3950
3949
 
3951
- IMPORTANT: You must ONLY protect files and paths that are EXPLICITLY listed in protected_files and protected_paths. If a file is NOT in the list, it is NOT protected and access should be ALLOWED. Do NOT invent or assume additional protected files.
3950
+ RULES:
3951
+ 1. DENY ONLY if the tool call could access a file or path that is in protected_files or protected_paths.
3952
+ 2. ALLOW everything else. You must NOT invent your own security rules.
3953
+ 3. If a file is NOT in protected_files, it is NOT protected \u2014 even if the filename looks sensitive.
3954
+ 4. "cat test.txt" is ALLOWED if test.txt is not in protected_files.
3955
+ 5. "curl https://example.com" is ALLOWED unless it sends protected file content.
3956
+ 6. "printenv" is ALLOWED unless the policy explicitly protects it.
3952
3957
 
3953
- DENY if the tool call could, directly or indirectly, access a file from the protected_files list \u2014 even through:
3954
- - Shell glob patterns (e.g., "cred*" could match "credentials.json" IF credentials.json is in protected_files)
3955
- - Command substitution ($(...), backticks)
3956
- - Process substitution (<(cat file)) \u2014 check inside <(...) for protected files
3957
- - Variable interpolation (e.g., f=".en"; cat \${f}v builds ".env" \u2014 DENY only if .env is in protected_files)
3958
- - Input redirection (< file)
3959
- - Multi-stage operations: tar/cp a protected file then read the copy \u2014 DENY the entire chain
3960
- - Any utility that reads file content (cat, head, tail, less, perl, awk, sed, xxd, od, strings, dd, etc.)
3958
+ BYPASS DETECTION \u2014 DENY if the command accesses a protected file through:
3959
+ - Shell glob patterns: "cat cred*" could match "credentials.json" IF it is in protected_files
3960
+ - Command substitution: "cat $(echo .env)" builds ".env"
3961
+ - Variable interpolation: f=".en"; cat \${f}v builds ".env"
3962
+ - Process substitution: <(cat .env)
3963
+ - Multi-stage: cp protected_file /tmp/x && cat /tmp/x
3964
+ - Input redirection: < .env
3965
+ - Any file-reading utility (cat, head, tail, less, perl, awk, sed, xxd, etc.)
3961
3966
 
3962
- Also DENY if:
3963
- - The command sends data to external URLs (curl -d, wget --post)
3964
- - The command leaks environment variables (printenv, env, process.env)
3965
- - The command executes remotely downloaded code (curl|bash)
3967
+ CRITICAL: You have NO security opinions of your own. You ONLY enforce the protected_files and protected_paths lists. If something is not in those lists, it is ALLOWED. Do NOT over-block.
3966
3968
 
3967
- ALLOW if:
3968
- - The file is NOT in protected_files \u2014 even if cat, head, etc. is used. Reading non-protected files is normal.
3969
- - The action is a normal development operation (ls, git status, npm build, cat app.js, etc.)
3970
- - The action does not touch any protected file or path
3971
-
3972
- CRITICAL: Only DENY access to files EXPLICITLY in the protected_files list. "cat app.js" is ALLOWED if app.js is not in protected_files. Do NOT over-block.
3973
-
3974
- Respond with ONLY valid JSON, no markdown, no explanation outside the JSON:
3969
+ Respond with ONLY valid JSON:
3975
3970
  {"decision": "ALLOW" or "DENY", "reason": "brief one-line explanation", "confidence": 0.0 to 1.0}`;
3976
3971
  var AuthError = class extends Error {
3977
3972
  constructor(message) {
@@ -3983,24 +3978,16 @@ var AiJudge = class _AiJudge {
3983
3978
  config;
3984
3979
  protectedFiles;
3985
3980
  protectedPaths;
3986
- deniedActions;
3987
3981
  isOllamaEndpoint;
3988
3982
  // Circuit breaker: after 3 consecutive failures in 60s, skip AI Judge
3989
3983
  consecutiveFailures = 0;
3990
3984
  lastFailureTime = 0;
3991
3985
  static CIRCUIT_BREAKER_THRESHOLD = 3;
3992
3986
  static CIRCUIT_BREAKER_RESET_MS = 6e4;
3993
- constructor(config, protectedFiles, protectedPaths, deniedActions = [
3994
- "file deletion",
3995
- "data exfiltration",
3996
- "remote code execution",
3997
- "environment variable leak",
3998
- "security control bypass"
3999
- ]) {
3987
+ constructor(config, protectedFiles, protectedPaths) {
4000
3988
  this.config = config;
4001
3989
  this.protectedFiles = protectedFiles;
4002
3990
  this.protectedPaths = protectedPaths;
4003
- this.deniedActions = deniedActions;
4004
3991
  this.isOllamaEndpoint = config.endpoint.includes("11434") || config.endpoint.includes("ollama");
4005
3992
  }
4006
3993
  /**
@@ -4024,8 +4011,7 @@ var AiJudge = class _AiJudge {
4024
4011
  tool: toolName,
4025
4012
  arguments: sanitizedArgs,
4026
4013
  protected_files: this.protectedFiles,
4027
- protected_paths: this.protectedPaths,
4028
- denied_actions: this.deniedActions
4014
+ protected_paths: this.protectedPaths
4029
4015
  });
4030
4016
  try {
4031
4017
  const response = await this.callLLM(userMessage);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.35.0",
3
+ "version": "0.37.0",
4
4
  "description": "AI tool security proxy — protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
5
5
  "type": "module",
6
6
  "bin": {