@solongate/proxy 0.81.83 → 0.81.85
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/global-install.d.ts +0 -7
- package/dist/global-install.js +2 -22
- package/dist/index.js +6 -25
- package/dist/login.js +1 -1
- package/dist/tui/index.js +2 -21
- package/hooks/guard.bundled.mjs +7 -7
- package/hooks/guard.mjs +20 -15
- package/package.json +1 -1
package/dist/global-install.d.ts
CHANGED
|
@@ -11,13 +11,6 @@ export declare function globalPaths(): {
|
|
|
11
11
|
};
|
|
12
12
|
export declare function clearGuardUpdateCheck(): boolean;
|
|
13
13
|
export declare function runGlobalRestore(): void;
|
|
14
|
-
/**
|
|
15
|
-
* Delete the guard's cached policy/security config (`~/.solongate/.policy-cache-*.json`)
|
|
16
|
-
* so the next tool call RE-FETCHES it from the API. Fixes a stale cache — e.g. the
|
|
17
|
-
* guard still enforcing DLP `detect` after you switched it to `block` in the
|
|
18
|
-
* dataroom. Best-effort; returns how many cache files it cleared.
|
|
19
|
-
*/
|
|
20
|
-
export declare function clearPolicyCache(): number;
|
|
21
14
|
/**
|
|
22
15
|
* TUI-safe (re)install — the dataroom's one-key "install / update guard" action.
|
|
23
16
|
* Writes the hook files THIS CLI ships (readGuard = the current package's bundle,
|
package/dist/global-install.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/global-install.ts
|
|
2
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync } from "fs";
|
|
3
3
|
import { resolve, join, dirname } from "path";
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
@@ -137,24 +137,6 @@ function runGlobalRestore() {
|
|
|
137
137
|
}
|
|
138
138
|
console.log(" Global SolonGate enforcement uninstalled. Restart Claude Code.");
|
|
139
139
|
}
|
|
140
|
-
function clearPolicyCache() {
|
|
141
|
-
try {
|
|
142
|
-
const dir = globalPaths().sgDir;
|
|
143
|
-
let n = 0;
|
|
144
|
-
for (const f of readdirSync(dir)) {
|
|
145
|
-
if (f.startsWith(".policy-cache-") && f.endsWith(".json")) {
|
|
146
|
-
try {
|
|
147
|
-
rmSync(join(dir, f), { force: true });
|
|
148
|
-
n++;
|
|
149
|
-
} catch {
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return n;
|
|
154
|
-
} catch {
|
|
155
|
-
return 0;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
140
|
function installGlobalQuiet() {
|
|
159
141
|
try {
|
|
160
142
|
const p = globalPaths();
|
|
@@ -197,9 +179,8 @@ function installGlobalQuiet() {
|
|
|
197
179
|
}
|
|
198
180
|
};
|
|
199
181
|
writeFileSync(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
200
|
-
clearPolicyCache();
|
|
201
182
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") lockProtected();
|
|
202
|
-
return { ok: true, message: "guard installed
|
|
183
|
+
return { ok: true, message: "guard installed (open a new session)" };
|
|
203
184
|
} catch (e) {
|
|
204
185
|
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
205
186
|
}
|
|
@@ -385,7 +366,6 @@ async function installGlobalWithKey(apiKey, apiUrl) {
|
|
|
385
366
|
}
|
|
386
367
|
export {
|
|
387
368
|
clearGuardUpdateCheck,
|
|
388
|
-
clearPolicyCache,
|
|
389
369
|
globalPaths,
|
|
390
370
|
guardHookOutdated,
|
|
391
371
|
installClaudeShim,
|
package/dist/index.js
CHANGED
|
@@ -10085,7 +10085,7 @@ var init_Audit = __esm({
|
|
|
10085
10085
|
});
|
|
10086
10086
|
|
|
10087
10087
|
// src/global-install.ts
|
|
10088
|
-
import { readFileSync as readFileSync9, writeFileSync as writeFileSync9, existsSync as existsSync4, mkdirSync as mkdirSync8, rmSync as rmSync2
|
|
10088
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync9, existsSync as existsSync4, mkdirSync as mkdirSync8, rmSync as rmSync2 } from "fs";
|
|
10089
10089
|
import { resolve as resolve4, join as join11, dirname as dirname3 } from "path";
|
|
10090
10090
|
import { homedir as homedir9 } from "os";
|
|
10091
10091
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
@@ -10186,24 +10186,6 @@ function readGuard() {
|
|
|
10186
10186
|
const bundled = join11(HOOKS_DIR, "guard.bundled.mjs");
|
|
10187
10187
|
return existsSync4(bundled) ? readFileSync9(bundled, "utf-8") : readHook("guard.mjs");
|
|
10188
10188
|
}
|
|
10189
|
-
function clearPolicyCache() {
|
|
10190
|
-
try {
|
|
10191
|
-
const dir = globalPaths().sgDir;
|
|
10192
|
-
let n = 0;
|
|
10193
|
-
for (const f of readdirSync(dir)) {
|
|
10194
|
-
if (f.startsWith(".policy-cache-") && f.endsWith(".json")) {
|
|
10195
|
-
try {
|
|
10196
|
-
rmSync2(join11(dir, f), { force: true });
|
|
10197
|
-
n++;
|
|
10198
|
-
} catch {
|
|
10199
|
-
}
|
|
10200
|
-
}
|
|
10201
|
-
}
|
|
10202
|
-
return n;
|
|
10203
|
-
} catch {
|
|
10204
|
-
return 0;
|
|
10205
|
-
}
|
|
10206
|
-
}
|
|
10207
10189
|
function installGlobalQuiet() {
|
|
10208
10190
|
try {
|
|
10209
10191
|
const p = globalPaths();
|
|
@@ -10246,9 +10228,8 @@ function installGlobalQuiet() {
|
|
|
10246
10228
|
}
|
|
10247
10229
|
};
|
|
10248
10230
|
writeFileSync9(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10249
|
-
clearPolicyCache();
|
|
10250
10231
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") lockProtected();
|
|
10251
|
-
return { ok: true, message: "guard installed
|
|
10232
|
+
return { ok: true, message: "guard installed (open a new session)" };
|
|
10252
10233
|
} catch (e) {
|
|
10253
10234
|
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
10254
10235
|
}
|
|
@@ -12369,7 +12350,7 @@ import { createServer, request as httpRequest } from "http";
|
|
|
12369
12350
|
import { request as httpsRequest } from "https";
|
|
12370
12351
|
import { spawn as spawn5 } from "child_process";
|
|
12371
12352
|
import { URL as URL2 } from "url";
|
|
12372
|
-
import { readFileSync as readFileSync11, existsSync as existsSync7, readdirSync
|
|
12353
|
+
import { readFileSync as readFileSync11, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
12373
12354
|
import { resolve as resolve5 } from "path";
|
|
12374
12355
|
import { homedir as homedir13 } from "os";
|
|
12375
12356
|
function findCacheFile() {
|
|
@@ -12381,7 +12362,7 @@ function findCacheFile() {
|
|
|
12381
12362
|
}
|
|
12382
12363
|
let best = null, bestTs = -1;
|
|
12383
12364
|
try {
|
|
12384
|
-
for (const name of
|
|
12365
|
+
for (const name of readdirSync(dir)) {
|
|
12385
12366
|
if (name.startsWith(".policy-cache-") && name.endsWith(".json")) {
|
|
12386
12367
|
const full = resolve5(dir, name);
|
|
12387
12368
|
const ts = statSync4(full).mtimeMs;
|
|
@@ -12691,7 +12672,7 @@ import { createServer as createServer2 } from "http";
|
|
|
12691
12672
|
import { readFileSync as readFileSync12, statSync as statSync5 } from "fs";
|
|
12692
12673
|
import { resolve as resolve6, join as join15, isAbsolute } from "path";
|
|
12693
12674
|
import { homedir as homedir14 } from "os";
|
|
12694
|
-
import { readdirSync as
|
|
12675
|
+
import { readdirSync as readdirSync2 } from "fs";
|
|
12695
12676
|
function allowedOrigins() {
|
|
12696
12677
|
const base = [
|
|
12697
12678
|
"https://dashboard.solongate.com",
|
|
@@ -12712,7 +12693,7 @@ function resolveLocalLogDir(rawPath) {
|
|
|
12712
12693
|
async function findLogDir() {
|
|
12713
12694
|
const base = resolve6(homedir14(), ".solongate");
|
|
12714
12695
|
try {
|
|
12715
|
-
const files =
|
|
12696
|
+
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
12716
12697
|
for (const f of files) {
|
|
12717
12698
|
try {
|
|
12718
12699
|
const c2 = JSON.parse(readFileSync12(join15(base, f), "utf-8"));
|
package/dist/login.js
CHANGED
|
@@ -26,7 +26,7 @@ var c = {
|
|
|
26
26
|
var BANNER_COLORS = [c.blue1, c.blue2, c.blue3, c.blue4, c.blue5, c.blue6];
|
|
27
27
|
|
|
28
28
|
// src/global-install.ts
|
|
29
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync
|
|
29
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, rmSync } from "fs";
|
|
30
30
|
import { resolve, join, dirname } from "path";
|
|
31
31
|
import { homedir } from "os";
|
|
32
32
|
import { fileURLToPath } from "url";
|
package/dist/tui/index.js
CHANGED
|
@@ -3140,7 +3140,7 @@ import TextInput5 from "ink-text-input";
|
|
|
3140
3140
|
import { useEffect as useEffect6, useRef as useRef3, useState as useState7 } from "react";
|
|
3141
3141
|
|
|
3142
3142
|
// src/global-install.ts
|
|
3143
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync2, mkdirSync as mkdirSync4, rmSync
|
|
3143
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync5, existsSync as existsSync2, mkdirSync as mkdirSync4, rmSync } from "fs";
|
|
3144
3144
|
import { resolve as resolve2, join as join6, dirname } from "path";
|
|
3145
3145
|
import { homedir as homedir6 } from "os";
|
|
3146
3146
|
import { fileURLToPath } from "url";
|
|
@@ -3243,24 +3243,6 @@ function readGuard() {
|
|
|
3243
3243
|
const bundled = join6(HOOKS_DIR, "guard.bundled.mjs");
|
|
3244
3244
|
return existsSync2(bundled) ? readFileSync4(bundled, "utf-8") : readHook("guard.mjs");
|
|
3245
3245
|
}
|
|
3246
|
-
function clearPolicyCache() {
|
|
3247
|
-
try {
|
|
3248
|
-
const dir = globalPaths().sgDir;
|
|
3249
|
-
let n = 0;
|
|
3250
|
-
for (const f of readdirSync(dir)) {
|
|
3251
|
-
if (f.startsWith(".policy-cache-") && f.endsWith(".json")) {
|
|
3252
|
-
try {
|
|
3253
|
-
rmSync(join6(dir, f), { force: true });
|
|
3254
|
-
n++;
|
|
3255
|
-
} catch {
|
|
3256
|
-
}
|
|
3257
|
-
}
|
|
3258
|
-
}
|
|
3259
|
-
return n;
|
|
3260
|
-
} catch {
|
|
3261
|
-
return 0;
|
|
3262
|
-
}
|
|
3263
|
-
}
|
|
3264
3246
|
function installGlobalQuiet() {
|
|
3265
3247
|
try {
|
|
3266
3248
|
const p = globalPaths();
|
|
@@ -3303,9 +3285,8 @@ function installGlobalQuiet() {
|
|
|
3303
3285
|
}
|
|
3304
3286
|
};
|
|
3305
3287
|
writeFileSync5(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
3306
|
-
clearPolicyCache();
|
|
3307
3288
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") lockProtected();
|
|
3308
|
-
return { ok: true, message: "guard installed
|
|
3289
|
+
return { ok: true, message: "guard installed (open a new session)" };
|
|
3309
3290
|
} catch (e) {
|
|
3310
3291
|
return { ok: false, message: e instanceof Error ? e.message : String(e) };
|
|
3311
3292
|
}
|
package/hooks/guard.bundled.mjs
CHANGED
|
@@ -6536,7 +6536,7 @@ import { resolve, join, dirname, isAbsolute } from "node:path";
|
|
|
6536
6536
|
import { homedir } from "node:os";
|
|
6537
6537
|
import { gunzipSync } from "node:zlib";
|
|
6538
6538
|
import { createHash } from "node:crypto";
|
|
6539
|
-
var HOOK_VERSION =
|
|
6539
|
+
var HOOK_VERSION = 42;
|
|
6540
6540
|
function localLogsOnly(security) {
|
|
6541
6541
|
if (security && typeof security === "object") {
|
|
6542
6542
|
const l = security.localLogs;
|
|
@@ -6804,17 +6804,16 @@ function blockTool(reason) {
|
|
|
6804
6804
|
}));
|
|
6805
6805
|
sgFinish(0);
|
|
6806
6806
|
} else {
|
|
6807
|
+
const msg = reason || "[SolonGate] Blocked by policy";
|
|
6807
6808
|
process.stdout.write(JSON.stringify({
|
|
6808
6809
|
hookSpecificOutput: {
|
|
6809
6810
|
hookEventName: "PreToolUse",
|
|
6810
6811
|
permissionDecision: "deny",
|
|
6811
|
-
|
|
6812
|
-
// with empty content, which the API rejects and crashes the agent. Always
|
|
6813
|
-
// carry a SolonGate-worded reason so the block says WHAT stopped it.
|
|
6814
|
-
permissionDecisionReason: reason || "[SolonGate] Blocked by policy"
|
|
6812
|
+
permissionDecisionReason: msg
|
|
6815
6813
|
}
|
|
6816
6814
|
}));
|
|
6817
|
-
|
|
6815
|
+
process.stderr.write(msg + "\n");
|
|
6816
|
+
sgFinish(2);
|
|
6818
6817
|
}
|
|
6819
6818
|
}
|
|
6820
6819
|
function allowTool() {
|
|
@@ -7924,7 +7923,8 @@ if (!REFRESH_MODE) {
|
|
|
7924
7923
|
sgFinish(0);
|
|
7925
7924
|
}
|
|
7926
7925
|
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: ghostHit } }));
|
|
7927
|
-
|
|
7926
|
+
process.stderr.write(ghostHit + "\n");
|
|
7927
|
+
sgFinish(2);
|
|
7928
7928
|
}
|
|
7929
7929
|
if (AGENT_TYPE !== "gemini-cli" && toolName === "Bash") {
|
|
7930
7930
|
const rw = ghostListingRewrite(args, securityCfg.ghost);
|
package/hooks/guard.mjs
CHANGED
|
@@ -32,7 +32,7 @@ import { createHash } from 'node:crypto';
|
|
|
32
32
|
// the installed hook self-updates when the cloud version is higher (see
|
|
33
33
|
// maybeSelfUpdate). This is what makes guard fixes propagate without a manual
|
|
34
34
|
// reinstall — the same trust model as the OPA WASM this hook already runs.
|
|
35
|
-
const HOOK_VERSION =
|
|
35
|
+
const HOOK_VERSION = 42;
|
|
36
36
|
|
|
37
37
|
// True when local log storage is ON. In that mode logs are kept LOCAL ONLY and
|
|
38
38
|
// nothing is sent to the cloud audit log.
|
|
@@ -385,23 +385,25 @@ function blockTool(reason) {
|
|
|
385
385
|
}));
|
|
386
386
|
sgFinish(0);
|
|
387
387
|
} else {
|
|
388
|
-
// Claude Code —
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
//
|
|
392
|
-
//
|
|
393
|
-
//
|
|
388
|
+
// Claude Code — emit the JSON PreToolUse deny on stdout AND exit 2 (reason on
|
|
389
|
+
// stderr). Exit 2 is the ONLY block Claude Code enforces in EVERY permission
|
|
390
|
+
// mode: JSON + exit 0 goes through the NORMAL permission flow, which
|
|
391
|
+
// AUTO-ACCEPT ("auto mode") OVERRIDES — the tool then runs despite the deny
|
|
392
|
+
// (observed: a DLP-blocked Write still landed on disk in auto mode). Exit 2
|
|
393
|
+
// hard-blocks BEFORE the permission system, in every mode. The JSON on stdout
|
|
394
|
+
// stays as the Windows/PowerShell fallback (there a native exit code may not
|
|
395
|
+
// propagate reliably; Claude Code parses the JSON instead). Reason is never
|
|
396
|
+
// empty — an empty deny becomes an is_error tool_result the API rejects.
|
|
397
|
+
const msg = reason || '[SolonGate] Blocked by policy';
|
|
394
398
|
process.stdout.write(JSON.stringify({
|
|
395
399
|
hookSpecificOutput: {
|
|
396
400
|
hookEventName: 'PreToolUse',
|
|
397
401
|
permissionDecision: 'deny',
|
|
398
|
-
|
|
399
|
-
// with empty content, which the API rejects and crashes the agent. Always
|
|
400
|
-
// carry a SolonGate-worded reason so the block says WHAT stopped it.
|
|
401
|
-
permissionDecisionReason: reason || '[SolonGate] Blocked by policy',
|
|
402
|
+
permissionDecisionReason: msg,
|
|
402
403
|
},
|
|
403
404
|
}));
|
|
404
|
-
|
|
405
|
+
process.stderr.write(msg + '\n');
|
|
406
|
+
sgFinish(2);
|
|
405
407
|
}
|
|
406
408
|
}
|
|
407
409
|
|
|
@@ -1761,10 +1763,13 @@ if (!REFRESH_MODE) { try { input += readFileSync(0, 'utf-8'); } catch {} }
|
|
|
1761
1763
|
} catch {}
|
|
1762
1764
|
await maybeSelfUpdate();
|
|
1763
1765
|
if (AGENT_TYPE === 'gemini-cli') { process.stdout.write(JSON.stringify({ decision: 'deny', reason: ghostHit })); sgFinish(0); }
|
|
1764
|
-
// Claude Code: JSON deny on stdout + exit
|
|
1765
|
-
//
|
|
1766
|
+
// Claude Code: JSON deny on stdout + exit 2 (reason on stderr). Exit 2 is
|
|
1767
|
+
// the only block enforced in auto-accept mode (see blockTool); the JSON is
|
|
1768
|
+
// the Windows fallback. ghostHit is a bare "No such file or directory", so
|
|
1769
|
+
// the stderr text keeps the stealth (looks like the path simply isn't there).
|
|
1766
1770
|
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: ghostHit } }));
|
|
1767
|
-
|
|
1771
|
+
process.stderr.write(ghostHit + '\n');
|
|
1772
|
+
sgFinish(2);
|
|
1768
1773
|
}
|
|
1769
1774
|
// No direct hit: if this is a listing command, rewrite it so hidden
|
|
1770
1775
|
// entries are filtered out of its output (Claude Code only).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.85",
|
|
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": {
|