@solongate/proxy 0.36.0 → 0.38.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
@@ -5640,39 +5640,34 @@ var PolicySyncManager = class {
5640
5640
  };
5641
5641
 
5642
5642
  // src/ai-judge.ts
5643
- 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.
5644
5644
 
5645
5645
  You will receive a JSON object with:
5646
5646
  - "tool": the tool name being called
5647
5647
  - "arguments": the tool's arguments
5648
- - "protected_files": EXACT list of files that must NEVER be accessed. ONLY these specific files are protected \u2014 nothing else.
5649
- - "protected_paths": EXACT list of directories that must NEVER be accessed. ONLY these specific paths are protected \u2014 nothing else.
5650
- - "denied_actions": list of actions that are never allowed
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
5651
5650
 
5652
- 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.
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.
5653
5658
 
5654
- DENY if the tool call could, directly or indirectly, access a file from the protected_files list \u2014 even through:
5655
- - Shell glob patterns (e.g., "cred*" could match "credentials.json" IF credentials.json is in protected_files)
5656
- - Command substitution ($(...), backticks)
5657
- - Process substitution (<(cat file)) \u2014 check inside <(...) for protected files
5658
- - Variable interpolation (e.g., f=".en"; cat \${f}v builds ".env" \u2014 DENY only if .env is in protected_files)
5659
- - Input redirection (< file)
5660
- - Multi-stage operations: tar/cp a protected file then read the copy \u2014 DENY the entire chain
5661
- - Any utility that reads file content (cat, head, tail, less, perl, awk, sed, xxd, od, strings, dd, etc.)
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.)
5662
5667
 
5663
- Also DENY if:
5664
- - The command sends data to external URLs (curl -d, wget --post)
5665
- - The command leaks environment variables (printenv, env, process.env)
5666
- - The command executes remotely downloaded code (curl|bash)
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.
5667
5669
 
5668
- ALLOW if:
5669
- - The file is NOT in protected_files \u2014 even if cat, head, etc. is used. Reading non-protected files is normal.
5670
- - The action is a normal development operation (ls, git status, npm build, cat app.js, etc.)
5671
- - The action does not touch any protected file or path
5672
-
5673
- 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.
5674
-
5675
- Respond with ONLY valid JSON, no markdown, no explanation outside the JSON:
5670
+ Respond with ONLY valid JSON:
5676
5671
  {"decision": "ALLOW" or "DENY", "reason": "brief one-line explanation", "confidence": 0.0 to 1.0}`;
5677
5672
  var AuthError = class extends Error {
5678
5673
  constructor(message) {
@@ -5684,24 +5679,16 @@ var AiJudge = class _AiJudge {
5684
5679
  config;
5685
5680
  protectedFiles;
5686
5681
  protectedPaths;
5687
- deniedActions;
5688
5682
  isOllamaEndpoint;
5689
5683
  // Circuit breaker: after 3 consecutive failures in 60s, skip AI Judge
5690
5684
  consecutiveFailures = 0;
5691
5685
  lastFailureTime = 0;
5692
5686
  static CIRCUIT_BREAKER_THRESHOLD = 3;
5693
5687
  static CIRCUIT_BREAKER_RESET_MS = 6e4;
5694
- constructor(config, protectedFiles, protectedPaths, deniedActions = [
5695
- "file deletion",
5696
- "data exfiltration",
5697
- "remote code execution",
5698
- "environment variable leak",
5699
- "security control bypass"
5700
- ]) {
5688
+ constructor(config, protectedFiles, protectedPaths) {
5701
5689
  this.config = config;
5702
5690
  this.protectedFiles = protectedFiles;
5703
5691
  this.protectedPaths = protectedPaths;
5704
- this.deniedActions = deniedActions;
5705
5692
  this.isOllamaEndpoint = config.endpoint.includes("11434") || config.endpoint.includes("ollama");
5706
5693
  }
5707
5694
  /**
@@ -5725,8 +5712,7 @@ var AiJudge = class _AiJudge {
5725
5712
  tool: toolName,
5726
5713
  arguments: sanitizedArgs,
5727
5714
  protected_files: this.protectedFiles,
5728
- protected_paths: this.protectedPaths,
5729
- denied_actions: this.deniedActions
5715
+ protected_paths: this.protectedPaths
5730
5716
  });
5731
5717
  try {
5732
5718
  const response = await this.callLLM(userMessage);
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/hooks/guard.mjs CHANGED
@@ -1134,7 +1134,9 @@ process.stdin.on('end', async () => {
1134
1134
 
1135
1135
  // ── AI Judge: semantic intent analysis (runs when policy ALLOWs) ──
1136
1136
  if (!reason) {
1137
- const GROQ_KEY = process.env.GROQ_API_KEY || dotenv.GROQ_API_KEY || '';
1137
+ let GROQ_KEY = process.env.GROQ_API_KEY || dotenv.GROQ_API_KEY || '';
1138
+ // Skip placeholder values
1139
+ if (GROQ_KEY && (GROQ_KEY.includes('your_') || GROQ_KEY.includes('_here') || GROQ_KEY.length < 10)) GROQ_KEY = '';
1138
1140
  let aiJudgeEnabled = false;
1139
1141
  let aiJudgeModel = 'llama-3.1-8b-instant';
1140
1142
  let aiJudgeEndpoint = 'https://api.groq.com/openai';
@@ -1197,40 +1199,34 @@ process.stdin.on('end', async () => {
1197
1199
  arguments: args,
1198
1200
  protected_files: protectedFiles,
1199
1201
  protected_paths: protectedPathsList,
1200
- denied_actions: ['file deletion', 'data exfiltration', 'remote code execution', 'environment variable leak', 'security control bypass'],
1201
1202
  });
1202
1203
 
1203
- const systemPrompt = `You are a security judge for an AI coding tool. You evaluate tool calls and decide if they should be ALLOWED or DENIED.
1204
+ const systemPrompt = `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.
1204
1205
 
1205
1206
  You will receive a JSON object with:
1206
- - "tool": the tool name being called (e.g., Bash, Write, Read, Edit)
1207
+ - "tool": the tool name being called
1207
1208
  - "arguments": the tool's arguments
1208
- - "protected_files": EXACT list of files that must NEVER be accessed. ONLY these specific files are protected nothing else.
1209
- - "protected_paths": EXACT list of directories that must NEVER be accessed. ONLY these specific paths are protected — nothing else.
1210
- - "denied_actions": list of actions that are never allowed
1211
-
1212
- 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.
1213
-
1214
- DENY if the tool call could, directly or indirectly, access a file from the protected_files list — even through:
1215
- - Shell glob patterns (e.g., "cred*" could match "credentials.json" IF credentials.json is in protected_files)
1216
- - Command substitution ($(...), backticks)
1217
- - Process substitution (<(cat file)) check inside <(...) for protected files
1218
- - Variable interpolation (e.g., f=".en"; cat \${f}v builds ".env" — DENY only if .env is in protected_files)
1219
- - Input redirection (< file)
1220
- - Multi-stage operations: tar/cp a protected file then read the copy DENY the entire chain
1221
- - Any utility that reads file content (cat, head, tail, less, perl, awk, sed, xxd, od, strings, dd, etc.)
1222
-
1223
- Also DENY if:
1224
- - The command sends data to external URLs (curl -d, wget --post)
1225
- - The command leaks environment variables (printenv, env, process.env)
1226
- - The command executes remotely downloaded code (curl|bash)
1227
-
1228
- ALLOW if:
1229
- - The file is NOT in protected_files — even if cat, head, etc. is used. Reading non-protected files is normal.
1230
- - The action is a normal development operation (ls, git status, npm build, cat app.js, etc.)
1231
- - The action does not touch any protected file or path
1232
-
1233
- 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. "cat package.json" is ALLOWED if package.json is not in protected_files. Do NOT over-block.
1209
+ - "protected_files": the EXACT and COMPLETE list of protected files from the user's policy
1210
+ - "protected_paths": the EXACT and COMPLETE list of protected directories from the user's policy
1211
+
1212
+ RULES:
1213
+ 1. DENY ONLY if the tool call could access a file or path that is in protected_files or protected_paths.
1214
+ 2. ALLOW everything else. You must NOT invent your own security rules.
1215
+ 3. If a file is NOT in protected_files, it is NOT protected even if the filename looks sensitive.
1216
+ 4. "cat test.txt" is ALLOWED if test.txt is not in protected_files.
1217
+ 5. "curl https://example.com" is ALLOWED unless it sends protected file content.
1218
+ 6. "printenv" is ALLOWED unless the policy explicitly protects it.
1219
+
1220
+ BYPASS DETECTION DENY if the command accesses a protected file through:
1221
+ - Shell glob patterns: "cat cred*" could match "credentials.json" IF it is in protected_files
1222
+ - Command substitution: "cat $(echo .env)" builds ".env"
1223
+ - Variable interpolation: f=".en"; cat \${f}v builds ".env"
1224
+ - Process substitution: <(cat .env)
1225
+ - Multi-stage: cp protected_file /tmp/x && cat /tmp/x
1226
+ - Input redirection: < .env
1227
+ - Any file-reading utility (cat, head, tail, less, perl, awk, sed, xxd, etc.)
1228
+
1229
+ 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.
1234
1230
 
1235
1231
  Respond with ONLY valid JSON: {"decision": "ALLOW" or "DENY", "reason": "brief explanation", "confidence": 0.0 to 1.0}`;
1236
1232
 
@@ -1258,17 +1254,16 @@ Respond with ONLY valid JSON: {"decision": "ALLOW" or "DENY", "reason": "brief e
1258
1254
  const jsonMatch = content.match(/\{[\s\S]*\}/);
1259
1255
  if (jsonMatch) {
1260
1256
  const verdict = JSON.parse(jsonMatch[0]);
1261
- if (verdict.decision === 'DENY') {
1257
+ if (verdict.decision === 'DENY' && verdict.confidence >= 0.7) {
1262
1258
  reason = '[SolonGate AI Judge] Blocked: ' + (verdict.reason || 'Semantic analysis detected a policy violation');
1263
1259
  }
1260
+ // Low-confidence DENY or ALLOW → skip (don't block)
1264
1261
  }
1265
- } else {
1266
- // Fail-closed: LLM error → DENY
1267
- reason = '[SolonGate AI Judge] Blocked: Groq API error (fail-closed)';
1268
1262
  }
1269
- } catch (err) {
1270
- // Fail-closed: timeout or parse error DENY
1271
- reason = '[SolonGate AI Judge] Blocked: ' + (err.message || 'error') + ' (fail-closed)';
1263
+ // Auth/config errors (401, 403) → skip AI Judge, don't DENY
1264
+ // Other LLM errors skip too (policy engine already evaluated)
1265
+ } catch {
1266
+ // Timeout or parse error → skip AI Judge (policy engine already passed)
1272
1267
  }
1273
1268
  }
1274
1269
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.36.0",
3
+ "version": "0.38.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": {