@solongate/proxy 0.78.0 → 0.79.0
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/api-client/index.d.ts +4 -0
- package/dist/api-client/keys.d.ts +17 -0
- package/dist/api-client/mcp.d.ts +10 -0
- package/dist/api-client/settings.d.ts +46 -0
- package/dist/commands/alerts.d.ts +1 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/index.js +417 -2
- package/dist/commands/keys.d.ts +1 -0
- package/dist/commands/mcp.d.ts +1 -0
- package/dist/commands/watch.d.ts +1 -0
- package/dist/commands/webhooks.d.ts +1 -0
- package/dist/index.js +563 -82
- package/dist/tui/index.js +55 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6867,9 +6867,15 @@ var init_policies = __esm({
|
|
|
6867
6867
|
var settings_exports = {};
|
|
6868
6868
|
__export(settings_exports, {
|
|
6869
6869
|
clearRateLimitHistory: () => clearRateLimitHistory,
|
|
6870
|
+
createAlert: () => createAlert,
|
|
6871
|
+
createWebhook: () => createWebhook,
|
|
6872
|
+
deleteAlert: () => deleteAlert,
|
|
6873
|
+
deleteWebhook: () => deleteWebhook,
|
|
6874
|
+
getAlerts: () => getAlerts,
|
|
6870
6875
|
getGuardStatus: () => getGuardStatus,
|
|
6871
6876
|
getRateLimitHistory: () => getRateLimitHistory,
|
|
6872
6877
|
getSecurityLayers: () => getSecurityLayers,
|
|
6878
|
+
getWebhooks: () => getWebhooks,
|
|
6873
6879
|
setSecurityLayers: () => setSecurityLayers
|
|
6874
6880
|
});
|
|
6875
6881
|
function getSecurityLayers() {
|
|
@@ -6887,6 +6893,24 @@ function clearRateLimitHistory() {
|
|
|
6887
6893
|
function getGuardStatus() {
|
|
6888
6894
|
return request("GET", "/settings/guard-status");
|
|
6889
6895
|
}
|
|
6896
|
+
function getAlerts() {
|
|
6897
|
+
return request("GET", "/settings/denial-alerts");
|
|
6898
|
+
}
|
|
6899
|
+
function createAlert(body) {
|
|
6900
|
+
return request("POST", "/settings/denial-alerts", { body });
|
|
6901
|
+
}
|
|
6902
|
+
function deleteAlert(id) {
|
|
6903
|
+
return request("DELETE", "/settings/denial-alerts", { query: { id } });
|
|
6904
|
+
}
|
|
6905
|
+
function getWebhooks() {
|
|
6906
|
+
return request("GET", "/settings/denial-webhook");
|
|
6907
|
+
}
|
|
6908
|
+
function createWebhook(body) {
|
|
6909
|
+
return request("POST", "/settings/denial-webhook", { body });
|
|
6910
|
+
}
|
|
6911
|
+
function deleteWebhook(id) {
|
|
6912
|
+
return request("DELETE", "/settings/denial-webhook", { query: { id } });
|
|
6913
|
+
}
|
|
6890
6914
|
var init_settings = __esm({
|
|
6891
6915
|
"src/api-client/settings.ts"() {
|
|
6892
6916
|
"use strict";
|
|
@@ -6971,6 +6995,44 @@ var init_agents = __esm({
|
|
|
6971
6995
|
}
|
|
6972
6996
|
});
|
|
6973
6997
|
|
|
6998
|
+
// src/api-client/keys.ts
|
|
6999
|
+
var keys_exports = {};
|
|
7000
|
+
__export(keys_exports, {
|
|
7001
|
+
create: () => create2,
|
|
7002
|
+
list: () => list3,
|
|
7003
|
+
revoke: () => revoke
|
|
7004
|
+
});
|
|
7005
|
+
function list3() {
|
|
7006
|
+
return request("GET", "/keys");
|
|
7007
|
+
}
|
|
7008
|
+
function create2(name, isLive = true) {
|
|
7009
|
+
return request("POST", "/keys", { body: { name, is_live: isLive } });
|
|
7010
|
+
}
|
|
7011
|
+
function revoke(id) {
|
|
7012
|
+
return request("DELETE", `/keys/${encodeURIComponent(id)}`);
|
|
7013
|
+
}
|
|
7014
|
+
var init_keys = __esm({
|
|
7015
|
+
"src/api-client/keys.ts"() {
|
|
7016
|
+
"use strict";
|
|
7017
|
+
init_client();
|
|
7018
|
+
}
|
|
7019
|
+
});
|
|
7020
|
+
|
|
7021
|
+
// src/api-client/mcp.ts
|
|
7022
|
+
var mcp_exports = {};
|
|
7023
|
+
__export(mcp_exports, {
|
|
7024
|
+
list: () => list4
|
|
7025
|
+
});
|
|
7026
|
+
function list4() {
|
|
7027
|
+
return request("GET", "/mcp-servers");
|
|
7028
|
+
}
|
|
7029
|
+
var init_mcp = __esm({
|
|
7030
|
+
"src/api-client/mcp.ts"() {
|
|
7031
|
+
"use strict";
|
|
7032
|
+
init_client();
|
|
7033
|
+
}
|
|
7034
|
+
});
|
|
7035
|
+
|
|
6974
7036
|
// src/api-client/index.ts
|
|
6975
7037
|
var api;
|
|
6976
7038
|
var init_api_client = __esm({
|
|
@@ -6983,7 +7045,9 @@ var init_api_client = __esm({
|
|
|
6983
7045
|
init_stats();
|
|
6984
7046
|
init_audit();
|
|
6985
7047
|
init_agents();
|
|
6986
|
-
|
|
7048
|
+
init_keys();
|
|
7049
|
+
init_mcp();
|
|
7050
|
+
api = { policies: policies_exports, settings: settings_exports, stats: stats_exports, audit: audit_exports, agents: agents_exports, keys: keys_exports, mcp: mcp_exports };
|
|
6987
7051
|
}
|
|
6988
7052
|
});
|
|
6989
7053
|
|
|
@@ -7870,8 +7934,8 @@ function ruleSummary(r) {
|
|
|
7870
7934
|
return bits.join(" ");
|
|
7871
7935
|
}
|
|
7872
7936
|
function PoliciesPanel({ focused }) {
|
|
7873
|
-
const
|
|
7874
|
-
const policies =
|
|
7937
|
+
const list6 = useLoader(() => api.policies.list());
|
|
7938
|
+
const policies = list6.data?.policies ?? [];
|
|
7875
7939
|
const [view, setView] = useState3("list");
|
|
7876
7940
|
const [pi, setPi] = useState3(0);
|
|
7877
7941
|
const [ri, setRi] = useState3(0);
|
|
@@ -7913,7 +7977,7 @@ function PoliciesPanel({ focused }) {
|
|
|
7913
7977
|
setRules(res.rules);
|
|
7914
7978
|
setDirty(false);
|
|
7915
7979
|
setStatus("\u2713 Saved v" + res._version);
|
|
7916
|
-
|
|
7980
|
+
list6.reload();
|
|
7917
7981
|
} catch (e) {
|
|
7918
7982
|
setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
|
|
7919
7983
|
}
|
|
@@ -7983,7 +8047,7 @@ function PoliciesPanel({ focused }) {
|
|
|
7983
8047
|
{ isActive: focused && !editing }
|
|
7984
8048
|
);
|
|
7985
8049
|
if (view === "list") {
|
|
7986
|
-
return /* @__PURE__ */ jsx3(DataView, { loading:
|
|
8050
|
+
return /* @__PURE__ */ jsx3(DataView, { loading: list6.loading && !list6.data, error: list6.error, empty: !!list6.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
7987
8051
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: focused ? "\u2191\u2193 select \xB7 enter open" : "press \u2192 to browse" }),
|
|
7988
8052
|
/* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: policies.map((p, i) => /* @__PURE__ */ jsxs3(Text3, { color: i === pi ? theme.accentBright : void 0, bold: i === pi, children: [
|
|
7989
8053
|
(i === pi ? "\u25B8 " : " ") + truncate2(p.name, 26).padEnd(27),
|
|
@@ -9334,6 +9398,16 @@ async function run5(argv) {
|
|
|
9334
9398
|
else err(green(` \u2713 Whitelisted (${res2.scope})`) + dim(` \u2192 ${res2.policy_id} v${res2.policy_version}`));
|
|
9335
9399
|
return 0;
|
|
9336
9400
|
}
|
|
9401
|
+
if (positionals[0] === "block") {
|
|
9402
|
+
const id = positionals[1];
|
|
9403
|
+
if (!id) return err(" Usage: audit block <logId> [--scope exact|tool]"), 1;
|
|
9404
|
+
const scope = flagStr(flags, "scope") ?? "exact";
|
|
9405
|
+
const res2 = await api.audit.block(id, scope);
|
|
9406
|
+
if (json) return printJson(res2), 0;
|
|
9407
|
+
if (res2.deduped) err(green(" \u2713 ") + dim("Equivalent DENY already present."));
|
|
9408
|
+
else err(green(` \u2713 Blocked (${res2.scope})`) + dim(` \u2192 ${res2.policy_id} v${res2.policy_version}`));
|
|
9409
|
+
return 0;
|
|
9410
|
+
}
|
|
9337
9411
|
const query = {
|
|
9338
9412
|
filter: flagStr(flags, "filter"),
|
|
9339
9413
|
tool: flagStr(flags, "tool"),
|
|
@@ -9441,6 +9515,395 @@ var init_agents2 = __esm({
|
|
|
9441
9515
|
}
|
|
9442
9516
|
});
|
|
9443
9517
|
|
|
9518
|
+
// src/commands/doctor.ts
|
|
9519
|
+
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
9520
|
+
import { homedir as homedir4 } from "os";
|
|
9521
|
+
import { join as join6 } from "path";
|
|
9522
|
+
async function run6(argv) {
|
|
9523
|
+
const { flags } = parse(argv);
|
|
9524
|
+
const json = flagBool(flags, "json");
|
|
9525
|
+
const checks = [];
|
|
9526
|
+
if (!isAuthenticated()) {
|
|
9527
|
+
checks.push({ name: "login", ok: false, detail: "not logged in \u2014 run `solongate login`" });
|
|
9528
|
+
} else {
|
|
9529
|
+
const { apiUrl } = resolveCredentials();
|
|
9530
|
+
checks.push({ name: "login", ok: true, detail: `paired \xB7 ${apiUrl}` });
|
|
9531
|
+
try {
|
|
9532
|
+
const active2 = await api.policies.active();
|
|
9533
|
+
if (active2.policy) {
|
|
9534
|
+
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}` });
|
|
9535
|
+
} else {
|
|
9536
|
+
checks.push({ name: "active policy", ok: "warn", detail: "no policy resolves \u2014 every call falls back to default" });
|
|
9537
|
+
}
|
|
9538
|
+
const sec = active2.security;
|
|
9539
|
+
checks.push({ name: "rate limit", ok: sec?.rateLimit ? true : "warn", detail: sec?.rateLimit ? `${sec.rateLimit.perMinute}/min` : "off" });
|
|
9540
|
+
checks.push({ name: "dlp", ok: sec?.dlpBlock ? true : "warn", detail: sec?.dlpBlock ? `block \xB7 ${sec.dlpBlock.patterns.length} patterns` : sec?.dlpRedact ? "redact" : "off" });
|
|
9541
|
+
checks.push({ name: "self-protection", ok: active2.self_protection_enabled ? true : "warn", detail: active2.self_protection_enabled ? "on" : "off" });
|
|
9542
|
+
} catch (e) {
|
|
9543
|
+
checks.push({ name: "api", ok: false, detail: "unreachable: " + (e instanceof Error ? e.message : String(e)) });
|
|
9544
|
+
}
|
|
9545
|
+
try {
|
|
9546
|
+
const g = await api.settings.getGuardStatus();
|
|
9547
|
+
checks.push({ name: "guard hook", ok: g.up_to_date ? true : "warn", detail: g.up_to_date ? `v${g.installed} (latest) \xB7 ${g.device_count} device(s)` : `v${g.installed} \u2192 v${g.latest} available \xB7 run \`solongate login\`` });
|
|
9548
|
+
} catch {
|
|
9549
|
+
}
|
|
9550
|
+
}
|
|
9551
|
+
if (existsSync4(LOCAL_LOG2)) {
|
|
9552
|
+
const st = statSync2(LOCAL_LOG2);
|
|
9553
|
+
const ageMin = (Date.now() - st.mtimeMs) / 6e4;
|
|
9554
|
+
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"}` });
|
|
9555
|
+
} else {
|
|
9556
|
+
checks.push({ name: "local logs", ok: "warn", detail: "off (logs go to cloud) \u2014 enable in dashboard \u2192 Settings" });
|
|
9557
|
+
}
|
|
9558
|
+
if (json) return printJson(checks), checks.some((c2) => c2.ok === false) ? 1 : 0;
|
|
9559
|
+
err("");
|
|
9560
|
+
err(` ${bold("SolonGate doctor")}`);
|
|
9561
|
+
err("");
|
|
9562
|
+
for (const c2 of checks) {
|
|
9563
|
+
const mark = c2.ok === true ? green("\u2713") : c2.ok === "warn" ? yellow("!") : red("\u2717");
|
|
9564
|
+
err(` ${mark} ${c2.name.padEnd(16)} ${dim(c2.detail)}`);
|
|
9565
|
+
}
|
|
9566
|
+
err("");
|
|
9567
|
+
const bad = checks.filter((c2) => c2.ok === false).length;
|
|
9568
|
+
const warn = checks.filter((c2) => c2.ok === "warn").length;
|
|
9569
|
+
if (bad) err(` ${red(`${bad} problem(s)`)}${warn ? dim(` \xB7 ${warn} warning(s)`) : ""}`);
|
|
9570
|
+
else if (warn) err(` ${yellow(`${warn} warning(s)`)} ${dim("\u2014 guard is working")}`);
|
|
9571
|
+
else err(` ${green("all good")}`);
|
|
9572
|
+
return bad ? 1 : 0;
|
|
9573
|
+
}
|
|
9574
|
+
var LOCAL_LOG2;
|
|
9575
|
+
var init_doctor = __esm({
|
|
9576
|
+
"src/commands/doctor.ts"() {
|
|
9577
|
+
"use strict";
|
|
9578
|
+
init_api_client();
|
|
9579
|
+
init_format();
|
|
9580
|
+
init_args();
|
|
9581
|
+
LOCAL_LOG2 = join6(homedir4(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
9582
|
+
}
|
|
9583
|
+
});
|
|
9584
|
+
|
|
9585
|
+
// src/commands/watch.ts
|
|
9586
|
+
import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
9587
|
+
import { homedir as homedir5 } from "os";
|
|
9588
|
+
import { join as join7 } from "path";
|
|
9589
|
+
function tailLocal(file, maxBytes = 131072) {
|
|
9590
|
+
try {
|
|
9591
|
+
const size = statSync3(file).size;
|
|
9592
|
+
const start = Math.max(0, size - maxBytes);
|
|
9593
|
+
const fd = openSync2(file, "r");
|
|
9594
|
+
const buf = Buffer.alloc(size - start);
|
|
9595
|
+
readSync2(fd, buf, 0, buf.length, start);
|
|
9596
|
+
closeSync2(fd);
|
|
9597
|
+
const lines = buf.toString("utf-8").split("\n").filter(Boolean);
|
|
9598
|
+
if (start > 0) lines.shift();
|
|
9599
|
+
return lines;
|
|
9600
|
+
} catch {
|
|
9601
|
+
return [];
|
|
9602
|
+
}
|
|
9603
|
+
}
|
|
9604
|
+
function print(r, json) {
|
|
9605
|
+
if (json) return out(JSON.stringify(r));
|
|
9606
|
+
const dec = r.decision === "ALLOW" ? c.green : c.red;
|
|
9607
|
+
const src = r.source === "local" ? c.green + "LOC" : c.blue4 + "CLD";
|
|
9608
|
+
out(
|
|
9609
|
+
`${c.dim}[${time(r.at)}]${c.reset} ${src}${c.reset} ${dec}${r.decision.padEnd(6)}${c.reset} ${c.cyan}${trunc(r.tool, 12).padEnd(13)}${c.reset}${c.dim}${r.permission.slice(0, 4).padEnd(5)}${c.reset}${r.dlp ? c.red + "DLP! " + c.reset : ""}${c.dim}${trunc(r.agent || "-", 12).padEnd(13)}${r.detail}${c.reset}`
|
|
9610
|
+
);
|
|
9611
|
+
}
|
|
9612
|
+
async function run7(argv) {
|
|
9613
|
+
const { flags } = parse(argv);
|
|
9614
|
+
const json = flagBool(flags, "json");
|
|
9615
|
+
const decisionFilter = (flagStr(flags, "filter") || "").toUpperCase();
|
|
9616
|
+
const toolFilter = (flagStr(flags, "tool") || "").toLowerCase();
|
|
9617
|
+
const localOnly = flagBool(flags, "local-only");
|
|
9618
|
+
const cloudOnly = flagBool(flags, "cloud-only");
|
|
9619
|
+
const keep = (r) => {
|
|
9620
|
+
if (decisionFilter && r.decision.toUpperCase() !== decisionFilter && !(decisionFilter === "DENY" && r.decision === "DENIED")) return false;
|
|
9621
|
+
if (toolFilter && !r.tool.toLowerCase().includes(toolFilter)) return false;
|
|
9622
|
+
return true;
|
|
9623
|
+
};
|
|
9624
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9625
|
+
let lastLocalTs = 0;
|
|
9626
|
+
let first = true;
|
|
9627
|
+
const emit = (rows) => {
|
|
9628
|
+
rows.sort((a, b) => a.at - b.at);
|
|
9629
|
+
for (const r of rows) if (keep(r)) print(r, json);
|
|
9630
|
+
};
|
|
9631
|
+
const pollLocal = () => {
|
|
9632
|
+
if (cloudOnly || !existsSync5(LOCAL_LOG3)) return;
|
|
9633
|
+
const rows = [];
|
|
9634
|
+
for (const line of tailLocal(LOCAL_LOG3)) {
|
|
9635
|
+
try {
|
|
9636
|
+
const j = JSON.parse(line);
|
|
9637
|
+
const at = Date.parse(String(j.ts ?? ""));
|
|
9638
|
+
if (!Number.isFinite(at) || at <= lastLocalTs) continue;
|
|
9639
|
+
rows.push({
|
|
9640
|
+
at,
|
|
9641
|
+
tool: String(j.tool ?? "?"),
|
|
9642
|
+
decision: String(j.decision ?? "ALLOW"),
|
|
9643
|
+
permission: String(j.permission ?? ""),
|
|
9644
|
+
detail: (j.arguments ? JSON.stringify(j.arguments) : String(j.reason ?? "")).replace(/\s+/g, " "),
|
|
9645
|
+
agent: String(j.agent_name ?? ""),
|
|
9646
|
+
source: "local",
|
|
9647
|
+
dlp: !!j.dlp
|
|
9648
|
+
});
|
|
9649
|
+
} catch {
|
|
9650
|
+
}
|
|
9651
|
+
}
|
|
9652
|
+
if (rows.length) lastLocalTs = rows[rows.length - 1].at;
|
|
9653
|
+
if (!first) emit(rows);
|
|
9654
|
+
};
|
|
9655
|
+
const pollCloud = async () => {
|
|
9656
|
+
if (localOnly) return;
|
|
9657
|
+
try {
|
|
9658
|
+
const res = await api.audit.list({ limit: 50 });
|
|
9659
|
+
const rows = [];
|
|
9660
|
+
for (const e of res.entries) {
|
|
9661
|
+
if (seen.has(e.id)) continue;
|
|
9662
|
+
seen.add(e.id);
|
|
9663
|
+
rows.push({
|
|
9664
|
+
at: Date.parse(e.created_at),
|
|
9665
|
+
tool: e.tool_name,
|
|
9666
|
+
decision: e.decision,
|
|
9667
|
+
permission: e.permission ?? "",
|
|
9668
|
+
detail: (e.arguments_summary ? JSON.stringify(e.arguments_summary) : e.reason ?? "").replace(/\s+/g, " "),
|
|
9669
|
+
agent: e.agent_name ?? "",
|
|
9670
|
+
source: "cloud",
|
|
9671
|
+
dlp: !!e.dlp_matches?.length
|
|
9672
|
+
});
|
|
9673
|
+
}
|
|
9674
|
+
if (!first) emit(rows);
|
|
9675
|
+
} catch {
|
|
9676
|
+
}
|
|
9677
|
+
};
|
|
9678
|
+
if (!json) err(` ${c.dim}watching guard stream \u2014 Ctrl+C to stop${c.reset}`);
|
|
9679
|
+
pollLocal();
|
|
9680
|
+
await pollCloud();
|
|
9681
|
+
first = false;
|
|
9682
|
+
return new Promise(() => {
|
|
9683
|
+
setInterval(pollLocal, 2e3);
|
|
9684
|
+
setInterval(() => void pollCloud(), 4e3);
|
|
9685
|
+
});
|
|
9686
|
+
}
|
|
9687
|
+
var LOCAL_LOG3, trunc, time;
|
|
9688
|
+
var init_watch = __esm({
|
|
9689
|
+
"src/commands/watch.ts"() {
|
|
9690
|
+
"use strict";
|
|
9691
|
+
init_api_client();
|
|
9692
|
+
init_cli_utils();
|
|
9693
|
+
init_args();
|
|
9694
|
+
init_format();
|
|
9695
|
+
LOCAL_LOG3 = join7(homedir5(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
9696
|
+
trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
9697
|
+
time = (ms) => new Date(ms).toTimeString().slice(0, 8);
|
|
9698
|
+
}
|
|
9699
|
+
});
|
|
9700
|
+
|
|
9701
|
+
// src/commands/keys.ts
|
|
9702
|
+
async function run8(argv) {
|
|
9703
|
+
const { positionals, flags } = parse(argv);
|
|
9704
|
+
const sub = positionals[0] ?? "list";
|
|
9705
|
+
const json = flagBool(flags, "json");
|
|
9706
|
+
switch (sub) {
|
|
9707
|
+
case "help":
|
|
9708
|
+
return err(USAGE6), 0;
|
|
9709
|
+
case "list": {
|
|
9710
|
+
const { keys } = await api.keys.list();
|
|
9711
|
+
if (json) return printJson(keys), 0;
|
|
9712
|
+
if (!keys.length) return err(dim(" No API keys.")), 0;
|
|
9713
|
+
table(
|
|
9714
|
+
["ID", "NAME", "PREFIX", "CREATED"],
|
|
9715
|
+
keys.map((k) => [dim(truncate3(k.id, 10)), truncate3(k.name, 24), cyan(k.key_prefix), dim(k.created_at)])
|
|
9716
|
+
);
|
|
9717
|
+
return 0;
|
|
9718
|
+
}
|
|
9719
|
+
case "create": {
|
|
9720
|
+
const name = flagStr(flags, "name");
|
|
9721
|
+
if (!name) return err(" Usage: keys create --name <name>"), 1;
|
|
9722
|
+
const res = await api.keys.create(name, !flagBool(flags, "test"));
|
|
9723
|
+
if (json) return printJson(res), 0;
|
|
9724
|
+
err(green(` \u2713 Created "${res.name}"`));
|
|
9725
|
+
err("");
|
|
9726
|
+
err(" " + bold(res.key));
|
|
9727
|
+
err(dim(" \u2191 shown only once \u2014 copy it now."));
|
|
9728
|
+
return 0;
|
|
9729
|
+
}
|
|
9730
|
+
case "revoke": {
|
|
9731
|
+
const id = positionals[1];
|
|
9732
|
+
if (!id) return err(" Usage: keys revoke <id>"), 1;
|
|
9733
|
+
await api.keys.revoke(id);
|
|
9734
|
+
if (json) return printJson({ ok: true, id }), 0;
|
|
9735
|
+
return err(green(` \u2713 Revoked ${id}`)), 0;
|
|
9736
|
+
}
|
|
9737
|
+
default:
|
|
9738
|
+
return err(USAGE6), 1;
|
|
9739
|
+
}
|
|
9740
|
+
}
|
|
9741
|
+
var USAGE6;
|
|
9742
|
+
var init_keys2 = __esm({
|
|
9743
|
+
"src/commands/keys.ts"() {
|
|
9744
|
+
"use strict";
|
|
9745
|
+
init_api_client();
|
|
9746
|
+
init_args();
|
|
9747
|
+
init_format();
|
|
9748
|
+
USAGE6 = `${bold("solongate keys")} \u2014 API keys
|
|
9749
|
+
|
|
9750
|
+
keys list List keys (prefix only)
|
|
9751
|
+
keys create --name <n> Create a key (secret shown once)
|
|
9752
|
+
keys revoke <id> Revoke a key
|
|
9753
|
+
|
|
9754
|
+
Add --json for machine-readable output.`;
|
|
9755
|
+
}
|
|
9756
|
+
});
|
|
9757
|
+
|
|
9758
|
+
// src/commands/mcp.ts
|
|
9759
|
+
async function run9(argv) {
|
|
9760
|
+
const { flags } = parse(argv);
|
|
9761
|
+
const json = flagBool(flags, "json");
|
|
9762
|
+
const { servers } = await api.mcp.list();
|
|
9763
|
+
if (json) return printJson(servers), 0;
|
|
9764
|
+
if (!servers.length) return err(dim(" No MCP servers registered.")), 0;
|
|
9765
|
+
table(
|
|
9766
|
+
["STATUS", "NAME", "TARGET"],
|
|
9767
|
+
servers.map((s) => [
|
|
9768
|
+
s.status === "active" ? green(s.status) : yellow(s.status),
|
|
9769
|
+
cyan(truncate3(s.name, 24)),
|
|
9770
|
+
dim(truncate3(s.url || s.command || "\u2014", 46))
|
|
9771
|
+
])
|
|
9772
|
+
);
|
|
9773
|
+
return 0;
|
|
9774
|
+
}
|
|
9775
|
+
var init_mcp2 = __esm({
|
|
9776
|
+
"src/commands/mcp.ts"() {
|
|
9777
|
+
"use strict";
|
|
9778
|
+
init_api_client();
|
|
9779
|
+
init_args();
|
|
9780
|
+
init_format();
|
|
9781
|
+
}
|
|
9782
|
+
});
|
|
9783
|
+
|
|
9784
|
+
// src/commands/alerts.ts
|
|
9785
|
+
async function run10(argv) {
|
|
9786
|
+
const { positionals, flags } = parse(argv);
|
|
9787
|
+
const sub = positionals[0] ?? "list";
|
|
9788
|
+
const json = flagBool(flags, "json");
|
|
9789
|
+
switch (sub) {
|
|
9790
|
+
case "help":
|
|
9791
|
+
return err(USAGE7), 0;
|
|
9792
|
+
case "list": {
|
|
9793
|
+
const { rules } = await api.settings.getAlerts();
|
|
9794
|
+
if (json) return printJson(rules), 0;
|
|
9795
|
+
if (!rules.length) return err(dim(" No alert rules.")), 0;
|
|
9796
|
+
table(
|
|
9797
|
+
["ID", "ON", "SIGNAL", "THRESH", "WINDOW", "CHANNELS"],
|
|
9798
|
+
rules.map((r) => [
|
|
9799
|
+
dim(truncate3(r.id, 10)),
|
|
9800
|
+
r.enabled ? green("\u25CF") : dim("\u25CB"),
|
|
9801
|
+
cyan(r.signal),
|
|
9802
|
+
`${r.threshold}`,
|
|
9803
|
+
`${r.windowSeconds}s`,
|
|
9804
|
+
dim([...r.emails ?? [], ...(r.telegram ?? []).map((t) => "tg:" + t), ...(r.slackUrls ?? []).map(() => "slack")].join(" ") || "\u2014")
|
|
9805
|
+
])
|
|
9806
|
+
);
|
|
9807
|
+
return 0;
|
|
9808
|
+
}
|
|
9809
|
+
case "add": {
|
|
9810
|
+
const email = flagStr(flags, "email");
|
|
9811
|
+
const telegram = flagStr(flags, "telegram");
|
|
9812
|
+
const slack = flagStr(flags, "slack");
|
|
9813
|
+
if (!email && !telegram && !slack) return err(" Need a channel: --email / --telegram / --slack"), 1;
|
|
9814
|
+
const res = await api.settings.createAlert({
|
|
9815
|
+
signal: flagStr(flags, "signal") ?? "deny",
|
|
9816
|
+
threshold: flagNum(flags, "threshold") ?? 5,
|
|
9817
|
+
windowSeconds: flagNum(flags, "window") ?? 300,
|
|
9818
|
+
emails: email ? [email] : void 0,
|
|
9819
|
+
telegram: telegram ? [telegram] : void 0,
|
|
9820
|
+
slackUrl: slack
|
|
9821
|
+
});
|
|
9822
|
+
if (json) return printJson(res.rule), 0;
|
|
9823
|
+
return err(green(` \u2713 Alert added (${res.rule.signal}, ${res.rule.threshold}/${res.rule.windowSeconds}s)`)), 0;
|
|
9824
|
+
}
|
|
9825
|
+
case "remove": {
|
|
9826
|
+
const id = positionals[1];
|
|
9827
|
+
if (!id) return err(" Usage: alerts remove <id>"), 1;
|
|
9828
|
+
await api.settings.deleteAlert(id);
|
|
9829
|
+
if (json) return printJson({ ok: true, id }), 0;
|
|
9830
|
+
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
9831
|
+
}
|
|
9832
|
+
default:
|
|
9833
|
+
return err(USAGE7), 1;
|
|
9834
|
+
}
|
|
9835
|
+
}
|
|
9836
|
+
var USAGE7;
|
|
9837
|
+
var init_alerts = __esm({
|
|
9838
|
+
"src/commands/alerts.ts"() {
|
|
9839
|
+
"use strict";
|
|
9840
|
+
init_api_client();
|
|
9841
|
+
init_args();
|
|
9842
|
+
init_format();
|
|
9843
|
+
USAGE7 = `${bold("solongate alerts")} \u2014 spike alerts (Telegram / email)
|
|
9844
|
+
|
|
9845
|
+
alerts list
|
|
9846
|
+
alerts add --signal deny|dlp|ratelimit|any --threshold N --window S
|
|
9847
|
+
(--email <a> | --telegram <chatId> | --slack <url>)
|
|
9848
|
+
alerts remove <id>
|
|
9849
|
+
|
|
9850
|
+
Add --json for machine-readable output.`;
|
|
9851
|
+
}
|
|
9852
|
+
});
|
|
9853
|
+
|
|
9854
|
+
// src/commands/webhooks.ts
|
|
9855
|
+
async function run11(argv) {
|
|
9856
|
+
const { positionals, flags } = parse(argv);
|
|
9857
|
+
const sub = positionals[0] ?? "list";
|
|
9858
|
+
const json = flagBool(flags, "json");
|
|
9859
|
+
switch (sub) {
|
|
9860
|
+
case "help":
|
|
9861
|
+
return err(USAGE8), 0;
|
|
9862
|
+
case "list": {
|
|
9863
|
+
const { webhooks } = await api.settings.getWebhooks();
|
|
9864
|
+
if (json) return printJson(webhooks), 0;
|
|
9865
|
+
if (!webhooks.length) return err(dim(" No webhooks.")), 0;
|
|
9866
|
+
table(
|
|
9867
|
+
["ID", "ON", "EVENTS", "URL"],
|
|
9868
|
+
webhooks.map((w) => [dim(truncate3(w.id, 10)), w.enabled ? green("\u25CF") : dim("\u25CB"), cyan(w.events), dim(truncate3(w.url, 46))])
|
|
9869
|
+
);
|
|
9870
|
+
return 0;
|
|
9871
|
+
}
|
|
9872
|
+
case "add": {
|
|
9873
|
+
const url = flagStr(flags, "url");
|
|
9874
|
+
if (!url) return err(" Usage: webhooks add --url <https://\u2026> [--events denials|allowed|all]"), 1;
|
|
9875
|
+
const res = await api.settings.createWebhook({ url, events: flagStr(flags, "events") ?? "denials" });
|
|
9876
|
+
if (json) return printJson(res.webhook), 0;
|
|
9877
|
+
return err(green(` \u2713 Webhook added (${res.webhook.events}) \u2192 ${res.webhook.url}`)), 0;
|
|
9878
|
+
}
|
|
9879
|
+
case "remove": {
|
|
9880
|
+
const id = positionals[1];
|
|
9881
|
+
if (!id) return err(" Usage: webhooks remove <id>"), 1;
|
|
9882
|
+
await api.settings.deleteWebhook(id);
|
|
9883
|
+
if (json) return printJson({ ok: true, id }), 0;
|
|
9884
|
+
return err(green(` \u2713 Removed ${id}`)), 0;
|
|
9885
|
+
}
|
|
9886
|
+
default:
|
|
9887
|
+
return err(USAGE8), 1;
|
|
9888
|
+
}
|
|
9889
|
+
}
|
|
9890
|
+
var USAGE8;
|
|
9891
|
+
var init_webhooks = __esm({
|
|
9892
|
+
"src/commands/webhooks.ts"() {
|
|
9893
|
+
"use strict";
|
|
9894
|
+
init_api_client();
|
|
9895
|
+
init_args();
|
|
9896
|
+
init_format();
|
|
9897
|
+
USAGE8 = `${bold("solongate webhooks")} \u2014 event webhooks
|
|
9898
|
+
|
|
9899
|
+
webhooks list
|
|
9900
|
+
webhooks add --url <https://\u2026> [--events denials|allowed|all]
|
|
9901
|
+
webhooks remove <id>
|
|
9902
|
+
|
|
9903
|
+
Add --json for machine-readable output.`;
|
|
9904
|
+
}
|
|
9905
|
+
});
|
|
9906
|
+
|
|
9444
9907
|
// src/commands/index.ts
|
|
9445
9908
|
var commands_exports = {};
|
|
9446
9909
|
__export(commands_exports, {
|
|
@@ -9463,6 +9926,18 @@ async function dispatch(command, argv) {
|
|
|
9463
9926
|
return runAgents(argv);
|
|
9464
9927
|
case "agent":
|
|
9465
9928
|
return runAgent(argv);
|
|
9929
|
+
case "doctor":
|
|
9930
|
+
return run6(argv);
|
|
9931
|
+
case "watch":
|
|
9932
|
+
return run7(argv);
|
|
9933
|
+
case "keys":
|
|
9934
|
+
return run8(argv);
|
|
9935
|
+
case "mcp":
|
|
9936
|
+
return run9(argv);
|
|
9937
|
+
case "alerts":
|
|
9938
|
+
return run10(argv);
|
|
9939
|
+
case "webhooks":
|
|
9940
|
+
return run11(argv);
|
|
9466
9941
|
default:
|
|
9467
9942
|
err(` Unknown command: ${command}`);
|
|
9468
9943
|
return 1;
|
|
@@ -9497,7 +9972,13 @@ var init_commands = __esm({
|
|
|
9497
9972
|
init_stats2();
|
|
9498
9973
|
init_audit2();
|
|
9499
9974
|
init_agents2();
|
|
9500
|
-
|
|
9975
|
+
init_doctor();
|
|
9976
|
+
init_watch();
|
|
9977
|
+
init_keys2();
|
|
9978
|
+
init_mcp2();
|
|
9979
|
+
init_alerts();
|
|
9980
|
+
init_webhooks();
|
|
9981
|
+
COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "keys", "mcp", "alerts", "webhooks"];
|
|
9501
9982
|
}
|
|
9502
9983
|
});
|
|
9503
9984
|
|
|
@@ -9513,14 +9994,14 @@ __export(global_install_exports, {
|
|
|
9513
9994
|
runGlobalRestore: () => runGlobalRestore,
|
|
9514
9995
|
unlockProtected: () => unlockProtected
|
|
9515
9996
|
});
|
|
9516
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as
|
|
9517
|
-
import { resolve as resolve4, join as
|
|
9518
|
-
import { homedir as
|
|
9997
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
9998
|
+
import { resolve as resolve4, join as join8, dirname } from "path";
|
|
9999
|
+
import { homedir as homedir6 } from "os";
|
|
9519
10000
|
import { fileURLToPath } from "url";
|
|
9520
10001
|
import { createInterface } from "readline";
|
|
9521
10002
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
9522
10003
|
function lockFile(file) {
|
|
9523
|
-
if (!
|
|
10004
|
+
if (!existsSync6(file)) return;
|
|
9524
10005
|
try {
|
|
9525
10006
|
if (process.platform === "win32") {
|
|
9526
10007
|
try {
|
|
@@ -9546,7 +10027,7 @@ function lockFile(file) {
|
|
|
9546
10027
|
}
|
|
9547
10028
|
}
|
|
9548
10029
|
function unlockFile(file) {
|
|
9549
|
-
if (!
|
|
10030
|
+
if (!existsSync6(file)) return;
|
|
9550
10031
|
try {
|
|
9551
10032
|
if (process.platform === "win32") {
|
|
9552
10033
|
try {
|
|
@@ -9578,10 +10059,10 @@ function unlockFile(file) {
|
|
|
9578
10059
|
function protectedTargets() {
|
|
9579
10060
|
const p = globalPaths();
|
|
9580
10061
|
return [
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
|
|
10062
|
+
join8(p.hooksDir, "guard.mjs"),
|
|
10063
|
+
join8(p.hooksDir, "audit.mjs"),
|
|
10064
|
+
join8(p.hooksDir, "stop.mjs"),
|
|
10065
|
+
join8(p.hooksDir, "shield.mjs"),
|
|
9585
10066
|
p.configPath,
|
|
9586
10067
|
p.settingsPath
|
|
9587
10068
|
];
|
|
@@ -9593,26 +10074,26 @@ function unlockProtected() {
|
|
|
9593
10074
|
for (const f of protectedTargets()) unlockFile(f);
|
|
9594
10075
|
}
|
|
9595
10076
|
function globalPaths() {
|
|
9596
|
-
const home =
|
|
9597
|
-
const sgDir =
|
|
9598
|
-
const hooksDir =
|
|
9599
|
-
const claudeDir =
|
|
10077
|
+
const home = homedir6();
|
|
10078
|
+
const sgDir = join8(home, ".solongate");
|
|
10079
|
+
const hooksDir = join8(sgDir, "hooks");
|
|
10080
|
+
const claudeDir = join8(home, ".claude");
|
|
9600
10081
|
return {
|
|
9601
10082
|
home,
|
|
9602
10083
|
sgDir,
|
|
9603
10084
|
hooksDir,
|
|
9604
10085
|
claudeDir,
|
|
9605
|
-
settingsPath:
|
|
9606
|
-
backupPath:
|
|
9607
|
-
configPath:
|
|
10086
|
+
settingsPath: join8(claudeDir, "settings.json"),
|
|
10087
|
+
backupPath: join8(claudeDir, "settings.solongate.bak"),
|
|
10088
|
+
configPath: join8(sgDir, "cloud-guard.json")
|
|
9608
10089
|
};
|
|
9609
10090
|
}
|
|
9610
10091
|
function readHook(filename) {
|
|
9611
|
-
return readFileSync6(
|
|
10092
|
+
return readFileSync6(join8(HOOKS_DIR, filename), "utf-8");
|
|
9612
10093
|
}
|
|
9613
10094
|
function readGuard() {
|
|
9614
|
-
const bundled =
|
|
9615
|
-
return
|
|
10095
|
+
const bundled = join8(HOOKS_DIR, "guard.bundled.mjs");
|
|
10096
|
+
return existsSync6(bundled) ? readFileSync6(bundled, "utf-8") : readHook("guard.mjs");
|
|
9616
10097
|
}
|
|
9617
10098
|
function ask(question) {
|
|
9618
10099
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -9625,10 +10106,10 @@ function runGlobalRestore() {
|
|
|
9625
10106
|
const p = globalPaths();
|
|
9626
10107
|
unlockProtected();
|
|
9627
10108
|
removeClaudeShim();
|
|
9628
|
-
if (
|
|
10109
|
+
if (existsSync6(p.backupPath)) {
|
|
9629
10110
|
writeFileSync3(p.settingsPath, readFileSync6(p.backupPath, "utf-8"));
|
|
9630
10111
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
9631
|
-
} else if (
|
|
10112
|
+
} else if (existsSync6(p.settingsPath)) {
|
|
9632
10113
|
try {
|
|
9633
10114
|
const s = JSON.parse(readFileSync6(p.settingsPath, "utf-8"));
|
|
9634
10115
|
delete s.hooks;
|
|
@@ -9666,11 +10147,11 @@ function shimTargets() {
|
|
|
9666
10147
|
return [];
|
|
9667
10148
|
}
|
|
9668
10149
|
}
|
|
9669
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) =>
|
|
10150
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join8(homedir6(), f)).filter((f) => existsSync6(f));
|
|
9670
10151
|
}
|
|
9671
10152
|
function writeShimBlock(file, block2) {
|
|
9672
10153
|
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
9673
|
-
let content =
|
|
10154
|
+
let content = existsSync6(file) ? readFileSync6(file, "utf-8") : "";
|
|
9674
10155
|
content = content.replace(re, "");
|
|
9675
10156
|
if (block2) {
|
|
9676
10157
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
@@ -9737,18 +10218,18 @@ async function runGlobalInstall(opts = {}) {
|
|
|
9737
10218
|
mkdirSync3(p.hooksDir, { recursive: true });
|
|
9738
10219
|
mkdirSync3(p.claudeDir, { recursive: true });
|
|
9739
10220
|
unlockProtected();
|
|
9740
|
-
writeFileSync3(
|
|
9741
|
-
writeFileSync3(
|
|
9742
|
-
writeFileSync3(
|
|
9743
|
-
writeFileSync3(
|
|
10221
|
+
writeFileSync3(join8(p.hooksDir, "guard.mjs"), readGuard());
|
|
10222
|
+
writeFileSync3(join8(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
10223
|
+
writeFileSync3(join8(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
10224
|
+
writeFileSync3(join8(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
9744
10225
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
9745
10226
|
removeClaudeShim();
|
|
9746
10227
|
writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
9747
10228
|
console.log(` Wrote ${p.configPath}`);
|
|
9748
10229
|
let existing = {};
|
|
9749
|
-
if (
|
|
10230
|
+
if (existsSync6(p.settingsPath)) {
|
|
9750
10231
|
const raw = readFileSync6(p.settingsPath, "utf-8");
|
|
9751
|
-
if (!
|
|
10232
|
+
if (!existsSync6(p.backupPath)) {
|
|
9752
10233
|
writeFileSync3(p.backupPath, raw);
|
|
9753
10234
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
9754
10235
|
}
|
|
@@ -9758,9 +10239,9 @@ async function runGlobalInstall(opts = {}) {
|
|
|
9758
10239
|
existing = {};
|
|
9759
10240
|
}
|
|
9760
10241
|
}
|
|
9761
|
-
const guardAbs =
|
|
9762
|
-
const auditAbs =
|
|
9763
|
-
const stopAbs =
|
|
10242
|
+
const guardAbs = join8(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
10243
|
+
const auditAbs = join8(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
10244
|
+
const stopAbs = join8(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
9764
10245
|
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
9765
10246
|
const merged = {
|
|
9766
10247
|
...existing,
|
|
@@ -9950,22 +10431,22 @@ import { createServer, request as httpRequest } from "http";
|
|
|
9950
10431
|
import { request as httpsRequest } from "https";
|
|
9951
10432
|
import { spawn as spawn3 } from "child_process";
|
|
9952
10433
|
import { URL as URL2 } from "url";
|
|
9953
|
-
import { readFileSync as readFileSync7, existsSync as
|
|
10434
|
+
import { readFileSync as readFileSync7, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
9954
10435
|
import { resolve as resolve5 } from "path";
|
|
9955
|
-
import { homedir as
|
|
10436
|
+
import { homedir as homedir7 } from "os";
|
|
9956
10437
|
function findCacheFile() {
|
|
9957
|
-
const dir = resolve5(
|
|
10438
|
+
const dir = resolve5(homedir7(), ".solongate");
|
|
9958
10439
|
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
9959
10440
|
if (envSel) {
|
|
9960
10441
|
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
9961
|
-
if (
|
|
10442
|
+
if (existsSync7(f)) return f;
|
|
9962
10443
|
}
|
|
9963
10444
|
let best = null, bestTs = -1;
|
|
9964
10445
|
try {
|
|
9965
10446
|
for (const name of readdirSync(dir)) {
|
|
9966
10447
|
if (name.startsWith(".policy-cache-") && name.endsWith(".json")) {
|
|
9967
10448
|
const full = resolve5(dir, name);
|
|
9968
|
-
const ts =
|
|
10449
|
+
const ts = statSync4(full).mtimeMs;
|
|
9969
10450
|
if (ts > bestTs) {
|
|
9970
10451
|
bestTs = ts;
|
|
9971
10452
|
best = full;
|
|
@@ -9979,7 +10460,7 @@ function findCacheFile() {
|
|
|
9979
10460
|
function loadCfg() {
|
|
9980
10461
|
try {
|
|
9981
10462
|
const f = findCacheFile();
|
|
9982
|
-
if (f &&
|
|
10463
|
+
if (f && existsSync7(f)) {
|
|
9983
10464
|
const c2 = JSON.parse(readFileSync7(f, "utf-8"));
|
|
9984
10465
|
const d = c2?.security?.dlpRedact;
|
|
9985
10466
|
const g = c2?.security?.ghost;
|
|
@@ -10256,9 +10737,9 @@ __export(logs_server_exports, {
|
|
|
10256
10737
|
runLogsServer: () => runLogsServer
|
|
10257
10738
|
});
|
|
10258
10739
|
import { createServer as createServer2 } from "http";
|
|
10259
|
-
import { readFileSync as readFileSync8, statSync as
|
|
10260
|
-
import { resolve as resolve6, join as
|
|
10261
|
-
import { homedir as
|
|
10740
|
+
import { readFileSync as readFileSync8, statSync as statSync5 } from "fs";
|
|
10741
|
+
import { resolve as resolve6, join as join9, isAbsolute } from "path";
|
|
10742
|
+
import { homedir as homedir8 } from "os";
|
|
10262
10743
|
import { readdirSync as readdirSync2 } from "fs";
|
|
10263
10744
|
function allowedOrigins() {
|
|
10264
10745
|
const base = [
|
|
@@ -10275,15 +10756,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
10275
10756
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
10276
10757
|
if (!dir) return null;
|
|
10277
10758
|
if (isAbsolute(dir)) return dir;
|
|
10278
|
-
return resolve6(
|
|
10759
|
+
return resolve6(homedir8(), ".solongate", "local-logs");
|
|
10279
10760
|
}
|
|
10280
10761
|
async function findLogDir() {
|
|
10281
|
-
const base = resolve6(
|
|
10762
|
+
const base = resolve6(homedir8(), ".solongate");
|
|
10282
10763
|
try {
|
|
10283
10764
|
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
10284
10765
|
for (const f of files) {
|
|
10285
10766
|
try {
|
|
10286
|
-
const c2 = JSON.parse(readFileSync8(
|
|
10767
|
+
const c2 = JSON.parse(readFileSync8(join9(base, f), "utf-8"));
|
|
10287
10768
|
const p = c2?.security?.localLogs?.path;
|
|
10288
10769
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
10289
10770
|
} catch {
|
|
@@ -10292,7 +10773,7 @@ async function findLogDir() {
|
|
|
10292
10773
|
} catch {
|
|
10293
10774
|
}
|
|
10294
10775
|
try {
|
|
10295
|
-
const cfgRaw = readFileSync8(
|
|
10776
|
+
const cfgRaw = readFileSync8(join9(base, "cloud-guard.json"), "utf-8");
|
|
10296
10777
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
10297
10778
|
if (apiKey) {
|
|
10298
10779
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -10321,9 +10802,9 @@ function setCors(req, res) {
|
|
|
10321
10802
|
}
|
|
10322
10803
|
function fileInfo(dir) {
|
|
10323
10804
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
10324
|
-
const file =
|
|
10805
|
+
const file = join9(dir, LOG_FILENAME);
|
|
10325
10806
|
try {
|
|
10326
|
-
const st =
|
|
10807
|
+
const st = statSync5(file);
|
|
10327
10808
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
10328
10809
|
} catch {
|
|
10329
10810
|
return { file, exists: false, size: 0, mtimeMs: 0 };
|
|
@@ -10434,7 +10915,7 @@ var init_logs_server = __esm({
|
|
|
10434
10915
|
|
|
10435
10916
|
// src/inject.ts
|
|
10436
10917
|
var inject_exports = {};
|
|
10437
|
-
import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, existsSync as
|
|
10918
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, existsSync as existsSync8, copyFileSync } from "fs";
|
|
10438
10919
|
import { resolve as resolve7 } from "path";
|
|
10439
10920
|
import { execSync } from "child_process";
|
|
10440
10921
|
function parseInjectArgs(argv) {
|
|
@@ -10492,7 +10973,7 @@ WHAT IT DOES
|
|
|
10492
10973
|
`);
|
|
10493
10974
|
}
|
|
10494
10975
|
function detectProject() {
|
|
10495
|
-
if (!
|
|
10976
|
+
if (!existsSync8(resolve7("package.json"))) return false;
|
|
10496
10977
|
try {
|
|
10497
10978
|
const pkg = JSON.parse(readFileSync9(resolve7("package.json"), "utf-8"));
|
|
10498
10979
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
@@ -10508,13 +10989,13 @@ function findTsEntryFile() {
|
|
|
10508
10989
|
const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
|
|
10509
10990
|
if (typeof binPath === "string") {
|
|
10510
10991
|
const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
10511
|
-
if (
|
|
10512
|
-
if (
|
|
10992
|
+
if (existsSync8(resolve7(srcPath))) return resolve7(srcPath);
|
|
10993
|
+
if (existsSync8(resolve7(binPath))) return resolve7(binPath);
|
|
10513
10994
|
}
|
|
10514
10995
|
}
|
|
10515
10996
|
if (pkg.main) {
|
|
10516
10997
|
const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
10517
|
-
if (
|
|
10998
|
+
if (existsSync8(resolve7(srcPath))) return resolve7(srcPath);
|
|
10518
10999
|
}
|
|
10519
11000
|
} catch {
|
|
10520
11001
|
}
|
|
@@ -10528,7 +11009,7 @@ function findTsEntryFile() {
|
|
|
10528
11009
|
];
|
|
10529
11010
|
for (const c2 of candidates) {
|
|
10530
11011
|
const full = resolve7(c2);
|
|
10531
|
-
if (
|
|
11012
|
+
if (existsSync8(full)) {
|
|
10532
11013
|
try {
|
|
10533
11014
|
const content = readFileSync9(full, "utf-8");
|
|
10534
11015
|
if (content.includes("McpServer") || content.includes("McpServer")) {
|
|
@@ -10539,13 +11020,13 @@ function findTsEntryFile() {
|
|
|
10539
11020
|
}
|
|
10540
11021
|
}
|
|
10541
11022
|
for (const c2 of candidates) {
|
|
10542
|
-
if (
|
|
11023
|
+
if (existsSync8(resolve7(c2))) return resolve7(c2);
|
|
10543
11024
|
}
|
|
10544
11025
|
return null;
|
|
10545
11026
|
}
|
|
10546
11027
|
function detectPackageManager() {
|
|
10547
|
-
if (
|
|
10548
|
-
if (
|
|
11028
|
+
if (existsSync8(resolve7("pnpm-lock.yaml"))) return "pnpm";
|
|
11029
|
+
if (existsSync8(resolve7("yarn.lock"))) return "yarn";
|
|
10549
11030
|
return "npm";
|
|
10550
11031
|
}
|
|
10551
11032
|
function installSdk() {
|
|
@@ -10688,7 +11169,7 @@ async function main2() {
|
|
|
10688
11169
|
}
|
|
10689
11170
|
log3(" Language: TypeScript");
|
|
10690
11171
|
const entryFile = opts.file ? resolve7(opts.file) : findTsEntryFile();
|
|
10691
|
-
if (!entryFile || !
|
|
11172
|
+
if (!entryFile || !existsSync8(entryFile)) {
|
|
10692
11173
|
log3(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
|
|
10693
11174
|
log3("");
|
|
10694
11175
|
log3(" Specify it manually: --file <path>");
|
|
@@ -10701,7 +11182,7 @@ async function main2() {
|
|
|
10701
11182
|
log3("");
|
|
10702
11183
|
const backupPath = entryFile + ".solongate-backup";
|
|
10703
11184
|
if (opts.restore) {
|
|
10704
|
-
if (!
|
|
11185
|
+
if (!existsSync8(backupPath)) {
|
|
10705
11186
|
log3(" No backup found. Nothing to restore.");
|
|
10706
11187
|
process.exit(1);
|
|
10707
11188
|
}
|
|
@@ -10737,7 +11218,7 @@ async function main2() {
|
|
|
10737
11218
|
log3(" To apply: npx @solongate/proxy inject");
|
|
10738
11219
|
process.exit(0);
|
|
10739
11220
|
}
|
|
10740
|
-
if (!
|
|
11221
|
+
if (!existsSync8(backupPath)) {
|
|
10741
11222
|
copyFileSync(entryFile, backupPath);
|
|
10742
11223
|
log3("");
|
|
10743
11224
|
log3(` Backup: ${backupPath}`);
|
|
@@ -10771,8 +11252,8 @@ var init_inject = __esm({
|
|
|
10771
11252
|
|
|
10772
11253
|
// src/create.ts
|
|
10773
11254
|
var create_exports = {};
|
|
10774
|
-
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as
|
|
10775
|
-
import { resolve as resolve8, join as
|
|
11255
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, existsSync as existsSync9 } from "fs";
|
|
11256
|
+
import { resolve as resolve8, join as join10 } from "path";
|
|
10776
11257
|
import { execSync as execSync2 } from "child_process";
|
|
10777
11258
|
function withSpinner(message, fn) {
|
|
10778
11259
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -10852,7 +11333,7 @@ EXAMPLES
|
|
|
10852
11333
|
}
|
|
10853
11334
|
function createProject(dir, name, _policy) {
|
|
10854
11335
|
writeFileSync5(
|
|
10855
|
-
|
|
11336
|
+
join10(dir, "package.json"),
|
|
10856
11337
|
JSON.stringify(
|
|
10857
11338
|
{
|
|
10858
11339
|
name,
|
|
@@ -10882,7 +11363,7 @@ function createProject(dir, name, _policy) {
|
|
|
10882
11363
|
) + "\n"
|
|
10883
11364
|
);
|
|
10884
11365
|
writeFileSync5(
|
|
10885
|
-
|
|
11366
|
+
join10(dir, "tsconfig.json"),
|
|
10886
11367
|
JSON.stringify(
|
|
10887
11368
|
{
|
|
10888
11369
|
compilerOptions: {
|
|
@@ -10902,9 +11383,9 @@ function createProject(dir, name, _policy) {
|
|
|
10902
11383
|
2
|
|
10903
11384
|
) + "\n"
|
|
10904
11385
|
);
|
|
10905
|
-
mkdirSync4(
|
|
11386
|
+
mkdirSync4(join10(dir, "src"), { recursive: true });
|
|
10906
11387
|
writeFileSync5(
|
|
10907
|
-
|
|
11388
|
+
join10(dir, "src", "index.ts"),
|
|
10908
11389
|
`#!/usr/bin/env node
|
|
10909
11390
|
|
|
10910
11391
|
console.log = (...args: unknown[]) => {
|
|
@@ -10946,7 +11427,7 @@ console.log('Press Ctrl+C to stop.');
|
|
|
10946
11427
|
`
|
|
10947
11428
|
);
|
|
10948
11429
|
writeFileSync5(
|
|
10949
|
-
|
|
11430
|
+
join10(dir, ".mcp.json"),
|
|
10950
11431
|
JSON.stringify(
|
|
10951
11432
|
{
|
|
10952
11433
|
mcpServers: {
|
|
@@ -10964,12 +11445,12 @@ console.log('Press Ctrl+C to stop.');
|
|
|
10964
11445
|
) + "\n"
|
|
10965
11446
|
);
|
|
10966
11447
|
writeFileSync5(
|
|
10967
|
-
|
|
11448
|
+
join10(dir, ".env"),
|
|
10968
11449
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
10969
11450
|
`
|
|
10970
11451
|
);
|
|
10971
11452
|
writeFileSync5(
|
|
10972
|
-
|
|
11453
|
+
join10(dir, ".gitignore"),
|
|
10973
11454
|
`node_modules/
|
|
10974
11455
|
dist/
|
|
10975
11456
|
*.solongate-backup
|
|
@@ -10983,7 +11464,7 @@ async function main3() {
|
|
|
10983
11464
|
const opts = parseCreateArgs(process.argv);
|
|
10984
11465
|
const dir = resolve8(opts.name);
|
|
10985
11466
|
printBanner("Create MCP Server");
|
|
10986
|
-
if (
|
|
11467
|
+
if (existsSync9(dir)) {
|
|
10987
11468
|
log3(` ${c.red}Error:${c.reset} Directory "${opts.name}" already exists.`);
|
|
10988
11469
|
process.exit(1);
|
|
10989
11470
|
}
|
|
@@ -11062,12 +11543,12 @@ var init_create = __esm({
|
|
|
11062
11543
|
|
|
11063
11544
|
// src/pull-push.ts
|
|
11064
11545
|
var pull_push_exports = {};
|
|
11065
|
-
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as
|
|
11546
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync10 } from "fs";
|
|
11066
11547
|
import { resolve as resolve9 } from "path";
|
|
11067
11548
|
function loadEnv() {
|
|
11068
11549
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
11069
11550
|
const envPath = resolve9(".env");
|
|
11070
|
-
if (!
|
|
11551
|
+
if (!existsSync10(envPath)) return;
|
|
11071
11552
|
try {
|
|
11072
11553
|
const content = readFileSync10(envPath, "utf-8");
|
|
11073
11554
|
for (const line of content.split("\n")) {
|
|
@@ -11134,7 +11615,7 @@ async function listPolicies(apiKey) {
|
|
|
11134
11615
|
const data = await res.json();
|
|
11135
11616
|
return data.policies ?? [];
|
|
11136
11617
|
}
|
|
11137
|
-
async function
|
|
11618
|
+
async function list5(apiKey, policyId) {
|
|
11138
11619
|
const policies = await listPolicies(apiKey);
|
|
11139
11620
|
if (policies.length === 0) {
|
|
11140
11621
|
log5(yellow2("No policies found. Create one in the dashboard first."));
|
|
@@ -11269,7 +11750,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
11269
11750
|
log5("");
|
|
11270
11751
|
}
|
|
11271
11752
|
async function push(apiKey, file, policyId) {
|
|
11272
|
-
if (!
|
|
11753
|
+
if (!existsSync10(file)) {
|
|
11273
11754
|
log5(red2(`ERROR: File not found: ${file}`));
|
|
11274
11755
|
process.exit(1);
|
|
11275
11756
|
}
|
|
@@ -11337,7 +11818,7 @@ async function main4() {
|
|
|
11337
11818
|
} else if (command === "push") {
|
|
11338
11819
|
await push(apiKey, file, policyId);
|
|
11339
11820
|
} else if (command === "list" || command === "ls") {
|
|
11340
|
-
await
|
|
11821
|
+
await list5(apiKey, policyId);
|
|
11341
11822
|
} else {
|
|
11342
11823
|
log5(red2(`Unknown command: ${command}`));
|
|
11343
11824
|
log5("");
|
|
@@ -14402,7 +14883,7 @@ ${msg.content.text}`;
|
|
|
14402
14883
|
|
|
14403
14884
|
// src/index.ts
|
|
14404
14885
|
init_cli_utils();
|
|
14405
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["login", "logout", "shield", "create", "inject", "pull", "push", "list", "ls", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "ui", "dashboard", "tui"]);
|
|
14886
|
+
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["login", "logout", "shield", "create", "inject", "pull", "push", "list", "ls", "logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "keys", "mcp", "alerts", "webhooks", "ui", "dashboard", "tui"]);
|
|
14406
14887
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "");
|
|
14407
14888
|
if (!IS_HUMAN_CLI) {
|
|
14408
14889
|
console.log = (...args) => {
|
|
@@ -14451,7 +14932,7 @@ async function main5() {
|
|
|
14451
14932
|
await launchTui2();
|
|
14452
14933
|
return;
|
|
14453
14934
|
}
|
|
14454
|
-
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent"]);
|
|
14935
|
+
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "agents", "agent", "doctor", "watch", "keys", "mcp", "alerts", "webhooks"]);
|
|
14455
14936
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
14456
14937
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
14457
14938
|
const code = await runCommand2(subcommand, process.argv.slice(3));
|