@solongate/proxy 0.82.19 → 0.82.21
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/index.d.ts +1 -1
- package/dist/commands/index.js +11 -81
- package/dist/index.js +276 -649
- package/package.json +1 -1
- package/dist/commands/keys.d.ts +0 -1
- package/dist/commands/mcp.d.ts +0 -1
- package/dist/shield.d.ts +0 -1
- package/dist/shield.js +0 -314
package/dist/index.js
CHANGED
|
@@ -3398,12 +3398,12 @@ ${ctx.indent}`;
|
|
|
3398
3398
|
for (const {
|
|
3399
3399
|
format,
|
|
3400
3400
|
test,
|
|
3401
|
-
resolve:
|
|
3401
|
+
resolve: resolve9
|
|
3402
3402
|
} of tags) {
|
|
3403
3403
|
if (test) {
|
|
3404
3404
|
const match = str.match(test);
|
|
3405
3405
|
if (match) {
|
|
3406
|
-
let res =
|
|
3406
|
+
let res = resolve9.apply(null, match);
|
|
3407
3407
|
if (!(res instanceof Scalar)) res = new Scalar(res);
|
|
3408
3408
|
if (format) res.format = format;
|
|
3409
3409
|
return res;
|
|
@@ -6622,9 +6622,9 @@ async function fetchLatest() {
|
|
|
6622
6622
|
function spawnGlobalInstall(version) {
|
|
6623
6623
|
try {
|
|
6624
6624
|
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6625
|
-
const
|
|
6625
|
+
const log5 = openSync(LOG_FILE, "a");
|
|
6626
6626
|
const p = spawn("npm", ["install", "-g", `${PKG}@${version}`], {
|
|
6627
|
-
stdio: ["ignore",
|
|
6627
|
+
stdio: ["ignore", log5, log5],
|
|
6628
6628
|
detached: true,
|
|
6629
6629
|
windowsHide: true,
|
|
6630
6630
|
shell: process.platform === "win32"
|
|
@@ -6638,7 +6638,7 @@ function spawnGlobalInstall(version) {
|
|
|
6638
6638
|
}
|
|
6639
6639
|
}
|
|
6640
6640
|
function runGlobalInstall(version) {
|
|
6641
|
-
return new Promise((
|
|
6641
|
+
return new Promise((resolve9) => {
|
|
6642
6642
|
try {
|
|
6643
6643
|
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6644
6644
|
execFile(
|
|
@@ -6653,11 +6653,11 @@ ${stderr}
|
|
|
6653
6653
|
`, { flag: "a" });
|
|
6654
6654
|
} catch {
|
|
6655
6655
|
}
|
|
6656
|
-
|
|
6656
|
+
resolve9(!err2);
|
|
6657
6657
|
}
|
|
6658
6658
|
);
|
|
6659
6659
|
} catch {
|
|
6660
|
-
|
|
6660
|
+
resolve9(false);
|
|
6661
6661
|
}
|
|
6662
6662
|
});
|
|
6663
6663
|
}
|
|
@@ -6772,11 +6772,11 @@ function startLogsServerDaemon() {
|
|
|
6772
6772
|
}
|
|
6773
6773
|
try {
|
|
6774
6774
|
mkdirSync4(DIR, { recursive: true });
|
|
6775
|
-
const
|
|
6775
|
+
const log5 = openSync2(LOG_FILE2, "a");
|
|
6776
6776
|
const cli = join5(dirname2(fileURLToPath2(import.meta.url)), "index.js");
|
|
6777
6777
|
const p = spawn2(process.execPath, [cli, "logs-server"], {
|
|
6778
6778
|
detached: true,
|
|
6779
|
-
stdio: ["ignore",
|
|
6779
|
+
stdio: ["ignore", log5, log5],
|
|
6780
6780
|
windowsHide: true
|
|
6781
6781
|
});
|
|
6782
6782
|
p.on("error", () => {
|
|
@@ -7854,7 +7854,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7854
7854
|
const [localBuf, setLocalBuf] = useState2([]);
|
|
7855
7855
|
const [localOn, setLocalOn] = useState2(null);
|
|
7856
7856
|
const [ring, setRing] = useState2(null);
|
|
7857
|
-
const [
|
|
7857
|
+
const [log5, setLog] = useState2([]);
|
|
7858
7858
|
const [filter, setFilter] = useState2("all");
|
|
7859
7859
|
const [signal, setSignal] = useState2("none");
|
|
7860
7860
|
const [search, setSearch] = useState2("");
|
|
@@ -8698,7 +8698,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8698
8698
|
] }),
|
|
8699
8699
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
|
|
8700
8700
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
|
|
8701
|
-
|
|
8701
|
+
log5.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8702
8702
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
8703
8703
|
hhmmss(l.ts),
|
|
8704
8704
|
" "
|
|
@@ -9635,7 +9635,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9635
9635
|
const sessLoading = source === "cloud" ? agentsQ.loading : localQ.loading;
|
|
9636
9636
|
const doDelete = (kind) => {
|
|
9637
9637
|
setMsg({ text: "deleting\u2026", level: "ok" });
|
|
9638
|
-
const
|
|
9638
|
+
const run10 = async () => {
|
|
9639
9639
|
if (source === "cloud") {
|
|
9640
9640
|
if (kind === "one") {
|
|
9641
9641
|
if (!current) throw new Error("nothing selected");
|
|
@@ -9651,14 +9651,14 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9651
9651
|
localQ.reload();
|
|
9652
9652
|
}
|
|
9653
9653
|
};
|
|
9654
|
-
|
|
9654
|
+
run10().then(() => {
|
|
9655
9655
|
setMsg({ text: kind === "one" ? "\u2713 entry deleted" : `\u2713 ALL ${source} logs deleted`, level: "ok" });
|
|
9656
9656
|
toTop();
|
|
9657
9657
|
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
9658
9658
|
};
|
|
9659
9659
|
const doExport = (kind) => {
|
|
9660
9660
|
setMsg({ text: "exporting\u2026", level: "ok" });
|
|
9661
|
-
const
|
|
9661
|
+
const run10 = async () => {
|
|
9662
9662
|
const dir = join10(homedir8(), ".solongate");
|
|
9663
9663
|
const file = join10(dir, `audit-export-${source}.jsonl`);
|
|
9664
9664
|
let rows2;
|
|
@@ -9671,7 +9671,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9671
9671
|
writeFileSync8(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
|
|
9672
9672
|
return { n: rows2.length, file };
|
|
9673
9673
|
};
|
|
9674
|
-
|
|
9674
|
+
run10().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" }));
|
|
9675
9675
|
};
|
|
9676
9676
|
useInput5(
|
|
9677
9677
|
(input, key) => {
|
|
@@ -10554,7 +10554,7 @@ function SettingsPanel({
|
|
|
10554
10554
|
guardQ.reload();
|
|
10555
10555
|
selfQ.reload();
|
|
10556
10556
|
};
|
|
10557
|
-
const
|
|
10557
|
+
const run10 = (label, fn, reload) => {
|
|
10558
10558
|
if (busy) return;
|
|
10559
10559
|
setBusy(true);
|
|
10560
10560
|
setMsg({ text: label + "\u2026", level: "ok" });
|
|
@@ -10636,8 +10636,8 @@ function SettingsPanel({
|
|
|
10636
10636
|
const body = { signal: editor.signal, threshold: editor.threshold, windowSeconds: editor.windowSeconds, enabled: editor.enabled, ...channels };
|
|
10637
10637
|
const id = editor.id;
|
|
10638
10638
|
setEditor(null);
|
|
10639
|
-
if (id)
|
|
10640
|
-
else
|
|
10639
|
+
if (id) run10("alert updated", () => api.settings.updateAlert(id, body), alertQ.reload);
|
|
10640
|
+
else run10(`${editor.channel} alert added`, () => api.settings.createAlert({ name: "SolonGate alert", ...body }), alertQ.reload);
|
|
10641
10641
|
};
|
|
10642
10642
|
const activate = (r) => {
|
|
10643
10643
|
if (r.kind === "acct") {
|
|
@@ -10653,14 +10653,14 @@ function SettingsPanel({
|
|
|
10653
10653
|
guardQ.reload();
|
|
10654
10654
|
} else if (r.kind === "self") {
|
|
10655
10655
|
if (!selfProt) return;
|
|
10656
|
-
|
|
10656
|
+
run10(selfProt.enabled ? "self-protection disabled" : "self-protection enabled", () => api.settings.setSelfProtection(!selfProt.enabled), selfQ.reload);
|
|
10657
10657
|
} else if (r.kind === "ll-enabled") {
|
|
10658
10658
|
if (!local) return;
|
|
10659
10659
|
if (!local.enabled && !local.path.trim()) {
|
|
10660
10660
|
setMsg({ text: "set a path first (\u2193 then enter)", level: "bad" });
|
|
10661
10661
|
return;
|
|
10662
10662
|
}
|
|
10663
|
-
|
|
10663
|
+
run10(local.enabled ? "local logs disabled" : "local logs enabled", () => api.settings.setLocalLogs({ enabled: !local.enabled, path: local.path }), localQ.reload);
|
|
10664
10664
|
} else if (r.kind === "ll-path") {
|
|
10665
10665
|
setInput(local?.path ?? "");
|
|
10666
10666
|
setEditing("path");
|
|
@@ -10671,7 +10671,7 @@ function SettingsPanel({
|
|
|
10671
10671
|
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" }
|
|
10672
10672
|
);
|
|
10673
10673
|
} else if (r.kind === "wh") {
|
|
10674
|
-
|
|
10674
|
+
run10(r.wh.enabled ? "webhook disabled" : "webhook enabled", () => api.settings.updateWebhook(r.wh.id, { enabled: !r.wh.enabled }), whQ.reload);
|
|
10675
10675
|
} else if (r.kind === "wh-add") {
|
|
10676
10676
|
setInput("");
|
|
10677
10677
|
setEditing("wh-url");
|
|
@@ -10690,7 +10690,7 @@ function SettingsPanel({
|
|
|
10690
10690
|
setEditing(null);
|
|
10691
10691
|
if (which === "path") {
|
|
10692
10692
|
const enabled = (local?.enabled ?? false) && v.length > 0;
|
|
10693
|
-
|
|
10693
|
+
run10(v ? `path saved${enabled ? "" : " (press enter on enabled to turn on)"}` : "path cleared (local logs off)", () => api.settings.setLocalLogs({ enabled, path: v }), localQ.reload);
|
|
10694
10694
|
} else if (which === "wh-url") {
|
|
10695
10695
|
const url = v.replace(/^["'<]+|["'>]+$/g, "").trim();
|
|
10696
10696
|
if (!url) return;
|
|
@@ -10698,7 +10698,7 @@ function SettingsPanel({
|
|
|
10698
10698
|
setMsg({ text: "\u2717 webhook url must start with http:// or https://", level: "bad" });
|
|
10699
10699
|
return;
|
|
10700
10700
|
}
|
|
10701
|
-
|
|
10701
|
+
run10("webhook added", () => api.settings.createWebhook({ url, events: "denials" }), whQ.reload);
|
|
10702
10702
|
} else if (which === "alert-target" && editor) {
|
|
10703
10703
|
setEditor({ ...editor, target: v, field: 1 });
|
|
10704
10704
|
}
|
|
@@ -10752,7 +10752,7 @@ function SettingsPanel({
|
|
|
10752
10752
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
10753
10753
|
refreshAccounts();
|
|
10754
10754
|
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
10755
|
-
if (cur.kind === "alert")
|
|
10755
|
+
if (cur.kind === "alert") run10(cur.rule.enabled ? "alert disabled" : "alert enabled", () => api.settings.setAlertEnabled(cur.rule.id, !cur.rule.enabled), alertQ.reload);
|
|
10756
10756
|
else activate(cur);
|
|
10757
10757
|
}
|
|
10758
10758
|
} else if (inp === "x" && cur.kind === "acct") {
|
|
@@ -10782,13 +10782,13 @@ function SettingsPanel({
|
|
|
10782
10782
|
refreshAccounts();
|
|
10783
10783
|
onAccountsChanged?.();
|
|
10784
10784
|
} else if (inp === "t" && cur.kind === "wh") {
|
|
10785
|
-
|
|
10785
|
+
run10("webhook test sent \u2014 check your endpoint", () => api.settings.sendTestWebhook(cur.wh.id).then((r) => {
|
|
10786
10786
|
if (!r.delivered) throw new Error("endpoint rejected the test (non-2xx)");
|
|
10787
10787
|
}), whQ.reload);
|
|
10788
10788
|
} else if (inp === "e" && cur.kind === "ll-path") activate(cur);
|
|
10789
10789
|
else if (inp === "e" && cur.kind === "wh") {
|
|
10790
10790
|
const next = EVENTS[(EVENTS.indexOf(cur.wh.events) + 1) % EVENTS.length];
|
|
10791
|
-
|
|
10791
|
+
run10(`webhook events \u2192 ${next}`, () => api.settings.updateWebhook(cur.wh.id, { events: next }), whQ.reload);
|
|
10792
10792
|
} else if (inp === "e" && cur.kind === "alert") {
|
|
10793
10793
|
const ch = alertChannel(cur.rule);
|
|
10794
10794
|
if (ch) openAlertEditor(ch, cur.rule);
|
|
@@ -10825,10 +10825,10 @@ function SettingsPanel({
|
|
|
10825
10825
|
setConfirmDel(null);
|
|
10826
10826
|
if (cur.kind === "wh") {
|
|
10827
10827
|
const id = cur.wh.id;
|
|
10828
|
-
|
|
10828
|
+
run10("webhook deleted", () => api.settings.deleteWebhook(id).then(() => setHidden((h) => new Set(h).add("wh:" + id))), whQ.reload);
|
|
10829
10829
|
} else {
|
|
10830
10830
|
const id = cur.rule.id;
|
|
10831
|
-
|
|
10831
|
+
run10("alert deleted", () => api.settings.deleteAlert(id).then(() => setHidden((h) => new Set(h).add("alert:" + id))), alertQ.reload);
|
|
10832
10832
|
}
|
|
10833
10833
|
} else if (inp === "r") reloadAll();
|
|
10834
10834
|
},
|
|
@@ -11128,9 +11128,9 @@ function App() {
|
|
|
11128
11128
|
const [update2, setUpdate] = useState8({ kind: "idle" });
|
|
11129
11129
|
useEffect7(() => {
|
|
11130
11130
|
let alive = true;
|
|
11131
|
-
const
|
|
11132
|
-
|
|
11133
|
-
const t = setInterval(
|
|
11131
|
+
const run10 = () => void tuiUpdateFlow((s) => alive && setUpdate(s));
|
|
11132
|
+
run10();
|
|
11133
|
+
const t = setInterval(run10, 30 * 6e4);
|
|
11134
11134
|
return () => {
|
|
11135
11135
|
alive = false;
|
|
11136
11136
|
clearInterval(t);
|
|
@@ -12204,7 +12204,7 @@ var init_watch = __esm({
|
|
|
12204
12204
|
}
|
|
12205
12205
|
});
|
|
12206
12206
|
|
|
12207
|
-
// src/commands/
|
|
12207
|
+
// src/commands/alerts.ts
|
|
12208
12208
|
async function run8(argv) {
|
|
12209
12209
|
const { positionals, flags } = parse(argv);
|
|
12210
12210
|
const sub = positionals[0] ?? "list";
|
|
@@ -12212,89 +12212,6 @@ async function run8(argv) {
|
|
|
12212
12212
|
switch (sub) {
|
|
12213
12213
|
case "help":
|
|
12214
12214
|
return err(USAGE6), 0;
|
|
12215
|
-
case "list": {
|
|
12216
|
-
const { keys } = await api.keys.list();
|
|
12217
|
-
if (json) return printJson(keys), 0;
|
|
12218
|
-
if (!keys.length) return err(dim(" No API keys.")), 0;
|
|
12219
|
-
table(
|
|
12220
|
-
["ID", "NAME", "PREFIX", "CREATED"],
|
|
12221
|
-
keys.map((k) => [dim(truncate3(k.id, 10)), truncate3(k.name, 24), cyan(k.key_prefix), dim(k.created_at)])
|
|
12222
|
-
);
|
|
12223
|
-
return 0;
|
|
12224
|
-
}
|
|
12225
|
-
case "create": {
|
|
12226
|
-
const name = flagStr(flags, "name");
|
|
12227
|
-
if (!name) return err(" Usage: keys create --name <name>"), 1;
|
|
12228
|
-
const res = await api.keys.create(name, !flagBool(flags, "test"));
|
|
12229
|
-
if (json) return printJson(res), 0;
|
|
12230
|
-
err(green(` \u2713 Created "${res.name}"`));
|
|
12231
|
-
err("");
|
|
12232
|
-
err(" " + bold(res.key));
|
|
12233
|
-
err(dim(" \u2191 shown only once \u2014 copy it now."));
|
|
12234
|
-
return 0;
|
|
12235
|
-
}
|
|
12236
|
-
case "revoke": {
|
|
12237
|
-
const id = positionals[1];
|
|
12238
|
-
if (!id) return err(" Usage: keys revoke <id>"), 1;
|
|
12239
|
-
await api.keys.revoke(id);
|
|
12240
|
-
if (json) return printJson({ ok: true, id }), 0;
|
|
12241
|
-
return err(green(` \u2713 Revoked ${id}`)), 0;
|
|
12242
|
-
}
|
|
12243
|
-
default:
|
|
12244
|
-
return err(USAGE6), 1;
|
|
12245
|
-
}
|
|
12246
|
-
}
|
|
12247
|
-
var USAGE6;
|
|
12248
|
-
var init_keys2 = __esm({
|
|
12249
|
-
"src/commands/keys.ts"() {
|
|
12250
|
-
"use strict";
|
|
12251
|
-
init_api_client();
|
|
12252
|
-
init_args();
|
|
12253
|
-
init_format();
|
|
12254
|
-
USAGE6 = `${bold("solongate keys")} \u2014 API keys
|
|
12255
|
-
|
|
12256
|
-
keys list List keys (prefix only)
|
|
12257
|
-
keys create --name <n> Create a key (secret shown once)
|
|
12258
|
-
keys revoke <id> Revoke a key
|
|
12259
|
-
|
|
12260
|
-
Add --json for machine-readable output.`;
|
|
12261
|
-
}
|
|
12262
|
-
});
|
|
12263
|
-
|
|
12264
|
-
// src/commands/mcp.ts
|
|
12265
|
-
async function run9(argv) {
|
|
12266
|
-
const { flags } = parse(argv);
|
|
12267
|
-
const json = flagBool(flags, "json");
|
|
12268
|
-
const { servers } = await api.mcp.list();
|
|
12269
|
-
if (json) return printJson(servers), 0;
|
|
12270
|
-
if (!servers.length) return err(dim(" No MCP servers registered.")), 0;
|
|
12271
|
-
table(
|
|
12272
|
-
["STATUS", "NAME", "TARGET"],
|
|
12273
|
-
servers.map((s) => [
|
|
12274
|
-
s.status === "active" ? green(s.status) : yellow(s.status),
|
|
12275
|
-
cyan(truncate3(s.name, 24)),
|
|
12276
|
-
dim(truncate3(s.url || s.command || "\u2014", 46))
|
|
12277
|
-
])
|
|
12278
|
-
);
|
|
12279
|
-
return 0;
|
|
12280
|
-
}
|
|
12281
|
-
var init_mcp2 = __esm({
|
|
12282
|
-
"src/commands/mcp.ts"() {
|
|
12283
|
-
"use strict";
|
|
12284
|
-
init_api_client();
|
|
12285
|
-
init_args();
|
|
12286
|
-
init_format();
|
|
12287
|
-
}
|
|
12288
|
-
});
|
|
12289
|
-
|
|
12290
|
-
// src/commands/alerts.ts
|
|
12291
|
-
async function run10(argv) {
|
|
12292
|
-
const { positionals, flags } = parse(argv);
|
|
12293
|
-
const sub = positionals[0] ?? "list";
|
|
12294
|
-
const json = flagBool(flags, "json");
|
|
12295
|
-
switch (sub) {
|
|
12296
|
-
case "help":
|
|
12297
|
-
return err(USAGE7), 0;
|
|
12298
12215
|
case "list": {
|
|
12299
12216
|
const { rules } = await api.settings.getAlerts();
|
|
12300
12217
|
if (json) return printJson(rules), 0;
|
|
@@ -12336,17 +12253,17 @@ async function run10(argv) {
|
|
|
12336
12253
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
12337
12254
|
}
|
|
12338
12255
|
default:
|
|
12339
|
-
return err(
|
|
12256
|
+
return err(USAGE6), 1;
|
|
12340
12257
|
}
|
|
12341
12258
|
}
|
|
12342
|
-
var
|
|
12259
|
+
var USAGE6;
|
|
12343
12260
|
var init_alerts = __esm({
|
|
12344
12261
|
"src/commands/alerts.ts"() {
|
|
12345
12262
|
"use strict";
|
|
12346
12263
|
init_api_client();
|
|
12347
12264
|
init_args();
|
|
12348
12265
|
init_format();
|
|
12349
|
-
|
|
12266
|
+
USAGE6 = `${bold("solongate alerts")} \u2014 spike alerts (Telegram / email)
|
|
12350
12267
|
|
|
12351
12268
|
alerts list
|
|
12352
12269
|
alerts add --signal deny|dlp|ratelimit|any --threshold N --window S
|
|
@@ -12358,13 +12275,13 @@ var init_alerts = __esm({
|
|
|
12358
12275
|
});
|
|
12359
12276
|
|
|
12360
12277
|
// src/commands/webhooks.ts
|
|
12361
|
-
async function
|
|
12278
|
+
async function run9(argv) {
|
|
12362
12279
|
const { positionals, flags } = parse(argv);
|
|
12363
12280
|
const sub = positionals[0] ?? "list";
|
|
12364
12281
|
const json = flagBool(flags, "json");
|
|
12365
12282
|
switch (sub) {
|
|
12366
12283
|
case "help":
|
|
12367
|
-
return err(
|
|
12284
|
+
return err(USAGE7), 0;
|
|
12368
12285
|
case "list": {
|
|
12369
12286
|
const { webhooks } = await api.settings.getWebhooks();
|
|
12370
12287
|
if (json) return printJson(webhooks), 0;
|
|
@@ -12390,17 +12307,17 @@ async function run11(argv) {
|
|
|
12390
12307
|
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
12391
12308
|
}
|
|
12392
12309
|
default:
|
|
12393
|
-
return err(
|
|
12310
|
+
return err(USAGE7), 1;
|
|
12394
12311
|
}
|
|
12395
12312
|
}
|
|
12396
|
-
var
|
|
12313
|
+
var USAGE7;
|
|
12397
12314
|
var init_webhooks = __esm({
|
|
12398
12315
|
"src/commands/webhooks.ts"() {
|
|
12399
12316
|
"use strict";
|
|
12400
12317
|
init_api_client();
|
|
12401
12318
|
init_args();
|
|
12402
12319
|
init_format();
|
|
12403
|
-
|
|
12320
|
+
USAGE7 = `${bold("solongate webhooks")} \u2014 event webhooks
|
|
12404
12321
|
|
|
12405
12322
|
webhooks list
|
|
12406
12323
|
webhooks add --url <https://\u2026> [--events denials|allowed|all]
|
|
@@ -12436,14 +12353,10 @@ async function dispatch(command, argv) {
|
|
|
12436
12353
|
return run6(argv);
|
|
12437
12354
|
case "watch":
|
|
12438
12355
|
return run7(argv);
|
|
12439
|
-
case "keys":
|
|
12440
|
-
return run8(argv);
|
|
12441
|
-
case "mcp":
|
|
12442
|
-
return run9(argv);
|
|
12443
12356
|
case "alerts":
|
|
12444
|
-
return
|
|
12357
|
+
return run8(argv);
|
|
12445
12358
|
case "webhooks":
|
|
12446
|
-
return
|
|
12359
|
+
return run9(argv);
|
|
12447
12360
|
default:
|
|
12448
12361
|
err(` Unknown command: ${command}`);
|
|
12449
12362
|
return 1;
|
|
@@ -12480,333 +12393,9 @@ var init_commands = __esm({
|
|
|
12480
12393
|
init_agents2();
|
|
12481
12394
|
init_doctor();
|
|
12482
12395
|
init_watch();
|
|
12483
|
-
init_keys2();
|
|
12484
|
-
init_mcp2();
|
|
12485
12396
|
init_alerts();
|
|
12486
12397
|
init_webhooks();
|
|
12487
|
-
COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "
|
|
12488
|
-
}
|
|
12489
|
-
});
|
|
12490
|
-
|
|
12491
|
-
// src/shield.ts
|
|
12492
|
-
var shield_exports = {};
|
|
12493
|
-
__export(shield_exports, {
|
|
12494
|
-
runShield: () => runShield
|
|
12495
|
-
});
|
|
12496
|
-
import { createServer, request as httpRequest } from "http";
|
|
12497
|
-
import { request as httpsRequest } from "https";
|
|
12498
|
-
import { spawn as spawn5 } from "child_process";
|
|
12499
|
-
import { URL as URL2 } from "url";
|
|
12500
|
-
import { readFileSync as readFileSync11, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
12501
|
-
import { resolve as resolve5 } from "path";
|
|
12502
|
-
import { homedir as homedir13 } from "os";
|
|
12503
|
-
function findCacheFile() {
|
|
12504
|
-
const dir = resolve5(homedir13(), ".solongate");
|
|
12505
|
-
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
12506
|
-
if (envSel) {
|
|
12507
|
-
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
12508
|
-
if (existsSync7(f)) return f;
|
|
12509
|
-
}
|
|
12510
|
-
let best = null, bestTs = -1;
|
|
12511
|
-
try {
|
|
12512
|
-
for (const name of readdirSync(dir)) {
|
|
12513
|
-
if (name.startsWith(".policy-cache-") && name.endsWith(".json")) {
|
|
12514
|
-
const full = resolve5(dir, name);
|
|
12515
|
-
const ts = statSync4(full).mtimeMs;
|
|
12516
|
-
if (ts > bestTs) {
|
|
12517
|
-
bestTs = ts;
|
|
12518
|
-
best = full;
|
|
12519
|
-
}
|
|
12520
|
-
}
|
|
12521
|
-
}
|
|
12522
|
-
} catch {
|
|
12523
|
-
}
|
|
12524
|
-
return best;
|
|
12525
|
-
}
|
|
12526
|
-
function loadCfg() {
|
|
12527
|
-
try {
|
|
12528
|
-
const f = findCacheFile();
|
|
12529
|
-
if (f && existsSync7(f)) {
|
|
12530
|
-
const c2 = JSON.parse(readFileSync11(f, "utf-8"));
|
|
12531
|
-
const d = c2?.security?.dlpRedact;
|
|
12532
|
-
const g = c2?.security?.ghost;
|
|
12533
|
-
const ghost = g && Array.isArray(g.patterns) ? g.patterns : [];
|
|
12534
|
-
if (d && Array.isArray(d.patterns)) return { patterns: d.patterns, custom: Array.isArray(d.custom) ? d.custom : [], ghost };
|
|
12535
|
-
return { patterns: DLP_PATTERNS.map((p) => p.name), custom: [], ghost };
|
|
12536
|
-
}
|
|
12537
|
-
} catch {
|
|
12538
|
-
}
|
|
12539
|
-
return { patterns: DLP_PATTERNS.map((p) => p.name), custom: [], ghost: [] };
|
|
12540
|
-
}
|
|
12541
|
-
function ghostGlobToRegExp(glob) {
|
|
12542
|
-
let re = "";
|
|
12543
|
-
for (let i = 0; i < glob.length; i++) {
|
|
12544
|
-
const c2 = glob[i];
|
|
12545
|
-
if (c2 === "*") {
|
|
12546
|
-
if (glob[i + 1] === "*") {
|
|
12547
|
-
re += ".*";
|
|
12548
|
-
i++;
|
|
12549
|
-
} else re += "[^/]*";
|
|
12550
|
-
} else if (c2 === "?") re += "[^/]";
|
|
12551
|
-
else if ("\\^$.|+()[]{}".indexOf(c2) !== -1) re += "\\" + c2;
|
|
12552
|
-
else re += c2;
|
|
12553
|
-
}
|
|
12554
|
-
try {
|
|
12555
|
-
return new RegExp("^" + re + "$");
|
|
12556
|
-
} catch {
|
|
12557
|
-
return null;
|
|
12558
|
-
}
|
|
12559
|
-
}
|
|
12560
|
-
function ghostMatch(targetPath, patterns) {
|
|
12561
|
-
if (!targetPath || !Array.isArray(patterns) || patterns.length === 0) return false;
|
|
12562
|
-
const norm = String(targetPath).replace(/\\/g, "/").replace(/\/+$/, "");
|
|
12563
|
-
if (!norm) return false;
|
|
12564
|
-
const segments = norm.split("/").filter(Boolean);
|
|
12565
|
-
const base = segments.length ? segments[segments.length - 1] : norm;
|
|
12566
|
-
for (let pat of patterns) {
|
|
12567
|
-
pat = String(pat || "").trim();
|
|
12568
|
-
if (!pat) continue;
|
|
12569
|
-
let dirOnly = false;
|
|
12570
|
-
if (pat.endsWith("/")) {
|
|
12571
|
-
dirOnly = true;
|
|
12572
|
-
pat = pat.slice(0, -1);
|
|
12573
|
-
}
|
|
12574
|
-
if (!pat) continue;
|
|
12575
|
-
const hasSlash = pat.indexOf("/") !== -1;
|
|
12576
|
-
const hasWild = /[*?]/.test(pat);
|
|
12577
|
-
const re = ghostGlobToRegExp(pat);
|
|
12578
|
-
if (!re) continue;
|
|
12579
|
-
if (dirOnly) {
|
|
12580
|
-
if (!hasSlash && !hasWild) {
|
|
12581
|
-
if (segments.indexOf(pat) !== -1) return true;
|
|
12582
|
-
continue;
|
|
12583
|
-
}
|
|
12584
|
-
let acc = "";
|
|
12585
|
-
for (const s of segments) {
|
|
12586
|
-
acc = acc ? acc + "/" + s : s;
|
|
12587
|
-
if (re.test(acc) || re.test(s)) return true;
|
|
12588
|
-
}
|
|
12589
|
-
continue;
|
|
12590
|
-
}
|
|
12591
|
-
if (!hasSlash) {
|
|
12592
|
-
if (re.test(base)) return true;
|
|
12593
|
-
if (segments.some((s) => re.test(s))) return true;
|
|
12594
|
-
continue;
|
|
12595
|
-
}
|
|
12596
|
-
if (re.test(norm)) return true;
|
|
12597
|
-
}
|
|
12598
|
-
return false;
|
|
12599
|
-
}
|
|
12600
|
-
function ghostCleanToken(tok) {
|
|
12601
|
-
let t = String(tok || "").trim();
|
|
12602
|
-
t = t.replace(/^[<>|;&(]+/, "").replace(/[);&|]+$/, "");
|
|
12603
|
-
t = t.replace(/^['"]+/, "").replace(/['"]+$/, "");
|
|
12604
|
-
t = t.replace(/^\d*>>?/, "");
|
|
12605
|
-
return t.trim();
|
|
12606
|
-
}
|
|
12607
|
-
function ghostStripLines(text, pats) {
|
|
12608
|
-
if (!Array.isArray(pats) || pats.length === 0) return text;
|
|
12609
|
-
const lines = String(text).split("\n");
|
|
12610
|
-
const kept = [];
|
|
12611
|
-
for (const line of lines) {
|
|
12612
|
-
const trimmed = line.trim();
|
|
12613
|
-
if (!trimmed) {
|
|
12614
|
-
kept.push(line);
|
|
12615
|
-
continue;
|
|
12616
|
-
}
|
|
12617
|
-
if (ghostMatch(trimmed, pats)) continue;
|
|
12618
|
-
const toks = trimmed.split(/\s+/);
|
|
12619
|
-
const anyHit = toks.some((t) => ghostMatch(ghostCleanToken(t), pats));
|
|
12620
|
-
if (!anyHit) {
|
|
12621
|
-
kept.push(line);
|
|
12622
|
-
continue;
|
|
12623
|
-
}
|
|
12624
|
-
if (toks.length > 3) continue;
|
|
12625
|
-
const remaining = toks.filter((t) => !ghostMatch(ghostCleanToken(t), pats));
|
|
12626
|
-
if (remaining.length === 0) continue;
|
|
12627
|
-
kept.push(remaining.join(" "));
|
|
12628
|
-
}
|
|
12629
|
-
return kept.join("\n");
|
|
12630
|
-
}
|
|
12631
|
-
function dlpGlobToRe(glob, flags) {
|
|
12632
|
-
let re = "";
|
|
12633
|
-
for (const ch of String(glob || "")) {
|
|
12634
|
-
if (ch === "*") re += "[^\\s]*";
|
|
12635
|
-
else if (".+?^${}()|[]\\".indexOf(ch) !== -1) re += "\\" + ch;
|
|
12636
|
-
else re += ch;
|
|
12637
|
-
}
|
|
12638
|
-
return new RegExp(re, flags);
|
|
12639
|
-
}
|
|
12640
|
-
function redactString(s, cfg) {
|
|
12641
|
-
if (!cfg || typeof s !== "string" || !s) return s;
|
|
12642
|
-
const allow = new Set(cfg.patterns);
|
|
12643
|
-
const NUL = String.fromCharCode(0);
|
|
12644
|
-
const labels = [];
|
|
12645
|
-
const stash = (label) => NUL + (labels.push(label) - 1) + NUL;
|
|
12646
|
-
let out2 = s;
|
|
12647
|
-
for (const p of DLP_PATTERNS) if (allow.has(p.name)) out2 = out2.replace(p.re, () => stash(`[REDACTED: ${p.name}]`));
|
|
12648
|
-
for (const c2 of cfg.custom) {
|
|
12649
|
-
try {
|
|
12650
|
-
out2 = out2.replace(dlpGlobToRe(c2.re, "gi"), () => stash(`[REDACTED: ${c2.name || "custom"}]`));
|
|
12651
|
-
} catch {
|
|
12652
|
-
}
|
|
12653
|
-
}
|
|
12654
|
-
return out2.replace(new RegExp(NUL + "(\\d+)" + NUL, "g"), (_, i) => labels[+i] || "");
|
|
12655
|
-
}
|
|
12656
|
-
function redactDeep(value, cfg) {
|
|
12657
|
-
const ghost = cfg && Array.isArray(cfg.ghost) ? cfg.ghost : null;
|
|
12658
|
-
if (typeof value === "string") {
|
|
12659
|
-
let out2 = redactString(value, cfg);
|
|
12660
|
-
if (ghost && ghost.length) out2 = ghostStripLines(out2, ghost);
|
|
12661
|
-
if (out2 === "" && value !== "") out2 = "\n";
|
|
12662
|
-
return out2;
|
|
12663
|
-
}
|
|
12664
|
-
if (Array.isArray(value)) {
|
|
12665
|
-
const arr = ghost && ghost.length ? value.filter((v) => !(typeof v === "string" && ghostMatch(v.trim(), ghost))) : value;
|
|
12666
|
-
return arr.map((v) => redactDeep(v, cfg));
|
|
12667
|
-
}
|
|
12668
|
-
if (value && typeof value === "object") {
|
|
12669
|
-
const out2 = {};
|
|
12670
|
-
for (const [k, v] of Object.entries(value)) out2[k] = redactDeep(v, cfg);
|
|
12671
|
-
return out2;
|
|
12672
|
-
}
|
|
12673
|
-
return value;
|
|
12674
|
-
}
|
|
12675
|
-
function pickUpstream() {
|
|
12676
|
-
const raw = process.env.SOLONGATE_SHIELD_UPSTREAM || process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
|
|
12677
|
-
try {
|
|
12678
|
-
return new URL2(raw);
|
|
12679
|
-
} catch {
|
|
12680
|
-
return new URL2("https://api.anthropic.com");
|
|
12681
|
-
}
|
|
12682
|
-
}
|
|
12683
|
-
function startProxy(upstream) {
|
|
12684
|
-
const forward = upstream.protocol === "https:" ? httpsRequest : httpRequest;
|
|
12685
|
-
const server = createServer((req, res) => {
|
|
12686
|
-
const cfg = loadCfg();
|
|
12687
|
-
const chunks = [];
|
|
12688
|
-
req.on("data", (c2) => chunks.push(c2));
|
|
12689
|
-
req.on("end", () => {
|
|
12690
|
-
let body = Buffer.concat(chunks);
|
|
12691
|
-
try {
|
|
12692
|
-
if (body.length && (req.headers["content-type"] || "").includes("json")) {
|
|
12693
|
-
const parsed = JSON.parse(body.toString("utf-8"));
|
|
12694
|
-
if (parsed && typeof parsed === "object" && Array.isArray(parsed["messages"])) {
|
|
12695
|
-
if (parsed["system"] !== void 0) parsed["system"] = redactDeep(parsed["system"], cfg);
|
|
12696
|
-
const msgs = parsed["messages"];
|
|
12697
|
-
for (let i = 0; i < msgs.length; i++) {
|
|
12698
|
-
const m = msgs[i];
|
|
12699
|
-
if (m && m["role"] !== "assistant") msgs[i] = redactDeep(m, cfg);
|
|
12700
|
-
}
|
|
12701
|
-
body = Buffer.from(JSON.stringify(parsed), "utf-8");
|
|
12702
|
-
} else {
|
|
12703
|
-
body = Buffer.from(JSON.stringify(redactDeep(parsed, cfg)), "utf-8");
|
|
12704
|
-
}
|
|
12705
|
-
}
|
|
12706
|
-
} catch {
|
|
12707
|
-
}
|
|
12708
|
-
const headers = { ...req.headers };
|
|
12709
|
-
delete headers["host"];
|
|
12710
|
-
delete headers["content-length"];
|
|
12711
|
-
delete headers["accept-encoding"];
|
|
12712
|
-
headers["content-length"] = String(body.length);
|
|
12713
|
-
const upstreamReq = forward(
|
|
12714
|
-
{
|
|
12715
|
-
protocol: upstream.protocol,
|
|
12716
|
-
hostname: upstream.hostname,
|
|
12717
|
-
port: upstream.port || (upstream.protocol === "https:" ? 443 : 80),
|
|
12718
|
-
method: req.method,
|
|
12719
|
-
path: req.url,
|
|
12720
|
-
headers: { ...headers, host: upstream.host }
|
|
12721
|
-
},
|
|
12722
|
-
(upRes) => {
|
|
12723
|
-
res.writeHead(upRes.statusCode || 502, upRes.headers);
|
|
12724
|
-
upRes.pipe(res);
|
|
12725
|
-
}
|
|
12726
|
-
);
|
|
12727
|
-
upstreamReq.on("error", (e) => {
|
|
12728
|
-
log4("upstream error:", e.message);
|
|
12729
|
-
if (!res.headersSent) res.writeHead(502, { "content-type": "text/plain" });
|
|
12730
|
-
res.end("shield upstream error");
|
|
12731
|
-
});
|
|
12732
|
-
upstreamReq.end(body);
|
|
12733
|
-
});
|
|
12734
|
-
req.on("error", () => {
|
|
12735
|
-
try {
|
|
12736
|
-
res.destroy();
|
|
12737
|
-
} catch {
|
|
12738
|
-
}
|
|
12739
|
-
});
|
|
12740
|
-
});
|
|
12741
|
-
return new Promise((resolveP) => {
|
|
12742
|
-
server.listen(0, "127.0.0.1", () => {
|
|
12743
|
-
const addr = server.address();
|
|
12744
|
-
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
12745
|
-
resolveP({ port, close: () => server.close() });
|
|
12746
|
-
});
|
|
12747
|
-
});
|
|
12748
|
-
}
|
|
12749
|
-
async function runShield() {
|
|
12750
|
-
const sep = process.argv.indexOf("--");
|
|
12751
|
-
const cmd = sep !== -1 ? process.argv.slice(sep + 1) : [];
|
|
12752
|
-
if (cmd.length === 0) {
|
|
12753
|
-
log4("usage: npx @solongate/proxy shield -- <command> [args...] (e.g. shield -- claude)");
|
|
12754
|
-
process.exit(1);
|
|
12755
|
-
}
|
|
12756
|
-
const upstream = pickUpstream();
|
|
12757
|
-
const { port, close } = await startProxy(upstream);
|
|
12758
|
-
log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
|
|
12759
|
-
const child = spawn5(cmd[0], cmd.slice(1), {
|
|
12760
|
-
stdio: "inherit",
|
|
12761
|
-
env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
|
|
12762
|
-
shell: process.platform === "win32"
|
|
12763
|
-
// resolve `claude.cmd` etc. on Windows
|
|
12764
|
-
});
|
|
12765
|
-
const shutdown = () => {
|
|
12766
|
-
try {
|
|
12767
|
-
close();
|
|
12768
|
-
} catch {
|
|
12769
|
-
}
|
|
12770
|
-
};
|
|
12771
|
-
child.on("exit", (code, signal) => {
|
|
12772
|
-
shutdown();
|
|
12773
|
-
if (signal) process.kill(process.pid, signal);
|
|
12774
|
-
else process.exit(code ?? 0);
|
|
12775
|
-
});
|
|
12776
|
-
child.on("error", (e) => {
|
|
12777
|
-
log4("failed to launch command:", e.message);
|
|
12778
|
-
shutdown();
|
|
12779
|
-
process.exit(1);
|
|
12780
|
-
});
|
|
12781
|
-
for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => {
|
|
12782
|
-
try {
|
|
12783
|
-
child.kill(sig);
|
|
12784
|
-
} catch {
|
|
12785
|
-
}
|
|
12786
|
-
});
|
|
12787
|
-
}
|
|
12788
|
-
var log4, DLP_PATTERNS;
|
|
12789
|
-
var init_shield = __esm({
|
|
12790
|
-
"src/shield.ts"() {
|
|
12791
|
-
"use strict";
|
|
12792
|
-
log4 = (...a) => process.stderr.write(`[SolonGate shield] ${a.map(String).join(" ")}
|
|
12793
|
-
`);
|
|
12794
|
-
DLP_PATTERNS = [
|
|
12795
|
-
{ name: "AWS access key", re: /AKIA[0-9A-Z]{16}/g },
|
|
12796
|
-
{ name: "Private key block", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----|-----BEGIN [A-Z ]*PRIVATE KEY-----/g },
|
|
12797
|
-
{ name: "Anthropic key", re: /sk-ant-[A-Za-z0-9_-]{20,}/g },
|
|
12798
|
-
{ name: "OpenAI key", re: /sk-(proj-)?[A-Za-z0-9_-]{20,}/g },
|
|
12799
|
-
{ name: "GitHub token", re: /gh[pousr]_[A-Za-z0-9]{20,}/g },
|
|
12800
|
-
{ name: "GitHub fine-grained PAT", re: /github_pat_[A-Za-z0-9_]{20,}/g },
|
|
12801
|
-
{ name: "GitLab token", re: /glpat-[A-Za-z0-9_-]{20,}/g },
|
|
12802
|
-
{ name: "Slack token", re: /xox[baprs]-[A-Za-z0-9-]{10,}/g },
|
|
12803
|
-
{ name: "Stripe key", re: /[sr]k_(live|test)_[A-Za-z0-9]{20,}/g },
|
|
12804
|
-
{ name: "SendGrid key", re: /SG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}/g },
|
|
12805
|
-
{ name: "Twilio key", re: /SK[0-9a-fA-F]{32}/g },
|
|
12806
|
-
{ name: "npm token", re: /npm_[A-Za-z0-9]{36}/g },
|
|
12807
|
-
{ name: "JWT", re: /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g },
|
|
12808
|
-
{ name: "Bearer token", re: /bearer\s+[A-Za-z0-9._-]{20,}/gi }
|
|
12809
|
-
];
|
|
12398
|
+
COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks"];
|
|
12810
12399
|
}
|
|
12811
12400
|
});
|
|
12812
12401
|
|
|
@@ -12815,11 +12404,11 @@ var logs_server_exports = {};
|
|
|
12815
12404
|
__export(logs_server_exports, {
|
|
12816
12405
|
runLogsServer: () => runLogsServer
|
|
12817
12406
|
});
|
|
12818
|
-
import { createServer
|
|
12819
|
-
import { readFileSync as
|
|
12820
|
-
import { resolve as
|
|
12821
|
-
import { homedir as
|
|
12822
|
-
import { readdirSync
|
|
12407
|
+
import { createServer } from "http";
|
|
12408
|
+
import { readFileSync as readFileSync11, statSync as statSync4 } from "fs";
|
|
12409
|
+
import { resolve as resolve5, join as join15, isAbsolute } from "path";
|
|
12410
|
+
import { homedir as homedir13 } from "os";
|
|
12411
|
+
import { readdirSync } from "fs";
|
|
12823
12412
|
function allowedOrigins() {
|
|
12824
12413
|
const base = [
|
|
12825
12414
|
"https://dashboard.solongate.com",
|
|
@@ -12835,15 +12424,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
12835
12424
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
12836
12425
|
if (!dir) return null;
|
|
12837
12426
|
if (isAbsolute(dir)) return dir;
|
|
12838
|
-
return
|
|
12427
|
+
return resolve5(homedir13(), ".solongate", "local-logs");
|
|
12839
12428
|
}
|
|
12840
12429
|
async function findLogDir() {
|
|
12841
|
-
const base =
|
|
12430
|
+
const base = resolve5(homedir13(), ".solongate");
|
|
12842
12431
|
try {
|
|
12843
|
-
const files =
|
|
12432
|
+
const files = readdirSync(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
12844
12433
|
for (const f of files) {
|
|
12845
12434
|
try {
|
|
12846
|
-
const c2 = JSON.parse(
|
|
12435
|
+
const c2 = JSON.parse(readFileSync11(join15(base, f), "utf-8"));
|
|
12847
12436
|
const p = c2?.security?.localLogs?.path;
|
|
12848
12437
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
12849
12438
|
} catch {
|
|
@@ -12852,7 +12441,7 @@ async function findLogDir() {
|
|
|
12852
12441
|
} catch {
|
|
12853
12442
|
}
|
|
12854
12443
|
try {
|
|
12855
|
-
const cfgRaw =
|
|
12444
|
+
const cfgRaw = readFileSync11(join15(base, "cloud-guard.json"), "utf-8");
|
|
12856
12445
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
12857
12446
|
if (apiKey) {
|
|
12858
12447
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -12883,7 +12472,7 @@ function fileInfo(dir) {
|
|
|
12883
12472
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
12884
12473
|
const file = join15(dir, LOG_FILENAME);
|
|
12885
12474
|
try {
|
|
12886
|
-
const st =
|
|
12475
|
+
const st = statSync4(file);
|
|
12887
12476
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
12888
12477
|
} catch {
|
|
12889
12478
|
return { file, exists: false, size: 0, mtimeMs: 0 };
|
|
@@ -12915,7 +12504,7 @@ async function runLogsServer() {
|
|
|
12915
12504
|
}
|
|
12916
12505
|
const portArg = argv[argv.indexOf("--port") + 1];
|
|
12917
12506
|
const port = Number(process.env.SOLONGATE_LOGS_PORT || (argv.includes("--port") ? portArg : "") || DEFAULT_PORT) || DEFAULT_PORT;
|
|
12918
|
-
const server =
|
|
12507
|
+
const server = createServer(async (req, res) => {
|
|
12919
12508
|
setCors(req, res);
|
|
12920
12509
|
if (req.method === "OPTIONS") {
|
|
12921
12510
|
res.writeHead(204);
|
|
@@ -12964,7 +12553,7 @@ async function runLogsServer() {
|
|
|
12964
12553
|
return;
|
|
12965
12554
|
}
|
|
12966
12555
|
try {
|
|
12967
|
-
const text =
|
|
12556
|
+
const text = readFileSync11(info.file, "utf-8");
|
|
12968
12557
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8", "Last-Modified": lastMod, "X-Solongate-Exists": "1" });
|
|
12969
12558
|
res.end(text);
|
|
12970
12559
|
} catch {
|
|
@@ -13018,8 +12607,8 @@ var init_logs_server = __esm({
|
|
|
13018
12607
|
|
|
13019
12608
|
// src/inject.ts
|
|
13020
12609
|
var inject_exports = {};
|
|
13021
|
-
import { readFileSync as
|
|
13022
|
-
import { resolve as
|
|
12610
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync10, existsSync as existsSync7, copyFileSync } from "fs";
|
|
12611
|
+
import { resolve as resolve6 } from "path";
|
|
13023
12612
|
import { execSync } from "child_process";
|
|
13024
12613
|
function parseInjectArgs(argv) {
|
|
13025
12614
|
const args = argv.slice(2);
|
|
@@ -13076,9 +12665,9 @@ WHAT IT DOES
|
|
|
13076
12665
|
`);
|
|
13077
12666
|
}
|
|
13078
12667
|
function detectProject() {
|
|
13079
|
-
if (!
|
|
12668
|
+
if (!existsSync7(resolve6("package.json"))) return false;
|
|
13080
12669
|
try {
|
|
13081
|
-
const pkg = JSON.parse(
|
|
12670
|
+
const pkg = JSON.parse(readFileSync12(resolve6("package.json"), "utf-8"));
|
|
13082
12671
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13083
12672
|
return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
|
|
13084
12673
|
} catch {
|
|
@@ -13087,18 +12676,18 @@ function detectProject() {
|
|
|
13087
12676
|
}
|
|
13088
12677
|
function findTsEntryFile() {
|
|
13089
12678
|
try {
|
|
13090
|
-
const pkg = JSON.parse(
|
|
12679
|
+
const pkg = JSON.parse(readFileSync12(resolve6("package.json"), "utf-8"));
|
|
13091
12680
|
if (pkg.bin) {
|
|
13092
12681
|
const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
|
|
13093
12682
|
if (typeof binPath === "string") {
|
|
13094
12683
|
const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
13095
|
-
if (
|
|
13096
|
-
if (
|
|
12684
|
+
if (existsSync7(resolve6(srcPath))) return resolve6(srcPath);
|
|
12685
|
+
if (existsSync7(resolve6(binPath))) return resolve6(binPath);
|
|
13097
12686
|
}
|
|
13098
12687
|
}
|
|
13099
12688
|
if (pkg.main) {
|
|
13100
12689
|
const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
13101
|
-
if (
|
|
12690
|
+
if (existsSync7(resolve6(srcPath))) return resolve6(srcPath);
|
|
13102
12691
|
}
|
|
13103
12692
|
} catch {
|
|
13104
12693
|
}
|
|
@@ -13111,10 +12700,10 @@ function findTsEntryFile() {
|
|
|
13111
12700
|
"main.ts"
|
|
13112
12701
|
];
|
|
13113
12702
|
for (const c2 of candidates) {
|
|
13114
|
-
const full =
|
|
13115
|
-
if (
|
|
12703
|
+
const full = resolve6(c2);
|
|
12704
|
+
if (existsSync7(full)) {
|
|
13116
12705
|
try {
|
|
13117
|
-
const content =
|
|
12706
|
+
const content = readFileSync12(full, "utf-8");
|
|
13118
12707
|
if (content.includes("McpServer") || content.includes("McpServer")) {
|
|
13119
12708
|
return full;
|
|
13120
12709
|
}
|
|
@@ -13123,18 +12712,18 @@ function findTsEntryFile() {
|
|
|
13123
12712
|
}
|
|
13124
12713
|
}
|
|
13125
12714
|
for (const c2 of candidates) {
|
|
13126
|
-
if (
|
|
12715
|
+
if (existsSync7(resolve6(c2))) return resolve6(c2);
|
|
13127
12716
|
}
|
|
13128
12717
|
return null;
|
|
13129
12718
|
}
|
|
13130
12719
|
function detectPackageManager() {
|
|
13131
|
-
if (
|
|
13132
|
-
if (
|
|
12720
|
+
if (existsSync7(resolve6("pnpm-lock.yaml"))) return "pnpm";
|
|
12721
|
+
if (existsSync7(resolve6("yarn.lock"))) return "yarn";
|
|
13133
12722
|
return "npm";
|
|
13134
12723
|
}
|
|
13135
12724
|
function installSdk() {
|
|
13136
12725
|
try {
|
|
13137
|
-
const pkg = JSON.parse(
|
|
12726
|
+
const pkg = JSON.parse(readFileSync12(resolve6("package.json"), "utf-8"));
|
|
13138
12727
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13139
12728
|
if (allDeps["@solongate/proxy"]) {
|
|
13140
12729
|
log3(" @solongate/proxy already installed");
|
|
@@ -13155,7 +12744,7 @@ function installSdk() {
|
|
|
13155
12744
|
}
|
|
13156
12745
|
}
|
|
13157
12746
|
function injectTypeScript(filePath) {
|
|
13158
|
-
const original =
|
|
12747
|
+
const original = readFileSync12(filePath, "utf-8");
|
|
13159
12748
|
const changes = [];
|
|
13160
12749
|
let modified = original;
|
|
13161
12750
|
if (modified.includes("SecureMcpServer")) {
|
|
@@ -13271,8 +12860,8 @@ async function main() {
|
|
|
13271
12860
|
process.exit(1);
|
|
13272
12861
|
}
|
|
13273
12862
|
log3(" Language: TypeScript");
|
|
13274
|
-
const entryFile = opts.file ?
|
|
13275
|
-
if (!entryFile || !
|
|
12863
|
+
const entryFile = opts.file ? resolve6(opts.file) : findTsEntryFile();
|
|
12864
|
+
if (!entryFile || !existsSync7(entryFile)) {
|
|
13276
12865
|
log3(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
|
|
13277
12866
|
log3("");
|
|
13278
12867
|
log3(" Specify it manually: --file <path>");
|
|
@@ -13285,7 +12874,7 @@ async function main() {
|
|
|
13285
12874
|
log3("");
|
|
13286
12875
|
const backupPath = entryFile + ".solongate-backup";
|
|
13287
12876
|
if (opts.restore) {
|
|
13288
|
-
if (!
|
|
12877
|
+
if (!existsSync7(backupPath)) {
|
|
13289
12878
|
log3(" No backup found. Nothing to restore.");
|
|
13290
12879
|
process.exit(1);
|
|
13291
12880
|
}
|
|
@@ -13321,7 +12910,7 @@ async function main() {
|
|
|
13321
12910
|
log3(" To apply: npx @solongate/proxy inject");
|
|
13322
12911
|
process.exit(0);
|
|
13323
12912
|
}
|
|
13324
|
-
if (!
|
|
12913
|
+
if (!existsSync7(backupPath)) {
|
|
13325
12914
|
copyFileSync(entryFile, backupPath);
|
|
13326
12915
|
log3("");
|
|
13327
12916
|
log3(` Backup: ${backupPath}`);
|
|
@@ -13355,8 +12944,8 @@ var init_inject = __esm({
|
|
|
13355
12944
|
|
|
13356
12945
|
// src/create.ts
|
|
13357
12946
|
var create_exports = {};
|
|
13358
|
-
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, existsSync as
|
|
13359
|
-
import { resolve as
|
|
12947
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, existsSync as existsSync8 } from "fs";
|
|
12948
|
+
import { resolve as resolve7, join as join16 } from "path";
|
|
13360
12949
|
import { execSync as execSync2 } from "child_process";
|
|
13361
12950
|
function withSpinner(message, fn) {
|
|
13362
12951
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -13565,9 +13154,9 @@ dist/
|
|
|
13565
13154
|
}
|
|
13566
13155
|
async function main2() {
|
|
13567
13156
|
const opts = parseCreateArgs(process.argv);
|
|
13568
|
-
const dir =
|
|
13157
|
+
const dir = resolve7(opts.name);
|
|
13569
13158
|
printBanner("Create MCP Server");
|
|
13570
|
-
if (
|
|
13159
|
+
if (existsSync8(dir)) {
|
|
13571
13160
|
log3(` ${c.red}Error:${c.reset} Directory "${opts.name}" already exists.`);
|
|
13572
13161
|
process.exit(1);
|
|
13573
13162
|
}
|
|
@@ -13646,14 +13235,14 @@ var init_create = __esm({
|
|
|
13646
13235
|
|
|
13647
13236
|
// src/pull-push.ts
|
|
13648
13237
|
var pull_push_exports = {};
|
|
13649
|
-
import { readFileSync as
|
|
13650
|
-
import { resolve as
|
|
13238
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync12, existsSync as existsSync9 } from "fs";
|
|
13239
|
+
import { resolve as resolve8 } from "path";
|
|
13651
13240
|
function loadEnv() {
|
|
13652
13241
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
13653
|
-
const envPath =
|
|
13654
|
-
if (!
|
|
13242
|
+
const envPath = resolve8(".env");
|
|
13243
|
+
if (!existsSync9(envPath)) return;
|
|
13655
13244
|
try {
|
|
13656
|
-
const content =
|
|
13245
|
+
const content = readFileSync13(envPath, "utf-8");
|
|
13657
13246
|
for (const line of content.split("\n")) {
|
|
13658
13247
|
const trimmed = line.trim();
|
|
13659
13248
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -13695,20 +13284,20 @@ function parseCliArgs() {
|
|
|
13695
13284
|
}
|
|
13696
13285
|
}
|
|
13697
13286
|
if (!apiKey) {
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13287
|
+
log4(red2("ERROR: API key not found."));
|
|
13288
|
+
log4("");
|
|
13289
|
+
log4("Set it in .env file:");
|
|
13290
|
+
log4(" SOLONGATE_API_KEY=sg_live_...");
|
|
13291
|
+
log4("");
|
|
13292
|
+
log4("Or pass via environment:");
|
|
13293
|
+
log4(` SOLONGATE_API_KEY=sg_live_... solongate-proxy ${command}`);
|
|
13705
13294
|
process.exit(1);
|
|
13706
13295
|
}
|
|
13707
13296
|
if (!apiKey.startsWith("sg_live_")) {
|
|
13708
|
-
|
|
13297
|
+
log4(red2("ERROR: Pull/push/list requires a live API key (sg_live_...)."));
|
|
13709
13298
|
process.exit(1);
|
|
13710
13299
|
}
|
|
13711
|
-
return { command, apiKey, file:
|
|
13300
|
+
return { command, apiKey, file: resolve8(file), policyId };
|
|
13712
13301
|
}
|
|
13713
13302
|
async function listPolicies(apiKey) {
|
|
13714
13303
|
const res = await fetch(`${API_URL}/api/v1/policies`, {
|
|
@@ -13721,18 +13310,18 @@ async function listPolicies(apiKey) {
|
|
|
13721
13310
|
async function list5(apiKey, policyId) {
|
|
13722
13311
|
const policies = await listPolicies(apiKey);
|
|
13723
13312
|
if (policies.length === 0) {
|
|
13724
|
-
|
|
13725
|
-
|
|
13313
|
+
log4(yellow2("No policies found. Create one in the dashboard first."));
|
|
13314
|
+
log4(dim2(" https://dashboard.solongate.com/policies"));
|
|
13726
13315
|
return;
|
|
13727
13316
|
}
|
|
13728
13317
|
if (policyId) {
|
|
13729
13318
|
const match = policies.find((p) => p.id === policyId);
|
|
13730
13319
|
if (!match) {
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
13320
|
+
log4(red2(`Policy not found: ${policyId}`));
|
|
13321
|
+
log4("");
|
|
13322
|
+
log4("Available policies:");
|
|
13734
13323
|
for (const p of policies) {
|
|
13735
|
-
|
|
13324
|
+
log4(` ${dim2("\u2022")} ${p.id}`);
|
|
13736
13325
|
}
|
|
13737
13326
|
process.exit(1);
|
|
13738
13327
|
}
|
|
@@ -13740,10 +13329,10 @@ async function list5(apiKey, policyId) {
|
|
|
13740
13329
|
printPolicyDetail(full);
|
|
13741
13330
|
return;
|
|
13742
13331
|
}
|
|
13743
|
-
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
13332
|
+
log4("");
|
|
13333
|
+
log4(bold2(` Policies (${policies.length})`));
|
|
13334
|
+
log4(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
13335
|
+
log4("");
|
|
13747
13336
|
const fullPolicies = await Promise.all(
|
|
13748
13337
|
policies.map(
|
|
13749
13338
|
(p) => fetchCloudPolicy(apiKey, API_URL, p.id).then((full) => ({ policy: p, rules: full.rules })).catch(() => ({ policy: p, rules: [] }))
|
|
@@ -13752,136 +13341,136 @@ async function list5(apiKey, policyId) {
|
|
|
13752
13341
|
for (const { policy, rules } of fullPolicies) {
|
|
13753
13342
|
printPolicySummary(policy, [...rules]);
|
|
13754
13343
|
}
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13759
|
-
|
|
13760
|
-
|
|
13344
|
+
log4(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
13345
|
+
log4("");
|
|
13346
|
+
log4(` ${dim2("View details:")} solongate-proxy list --policy-id <ID>`);
|
|
13347
|
+
log4(` ${dim2("Pull policy:")} solongate-proxy pull --policy-id <ID>`);
|
|
13348
|
+
log4(` ${dim2("Push policy:")} solongate-proxy push --policy-id <ID>`);
|
|
13349
|
+
log4("");
|
|
13761
13350
|
}
|
|
13762
13351
|
function printPolicySummary(p, rules) {
|
|
13763
13352
|
const ruleCount = rules.length;
|
|
13764
13353
|
const allowCount = rules.filter((r) => r.effect === "ALLOW").length;
|
|
13765
13354
|
const denyCount = rules.filter((r) => r.effect === "DENY").length;
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
13355
|
+
log4(` ${cyan2(p.id)}`);
|
|
13356
|
+
log4(` ${bold2(p.name)} ${dim2(`v${p.version ?? "?"}`)}`);
|
|
13357
|
+
log4(` ${dim2("Rules:")} ${ruleCount} ${green2(`${allowCount} ALLOW`)} ${red2(`${denyCount} DENY`)}`);
|
|
13769
13358
|
if (p.created_at) {
|
|
13770
|
-
|
|
13359
|
+
log4(` ${dim2("Updated:")} ${new Date(p.created_at).toLocaleString()}`);
|
|
13771
13360
|
}
|
|
13772
|
-
|
|
13361
|
+
log4("");
|
|
13773
13362
|
}
|
|
13774
13363
|
function printPolicyDetail(policy) {
|
|
13775
|
-
|
|
13776
|
-
|
|
13777
|
-
|
|
13778
|
-
|
|
13364
|
+
log4("");
|
|
13365
|
+
log4(bold2(` ${policy.name}`));
|
|
13366
|
+
log4(` ${dim2("ID:")} ${cyan2(policy.id)} ${dim2("Version:")} ${policy.version} ${dim2("Rules:")} ${policy.rules.length}`);
|
|
13367
|
+
log4("");
|
|
13779
13368
|
if (policy.rules.length === 0) {
|
|
13780
|
-
|
|
13781
|
-
|
|
13369
|
+
log4(yellow2(" No rules defined."));
|
|
13370
|
+
log4("");
|
|
13782
13371
|
return;
|
|
13783
13372
|
}
|
|
13784
|
-
|
|
13373
|
+
log4(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
13785
13374
|
for (const rule of policy.rules) {
|
|
13786
13375
|
const effectColor = rule.effect === "ALLOW" ? green2 : red2;
|
|
13787
|
-
|
|
13788
|
-
|
|
13376
|
+
log4("");
|
|
13377
|
+
log4(` ${effectColor(rule.effect.padEnd(5))} ${bold2(rule.toolPattern)} ${dim2(`P:${rule.priority}`)}`);
|
|
13789
13378
|
if (rule.description) {
|
|
13790
|
-
|
|
13379
|
+
log4(` ${dim2(rule.description)}`);
|
|
13791
13380
|
}
|
|
13792
|
-
|
|
13381
|
+
log4(` ${dim2(`${rule.permission} trust:${rule.minimumTrustLevel || "UNTRUSTED"}`)}`);
|
|
13793
13382
|
if (rule.pathConstraints) {
|
|
13794
13383
|
const pc = rule.pathConstraints;
|
|
13795
|
-
if (pc.rootDirectory)
|
|
13796
|
-
if (pc.allowed?.length)
|
|
13797
|
-
if (pc.denied?.length)
|
|
13384
|
+
if (pc.rootDirectory) log4(` ${magenta("ROOT")} ${pc.rootDirectory}`);
|
|
13385
|
+
if (pc.allowed?.length) log4(` ${green2("PATHS")} ${pc.allowed.join(", ")}`);
|
|
13386
|
+
if (pc.denied?.length) log4(` ${red2("DENY")} ${pc.denied.join(", ")}`);
|
|
13798
13387
|
}
|
|
13799
13388
|
if (rule.commandConstraints) {
|
|
13800
13389
|
const cc = rule.commandConstraints;
|
|
13801
|
-
if (cc.allowed?.length)
|
|
13802
|
-
if (cc.denied?.length)
|
|
13390
|
+
if (cc.allowed?.length) log4(` ${green2("CMDS")} ${cc.allowed.join(", ")}`);
|
|
13391
|
+
if (cc.denied?.length) log4(` ${red2("DENY")} ${cc.denied.join(", ")}`);
|
|
13803
13392
|
}
|
|
13804
13393
|
if (rule.filenameConstraints) {
|
|
13805
13394
|
const fc = rule.filenameConstraints;
|
|
13806
|
-
if (fc.allowed?.length)
|
|
13807
|
-
if (fc.denied?.length)
|
|
13395
|
+
if (fc.allowed?.length) log4(` ${green2("FILES")} ${fc.allowed.join(", ")}`);
|
|
13396
|
+
if (fc.denied?.length) log4(` ${red2("DENY")} ${fc.denied.join(", ")}`);
|
|
13808
13397
|
}
|
|
13809
13398
|
if (rule.urlConstraints) {
|
|
13810
13399
|
const uc = rule.urlConstraints;
|
|
13811
|
-
if (uc.allowed?.length)
|
|
13812
|
-
if (uc.denied?.length)
|
|
13400
|
+
if (uc.allowed?.length) log4(` ${green2("URLS")} ${uc.allowed.join(", ")}`);
|
|
13401
|
+
if (uc.denied?.length) log4(` ${red2("DENY")} ${uc.denied.join(", ")}`);
|
|
13813
13402
|
}
|
|
13814
13403
|
}
|
|
13815
|
-
|
|
13816
|
-
|
|
13817
|
-
|
|
13404
|
+
log4("");
|
|
13405
|
+
log4(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
13406
|
+
log4("");
|
|
13818
13407
|
}
|
|
13819
13408
|
async function pull(apiKey, file, policyId) {
|
|
13820
13409
|
if (!policyId) {
|
|
13821
13410
|
const policies = await listPolicies(apiKey);
|
|
13822
13411
|
if (policies.length === 0) {
|
|
13823
|
-
|
|
13412
|
+
log4(red2("No policies found. Create one in the dashboard first."));
|
|
13824
13413
|
process.exit(1);
|
|
13825
13414
|
}
|
|
13826
13415
|
if (policies.length === 1) {
|
|
13827
13416
|
policyId = policies[0].id;
|
|
13828
|
-
|
|
13417
|
+
log4(dim2(`Auto-selecting only policy: ${policyId}`));
|
|
13829
13418
|
} else {
|
|
13830
|
-
|
|
13831
|
-
|
|
13419
|
+
log4(yellow2(`Found ${policies.length} policies:`));
|
|
13420
|
+
log4("");
|
|
13832
13421
|
for (const p of policies) {
|
|
13833
|
-
|
|
13422
|
+
log4(` ${cyan2(p.id)} ${p.name} ${dim2(`v${p.version ?? "?"}`)}`);
|
|
13834
13423
|
}
|
|
13835
|
-
|
|
13836
|
-
|
|
13424
|
+
log4("");
|
|
13425
|
+
log4("Use --policy-id <ID> to specify which one to pull.");
|
|
13837
13426
|
process.exit(1);
|
|
13838
13427
|
}
|
|
13839
13428
|
}
|
|
13840
|
-
|
|
13429
|
+
log4(`Pulling ${cyan2(policyId)} from dashboard...`);
|
|
13841
13430
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
13842
13431
|
const { id: _id, ...policyWithoutId } = policy;
|
|
13843
13432
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
13844
13433
|
writeFileSync12(file, json, "utf-8");
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13434
|
+
log4("");
|
|
13435
|
+
log4(green2(" Saved to: ") + file);
|
|
13436
|
+
log4(` ${dim2("Name:")} ${policy.name}`);
|
|
13437
|
+
log4(` ${dim2("Version:")} ${policy.version}`);
|
|
13438
|
+
log4(` ${dim2("Rules:")} ${policy.rules.length}`);
|
|
13439
|
+
log4("");
|
|
13440
|
+
log4(dim2("The policy file does not contain an ID."));
|
|
13441
|
+
log4(dim2("Use --policy-id to specify the target when pushing/pulling."));
|
|
13442
|
+
log4("");
|
|
13854
13443
|
}
|
|
13855
13444
|
async function push(apiKey, file, policyId) {
|
|
13856
|
-
if (!
|
|
13857
|
-
|
|
13445
|
+
if (!existsSync9(file)) {
|
|
13446
|
+
log4(red2(`ERROR: File not found: ${file}`));
|
|
13858
13447
|
process.exit(1);
|
|
13859
13448
|
}
|
|
13860
13449
|
if (!policyId) {
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
|
|
13450
|
+
log4(red2("ERROR: --policy-id is required for push."));
|
|
13451
|
+
log4("");
|
|
13452
|
+
log4("This determines which cloud policy to update.");
|
|
13453
|
+
log4("");
|
|
13454
|
+
log4("Usage:");
|
|
13455
|
+
log4(" solongate-proxy push --policy-id my-policy");
|
|
13456
|
+
log4(" solongate-proxy push --policy-id my-policy --file custom.json");
|
|
13457
|
+
log4("");
|
|
13458
|
+
log4("List your policies:");
|
|
13459
|
+
log4(" solongate-proxy list");
|
|
13871
13460
|
process.exit(1);
|
|
13872
13461
|
}
|
|
13873
|
-
const content =
|
|
13462
|
+
const content = readFileSync13(file, "utf-8");
|
|
13874
13463
|
let policy;
|
|
13875
13464
|
try {
|
|
13876
13465
|
policy = JSON.parse(content);
|
|
13877
13466
|
} catch {
|
|
13878
|
-
|
|
13467
|
+
log4(red2(`ERROR: Invalid JSON in ${file}`));
|
|
13879
13468
|
process.exit(1);
|
|
13880
13469
|
}
|
|
13881
|
-
|
|
13882
|
-
|
|
13883
|
-
|
|
13884
|
-
|
|
13470
|
+
log4(`Pushing to ${cyan2(policyId)}...`);
|
|
13471
|
+
log4(` ${dim2("File:")} ${file}`);
|
|
13472
|
+
log4(` ${dim2("Name:")} ${policy.name || "Unnamed"}`);
|
|
13473
|
+
log4(` ${dim2("Rules:")} ${(policy.rules || []).length}`);
|
|
13885
13474
|
const checkRes = await fetch(`${API_URL}/api/v1/policies/${policyId}`, {
|
|
13886
13475
|
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
13887
13476
|
});
|
|
@@ -13903,15 +13492,15 @@ async function push(apiKey, file, policyId) {
|
|
|
13903
13492
|
});
|
|
13904
13493
|
if (!res.ok) {
|
|
13905
13494
|
const body = await res.text().catch(() => "");
|
|
13906
|
-
|
|
13495
|
+
log4(red2(`ERROR: Push failed (${res.status}): ${body}`));
|
|
13907
13496
|
process.exit(1);
|
|
13908
13497
|
}
|
|
13909
13498
|
const data = await res.json();
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13499
|
+
log4("");
|
|
13500
|
+
log4(green2(` Pushed to cloud: v${data._version ?? "created"}`));
|
|
13501
|
+
log4(` ${dim2("Policy ID:")} ${policyId}`);
|
|
13502
|
+
log4(` ${dim2("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
|
|
13503
|
+
log4("");
|
|
13915
13504
|
}
|
|
13916
13505
|
async function main3() {
|
|
13917
13506
|
const { command, apiKey, file, policyId } = parseCliArgs();
|
|
@@ -13923,32 +13512,32 @@ async function main3() {
|
|
|
13923
13512
|
} else if (command === "list" || command === "ls") {
|
|
13924
13513
|
await list5(apiKey, policyId);
|
|
13925
13514
|
} else {
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13515
|
+
log4(red2(`Unknown command: ${command}`));
|
|
13516
|
+
log4("");
|
|
13517
|
+
log4(bold2("Usage:"));
|
|
13518
|
+
log4(" solongate-proxy list List all policies");
|
|
13519
|
+
log4(" solongate-proxy list --policy-id <ID> Show policy details");
|
|
13520
|
+
log4(" solongate-proxy pull --policy-id <ID> Pull policy to local file");
|
|
13521
|
+
log4(" solongate-proxy push --policy-id <ID> Push local file to cloud");
|
|
13522
|
+
log4("");
|
|
13523
|
+
log4(bold2("Flags:"));
|
|
13524
|
+
log4(" --policy-id, --id <ID> Cloud policy ID (required for push)");
|
|
13525
|
+
log4(" --file, -f <path> Local file path (default: policy.json)");
|
|
13526
|
+
log4(" --api-key <key> API key (or set SOLONGATE_API_KEY)");
|
|
13527
|
+
log4("");
|
|
13939
13528
|
process.exit(1);
|
|
13940
13529
|
}
|
|
13941
13530
|
} catch (err2) {
|
|
13942
|
-
|
|
13531
|
+
log4(red2(`ERROR: ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
13943
13532
|
process.exit(1);
|
|
13944
13533
|
}
|
|
13945
13534
|
}
|
|
13946
|
-
var
|
|
13535
|
+
var log4, dim2, bold2, green2, red2, yellow2, cyan2, magenta, API_URL;
|
|
13947
13536
|
var init_pull_push = __esm({
|
|
13948
13537
|
"src/pull-push.ts"() {
|
|
13949
13538
|
"use strict";
|
|
13950
13539
|
init_config();
|
|
13951
|
-
|
|
13540
|
+
log4 = (...args) => process.stderr.write(`${args.map(String).join(" ")}
|
|
13952
13541
|
`);
|
|
13953
13542
|
dim2 = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
13954
13543
|
bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
@@ -13964,7 +13553,7 @@ var init_pull_push = __esm({
|
|
|
13964
13553
|
|
|
13965
13554
|
// src/index.ts
|
|
13966
13555
|
init_config();
|
|
13967
|
-
import { readFileSync as
|
|
13556
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
13968
13557
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13969
13558
|
import { dirname as dirname4, join as join17 } from "path";
|
|
13970
13559
|
|
|
@@ -16390,7 +15979,7 @@ var Mutex = class {
|
|
|
16390
15979
|
this.locked = true;
|
|
16391
15980
|
return;
|
|
16392
15981
|
}
|
|
16393
|
-
return new Promise((
|
|
15982
|
+
return new Promise((resolve9, reject) => {
|
|
16394
15983
|
const timer = setTimeout(() => {
|
|
16395
15984
|
const idx = this.queue.indexOf(onReady);
|
|
16396
15985
|
if (idx !== -1) this.queue.splice(idx, 1);
|
|
@@ -16398,7 +15987,7 @@ var Mutex = class {
|
|
|
16398
15987
|
}, timeoutMs);
|
|
16399
15988
|
const onReady = () => {
|
|
16400
15989
|
clearTimeout(timer);
|
|
16401
|
-
|
|
15990
|
+
resolve9();
|
|
16402
15991
|
};
|
|
16403
15992
|
this.queue.push(onReady);
|
|
16404
15993
|
});
|
|
@@ -16989,7 +16578,7 @@ ${msg.content.text}`;
|
|
|
16989
16578
|
|
|
16990
16579
|
// src/index.ts
|
|
16991
16580
|
init_cli_utils();
|
|
16992
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["
|
|
16581
|
+
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["create", "inject", "pull", "push", "list", "ls", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
|
|
16993
16582
|
var CLI_INFO_ARGS = /* @__PURE__ */ new Set(["login", "help", "--help", "-h", "--version", "-v", "version"]);
|
|
16994
16583
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "") || CLI_INFO_ARGS.has(process.argv[2] ?? "");
|
|
16995
16584
|
if (!IS_HUMAN_CLI) {
|
|
@@ -17009,7 +16598,7 @@ if (!IS_HUMAN_CLI) {
|
|
|
17009
16598
|
var PKG_VERSION = (() => {
|
|
17010
16599
|
try {
|
|
17011
16600
|
const p = join17(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
17012
|
-
return JSON.parse(
|
|
16601
|
+
return JSON.parse(readFileSync14(p, "utf-8")).version || "unknown";
|
|
17013
16602
|
} catch {
|
|
17014
16603
|
return "unknown";
|
|
17015
16604
|
}
|
|
@@ -17029,41 +16618,73 @@ function printWelcome() {
|
|
|
17029
16618
|
console.log("");
|
|
17030
16619
|
}
|
|
17031
16620
|
function printHelp3() {
|
|
17032
|
-
const
|
|
17033
|
-
console.log(
|
|
17034
|
-
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
row("ratelimit", "view and manage rate limits");
|
|
17048
|
-
row("dlp", "view and manage DLP (secret) rules");
|
|
17049
|
-
row("alerts", "view and manage alerts");
|
|
17050
|
-
row("webhooks", "view and manage webhooks");
|
|
16621
|
+
const W = 46;
|
|
16622
|
+
const head = (t) => console.log(`
|
|
16623
|
+
${c.bold}${t}${c.reset}`);
|
|
16624
|
+
const cmd = (syntax, desc = "") => {
|
|
16625
|
+
if (!desc) {
|
|
16626
|
+
console.log(` ${c.cyan}${syntax}${c.reset}`);
|
|
16627
|
+
return;
|
|
16628
|
+
}
|
|
16629
|
+
if (syntax.length <= W) {
|
|
16630
|
+
console.log(` ${c.cyan}${syntax}${c.reset}${" ".repeat(W - syntax.length)}${c.dim}${desc}${c.reset}`);
|
|
16631
|
+
} else {
|
|
16632
|
+
console.log(` ${c.cyan}${syntax}${c.reset}`);
|
|
16633
|
+
console.log(` ${" ".repeat(W)}${c.dim}${desc}${c.reset}`);
|
|
16634
|
+
}
|
|
16635
|
+
};
|
|
17051
16636
|
console.log("");
|
|
17052
|
-
console.log(` ${c.bold}
|
|
17053
|
-
row("audit", "browse the audit log of tool-call decisions");
|
|
17054
|
-
row("stats", "usage statistics");
|
|
17055
|
-
row("watch", "live-tail tool calls as they happen");
|
|
17056
|
-
row("agents", "list agents and sessions");
|
|
16637
|
+
console.log(` ${c.bold}${c.blue4}SolonGate${c.reset} ${c.dim}secure gateway for your AI agents${c.reset} ${c.dim}v${PKG_VERSION}${c.reset}`);
|
|
17057
16638
|
console.log("");
|
|
17058
|
-
console.log(` ${c.
|
|
17059
|
-
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
16639
|
+
console.log(` ${c.dim}Usage:${c.reset} ${c.cyan}solongate${c.reset} ${c.dim}[command]${c.reset} ${c.dim}(no command opens the dataroom: all of this in a terminal UI)${c.reset}`);
|
|
16640
|
+
head("Setup & status");
|
|
16641
|
+
cmd("solongate", "open the dataroom UI (login, policies, audit, settings)");
|
|
16642
|
+
cmd("doctor [--json]", "health check: login, policy, guard, local logs");
|
|
16643
|
+
cmd("create", "scaffold a guarded MCP server in this folder");
|
|
16644
|
+
cmd("logs-server", "serve local audit logs to the dashboard");
|
|
16645
|
+
head("Policies");
|
|
16646
|
+
cmd("policy list", "list all policies");
|
|
16647
|
+
cmd("policy show <id> [--version N]", "show one policy (rules, mode)");
|
|
16648
|
+
cmd("policy rules <id>", "list a policy's rules");
|
|
16649
|
+
cmd("policy allow <id> --tool <p> [--command|--path|--url <val>]", "add an ALLOW rule");
|
|
16650
|
+
cmd("policy revoke <id> <ruleId>", "remove a rule");
|
|
16651
|
+
cmd("policy activate <id> | --clear", "pin / unpin the active policy");
|
|
16652
|
+
cmd("policy rollback <id> <version>", "roll back to a version");
|
|
16653
|
+
cmd("policy versions <id>", "version history");
|
|
16654
|
+
cmd("policy active", "show the resolved active policy");
|
|
16655
|
+
cmd("policy dry-run <id|file.json> [--mode denylist|whitelist]", "replay recent traffic against rules");
|
|
16656
|
+
head("Rate limits");
|
|
16657
|
+
cmd("ratelimit show", "current limits + change history");
|
|
16658
|
+
cmd("ratelimit set --minute N [--hour N] [--day N] [--mode off|detect|block]", "edit limits (unset fields kept)");
|
|
16659
|
+
cmd("ratelimit history", "recent limit changes");
|
|
16660
|
+
head("DLP (secrets)");
|
|
16661
|
+
cmd("dlp show", "current mode + enabled patterns");
|
|
16662
|
+
cmd("dlp mode <off|detect|block>", "set enforcement mode");
|
|
16663
|
+
cmd("dlp enable <pattern>", "enable a built-in pattern");
|
|
16664
|
+
cmd("dlp disable <pattern>", "disable a built-in pattern");
|
|
16665
|
+
cmd("dlp add-custom --name X --re <regex>", "add a custom pattern");
|
|
16666
|
+
cmd("dlp remove-custom <name>", "remove a custom pattern");
|
|
16667
|
+
head("Monitoring");
|
|
16668
|
+
cmd("audit [--filter ALLOW|DENY] [--tool <s>] [--signal dlp|ratelimit] [--limit N]", "browse the audit log");
|
|
16669
|
+
cmd("audit whitelist <logId> [--scope exact|tool]", "turn a denial into an ALLOW rule");
|
|
16670
|
+
cmd("audit block <logId> [--scope exact|tool]", "turn a call into a DENY rule");
|
|
16671
|
+
cmd("stats [timeseries|drift]", "traffic & security statistics");
|
|
16672
|
+
cmd("watch [--filter DENY] [--tool <s>]", "live-tail tool calls (Ctrl+C to stop)");
|
|
16673
|
+
cmd("agents [--all]", "live agent feed");
|
|
16674
|
+
cmd("agent <agent_id>", "one-agent detail");
|
|
16675
|
+
head("Alerts & webhooks");
|
|
16676
|
+
cmd("alerts list");
|
|
16677
|
+
cmd("alerts add --signal deny|dlp|ratelimit|any --threshold N --window S (--email <a> | --telegram <id> | --slack <url>)", "spike alert");
|
|
16678
|
+
cmd("alerts remove <id>");
|
|
16679
|
+
cmd("webhooks list");
|
|
16680
|
+
cmd("webhooks add --url <https://\u2026> [--events denials|allowed|all]", "event webhook");
|
|
16681
|
+
cmd("webhooks remove <id>");
|
|
16682
|
+
head("Policy sync");
|
|
16683
|
+
cmd("pull --policy-id <ID> [--file f]", "pull a cloud policy to a local file");
|
|
16684
|
+
cmd("push --policy-id <ID> [--file f]", "push a local policy file to the cloud");
|
|
17065
16685
|
console.log("");
|
|
17066
|
-
console.log(` ${c.dim}
|
|
16686
|
+
console.log(` ${c.dim}Add ${c.reset}${c.cyan}--json${c.reset}${c.dim} to most read commands for machine output.${c.reset}`);
|
|
16687
|
+
console.log(` ${c.dim}Details for a command: ${c.reset}${c.cyan}solongate <command> help${c.reset}${c.dim} \xB7 Dashboard: ${c.reset}${c.cyan}https://dashboard.solongate.com${c.reset}`);
|
|
17067
16688
|
console.log("");
|
|
17068
16689
|
}
|
|
17069
16690
|
async function main4() {
|
|
@@ -17101,7 +16722,7 @@ async function main4() {
|
|
|
17101
16722
|
await launchTui2();
|
|
17102
16723
|
return;
|
|
17103
16724
|
}
|
|
17104
|
-
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "
|
|
16725
|
+
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "alerts", "webhooks"]);
|
|
17105
16726
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
17106
16727
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
17107
16728
|
const code = await runCommand2(subcommand, process.argv.slice(3));
|
|
@@ -17114,11 +16735,6 @@ async function main4() {
|
|
|
17114
16735
|
console.log("");
|
|
17115
16736
|
return;
|
|
17116
16737
|
}
|
|
17117
|
-
if (subcommand === "shield") {
|
|
17118
|
-
const { runShield: runShield2 } = await Promise.resolve().then(() => (init_shield(), shield_exports));
|
|
17119
|
-
await runShield2();
|
|
17120
|
-
return;
|
|
17121
|
-
}
|
|
17122
16738
|
if (subcommand === "logs-server" || subcommand === "local-logs") {
|
|
17123
16739
|
const { runLogsServer: runLogsServer2 } = await Promise.resolve().then(() => (init_logs_server(), logs_server_exports));
|
|
17124
16740
|
await runLogsServer2();
|
|
@@ -17138,6 +16754,17 @@ async function main4() {
|
|
|
17138
16754
|
await Promise.resolve().then(() => (init_pull_push(), pull_push_exports));
|
|
17139
16755
|
return;
|
|
17140
16756
|
}
|
|
16757
|
+
const hasProxySeparator = process.argv.includes("--");
|
|
16758
|
+
const looksLikeProxyFlag = (subcommand ?? "").startsWith("-");
|
|
16759
|
+
if (subcommand && !hasProxySeparator && !looksLikeProxyFlag) {
|
|
16760
|
+
process.stdout.write(`
|
|
16761
|
+
Unknown command: ${subcommand}
|
|
16762
|
+
`);
|
|
16763
|
+
process.stdout.write(` Run \`solongate --help\` to see every command, or \`solongate\` for the dataroom.
|
|
16764
|
+
|
|
16765
|
+
`);
|
|
16766
|
+
process.exit(1);
|
|
16767
|
+
}
|
|
17141
16768
|
try {
|
|
17142
16769
|
const config = parseArgs(process.argv);
|
|
17143
16770
|
const proxy = new SolonGateProxy(config);
|