@solongate/proxy 0.83.33 → 0.83.35
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/ghost.d.ts +1 -0
- package/dist/commands/index.js +118 -29
- package/dist/index.js +164 -60
- 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
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function run(argv: string[]): Promise<number>;
|
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,23 +1006,108 @@ 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);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// src/commands/ghost.ts
|
|
1014
|
+
var USAGE4 = usage("solongate ghost", "hidden paths", [
|
|
1015
|
+
["ghost show", "current mode + routes"],
|
|
1016
|
+
["ghost on", "start hiding the routes"],
|
|
1017
|
+
["ghost off", "stop hiding them (the routes are kept)"],
|
|
1018
|
+
["ghost add <glob>", "hide one more path"],
|
|
1019
|
+
["ghost remove <glob>", "stop hiding one path"]
|
|
1020
|
+
]);
|
|
1021
|
+
var modeColor3 = (m) => m === "on" ? green(m) : dim("off");
|
|
1022
|
+
var isBlanketGlob = (glob) => glob.replaceAll("*", "").trim() === "";
|
|
1023
|
+
async function run4(argv) {
|
|
1024
|
+
const { positionals, flags } = parse(argv);
|
|
1025
|
+
const sub = positionals[0] ?? "show";
|
|
1026
|
+
const json = flagBool(flags, "json");
|
|
1027
|
+
if (sub === "help") return err(USAGE4), 0;
|
|
1028
|
+
const { layers } = await api.settings.getSecurityLayers();
|
|
1029
|
+
const save = async (next) => (await api.settings.setSecurityLayers(next)).layers;
|
|
1030
|
+
switch (sub) {
|
|
1031
|
+
case "show": {
|
|
1032
|
+
if (json) return printJson(layers.ghost), 0;
|
|
1033
|
+
err("");
|
|
1034
|
+
err(` Ghost mode: ${modeColor3(layers.ghost.mode)}`);
|
|
1035
|
+
if (!layers.ghost.patterns.length) {
|
|
1036
|
+
err(dim("\n No routes. `solongate ghost add <glob>` to hide a path."));
|
|
1037
|
+
return 0;
|
|
1038
|
+
}
|
|
1039
|
+
table(["", "ROUTE"], layers.ghost.patterns.map((r) => [cyan("\u2022"), r]));
|
|
1040
|
+
if (layers.ghost.mode !== "on") {
|
|
1041
|
+
err(dim("\n Ghost is off: these routes are stored but nothing is hidden."));
|
|
1042
|
+
}
|
|
1043
|
+
return 0;
|
|
1044
|
+
}
|
|
1045
|
+
case "on":
|
|
1046
|
+
case "off": {
|
|
1047
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, mode: sub } });
|
|
1048
|
+
if (json) return printJson(saved.ghost), 0;
|
|
1049
|
+
err(green(` \u2713 Ghost \u2192 ${saved.ghost.mode}`));
|
|
1050
|
+
if (sub === "on" && !saved.ghost.patterns.length) {
|
|
1051
|
+
err(dim(" No routes yet, so nothing is hidden. `solongate ghost add <glob>`."));
|
|
1052
|
+
}
|
|
1053
|
+
return 0;
|
|
1054
|
+
}
|
|
1055
|
+
case "add": {
|
|
1056
|
+
const glob = positionals.slice(1).join(" ");
|
|
1057
|
+
if (!glob) return err(" Usage: ghost add <glob>"), 1;
|
|
1058
|
+
if (isBlanketGlob(glob)) {
|
|
1059
|
+
err(`${red(" \u2717 ")}"${glob}" would hide every path.`);
|
|
1060
|
+
err(dim(" Ghost routes are globs: `*` is any run of non-whitespace."));
|
|
1061
|
+
err(dim(" Anchor it on something, e.g. *payroll.csv or *internal/*.pem"));
|
|
1062
|
+
return 1;
|
|
1063
|
+
}
|
|
1064
|
+
if (layers.ghost.patterns.includes(glob)) {
|
|
1065
|
+
if (json) return printJson(layers.ghost), 0;
|
|
1066
|
+
return err(green(` \u2713 Route "${glob}" is already hidden`)), 0;
|
|
1067
|
+
}
|
|
1068
|
+
const patterns = [...layers.ghost.patterns, glob];
|
|
1069
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, patterns } });
|
|
1070
|
+
if (json) return printJson(saved.ghost), 0;
|
|
1071
|
+
err(green(` \u2713 Hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s))`));
|
|
1072
|
+
if (saved.ghost.mode !== "on") {
|
|
1073
|
+
err(dim(" Ghost is off. `solongate ghost on` to start hiding."));
|
|
1074
|
+
}
|
|
1075
|
+
return 0;
|
|
1076
|
+
}
|
|
1077
|
+
case "remove": {
|
|
1078
|
+
const glob = positionals.slice(1).join(" ");
|
|
1079
|
+
if (!glob) return err(" Usage: ghost remove <glob>"), 1;
|
|
1080
|
+
if (!layers.ghost.patterns.includes(glob)) {
|
|
1081
|
+
err(` No such route: "${glob}"`);
|
|
1082
|
+
if (layers.ghost.patterns.length) {
|
|
1083
|
+
err(dim(" Current:"));
|
|
1084
|
+
for (const r of layers.ghost.patterns) err(` ${dim("\u2022")} ${r}`);
|
|
1085
|
+
}
|
|
1086
|
+
return 1;
|
|
1087
|
+
}
|
|
1088
|
+
const patterns = layers.ghost.patterns.filter((r) => r !== glob);
|
|
1089
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, patterns } });
|
|
1090
|
+
if (json) return printJson(saved.ghost), 0;
|
|
1091
|
+
return err(green(` \u2713 Stopped hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s) left)`)), 0;
|
|
1092
|
+
}
|
|
1093
|
+
default:
|
|
1094
|
+
return unknownSub("ghost", sub, USAGE4);
|
|
1008
1095
|
}
|
|
1009
1096
|
}
|
|
1010
1097
|
|
|
1011
1098
|
// src/commands/stats.ts
|
|
1012
|
-
var
|
|
1099
|
+
var USAGE5 = usage("solongate stats", "traffic & security stats", [
|
|
1013
1100
|
["stats", "overview (totals, recent activity)"],
|
|
1014
1101
|
["stats timeseries [--period 24h|7d|30d|all]"],
|
|
1015
1102
|
["stats drift [--days N]", "denials rising/falling vs previous window"]
|
|
1016
1103
|
]);
|
|
1017
|
-
async function
|
|
1104
|
+
async function run5(argv) {
|
|
1018
1105
|
const { positionals, flags } = parse(argv);
|
|
1019
1106
|
const sub = positionals[0] ?? "overview";
|
|
1020
1107
|
const json = flagBool(flags, "json");
|
|
1021
1108
|
switch (sub) {
|
|
1022
1109
|
case "help":
|
|
1023
|
-
return err(
|
|
1110
|
+
return err(USAGE5), 0;
|
|
1024
1111
|
case "overview": {
|
|
1025
1112
|
const s = await api.stats.get();
|
|
1026
1113
|
if (json) return printJson(s), 0;
|
|
@@ -1073,21 +1160,21 @@ async function run4(argv) {
|
|
|
1073
1160
|
return 0;
|
|
1074
1161
|
}
|
|
1075
1162
|
default:
|
|
1076
|
-
return
|
|
1163
|
+
return unknownSub("stats", sub, USAGE5);
|
|
1077
1164
|
}
|
|
1078
1165
|
}
|
|
1079
1166
|
|
|
1080
1167
|
// src/commands/audit.ts
|
|
1081
|
-
var
|
|
1168
|
+
var USAGE6 = usage("solongate audit", "audit log", [
|
|
1082
1169
|
["audit [--filter ALLOW|DENY] [--tool <substr>] [--signal dlp|ratelimit]"],
|
|
1083
1170
|
[" [--search <text>] [--agent-name <name>] [--limit N]"],
|
|
1084
1171
|
["audit whitelist <logId> [--scope exact|tool]", "turn a denied call into an ALLOW rule"],
|
|
1085
1172
|
["audit block <logId> [--scope exact|tool]", "turn a call into a DENY rule"]
|
|
1086
1173
|
]);
|
|
1087
|
-
async function
|
|
1174
|
+
async function run6(argv) {
|
|
1088
1175
|
const { positionals, flags } = parse(argv);
|
|
1089
1176
|
const json = flagBool(flags, "json");
|
|
1090
|
-
if (positionals[0] === "help") return err(
|
|
1177
|
+
if (positionals[0] === "help") return err(USAGE6), 0;
|
|
1091
1178
|
if (positionals[0] === "whitelist") {
|
|
1092
1179
|
const id = positionals[1];
|
|
1093
1180
|
if (!id) return err(" Usage: audit whitelist <logId> [--scope exact|tool]"), 1;
|
|
@@ -1329,7 +1416,7 @@ async function collectChecks() {
|
|
|
1329
1416
|
}
|
|
1330
1417
|
return checks;
|
|
1331
1418
|
}
|
|
1332
|
-
async function
|
|
1419
|
+
async function run7(argv) {
|
|
1333
1420
|
const { flags } = parse(argv);
|
|
1334
1421
|
const json = flagBool(flags, "json");
|
|
1335
1422
|
const checks = await collectChecks();
|
|
@@ -1377,7 +1464,7 @@ function print(r, json) {
|
|
|
1377
1464
|
`${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}`
|
|
1378
1465
|
);
|
|
1379
1466
|
}
|
|
1380
|
-
async function
|
|
1467
|
+
async function run8(argv) {
|
|
1381
1468
|
const { flags } = parse(argv);
|
|
1382
1469
|
const json = flagBool(flags, "json");
|
|
1383
1470
|
const decisionFilter = (flagStr(flags, "filter") || "").toUpperCase();
|
|
@@ -1455,19 +1542,19 @@ async function run7(argv) {
|
|
|
1455
1542
|
}
|
|
1456
1543
|
|
|
1457
1544
|
// src/commands/alerts.ts
|
|
1458
|
-
var
|
|
1545
|
+
var USAGE7 = usage("solongate alerts", "spike alerts (Telegram / email)", [
|
|
1459
1546
|
["alerts list"],
|
|
1460
1547
|
["alerts add --signal deny|dlp|ratelimit|any --threshold N --window S"],
|
|
1461
1548
|
[" (--email <a> | --telegram <chatId> | --slack <url>)"],
|
|
1462
1549
|
["alerts remove <id>"]
|
|
1463
1550
|
]);
|
|
1464
|
-
async function
|
|
1551
|
+
async function run9(argv) {
|
|
1465
1552
|
const { positionals, flags } = parse(argv);
|
|
1466
1553
|
const sub = positionals[0] ?? "list";
|
|
1467
1554
|
const json = flagBool(flags, "json");
|
|
1468
1555
|
switch (sub) {
|
|
1469
1556
|
case "help":
|
|
1470
|
-
return err(
|
|
1557
|
+
return err(USAGE7), 0;
|
|
1471
1558
|
case "list": {
|
|
1472
1559
|
const { rules } = await api.settings.getAlerts();
|
|
1473
1560
|
if (json) return printJson(rules), 0;
|
|
@@ -1509,23 +1596,23 @@ async function run8(argv) {
|
|
|
1509
1596
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
1510
1597
|
}
|
|
1511
1598
|
default:
|
|
1512
|
-
return
|
|
1599
|
+
return unknownSub("alerts", sub, USAGE7);
|
|
1513
1600
|
}
|
|
1514
1601
|
}
|
|
1515
1602
|
|
|
1516
1603
|
// src/commands/webhooks.ts
|
|
1517
|
-
var
|
|
1604
|
+
var USAGE8 = usage("solongate webhooks", "event webhooks", [
|
|
1518
1605
|
["webhooks list"],
|
|
1519
1606
|
["webhooks add --url <https://\u2026> [--events denials|allowed|all]"],
|
|
1520
1607
|
["webhooks remove <id>"]
|
|
1521
1608
|
]);
|
|
1522
|
-
async function
|
|
1609
|
+
async function run10(argv) {
|
|
1523
1610
|
const { positionals, flags } = parse(argv);
|
|
1524
1611
|
const sub = positionals[0] ?? "list";
|
|
1525
1612
|
const json = flagBool(flags, "json");
|
|
1526
1613
|
switch (sub) {
|
|
1527
1614
|
case "help":
|
|
1528
|
-
return err(
|
|
1615
|
+
return err(USAGE8), 0;
|
|
1529
1616
|
case "list": {
|
|
1530
1617
|
const { webhooks } = await api.settings.getWebhooks();
|
|
1531
1618
|
if (json) return printJson(webhooks), 0;
|
|
@@ -1551,7 +1638,7 @@ async function run9(argv) {
|
|
|
1551
1638
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
1552
1639
|
}
|
|
1553
1640
|
default:
|
|
1554
|
-
return
|
|
1641
|
+
return unknownSub("webhooks", sub, USAGE8);
|
|
1555
1642
|
}
|
|
1556
1643
|
}
|
|
1557
1644
|
|
|
@@ -1564,22 +1651,24 @@ async function dispatch(command, argv) {
|
|
|
1564
1651
|
return run2(argv);
|
|
1565
1652
|
case "dlp":
|
|
1566
1653
|
return run3(argv);
|
|
1567
|
-
case "
|
|
1654
|
+
case "ghost":
|
|
1568
1655
|
return run4(argv);
|
|
1569
|
-
case "
|
|
1656
|
+
case "stats":
|
|
1570
1657
|
return run5(argv);
|
|
1658
|
+
case "audit":
|
|
1659
|
+
return run6(argv);
|
|
1571
1660
|
case "sessions":
|
|
1572
1661
|
return runAgents(argv);
|
|
1573
1662
|
case "session":
|
|
1574
1663
|
return runAgent(argv);
|
|
1575
1664
|
case "doctor":
|
|
1576
|
-
return run6(argv);
|
|
1577
|
-
case "watch":
|
|
1578
1665
|
return run7(argv);
|
|
1579
|
-
case "
|
|
1666
|
+
case "watch":
|
|
1580
1667
|
return run8(argv);
|
|
1581
|
-
case "
|
|
1668
|
+
case "alerts":
|
|
1582
1669
|
return run9(argv);
|
|
1670
|
+
case "webhooks":
|
|
1671
|
+
return run10(argv);
|
|
1583
1672
|
default:
|
|
1584
1673
|
err(` Unknown command: ${command}`);
|
|
1585
1674
|
return 1;
|
package/dist/index.js
CHANGED
|
@@ -9351,7 +9351,7 @@ function LivePanel({ active: active2 }) {
|
|
|
9351
9351
|
] });
|
|
9352
9352
|
}
|
|
9353
9353
|
if (mode === "layers") {
|
|
9354
|
-
const
|
|
9354
|
+
const modeColor5 = (m) => m === "block" || m === "on" ? theme.ok : m === "detect" ? theme.warn : theme.dim;
|
|
9355
9355
|
const barW = Math.max(10, Math.min(40, innerW - 30));
|
|
9356
9356
|
const burstsInBuf = mergedAll.filter((e) => e.burst).length;
|
|
9357
9357
|
const dlpInBuf = mergedAll.filter((e) => e.dlp).length;
|
|
@@ -9366,7 +9366,7 @@ function LivePanel({ active: active2 }) {
|
|
|
9366
9366
|
"\u258E",
|
|
9367
9367
|
label.padEnd(10)
|
|
9368
9368
|
] }),
|
|
9369
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true, color:
|
|
9369
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, color: modeColor5(m), children: (m ?? "?").padEnd(8) }),
|
|
9370
9370
|
note ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: note }) : null
|
|
9371
9371
|
] })
|
|
9372
9372
|
);
|
|
@@ -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 run11(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
|
+
run11(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
|
+
run11(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") run11(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
|
+
run11(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 run11 = 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
|
+
run11().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 run11 = 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
|
+
run11().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 run11 = (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) run11("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
12099
|
+
else run11(`${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
|
+
run11(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
|
+
run11(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
|
+
run11(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
|
+
run11(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
|
+
run11("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") run11(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
|
+
run11("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
|
+
run11(`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
|
+
run11("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
|
+
run11("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 run11 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
12779
|
+
run11();
|
|
12780
|
+
const t = setInterval(run11, 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;
|
|
@@ -13341,14 +13343,108 @@ var init_dlp = __esm({
|
|
|
13341
13343
|
}
|
|
13342
13344
|
});
|
|
13343
13345
|
|
|
13344
|
-
// src/commands/
|
|
13346
|
+
// src/commands/ghost.ts
|
|
13345
13347
|
async function run5(argv) {
|
|
13348
|
+
const { positionals, flags } = parse(argv);
|
|
13349
|
+
const sub = positionals[0] ?? "show";
|
|
13350
|
+
const json = flagBool(flags, "json");
|
|
13351
|
+
if (sub === "help") return err(USAGE4), 0;
|
|
13352
|
+
const { layers } = await api.settings.getSecurityLayers();
|
|
13353
|
+
const save = async (next) => (await api.settings.setSecurityLayers(next)).layers;
|
|
13354
|
+
switch (sub) {
|
|
13355
|
+
case "show": {
|
|
13356
|
+
if (json) return printJson(layers.ghost), 0;
|
|
13357
|
+
err("");
|
|
13358
|
+
err(` Ghost mode: ${modeColor4(layers.ghost.mode)}`);
|
|
13359
|
+
if (!layers.ghost.patterns.length) {
|
|
13360
|
+
err(dim("\n No routes. `solongate ghost add <glob>` to hide a path."));
|
|
13361
|
+
return 0;
|
|
13362
|
+
}
|
|
13363
|
+
table(["", "ROUTE"], layers.ghost.patterns.map((r) => [cyan("\u2022"), r]));
|
|
13364
|
+
if (layers.ghost.mode !== "on") {
|
|
13365
|
+
err(dim("\n Ghost is off: these routes are stored but nothing is hidden."));
|
|
13366
|
+
}
|
|
13367
|
+
return 0;
|
|
13368
|
+
}
|
|
13369
|
+
case "on":
|
|
13370
|
+
case "off": {
|
|
13371
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, mode: sub } });
|
|
13372
|
+
if (json) return printJson(saved.ghost), 0;
|
|
13373
|
+
err(green(` \u2713 Ghost \u2192 ${saved.ghost.mode}`));
|
|
13374
|
+
if (sub === "on" && !saved.ghost.patterns.length) {
|
|
13375
|
+
err(dim(" No routes yet, so nothing is hidden. `solongate ghost add <glob>`."));
|
|
13376
|
+
}
|
|
13377
|
+
return 0;
|
|
13378
|
+
}
|
|
13379
|
+
case "add": {
|
|
13380
|
+
const glob = positionals.slice(1).join(" ");
|
|
13381
|
+
if (!glob) return err(" Usage: ghost add <glob>"), 1;
|
|
13382
|
+
if (isBlanketGlob(glob)) {
|
|
13383
|
+
err(`${red(" \u2717 ")}"${glob}" would hide every path.`);
|
|
13384
|
+
err(dim(" Ghost routes are globs: `*` is any run of non-whitespace."));
|
|
13385
|
+
err(dim(" Anchor it on something, e.g. *payroll.csv or *internal/*.pem"));
|
|
13386
|
+
return 1;
|
|
13387
|
+
}
|
|
13388
|
+
if (layers.ghost.patterns.includes(glob)) {
|
|
13389
|
+
if (json) return printJson(layers.ghost), 0;
|
|
13390
|
+
return err(green(` \u2713 Route "${glob}" is already hidden`)), 0;
|
|
13391
|
+
}
|
|
13392
|
+
const patterns = [...layers.ghost.patterns, glob];
|
|
13393
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, patterns } });
|
|
13394
|
+
if (json) return printJson(saved.ghost), 0;
|
|
13395
|
+
err(green(` \u2713 Hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s))`));
|
|
13396
|
+
if (saved.ghost.mode !== "on") {
|
|
13397
|
+
err(dim(" Ghost is off. `solongate ghost on` to start hiding."));
|
|
13398
|
+
}
|
|
13399
|
+
return 0;
|
|
13400
|
+
}
|
|
13401
|
+
case "remove": {
|
|
13402
|
+
const glob = positionals.slice(1).join(" ");
|
|
13403
|
+
if (!glob) return err(" Usage: ghost remove <glob>"), 1;
|
|
13404
|
+
if (!layers.ghost.patterns.includes(glob)) {
|
|
13405
|
+
err(` No such route: "${glob}"`);
|
|
13406
|
+
if (layers.ghost.patterns.length) {
|
|
13407
|
+
err(dim(" Current:"));
|
|
13408
|
+
for (const r of layers.ghost.patterns) err(` ${dim("\u2022")} ${r}`);
|
|
13409
|
+
}
|
|
13410
|
+
return 1;
|
|
13411
|
+
}
|
|
13412
|
+
const patterns = layers.ghost.patterns.filter((r) => r !== glob);
|
|
13413
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, patterns } });
|
|
13414
|
+
if (json) return printJson(saved.ghost), 0;
|
|
13415
|
+
return err(green(` \u2713 Stopped hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s) left)`)), 0;
|
|
13416
|
+
}
|
|
13417
|
+
default:
|
|
13418
|
+
return unknownSub("ghost", sub, USAGE4);
|
|
13419
|
+
}
|
|
13420
|
+
}
|
|
13421
|
+
var USAGE4, modeColor4, isBlanketGlob;
|
|
13422
|
+
var init_ghost = __esm({
|
|
13423
|
+
"src/commands/ghost.ts"() {
|
|
13424
|
+
"use strict";
|
|
13425
|
+
init_api_client();
|
|
13426
|
+
init_args();
|
|
13427
|
+
init_format();
|
|
13428
|
+
USAGE4 = usage("solongate ghost", "hidden paths", [
|
|
13429
|
+
["ghost show", "current mode + routes"],
|
|
13430
|
+
["ghost on", "start hiding the routes"],
|
|
13431
|
+
["ghost off", "stop hiding them (the routes are kept)"],
|
|
13432
|
+
["ghost add <glob>", "hide one more path"],
|
|
13433
|
+
["ghost remove <glob>", "stop hiding one path"]
|
|
13434
|
+
]);
|
|
13435
|
+
modeColor4 = (m) => m === "on" ? green(m) : dim("off");
|
|
13436
|
+
isBlanketGlob = (glob) => glob.replaceAll("*", "").trim() === "";
|
|
13437
|
+
}
|
|
13438
|
+
});
|
|
13439
|
+
|
|
13440
|
+
// src/commands/stats.ts
|
|
13441
|
+
async function run6(argv) {
|
|
13346
13442
|
const { positionals, flags } = parse(argv);
|
|
13347
13443
|
const sub = positionals[0] ?? "overview";
|
|
13348
13444
|
const json = flagBool(flags, "json");
|
|
13349
13445
|
switch (sub) {
|
|
13350
13446
|
case "help":
|
|
13351
|
-
return err(
|
|
13447
|
+
return err(USAGE5), 0;
|
|
13352
13448
|
case "overview": {
|
|
13353
13449
|
const s = await api.stats.get();
|
|
13354
13450
|
if (json) return printJson(s), 0;
|
|
@@ -13401,17 +13497,17 @@ async function run5(argv) {
|
|
|
13401
13497
|
return 0;
|
|
13402
13498
|
}
|
|
13403
13499
|
default:
|
|
13404
|
-
return
|
|
13500
|
+
return unknownSub("stats", sub, USAGE5);
|
|
13405
13501
|
}
|
|
13406
13502
|
}
|
|
13407
|
-
var
|
|
13503
|
+
var USAGE5;
|
|
13408
13504
|
var init_stats2 = __esm({
|
|
13409
13505
|
"src/commands/stats.ts"() {
|
|
13410
13506
|
"use strict";
|
|
13411
13507
|
init_api_client();
|
|
13412
13508
|
init_args();
|
|
13413
13509
|
init_format();
|
|
13414
|
-
|
|
13510
|
+
USAGE5 = usage("solongate stats", "traffic & security stats", [
|
|
13415
13511
|
["stats", "overview (totals, recent activity)"],
|
|
13416
13512
|
["stats timeseries [--period 24h|7d|30d|all]"],
|
|
13417
13513
|
["stats drift [--days N]", "denials rising/falling vs previous window"]
|
|
@@ -13420,10 +13516,10 @@ var init_stats2 = __esm({
|
|
|
13420
13516
|
});
|
|
13421
13517
|
|
|
13422
13518
|
// src/commands/audit.ts
|
|
13423
|
-
async function
|
|
13519
|
+
async function run7(argv) {
|
|
13424
13520
|
const { positionals, flags } = parse(argv);
|
|
13425
13521
|
const json = flagBool(flags, "json");
|
|
13426
|
-
if (positionals[0] === "help") return err(
|
|
13522
|
+
if (positionals[0] === "help") return err(USAGE6), 0;
|
|
13427
13523
|
if (positionals[0] === "whitelist") {
|
|
13428
13524
|
const id = positionals[1];
|
|
13429
13525
|
if (!id) return err(" Usage: audit whitelist <logId> [--scope exact|tool]"), 1;
|
|
@@ -13471,14 +13567,14 @@ async function run6(argv) {
|
|
|
13471
13567
|
);
|
|
13472
13568
|
return 0;
|
|
13473
13569
|
}
|
|
13474
|
-
var
|
|
13570
|
+
var USAGE6;
|
|
13475
13571
|
var init_audit2 = __esm({
|
|
13476
13572
|
"src/commands/audit.ts"() {
|
|
13477
13573
|
"use strict";
|
|
13478
13574
|
init_api_client();
|
|
13479
13575
|
init_args();
|
|
13480
13576
|
init_format();
|
|
13481
|
-
|
|
13577
|
+
USAGE6 = usage("solongate audit", "audit log", [
|
|
13482
13578
|
["audit [--filter ALLOW|DENY] [--tool <substr>] [--signal dlp|ratelimit]"],
|
|
13483
13579
|
[" [--search <text>] [--agent-name <name>] [--limit N]"],
|
|
13484
13580
|
["audit whitelist <logId> [--scope exact|tool]", "turn a denied call into an ALLOW rule"],
|
|
@@ -13574,7 +13670,7 @@ function print(r, json) {
|
|
|
13574
13670
|
`${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}`
|
|
13575
13671
|
);
|
|
13576
13672
|
}
|
|
13577
|
-
async function
|
|
13673
|
+
async function run8(argv) {
|
|
13578
13674
|
const { flags } = parse(argv);
|
|
13579
13675
|
const json = flagBool(flags, "json");
|
|
13580
13676
|
const decisionFilter = (flagStr(flags, "filter") || "").toUpperCase();
|
|
@@ -13665,13 +13761,13 @@ var init_watch = __esm({
|
|
|
13665
13761
|
});
|
|
13666
13762
|
|
|
13667
13763
|
// src/commands/alerts.ts
|
|
13668
|
-
async function
|
|
13764
|
+
async function run9(argv) {
|
|
13669
13765
|
const { positionals, flags } = parse(argv);
|
|
13670
13766
|
const sub = positionals[0] ?? "list";
|
|
13671
13767
|
const json = flagBool(flags, "json");
|
|
13672
13768
|
switch (sub) {
|
|
13673
13769
|
case "help":
|
|
13674
|
-
return err(
|
|
13770
|
+
return err(USAGE7), 0;
|
|
13675
13771
|
case "list": {
|
|
13676
13772
|
const { rules } = await api.settings.getAlerts();
|
|
13677
13773
|
if (json) return printJson(rules), 0;
|
|
@@ -13713,17 +13809,17 @@ async function run8(argv) {
|
|
|
13713
13809
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
13714
13810
|
}
|
|
13715
13811
|
default:
|
|
13716
|
-
return
|
|
13812
|
+
return unknownSub("alerts", sub, USAGE7);
|
|
13717
13813
|
}
|
|
13718
13814
|
}
|
|
13719
|
-
var
|
|
13815
|
+
var USAGE7;
|
|
13720
13816
|
var init_alerts = __esm({
|
|
13721
13817
|
"src/commands/alerts.ts"() {
|
|
13722
13818
|
"use strict";
|
|
13723
13819
|
init_api_client();
|
|
13724
13820
|
init_args();
|
|
13725
13821
|
init_format();
|
|
13726
|
-
|
|
13822
|
+
USAGE7 = usage("solongate alerts", "spike alerts (Telegram / email)", [
|
|
13727
13823
|
["alerts list"],
|
|
13728
13824
|
["alerts add --signal deny|dlp|ratelimit|any --threshold N --window S"],
|
|
13729
13825
|
[" (--email <a> | --telegram <chatId> | --slack <url>)"],
|
|
@@ -13733,13 +13829,13 @@ var init_alerts = __esm({
|
|
|
13733
13829
|
});
|
|
13734
13830
|
|
|
13735
13831
|
// src/commands/webhooks.ts
|
|
13736
|
-
async function
|
|
13832
|
+
async function run10(argv) {
|
|
13737
13833
|
const { positionals, flags } = parse(argv);
|
|
13738
13834
|
const sub = positionals[0] ?? "list";
|
|
13739
13835
|
const json = flagBool(flags, "json");
|
|
13740
13836
|
switch (sub) {
|
|
13741
13837
|
case "help":
|
|
13742
|
-
return err(
|
|
13838
|
+
return err(USAGE8), 0;
|
|
13743
13839
|
case "list": {
|
|
13744
13840
|
const { webhooks } = await api.settings.getWebhooks();
|
|
13745
13841
|
if (json) return printJson(webhooks), 0;
|
|
@@ -13765,17 +13861,17 @@ async function run9(argv) {
|
|
|
13765
13861
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
13766
13862
|
}
|
|
13767
13863
|
default:
|
|
13768
|
-
return
|
|
13864
|
+
return unknownSub("webhooks", sub, USAGE8);
|
|
13769
13865
|
}
|
|
13770
13866
|
}
|
|
13771
|
-
var
|
|
13867
|
+
var USAGE8;
|
|
13772
13868
|
var init_webhooks = __esm({
|
|
13773
13869
|
"src/commands/webhooks.ts"() {
|
|
13774
13870
|
"use strict";
|
|
13775
13871
|
init_api_client();
|
|
13776
13872
|
init_args();
|
|
13777
13873
|
init_format();
|
|
13778
|
-
|
|
13874
|
+
USAGE8 = usage("solongate webhooks", "event webhooks", [
|
|
13779
13875
|
["webhooks list"],
|
|
13780
13876
|
["webhooks add --url <https://\u2026> [--events denials|allowed|all]"],
|
|
13781
13877
|
["webhooks remove <id>"]
|
|
@@ -13797,10 +13893,12 @@ async function dispatch(command, argv) {
|
|
|
13797
13893
|
return run3(argv);
|
|
13798
13894
|
case "dlp":
|
|
13799
13895
|
return run4(argv);
|
|
13800
|
-
case "
|
|
13896
|
+
case "ghost":
|
|
13801
13897
|
return run5(argv);
|
|
13802
|
-
case "
|
|
13898
|
+
case "stats":
|
|
13803
13899
|
return run6(argv);
|
|
13900
|
+
case "audit":
|
|
13901
|
+
return run7(argv);
|
|
13804
13902
|
case "sessions":
|
|
13805
13903
|
return runAgents(argv);
|
|
13806
13904
|
case "session":
|
|
@@ -13808,11 +13906,11 @@ async function dispatch(command, argv) {
|
|
|
13808
13906
|
case "doctor":
|
|
13809
13907
|
return run(argv);
|
|
13810
13908
|
case "watch":
|
|
13811
|
-
return run7(argv);
|
|
13812
|
-
case "alerts":
|
|
13813
13909
|
return run8(argv);
|
|
13814
|
-
case "
|
|
13910
|
+
case "alerts":
|
|
13815
13911
|
return run9(argv);
|
|
13912
|
+
case "webhooks":
|
|
13913
|
+
return run10(argv);
|
|
13816
13914
|
default:
|
|
13817
13915
|
err(` Unknown command: ${command}`);
|
|
13818
13916
|
return 1;
|
|
@@ -13844,6 +13942,7 @@ var init_commands = __esm({
|
|
|
13844
13942
|
init_policy();
|
|
13845
13943
|
init_ratelimit();
|
|
13846
13944
|
init_dlp();
|
|
13945
|
+
init_ghost();
|
|
13847
13946
|
init_stats2();
|
|
13848
13947
|
init_audit2();
|
|
13849
13948
|
init_agents2();
|
|
@@ -17440,7 +17539,7 @@ ${msg.content.text}`;
|
|
|
17440
17539
|
|
|
17441
17540
|
// src/index.ts
|
|
17442
17541
|
init_cli_utils();
|
|
17443
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["update", "repair", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
|
|
17542
|
+
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"]);
|
|
17444
17543
|
var CLI_INFO_ARGS = /* @__PURE__ */ new Set(["login", "help", "--help", "-h", "--version", "-v", "version"]);
|
|
17445
17544
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "") || CLI_INFO_ARGS.has(process.argv[2] ?? "");
|
|
17446
17545
|
if (!IS_HUMAN_CLI) {
|
|
@@ -17531,6 +17630,11 @@ function printHelp() {
|
|
|
17531
17630
|
cmd("dlp disable <pattern>", "disable a built-in pattern");
|
|
17532
17631
|
cmd("dlp add-custom --name X --re <regex>", "add a custom pattern");
|
|
17533
17632
|
cmd("dlp remove-custom <name>", "remove a custom pattern");
|
|
17633
|
+
head("Ghost (hidden paths)");
|
|
17634
|
+
cmd("ghost show", "current mode + routes");
|
|
17635
|
+
cmd("ghost on | off", "start or stop hiding the routes");
|
|
17636
|
+
cmd("ghost add <glob>", "hide one more path");
|
|
17637
|
+
cmd("ghost remove <glob>", "stop hiding one path");
|
|
17534
17638
|
head("Monitoring");
|
|
17535
17639
|
cmd("audit [--filter ALLOW|DENY] [--tool <s>] [--signal dlp|ratelimit] [--limit N]", "browse the audit log");
|
|
17536
17640
|
cmd("audit whitelist <logId> [--scope exact|tool]", "turn a denial into an ALLOW rule");
|
|
@@ -17629,7 +17733,7 @@ async function main() {
|
|
|
17629
17733
|
await launchTui2();
|
|
17630
17734
|
return;
|
|
17631
17735
|
}
|
|
17632
|
-
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
|
|
17736
|
+
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "ghost", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
|
|
17633
17737
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
17634
17738
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
17635
17739
|
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.35",
|
|
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.35",
|
|
65
|
+
"@solongate/guard-linux-arm64": "0.83.35",
|
|
66
|
+
"@solongate/guard-darwin-x64": "0.83.35",
|
|
67
|
+
"@solongate/guard-darwin-arm64": "0.83.35",
|
|
68
|
+
"@solongate/guard-win32-x64": "0.83.35",
|
|
69
|
+
"@solongate/guard-win32-arm64": "0.83.35"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"@modelcontextprotocol/sdk": "^1.26.0",
|