@solongate/proxy 0.83.34 → 0.83.36
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/commands/format.d.ts +17 -0
- package/dist/commands/index.js +98 -20
- package/dist/commands/trace.d.ts +1 -0
- package/dist/index.js +161 -73
- package/package.json +7 -7
|
@@ -15,6 +15,23 @@ export declare const cyan: (s: string) => string;
|
|
|
15
15
|
* (used for long or continuation lines). Returns the whole block as one string.
|
|
16
16
|
*/
|
|
17
17
|
export declare function usage(title: string, tagline: string, rows: Array<[string, string?]>, footer?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* What a command's switch falls through to when the first positional is not one
|
|
20
|
+
* of its subcommands.
|
|
21
|
+
*
|
|
22
|
+
* Printing the usage block on its own was the old behaviour everywhere, and it
|
|
23
|
+
* reads as though the command simply has no default: a correct-looking help
|
|
24
|
+
* screen appears, and finding the mistake means diffing it against what you
|
|
25
|
+
* typed. Naming the token first costs one line and removes that step.
|
|
26
|
+
*
|
|
27
|
+
* `solongate ghost -g` is the case that made it obvious. The parser treats only
|
|
28
|
+
* `--x` as a flag, so a single-dash token arrives as a SUBCOMMAND, and the
|
|
29
|
+
* result was a help screen that looked like a successful command.
|
|
30
|
+
*
|
|
31
|
+
* The empty case still happens: a command invoked with a flag and no subcommand
|
|
32
|
+
* has nothing to name, and `Unknown subcommand: ""` would be worse than none.
|
|
33
|
+
*/
|
|
34
|
+
export declare function unknownSub(command: string, sub: string, usageText: string): number;
|
|
18
35
|
/** Color a decision string (ALLOW green, DENY/DENIED red). */
|
|
19
36
|
export declare function decisionColor(decision: string): string;
|
|
20
37
|
/**
|
package/dist/commands/index.js
CHANGED
|
@@ -606,6 +606,11 @@ function usage(title, tagline, rows, footer = "Add --json for machine-readable o
|
|
|
606
606
|
if (footer) lines.push("", ` ${c.dim}${footer}${c.reset}`);
|
|
607
607
|
return lines.join("\n");
|
|
608
608
|
}
|
|
609
|
+
function unknownSub(command, sub, usageText) {
|
|
610
|
+
if (sub) err(`${red(" \u2717 ")}Unknown ${command} subcommand: ${cyan(sub)}`);
|
|
611
|
+
err(usageText);
|
|
612
|
+
return 1;
|
|
613
|
+
}
|
|
609
614
|
function decisionColor(decision) {
|
|
610
615
|
const d = decision.toUpperCase();
|
|
611
616
|
if (d === "ALLOW") return green(d);
|
|
@@ -833,10 +838,7 @@ async function run(argv) {
|
|
|
833
838
|
return 0;
|
|
834
839
|
}
|
|
835
840
|
default:
|
|
836
|
-
|
|
837
|
-
`);
|
|
838
|
-
err(USAGE);
|
|
839
|
-
return 1;
|
|
841
|
+
return unknownSub("policy", sub, USAGE);
|
|
840
842
|
}
|
|
841
843
|
}
|
|
842
844
|
function printRules(rules) {
|
|
@@ -925,7 +927,7 @@ async function run2(argv) {
|
|
|
925
927
|
return 0;
|
|
926
928
|
}
|
|
927
929
|
default:
|
|
928
|
-
return
|
|
930
|
+
return unknownSub("ratelimit", sub, USAGE2);
|
|
929
931
|
}
|
|
930
932
|
}
|
|
931
933
|
|
|
@@ -1004,7 +1006,7 @@ async function run3(argv) {
|
|
|
1004
1006
|
return err(green(` \u2713 Removed custom pattern "${name}"`)), 0;
|
|
1005
1007
|
}
|
|
1006
1008
|
default:
|
|
1007
|
-
return
|
|
1009
|
+
return unknownSub("dlp", sub, USAGE3);
|
|
1008
1010
|
}
|
|
1009
1011
|
}
|
|
1010
1012
|
|
|
@@ -1089,7 +1091,7 @@ async function run4(argv) {
|
|
|
1089
1091
|
return err(green(` \u2713 Stopped hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s) left)`)), 0;
|
|
1090
1092
|
}
|
|
1091
1093
|
default:
|
|
1092
|
-
return
|
|
1094
|
+
return unknownSub("ghost", sub, USAGE4);
|
|
1093
1095
|
}
|
|
1094
1096
|
}
|
|
1095
1097
|
|
|
@@ -1158,7 +1160,7 @@ async function run5(argv) {
|
|
|
1158
1160
|
return 0;
|
|
1159
1161
|
}
|
|
1160
1162
|
default:
|
|
1161
|
-
return
|
|
1163
|
+
return unknownSub("stats", sub, USAGE5);
|
|
1162
1164
|
}
|
|
1163
1165
|
}
|
|
1164
1166
|
|
|
@@ -1435,6 +1437,80 @@ async function run7(argv) {
|
|
|
1435
1437
|
return bad ? 1 : 0;
|
|
1436
1438
|
}
|
|
1437
1439
|
|
|
1440
|
+
// src/commands/trace.ts
|
|
1441
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
1442
|
+
import { homedir as homedir5 } from "os";
|
|
1443
|
+
import { join as join5, resolve as resolve3 } from "path";
|
|
1444
|
+
var USAGE7 = usage("solongate trace", "what the guard saw here", [
|
|
1445
|
+
["trace", "the last evaluations in this directory"],
|
|
1446
|
+
["trace --limit N", "how many to show (default 20)"],
|
|
1447
|
+
["trace --json", "the raw records"]
|
|
1448
|
+
]);
|
|
1449
|
+
function projectKey(dir) {
|
|
1450
|
+
let h = 2166136261;
|
|
1451
|
+
const s = String(dir || "");
|
|
1452
|
+
for (let i = 0; i < s.length; i++) {
|
|
1453
|
+
h ^= s.charCodeAt(i);
|
|
1454
|
+
h = h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)) >>> 0;
|
|
1455
|
+
}
|
|
1456
|
+
return h.toString(16);
|
|
1457
|
+
}
|
|
1458
|
+
var countCell = (n) => {
|
|
1459
|
+
if (n === void 0 || n === null) return dim("-");
|
|
1460
|
+
if (n === 0) return red("0");
|
|
1461
|
+
return String(n);
|
|
1462
|
+
};
|
|
1463
|
+
async function run8(argv) {
|
|
1464
|
+
const { positionals, flags } = parse(argv);
|
|
1465
|
+
const sub = positionals[0] ?? "";
|
|
1466
|
+
if (sub === "help") return err(USAGE7), 0;
|
|
1467
|
+
if (sub) return unknownSub("trace", sub, USAGE7);
|
|
1468
|
+
const limit = flagNum(flags, "limit") || 20;
|
|
1469
|
+
const dir = join5(homedir5(), ".solongate", "projects", projectKey(resolve3(process.cwd())));
|
|
1470
|
+
let records;
|
|
1471
|
+
try {
|
|
1472
|
+
records = readFileSync6(join5(dir, ".eval-ring.jsonl"), "utf-8").split("\n").map((l) => l.trim()).filter(Boolean).map((l) => {
|
|
1473
|
+
try {
|
|
1474
|
+
return JSON.parse(l);
|
|
1475
|
+
} catch {
|
|
1476
|
+
return null;
|
|
1477
|
+
}
|
|
1478
|
+
}).filter((r) => r !== null).sort((a, b) => (b.ts ?? 0) - (a.ts ?? 0));
|
|
1479
|
+
} catch {
|
|
1480
|
+
err("");
|
|
1481
|
+
err(" No local records for this directory.");
|
|
1482
|
+
err(dim(` ${dir}`));
|
|
1483
|
+
err("");
|
|
1484
|
+
err(dim(" The guard writes one per evaluation, in the directory the call was"));
|
|
1485
|
+
err(dim(" made in. Run this from the project you are testing."));
|
|
1486
|
+
return 1;
|
|
1487
|
+
}
|
|
1488
|
+
records = records.slice(0, limit);
|
|
1489
|
+
if (flagBool(flags, "json")) return printJson(records), 0;
|
|
1490
|
+
err("");
|
|
1491
|
+
err(` ${records.length} local evaluation(s) \xB7 ${dim(dir)}`);
|
|
1492
|
+
table(
|
|
1493
|
+
["WHEN", "CLIENT", "TOOL", "PERM", "PATHS", "CMDS", "URLS", "ARGS", "MS"],
|
|
1494
|
+
records.map((r) => [
|
|
1495
|
+
r.ts ? new Date(r.ts).toTimeString().slice(0, 8) : "",
|
|
1496
|
+
r.client ?? "",
|
|
1497
|
+
r.tool ?? "",
|
|
1498
|
+
dim(r.perm ?? ""),
|
|
1499
|
+
countCell(r.paths),
|
|
1500
|
+
countCell(r.cmds),
|
|
1501
|
+
countCell(r.urls),
|
|
1502
|
+
// An empty list is not the same as an absent one: it means the guard
|
|
1503
|
+
// parsed the payload and found no arguments in it at all.
|
|
1504
|
+
r.args === void 0 ? dim("-") : r.args.length ? r.args.join(",") : red("(none)"),
|
|
1505
|
+
dim(`${Math.round(r.ms ?? 0)}ms`)
|
|
1506
|
+
])
|
|
1507
|
+
);
|
|
1508
|
+
err("");
|
|
1509
|
+
err(dim(" PATHS/CMDS/URLS is what the guard extracted from the call. A path rule"));
|
|
1510
|
+
err(dim(" cannot fire on a call whose PATHS is 0, whatever the rule says."));
|
|
1511
|
+
return 0;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1438
1514
|
// src/commands/watch.ts
|
|
1439
1515
|
import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync4 } from "fs";
|
|
1440
1516
|
var trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
@@ -1462,7 +1538,7 @@ function print(r, json) {
|
|
|
1462
1538
|
`${c.dim}[${time(r.at)}]${c.reset} ${src}${c.reset} ${dec}${r.decision.padEnd(6)}${c.reset} ${c.cyan}${trunc(r.tool, 12).padEnd(13)}${c.reset}${c.dim}${r.permission.slice(0, 4).padEnd(5)}${c.reset}${r.dlp ? c.red + "DLP! " + c.reset : ""}${c.dim}${trunc(r.agent || "-", 12).padEnd(13)}${r.detail}${c.reset}`
|
|
1463
1539
|
);
|
|
1464
1540
|
}
|
|
1465
|
-
async function
|
|
1541
|
+
async function run9(argv) {
|
|
1466
1542
|
const { flags } = parse(argv);
|
|
1467
1543
|
const json = flagBool(flags, "json");
|
|
1468
1544
|
const decisionFilter = (flagStr(flags, "filter") || "").toUpperCase();
|
|
@@ -1540,19 +1616,19 @@ async function run8(argv) {
|
|
|
1540
1616
|
}
|
|
1541
1617
|
|
|
1542
1618
|
// src/commands/alerts.ts
|
|
1543
|
-
var
|
|
1619
|
+
var USAGE8 = usage("solongate alerts", "spike alerts (Telegram / email)", [
|
|
1544
1620
|
["alerts list"],
|
|
1545
1621
|
["alerts add --signal deny|dlp|ratelimit|any --threshold N --window S"],
|
|
1546
1622
|
[" (--email <a> | --telegram <chatId> | --slack <url>)"],
|
|
1547
1623
|
["alerts remove <id>"]
|
|
1548
1624
|
]);
|
|
1549
|
-
async function
|
|
1625
|
+
async function run10(argv) {
|
|
1550
1626
|
const { positionals, flags } = parse(argv);
|
|
1551
1627
|
const sub = positionals[0] ?? "list";
|
|
1552
1628
|
const json = flagBool(flags, "json");
|
|
1553
1629
|
switch (sub) {
|
|
1554
1630
|
case "help":
|
|
1555
|
-
return err(
|
|
1631
|
+
return err(USAGE8), 0;
|
|
1556
1632
|
case "list": {
|
|
1557
1633
|
const { rules } = await api.settings.getAlerts();
|
|
1558
1634
|
if (json) return printJson(rules), 0;
|
|
@@ -1594,23 +1670,23 @@ async function run9(argv) {
|
|
|
1594
1670
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
1595
1671
|
}
|
|
1596
1672
|
default:
|
|
1597
|
-
return
|
|
1673
|
+
return unknownSub("alerts", sub, USAGE8);
|
|
1598
1674
|
}
|
|
1599
1675
|
}
|
|
1600
1676
|
|
|
1601
1677
|
// src/commands/webhooks.ts
|
|
1602
|
-
var
|
|
1678
|
+
var USAGE9 = usage("solongate webhooks", "event webhooks", [
|
|
1603
1679
|
["webhooks list"],
|
|
1604
1680
|
["webhooks add --url <https://\u2026> [--events denials|allowed|all]"],
|
|
1605
1681
|
["webhooks remove <id>"]
|
|
1606
1682
|
]);
|
|
1607
|
-
async function
|
|
1683
|
+
async function run11(argv) {
|
|
1608
1684
|
const { positionals, flags } = parse(argv);
|
|
1609
1685
|
const sub = positionals[0] ?? "list";
|
|
1610
1686
|
const json = flagBool(flags, "json");
|
|
1611
1687
|
switch (sub) {
|
|
1612
1688
|
case "help":
|
|
1613
|
-
return err(
|
|
1689
|
+
return err(USAGE9), 0;
|
|
1614
1690
|
case "list": {
|
|
1615
1691
|
const { webhooks } = await api.settings.getWebhooks();
|
|
1616
1692
|
if (json) return printJson(webhooks), 0;
|
|
@@ -1636,7 +1712,7 @@ async function run10(argv) {
|
|
|
1636
1712
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
1637
1713
|
}
|
|
1638
1714
|
default:
|
|
1639
|
-
return
|
|
1715
|
+
return unknownSub("webhooks", sub, USAGE9);
|
|
1640
1716
|
}
|
|
1641
1717
|
}
|
|
1642
1718
|
|
|
@@ -1661,12 +1737,14 @@ async function dispatch(command, argv) {
|
|
|
1661
1737
|
return runAgent(argv);
|
|
1662
1738
|
case "doctor":
|
|
1663
1739
|
return run7(argv);
|
|
1664
|
-
case "
|
|
1740
|
+
case "trace":
|
|
1665
1741
|
return run8(argv);
|
|
1666
|
-
case "
|
|
1742
|
+
case "watch":
|
|
1667
1743
|
return run9(argv);
|
|
1668
|
-
case "
|
|
1744
|
+
case "alerts":
|
|
1669
1745
|
return run10(argv);
|
|
1746
|
+
case "webhooks":
|
|
1747
|
+
return run11(argv);
|
|
1670
1748
|
default:
|
|
1671
1749
|
err(` Unknown command: ${command}`);
|
|
1672
1750
|
return 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function run(argv: string[]): Promise<number>;
|
package/dist/index.js
CHANGED
|
@@ -3043,12 +3043,12 @@ ${ctx.indent}`;
|
|
|
3043
3043
|
for (const {
|
|
3044
3044
|
format,
|
|
3045
3045
|
test,
|
|
3046
|
-
resolve:
|
|
3046
|
+
resolve: resolve8
|
|
3047
3047
|
} of tags) {
|
|
3048
3048
|
if (test) {
|
|
3049
3049
|
const match = str.match(test);
|
|
3050
3050
|
if (match) {
|
|
3051
|
-
let res =
|
|
3051
|
+
let res = resolve8.apply(null, match);
|
|
3052
3052
|
if (!(res instanceof Scalar)) res = new Scalar(res);
|
|
3053
3053
|
if (format) res.format = format;
|
|
3054
3054
|
return res;
|
|
@@ -7303,7 +7303,7 @@ async function runUpdateCommand() {
|
|
|
7303
7303
|
return 0;
|
|
7304
7304
|
}
|
|
7305
7305
|
function runGlobalInstall2(version) {
|
|
7306
|
-
return new Promise((
|
|
7306
|
+
return new Promise((resolve8) => {
|
|
7307
7307
|
try {
|
|
7308
7308
|
mkdirSync4(join5(homedir3(), ".solongate"), { recursive: true });
|
|
7309
7309
|
execFile(
|
|
@@ -7319,11 +7319,11 @@ ${output}
|
|
|
7319
7319
|
`, { flag: "a" });
|
|
7320
7320
|
} catch {
|
|
7321
7321
|
}
|
|
7322
|
-
|
|
7322
|
+
resolve8({ ok: !err2, needsAdmin: !!err2 && NEEDS_ADMIN_RE.test(output) });
|
|
7323
7323
|
}
|
|
7324
7324
|
);
|
|
7325
7325
|
} catch {
|
|
7326
|
-
|
|
7326
|
+
resolve8({ ok: false, needsAdmin: false });
|
|
7327
7327
|
}
|
|
7328
7328
|
});
|
|
7329
7329
|
}
|
|
@@ -7364,13 +7364,13 @@ function ownNodeModules() {
|
|
|
7364
7364
|
return null;
|
|
7365
7365
|
}
|
|
7366
7366
|
function globalInstallCheck() {
|
|
7367
|
-
prefixCheck ??= new Promise((
|
|
7367
|
+
prefixCheck ??= new Promise((resolve8) => {
|
|
7368
7368
|
try {
|
|
7369
7369
|
const dir = ownNodeModules();
|
|
7370
|
-
if (!dir) return
|
|
7371
|
-
access(dir, FS.W_OK, (e) =>
|
|
7370
|
+
if (!dir) return resolve8({ writable: null, dir: null });
|
|
7371
|
+
access(dir, FS.W_OK, (e) => resolve8({ writable: !e, dir }));
|
|
7372
7372
|
} catch {
|
|
7373
|
-
|
|
7373
|
+
resolve8({ writable: null, dir: null });
|
|
7374
7374
|
}
|
|
7375
7375
|
});
|
|
7376
7376
|
return prefixCheck;
|
|
@@ -9755,7 +9755,7 @@ function DryRunPanel({ focused }) {
|
|
|
9755
9755
|
const [off, setOff] = useState3(0);
|
|
9756
9756
|
const { cols, rows } = usePanelSize();
|
|
9757
9757
|
const selected = policies[Math.min(pi, Math.max(0, policies.length - 1))];
|
|
9758
|
-
function
|
|
9758
|
+
function run12(policyIdx = pi, lim = limit) {
|
|
9759
9759
|
const p = policies[policyIdx];
|
|
9760
9760
|
if (!p) return;
|
|
9761
9761
|
setRunning(true);
|
|
@@ -9773,7 +9773,7 @@ function DryRunPanel({ focused }) {
|
|
|
9773
9773
|
pendingPolicyId = null;
|
|
9774
9774
|
}
|
|
9775
9775
|
setPi(idx);
|
|
9776
|
-
|
|
9776
|
+
run12(idx, limit);
|
|
9777
9777
|
}, [policies.length]);
|
|
9778
9778
|
useInput2((input, key) => {
|
|
9779
9779
|
if (!focused || editLogs !== null) return;
|
|
@@ -9782,10 +9782,10 @@ function DryRunPanel({ focused }) {
|
|
|
9782
9782
|
else if (input === "p" || input === "P") {
|
|
9783
9783
|
const n = policies.length ? (pi + 1) % policies.length : 0;
|
|
9784
9784
|
setPi(n);
|
|
9785
|
-
|
|
9785
|
+
run12(n, limit);
|
|
9786
9786
|
} else if (input === "n" || input === "N") {
|
|
9787
9787
|
setEditLogs(String(limit));
|
|
9788
|
-
} else if (input === "r" || input === "R")
|
|
9788
|
+
} else if (input === "r" || input === "R") run12(pi, limit);
|
|
9789
9789
|
});
|
|
9790
9790
|
function commitLogs(raw) {
|
|
9791
9791
|
const cap = Math.min(MAX_LIMIT, totalLogs && totalLogs > 0 ? totalLogs : MAX_LIMIT);
|
|
@@ -9793,7 +9793,7 @@ function DryRunPanel({ focused }) {
|
|
|
9793
9793
|
const next = Number.isFinite(parsed) && parsed > 0 ? Math.min(parsed, cap) : limit;
|
|
9794
9794
|
setEditLogs(null);
|
|
9795
9795
|
setLimit(next);
|
|
9796
|
-
|
|
9796
|
+
run12(pi, next);
|
|
9797
9797
|
}
|
|
9798
9798
|
const w = Math.max(40, cols);
|
|
9799
9799
|
const lines = [];
|
|
@@ -11090,7 +11090,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
11090
11090
|
const sessLoading = source === "cloud" ? agentsQ.loading : localQ.loading;
|
|
11091
11091
|
const doDelete = (kind) => {
|
|
11092
11092
|
setMsg({ text: "deleting\u2026", level: "ok" });
|
|
11093
|
-
const
|
|
11093
|
+
const run12 = async () => {
|
|
11094
11094
|
if (source === "cloud") {
|
|
11095
11095
|
if (kind === "one") {
|
|
11096
11096
|
if (!current) throw new Error("nothing selected");
|
|
@@ -11106,14 +11106,14 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
11106
11106
|
localQ.reload();
|
|
11107
11107
|
}
|
|
11108
11108
|
};
|
|
11109
|
-
|
|
11109
|
+
run12().then(() => {
|
|
11110
11110
|
setMsg({ text: kind === "one" ? "\u2713 entry deleted" : `\u2713 ALL ${source} logs deleted`, level: "ok" });
|
|
11111
11111
|
toTop();
|
|
11112
11112
|
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
11113
11113
|
};
|
|
11114
11114
|
const doExport = (kind) => {
|
|
11115
11115
|
setMsg({ text: "exporting\u2026", level: "ok" });
|
|
11116
|
-
const
|
|
11116
|
+
const run12 = async () => {
|
|
11117
11117
|
const dir = join11(homedir9(), ".solongate");
|
|
11118
11118
|
const file = join11(dir, `audit-export-${source}.jsonl`);
|
|
11119
11119
|
let rows2;
|
|
@@ -11126,7 +11126,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
11126
11126
|
writeFileSync9(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
|
|
11127
11127
|
return { n: rows2.length, file };
|
|
11128
11128
|
};
|
|
11129
|
-
|
|
11129
|
+
run12().then(({ n, file }) => setMsg({ text: `\u2713 exported ${n} rows \u2192 ${file}`, level: "ok" })).catch((e) => setMsg({ text: "\u2717 export failed: " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
11130
11130
|
};
|
|
11131
11131
|
useInput6(
|
|
11132
11132
|
(input, key) => {
|
|
@@ -11620,6 +11620,11 @@ function usage(title, tagline, rows, footer = "Add --json for machine-readable o
|
|
|
11620
11620
|
if (footer) lines.push("", ` ${c.dim}${footer}${c.reset}`);
|
|
11621
11621
|
return lines.join("\n");
|
|
11622
11622
|
}
|
|
11623
|
+
function unknownSub(command, sub, usageText) {
|
|
11624
|
+
if (sub) err(`${red(" \u2717 ")}Unknown ${command} subcommand: ${cyan(sub)}`);
|
|
11625
|
+
err(usageText);
|
|
11626
|
+
return 1;
|
|
11627
|
+
}
|
|
11623
11628
|
function decisionColor2(decision) {
|
|
11624
11629
|
const d = decision.toUpperCase();
|
|
11625
11630
|
if (d === "ALLOW") return green(d);
|
|
@@ -12008,7 +12013,7 @@ function SettingsPanel({
|
|
|
12008
12013
|
guardQ.reload();
|
|
12009
12014
|
selfQ.reload();
|
|
12010
12015
|
};
|
|
12011
|
-
const
|
|
12016
|
+
const run12 = (label, fn, reload) => {
|
|
12012
12017
|
if (busy) return;
|
|
12013
12018
|
setBusy(true);
|
|
12014
12019
|
setMsg({ text: label + "\u2026", level: "ok" });
|
|
@@ -12090,8 +12095,8 @@ function SettingsPanel({
|
|
|
12090
12095
|
const body = { signal: editor.signal, threshold: editor.threshold, windowSeconds: editor.windowSeconds, enabled: editor.enabled, ...channels };
|
|
12091
12096
|
const id = editor.id;
|
|
12092
12097
|
setEditor(null);
|
|
12093
|
-
if (id)
|
|
12094
|
-
else
|
|
12098
|
+
if (id) run12("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
12099
|
+
else run12(`${editor.channel} alert added`, () => api.settings.createAlert({ name: "SolonGate alert", ...body }), alertQ.reload);
|
|
12095
12100
|
};
|
|
12096
12101
|
const activate = (r) => {
|
|
12097
12102
|
if (r.kind === "acct") {
|
|
@@ -12165,7 +12170,7 @@ function SettingsPanel({
|
|
|
12165
12170
|
})();
|
|
12166
12171
|
} else if (r.kind === "self") {
|
|
12167
12172
|
if (!selfProt) return;
|
|
12168
|
-
|
|
12173
|
+
run12(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
12169
12174
|
} else if (r.kind === "cli-update") {
|
|
12170
12175
|
if (updBusy) return;
|
|
12171
12176
|
setUpdBusy(true);
|
|
@@ -12212,7 +12217,7 @@ function SettingsPanel({
|
|
|
12212
12217
|
setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
|
|
12213
12218
|
return;
|
|
12214
12219
|
}
|
|
12215
|
-
|
|
12220
|
+
run12(local.enabled ? "local logs disabled" : "local logs enabled", () => api.settings.setLocalLogs({ enabled: !local.enabled, path: local.path }), localQ.reload);
|
|
12216
12221
|
} else if (r.kind === "ll-path") {
|
|
12217
12222
|
setInput(local?.path ?? "");
|
|
12218
12223
|
setEditing("path");
|
|
@@ -12223,7 +12228,7 @@ function SettingsPanel({
|
|
|
12223
12228
|
next.running ? { text: `\u2713 dashboard link running on 127.0.0.1:${next.port} \u2014 keeps running after you close the dataroom`, level: "ok" } : { text: "\u2713 dashboard link stopped (disabled until you start it again)", level: "ok" }
|
|
12224
12229
|
);
|
|
12225
12230
|
} else if (r.kind === "wh") {
|
|
12226
|
-
|
|
12231
|
+
run12(r.wh.enabled ? "webhook disabled" : "webhook enabled", () => api.settings.updateWebhook(r.wh.id, { enabled: !r.wh.enabled }), whQ.reload);
|
|
12227
12232
|
} else if (r.kind === "wh-add") {
|
|
12228
12233
|
setInput("");
|
|
12229
12234
|
setEditing("wh-url");
|
|
@@ -12242,7 +12247,7 @@ function SettingsPanel({
|
|
|
12242
12247
|
setEditing(null);
|
|
12243
12248
|
if (which === "path") {
|
|
12244
12249
|
const enabled = (local?.enabled ?? false) && v.length > 0;
|
|
12245
|
-
|
|
12250
|
+
run12(v ? `path saved${enabled ? "" : " (press enter on enabled to turn on)"}` : "path cleared (local logs off)", () => api.settings.setLocalLogs({ enabled, path: v }), localQ.reload);
|
|
12246
12251
|
} else if (which === "wh-url") {
|
|
12247
12252
|
const url = v.replace(/^["'<]+|["'>]+$/g, "").trim();
|
|
12248
12253
|
if (!url) return;
|
|
@@ -12250,7 +12255,7 @@ function SettingsPanel({
|
|
|
12250
12255
|
setMsg({ text: "\u2717 webhook url must start with http:// or https://", level: "bad" });
|
|
12251
12256
|
return;
|
|
12252
12257
|
}
|
|
12253
|
-
|
|
12258
|
+
run12("webhook added", () => api.settings.createWebhook({ url, events: "denials" }), whQ.reload);
|
|
12254
12259
|
} else if (which === "alert-target" && editor) {
|
|
12255
12260
|
setEditor({ ...editor, target: v, field: 1 });
|
|
12256
12261
|
}
|
|
@@ -12305,7 +12310,7 @@ function SettingsPanel({
|
|
|
12305
12310
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
12306
12311
|
refreshAccounts();
|
|
12307
12312
|
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "auto-update" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
12308
|
-
if (cur.kind === "alert")
|
|
12313
|
+
if (cur.kind === "alert") run12(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
12309
12314
|
else activate(cur);
|
|
12310
12315
|
}
|
|
12311
12316
|
} else if (inp === "x" && cur.kind === "acct") {
|
|
@@ -12336,13 +12341,13 @@ function SettingsPanel({
|
|
|
12336
12341
|
refreshAccounts();
|
|
12337
12342
|
onAccountsChanged?.();
|
|
12338
12343
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
12339
|
-
|
|
12344
|
+
run12("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
12340
12345
|
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
12341
12346
|
}), whQ.reload);
|
|
12342
12347
|
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
12343
12348
|
else if (inp === "e" && cur.kind === "wh") {
|
|
12344
12349
|
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
12345
|
-
|
|
12350
|
+
run12(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
12346
12351
|
} else if (inp === "e" && cur.kind === "alert") {
|
|
12347
12352
|
const ch = alertChannel(cur.rule);
|
|
12348
12353
|
if (ch) openAlertEditor(ch, cur.rule);
|
|
@@ -12379,10 +12384,10 @@ function SettingsPanel({
|
|
|
12379
12384
|
setConfirmDel(null);
|
|
12380
12385
|
if (cur.kind === "wh") {
|
|
12381
12386
|
const id = cur.wh.id;
|
|
12382
|
-
|
|
12387
|
+
run12("webhook deleted", () => api.settings.deleteWebhook(id).then(() => setHidden((h) => new Set(h).add("wh:" + id))), whQ.reload);
|
|
12383
12388
|
} else {
|
|
12384
12389
|
const id = cur.rule.id;
|
|
12385
|
-
|
|
12390
|
+
run12("alert deleted", () => api.settings.deleteAlert(id).then(() => setHidden((h) => new Set(h).add("alert:" + id))), alertQ.reload);
|
|
12386
12391
|
}
|
|
12387
12392
|
} else if (inp === "r") reloadAll();
|
|
12388
12393
|
},
|
|
@@ -12770,9 +12775,9 @@ function App() {
|
|
|
12770
12775
|
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
12771
12776
|
useEffect8(() => {
|
|
12772
12777
|
let alive = true;
|
|
12773
|
-
const
|
|
12774
|
-
|
|
12775
|
-
const t = setInterval(
|
|
12778
|
+
const run12 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
12779
|
+
run12();
|
|
12780
|
+
const t = setInterval(run12, 30 * 6e4);
|
|
12776
12781
|
return () => {
|
|
12777
12782
|
alive = false;
|
|
12778
12783
|
clearInterval(t);
|
|
@@ -13127,10 +13132,7 @@ async function run2(argv) {
|
|
|
13127
13132
|
return 0;
|
|
13128
13133
|
}
|
|
13129
13134
|
default:
|
|
13130
|
-
|
|
13131
|
-
`);
|
|
13132
|
-
err(USAGE);
|
|
13133
|
-
return 1;
|
|
13135
|
+
return unknownSub("policy", sub, USAGE);
|
|
13134
13136
|
}
|
|
13135
13137
|
}
|
|
13136
13138
|
function printRules(rules) {
|
|
@@ -13234,7 +13236,7 @@ async function run3(argv) {
|
|
|
13234
13236
|
return 0;
|
|
13235
13237
|
}
|
|
13236
13238
|
default:
|
|
13237
|
-
return
|
|
13239
|
+
return unknownSub("ratelimit", sub, USAGE2);
|
|
13238
13240
|
}
|
|
13239
13241
|
}
|
|
13240
13242
|
var USAGE2, modeColor2;
|
|
@@ -13319,7 +13321,7 @@ async function run4(argv) {
|
|
|
13319
13321
|
return err(green(` \u2713 Removed custom pattern "${name}"`)), 0;
|
|
13320
13322
|
}
|
|
13321
13323
|
default:
|
|
13322
|
-
return
|
|
13324
|
+
return unknownSub("dlp", sub, USAGE3);
|
|
13323
13325
|
}
|
|
13324
13326
|
}
|
|
13325
13327
|
var USAGE3, modeColor3;
|
|
@@ -13413,7 +13415,7 @@ async function run5(argv) {
|
|
|
13413
13415
|
return err(green(` \u2713 Stopped hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s) left)`)), 0;
|
|
13414
13416
|
}
|
|
13415
13417
|
default:
|
|
13416
|
-
return
|
|
13418
|
+
return unknownSub("ghost", sub, USAGE4);
|
|
13417
13419
|
}
|
|
13418
13420
|
}
|
|
13419
13421
|
var USAGE4, modeColor4, isBlanketGlob;
|
|
@@ -13495,7 +13497,7 @@ async function run6(argv) {
|
|
|
13495
13497
|
return 0;
|
|
13496
13498
|
}
|
|
13497
13499
|
default:
|
|
13498
|
-
return
|
|
13500
|
+
return unknownSub("stats", sub, USAGE5);
|
|
13499
13501
|
}
|
|
13500
13502
|
}
|
|
13501
13503
|
var USAGE5;
|
|
@@ -13643,6 +13645,88 @@ var init_agents2 = __esm({
|
|
|
13643
13645
|
}
|
|
13644
13646
|
});
|
|
13645
13647
|
|
|
13648
|
+
// src/commands/trace.ts
|
|
13649
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
13650
|
+
import { homedir as homedir12 } from "os";
|
|
13651
|
+
import { join as join14, resolve as resolve6 } from "path";
|
|
13652
|
+
function projectKey2(dir) {
|
|
13653
|
+
let h = 2166136261;
|
|
13654
|
+
const s = String(dir || "");
|
|
13655
|
+
for (let i = 0; i < s.length; i++) {
|
|
13656
|
+
h ^= s.charCodeAt(i);
|
|
13657
|
+
h = h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)) >>> 0;
|
|
13658
|
+
}
|
|
13659
|
+
return h.toString(16);
|
|
13660
|
+
}
|
|
13661
|
+
async function run8(argv) {
|
|
13662
|
+
const { positionals, flags } = parse(argv);
|
|
13663
|
+
const sub = positionals[0] ?? "";
|
|
13664
|
+
if (sub === "help") return err(USAGE7), 0;
|
|
13665
|
+
if (sub) return unknownSub("trace", sub, USAGE7);
|
|
13666
|
+
const limit = flagNum(flags, "limit") || 20;
|
|
13667
|
+
const dir = join14(homedir12(), ".solongate", "projects", projectKey2(resolve6(process.cwd())));
|
|
13668
|
+
let records;
|
|
13669
|
+
try {
|
|
13670
|
+
records = readFileSync12(join14(dir, ".eval-ring.jsonl"), "utf-8").split("\n").map((l) => l.trim()).filter(Boolean).map((l) => {
|
|
13671
|
+
try {
|
|
13672
|
+
return JSON.parse(l);
|
|
13673
|
+
} catch {
|
|
13674
|
+
return null;
|
|
13675
|
+
}
|
|
13676
|
+
}).filter((r) => r !== null).sort((a, b) => (b.ts ?? 0) - (a.ts ?? 0));
|
|
13677
|
+
} catch {
|
|
13678
|
+
err("");
|
|
13679
|
+
err(" No local records for this directory.");
|
|
13680
|
+
err(dim(` ${dir}`));
|
|
13681
|
+
err("");
|
|
13682
|
+
err(dim(" The guard writes one per evaluation, in the directory the call was"));
|
|
13683
|
+
err(dim(" made in. Run this from the project you are testing."));
|
|
13684
|
+
return 1;
|
|
13685
|
+
}
|
|
13686
|
+
records = records.slice(0, limit);
|
|
13687
|
+
if (flagBool(flags, "json")) return printJson(records), 0;
|
|
13688
|
+
err("");
|
|
13689
|
+
err(` ${records.length} local evaluation(s) \xB7 ${dim(dir)}`);
|
|
13690
|
+
table(
|
|
13691
|
+
["WHEN", "CLIENT", "TOOL", "PERM", "PATHS", "CMDS", "URLS", "ARGS", "MS"],
|
|
13692
|
+
records.map((r) => [
|
|
13693
|
+
r.ts ? new Date(r.ts).toTimeString().slice(0, 8) : "",
|
|
13694
|
+
r.client ?? "",
|
|
13695
|
+
r.tool ?? "",
|
|
13696
|
+
dim(r.perm ?? ""),
|
|
13697
|
+
countCell(r.paths),
|
|
13698
|
+
countCell(r.cmds),
|
|
13699
|
+
countCell(r.urls),
|
|
13700
|
+
// An empty list is not the same as an absent one: it means the guard
|
|
13701
|
+
// parsed the payload and found no arguments in it at all.
|
|
13702
|
+
r.args === void 0 ? dim("-") : r.args.length ? r.args.join(",") : red("(none)"),
|
|
13703
|
+
dim(`${Math.round(r.ms ?? 0)}ms`)
|
|
13704
|
+
])
|
|
13705
|
+
);
|
|
13706
|
+
err("");
|
|
13707
|
+
err(dim(" PATHS/CMDS/URLS is what the guard extracted from the call. A path rule"));
|
|
13708
|
+
err(dim(" cannot fire on a call whose PATHS is 0, whatever the rule says."));
|
|
13709
|
+
return 0;
|
|
13710
|
+
}
|
|
13711
|
+
var USAGE7, countCell;
|
|
13712
|
+
var init_trace = __esm({
|
|
13713
|
+
"src/commands/trace.ts"() {
|
|
13714
|
+
"use strict";
|
|
13715
|
+
init_args();
|
|
13716
|
+
init_format();
|
|
13717
|
+
USAGE7 = usage("solongate trace", "what the guard saw here", [
|
|
13718
|
+
["trace", "the last evaluations in this directory"],
|
|
13719
|
+
["trace --limit N", "how many to show (default 20)"],
|
|
13720
|
+
["trace --json", "the raw records"]
|
|
13721
|
+
]);
|
|
13722
|
+
countCell = (n) => {
|
|
13723
|
+
if (n === void 0 || n === null) return dim("-");
|
|
13724
|
+
if (n === 0) return red("0");
|
|
13725
|
+
return String(n);
|
|
13726
|
+
};
|
|
13727
|
+
}
|
|
13728
|
+
});
|
|
13729
|
+
|
|
13646
13730
|
// src/commands/watch.ts
|
|
13647
13731
|
import { closeSync as closeSync2, existsSync as existsSync7, openSync as openSync4, readSync as readSync2, statSync as statSync4 } from "fs";
|
|
13648
13732
|
function tailLocal(file, maxBytes = 131072) {
|
|
@@ -13668,7 +13752,7 @@ function print(r, json) {
|
|
|
13668
13752
|
`${c.dim}[${time(r.at)}]${c.reset} ${src}${c.reset} ${dec}${r.decision.padEnd(6)}${c.reset} ${c.cyan}${trunc(r.tool, 12).padEnd(13)}${c.reset}${c.dim}${r.permission.slice(0, 4).padEnd(5)}${c.reset}${r.dlp ? c.red + "DLP! " + c.reset : ""}${c.dim}${trunc(r.agent || "-", 12).padEnd(13)}${r.detail}${c.reset}`
|
|
13669
13753
|
);
|
|
13670
13754
|
}
|
|
13671
|
-
async function
|
|
13755
|
+
async function run9(argv) {
|
|
13672
13756
|
const { flags } = parse(argv);
|
|
13673
13757
|
const json = flagBool(flags, "json");
|
|
13674
13758
|
const decisionFilter = (flagStr(flags, "filter") || "").toUpperCase();
|
|
@@ -13759,13 +13843,13 @@ var init_watch = __esm({
|
|
|
13759
13843
|
});
|
|
13760
13844
|
|
|
13761
13845
|
// src/commands/alerts.ts
|
|
13762
|
-
async function
|
|
13846
|
+
async function run10(argv) {
|
|
13763
13847
|
const { positionals, flags } = parse(argv);
|
|
13764
13848
|
const sub = positionals[0] ?? "list";
|
|
13765
13849
|
const json = flagBool(flags, "json");
|
|
13766
13850
|
switch (sub) {
|
|
13767
13851
|
case "help":
|
|
13768
|
-
return err(
|
|
13852
|
+
return err(USAGE8), 0;
|
|
13769
13853
|
case "list": {
|
|
13770
13854
|
const { rules } = await api.settings.getAlerts();
|
|
13771
13855
|
if (json) return printJson(rules), 0;
|
|
@@ -13807,17 +13891,17 @@ async function run9(argv) {
|
|
|
13807
13891
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
13808
13892
|
}
|
|
13809
13893
|
default:
|
|
13810
|
-
return
|
|
13894
|
+
return unknownSub("alerts", sub, USAGE8);
|
|
13811
13895
|
}
|
|
13812
13896
|
}
|
|
13813
|
-
var
|
|
13897
|
+
var USAGE8;
|
|
13814
13898
|
var init_alerts = __esm({
|
|
13815
13899
|
"src/commands/alerts.ts"() {
|
|
13816
13900
|
"use strict";
|
|
13817
13901
|
init_api_client();
|
|
13818
13902
|
init_args();
|
|
13819
13903
|
init_format();
|
|
13820
|
-
|
|
13904
|
+
USAGE8 = usage("solongate alerts", "spike alerts (Telegram / email)", [
|
|
13821
13905
|
["alerts list"],
|
|
13822
13906
|
["alerts add --signal deny|dlp|ratelimit|any --threshold N --window S"],
|
|
13823
13907
|
[" (--email <a> | --telegram <chatId> | --slack <url>)"],
|
|
@@ -13827,13 +13911,13 @@ var init_alerts = __esm({
|
|
|
13827
13911
|
});
|
|
13828
13912
|
|
|
13829
13913
|
// src/commands/webhooks.ts
|
|
13830
|
-
async function
|
|
13914
|
+
async function run11(argv) {
|
|
13831
13915
|
const { positionals, flags } = parse(argv);
|
|
13832
13916
|
const sub = positionals[0] ?? "list";
|
|
13833
13917
|
const json = flagBool(flags, "json");
|
|
13834
13918
|
switch (sub) {
|
|
13835
13919
|
case "help":
|
|
13836
|
-
return err(
|
|
13920
|
+
return err(USAGE9), 0;
|
|
13837
13921
|
case "list": {
|
|
13838
13922
|
const { webhooks } = await api.settings.getWebhooks();
|
|
13839
13923
|
if (json) return printJson(webhooks), 0;
|
|
@@ -13859,17 +13943,17 @@ async function run10(argv) {
|
|
|
13859
13943
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
13860
13944
|
}
|
|
13861
13945
|
default:
|
|
13862
|
-
return
|
|
13946
|
+
return unknownSub("webhooks", sub, USAGE9);
|
|
13863
13947
|
}
|
|
13864
13948
|
}
|
|
13865
|
-
var
|
|
13949
|
+
var USAGE9;
|
|
13866
13950
|
var init_webhooks = __esm({
|
|
13867
13951
|
"src/commands/webhooks.ts"() {
|
|
13868
13952
|
"use strict";
|
|
13869
13953
|
init_api_client();
|
|
13870
13954
|
init_args();
|
|
13871
13955
|
init_format();
|
|
13872
|
-
|
|
13956
|
+
USAGE9 = usage("solongate webhooks", "event webhooks", [
|
|
13873
13957
|
["webhooks list"],
|
|
13874
13958
|
["webhooks add --url <https://\u2026> [--events denials|allowed|all]"],
|
|
13875
13959
|
["webhooks remove <id>"]
|
|
@@ -13903,12 +13987,14 @@ async function dispatch(command, argv) {
|
|
|
13903
13987
|
return runAgent(argv);
|
|
13904
13988
|
case "doctor":
|
|
13905
13989
|
return run(argv);
|
|
13906
|
-
case "
|
|
13990
|
+
case "trace":
|
|
13907
13991
|
return run8(argv);
|
|
13908
|
-
case "
|
|
13992
|
+
case "watch":
|
|
13909
13993
|
return run9(argv);
|
|
13910
|
-
case "
|
|
13994
|
+
case "alerts":
|
|
13911
13995
|
return run10(argv);
|
|
13996
|
+
case "webhooks":
|
|
13997
|
+
return run11(argv);
|
|
13912
13998
|
default:
|
|
13913
13999
|
err(` Unknown command: ${command}`);
|
|
13914
14000
|
return 1;
|
|
@@ -13945,6 +14031,7 @@ var init_commands = __esm({
|
|
|
13945
14031
|
init_audit2();
|
|
13946
14032
|
init_agents2();
|
|
13947
14033
|
init_doctor();
|
|
14034
|
+
init_trace();
|
|
13948
14035
|
init_watch();
|
|
13949
14036
|
init_alerts();
|
|
13950
14037
|
init_webhooks();
|
|
@@ -13958,9 +14045,9 @@ __export(logs_server_exports, {
|
|
|
13958
14045
|
runLogsServer: () => runLogsServer
|
|
13959
14046
|
});
|
|
13960
14047
|
import { createServer } from "http";
|
|
13961
|
-
import { readFileSync as
|
|
13962
|
-
import { resolve as
|
|
13963
|
-
import { homedir as
|
|
14048
|
+
import { readFileSync as readFileSync13, statSync as statSync5 } from "fs";
|
|
14049
|
+
import { resolve as resolve7, join as join15, isAbsolute as isAbsolute2 } from "path";
|
|
14050
|
+
import { homedir as homedir13 } from "os";
|
|
13964
14051
|
import { readdirSync as readdirSync3 } from "fs";
|
|
13965
14052
|
function allowedOrigins() {
|
|
13966
14053
|
const base = [
|
|
@@ -13977,15 +14064,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
13977
14064
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
13978
14065
|
if (!dir) return null;
|
|
13979
14066
|
if (isAbsolute2(dir)) return dir;
|
|
13980
|
-
return
|
|
14067
|
+
return resolve7(homedir13(), ".solongate", "local-logs");
|
|
13981
14068
|
}
|
|
13982
14069
|
async function findLogDir() {
|
|
13983
|
-
const base =
|
|
14070
|
+
const base = resolve7(homedir13(), ".solongate");
|
|
13984
14071
|
try {
|
|
13985
14072
|
const files = readdirSync3(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
13986
14073
|
for (const f of files) {
|
|
13987
14074
|
try {
|
|
13988
|
-
const c2 = JSON.parse(
|
|
14075
|
+
const c2 = JSON.parse(readFileSync13(join15(base, f), "utf-8"));
|
|
13989
14076
|
const p = c2?.security?.localLogs?.path;
|
|
13990
14077
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
13991
14078
|
} catch {
|
|
@@ -13994,7 +14081,7 @@ async function findLogDir() {
|
|
|
13994
14081
|
} catch {
|
|
13995
14082
|
}
|
|
13996
14083
|
try {
|
|
13997
|
-
const cfgRaw =
|
|
14084
|
+
const cfgRaw = readFileSync13(join15(base, "cloud-guard.json"), "utf-8");
|
|
13998
14085
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
13999
14086
|
if (apiKey) {
|
|
14000
14087
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -14023,7 +14110,7 @@ function setCors(req, res) {
|
|
|
14023
14110
|
}
|
|
14024
14111
|
function fileInfo(dir) {
|
|
14025
14112
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
14026
|
-
const file =
|
|
14113
|
+
const file = join15(dir, LOG_FILENAME);
|
|
14027
14114
|
try {
|
|
14028
14115
|
const st = statSync5(file);
|
|
14029
14116
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
@@ -14106,7 +14193,7 @@ async function runLogsServer() {
|
|
|
14106
14193
|
return;
|
|
14107
14194
|
}
|
|
14108
14195
|
try {
|
|
14109
|
-
const text =
|
|
14196
|
+
const text = readFileSync13(info.file, "utf-8");
|
|
14110
14197
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
|
|
14111
14198
|
res.end(text);
|
|
14112
14199
|
} catch {
|
|
@@ -14159,9 +14246,9 @@ var init_logs_server = __esm({
|
|
|
14159
14246
|
});
|
|
14160
14247
|
|
|
14161
14248
|
// src/index.ts
|
|
14162
|
-
import { readFileSync as
|
|
14249
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
14163
14250
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
14164
|
-
import { dirname as dirname4, join as
|
|
14251
|
+
import { dirname as dirname4, join as join16 } from "path";
|
|
14165
14252
|
|
|
14166
14253
|
// src/config.ts
|
|
14167
14254
|
import { readFileSync, existsSync } from "fs";
|
|
@@ -16937,7 +17024,7 @@ var Mutex = class {
|
|
|
16937
17024
|
this.locked = true;
|
|
16938
17025
|
return;
|
|
16939
17026
|
}
|
|
16940
|
-
return new Promise((
|
|
17027
|
+
return new Promise((resolve8, reject) => {
|
|
16941
17028
|
const timer = setTimeout(() => {
|
|
16942
17029
|
const idx = this.queue.indexOf(onReady);
|
|
16943
17030
|
if (idx !== -1) this.queue.splice(idx, 1);
|
|
@@ -16945,7 +17032,7 @@ var Mutex = class {
|
|
|
16945
17032
|
}, timeoutMs);
|
|
16946
17033
|
const onReady = () => {
|
|
16947
17034
|
clearTimeout(timer);
|
|
16948
|
-
|
|
17035
|
+
resolve8();
|
|
16949
17036
|
};
|
|
16950
17037
|
this.queue.push(onReady);
|
|
16951
17038
|
});
|
|
@@ -17537,7 +17624,7 @@ ${msg.content.text}`;
|
|
|
17537
17624
|
|
|
17538
17625
|
// src/index.ts
|
|
17539
17626
|
init_cli_utils();
|
|
17540
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["update", "repair", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "ghost", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
|
|
17627
|
+
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["update", "repair", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "ghost", "stats", "audit", "sessions", "session", "doctor", "trace", "watch", "alerts", "webhooks", "dataroom"]);
|
|
17541
17628
|
var CLI_INFO_ARGS = /* @__PURE__ */ new Set(["login", "help", "--help", "-h", "--version", "-v", "version"]);
|
|
17542
17629
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "") || CLI_INFO_ARGS.has(process.argv[2] ?? "");
|
|
17543
17630
|
if (!IS_HUMAN_CLI) {
|
|
@@ -17556,8 +17643,8 @@ if (!IS_HUMAN_CLI) {
|
|
|
17556
17643
|
}
|
|
17557
17644
|
var PKG_VERSION = (() => {
|
|
17558
17645
|
try {
|
|
17559
|
-
const p =
|
|
17560
|
-
return JSON.parse(
|
|
17646
|
+
const p = join16(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
17647
|
+
return JSON.parse(readFileSync14(p, "utf-8")).version || "unknown";
|
|
17561
17648
|
} catch {
|
|
17562
17649
|
return "unknown";
|
|
17563
17650
|
}
|
|
@@ -17602,6 +17689,7 @@ function printHelp() {
|
|
|
17602
17689
|
cmd("update auto on|off", "background auto-update (default off \u2014 on macOS npm -g often needs sudo)");
|
|
17603
17690
|
cmd("repair", "restore the guard + hook + settings files if they were deleted or disarmed");
|
|
17604
17691
|
cmd("doctor", "health check: login, policy, guard, local logs");
|
|
17692
|
+
cmd("trace [--limit N]", "what the guard saw in this directory, allows included");
|
|
17605
17693
|
cmd("doctor --json", "the same health check as machine-readable JSON");
|
|
17606
17694
|
cmd("logs-server start", "start the local audit-log service for the dashboard (background)");
|
|
17607
17695
|
cmd("logs-server stop", "stop AND disable it (only this makes it stay down)");
|
|
@@ -17731,7 +17819,7 @@ async function main() {
|
|
|
17731
17819
|
await launchTui2();
|
|
17732
17820
|
return;
|
|
17733
17821
|
}
|
|
17734
|
-
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "ghost", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
|
|
17822
|
+
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "ghost", "stats", "audit", "sessions", "session", "doctor", "trace", "watch", "alerts", "webhooks"]);
|
|
17735
17823
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
17736
17824
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
17737
17825
|
const code = await runCommand2(subcommand, process.argv.slice(3));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.83.
|
|
3
|
+
"version": "0.83.36",
|
|
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.36",
|
|
65
|
+
"@solongate/guard-linux-arm64": "0.83.36",
|
|
66
|
+
"@solongate/guard-darwin-x64": "0.83.36",
|
|
67
|
+
"@solongate/guard-darwin-arm64": "0.83.36",
|
|
68
|
+
"@solongate/guard-win32-x64": "0.83.36",
|
|
69
|
+
"@solongate/guard-win32-arm64": "0.83.36"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"@modelcontextprotocol/sdk": "^1.26.0",
|