@solongate/proxy 0.83.32 → 0.83.34
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/ghost.d.ts +1 -0
- package/dist/commands/index.js +116 -27
- package/dist/index.js +163 -59
- package/package.json +7 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function run(argv: string[]): Promise<number>;
|
package/dist/commands/index.js
CHANGED
|
@@ -692,7 +692,7 @@ var USAGE = usage("solongate policy", "manage cloud policies", [
|
|
|
692
692
|
["policy deny <id> [--command|--path|--url <val>]", "append a DENY rule"],
|
|
693
693
|
["policy revoke <id> <ruleId>", "remove a rule"],
|
|
694
694
|
["policy active", "show the resolved active policy"],
|
|
695
|
-
["policy activate <id> | --
|
|
695
|
+
["policy activate <id> | --off", "pin the active policy, or enforce nothing"],
|
|
696
696
|
["policy dry-run <id|file.json> [--limit N] [--mode denylist|whitelist]", "replay recent traffic against rules"]
|
|
697
697
|
], "Add --json to any read command for machine-readable output.");
|
|
698
698
|
async function run(argv) {
|
|
@@ -798,13 +798,15 @@ async function run(argv) {
|
|
|
798
798
|
return 0;
|
|
799
799
|
}
|
|
800
800
|
case "activate": {
|
|
801
|
-
if (flagBool(flags, "clear")) {
|
|
801
|
+
if (flagBool(flags, "off") || flagBool(flags, "clear")) {
|
|
802
802
|
const res2 = await api.policies.setActive(null);
|
|
803
803
|
if (json) return printJson(res2), 0;
|
|
804
|
-
|
|
804
|
+
err(green(" \u2713 Deactivated - this project now enforces no policy."));
|
|
805
|
+
err(dim(" Pin one again with: solongate policy activate <id>"));
|
|
806
|
+
return 0;
|
|
805
807
|
}
|
|
806
808
|
const id = positionals[1];
|
|
807
|
-
if (!id) return err(" Usage: policy activate <id> | policy activate --
|
|
809
|
+
if (!id) return err(" Usage: policy activate <id> | policy activate --off"), 1;
|
|
808
810
|
const res = await api.policies.setActive(id);
|
|
809
811
|
if (json) return printJson(res), 0;
|
|
810
812
|
err(green(` \u2713 Pinned active policy \u2192 ${res.active}`));
|
|
@@ -1006,19 +1008,104 @@ async function run3(argv) {
|
|
|
1006
1008
|
}
|
|
1007
1009
|
}
|
|
1008
1010
|
|
|
1011
|
+
// src/commands/ghost.ts
|
|
1012
|
+
var USAGE4 = usage("solongate ghost", "hidden paths", [
|
|
1013
|
+
["ghost show", "current mode + routes"],
|
|
1014
|
+
["ghost on", "start hiding the routes"],
|
|
1015
|
+
["ghost off", "stop hiding them (the routes are kept)"],
|
|
1016
|
+
["ghost add <glob>", "hide one more path"],
|
|
1017
|
+
["ghost remove <glob>", "stop hiding one path"]
|
|
1018
|
+
]);
|
|
1019
|
+
var modeColor3 = (m) => m === "on" ? green(m) : dim("off");
|
|
1020
|
+
var isBlanketGlob = (glob) => glob.replaceAll("*", "").trim() === "";
|
|
1021
|
+
async function run4(argv) {
|
|
1022
|
+
const { positionals, flags } = parse(argv);
|
|
1023
|
+
const sub = positionals[0] ?? "show";
|
|
1024
|
+
const json = flagBool(flags, "json");
|
|
1025
|
+
if (sub === "help") return err(USAGE4), 0;
|
|
1026
|
+
const { layers } = await api.settings.getSecurityLayers();
|
|
1027
|
+
const save = async (next) => (await api.settings.setSecurityLayers(next)).layers;
|
|
1028
|
+
switch (sub) {
|
|
1029
|
+
case "show": {
|
|
1030
|
+
if (json) return printJson(layers.ghost), 0;
|
|
1031
|
+
err("");
|
|
1032
|
+
err(` Ghost mode: ${modeColor3(layers.ghost.mode)}`);
|
|
1033
|
+
if (!layers.ghost.patterns.length) {
|
|
1034
|
+
err(dim("\n No routes. `solongate ghost add <glob>` to hide a path."));
|
|
1035
|
+
return 0;
|
|
1036
|
+
}
|
|
1037
|
+
table(["", "ROUTE"], layers.ghost.patterns.map((r) => [cyan("\u2022"), r]));
|
|
1038
|
+
if (layers.ghost.mode !== "on") {
|
|
1039
|
+
err(dim("\n Ghost is off: these routes are stored but nothing is hidden."));
|
|
1040
|
+
}
|
|
1041
|
+
return 0;
|
|
1042
|
+
}
|
|
1043
|
+
case "on":
|
|
1044
|
+
case "off": {
|
|
1045
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, mode: sub } });
|
|
1046
|
+
if (json) return printJson(saved.ghost), 0;
|
|
1047
|
+
err(green(` \u2713 Ghost \u2192 ${saved.ghost.mode}`));
|
|
1048
|
+
if (sub === "on" && !saved.ghost.patterns.length) {
|
|
1049
|
+
err(dim(" No routes yet, so nothing is hidden. `solongate ghost add <glob>`."));
|
|
1050
|
+
}
|
|
1051
|
+
return 0;
|
|
1052
|
+
}
|
|
1053
|
+
case "add": {
|
|
1054
|
+
const glob = positionals.slice(1).join(" ");
|
|
1055
|
+
if (!glob) return err(" Usage: ghost add <glob>"), 1;
|
|
1056
|
+
if (isBlanketGlob(glob)) {
|
|
1057
|
+
err(`${red(" \u2717 ")}"${glob}" would hide every path.`);
|
|
1058
|
+
err(dim(" Ghost routes are globs: `*` is any run of non-whitespace."));
|
|
1059
|
+
err(dim(" Anchor it on something, e.g. *payroll.csv or *internal/*.pem"));
|
|
1060
|
+
return 1;
|
|
1061
|
+
}
|
|
1062
|
+
if (layers.ghost.patterns.includes(glob)) {
|
|
1063
|
+
if (json) return printJson(layers.ghost), 0;
|
|
1064
|
+
return err(green(` \u2713 Route "${glob}" is already hidden`)), 0;
|
|
1065
|
+
}
|
|
1066
|
+
const patterns = [...layers.ghost.patterns, glob];
|
|
1067
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, patterns } });
|
|
1068
|
+
if (json) return printJson(saved.ghost), 0;
|
|
1069
|
+
err(green(` \u2713 Hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s))`));
|
|
1070
|
+
if (saved.ghost.mode !== "on") {
|
|
1071
|
+
err(dim(" Ghost is off. `solongate ghost on` to start hiding."));
|
|
1072
|
+
}
|
|
1073
|
+
return 0;
|
|
1074
|
+
}
|
|
1075
|
+
case "remove": {
|
|
1076
|
+
const glob = positionals.slice(1).join(" ");
|
|
1077
|
+
if (!glob) return err(" Usage: ghost remove <glob>"), 1;
|
|
1078
|
+
if (!layers.ghost.patterns.includes(glob)) {
|
|
1079
|
+
err(` No such route: "${glob}"`);
|
|
1080
|
+
if (layers.ghost.patterns.length) {
|
|
1081
|
+
err(dim(" Current:"));
|
|
1082
|
+
for (const r of layers.ghost.patterns) err(` ${dim("\u2022")} ${r}`);
|
|
1083
|
+
}
|
|
1084
|
+
return 1;
|
|
1085
|
+
}
|
|
1086
|
+
const patterns = layers.ghost.patterns.filter((r) => r !== glob);
|
|
1087
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, patterns } });
|
|
1088
|
+
if (json) return printJson(saved.ghost), 0;
|
|
1089
|
+
return err(green(` \u2713 Stopped hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s) left)`)), 0;
|
|
1090
|
+
}
|
|
1091
|
+
default:
|
|
1092
|
+
return err(USAGE4), 1;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1009
1096
|
// src/commands/stats.ts
|
|
1010
|
-
var
|
|
1097
|
+
var USAGE5 = usage("solongate stats", "traffic & security stats", [
|
|
1011
1098
|
["stats", "overview (totals, recent activity)"],
|
|
1012
1099
|
["stats timeseries [--period 24h|7d|30d|all]"],
|
|
1013
1100
|
["stats drift [--days N]", "denials rising/falling vs previous window"]
|
|
1014
1101
|
]);
|
|
1015
|
-
async function
|
|
1102
|
+
async function run5(argv) {
|
|
1016
1103
|
const { positionals, flags } = parse(argv);
|
|
1017
1104
|
const sub = positionals[0] ?? "overview";
|
|
1018
1105
|
const json = flagBool(flags, "json");
|
|
1019
1106
|
switch (sub) {
|
|
1020
1107
|
case "help":
|
|
1021
|
-
return err(
|
|
1108
|
+
return err(USAGE5), 0;
|
|
1022
1109
|
case "overview": {
|
|
1023
1110
|
const s = await api.stats.get();
|
|
1024
1111
|
if (json) return printJson(s), 0;
|
|
@@ -1071,21 +1158,21 @@ async function run4(argv) {
|
|
|
1071
1158
|
return 0;
|
|
1072
1159
|
}
|
|
1073
1160
|
default:
|
|
1074
|
-
return err(
|
|
1161
|
+
return err(USAGE5), 1;
|
|
1075
1162
|
}
|
|
1076
1163
|
}
|
|
1077
1164
|
|
|
1078
1165
|
// src/commands/audit.ts
|
|
1079
|
-
var
|
|
1166
|
+
var USAGE6 = usage("solongate audit", "audit log", [
|
|
1080
1167
|
["audit [--filter ALLOW|DENY] [--tool <substr>] [--signal dlp|ratelimit]"],
|
|
1081
1168
|
[" [--search <text>] [--agent-name <name>] [--limit N]"],
|
|
1082
1169
|
["audit whitelist <logId> [--scope exact|tool]", "turn a denied call into an ALLOW rule"],
|
|
1083
1170
|
["audit block <logId> [--scope exact|tool]", "turn a call into a DENY rule"]
|
|
1084
1171
|
]);
|
|
1085
|
-
async function
|
|
1172
|
+
async function run6(argv) {
|
|
1086
1173
|
const { positionals, flags } = parse(argv);
|
|
1087
1174
|
const json = flagBool(flags, "json");
|
|
1088
|
-
if (positionals[0] === "help") return err(
|
|
1175
|
+
if (positionals[0] === "help") return err(USAGE6), 0;
|
|
1089
1176
|
if (positionals[0] === "whitelist") {
|
|
1090
1177
|
const id = positionals[1];
|
|
1091
1178
|
if (!id) return err(" Usage: audit whitelist <logId> [--scope exact|tool]"), 1;
|
|
@@ -1327,7 +1414,7 @@ async function collectChecks() {
|
|
|
1327
1414
|
}
|
|
1328
1415
|
return checks;
|
|
1329
1416
|
}
|
|
1330
|
-
async function
|
|
1417
|
+
async function run7(argv) {
|
|
1331
1418
|
const { flags } = parse(argv);
|
|
1332
1419
|
const json = flagBool(flags, "json");
|
|
1333
1420
|
const checks = await collectChecks();
|
|
@@ -1375,7 +1462,7 @@ function print(r, json) {
|
|
|
1375
1462
|
`${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}`
|
|
1376
1463
|
);
|
|
1377
1464
|
}
|
|
1378
|
-
async function
|
|
1465
|
+
async function run8(argv) {
|
|
1379
1466
|
const { flags } = parse(argv);
|
|
1380
1467
|
const json = flagBool(flags, "json");
|
|
1381
1468
|
const decisionFilter = (flagStr(flags, "filter") || "").toUpperCase();
|
|
@@ -1453,19 +1540,19 @@ async function run7(argv) {
|
|
|
1453
1540
|
}
|
|
1454
1541
|
|
|
1455
1542
|
// src/commands/alerts.ts
|
|
1456
|
-
var
|
|
1543
|
+
var USAGE7 = usage("solongate alerts", "spike alerts (Telegram / email)", [
|
|
1457
1544
|
["alerts list"],
|
|
1458
1545
|
["alerts add --signal deny|dlp|ratelimit|any --threshold N --window S"],
|
|
1459
1546
|
[" (--email <a> | --telegram <chatId> | --slack <url>)"],
|
|
1460
1547
|
["alerts remove <id>"]
|
|
1461
1548
|
]);
|
|
1462
|
-
async function
|
|
1549
|
+
async function run9(argv) {
|
|
1463
1550
|
const { positionals, flags } = parse(argv);
|
|
1464
1551
|
const sub = positionals[0] ?? "list";
|
|
1465
1552
|
const json = flagBool(flags, "json");
|
|
1466
1553
|
switch (sub) {
|
|
1467
1554
|
case "help":
|
|
1468
|
-
return err(
|
|
1555
|
+
return err(USAGE7), 0;
|
|
1469
1556
|
case "list": {
|
|
1470
1557
|
const { rules } = await api.settings.getAlerts();
|
|
1471
1558
|
if (json) return printJson(rules), 0;
|
|
@@ -1507,23 +1594,23 @@ async function run8(argv) {
|
|
|
1507
1594
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
1508
1595
|
}
|
|
1509
1596
|
default:
|
|
1510
|
-
return err(
|
|
1597
|
+
return err(USAGE7), 1;
|
|
1511
1598
|
}
|
|
1512
1599
|
}
|
|
1513
1600
|
|
|
1514
1601
|
// src/commands/webhooks.ts
|
|
1515
|
-
var
|
|
1602
|
+
var USAGE8 = usage("solongate webhooks", "event webhooks", [
|
|
1516
1603
|
["webhooks list"],
|
|
1517
1604
|
["webhooks add --url <https://\u2026> [--events denials|allowed|all]"],
|
|
1518
1605
|
["webhooks remove <id>"]
|
|
1519
1606
|
]);
|
|
1520
|
-
async function
|
|
1607
|
+
async function run10(argv) {
|
|
1521
1608
|
const { positionals, flags } = parse(argv);
|
|
1522
1609
|
const sub = positionals[0] ?? "list";
|
|
1523
1610
|
const json = flagBool(flags, "json");
|
|
1524
1611
|
switch (sub) {
|
|
1525
1612
|
case "help":
|
|
1526
|
-
return err(
|
|
1613
|
+
return err(USAGE8), 0;
|
|
1527
1614
|
case "list": {
|
|
1528
1615
|
const { webhooks } = await api.settings.getWebhooks();
|
|
1529
1616
|
if (json) return printJson(webhooks), 0;
|
|
@@ -1549,7 +1636,7 @@ async function run9(argv) {
|
|
|
1549
1636
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
1550
1637
|
}
|
|
1551
1638
|
default:
|
|
1552
|
-
return err(
|
|
1639
|
+
return err(USAGE8), 1;
|
|
1553
1640
|
}
|
|
1554
1641
|
}
|
|
1555
1642
|
|
|
@@ -1562,22 +1649,24 @@ async function dispatch(command, argv) {
|
|
|
1562
1649
|
return run2(argv);
|
|
1563
1650
|
case "dlp":
|
|
1564
1651
|
return run3(argv);
|
|
1565
|
-
case "
|
|
1652
|
+
case "ghost":
|
|
1566
1653
|
return run4(argv);
|
|
1567
|
-
case "
|
|
1654
|
+
case "stats":
|
|
1568
1655
|
return run5(argv);
|
|
1656
|
+
case "audit":
|
|
1657
|
+
return run6(argv);
|
|
1569
1658
|
case "sessions":
|
|
1570
1659
|
return runAgents(argv);
|
|
1571
1660
|
case "session":
|
|
1572
1661
|
return runAgent(argv);
|
|
1573
1662
|
case "doctor":
|
|
1574
|
-
return run6(argv);
|
|
1575
|
-
case "watch":
|
|
1576
1663
|
return run7(argv);
|
|
1577
|
-
case "
|
|
1664
|
+
case "watch":
|
|
1578
1665
|
return run8(argv);
|
|
1579
|
-
case "
|
|
1666
|
+
case "alerts":
|
|
1580
1667
|
return run9(argv);
|
|
1668
|
+
case "webhooks":
|
|
1669
|
+
return run10(argv);
|
|
1581
1670
|
default:
|
|
1582
1671
|
err(` Unknown command: ${command}`);
|
|
1583
1672
|
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) => {
|
|
@@ -12008,7 +12008,7 @@ function SettingsPanel({
|
|
|
12008
12008
|
guardQ.reload();
|
|
12009
12009
|
selfQ.reload();
|
|
12010
12010
|
};
|
|
12011
|
-
const
|
|
12011
|
+
const run11 = (label, fn, reload) => {
|
|
12012
12012
|
if (busy) return;
|
|
12013
12013
|
setBusy(true);
|
|
12014
12014
|
setMsg({ text: label + "\u2026", level: "ok" });
|
|
@@ -12090,8 +12090,8 @@ function SettingsPanel({
|
|
|
12090
12090
|
const body = { signal: editor.signal, threshold: editor.threshold, windowSeconds: editor.windowSeconds, enabled: editor.enabled, ...channels };
|
|
12091
12091
|
const id = editor.id;
|
|
12092
12092
|
setEditor(null);
|
|
12093
|
-
if (id)
|
|
12094
|
-
else
|
|
12093
|
+
if (id) run11("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
12094
|
+
else run11(`${editor.channel} alert added`, () => api.settings.createAlert({ name: "SolonGate alert", ...body }), alertQ.reload);
|
|
12095
12095
|
};
|
|
12096
12096
|
const activate = (r) => {
|
|
12097
12097
|
if (r.kind === "acct") {
|
|
@@ -12165,7 +12165,7 @@ function SettingsPanel({
|
|
|
12165
12165
|
})();
|
|
12166
12166
|
} else if (r.kind === "self") {
|
|
12167
12167
|
if (!selfProt) return;
|
|
12168
|
-
|
|
12168
|
+
run11(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
12169
12169
|
} else if (r.kind === "cli-update") {
|
|
12170
12170
|
if (updBusy) return;
|
|
12171
12171
|
setUpdBusy(true);
|
|
@@ -12212,7 +12212,7 @@ function SettingsPanel({
|
|
|
12212
12212
|
setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
|
|
12213
12213
|
return;
|
|
12214
12214
|
}
|
|
12215
|
-
|
|
12215
|
+
run11(local.enabled ? "local logs disabled" : "local logs enabled", () => api.settings.setLocalLogs({ enabled: !local.enabled, path: local.path }), localQ.reload);
|
|
12216
12216
|
} else if (r.kind === "ll-path") {
|
|
12217
12217
|
setInput(local?.path ?? "");
|
|
12218
12218
|
setEditing("path");
|
|
@@ -12223,7 +12223,7 @@ function SettingsPanel({
|
|
|
12223
12223
|
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
12224
|
);
|
|
12225
12225
|
} else if (r.kind === "wh") {
|
|
12226
|
-
|
|
12226
|
+
run11(r.wh.enabled ? "webhook disabled" : "webhook enabled", () => api.settings.updateWebhook(r.wh.id, { enabled: !r.wh.enabled }), whQ.reload);
|
|
12227
12227
|
} else if (r.kind === "wh-add") {
|
|
12228
12228
|
setInput("");
|
|
12229
12229
|
setEditing("wh-url");
|
|
@@ -12242,7 +12242,7 @@ function SettingsPanel({
|
|
|
12242
12242
|
setEditing(null);
|
|
12243
12243
|
if (which === "path") {
|
|
12244
12244
|
const enabled = (local?.enabled ?? false) && v.length > 0;
|
|
12245
|
-
|
|
12245
|
+
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
12246
|
} else if (which === "wh-url") {
|
|
12247
12247
|
const url = v.replace(/^["'<]+|["'>]+$/g, "").trim();
|
|
12248
12248
|
if (!url) return;
|
|
@@ -12250,7 +12250,7 @@ function SettingsPanel({
|
|
|
12250
12250
|
setMsg({ text: "\u2717 webhook url must start with http:// or https://", level: "bad" });
|
|
12251
12251
|
return;
|
|
12252
12252
|
}
|
|
12253
|
-
|
|
12253
|
+
run11("webhook added", () => api.settings.createWebhook({ url, events: "denials" }), whQ.reload);
|
|
12254
12254
|
} else if (which === "alert-target" && editor) {
|
|
12255
12255
|
setEditor({ ...editor, target: v, field: 1 });
|
|
12256
12256
|
}
|
|
@@ -12305,7 +12305,7 @@ function SettingsPanel({
|
|
|
12305
12305
|
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
12306
|
refreshAccounts();
|
|
12307
12307
|
} 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")
|
|
12308
|
+
if (cur.kind === "alert") run11(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
12309
12309
|
else activate(cur);
|
|
12310
12310
|
}
|
|
12311
12311
|
} else if (inp === "x" && cur.kind === "acct") {
|
|
@@ -12336,13 +12336,13 @@ function SettingsPanel({
|
|
|
12336
12336
|
refreshAccounts();
|
|
12337
12337
|
onAccountsChanged?.();
|
|
12338
12338
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
12339
|
-
|
|
12339
|
+
run11("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
12340
12340
|
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
12341
12341
|
}), whQ.reload);
|
|
12342
12342
|
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
12343
12343
|
else if (inp === "e" && cur.kind === "wh") {
|
|
12344
12344
|
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
12345
|
-
|
|
12345
|
+
run11(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
12346
12346
|
} else if (inp === "e" && cur.kind === "alert") {
|
|
12347
12347
|
const ch = alertChannel(cur.rule);
|
|
12348
12348
|
if (ch) openAlertEditor(ch, cur.rule);
|
|
@@ -12379,10 +12379,10 @@ function SettingsPanel({
|
|
|
12379
12379
|
setConfirmDel(null);
|
|
12380
12380
|
if (cur.kind === "wh") {
|
|
12381
12381
|
const id = cur.wh.id;
|
|
12382
|
-
|
|
12382
|
+
run11("webhook deleted", () => api.settings.deleteWebhook(id).then(() => setHidden((h) => new Set(h).add("wh:" + id))), whQ.reload);
|
|
12383
12383
|
} else {
|
|
12384
12384
|
const id = cur.rule.id;
|
|
12385
|
-
|
|
12385
|
+
run11("alert deleted", () => api.settings.deleteAlert(id).then(() => setHidden((h) => new Set(h).add("alert:" + id))), alertQ.reload);
|
|
12386
12386
|
}
|
|
12387
12387
|
} else if (inp === "r") reloadAll();
|
|
12388
12388
|
},
|
|
@@ -12770,9 +12770,9 @@ function App() {
|
|
|
12770
12770
|
const [update2, setUpdate] = useState9({ kind: "idle" });
|
|
12771
12771
|
useEffect8(() => {
|
|
12772
12772
|
let alive = true;
|
|
12773
|
-
const
|
|
12774
|
-
|
|
12775
|
-
const t = setInterval(
|
|
12773
|
+
const run11 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
12774
|
+
run11();
|
|
12775
|
+
const t = setInterval(run11, 30 * 6e4);
|
|
12776
12776
|
return () => {
|
|
12777
12777
|
alive = false;
|
|
12778
12778
|
clearInterval(t);
|
|
@@ -13092,13 +13092,15 @@ async function run2(argv) {
|
|
|
13092
13092
|
return 0;
|
|
13093
13093
|
}
|
|
13094
13094
|
case "activate": {
|
|
13095
|
-
if (flagBool(flags, "clear")) {
|
|
13095
|
+
if (flagBool(flags, "off") || flagBool(flags, "clear")) {
|
|
13096
13096
|
const res2 = await api.policies.setActive(null);
|
|
13097
13097
|
if (json) return printJson(res2), 0;
|
|
13098
|
-
|
|
13098
|
+
err(green(" \u2713 Deactivated - this project now enforces no policy."));
|
|
13099
|
+
err(dim(" Pin one again with: solongate policy activate <id>"));
|
|
13100
|
+
return 0;
|
|
13099
13101
|
}
|
|
13100
13102
|
const id = positionals[1];
|
|
13101
|
-
if (!id) return err(" Usage: policy activate <id> | policy activate --
|
|
13103
|
+
if (!id) return err(" Usage: policy activate <id> | policy activate --off"), 1;
|
|
13102
13104
|
const res = await api.policies.setActive(id);
|
|
13103
13105
|
if (json) return printJson(res), 0;
|
|
13104
13106
|
err(green(` \u2713 Pinned active policy \u2192 ${res.active}`));
|
|
@@ -13167,7 +13169,7 @@ var init_policy = __esm({
|
|
|
13167
13169
|
["policy deny <id> [--command|--path|--url <val>]", "append a DENY rule"],
|
|
13168
13170
|
["policy revoke <id> <ruleId>", "remove a rule"],
|
|
13169
13171
|
["policy active", "show the resolved active policy"],
|
|
13170
|
-
["policy activate <id> | --
|
|
13172
|
+
["policy activate <id> | --off", "pin the active policy, or enforce nothing"],
|
|
13171
13173
|
["policy dry-run <id|file.json> [--limit N] [--mode denylist|whitelist]", "replay recent traffic against rules"]
|
|
13172
13174
|
], "Add --json to any read command for machine-readable output.");
|
|
13173
13175
|
}
|
|
@@ -13339,14 +13341,108 @@ var init_dlp = __esm({
|
|
|
13339
13341
|
}
|
|
13340
13342
|
});
|
|
13341
13343
|
|
|
13342
|
-
// src/commands/
|
|
13344
|
+
// src/commands/ghost.ts
|
|
13343
13345
|
async function run5(argv) {
|
|
13346
|
+
const { positionals, flags } = parse(argv);
|
|
13347
|
+
const sub = positionals[0] ?? "show";
|
|
13348
|
+
const json = flagBool(flags, "json");
|
|
13349
|
+
if (sub === "help") return err(USAGE4), 0;
|
|
13350
|
+
const { layers } = await api.settings.getSecurityLayers();
|
|
13351
|
+
const save = async (next) => (await api.settings.setSecurityLayers(next)).layers;
|
|
13352
|
+
switch (sub) {
|
|
13353
|
+
case "show": {
|
|
13354
|
+
if (json) return printJson(layers.ghost), 0;
|
|
13355
|
+
err("");
|
|
13356
|
+
err(` Ghost mode: ${modeColor4(layers.ghost.mode)}`);
|
|
13357
|
+
if (!layers.ghost.patterns.length) {
|
|
13358
|
+
err(dim("\n No routes. `solongate ghost add <glob>` to hide a path."));
|
|
13359
|
+
return 0;
|
|
13360
|
+
}
|
|
13361
|
+
table(["", "ROUTE"], layers.ghost.patterns.map((r) => [cyan("\u2022"), r]));
|
|
13362
|
+
if (layers.ghost.mode !== "on") {
|
|
13363
|
+
err(dim("\n Ghost is off: these routes are stored but nothing is hidden."));
|
|
13364
|
+
}
|
|
13365
|
+
return 0;
|
|
13366
|
+
}
|
|
13367
|
+
case "on":
|
|
13368
|
+
case "off": {
|
|
13369
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, mode: sub } });
|
|
13370
|
+
if (json) return printJson(saved.ghost), 0;
|
|
13371
|
+
err(green(` \u2713 Ghost \u2192 ${saved.ghost.mode}`));
|
|
13372
|
+
if (sub === "on" && !saved.ghost.patterns.length) {
|
|
13373
|
+
err(dim(" No routes yet, so nothing is hidden. `solongate ghost add <glob>`."));
|
|
13374
|
+
}
|
|
13375
|
+
return 0;
|
|
13376
|
+
}
|
|
13377
|
+
case "add": {
|
|
13378
|
+
const glob = positionals.slice(1).join(" ");
|
|
13379
|
+
if (!glob) return err(" Usage: ghost add <glob>"), 1;
|
|
13380
|
+
if (isBlanketGlob(glob)) {
|
|
13381
|
+
err(`${red(" \u2717 ")}"${glob}" would hide every path.`);
|
|
13382
|
+
err(dim(" Ghost routes are globs: `*` is any run of non-whitespace."));
|
|
13383
|
+
err(dim(" Anchor it on something, e.g. *payroll.csv or *internal/*.pem"));
|
|
13384
|
+
return 1;
|
|
13385
|
+
}
|
|
13386
|
+
if (layers.ghost.patterns.includes(glob)) {
|
|
13387
|
+
if (json) return printJson(layers.ghost), 0;
|
|
13388
|
+
return err(green(` \u2713 Route "${glob}" is already hidden`)), 0;
|
|
13389
|
+
}
|
|
13390
|
+
const patterns = [...layers.ghost.patterns, glob];
|
|
13391
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, patterns } });
|
|
13392
|
+
if (json) return printJson(saved.ghost), 0;
|
|
13393
|
+
err(green(` \u2713 Hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s))`));
|
|
13394
|
+
if (saved.ghost.mode !== "on") {
|
|
13395
|
+
err(dim(" Ghost is off. `solongate ghost on` to start hiding."));
|
|
13396
|
+
}
|
|
13397
|
+
return 0;
|
|
13398
|
+
}
|
|
13399
|
+
case "remove": {
|
|
13400
|
+
const glob = positionals.slice(1).join(" ");
|
|
13401
|
+
if (!glob) return err(" Usage: ghost remove <glob>"), 1;
|
|
13402
|
+
if (!layers.ghost.patterns.includes(glob)) {
|
|
13403
|
+
err(` No such route: "${glob}"`);
|
|
13404
|
+
if (layers.ghost.patterns.length) {
|
|
13405
|
+
err(dim(" Current:"));
|
|
13406
|
+
for (const r of layers.ghost.patterns) err(` ${dim("\u2022")} ${r}`);
|
|
13407
|
+
}
|
|
13408
|
+
return 1;
|
|
13409
|
+
}
|
|
13410
|
+
const patterns = layers.ghost.patterns.filter((r) => r !== glob);
|
|
13411
|
+
const saved = await save({ ...layers, ghost: { ...layers.ghost, patterns } });
|
|
13412
|
+
if (json) return printJson(saved.ghost), 0;
|
|
13413
|
+
return err(green(` \u2713 Stopped hiding "${glob}"`) + dim(` (${saved.ghost.patterns.length} route(s) left)`)), 0;
|
|
13414
|
+
}
|
|
13415
|
+
default:
|
|
13416
|
+
return err(USAGE4), 1;
|
|
13417
|
+
}
|
|
13418
|
+
}
|
|
13419
|
+
var USAGE4, modeColor4, isBlanketGlob;
|
|
13420
|
+
var init_ghost = __esm({
|
|
13421
|
+
"src/commands/ghost.ts"() {
|
|
13422
|
+
"use strict";
|
|
13423
|
+
init_api_client();
|
|
13424
|
+
init_args();
|
|
13425
|
+
init_format();
|
|
13426
|
+
USAGE4 = usage("solongate ghost", "hidden paths", [
|
|
13427
|
+
["ghost show", "current mode + routes"],
|
|
13428
|
+
["ghost on", "start hiding the routes"],
|
|
13429
|
+
["ghost off", "stop hiding them (the routes are kept)"],
|
|
13430
|
+
["ghost add <glob>", "hide one more path"],
|
|
13431
|
+
["ghost remove <glob>", "stop hiding one path"]
|
|
13432
|
+
]);
|
|
13433
|
+
modeColor4 = (m) => m === "on" ? green(m) : dim("off");
|
|
13434
|
+
isBlanketGlob = (glob) => glob.replaceAll("*", "").trim() === "";
|
|
13435
|
+
}
|
|
13436
|
+
});
|
|
13437
|
+
|
|
13438
|
+
// src/commands/stats.ts
|
|
13439
|
+
async function run6(argv) {
|
|
13344
13440
|
const { positionals, flags } = parse(argv);
|
|
13345
13441
|
const sub = positionals[0] ?? "overview";
|
|
13346
13442
|
const json = flagBool(flags, "json");
|
|
13347
13443
|
switch (sub) {
|
|
13348
13444
|
case "help":
|
|
13349
|
-
return err(
|
|
13445
|
+
return err(USAGE5), 0;
|
|
13350
13446
|
case "overview": {
|
|
13351
13447
|
const s = await api.stats.get();
|
|
13352
13448
|
if (json) return printJson(s), 0;
|
|
@@ -13399,17 +13495,17 @@ async function run5(argv) {
|
|
|
13399
13495
|
return 0;
|
|
13400
13496
|
}
|
|
13401
13497
|
default:
|
|
13402
|
-
return err(
|
|
13498
|
+
return err(USAGE5), 1;
|
|
13403
13499
|
}
|
|
13404
13500
|
}
|
|
13405
|
-
var
|
|
13501
|
+
var USAGE5;
|
|
13406
13502
|
var init_stats2 = __esm({
|
|
13407
13503
|
"src/commands/stats.ts"() {
|
|
13408
13504
|
"use strict";
|
|
13409
13505
|
init_api_client();
|
|
13410
13506
|
init_args();
|
|
13411
13507
|
init_format();
|
|
13412
|
-
|
|
13508
|
+
USAGE5 = usage("solongate stats", "traffic & security stats", [
|
|
13413
13509
|
["stats", "overview (totals, recent activity)"],
|
|
13414
13510
|
["stats timeseries [--period 24h|7d|30d|all]"],
|
|
13415
13511
|
["stats drift [--days N]", "denials rising/falling vs previous window"]
|
|
@@ -13418,10 +13514,10 @@ var init_stats2 = __esm({
|
|
|
13418
13514
|
});
|
|
13419
13515
|
|
|
13420
13516
|
// src/commands/audit.ts
|
|
13421
|
-
async function
|
|
13517
|
+
async function run7(argv) {
|
|
13422
13518
|
const { positionals, flags } = parse(argv);
|
|
13423
13519
|
const json = flagBool(flags, "json");
|
|
13424
|
-
if (positionals[0] === "help") return err(
|
|
13520
|
+
if (positionals[0] === "help") return err(USAGE6), 0;
|
|
13425
13521
|
if (positionals[0] === "whitelist") {
|
|
13426
13522
|
const id = positionals[1];
|
|
13427
13523
|
if (!id) return err(" Usage: audit whitelist <logId> [--scope exact|tool]"), 1;
|
|
@@ -13469,14 +13565,14 @@ async function run6(argv) {
|
|
|
13469
13565
|
);
|
|
13470
13566
|
return 0;
|
|
13471
13567
|
}
|
|
13472
|
-
var
|
|
13568
|
+
var USAGE6;
|
|
13473
13569
|
var init_audit2 = __esm({
|
|
13474
13570
|
"src/commands/audit.ts"() {
|
|
13475
13571
|
"use strict";
|
|
13476
13572
|
init_api_client();
|
|
13477
13573
|
init_args();
|
|
13478
13574
|
init_format();
|
|
13479
|
-
|
|
13575
|
+
USAGE6 = usage("solongate audit", "audit log", [
|
|
13480
13576
|
["audit [--filter ALLOW|DENY] [--tool <substr>] [--signal dlp|ratelimit]"],
|
|
13481
13577
|
[" [--search <text>] [--agent-name <name>] [--limit N]"],
|
|
13482
13578
|
["audit whitelist <logId> [--scope exact|tool]", "turn a denied call into an ALLOW rule"],
|
|
@@ -13572,7 +13668,7 @@ function print(r, json) {
|
|
|
13572
13668
|
`${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}`
|
|
13573
13669
|
);
|
|
13574
13670
|
}
|
|
13575
|
-
async function
|
|
13671
|
+
async function run8(argv) {
|
|
13576
13672
|
const { flags } = parse(argv);
|
|
13577
13673
|
const json = flagBool(flags, "json");
|
|
13578
13674
|
const decisionFilter = (flagStr(flags, "filter") || "").toUpperCase();
|
|
@@ -13663,13 +13759,13 @@ var init_watch = __esm({
|
|
|
13663
13759
|
});
|
|
13664
13760
|
|
|
13665
13761
|
// src/commands/alerts.ts
|
|
13666
|
-
async function
|
|
13762
|
+
async function run9(argv) {
|
|
13667
13763
|
const { positionals, flags } = parse(argv);
|
|
13668
13764
|
const sub = positionals[0] ?? "list";
|
|
13669
13765
|
const json = flagBool(flags, "json");
|
|
13670
13766
|
switch (sub) {
|
|
13671
13767
|
case "help":
|
|
13672
|
-
return err(
|
|
13768
|
+
return err(USAGE7), 0;
|
|
13673
13769
|
case "list": {
|
|
13674
13770
|
const { rules } = await api.settings.getAlerts();
|
|
13675
13771
|
if (json) return printJson(rules), 0;
|
|
@@ -13711,17 +13807,17 @@ async function run8(argv) {
|
|
|
13711
13807
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
13712
13808
|
}
|
|
13713
13809
|
default:
|
|
13714
|
-
return err(
|
|
13810
|
+
return err(USAGE7), 1;
|
|
13715
13811
|
}
|
|
13716
13812
|
}
|
|
13717
|
-
var
|
|
13813
|
+
var USAGE7;
|
|
13718
13814
|
var init_alerts = __esm({
|
|
13719
13815
|
"src/commands/alerts.ts"() {
|
|
13720
13816
|
"use strict";
|
|
13721
13817
|
init_api_client();
|
|
13722
13818
|
init_args();
|
|
13723
13819
|
init_format();
|
|
13724
|
-
|
|
13820
|
+
USAGE7 = usage("solongate alerts", "spike alerts (Telegram / email)", [
|
|
13725
13821
|
["alerts list"],
|
|
13726
13822
|
["alerts add --signal deny|dlp|ratelimit|any --threshold N --window S"],
|
|
13727
13823
|
[" (--email <a> | --telegram <chatId> | --slack <url>)"],
|
|
@@ -13731,13 +13827,13 @@ var init_alerts = __esm({
|
|
|
13731
13827
|
});
|
|
13732
13828
|
|
|
13733
13829
|
// src/commands/webhooks.ts
|
|
13734
|
-
async function
|
|
13830
|
+
async function run10(argv) {
|
|
13735
13831
|
const { positionals, flags } = parse(argv);
|
|
13736
13832
|
const sub = positionals[0] ?? "list";
|
|
13737
13833
|
const json = flagBool(flags, "json");
|
|
13738
13834
|
switch (sub) {
|
|
13739
13835
|
case "help":
|
|
13740
|
-
return err(
|
|
13836
|
+
return err(USAGE8), 0;
|
|
13741
13837
|
case "list": {
|
|
13742
13838
|
const { webhooks } = await api.settings.getWebhooks();
|
|
13743
13839
|
if (json) return printJson(webhooks), 0;
|
|
@@ -13763,17 +13859,17 @@ async function run9(argv) {
|
|
|
13763
13859
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
13764
13860
|
}
|
|
13765
13861
|
default:
|
|
13766
|
-
return err(
|
|
13862
|
+
return err(USAGE8), 1;
|
|
13767
13863
|
}
|
|
13768
13864
|
}
|
|
13769
|
-
var
|
|
13865
|
+
var USAGE8;
|
|
13770
13866
|
var init_webhooks = __esm({
|
|
13771
13867
|
"src/commands/webhooks.ts"() {
|
|
13772
13868
|
"use strict";
|
|
13773
13869
|
init_api_client();
|
|
13774
13870
|
init_args();
|
|
13775
13871
|
init_format();
|
|
13776
|
-
|
|
13872
|
+
USAGE8 = usage("solongate webhooks", "event webhooks", [
|
|
13777
13873
|
["webhooks list"],
|
|
13778
13874
|
["webhooks add --url <https://\u2026> [--events denials|allowed|all]"],
|
|
13779
13875
|
["webhooks remove <id>"]
|
|
@@ -13795,10 +13891,12 @@ async function dispatch(command, argv) {
|
|
|
13795
13891
|
return run3(argv);
|
|
13796
13892
|
case "dlp":
|
|
13797
13893
|
return run4(argv);
|
|
13798
|
-
case "
|
|
13894
|
+
case "ghost":
|
|
13799
13895
|
return run5(argv);
|
|
13800
|
-
case "
|
|
13896
|
+
case "stats":
|
|
13801
13897
|
return run6(argv);
|
|
13898
|
+
case "audit":
|
|
13899
|
+
return run7(argv);
|
|
13802
13900
|
case "sessions":
|
|
13803
13901
|
return runAgents(argv);
|
|
13804
13902
|
case "session":
|
|
@@ -13806,11 +13904,11 @@ async function dispatch(command, argv) {
|
|
|
13806
13904
|
case "doctor":
|
|
13807
13905
|
return run(argv);
|
|
13808
13906
|
case "watch":
|
|
13809
|
-
return run7(argv);
|
|
13810
|
-
case "alerts":
|
|
13811
13907
|
return run8(argv);
|
|
13812
|
-
case "
|
|
13908
|
+
case "alerts":
|
|
13813
13909
|
return run9(argv);
|
|
13910
|
+
case "webhooks":
|
|
13911
|
+
return run10(argv);
|
|
13814
13912
|
default:
|
|
13815
13913
|
err(` Unknown command: ${command}`);
|
|
13816
13914
|
return 1;
|
|
@@ -13842,6 +13940,7 @@ var init_commands = __esm({
|
|
|
13842
13940
|
init_policy();
|
|
13843
13941
|
init_ratelimit();
|
|
13844
13942
|
init_dlp();
|
|
13943
|
+
init_ghost();
|
|
13845
13944
|
init_stats2();
|
|
13846
13945
|
init_audit2();
|
|
13847
13946
|
init_agents2();
|
|
@@ -17438,7 +17537,7 @@ ${msg.content.text}`;
|
|
|
17438
17537
|
|
|
17439
17538
|
// src/index.ts
|
|
17440
17539
|
init_cli_utils();
|
|
17441
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["update", "repair", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
|
|
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"]);
|
|
17442
17541
|
var CLI_INFO_ARGS = /* @__PURE__ */ new Set(["login", "help", "--help", "-h", "--version", "-v", "version"]);
|
|
17443
17542
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "") || CLI_INFO_ARGS.has(process.argv[2] ?? "");
|
|
17444
17543
|
if (!IS_HUMAN_CLI) {
|
|
@@ -17515,7 +17614,7 @@ function printHelp() {
|
|
|
17515
17614
|
cmd("policy allow <id> [--command|--path|--url <val>]", "add an ALLOW rule");
|
|
17516
17615
|
cmd("policy deny <id> [--command|--path|--url <val>]", "add a DENY rule");
|
|
17517
17616
|
cmd("policy revoke <id> <ruleId>", "remove a rule");
|
|
17518
|
-
cmd("policy activate <id> | --
|
|
17617
|
+
cmd("policy activate <id> | --off", "pin the active policy, or enforce nothing");
|
|
17519
17618
|
cmd("policy active", "show the resolved active policy");
|
|
17520
17619
|
cmd("policy dry-run <id|file.json> [--mode denylist|whitelist]", "replay recent traffic against rules");
|
|
17521
17620
|
head("Rate limits");
|
|
@@ -17529,6 +17628,11 @@ function printHelp() {
|
|
|
17529
17628
|
cmd("dlp disable <pattern>", "disable a built-in pattern");
|
|
17530
17629
|
cmd("dlp add-custom --name X --re <regex>", "add a custom pattern");
|
|
17531
17630
|
cmd("dlp remove-custom <name>", "remove a custom pattern");
|
|
17631
|
+
head("Ghost (hidden paths)");
|
|
17632
|
+
cmd("ghost show", "current mode + routes");
|
|
17633
|
+
cmd("ghost on | off", "start or stop hiding the routes");
|
|
17634
|
+
cmd("ghost add <glob>", "hide one more path");
|
|
17635
|
+
cmd("ghost remove <glob>", "stop hiding one path");
|
|
17532
17636
|
head("Monitoring");
|
|
17533
17637
|
cmd("audit [--filter ALLOW|DENY] [--tool <s>] [--signal dlp|ratelimit] [--limit N]", "browse the audit log");
|
|
17534
17638
|
cmd("audit whitelist <logId> [--scope exact|tool]", "turn a denial into an ALLOW rule");
|
|
@@ -17627,7 +17731,7 @@ async function main() {
|
|
|
17627
17731
|
await launchTui2();
|
|
17628
17732
|
return;
|
|
17629
17733
|
}
|
|
17630
|
-
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
|
|
17734
|
+
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "ghost", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
|
|
17631
17735
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
17632
17736
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
17633
17737
|
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.34",
|
|
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.34",
|
|
65
|
+
"@solongate/guard-linux-arm64": "0.83.34",
|
|
66
|
+
"@solongate/guard-darwin-x64": "0.83.34",
|
|
67
|
+
"@solongate/guard-darwin-arm64": "0.83.34",
|
|
68
|
+
"@solongate/guard-win32-x64": "0.83.34",
|
|
69
|
+
"@solongate/guard-win32-arm64": "0.83.34"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"@modelcontextprotocol/sdk": "^1.26.0",
|