@solongate/proxy 0.81.27 → 0.81.28
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/index.js +111 -88
- package/dist/tui/index.js +42 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8877,6 +8877,9 @@ var init_Dlp = __esm({
|
|
|
8877
8877
|
// src/tui/panels/Audit.tsx
|
|
8878
8878
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
8879
8879
|
import TextInput4 from "ink-text-input";
|
|
8880
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
8881
|
+
import { homedir as homedir6 } from "os";
|
|
8882
|
+
import { join as join8 } from "path";
|
|
8880
8883
|
import { useState as useState6 } from "react";
|
|
8881
8884
|
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
8882
8885
|
function loadLocalRows() {
|
|
@@ -8941,26 +8944,25 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
8941
8944
|
usePoll(cloudQ.reloadQuiet, 6e3, active2 && source === "cloud" && view === "logs" && !editing && page === 0);
|
|
8942
8945
|
const localQ = useLoader(() => source === "local" ? Promise.resolve(loadLocalRows()) : Promise.resolve(null), [source]);
|
|
8943
8946
|
usePoll(localQ.reloadQuiet, 6e3, active2 && source === "local" && view === "logs" && !editing && page === 0);
|
|
8947
|
+
const q = search.trim().toLowerCase();
|
|
8948
|
+
const localFiltered = (localQ.data ?? []).filter((r) => {
|
|
8949
|
+
if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
|
|
8950
|
+
if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
|
|
8951
|
+
if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
|
|
8952
|
+
if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
|
|
8953
|
+
if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
|
|
8954
|
+
if (sessFilter && r.session !== sessFilter) return false;
|
|
8955
|
+
if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
|
|
8956
|
+
return true;
|
|
8957
|
+
});
|
|
8944
8958
|
let pageRows = [];
|
|
8945
8959
|
let total = 0;
|
|
8946
8960
|
if (source === "cloud") {
|
|
8947
8961
|
pageRows = (cloudQ.data?.entries ?? []).map(cloudRow).sort((a, b) => b.at - a.at);
|
|
8948
8962
|
total = cloudQ.data?.total ?? 0;
|
|
8949
8963
|
} else {
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
const filtered = all.filter((r) => {
|
|
8953
|
-
if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
|
|
8954
|
-
if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
|
|
8955
|
-
if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
|
|
8956
|
-
if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
|
|
8957
|
-
if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
|
|
8958
|
-
if (sessFilter && r.session !== sessFilter) return false;
|
|
8959
|
-
if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
|
|
8960
|
-
return true;
|
|
8961
|
-
});
|
|
8962
|
-
total = filtered.length;
|
|
8963
|
-
pageRows = filtered.slice(page * PAGE, page * PAGE + PAGE);
|
|
8964
|
+
total = localFiltered.length;
|
|
8965
|
+
pageRows = localFiltered.slice(page * PAGE, page * PAGE + PAGE);
|
|
8964
8966
|
}
|
|
8965
8967
|
const pages = Math.max(1, Math.ceil(total / PAGE));
|
|
8966
8968
|
const current = pageRows[Math.min(sel, Math.max(0, pageRows.length - 1))];
|
|
@@ -9027,6 +9029,23 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9027
9029
|
toTop();
|
|
9028
9030
|
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
9029
9031
|
};
|
|
9032
|
+
const doExport = (kind) => {
|
|
9033
|
+
setMsg({ text: "exporting\u2026", level: "ok" });
|
|
9034
|
+
const run12 = async () => {
|
|
9035
|
+
const dir = join8(homedir6(), ".solongate");
|
|
9036
|
+
const file = join8(dir, `audit-export-${source}.jsonl`);
|
|
9037
|
+
let rows2;
|
|
9038
|
+
if (kind === "page") rows2 = pageRows;
|
|
9039
|
+
else if (source === "cloud") {
|
|
9040
|
+
const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
|
|
9041
|
+
rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
|
|
9042
|
+
} else rows2 = localFiltered;
|
|
9043
|
+
mkdirSync4(dir, { recursive: true });
|
|
9044
|
+
writeFileSync5(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
|
|
9045
|
+
return { n: rows2.length, file };
|
|
9046
|
+
};
|
|
9047
|
+
run12().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" }));
|
|
9048
|
+
};
|
|
9030
9049
|
useInput5(
|
|
9031
9050
|
(input, key) => {
|
|
9032
9051
|
if (showHelp) {
|
|
@@ -9115,7 +9134,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9115
9134
|
if (!current) return;
|
|
9116
9135
|
if (confirm?.kind !== "one" || confirm.key !== current.id) {
|
|
9117
9136
|
setConfirm({ kind: "one", key: current.id });
|
|
9118
|
-
setMsg({ text: `delete ${current.decision} ${current.tool} (${ago(current.at)} ago)
|
|
9137
|
+
setMsg({ text: `x = delete ONLY the selected entry: ${current.decision} ${current.tool} (${ago(current.at)} ago) \u2014 press x again`, level: "bad" });
|
|
9119
9138
|
return;
|
|
9120
9139
|
}
|
|
9121
9140
|
setConfirm(null);
|
|
@@ -9123,12 +9142,14 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
9123
9142
|
} else if (input === "X") {
|
|
9124
9143
|
if (confirm?.kind !== "all") {
|
|
9125
9144
|
setConfirm({ kind: "all", key: "all" });
|
|
9126
|
-
setMsg({ text:
|
|
9145
|
+
setMsg({ text: `\u26A0 X = delete ALL ${source} logs \u2014 every one of the ${total} matched entries! press X again`, level: "bad" });
|
|
9127
9146
|
return;
|
|
9128
9147
|
}
|
|
9129
9148
|
setConfirm(null);
|
|
9130
9149
|
doDelete("all");
|
|
9131
|
-
} else if (input === "
|
|
9150
|
+
} else if (input === "e") doExport("page");
|
|
9151
|
+
else if (input === "E") doExport("all");
|
|
9152
|
+
else if (input === "t") setEditing("tool");
|
|
9132
9153
|
else if (input === "n") setEditing("agent");
|
|
9133
9154
|
else if (input === "/") setEditing("search");
|
|
9134
9155
|
else if (input === "c") {
|
|
@@ -9451,8 +9472,10 @@ var init_Audit = __esm({
|
|
|
9451
9472
|
["g", "signal filter: all \u2192 dlp \u2192 ratelimit"],
|
|
9452
9473
|
["t / n", "tool / agent filter (type, enter done)"],
|
|
9453
9474
|
["/", "free-text search"],
|
|
9454
|
-
["x", "delete the selected entry (press x twice)"],
|
|
9455
|
-
["X", "delete ALL logs of the
|
|
9475
|
+
["x", "delete ONLY the selected entry (press x twice)"],
|
|
9476
|
+
["X", "delete ALL matched logs of the source (press X twice)"],
|
|
9477
|
+
["e", "export this page \u2192 ~/.solongate/audit-export-<src>.jsonl"],
|
|
9478
|
+
["E", "export ALL matched rows (cloud: up to 10k)"],
|
|
9456
9479
|
["c", "clear every filter (incl. session)"]
|
|
9457
9480
|
]
|
|
9458
9481
|
],
|
|
@@ -10540,8 +10563,8 @@ var init_agents2 = __esm({
|
|
|
10540
10563
|
|
|
10541
10564
|
// src/commands/doctor.ts
|
|
10542
10565
|
import { existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
10543
|
-
import { homedir as
|
|
10544
|
-
import { join as
|
|
10566
|
+
import { homedir as homedir7 } from "os";
|
|
10567
|
+
import { join as join9 } from "path";
|
|
10545
10568
|
async function run6(argv) {
|
|
10546
10569
|
const { flags } = parse(argv);
|
|
10547
10570
|
const json = flagBool(flags, "json");
|
|
@@ -10601,14 +10624,14 @@ var init_doctor = __esm({
|
|
|
10601
10624
|
init_api_client();
|
|
10602
10625
|
init_format();
|
|
10603
10626
|
init_args();
|
|
10604
|
-
LOCAL_LOG2 =
|
|
10627
|
+
LOCAL_LOG2 = join9(homedir7(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10605
10628
|
}
|
|
10606
10629
|
});
|
|
10607
10630
|
|
|
10608
10631
|
// src/commands/watch.ts
|
|
10609
10632
|
import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readSync as readSync2, statSync as statSync3 } from "fs";
|
|
10610
|
-
import { homedir as
|
|
10611
|
-
import { join as
|
|
10633
|
+
import { homedir as homedir8 } from "os";
|
|
10634
|
+
import { join as join10 } from "path";
|
|
10612
10635
|
function tailLocal(file, maxBytes = 131072) {
|
|
10613
10636
|
try {
|
|
10614
10637
|
const size = statSync3(file).size;
|
|
@@ -10715,7 +10738,7 @@ var init_watch = __esm({
|
|
|
10715
10738
|
init_cli_utils();
|
|
10716
10739
|
init_args();
|
|
10717
10740
|
init_format();
|
|
10718
|
-
LOCAL_LOG3 =
|
|
10741
|
+
LOCAL_LOG3 = join10(homedir8(), ".solongate", "local-logs", "solongate-audit.jsonl");
|
|
10719
10742
|
trunc = (s, n) => s.length <= n ? s : s.slice(0, n - 1) + "\u2026";
|
|
10720
10743
|
time = (ms) => new Date(ms).toTimeString().slice(0, 8);
|
|
10721
10744
|
}
|
|
@@ -11017,9 +11040,9 @@ __export(global_install_exports, {
|
|
|
11017
11040
|
runGlobalRestore: () => runGlobalRestore,
|
|
11018
11041
|
unlockProtected: () => unlockProtected
|
|
11019
11042
|
});
|
|
11020
|
-
import { readFileSync as readFileSync8, writeFileSync as
|
|
11021
|
-
import { resolve as resolve4, join as
|
|
11022
|
-
import { homedir as
|
|
11043
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync6, mkdirSync as mkdirSync5 } from "fs";
|
|
11044
|
+
import { resolve as resolve4, join as join11, dirname } from "path";
|
|
11045
|
+
import { homedir as homedir9 } from "os";
|
|
11023
11046
|
import { fileURLToPath } from "url";
|
|
11024
11047
|
import { createInterface } from "readline";
|
|
11025
11048
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -11082,10 +11105,10 @@ function unlockFile(file) {
|
|
|
11082
11105
|
function protectedTargets() {
|
|
11083
11106
|
const p = globalPaths();
|
|
11084
11107
|
return [
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
|
|
11108
|
+
join11(p.hooksDir, "guard.mjs"),
|
|
11109
|
+
join11(p.hooksDir, "audit.mjs"),
|
|
11110
|
+
join11(p.hooksDir, "stop.mjs"),
|
|
11111
|
+
join11(p.hooksDir, "shield.mjs"),
|
|
11089
11112
|
p.configPath,
|
|
11090
11113
|
p.settingsPath
|
|
11091
11114
|
];
|
|
@@ -11097,25 +11120,25 @@ function unlockProtected() {
|
|
|
11097
11120
|
for (const f of protectedTargets()) unlockFile(f);
|
|
11098
11121
|
}
|
|
11099
11122
|
function globalPaths() {
|
|
11100
|
-
const home =
|
|
11101
|
-
const sgDir =
|
|
11102
|
-
const hooksDir =
|
|
11103
|
-
const claudeDir =
|
|
11123
|
+
const home = homedir9();
|
|
11124
|
+
const sgDir = join11(home, ".solongate");
|
|
11125
|
+
const hooksDir = join11(sgDir, "hooks");
|
|
11126
|
+
const claudeDir = join11(home, ".claude");
|
|
11104
11127
|
return {
|
|
11105
11128
|
home,
|
|
11106
11129
|
sgDir,
|
|
11107
11130
|
hooksDir,
|
|
11108
11131
|
claudeDir,
|
|
11109
|
-
settingsPath:
|
|
11110
|
-
backupPath:
|
|
11111
|
-
configPath:
|
|
11132
|
+
settingsPath: join11(claudeDir, "settings.json"),
|
|
11133
|
+
backupPath: join11(claudeDir, "settings.solongate.bak"),
|
|
11134
|
+
configPath: join11(sgDir, "cloud-guard.json")
|
|
11112
11135
|
};
|
|
11113
11136
|
}
|
|
11114
11137
|
function readHook(filename) {
|
|
11115
|
-
return readFileSync8(
|
|
11138
|
+
return readFileSync8(join11(HOOKS_DIR, filename), "utf-8");
|
|
11116
11139
|
}
|
|
11117
11140
|
function readGuard() {
|
|
11118
|
-
const bundled =
|
|
11141
|
+
const bundled = join11(HOOKS_DIR, "guard.bundled.mjs");
|
|
11119
11142
|
return existsSync6(bundled) ? readFileSync8(bundled, "utf-8") : readHook("guard.mjs");
|
|
11120
11143
|
}
|
|
11121
11144
|
function ask(question) {
|
|
@@ -11130,13 +11153,13 @@ function runGlobalRestore() {
|
|
|
11130
11153
|
unlockProtected();
|
|
11131
11154
|
removeClaudeShim();
|
|
11132
11155
|
if (existsSync6(p.backupPath)) {
|
|
11133
|
-
|
|
11156
|
+
writeFileSync6(p.settingsPath, readFileSync8(p.backupPath, "utf-8"));
|
|
11134
11157
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
11135
11158
|
} else if (existsSync6(p.settingsPath)) {
|
|
11136
11159
|
try {
|
|
11137
11160
|
const s = JSON.parse(readFileSync8(p.settingsPath, "utf-8"));
|
|
11138
11161
|
delete s.hooks;
|
|
11139
|
-
|
|
11162
|
+
writeFileSync6(p.settingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
11140
11163
|
console.log(` Removed SolonGate hooks from ${p.settingsPath}.`);
|
|
11141
11164
|
} catch {
|
|
11142
11165
|
}
|
|
@@ -11170,7 +11193,7 @@ function shimTargets() {
|
|
|
11170
11193
|
return [];
|
|
11171
11194
|
}
|
|
11172
11195
|
}
|
|
11173
|
-
return [".bashrc", ".zshrc", ".profile"].map((f) =>
|
|
11196
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join11(homedir9(), f)).filter((f) => existsSync6(f));
|
|
11174
11197
|
}
|
|
11175
11198
|
function writeShimBlock(file, block2) {
|
|
11176
11199
|
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
@@ -11180,8 +11203,8 @@ function writeShimBlock(file, block2) {
|
|
|
11180
11203
|
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
11181
11204
|
content += block2 + "\n";
|
|
11182
11205
|
}
|
|
11183
|
-
|
|
11184
|
-
|
|
11206
|
+
mkdirSync5(dirname(file), { recursive: true });
|
|
11207
|
+
writeFileSync6(file, content);
|
|
11185
11208
|
}
|
|
11186
11209
|
function installClaudeShim(shieldPath) {
|
|
11187
11210
|
const real = resolveRealClaude();
|
|
@@ -11232,22 +11255,22 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11232
11255
|
process.exit(1);
|
|
11233
11256
|
}
|
|
11234
11257
|
const apiUrl = opts.apiUrl || process.env["SOLONGATE_API_URL"] || "https://api.solongate.com";
|
|
11235
|
-
|
|
11236
|
-
|
|
11258
|
+
mkdirSync5(p.hooksDir, { recursive: true });
|
|
11259
|
+
mkdirSync5(p.claudeDir, { recursive: true });
|
|
11237
11260
|
unlockProtected();
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11261
|
+
writeFileSync6(join11(p.hooksDir, "guard.mjs"), readGuard());
|
|
11262
|
+
writeFileSync6(join11(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
11263
|
+
writeFileSync6(join11(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
11264
|
+
writeFileSync6(join11(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
11242
11265
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
11243
|
-
installClaudeShim(
|
|
11244
|
-
|
|
11266
|
+
installClaudeShim(join11(p.hooksDir, "shield.mjs"));
|
|
11267
|
+
writeFileSync6(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
11245
11268
|
console.log(` Wrote ${p.configPath}`);
|
|
11246
11269
|
let existing = {};
|
|
11247
11270
|
if (existsSync6(p.settingsPath)) {
|
|
11248
11271
|
const raw = readFileSync8(p.settingsPath, "utf-8");
|
|
11249
11272
|
if (!existsSync6(p.backupPath)) {
|
|
11250
|
-
|
|
11273
|
+
writeFileSync6(p.backupPath, raw);
|
|
11251
11274
|
console.log(` Backed up existing settings \u2192 ${p.backupPath}`);
|
|
11252
11275
|
}
|
|
11253
11276
|
try {
|
|
@@ -11256,9 +11279,9 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11256
11279
|
existing = {};
|
|
11257
11280
|
}
|
|
11258
11281
|
}
|
|
11259
|
-
const guardAbs =
|
|
11260
|
-
const auditAbs =
|
|
11261
|
-
const stopAbs =
|
|
11282
|
+
const guardAbs = join11(p.hooksDir, "guard.mjs").replace(/\\/g, "/");
|
|
11283
|
+
const auditAbs = join11(p.hooksDir, "audit.mjs").replace(/\\/g, "/");
|
|
11284
|
+
const stopAbs = join11(p.hooksDir, "stop.mjs").replace(/\\/g, "/");
|
|
11262
11285
|
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
11263
11286
|
const call = process.platform === "win32" ? "& " : "";
|
|
11264
11287
|
const hookCmd = (script) => `${call}"${nodeBin}" "${script}" claude-code "Claude Code"`;
|
|
@@ -11270,7 +11293,7 @@ async function runGlobalInstall(opts = {}) {
|
|
|
11270
11293
|
Stop: [{ matcher: "", hooks: [{ type: "command", command: hookCmd(stopAbs) }] }]
|
|
11271
11294
|
}
|
|
11272
11295
|
};
|
|
11273
|
-
|
|
11296
|
+
writeFileSync6(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
11274
11297
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
11275
11298
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
11276
11299
|
lockProtected();
|
|
@@ -11452,9 +11475,9 @@ import { spawn as spawn3 } from "child_process";
|
|
|
11452
11475
|
import { URL as URL2 } from "url";
|
|
11453
11476
|
import { readFileSync as readFileSync9, existsSync as existsSync7, readdirSync, statSync as statSync4 } from "fs";
|
|
11454
11477
|
import { resolve as resolve5 } from "path";
|
|
11455
|
-
import { homedir as
|
|
11478
|
+
import { homedir as homedir10 } from "os";
|
|
11456
11479
|
function findCacheFile() {
|
|
11457
|
-
const dir = resolve5(
|
|
11480
|
+
const dir = resolve5(homedir10(), ".solongate");
|
|
11458
11481
|
const envSel = process.env.SOLONGATE_AGENT_ID;
|
|
11459
11482
|
if (envSel) {
|
|
11460
11483
|
const f = resolve5(dir, ".policy-cache-" + envSel.replace(/[^a-zA-Z0-9_-]/g, "_") + ".json");
|
|
@@ -11769,8 +11792,8 @@ __export(logs_server_exports, {
|
|
|
11769
11792
|
});
|
|
11770
11793
|
import { createServer as createServer2 } from "http";
|
|
11771
11794
|
import { readFileSync as readFileSync10, statSync as statSync5 } from "fs";
|
|
11772
|
-
import { resolve as resolve6, join as
|
|
11773
|
-
import { homedir as
|
|
11795
|
+
import { resolve as resolve6, join as join12, isAbsolute } from "path";
|
|
11796
|
+
import { homedir as homedir11 } from "os";
|
|
11774
11797
|
import { readdirSync as readdirSync2 } from "fs";
|
|
11775
11798
|
function allowedOrigins() {
|
|
11776
11799
|
const base = [
|
|
@@ -11787,15 +11810,15 @@ function resolveLocalLogDir(rawPath) {
|
|
|
11787
11810
|
const dir = String(rawPath || "").trim().replace(/[\\/]+$/, "");
|
|
11788
11811
|
if (!dir) return null;
|
|
11789
11812
|
if (isAbsolute(dir)) return dir;
|
|
11790
|
-
return resolve6(
|
|
11813
|
+
return resolve6(homedir11(), ".solongate", "local-logs");
|
|
11791
11814
|
}
|
|
11792
11815
|
async function findLogDir() {
|
|
11793
|
-
const base = resolve6(
|
|
11816
|
+
const base = resolve6(homedir11(), ".solongate");
|
|
11794
11817
|
try {
|
|
11795
11818
|
const files = readdirSync2(base).filter((f) => f.startsWith(".policy-cache-") && f.endsWith(".json"));
|
|
11796
11819
|
for (const f of files) {
|
|
11797
11820
|
try {
|
|
11798
|
-
const c2 = JSON.parse(readFileSync10(
|
|
11821
|
+
const c2 = JSON.parse(readFileSync10(join12(base, f), "utf-8"));
|
|
11799
11822
|
const p = c2?.security?.localLogs?.path;
|
|
11800
11823
|
if (typeof p === "string" && p.trim()) return { dir: resolveLocalLogDir(p), configured: p };
|
|
11801
11824
|
} catch {
|
|
@@ -11804,7 +11827,7 @@ async function findLogDir() {
|
|
|
11804
11827
|
} catch {
|
|
11805
11828
|
}
|
|
11806
11829
|
try {
|
|
11807
|
-
const cfgRaw = readFileSync10(
|
|
11830
|
+
const cfgRaw = readFileSync10(join12(base, "cloud-guard.json"), "utf-8");
|
|
11808
11831
|
const { apiKey, apiUrl } = JSON.parse(cfgRaw);
|
|
11809
11832
|
if (apiKey) {
|
|
11810
11833
|
const url = `${apiUrl || "https://api.solongate.com"}/api/v1/policies/active`;
|
|
@@ -11833,7 +11856,7 @@ function setCors(req, res) {
|
|
|
11833
11856
|
}
|
|
11834
11857
|
function fileInfo(dir) {
|
|
11835
11858
|
if (!dir) return { file: null, exists: false, size: 0, mtimeMs: 0 };
|
|
11836
|
-
const file =
|
|
11859
|
+
const file = join12(dir, LOG_FILENAME);
|
|
11837
11860
|
try {
|
|
11838
11861
|
const st = statSync5(file);
|
|
11839
11862
|
return { file, exists: true, size: st.size, mtimeMs: st.mtimeMs };
|
|
@@ -11946,7 +11969,7 @@ var init_logs_server = __esm({
|
|
|
11946
11969
|
|
|
11947
11970
|
// src/inject.ts
|
|
11948
11971
|
var inject_exports = {};
|
|
11949
|
-
import { readFileSync as readFileSync11, writeFileSync as
|
|
11972
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, existsSync as existsSync8, copyFileSync } from "fs";
|
|
11950
11973
|
import { resolve as resolve7 } from "path";
|
|
11951
11974
|
import { execSync } from "child_process";
|
|
11952
11975
|
function parseInjectArgs(argv) {
|
|
@@ -12254,7 +12277,7 @@ async function main2() {
|
|
|
12254
12277
|
log3("");
|
|
12255
12278
|
log3(` Backup: ${backupPath}`);
|
|
12256
12279
|
}
|
|
12257
|
-
|
|
12280
|
+
writeFileSync7(entryFile, result.modified);
|
|
12258
12281
|
log3("");
|
|
12259
12282
|
log3(" \u250C\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\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
12260
12283
|
log3(" \u2502 SolonGate SDK injected successfully! \u2502");
|
|
@@ -12283,8 +12306,8 @@ var init_inject = __esm({
|
|
|
12283
12306
|
|
|
12284
12307
|
// src/create.ts
|
|
12285
12308
|
var create_exports = {};
|
|
12286
|
-
import { mkdirSync as
|
|
12287
|
-
import { resolve as resolve8, join as
|
|
12309
|
+
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync8, existsSync as existsSync9 } from "fs";
|
|
12310
|
+
import { resolve as resolve8, join as join13 } from "path";
|
|
12288
12311
|
import { execSync as execSync2 } from "child_process";
|
|
12289
12312
|
function withSpinner(message, fn) {
|
|
12290
12313
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -12363,8 +12386,8 @@ EXAMPLES
|
|
|
12363
12386
|
`);
|
|
12364
12387
|
}
|
|
12365
12388
|
function createProject(dir, name, _policy) {
|
|
12366
|
-
|
|
12367
|
-
|
|
12389
|
+
writeFileSync8(
|
|
12390
|
+
join13(dir, "package.json"),
|
|
12368
12391
|
JSON.stringify(
|
|
12369
12392
|
{
|
|
12370
12393
|
name,
|
|
@@ -12393,8 +12416,8 @@ function createProject(dir, name, _policy) {
|
|
|
12393
12416
|
2
|
|
12394
12417
|
) + "\n"
|
|
12395
12418
|
);
|
|
12396
|
-
|
|
12397
|
-
|
|
12419
|
+
writeFileSync8(
|
|
12420
|
+
join13(dir, "tsconfig.json"),
|
|
12398
12421
|
JSON.stringify(
|
|
12399
12422
|
{
|
|
12400
12423
|
compilerOptions: {
|
|
@@ -12414,9 +12437,9 @@ function createProject(dir, name, _policy) {
|
|
|
12414
12437
|
2
|
|
12415
12438
|
) + "\n"
|
|
12416
12439
|
);
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
12440
|
+
mkdirSync6(join13(dir, "src"), { recursive: true });
|
|
12441
|
+
writeFileSync8(
|
|
12442
|
+
join13(dir, "src", "index.ts"),
|
|
12420
12443
|
`#!/usr/bin/env node
|
|
12421
12444
|
|
|
12422
12445
|
console.log = (...args: unknown[]) => {
|
|
@@ -12457,8 +12480,8 @@ console.log('');
|
|
|
12457
12480
|
console.log('Press Ctrl+C to stop.');
|
|
12458
12481
|
`
|
|
12459
12482
|
);
|
|
12460
|
-
|
|
12461
|
-
|
|
12483
|
+
writeFileSync8(
|
|
12484
|
+
join13(dir, ".mcp.json"),
|
|
12462
12485
|
JSON.stringify(
|
|
12463
12486
|
{
|
|
12464
12487
|
mcpServers: {
|
|
@@ -12475,13 +12498,13 @@ console.log('Press Ctrl+C to stop.');
|
|
|
12475
12498
|
2
|
|
12476
12499
|
) + "\n"
|
|
12477
12500
|
);
|
|
12478
|
-
|
|
12479
|
-
|
|
12501
|
+
writeFileSync8(
|
|
12502
|
+
join13(dir, ".env"),
|
|
12480
12503
|
`SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
|
|
12481
12504
|
`
|
|
12482
12505
|
);
|
|
12483
|
-
|
|
12484
|
-
|
|
12506
|
+
writeFileSync8(
|
|
12507
|
+
join13(dir, ".gitignore"),
|
|
12485
12508
|
`node_modules/
|
|
12486
12509
|
dist/
|
|
12487
12510
|
*.solongate-backup
|
|
@@ -12500,7 +12523,7 @@ async function main3() {
|
|
|
12500
12523
|
process.exit(1);
|
|
12501
12524
|
}
|
|
12502
12525
|
withSpinner(`Setting up ${opts.name}...`, () => {
|
|
12503
|
-
|
|
12526
|
+
mkdirSync6(dir, { recursive: true });
|
|
12504
12527
|
createProject(dir, opts.name, opts.policy);
|
|
12505
12528
|
});
|
|
12506
12529
|
if (!opts.noInstall) {
|
|
@@ -12574,7 +12597,7 @@ var init_create = __esm({
|
|
|
12574
12597
|
|
|
12575
12598
|
// src/pull-push.ts
|
|
12576
12599
|
var pull_push_exports = {};
|
|
12577
|
-
import { readFileSync as readFileSync12, writeFileSync as
|
|
12600
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, existsSync as existsSync10 } from "fs";
|
|
12578
12601
|
import { resolve as resolve9 } from "path";
|
|
12579
12602
|
function loadEnv() {
|
|
12580
12603
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
@@ -12769,7 +12792,7 @@ async function pull(apiKey, file, policyId) {
|
|
|
12769
12792
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
12770
12793
|
const { id: _id, ...policyWithoutId } = policy;
|
|
12771
12794
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
12772
|
-
|
|
12795
|
+
writeFileSync9(file, json, "utf-8");
|
|
12773
12796
|
log5("");
|
|
12774
12797
|
log5(green2(" Saved to: ") + file);
|
|
12775
12798
|
log5(` ${dim2("Name:")} ${policy.name}`);
|
package/dist/tui/index.js
CHANGED
|
@@ -2214,6 +2214,9 @@ function RegexTest({ re }) {
|
|
|
2214
2214
|
// src/tui/panels/Audit.tsx
|
|
2215
2215
|
import { Box as Box6, Text as Text6, useInput as useInput5 } from "ink";
|
|
2216
2216
|
import TextInput4 from "ink-text-input";
|
|
2217
|
+
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2218
|
+
import { homedir as homedir5 } from "os";
|
|
2219
|
+
import { join as join5 } from "path";
|
|
2217
2220
|
import { useState as useState6 } from "react";
|
|
2218
2221
|
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2219
2222
|
var DECISIONS = [void 0, "DENY", "ALLOW"];
|
|
@@ -2266,8 +2269,10 @@ var AUDIT_HELP = [
|
|
|
2266
2269
|
["g", "signal filter: all \u2192 dlp \u2192 ratelimit"],
|
|
2267
2270
|
["t / n", "tool / agent filter (type, enter done)"],
|
|
2268
2271
|
["/", "free-text search"],
|
|
2269
|
-
["x", "delete the selected entry (press x twice)"],
|
|
2270
|
-
["X", "delete ALL logs of the
|
|
2272
|
+
["x", "delete ONLY the selected entry (press x twice)"],
|
|
2273
|
+
["X", "delete ALL matched logs of the source (press X twice)"],
|
|
2274
|
+
["e", "export this page \u2192 ~/.solongate/audit-export-<src>.jsonl"],
|
|
2275
|
+
["E", "export ALL matched rows (cloud: up to 10k)"],
|
|
2271
2276
|
["c", "clear every filter (incl. session)"]
|
|
2272
2277
|
]
|
|
2273
2278
|
],
|
|
@@ -2342,26 +2347,25 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2342
2347
|
usePoll(cloudQ.reloadQuiet, 6e3, active2 && source === "cloud" && view === "logs" && !editing && page === 0);
|
|
2343
2348
|
const localQ = useLoader(() => source === "local" ? Promise.resolve(loadLocalRows()) : Promise.resolve(null), [source]);
|
|
2344
2349
|
usePoll(localQ.reloadQuiet, 6e3, active2 && source === "local" && view === "logs" && !editing && page === 0);
|
|
2350
|
+
const q = search.trim().toLowerCase();
|
|
2351
|
+
const localFiltered = (localQ.data ?? []).filter((r) => {
|
|
2352
|
+
if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
|
|
2353
|
+
if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
|
|
2354
|
+
if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
|
|
2355
|
+
if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
|
|
2356
|
+
if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
|
|
2357
|
+
if (sessFilter && r.session !== sessFilter) return false;
|
|
2358
|
+
if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
|
|
2359
|
+
return true;
|
|
2360
|
+
});
|
|
2345
2361
|
let pageRows = [];
|
|
2346
2362
|
let total = 0;
|
|
2347
2363
|
if (source === "cloud") {
|
|
2348
2364
|
pageRows = (cloudQ.data?.entries ?? []).map(cloudRow).sort((a, b) => b.at - a.at);
|
|
2349
2365
|
total = cloudQ.data?.total ?? 0;
|
|
2350
2366
|
} else {
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
const filtered = all.filter((r) => {
|
|
2354
|
-
if (DECISIONS[di] && r.decision !== DECISIONS[di]) return false;
|
|
2355
|
-
if (SIGNALS[gi] === "dlp" && r.dlp.length === 0) return false;
|
|
2356
|
-
if (SIGNALS[gi] === "ratelimit" && !r.burst) return false;
|
|
2357
|
-
if (tool && !r.tool.toLowerCase().includes(tool.toLowerCase())) return false;
|
|
2358
|
-
if (agent && (r.agent ?? "").toLowerCase() !== agent.toLowerCase()) return false;
|
|
2359
|
-
if (sessFilter && r.session !== sessFilter) return false;
|
|
2360
|
-
if (q && !`${r.tool} ${r.agent ?? ""} ${r.reason ?? ""} ${r.args ?? ""}`.toLowerCase().includes(q)) return false;
|
|
2361
|
-
return true;
|
|
2362
|
-
});
|
|
2363
|
-
total = filtered.length;
|
|
2364
|
-
pageRows = filtered.slice(page * PAGE, page * PAGE + PAGE);
|
|
2367
|
+
total = localFiltered.length;
|
|
2368
|
+
pageRows = localFiltered.slice(page * PAGE, page * PAGE + PAGE);
|
|
2365
2369
|
}
|
|
2366
2370
|
const pages = Math.max(1, Math.ceil(total / PAGE));
|
|
2367
2371
|
const current = pageRows[Math.min(sel, Math.max(0, pageRows.length - 1))];
|
|
@@ -2428,6 +2432,23 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2428
2432
|
toTop();
|
|
2429
2433
|
}).catch((e) => setMsg({ text: "\u2717 " + (e instanceof Error ? e.message : String(e)), level: "bad" }));
|
|
2430
2434
|
};
|
|
2435
|
+
const doExport = (kind) => {
|
|
2436
|
+
setMsg({ text: "exporting\u2026", level: "ok" });
|
|
2437
|
+
const run = async () => {
|
|
2438
|
+
const dir = join5(homedir5(), ".solongate");
|
|
2439
|
+
const file = join5(dir, `audit-export-${source}.jsonl`);
|
|
2440
|
+
let rows2;
|
|
2441
|
+
if (kind === "page") rows2 = pageRows;
|
|
2442
|
+
else if (source === "cloud") {
|
|
2443
|
+
const r = await api.audit.list({ ...query, limit: 1e4, offset: 0 });
|
|
2444
|
+
rows2 = r.entries.map(cloudRow).sort((a, b) => b.at - a.at);
|
|
2445
|
+
} else rows2 = localFiltered;
|
|
2446
|
+
mkdirSync2(dir, { recursive: true });
|
|
2447
|
+
writeFileSync3(file, rows2.map((x) => JSON.stringify(x)).join("\n") + (rows2.length ? "\n" : ""));
|
|
2448
|
+
return { n: rows2.length, file };
|
|
2449
|
+
};
|
|
2450
|
+
run().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" }));
|
|
2451
|
+
};
|
|
2431
2452
|
useInput5(
|
|
2432
2453
|
(input, key) => {
|
|
2433
2454
|
if (showHelp) {
|
|
@@ -2516,7 +2537,7 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2516
2537
|
if (!current) return;
|
|
2517
2538
|
if (confirm?.kind !== "one" || confirm.key !== current.id) {
|
|
2518
2539
|
setConfirm({ kind: "one", key: current.id });
|
|
2519
|
-
setMsg({ text: `delete ${current.decision} ${current.tool} (${ago(current.at)} ago)
|
|
2540
|
+
setMsg({ text: `x = delete ONLY the selected entry: ${current.decision} ${current.tool} (${ago(current.at)} ago) \u2014 press x again`, level: "bad" });
|
|
2520
2541
|
return;
|
|
2521
2542
|
}
|
|
2522
2543
|
setConfirm(null);
|
|
@@ -2524,12 +2545,14 @@ function AuditPanel({ active: active2, focused }) {
|
|
|
2524
2545
|
} else if (input === "X") {
|
|
2525
2546
|
if (confirm?.kind !== "all") {
|
|
2526
2547
|
setConfirm({ kind: "all", key: "all" });
|
|
2527
|
-
setMsg({ text:
|
|
2548
|
+
setMsg({ text: `\u26A0 X = delete ALL ${source} logs \u2014 every one of the ${total} matched entries! press X again`, level: "bad" });
|
|
2528
2549
|
return;
|
|
2529
2550
|
}
|
|
2530
2551
|
setConfirm(null);
|
|
2531
2552
|
doDelete("all");
|
|
2532
|
-
} else if (input === "
|
|
2553
|
+
} else if (input === "e") doExport("page");
|
|
2554
|
+
else if (input === "E") doExport("all");
|
|
2555
|
+
else if (input === "t") setEditing("tool");
|
|
2533
2556
|
else if (input === "n") setEditing("agent");
|
|
2534
2557
|
else if (input === "/") setEditing("search");
|
|
2535
2558
|
else if (input === "c") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.81.
|
|
3
|
+
"version": "0.81.28",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|