@solongate/proxy 0.83.50 → 0.83.52
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/hooks/guard.bundled.mjs +8 -4
- package/hooks/guard.mjs +21 -4
- package/package.json +7 -7
package/hooks/guard.bundled.mjs
CHANGED
|
@@ -6579,7 +6579,7 @@ function sweepLegacyFlagDir() {
|
|
|
6579
6579
|
} catch {
|
|
6580
6580
|
}
|
|
6581
6581
|
}
|
|
6582
|
-
var HOOK_VERSION =
|
|
6582
|
+
var HOOK_VERSION = 90;
|
|
6583
6583
|
var SG_REFRESH_ARG = process.argv.includes("--sg-refresh-policy");
|
|
6584
6584
|
var SG_STDIN = SG_REFRESH_ARG ? "" : (() => {
|
|
6585
6585
|
try {
|
|
@@ -7791,7 +7791,7 @@ function tamperCheck(toolName, args) {
|
|
|
7791
7791
|
}
|
|
7792
7792
|
var DLP_PATTERNS = [
|
|
7793
7793
|
{ name: "AWS access key", re: /AKIA[0-9A-Z]{16}/ },
|
|
7794
|
-
{ name: "Private key block", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
|
|
7794
|
+
{ name: "Private key block", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----|-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
|
|
7795
7795
|
{ name: "Anthropic key", re: /sk-ant-[A-Za-z0-9_-]{20,}/ },
|
|
7796
7796
|
{ name: "OpenAI key", re: /sk-(proj-)?[A-Za-z0-9_-]{20,}/ },
|
|
7797
7797
|
{ name: "GitHub token", re: /gh[pousr]_[A-Za-z0-9]{20,}/ },
|
|
@@ -8813,6 +8813,7 @@ if (!REFRESH_MODE) {
|
|
|
8813
8813
|
if (process.env.SOLONGATE_DEBUG) {
|
|
8814
8814
|
}
|
|
8815
8815
|
let reason = selfProtectEnabled ? tamperCheck(toolName, args) : null;
|
|
8816
|
+
let pendingGhostPatch = null;
|
|
8816
8817
|
if (!reason && securityCfg && securityCfg.ghost) {
|
|
8817
8818
|
const ghostHit = ghostBlock(toolName, args, securityCfg.ghost);
|
|
8818
8819
|
if (ghostHit) {
|
|
@@ -8842,7 +8843,7 @@ if (!REFRESH_MODE) {
|
|
|
8842
8843
|
if (toolName === "Bash" || toolName === "run_command" || guessPermission(toolName) === "EXECUTE") {
|
|
8843
8844
|
const rw = ghostListingRewrite(args, securityCfg.ghost);
|
|
8844
8845
|
if (rw)
|
|
8845
|
-
|
|
8846
|
+
pendingGhostPatch = { command: rw };
|
|
8846
8847
|
}
|
|
8847
8848
|
}
|
|
8848
8849
|
if (!reason)
|
|
@@ -8876,9 +8877,12 @@ if (!REFRESH_MODE) {
|
|
|
8876
8877
|
reason = "Security layer (DLP): reading a file that contains a secret is blocked. Blocked by SolonGate.";
|
|
8877
8878
|
opaRoute = "black";
|
|
8878
8879
|
} else if (plan && plan.rewrite) {
|
|
8879
|
-
rewriteTool(plan.rewrite);
|
|
8880
|
+
rewriteTool({ ...pendingGhostPatch || {}, ...plan.rewrite });
|
|
8881
|
+
pendingGhostPatch = null;
|
|
8880
8882
|
}
|
|
8881
8883
|
}
|
|
8884
|
+
if (!reason && pendingGhostPatch)
|
|
8885
|
+
rewriteTool(pendingGhostPatch);
|
|
8882
8886
|
if (AGENT_TYPE !== "codex")
|
|
8883
8887
|
process.stderr.write(`[SolonGate ROUTE] ${opaRoute.toUpperCase()} (${reason ? "block" : "allow"})
|
|
8884
8888
|
`);
|
package/hooks/guard.mjs
CHANGED
|
@@ -82,7 +82,7 @@ import { createHash } from 'node:crypto';
|
|
|
82
82
|
// the installed hook self-updates when the cloud version is higher (see
|
|
83
83
|
// maybeSelfUpdate). This is what makes guard fixes propagate without a manual
|
|
84
84
|
// reinstall — the same trust model as the OPA WASM this hook already runs.
|
|
85
|
-
const HOOK_VERSION =
|
|
85
|
+
const HOOK_VERSION = 90;
|
|
86
86
|
|
|
87
87
|
// ── The Go guard, when there is one and it is the right one ──────────────────
|
|
88
88
|
//
|
|
@@ -1685,7 +1685,7 @@ function tamperCheck(toolName, args) {
|
|
|
1685
1685
|
// rules plus generic Bearer / secret-assignment catch-alls for the long tail.
|
|
1686
1686
|
const DLP_PATTERNS = [
|
|
1687
1687
|
{ name: 'AWS access key', re: /AKIA[0-9A-Z]{16}/ },
|
|
1688
|
-
{ name: 'Private key block', re: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
|
|
1688
|
+
{ name: 'Private key block', re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----|-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
|
|
1689
1689
|
{ name: 'Anthropic key', re: /sk-ant-[A-Za-z0-9_-]{20,}/ },
|
|
1690
1690
|
{ name: 'OpenAI key', re: /sk-(proj-)?[A-Za-z0-9_-]{20,}/ },
|
|
1691
1691
|
{ name: 'GitHub token', re: /gh[pousr]_[A-Za-z0-9]{20,}/ },
|
|
@@ -2968,6 +2968,9 @@ if (!REFRESH_MODE) { input += SG_STDIN; }
|
|
|
2968
2968
|
// Tamper / self-protection — runs before policy eval. ON by default; the
|
|
2969
2969
|
// per-project cloud setting can disable it (fail safe: stays on if unread).
|
|
2970
2970
|
let reason = selfProtectEnabled ? tamperCheck(toolName, args) : null;
|
|
2971
|
+
// A ghost listing rewrite decided BELOW but applied at the very end, so that
|
|
2972
|
+
// rewriting a call is never the same thing as approving it.
|
|
2973
|
+
let pendingGhostPatch = null;
|
|
2971
2974
|
// Ghost paths — handled BEFORE the other layers and emitted as a STEALTH
|
|
2972
2975
|
// block: a mutating op on a hidden path is denied with a bare OS-style
|
|
2973
2976
|
// "No such file or directory" and NOTHING else (no ROUTE line, no SolonGate
|
|
@@ -3000,7 +3003,13 @@ if (!REFRESH_MODE) { input += SG_STDIN; }
|
|
|
3000
3003
|
// PreToolUse `overwrite` replaces the command before it runs (hooks.md).
|
|
3001
3004
|
if (toolName === 'Bash' || toolName === 'run_command' || guessPermission(toolName) === 'EXECUTE') {
|
|
3002
3005
|
const rw = ghostListingRewrite(args, securityCfg.ghost);
|
|
3003
|
-
|
|
3006
|
+
// HELD, not emitted. Emitting a rewrite ends the hook, so doing it here
|
|
3007
|
+
// meant the DLP argument scan, the rate limit and the POLICY never ran
|
|
3008
|
+
// for any call ghost touched — under a whitelist, `ls` in a project with
|
|
3009
|
+
// a ghost route was allowed whatever the policy said. Same reasoning as
|
|
3010
|
+
// the DLP read-redaction below, which was moved after policy eval for
|
|
3011
|
+
// exactly this failure. Applied at the end, once every layer has spoken.
|
|
3012
|
+
if (rw) pendingGhostPatch = { command: rw };
|
|
3004
3013
|
}
|
|
3005
3014
|
}
|
|
3006
3015
|
// Extra security layers run after tamper, before policy. Block reason wins
|
|
@@ -3070,10 +3079,18 @@ if (!REFRESH_MODE) { input += SG_STDIN; }
|
|
|
3070
3079
|
reason = 'Security layer (DLP): reading a file that contains a secret is blocked. Blocked by SolonGate.';
|
|
3071
3080
|
opaRoute = 'black';
|
|
3072
3081
|
} else if (plan && plan.rewrite) {
|
|
3073
|
-
|
|
3082
|
+
// Both patches can be live at once (a listing ghost filters, pointed at a
|
|
3083
|
+
// redacted copy). Redaction wins any key they share: it is the one that
|
|
3084
|
+
// keeps a secret out of the agent's hands.
|
|
3085
|
+
rewriteTool({ ...(pendingGhostPatch || {}), ...plan.rewrite }); // verdict first, update later
|
|
3086
|
+
pendingGhostPatch = null;
|
|
3074
3087
|
}
|
|
3075
3088
|
}
|
|
3076
3089
|
|
|
3090
|
+
// The held ghost rewrite, applied only now that tamper, DLP, the rate limit
|
|
3091
|
+
// and the policy have all had their say and none of them blocked.
|
|
3092
|
+
if (!reason && pendingGhostPatch) rewriteTool(pendingGhostPatch);
|
|
3093
|
+
|
|
3077
3094
|
// Diagnostic line for the terminal. NOT written on Codex: there the hook's
|
|
3078
3095
|
// ENTIRE stderr becomes the block reason shown to the model (exit 2), so this
|
|
3079
3096
|
// would prefix every denial with "[SolonGate ROUTE] BLACK (block)".
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.83.
|
|
3
|
+
"version": "0.83.52",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -61,12 +61,12 @@
|
|
|
61
61
|
"node": ">=20.0.0"
|
|
62
62
|
},
|
|
63
63
|
"optionalDependencies": {
|
|
64
|
-
"@solongate/guard-linux-x64": "0.83.
|
|
65
|
-
"@solongate/guard-linux-arm64": "0.83.
|
|
66
|
-
"@solongate/guard-darwin-x64": "0.83.
|
|
67
|
-
"@solongate/guard-darwin-arm64": "0.83.
|
|
68
|
-
"@solongate/guard-win32-x64": "0.83.
|
|
69
|
-
"@solongate/guard-win32-arm64": "0.83.
|
|
64
|
+
"@solongate/guard-linux-x64": "0.83.52",
|
|
65
|
+
"@solongate/guard-linux-arm64": "0.83.52",
|
|
66
|
+
"@solongate/guard-darwin-x64": "0.83.52",
|
|
67
|
+
"@solongate/guard-darwin-arm64": "0.83.52",
|
|
68
|
+
"@solongate/guard-win32-x64": "0.83.52",
|
|
69
|
+
"@solongate/guard-win32-arm64": "0.83.52"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"@modelcontextprotocol/sdk": "^1.26.0",
|