@solongate/proxy 0.82.24 → 0.82.25
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/agents.d.ts +2 -2
- package/dist/commands/format.d.ts +7 -0
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/index.js +84 -78
- package/dist/index.js +84 -78
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** `solongate agents`
|
|
1
|
+
/** `solongate agents` - the live feed. */
|
|
2
2
|
export declare function runAgents(argv: string[]): Promise<number>;
|
|
3
|
-
/** `solongate agent <id>`
|
|
3
|
+
/** `solongate agent <id>` - deep detail for one agent. */
|
|
4
4
|
export declare function runAgent(argv: string[]): Promise<number>;
|
|
@@ -8,6 +8,13 @@ export declare const green: (s: string) => string;
|
|
|
8
8
|
export declare const red: (s: string) => string;
|
|
9
9
|
export declare const yellow: (s: string) => string;
|
|
10
10
|
export declare const cyan: (s: string) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Render a colored command usage block, matching the top-level `solongate --help`
|
|
13
|
+
* style: bold title, cyan command syntax, dim descriptions. `rows` are
|
|
14
|
+
* [syntax, description?] pairs; a syntax with no description prints on its own
|
|
15
|
+
* (used for long or continuation lines). Returns the whole block as one string.
|
|
16
|
+
*/
|
|
17
|
+
export declare function usage(title: string, tagline: string, rows: Array<[string, string?]>, footer?: string): string;
|
|
11
18
|
/** Color a decision string (ALLOW green, DENY/DENIED red). */
|
|
12
19
|
export declare function decisionColor(decision: string): string;
|
|
13
20
|
/**
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Run a management command. `command` is the subcommand name (e.g. 'policy'),
|
|
3
|
-
* `argv` are the tokens after it. Never throws
|
|
3
|
+
* `argv` are the tokens after it. Never throws - resolves to an exit code.
|
|
4
4
|
*/
|
|
5
5
|
export declare function runCommand(command: string, argv: string[]): Promise<number>;
|
|
6
6
|
/** The subcommand names this router owns (used by src/index.ts to route). */
|
package/dist/commands/index.js
CHANGED
|
@@ -418,6 +418,28 @@ var green = (s) => `${c.green}${s}${c.reset}`;
|
|
|
418
418
|
var red = (s) => `${c.red}${s}${c.reset}`;
|
|
419
419
|
var yellow = (s) => `${c.yellow}${s}${c.reset}`;
|
|
420
420
|
var cyan = (s) => `${c.cyan}${s}${c.reset}`;
|
|
421
|
+
function usage(title, tagline, rows, footer = "Add --json for machine-readable output.") {
|
|
422
|
+
const W = 40;
|
|
423
|
+
const lines = ["", ` ${c.bold}${c.blue4}${title}${c.reset} ${c.dim}${tagline}${c.reset}`, ""];
|
|
424
|
+
for (const [syntax, desc] of rows) {
|
|
425
|
+
if (!syntax) {
|
|
426
|
+
lines.push("");
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
if (desc === void 0) {
|
|
430
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}`);
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
if (syntax.length <= W) {
|
|
434
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}${" ".repeat(W - syntax.length)}${c.dim}${desc}${c.reset}`);
|
|
435
|
+
} else {
|
|
436
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}`);
|
|
437
|
+
lines.push(` ${" ".repeat(W)}${c.dim}${desc}${c.reset}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (footer) lines.push("", ` ${c.dim}${footer}${c.reset}`);
|
|
441
|
+
return lines.join("\n");
|
|
442
|
+
}
|
|
421
443
|
function decisionColor(decision) {
|
|
422
444
|
const d = decision.toUpperCase();
|
|
423
445
|
if (d === "ALLOW") return green(d);
|
|
@@ -495,20 +517,16 @@ function flagBool(flags, name) {
|
|
|
495
517
|
}
|
|
496
518
|
|
|
497
519
|
// src/commands/policy.ts
|
|
498
|
-
var USAGE =
|
|
499
|
-
|
|
500
|
-
policy
|
|
501
|
-
policy
|
|
502
|
-
policy
|
|
503
|
-
policy
|
|
504
|
-
|
|
505
|
-
policy
|
|
506
|
-
policy
|
|
507
|
-
|
|
508
|
-
policy dry-run <id|file.json> [--limit N] [--mode denylist|whitelist]
|
|
509
|
-
Replay recent traffic against a policy's rules
|
|
510
|
-
|
|
511
|
-
Add --json to any read command for machine-readable output.`;
|
|
520
|
+
var USAGE = usage("solongate policy", "manage cloud policies", [
|
|
521
|
+
["policy list", "list all policies"],
|
|
522
|
+
["policy show <id> [--version N]", "show one policy (rules, mode)"],
|
|
523
|
+
["policy rules <id>", "list a policy's rules"],
|
|
524
|
+
["policy allow <id> --tool <p> [--command|--path|--url <val>]", "append an ALLOW rule"],
|
|
525
|
+
["policy revoke <id> <ruleId>", "remove a rule"],
|
|
526
|
+
["policy active", "show the resolved active policy"],
|
|
527
|
+
["policy activate <id> | --clear", "pin / unpin the active policy"],
|
|
528
|
+
["policy dry-run <id|file.json> [--limit N] [--mode denylist|whitelist]", "replay recent traffic against rules"]
|
|
529
|
+
], "Add --json to any read command for machine-readable output.");
|
|
512
530
|
async function run(argv) {
|
|
513
531
|
const { positionals, flags } = parse(argv);
|
|
514
532
|
const sub = positionals[0];
|
|
@@ -533,7 +551,7 @@ async function run(argv) {
|
|
|
533
551
|
p.mode === "whitelist" ? green("whitelist") : "denylist",
|
|
534
552
|
String(p.rules?.length ?? 0),
|
|
535
553
|
`v${p.version}`,
|
|
536
|
-
dim(truncate(p.created_by || "
|
|
554
|
+
dim(truncate(p.created_by || "-", 20))
|
|
537
555
|
])
|
|
538
556
|
);
|
|
539
557
|
return 0;
|
|
@@ -596,7 +614,7 @@ async function run(argv) {
|
|
|
596
614
|
}
|
|
597
615
|
err("");
|
|
598
616
|
err(` Active: ${bold(a.policy.name)} ${dim(`(${a.policy.id})`)} v${a.version}`);
|
|
599
|
-
err(` matched by: ${cyan(a.matched_by ?? "
|
|
617
|
+
err(` matched by: ${cyan(a.matched_by ?? "-")} self-protection: ${a.self_protection_enabled ? green("on") : dim("off")}`);
|
|
600
618
|
const rl = a.security?.rateLimit;
|
|
601
619
|
if (rl) err(` rate limit: ${rl.perMinute}/min ${rl.perHour}/h ${rl.perDay}/day`);
|
|
602
620
|
if (a.security?.dlpBlock) err(` DLP block: ${a.security.dlpBlock.patterns.length} patterns`);
|
|
@@ -651,7 +669,7 @@ function printRules(rules) {
|
|
|
651
669
|
String(r.priority),
|
|
652
670
|
cyan(truncate(r.toolPattern, 24)),
|
|
653
671
|
dim(truncate(r.id, 22)),
|
|
654
|
-
truncate(r.description || "
|
|
672
|
+
truncate(r.description || "-", 40)
|
|
655
673
|
])
|
|
656
674
|
);
|
|
657
675
|
}
|
|
@@ -665,13 +683,11 @@ async function resolveRules(target) {
|
|
|
665
683
|
}
|
|
666
684
|
|
|
667
685
|
// src/commands/ratelimit.ts
|
|
668
|
-
var USAGE2 =
|
|
669
|
-
|
|
670
|
-
ratelimit
|
|
671
|
-
ratelimit
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
Add --json for machine-readable output.`;
|
|
686
|
+
var USAGE2 = usage("solongate ratelimit", "request throttling", [
|
|
687
|
+
["ratelimit show", "current limits + change history"],
|
|
688
|
+
["ratelimit set --minute N [--hour N] [--day N] [--mode off|detect|block]"],
|
|
689
|
+
["ratelimit history", "recent limit changes"]
|
|
690
|
+
]);
|
|
675
691
|
var modeColor = (m) => m === "block" ? green(m) : m === "detect" ? yellow(m) : dim(m);
|
|
676
692
|
async function run2(argv) {
|
|
677
693
|
const { positionals, flags } = parse(argv);
|
|
@@ -736,16 +752,14 @@ async function run2(argv) {
|
|
|
736
752
|
}
|
|
737
753
|
|
|
738
754
|
// src/commands/dlp.ts
|
|
739
|
-
var USAGE3 =
|
|
740
|
-
|
|
741
|
-
dlp
|
|
742
|
-
dlp
|
|
743
|
-
dlp
|
|
744
|
-
dlp
|
|
745
|
-
dlp
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
Add --json for machine-readable output.`;
|
|
755
|
+
var USAGE3 = usage("solongate dlp", "data-loss prevention", [
|
|
756
|
+
["dlp show", "current mode + enabled patterns"],
|
|
757
|
+
["dlp mode <off|detect|block>", "set enforcement mode"],
|
|
758
|
+
["dlp enable <pattern>", "enable a built-in pattern"],
|
|
759
|
+
["dlp disable <pattern>", "disable a built-in pattern"],
|
|
760
|
+
["dlp add-custom --name X --re <regex>", "add a custom pattern"],
|
|
761
|
+
["dlp remove-custom <name>", "remove a custom pattern"]
|
|
762
|
+
]);
|
|
749
763
|
var modeColor2 = (m) => m === "block" ? green(m) : m === "detect" ? yellow(m) : dim(m);
|
|
750
764
|
async function run3(argv) {
|
|
751
765
|
const { positionals, flags } = parse(argv);
|
|
@@ -817,13 +831,11 @@ async function run3(argv) {
|
|
|
817
831
|
}
|
|
818
832
|
|
|
819
833
|
// src/commands/stats.ts
|
|
820
|
-
var USAGE4 =
|
|
821
|
-
|
|
822
|
-
stats
|
|
823
|
-
stats
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
Add --json for machine-readable output.`;
|
|
834
|
+
var USAGE4 = usage("solongate stats", "traffic & security stats", [
|
|
835
|
+
["stats", "overview (totals, recent activity)"],
|
|
836
|
+
["stats timeseries [--period 24h|7d|30d|all]"],
|
|
837
|
+
["stats drift [--days N]", "denials rising/falling vs previous window"]
|
|
838
|
+
]);
|
|
827
839
|
async function run4(argv) {
|
|
828
840
|
const { positionals, flags } = parse(argv);
|
|
829
841
|
const sub = positionals[0] ?? "overview";
|
|
@@ -845,7 +857,7 @@ async function run4(argv) {
|
|
|
845
857
|
decisionColor(a.decision),
|
|
846
858
|
cyan(truncate(a.tool_name, 24)),
|
|
847
859
|
dim(a.trust_level),
|
|
848
|
-
String(a.evaluation_time_ms ?? "
|
|
860
|
+
String(a.evaluation_time_ms ?? "-"),
|
|
849
861
|
dim(a.created_at)
|
|
850
862
|
])
|
|
851
863
|
);
|
|
@@ -876,8 +888,8 @@ async function run4(argv) {
|
|
|
876
888
|
bold(String(r.current)),
|
|
877
889
|
dim(String(r.previous)),
|
|
878
890
|
r.is_new ? green("NEW") : r.spike ? red(`+${r.delta}`) : String(r.delta),
|
|
879
|
-
cyan(truncate(r.rule_id ?? "
|
|
880
|
-
truncate(r.reason ?? r.last_tool ?? "
|
|
891
|
+
cyan(truncate(r.rule_id ?? "-", 22)),
|
|
892
|
+
truncate(r.reason ?? r.last_tool ?? "-", 36)
|
|
881
893
|
])
|
|
882
894
|
);
|
|
883
895
|
return 0;
|
|
@@ -888,14 +900,12 @@ async function run4(argv) {
|
|
|
888
900
|
}
|
|
889
901
|
|
|
890
902
|
// src/commands/audit.ts
|
|
891
|
-
var USAGE5 =
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
audit
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
Add --json for machine-readable output.`;
|
|
903
|
+
var USAGE5 = usage("solongate audit", "audit log", [
|
|
904
|
+
["audit [--filter ALLOW|DENY] [--tool <substr>] [--signal dlp|ratelimit]"],
|
|
905
|
+
[" [--search <text>] [--agent-name <name>] [--limit N]"],
|
|
906
|
+
["audit whitelist <logId> [--scope exact|tool]", "turn a denied call into an ALLOW rule"],
|
|
907
|
+
["audit block <logId> [--scope exact|tool]", "turn a call into a DENY rule"]
|
|
908
|
+
]);
|
|
899
909
|
async function run5(argv) {
|
|
900
910
|
const { positionals, flags } = parse(argv);
|
|
901
911
|
const json = flagBool(flags, "json");
|
|
@@ -938,8 +948,8 @@ async function run5(argv) {
|
|
|
938
948
|
res.entries.map((e) => [
|
|
939
949
|
decisionColor(e.decision),
|
|
940
950
|
cyan(truncate(e.tool_name, 22)),
|
|
941
|
-
dim(truncate(e.agent_name ?? "
|
|
942
|
-
truncate(e.reason ?? "
|
|
951
|
+
dim(truncate(e.agent_name ?? "-", 16)),
|
|
952
|
+
truncate(e.reason ?? "-", 30),
|
|
943
953
|
e.dlp_matches?.length ? red(String(e.dlp_matches.length)) : dim("0"),
|
|
944
954
|
dim(e.created_at),
|
|
945
955
|
dim(truncate(e.id, 10))
|
|
@@ -967,7 +977,7 @@ async function runAgents(argv) {
|
|
|
967
977
|
a.denied_calls ? red(String(a.denied_calls)) : dim("0"),
|
|
968
978
|
a.dlp_events ? red(String(a.dlp_events)) : dim("0"),
|
|
969
979
|
`${a.trust_score}`,
|
|
970
|
-
dim(truncate(a.character || "
|
|
980
|
+
dim(truncate(a.character || "-", 22))
|
|
971
981
|
])
|
|
972
982
|
);
|
|
973
983
|
return 0;
|
|
@@ -983,7 +993,7 @@ async function runAgent(argv) {
|
|
|
983
993
|
err(` ${bold(a.agent_id)} status: ${statusColor(String(a.status))}`);
|
|
984
994
|
const base = a.baseline;
|
|
985
995
|
if (base) {
|
|
986
|
-
err(` ${dim(base.character ?? "")} trust ${bold(String(base.trustScore ?? "
|
|
996
|
+
err(` ${dim(base.character ?? "")} trust ${bold(String(base.trustScore ?? "-"))}/100 deny-rate ${(Number(base.denyRate ?? 0) * 100).toFixed(0)}%`);
|
|
987
997
|
}
|
|
988
998
|
const feed = a.recent_feed ?? [];
|
|
989
999
|
if (feed.length) {
|
|
@@ -993,7 +1003,7 @@ async function runAgent(argv) {
|
|
|
993
1003
|
feed.slice(0, 15).map((f) => [
|
|
994
1004
|
f.decision === "ALLOW" ? green("ALLOW") : red(String(f.decision)),
|
|
995
1005
|
cyan(truncate(String(f.tool), 22)),
|
|
996
|
-
truncate(String(f.reason ?? "
|
|
1006
|
+
truncate(String(f.reason ?? "-"), 30),
|
|
997
1007
|
dim(String(f.created_at))
|
|
998
1008
|
])
|
|
999
1009
|
);
|
|
@@ -1011,7 +1021,7 @@ async function run6(argv) {
|
|
|
1011
1021
|
const json = flagBool(flags, "json");
|
|
1012
1022
|
const checks = [];
|
|
1013
1023
|
if (!isAuthenticated()) {
|
|
1014
|
-
checks.push({ name: "login", ok: false, detail: "not logged in
|
|
1024
|
+
checks.push({ name: "login", ok: false, detail: "not logged in - run `solongate`, add your account in the Accounts panel" });
|
|
1015
1025
|
} else {
|
|
1016
1026
|
const { apiUrl } = resolveCredentials();
|
|
1017
1027
|
checks.push({ name: "login", ok: true, detail: `paired \xB7 ${apiUrl}` });
|
|
@@ -1020,7 +1030,7 @@ async function run6(argv) {
|
|
|
1020
1030
|
if (active2.policy) {
|
|
1021
1031
|
checks.push({ name: "active policy", ok: true, detail: `${active2.policy.name} v${active2.version} \xB7 ${active2.policy.mode ?? "denylist"} \xB7 matched by ${active2.matched_by}` });
|
|
1022
1032
|
} else {
|
|
1023
|
-
checks.push({ name: "active policy", ok: "warn", detail: "no policy resolves
|
|
1033
|
+
checks.push({ name: "active policy", ok: "warn", detail: "no policy resolves - every call falls back to default" });
|
|
1024
1034
|
}
|
|
1025
1035
|
const sec = active2.security;
|
|
1026
1036
|
checks.push({ name: "rate limit", ok: sec?.rateLimit ? true : "warn", detail: sec?.rateLimit ? `${sec.rateLimit.perMinute}/min` : "off" });
|
|
@@ -1040,7 +1050,7 @@ async function run6(argv) {
|
|
|
1040
1050
|
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
1041
1051
|
checks.push({ name: "local logs", ok: true, detail: `on \xB7 ${(st.size / 1024).toFixed(0)}KB \xB7 last write ${ageMin < 1 ? "just now" : Math.round(ageMin) + "m ago"}` });
|
|
1042
1052
|
} else {
|
|
1043
|
-
checks.push({ name: "local logs", ok: "warn", detail: "off (logs go to cloud)
|
|
1053
|
+
checks.push({ name: "local logs", ok: "warn", detail: "off (logs go to cloud) - enable in dashboard \u2192 Settings" });
|
|
1044
1054
|
}
|
|
1045
1055
|
if (json) return printJson(checks), checks.some((c2) => c2.ok === false) ? 1 : 0;
|
|
1046
1056
|
err("");
|
|
@@ -1054,7 +1064,7 @@ async function run6(argv) {
|
|
|
1054
1064
|
const bad = checks.filter((c2) => c2.ok === false).length;
|
|
1055
1065
|
const warn = checks.filter((c2) => c2.ok === "warn").length;
|
|
1056
1066
|
if (bad) err(` ${red(`${bad} problem(s)`)}${warn ? dim(` \xB7 ${warn} warning(s)`) : ""}`);
|
|
1057
|
-
else if (warn) err(` ${yellow(`${warn} warning(s)`)} ${dim("
|
|
1067
|
+
else if (warn) err(` ${yellow(`${warn} warning(s)`)} ${dim("- guard is working")}`);
|
|
1058
1068
|
else err(` ${green("all good")}`);
|
|
1059
1069
|
return bad ? 1 : 0;
|
|
1060
1070
|
}
|
|
@@ -1155,7 +1165,7 @@ async function run7(argv) {
|
|
|
1155
1165
|
} catch {
|
|
1156
1166
|
}
|
|
1157
1167
|
};
|
|
1158
|
-
if (!json) err(` ${c.dim}watching guard stream
|
|
1168
|
+
if (!json) err(` ${c.dim}watching guard stream - Ctrl+C to stop${c.reset}`);
|
|
1159
1169
|
pollLocal();
|
|
1160
1170
|
await pollCloud();
|
|
1161
1171
|
first = false;
|
|
@@ -1166,14 +1176,12 @@ async function run7(argv) {
|
|
|
1166
1176
|
}
|
|
1167
1177
|
|
|
1168
1178
|
// src/commands/alerts.ts
|
|
1169
|
-
var USAGE6 =
|
|
1170
|
-
|
|
1171
|
-
alerts
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
Add --json for machine-readable output.`;
|
|
1179
|
+
var USAGE6 = usage("solongate alerts", "spike alerts (Telegram / email)", [
|
|
1180
|
+
["alerts list"],
|
|
1181
|
+
["alerts add --signal deny|dlp|ratelimit|any --threshold N --window S"],
|
|
1182
|
+
[" (--email <a> | --telegram <chatId> | --slack <url>)"],
|
|
1183
|
+
["alerts remove <id>"]
|
|
1184
|
+
]);
|
|
1177
1185
|
async function run8(argv) {
|
|
1178
1186
|
const { positionals, flags } = parse(argv);
|
|
1179
1187
|
const sub = positionals[0] ?? "list";
|
|
@@ -1193,7 +1201,7 @@ async function run8(argv) {
|
|
|
1193
1201
|
cyan(r.signal),
|
|
1194
1202
|
`${r.threshold}`,
|
|
1195
1203
|
`${r.windowSeconds}s`,
|
|
1196
|
-
dim([...r.emails ?? [], ...(r.telegram ?? []).map((t) => "tg:" + t), ...(r.slackUrls ?? []).map(() => "slack")].join(" ") || "
|
|
1204
|
+
dim([...r.emails ?? [], ...(r.telegram ?? []).map((t) => "tg:" + t), ...(r.slackUrls ?? []).map(() => "slack")].join(" ") || "-")
|
|
1197
1205
|
])
|
|
1198
1206
|
);
|
|
1199
1207
|
return 0;
|
|
@@ -1227,13 +1235,11 @@ async function run8(argv) {
|
|
|
1227
1235
|
}
|
|
1228
1236
|
|
|
1229
1237
|
// src/commands/webhooks.ts
|
|
1230
|
-
var USAGE7 =
|
|
1231
|
-
|
|
1232
|
-
webhooks
|
|
1233
|
-
webhooks
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
Add --json for machine-readable output.`;
|
|
1238
|
+
var USAGE7 = usage("solongate webhooks", "event webhooks", [
|
|
1239
|
+
["webhooks list"],
|
|
1240
|
+
["webhooks add --url <https://\u2026> [--events denials|allowed|all]"],
|
|
1241
|
+
["webhooks remove <id>"]
|
|
1242
|
+
]);
|
|
1237
1243
|
async function run9(argv) {
|
|
1238
1244
|
const { positionals, flags } = parse(argv);
|
|
1239
1245
|
const sub = positionals[0] ?? "list";
|
package/dist/index.js
CHANGED
|
@@ -11326,6 +11326,28 @@ var init_tui = __esm({
|
|
|
11326
11326
|
function printJson(value) {
|
|
11327
11327
|
out(JSON.stringify(value, null, 2));
|
|
11328
11328
|
}
|
|
11329
|
+
function usage(title, tagline, rows, footer = "Add --json for machine-readable output.") {
|
|
11330
|
+
const W = 40;
|
|
11331
|
+
const lines = ["", ` ${c.bold}${c.blue4}${title}${c.reset} ${c.dim}${tagline}${c.reset}`, ""];
|
|
11332
|
+
for (const [syntax, desc] of rows) {
|
|
11333
|
+
if (!syntax) {
|
|
11334
|
+
lines.push("");
|
|
11335
|
+
continue;
|
|
11336
|
+
}
|
|
11337
|
+
if (desc === void 0) {
|
|
11338
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}`);
|
|
11339
|
+
continue;
|
|
11340
|
+
}
|
|
11341
|
+
if (syntax.length <= W) {
|
|
11342
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}${" ".repeat(W - syntax.length)}${c.dim}${desc}${c.reset}`);
|
|
11343
|
+
} else {
|
|
11344
|
+
lines.push(` ${c.cyan}${syntax}${c.reset}`);
|
|
11345
|
+
lines.push(` ${" ".repeat(W)}${c.dim}${desc}${c.reset}`);
|
|
11346
|
+
}
|
|
11347
|
+
}
|
|
11348
|
+
if (footer) lines.push("", ` ${c.dim}${footer}${c.reset}`);
|
|
11349
|
+
return lines.join("\n");
|
|
11350
|
+
}
|
|
11329
11351
|
function decisionColor2(decision) {
|
|
11330
11352
|
const d = decision.toUpperCase();
|
|
11331
11353
|
if (d === "ALLOW") return green(d);
|
|
@@ -11445,7 +11467,7 @@ async function run(argv) {
|
|
|
11445
11467
|
p.mode === "whitelist" ? green("whitelist") : "denylist",
|
|
11446
11468
|
String(p.rules?.length ?? 0),
|
|
11447
11469
|
`v${p.version}`,
|
|
11448
|
-
dim(truncate3(p.created_by || "
|
|
11470
|
+
dim(truncate3(p.created_by || "-", 20))
|
|
11449
11471
|
])
|
|
11450
11472
|
);
|
|
11451
11473
|
return 0;
|
|
@@ -11508,7 +11530,7 @@ async function run(argv) {
|
|
|
11508
11530
|
}
|
|
11509
11531
|
err("");
|
|
11510
11532
|
err(` Active: ${bold(a.policy.name)} ${dim(`(${a.policy.id})`)} v${a.version}`);
|
|
11511
|
-
err(` matched by: ${cyan(a.matched_by ?? "
|
|
11533
|
+
err(` matched by: ${cyan(a.matched_by ?? "-")} self-protection: ${a.self_protection_enabled ? green("on") : dim("off")}`);
|
|
11512
11534
|
const rl = a.security?.rateLimit;
|
|
11513
11535
|
if (rl) err(` rate limit: ${rl.perMinute}/min ${rl.perHour}/h ${rl.perDay}/day`);
|
|
11514
11536
|
if (a.security?.dlpBlock) err(` DLP block: ${a.security.dlpBlock.patterns.length} patterns`);
|
|
@@ -11563,7 +11585,7 @@ function printRules(rules) {
|
|
|
11563
11585
|
String(r.priority),
|
|
11564
11586
|
cyan(truncate3(r.toolPattern, 24)),
|
|
11565
11587
|
dim(truncate3(r.id, 22)),
|
|
11566
|
-
truncate3(r.description || "
|
|
11588
|
+
truncate3(r.description || "-", 40)
|
|
11567
11589
|
])
|
|
11568
11590
|
);
|
|
11569
11591
|
}
|
|
@@ -11582,20 +11604,16 @@ var init_policy = __esm({
|
|
|
11582
11604
|
init_api_client();
|
|
11583
11605
|
init_args();
|
|
11584
11606
|
init_format();
|
|
11585
|
-
USAGE =
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
policy dry-run <id|file.json> [--limit N] [--mode denylist|whitelist]
|
|
11596
|
-
Replay recent traffic against a policy's rules
|
|
11597
|
-
|
|
11598
|
-
Add --json to any read command for machine-readable output.`;
|
|
11607
|
+
USAGE = usage("solongate policy", "manage cloud policies", [
|
|
11608
|
+
["policy list", "list all policies"],
|
|
11609
|
+
["policy show <id> [--version N]", "show one policy (rules, mode)"],
|
|
11610
|
+
["policy rules <id>", "list a policy's rules"],
|
|
11611
|
+
["policy allow <id> --tool <p> [--command|--path|--url <val>]", "append an ALLOW rule"],
|
|
11612
|
+
["policy revoke <id> <ruleId>", "remove a rule"],
|
|
11613
|
+
["policy active", "show the resolved active policy"],
|
|
11614
|
+
["policy activate <id> | --clear", "pin / unpin the active policy"],
|
|
11615
|
+
["policy dry-run <id|file.json> [--limit N] [--mode denylist|whitelist]", "replay recent traffic against rules"]
|
|
11616
|
+
], "Add --json to any read command for machine-readable output.");
|
|
11599
11617
|
}
|
|
11600
11618
|
});
|
|
11601
11619
|
|
|
@@ -11668,13 +11686,11 @@ var init_ratelimit = __esm({
|
|
|
11668
11686
|
init_api_client();
|
|
11669
11687
|
init_args();
|
|
11670
11688
|
init_format();
|
|
11671
|
-
USAGE2 =
|
|
11672
|
-
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
|
|
11676
|
-
|
|
11677
|
-
Add --json for machine-readable output.`;
|
|
11689
|
+
USAGE2 = usage("solongate ratelimit", "request throttling", [
|
|
11690
|
+
["ratelimit show", "current limits + change history"],
|
|
11691
|
+
["ratelimit set --minute N [--hour N] [--day N] [--mode off|detect|block]"],
|
|
11692
|
+
["ratelimit history", "recent limit changes"]
|
|
11693
|
+
]);
|
|
11678
11694
|
modeColor2 = (m) => m === "block" ? green(m) : m === "detect" ? yellow(m) : dim(m);
|
|
11679
11695
|
}
|
|
11680
11696
|
});
|
|
@@ -11755,16 +11771,14 @@ var init_dlp = __esm({
|
|
|
11755
11771
|
init_api_client();
|
|
11756
11772
|
init_args();
|
|
11757
11773
|
init_format();
|
|
11758
|
-
USAGE3 =
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
Add --json for machine-readable output.`;
|
|
11774
|
+
USAGE3 = usage("solongate dlp", "data-loss prevention", [
|
|
11775
|
+
["dlp show", "current mode + enabled patterns"],
|
|
11776
|
+
["dlp mode <off|detect|block>", "set enforcement mode"],
|
|
11777
|
+
["dlp enable <pattern>", "enable a built-in pattern"],
|
|
11778
|
+
["dlp disable <pattern>", "disable a built-in pattern"],
|
|
11779
|
+
["dlp add-custom --name X --re <regex>", "add a custom pattern"],
|
|
11780
|
+
["dlp remove-custom <name>", "remove a custom pattern"]
|
|
11781
|
+
]);
|
|
11768
11782
|
modeColor3 = (m) => m === "block" ? green(m) : m === "detect" ? yellow(m) : dim(m);
|
|
11769
11783
|
}
|
|
11770
11784
|
});
|
|
@@ -11791,7 +11805,7 @@ async function run4(argv) {
|
|
|
11791
11805
|
decisionColor2(a.decision),
|
|
11792
11806
|
cyan(truncate3(a.tool_name, 24)),
|
|
11793
11807
|
dim(a.trust_level),
|
|
11794
|
-
String(a.evaluation_time_ms ?? "
|
|
11808
|
+
String(a.evaluation_time_ms ?? "-"),
|
|
11795
11809
|
dim(a.created_at)
|
|
11796
11810
|
])
|
|
11797
11811
|
);
|
|
@@ -11822,8 +11836,8 @@ async function run4(argv) {
|
|
|
11822
11836
|
bold(String(r.current)),
|
|
11823
11837
|
dim(String(r.previous)),
|
|
11824
11838
|
r.is_new ? green("NEW") : r.spike ? red(`+${r.delta}`) : String(r.delta),
|
|
11825
|
-
cyan(truncate3(r.rule_id ?? "
|
|
11826
|
-
truncate3(r.reason ?? r.last_tool ?? "
|
|
11839
|
+
cyan(truncate3(r.rule_id ?? "-", 22)),
|
|
11840
|
+
truncate3(r.reason ?? r.last_tool ?? "-", 36)
|
|
11827
11841
|
])
|
|
11828
11842
|
);
|
|
11829
11843
|
return 0;
|
|
@@ -11839,13 +11853,11 @@ var init_stats2 = __esm({
|
|
|
11839
11853
|
init_api_client();
|
|
11840
11854
|
init_args();
|
|
11841
11855
|
init_format();
|
|
11842
|
-
USAGE4 =
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
Add --json for machine-readable output.`;
|
|
11856
|
+
USAGE4 = usage("solongate stats", "traffic & security stats", [
|
|
11857
|
+
["stats", "overview (totals, recent activity)"],
|
|
11858
|
+
["stats timeseries [--period 24h|7d|30d|all]"],
|
|
11859
|
+
["stats drift [--days N]", "denials rising/falling vs previous window"]
|
|
11860
|
+
]);
|
|
11849
11861
|
}
|
|
11850
11862
|
});
|
|
11851
11863
|
|
|
@@ -11892,8 +11904,8 @@ async function run5(argv) {
|
|
|
11892
11904
|
res.entries.map((e) => [
|
|
11893
11905
|
decisionColor2(e.decision),
|
|
11894
11906
|
cyan(truncate3(e.tool_name, 22)),
|
|
11895
|
-
dim(truncate3(e.agent_name ?? "
|
|
11896
|
-
truncate3(e.reason ?? "
|
|
11907
|
+
dim(truncate3(e.agent_name ?? "-", 16)),
|
|
11908
|
+
truncate3(e.reason ?? "-", 30),
|
|
11897
11909
|
e.dlp_matches?.length ? red(String(e.dlp_matches.length)) : dim("0"),
|
|
11898
11910
|
dim(e.created_at),
|
|
11899
11911
|
dim(truncate3(e.id, 10))
|
|
@@ -11908,14 +11920,12 @@ var init_audit2 = __esm({
|
|
|
11908
11920
|
init_api_client();
|
|
11909
11921
|
init_args();
|
|
11910
11922
|
init_format();
|
|
11911
|
-
USAGE5 =
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
|
|
11916
|
-
|
|
11917
|
-
|
|
11918
|
-
Add --json for machine-readable output.`;
|
|
11923
|
+
USAGE5 = usage("solongate audit", "audit log", [
|
|
11924
|
+
["audit [--filter ALLOW|DENY] [--tool <substr>] [--signal dlp|ratelimit]"],
|
|
11925
|
+
[" [--search <text>] [--agent-name <name>] [--limit N]"],
|
|
11926
|
+
["audit whitelist <logId> [--scope exact|tool]", "turn a denied call into an ALLOW rule"],
|
|
11927
|
+
["audit block <logId> [--scope exact|tool]", "turn a call into a DENY rule"]
|
|
11928
|
+
]);
|
|
11919
11929
|
}
|
|
11920
11930
|
});
|
|
11921
11931
|
|
|
@@ -11937,7 +11947,7 @@ async function runAgents(argv) {
|
|
|
11937
11947
|
a.denied_calls ? red(String(a.denied_calls)) : dim("0"),
|
|
11938
11948
|
a.dlp_events ? red(String(a.dlp_events)) : dim("0"),
|
|
11939
11949
|
`${a.trust_score}`,
|
|
11940
|
-
dim(truncate3(a.character || "
|
|
11950
|
+
dim(truncate3(a.character || "-", 22))
|
|
11941
11951
|
])
|
|
11942
11952
|
);
|
|
11943
11953
|
return 0;
|
|
@@ -11953,7 +11963,7 @@ async function runAgent(argv) {
|
|
|
11953
11963
|
err(` ${bold(a.agent_id)} status: ${statusColor(String(a.status))}`);
|
|
11954
11964
|
const base = a.baseline;
|
|
11955
11965
|
if (base) {
|
|
11956
|
-
err(` ${dim(base.character ?? "")} trust ${bold(String(base.trustScore ?? "
|
|
11966
|
+
err(` ${dim(base.character ?? "")} trust ${bold(String(base.trustScore ?? "-"))}/100 deny-rate ${(Number(base.denyRate ?? 0) * 100).toFixed(0)}%`);
|
|
11957
11967
|
}
|
|
11958
11968
|
const feed = a.recent_feed ?? [];
|
|
11959
11969
|
if (feed.length) {
|
|
@@ -11963,7 +11973,7 @@ async function runAgent(argv) {
|
|
|
11963
11973
|
feed.slice(0, 15).map((f) => [
|
|
11964
11974
|
f.decision === "ALLOW" ? green("ALLOW") : red(String(f.decision)),
|
|
11965
11975
|
cyan(truncate3(String(f.tool), 22)),
|
|
11966
|
-
truncate3(String(f.reason ?? "
|
|
11976
|
+
truncate3(String(f.reason ?? "-"), 30),
|
|
11967
11977
|
dim(String(f.created_at))
|
|
11968
11978
|
])
|
|
11969
11979
|
);
|
|
@@ -11990,7 +12000,7 @@ async function run6(argv) {
|
|
|
11990
12000
|
const json = flagBool(flags, "json");
|
|
11991
12001
|
const checks = [];
|
|
11992
12002
|
if (!isAuthenticated()) {
|
|
11993
|
-
checks.push({ name: "login", ok: false, detail: "not logged in
|
|
12003
|
+
checks.push({ name: "login", ok: false, detail: "not logged in - run `solongate`, add your account in the Accounts panel" });
|
|
11994
12004
|
} else {
|
|
11995
12005
|
const { apiUrl } = resolveCredentials();
|
|
11996
12006
|
checks.push({ name: "login", ok: true, detail: `paired \xB7 ${apiUrl}` });
|
|
@@ -11999,7 +12009,7 @@ async function run6(argv) {
|
|
|
11999
12009
|
if (active2.policy) {
|
|
12000
12010
|
checks.push({ name: "active policy", ok: true, detail: `${active2.policy.name} v${active2.version} \xB7 ${active2.policy.mode ?? "denylist"} \xB7 matched by ${active2.matched_by}` });
|
|
12001
12011
|
} else {
|
|
12002
|
-
checks.push({ name: "active policy", ok: "warn", detail: "no policy resolves
|
|
12012
|
+
checks.push({ name: "active policy", ok: "warn", detail: "no policy resolves - every call falls back to default" });
|
|
12003
12013
|
}
|
|
12004
12014
|
const sec = active2.security;
|
|
12005
12015
|
checks.push({ name: "rate limit", ok: sec?.rateLimit ? true : "warn", detail: sec?.rateLimit ? `${sec.rateLimit.perMinute}/min` : "off" });
|
|
@@ -12019,7 +12029,7 @@ async function run6(argv) {
|
|
|
12019
12029
|
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
12020
12030
|
checks.push({ name: "local logs", ok: true, detail: `on \xB7 ${(st.size / 1024).toFixed(0)}KB \xB7 last write ${ageMin < 1 ? "just now" : Math.round(ageMin) + "m ago"}` });
|
|
12021
12031
|
} else {
|
|
12022
|
-
checks.push({ name: "local logs", ok: "warn", detail: "off (logs go to cloud)
|
|
12032
|
+
checks.push({ name: "local logs", ok: "warn", detail: "off (logs go to cloud) - enable in dashboard \u2192 Settings" });
|
|
12023
12033
|
}
|
|
12024
12034
|
if (json) return printJson(checks), checks.some((c2) => c2.ok === false) ? 1 : 0;
|
|
12025
12035
|
err("");
|
|
@@ -12033,7 +12043,7 @@ async function run6(argv) {
|
|
|
12033
12043
|
const bad = checks.filter((c2) => c2.ok === false).length;
|
|
12034
12044
|
const warn = checks.filter((c2) => c2.ok === "warn").length;
|
|
12035
12045
|
if (bad) err(` ${red(`${bad} problem(s)`)}${warn ? dim(` \xB7 ${warn} warning(s)`) : ""}`);
|
|
12036
|
-
else if (warn) err(` ${yellow(`${warn} warning(s)`)} ${dim("
|
|
12046
|
+
else if (warn) err(` ${yellow(`${warn} warning(s)`)} ${dim("- guard is working")}`);
|
|
12037
12047
|
else err(` ${green("all good")}`);
|
|
12038
12048
|
return bad ? 1 : 0;
|
|
12039
12049
|
}
|
|
@@ -12141,7 +12151,7 @@ async function run7(argv) {
|
|
|
12141
12151
|
} catch {
|
|
12142
12152
|
}
|
|
12143
12153
|
};
|
|
12144
|
-
if (!json) err(` ${c.dim}watching guard stream
|
|
12154
|
+
if (!json) err(` ${c.dim}watching guard stream - Ctrl+C to stop${c.reset}`);
|
|
12145
12155
|
pollLocal();
|
|
12146
12156
|
await pollCloud();
|
|
12147
12157
|
first = false;
|
|
@@ -12184,7 +12194,7 @@ async function run8(argv) {
|
|
|
12184
12194
|
cyan(r.signal),
|
|
12185
12195
|
`${r.threshold}`,
|
|
12186
12196
|
`${r.windowSeconds}s`,
|
|
12187
|
-
dim([...r.emails ?? [], ...(r.telegram ?? []).map((t) => "tg:" + t), ...(r.slackUrls ?? []).map(() => "slack")].join(" ") || "
|
|
12197
|
+
dim([...r.emails ?? [], ...(r.telegram ?? []).map((t) => "tg:" + t), ...(r.slackUrls ?? []).map(() => "slack")].join(" ") || "-")
|
|
12188
12198
|
])
|
|
12189
12199
|
);
|
|
12190
12200
|
return 0;
|
|
@@ -12223,14 +12233,12 @@ var init_alerts = __esm({
|
|
|
12223
12233
|
init_api_client();
|
|
12224
12234
|
init_args();
|
|
12225
12235
|
init_format();
|
|
12226
|
-
USAGE6 =
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
|
|
12230
|
-
|
|
12231
|
-
|
|
12232
|
-
|
|
12233
|
-
Add --json for machine-readable output.`;
|
|
12236
|
+
USAGE6 = usage("solongate alerts", "spike alerts (Telegram / email)", [
|
|
12237
|
+
["alerts list"],
|
|
12238
|
+
["alerts add --signal deny|dlp|ratelimit|any --threshold N --window S"],
|
|
12239
|
+
[" (--email <a> | --telegram <chatId> | --slack <url>)"],
|
|
12240
|
+
["alerts remove <id>"]
|
|
12241
|
+
]);
|
|
12234
12242
|
}
|
|
12235
12243
|
});
|
|
12236
12244
|
|
|
@@ -12277,13 +12285,11 @@ var init_webhooks = __esm({
|
|
|
12277
12285
|
init_api_client();
|
|
12278
12286
|
init_args();
|
|
12279
12287
|
init_format();
|
|
12280
|
-
USAGE7 =
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
Add --json for machine-readable output.`;
|
|
12288
|
+
USAGE7 = usage("solongate webhooks", "event webhooks", [
|
|
12289
|
+
["webhooks list"],
|
|
12290
|
+
["webhooks add --url <https://\u2026> [--events denials|allowed|all]"],
|
|
12291
|
+
["webhooks remove <id>"]
|
|
12292
|
+
]);
|
|
12287
12293
|
}
|
|
12288
12294
|
});
|
|
12289
12295
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.82.
|
|
3
|
+
"version": "0.82.25",
|
|
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": {
|