@solongate/proxy 0.34.0 → 0.35.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 +37 -3
- package/dist/init.js +15 -3
- package/dist/lib.js +19 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -274,6 +274,9 @@ function parseArgs(argv) {
|
|
|
274
274
|
aiJudgeApiKey = process.env.GROQ_API_KEY;
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
|
+
if (aiJudgeApiKey && (aiJudgeApiKey.includes("your_") || aiJudgeApiKey.includes("_here") || aiJudgeApiKey.length < 10)) {
|
|
278
|
+
aiJudgeApiKey = void 0;
|
|
279
|
+
}
|
|
277
280
|
const aiJudge = aiJudgeEnabled ? {
|
|
278
281
|
enabled: true,
|
|
279
282
|
model: aiJudgeModel,
|
|
@@ -533,7 +536,7 @@ function isAlreadyProtected(server) {
|
|
|
533
536
|
}
|
|
534
537
|
return false;
|
|
535
538
|
}
|
|
536
|
-
function wrapServer(serverName, server, policy, agentName) {
|
|
539
|
+
function wrapServer(serverName, server, policy, agentName, aiJudge) {
|
|
537
540
|
const env = { ...server.env ?? {} };
|
|
538
541
|
env.SOLONGATE_API_KEY = "${SOLONGATE_API_KEY}";
|
|
539
542
|
const proxyArgs = ["-y", "@solongate/proxy@latest"];
|
|
@@ -543,6 +546,9 @@ function wrapServer(serverName, server, policy, agentName) {
|
|
|
543
546
|
if (agentName) {
|
|
544
547
|
proxyArgs.push("--agent-name", agentName);
|
|
545
548
|
}
|
|
549
|
+
if (aiJudge) {
|
|
550
|
+
proxyArgs.push("--ai-judge");
|
|
551
|
+
}
|
|
546
552
|
proxyArgs.push("--verbose", "--", server.command, ...server.args ?? []);
|
|
547
553
|
return {
|
|
548
554
|
command: "npx",
|
|
@@ -563,7 +569,8 @@ function parseInitArgs(argv) {
|
|
|
563
569
|
const args = argv.slice(2);
|
|
564
570
|
const options = {
|
|
565
571
|
all: false,
|
|
566
|
-
tools: []
|
|
572
|
+
tools: [],
|
|
573
|
+
aiJudge: false
|
|
567
574
|
};
|
|
568
575
|
for (let i = 0; i < args.length; i++) {
|
|
569
576
|
switch (args[i]) {
|
|
@@ -588,6 +595,9 @@ function parseInitArgs(argv) {
|
|
|
588
595
|
case "--openclaw":
|
|
589
596
|
options.tools.push("openclaw");
|
|
590
597
|
break;
|
|
598
|
+
case "--ai-judge":
|
|
599
|
+
options.aiJudge = true;
|
|
600
|
+
break;
|
|
591
601
|
case "--help":
|
|
592
602
|
case "-h":
|
|
593
603
|
printHelp();
|
|
@@ -615,8 +625,13 @@ AI TOOL HOOKS (default: all)
|
|
|
615
625
|
--gemini Install hooks for Gemini CLI
|
|
616
626
|
--openclaw Install hooks for OpenClaw
|
|
617
627
|
|
|
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
|
+
|
|
618
632
|
EXAMPLES
|
|
619
633
|
npx @solongate/proxy init --all # Protect everything, all tools
|
|
634
|
+
npx @solongate/proxy init --all --ai-judge # With AI Judge enabled
|
|
620
635
|
npx @solongate/proxy init --all --claude-code --gemini # Only Claude Code + Gemini hooks
|
|
621
636
|
npx @solongate/proxy init --all --policy policy.json # With custom policy
|
|
622
637
|
`;
|
|
@@ -1046,7 +1061,7 @@ async function main() {
|
|
|
1046
1061
|
const newConfig = { mcpServers: {} };
|
|
1047
1062
|
for (const name of serverNames) {
|
|
1048
1063
|
if (toProtect.includes(name)) {
|
|
1049
|
-
newConfig.mcpServers[name] = wrapServer(name, config.mcpServers[name], policyValue);
|
|
1064
|
+
newConfig.mcpServers[name] = wrapServer(name, config.mcpServers[name], policyValue, void 0, options.aiJudge);
|
|
1050
1065
|
} else {
|
|
1051
1066
|
newConfig.mcpServers[name] = config.mcpServers[name];
|
|
1052
1067
|
}
|
|
@@ -5671,6 +5686,12 @@ CRITICAL: Only DENY access to files EXPLICITLY in the protected_files list. "cat
|
|
|
5671
5686
|
|
|
5672
5687
|
Respond with ONLY valid JSON, no markdown, no explanation outside the JSON:
|
|
5673
5688
|
{"decision": "ALLOW" or "DENY", "reason": "brief one-line explanation", "confidence": 0.0 to 1.0}`;
|
|
5689
|
+
var AuthError = class extends Error {
|
|
5690
|
+
constructor(message) {
|
|
5691
|
+
super(message);
|
|
5692
|
+
this.name = "AuthError";
|
|
5693
|
+
}
|
|
5694
|
+
};
|
|
5674
5695
|
var AiJudge = class _AiJudge {
|
|
5675
5696
|
config;
|
|
5676
5697
|
protectedFiles;
|
|
@@ -5727,6 +5748,13 @@ var AiJudge = class _AiJudge {
|
|
|
5727
5748
|
this.consecutiveFailures++;
|
|
5728
5749
|
this.lastFailureTime = Date.now();
|
|
5729
5750
|
const message = err instanceof Error ? err.message : String(err);
|
|
5751
|
+
if (err instanceof AuthError) {
|
|
5752
|
+
return {
|
|
5753
|
+
decision: "ALLOW",
|
|
5754
|
+
reason: `AI Judge auth error (skipping): ${message.slice(0, 100)}`,
|
|
5755
|
+
confidence: 0.5
|
|
5756
|
+
};
|
|
5757
|
+
}
|
|
5730
5758
|
return {
|
|
5731
5759
|
decision: "DENY",
|
|
5732
5760
|
reason: `AI Judge error (fail-closed): ${message.slice(0, 100)}`,
|
|
@@ -5808,6 +5836,9 @@ var AiJudge = class _AiJudge {
|
|
|
5808
5836
|
});
|
|
5809
5837
|
if (!res.ok) {
|
|
5810
5838
|
const errBody = await res.text().catch(() => "");
|
|
5839
|
+
if (res.status === 401 || res.status === 403) {
|
|
5840
|
+
throw new AuthError(`LLM auth failed (${res.status}): ${errBody.slice(0, 200)}`);
|
|
5841
|
+
}
|
|
5811
5842
|
throw new Error(`LLM endpoint returned ${res.status}: ${errBody.slice(0, 200)}`);
|
|
5812
5843
|
}
|
|
5813
5844
|
const data = await res.json();
|
|
@@ -6048,6 +6079,9 @@ var SolonGateProxy = class {
|
|
|
6048
6079
|
if (match) groqKey = match[1].trim();
|
|
6049
6080
|
}
|
|
6050
6081
|
if (!groqKey) groqKey = process.env.GROQ_API_KEY;
|
|
6082
|
+
if (groqKey && (groqKey.includes("your_") || groqKey.includes("_here") || groqKey.length < 10)) {
|
|
6083
|
+
groqKey = void 0;
|
|
6084
|
+
}
|
|
6051
6085
|
if (groqKey) {
|
|
6052
6086
|
this.config.aiJudge = {
|
|
6053
6087
|
enabled: true,
|
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) {
|
|
120
|
+
function wrapServer(serverName, server, policy, agentName, aiJudge) {
|
|
121
121
|
const env = { ...server.env ?? {} };
|
|
122
122
|
env.SOLONGATE_API_KEY = "${SOLONGATE_API_KEY}";
|
|
123
123
|
const proxyArgs = ["-y", "@solongate/proxy@latest"];
|
|
@@ -127,6 +127,9 @@ function wrapServer(serverName, server, policy, agentName) {
|
|
|
127
127
|
if (agentName) {
|
|
128
128
|
proxyArgs.push("--agent-name", agentName);
|
|
129
129
|
}
|
|
130
|
+
if (aiJudge) {
|
|
131
|
+
proxyArgs.push("--ai-judge");
|
|
132
|
+
}
|
|
130
133
|
proxyArgs.push("--verbose", "--", server.command, ...server.args ?? []);
|
|
131
134
|
return {
|
|
132
135
|
command: "npx",
|
|
@@ -147,7 +150,8 @@ function parseInitArgs(argv) {
|
|
|
147
150
|
const args = argv.slice(2);
|
|
148
151
|
const options = {
|
|
149
152
|
all: false,
|
|
150
|
-
tools: []
|
|
153
|
+
tools: [],
|
|
154
|
+
aiJudge: false
|
|
151
155
|
};
|
|
152
156
|
for (let i = 0; i < args.length; i++) {
|
|
153
157
|
switch (args[i]) {
|
|
@@ -172,6 +176,9 @@ function parseInitArgs(argv) {
|
|
|
172
176
|
case "--openclaw":
|
|
173
177
|
options.tools.push("openclaw");
|
|
174
178
|
break;
|
|
179
|
+
case "--ai-judge":
|
|
180
|
+
options.aiJudge = true;
|
|
181
|
+
break;
|
|
175
182
|
case "--help":
|
|
176
183
|
case "-h":
|
|
177
184
|
printHelp();
|
|
@@ -199,8 +206,13 @@ AI TOOL HOOKS (default: all)
|
|
|
199
206
|
--gemini Install hooks for Gemini CLI
|
|
200
207
|
--openclaw Install hooks for OpenClaw
|
|
201
208
|
|
|
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
|
+
|
|
202
213
|
EXAMPLES
|
|
203
214
|
npx @solongate/proxy init --all # Protect everything, all tools
|
|
215
|
+
npx @solongate/proxy init --all --ai-judge # With AI Judge enabled
|
|
204
216
|
npx @solongate/proxy init --all --claude-code --gemini # Only Claude Code + Gemini hooks
|
|
205
217
|
npx @solongate/proxy init --all --policy policy.json # With custom policy
|
|
206
218
|
`;
|
|
@@ -632,7 +644,7 @@ async function main() {
|
|
|
632
644
|
const newConfig = { mcpServers: {} };
|
|
633
645
|
for (const name of serverNames) {
|
|
634
646
|
if (toProtect.includes(name)) {
|
|
635
|
-
newConfig.mcpServers[name] = wrapServer(name, config.mcpServers[name], policyValue);
|
|
647
|
+
newConfig.mcpServers[name] = wrapServer(name, config.mcpServers[name], policyValue, void 0, options.aiJudge);
|
|
636
648
|
} else {
|
|
637
649
|
newConfig.mcpServers[name] = config.mcpServers[name];
|
|
638
650
|
}
|
package/dist/lib.js
CHANGED
|
@@ -3973,6 +3973,12 @@ CRITICAL: Only DENY access to files EXPLICITLY in the protected_files list. "cat
|
|
|
3973
3973
|
|
|
3974
3974
|
Respond with ONLY valid JSON, no markdown, no explanation outside the JSON:
|
|
3975
3975
|
{"decision": "ALLOW" or "DENY", "reason": "brief one-line explanation", "confidence": 0.0 to 1.0}`;
|
|
3976
|
+
var AuthError = class extends Error {
|
|
3977
|
+
constructor(message) {
|
|
3978
|
+
super(message);
|
|
3979
|
+
this.name = "AuthError";
|
|
3980
|
+
}
|
|
3981
|
+
};
|
|
3976
3982
|
var AiJudge = class _AiJudge {
|
|
3977
3983
|
config;
|
|
3978
3984
|
protectedFiles;
|
|
@@ -4029,6 +4035,13 @@ var AiJudge = class _AiJudge {
|
|
|
4029
4035
|
this.consecutiveFailures++;
|
|
4030
4036
|
this.lastFailureTime = Date.now();
|
|
4031
4037
|
const message = err instanceof Error ? err.message : String(err);
|
|
4038
|
+
if (err instanceof AuthError) {
|
|
4039
|
+
return {
|
|
4040
|
+
decision: "ALLOW",
|
|
4041
|
+
reason: `AI Judge auth error (skipping): ${message.slice(0, 100)}`,
|
|
4042
|
+
confidence: 0.5
|
|
4043
|
+
};
|
|
4044
|
+
}
|
|
4032
4045
|
return {
|
|
4033
4046
|
decision: "DENY",
|
|
4034
4047
|
reason: `AI Judge error (fail-closed): ${message.slice(0, 100)}`,
|
|
@@ -4110,6 +4123,9 @@ var AiJudge = class _AiJudge {
|
|
|
4110
4123
|
});
|
|
4111
4124
|
if (!res.ok) {
|
|
4112
4125
|
const errBody = await res.text().catch(() => "");
|
|
4126
|
+
if (res.status === 401 || res.status === 403) {
|
|
4127
|
+
throw new AuthError(`LLM auth failed (${res.status}): ${errBody.slice(0, 200)}`);
|
|
4128
|
+
}
|
|
4113
4129
|
throw new Error(`LLM endpoint returned ${res.status}: ${errBody.slice(0, 200)}`);
|
|
4114
4130
|
}
|
|
4115
4131
|
const data = await res.json();
|
|
@@ -4350,6 +4366,9 @@ var SolonGateProxy = class {
|
|
|
4350
4366
|
if (match) groqKey = match[1].trim();
|
|
4351
4367
|
}
|
|
4352
4368
|
if (!groqKey) groqKey = process.env.GROQ_API_KEY;
|
|
4369
|
+
if (groqKey && (groqKey.includes("your_") || groqKey.includes("_here") || groqKey.length < 10)) {
|
|
4370
|
+
groqKey = void 0;
|
|
4371
|
+
}
|
|
4353
4372
|
if (groqKey) {
|
|
4354
4373
|
this.config.aiJudge = {
|
|
4355
4374
|
enabled: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.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": {
|