@solongate/proxy 0.51.0 → 0.53.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/global-install.d.ts +2 -0
- package/dist/global-install.js +83 -0
- package/dist/index.js +412 -145
- package/dist/login.js +72 -0
- package/dist/shield.d.ts +1 -0
- package/dist/shield.js +171 -0
- package/hooks/guard.bundled.mjs +7740 -7740
- package/hooks/shield.mjs +144 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3412,12 +3412,12 @@ ${ctx.indent}`;
|
|
|
3412
3412
|
for (const {
|
|
3413
3413
|
format,
|
|
3414
3414
|
test,
|
|
3415
|
-
resolve:
|
|
3415
|
+
resolve: resolve8
|
|
3416
3416
|
} of tags) {
|
|
3417
3417
|
if (test) {
|
|
3418
3418
|
const match = str.match(test);
|
|
3419
3419
|
if (match) {
|
|
3420
|
-
let res =
|
|
3420
|
+
let res = resolve8.apply(null, match);
|
|
3421
3421
|
if (!(res instanceof Scalar)) res = new Scalar(res);
|
|
3422
3422
|
if (format) res.format = format;
|
|
3423
3423
|
return res;
|
|
@@ -6572,8 +6572,10 @@ var init_cli_utils = __esm({
|
|
|
6572
6572
|
var global_install_exports = {};
|
|
6573
6573
|
__export(global_install_exports, {
|
|
6574
6574
|
globalPaths: () => globalPaths,
|
|
6575
|
+
installClaudeShim: () => installClaudeShim,
|
|
6575
6576
|
installGlobalWithKey: () => installGlobalWithKey,
|
|
6576
6577
|
lockProtected: () => lockProtected,
|
|
6578
|
+
removeClaudeShim: () => removeClaudeShim,
|
|
6577
6579
|
runGlobalInstall: () => runGlobalInstall,
|
|
6578
6580
|
runGlobalRestore: () => runGlobalRestore,
|
|
6579
6581
|
unlockProtected: () => unlockProtected
|
|
@@ -6646,6 +6648,7 @@ function protectedTargets() {
|
|
|
6646
6648
|
join4(p.hooksDir, "guard.mjs"),
|
|
6647
6649
|
join4(p.hooksDir, "audit.mjs"),
|
|
6648
6650
|
join4(p.hooksDir, "stop.mjs"),
|
|
6651
|
+
join4(p.hooksDir, "shield.mjs"),
|
|
6649
6652
|
p.configPath,
|
|
6650
6653
|
p.settingsPath
|
|
6651
6654
|
];
|
|
@@ -6688,6 +6691,7 @@ function ask(question) {
|
|
|
6688
6691
|
function runGlobalRestore() {
|
|
6689
6692
|
const p = globalPaths();
|
|
6690
6693
|
unlockProtected();
|
|
6694
|
+
removeClaudeShim();
|
|
6691
6695
|
if (existsSync4(p.backupPath)) {
|
|
6692
6696
|
writeFileSync3(p.settingsPath, readFileSync5(p.backupPath, "utf-8"));
|
|
6693
6697
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
@@ -6704,6 +6708,81 @@ function runGlobalRestore() {
|
|
|
6704
6708
|
}
|
|
6705
6709
|
console.log(" Global SolonGate enforcement uninstalled. Restart Claude Code.");
|
|
6706
6710
|
}
|
|
6711
|
+
function escapeRe(s) {
|
|
6712
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6713
|
+
}
|
|
6714
|
+
function resolveRealClaude() {
|
|
6715
|
+
try {
|
|
6716
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
6717
|
+
const out = execFileSync2(finder, ["claude"], { encoding: "utf-8" }).split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
6718
|
+
if (process.platform === "win32") {
|
|
6719
|
+
const low = (s) => s.toLowerCase();
|
|
6720
|
+
return out.find((l) => low(l).endsWith(".cmd")) || out.find((l) => low(l).endsWith(".exe")) || out.find((l) => low(l).endsWith(".bat")) || out[0] || null;
|
|
6721
|
+
}
|
|
6722
|
+
return out[0] || null;
|
|
6723
|
+
} catch {
|
|
6724
|
+
return null;
|
|
6725
|
+
}
|
|
6726
|
+
}
|
|
6727
|
+
function shimTargets() {
|
|
6728
|
+
if (process.platform === "win32") {
|
|
6729
|
+
try {
|
|
6730
|
+
const prof = execFileSync2("powershell", ["-NoProfile", "-Command", "$PROFILE.CurrentUserAllHosts"], { encoding: "utf-8" }).trim();
|
|
6731
|
+
return prof ? [prof] : [];
|
|
6732
|
+
} catch {
|
|
6733
|
+
return [];
|
|
6734
|
+
}
|
|
6735
|
+
}
|
|
6736
|
+
return [".bashrc", ".zshrc", ".profile"].map((f) => join4(homedir2(), f)).filter((f) => existsSync4(f));
|
|
6737
|
+
}
|
|
6738
|
+
function writeShimBlock(file, block) {
|
|
6739
|
+
const re = new RegExp(escapeRe(SHIM_BEGIN) + "[\\s\\S]*?" + escapeRe(SHIM_END) + "\\r?\\n?", "g");
|
|
6740
|
+
let content = existsSync4(file) ? readFileSync5(file, "utf-8") : "";
|
|
6741
|
+
content = content.replace(re, "");
|
|
6742
|
+
if (block) {
|
|
6743
|
+
if (content.length && !content.endsWith("\n")) content += "\n";
|
|
6744
|
+
content += block + "\n";
|
|
6745
|
+
}
|
|
6746
|
+
mkdirSync4(dirname2(file), { recursive: true });
|
|
6747
|
+
writeFileSync3(file, content);
|
|
6748
|
+
}
|
|
6749
|
+
function installClaudeShim(shieldPath) {
|
|
6750
|
+
const real = resolveRealClaude();
|
|
6751
|
+
if (!real) {
|
|
6752
|
+
console.log(" (Claude Code not found on PATH \u2014 skipped auto-shield. Install it, then re-run `login`.)");
|
|
6753
|
+
return;
|
|
6754
|
+
}
|
|
6755
|
+
const node = process.execPath.replace(/\\/g, "/");
|
|
6756
|
+
const shield = shieldPath.replace(/\\/g, "/");
|
|
6757
|
+
const win = process.platform === "win32";
|
|
6758
|
+
const block = win ? `${SHIM_BEGIN}
|
|
6759
|
+
function claude { & "${node}" "${shield}" -- "${real}" @args }
|
|
6760
|
+
${SHIM_END}` : `${SHIM_BEGIN}
|
|
6761
|
+
claude() { "${node}" "${shield}" -- "${real}" "$@"; }
|
|
6762
|
+
${SHIM_END}`;
|
|
6763
|
+
const targets = shimTargets();
|
|
6764
|
+
if (targets.length === 0) {
|
|
6765
|
+
console.log(" (No shell profile found for auto-shield; run `claude` via `solongate shield -- claude` manually.)");
|
|
6766
|
+
return;
|
|
6767
|
+
}
|
|
6768
|
+
for (const file of targets) {
|
|
6769
|
+
try {
|
|
6770
|
+
writeShimBlock(file, block);
|
|
6771
|
+
console.log(` Auto-shield on: \`claude\` now masks secrets (${file})`);
|
|
6772
|
+
} catch (e) {
|
|
6773
|
+
console.log(` (Could not enable auto-shield in ${file}: ${e.message})`);
|
|
6774
|
+
}
|
|
6775
|
+
}
|
|
6776
|
+
console.log(" Open a NEW terminal for it to take effect.");
|
|
6777
|
+
}
|
|
6778
|
+
function removeClaudeShim() {
|
|
6779
|
+
for (const file of shimTargets()) {
|
|
6780
|
+
try {
|
|
6781
|
+
writeShimBlock(file, null);
|
|
6782
|
+
} catch {
|
|
6783
|
+
}
|
|
6784
|
+
}
|
|
6785
|
+
}
|
|
6707
6786
|
async function runGlobalInstall(opts = {}) {
|
|
6708
6787
|
const p = globalPaths();
|
|
6709
6788
|
let apiKey = opts.apiKey || process.env["SOLONGATE_API_KEY"] || "";
|
|
@@ -6728,7 +6807,9 @@ async function runGlobalInstall(opts = {}) {
|
|
|
6728
6807
|
writeFileSync3(join4(p.hooksDir, "guard.mjs"), readGuard());
|
|
6729
6808
|
writeFileSync3(join4(p.hooksDir, "audit.mjs"), readHook("audit.mjs"));
|
|
6730
6809
|
writeFileSync3(join4(p.hooksDir, "stop.mjs"), readHook("stop.mjs"));
|
|
6810
|
+
writeFileSync3(join4(p.hooksDir, "shield.mjs"), readHook("shield.mjs"));
|
|
6731
6811
|
console.log(` Installed hooks \u2192 ${p.hooksDir}`);
|
|
6812
|
+
installClaudeShim(join4(p.hooksDir, "shield.mjs"));
|
|
6732
6813
|
writeFileSync3(p.configPath, JSON.stringify({ apiKey, apiUrl }, null, 2) + "\n");
|
|
6733
6814
|
console.log(` Wrote ${p.configPath}`);
|
|
6734
6815
|
let existing = {};
|
|
@@ -6766,12 +6847,14 @@ async function runGlobalInstall(opts = {}) {
|
|
|
6766
6847
|
async function installGlobalWithKey(apiKey, apiUrl) {
|
|
6767
6848
|
await runGlobalInstall({ apiKey, apiUrl });
|
|
6768
6849
|
}
|
|
6769
|
-
var __dirname, HOOKS_DIR;
|
|
6850
|
+
var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
6770
6851
|
var init_global_install = __esm({
|
|
6771
6852
|
"src/global-install.ts"() {
|
|
6772
6853
|
"use strict";
|
|
6773
6854
|
__dirname = dirname2(fileURLToPath(import.meta.url));
|
|
6774
6855
|
HOOKS_DIR = resolve3(__dirname, "..", "hooks");
|
|
6856
|
+
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
6857
|
+
SHIM_END = "# <<< SolonGate shield <<<";
|
|
6775
6858
|
}
|
|
6776
6859
|
});
|
|
6777
6860
|
|
|
@@ -6925,10 +7008,189 @@ var init_login = __esm({
|
|
|
6925
7008
|
}
|
|
6926
7009
|
});
|
|
6927
7010
|
|
|
7011
|
+
// src/shield.ts
|
|
7012
|
+
var shield_exports = {};
|
|
7013
|
+
__export(shield_exports, {
|
|
7014
|
+
runShield: () => runShield
|
|
7015
|
+
});
|
|
7016
|
+
import { createServer, request as httpRequest } from "http";
|
|
7017
|
+
import { request as httpsRequest } from "https";
|
|
7018
|
+
import { spawn as spawn2 } from "child_process";
|
|
7019
|
+
import { URL as URL2 } from "url";
|
|
7020
|
+
import { readFileSync as readFileSync6, existsSync as existsSync5 } from "fs";
|
|
7021
|
+
import { resolve as resolve4 } from "path";
|
|
7022
|
+
import { homedir as homedir3 } from "os";
|
|
7023
|
+
function loadCfg() {
|
|
7024
|
+
try {
|
|
7025
|
+
const sel = (process.env.SOLONGATE_AGENT_ID || "default").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7026
|
+
const f = resolve4(homedir3(), ".solongate", ".policy-cache-" + sel + ".json");
|
|
7027
|
+
if (existsSync5(f)) {
|
|
7028
|
+
const c3 = JSON.parse(readFileSync6(f, "utf-8"));
|
|
7029
|
+
const d = c3?.security?.dlpRedact;
|
|
7030
|
+
if (d && Array.isArray(d.patterns)) return { patterns: d.patterns, custom: Array.isArray(d.custom) ? d.custom : [] };
|
|
7031
|
+
}
|
|
7032
|
+
} catch {
|
|
7033
|
+
}
|
|
7034
|
+
return { patterns: DLP_PATTERNS.map((p) => p.name), custom: [] };
|
|
7035
|
+
}
|
|
7036
|
+
function redactString(s, cfg) {
|
|
7037
|
+
if (!cfg || typeof s !== "string" || !s) return s;
|
|
7038
|
+
const allow = new Set(cfg.patterns);
|
|
7039
|
+
let out = s;
|
|
7040
|
+
for (const p of DLP_PATTERNS) if (allow.has(p.name)) out = out.replace(p.re, `[REDACTED: ${p.name}]`);
|
|
7041
|
+
for (const c3 of cfg.custom) {
|
|
7042
|
+
try {
|
|
7043
|
+
out = out.replace(new RegExp(c3.re, "g"), `[REDACTED: ${c3.name || "custom"}]`);
|
|
7044
|
+
} catch {
|
|
7045
|
+
}
|
|
7046
|
+
}
|
|
7047
|
+
return out;
|
|
7048
|
+
}
|
|
7049
|
+
function redactDeep(value, cfg) {
|
|
7050
|
+
if (typeof value === "string") return redactString(value, cfg);
|
|
7051
|
+
if (Array.isArray(value)) return value.map((v) => redactDeep(v, cfg));
|
|
7052
|
+
if (value && typeof value === "object") {
|
|
7053
|
+
const out = {};
|
|
7054
|
+
for (const [k, v] of Object.entries(value)) out[k] = redactDeep(v, cfg);
|
|
7055
|
+
return out;
|
|
7056
|
+
}
|
|
7057
|
+
return value;
|
|
7058
|
+
}
|
|
7059
|
+
function pickUpstream() {
|
|
7060
|
+
const raw = process.env.SOLONGATE_SHIELD_UPSTREAM || process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
|
|
7061
|
+
try {
|
|
7062
|
+
return new URL2(raw);
|
|
7063
|
+
} catch {
|
|
7064
|
+
return new URL2("https://api.anthropic.com");
|
|
7065
|
+
}
|
|
7066
|
+
}
|
|
7067
|
+
function startProxy(upstream) {
|
|
7068
|
+
const cfg = loadCfg();
|
|
7069
|
+
const forward = upstream.protocol === "https:" ? httpsRequest : httpRequest;
|
|
7070
|
+
const server = createServer((req, res) => {
|
|
7071
|
+
const chunks = [];
|
|
7072
|
+
req.on("data", (c3) => chunks.push(c3));
|
|
7073
|
+
req.on("end", () => {
|
|
7074
|
+
let body = Buffer.concat(chunks);
|
|
7075
|
+
try {
|
|
7076
|
+
if (body.length && (req.headers["content-type"] || "").includes("json")) {
|
|
7077
|
+
const parsed = JSON.parse(body.toString("utf-8"));
|
|
7078
|
+
const redacted = redactDeep(parsed, cfg);
|
|
7079
|
+
body = Buffer.from(JSON.stringify(redacted), "utf-8");
|
|
7080
|
+
}
|
|
7081
|
+
} catch {
|
|
7082
|
+
}
|
|
7083
|
+
const headers = { ...req.headers };
|
|
7084
|
+
delete headers["host"];
|
|
7085
|
+
delete headers["content-length"];
|
|
7086
|
+
delete headers["accept-encoding"];
|
|
7087
|
+
headers["content-length"] = String(body.length);
|
|
7088
|
+
const upstreamReq = forward(
|
|
7089
|
+
{
|
|
7090
|
+
protocol: upstream.protocol,
|
|
7091
|
+
hostname: upstream.hostname,
|
|
7092
|
+
port: upstream.port || (upstream.protocol === "https:" ? 443 : 80),
|
|
7093
|
+
method: req.method,
|
|
7094
|
+
path: req.url,
|
|
7095
|
+
headers: { ...headers, host: upstream.host }
|
|
7096
|
+
},
|
|
7097
|
+
(upRes) => {
|
|
7098
|
+
res.writeHead(upRes.statusCode || 502, upRes.headers);
|
|
7099
|
+
upRes.pipe(res);
|
|
7100
|
+
}
|
|
7101
|
+
);
|
|
7102
|
+
upstreamReq.on("error", (e) => {
|
|
7103
|
+
log4("upstream error:", e.message);
|
|
7104
|
+
if (!res.headersSent) res.writeHead(502, { "content-type": "text/plain" });
|
|
7105
|
+
res.end("shield upstream error");
|
|
7106
|
+
});
|
|
7107
|
+
upstreamReq.end(body);
|
|
7108
|
+
});
|
|
7109
|
+
req.on("error", () => {
|
|
7110
|
+
try {
|
|
7111
|
+
res.destroy();
|
|
7112
|
+
} catch {
|
|
7113
|
+
}
|
|
7114
|
+
});
|
|
7115
|
+
});
|
|
7116
|
+
return new Promise((resolveP) => {
|
|
7117
|
+
server.listen(0, "127.0.0.1", () => {
|
|
7118
|
+
const addr = server.address();
|
|
7119
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
7120
|
+
resolveP({ port, close: () => server.close() });
|
|
7121
|
+
});
|
|
7122
|
+
});
|
|
7123
|
+
}
|
|
7124
|
+
async function runShield() {
|
|
7125
|
+
const sep = process.argv.indexOf("--");
|
|
7126
|
+
const cmd = sep !== -1 ? process.argv.slice(sep + 1) : [];
|
|
7127
|
+
if (cmd.length === 0) {
|
|
7128
|
+
log4("usage: npx @solongate/proxy shield -- <command> [args...] (e.g. shield -- claude)");
|
|
7129
|
+
process.exit(1);
|
|
7130
|
+
}
|
|
7131
|
+
const upstream = pickUpstream();
|
|
7132
|
+
const { port, close } = await startProxy(upstream);
|
|
7133
|
+
log4(`redacting secrets on the LLM path \u2192 masking before ${upstream.host} (127.0.0.1:${port})`);
|
|
7134
|
+
const child = spawn2(cmd[0], cmd.slice(1), {
|
|
7135
|
+
stdio: "inherit",
|
|
7136
|
+
env: { ...process.env, ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}` },
|
|
7137
|
+
shell: process.platform === "win32"
|
|
7138
|
+
// resolve `claude.cmd` etc. on Windows
|
|
7139
|
+
});
|
|
7140
|
+
const shutdown = () => {
|
|
7141
|
+
try {
|
|
7142
|
+
close();
|
|
7143
|
+
} catch {
|
|
7144
|
+
}
|
|
7145
|
+
};
|
|
7146
|
+
child.on("exit", (code, signal) => {
|
|
7147
|
+
shutdown();
|
|
7148
|
+
if (signal) process.kill(process.pid, signal);
|
|
7149
|
+
else process.exit(code ?? 0);
|
|
7150
|
+
});
|
|
7151
|
+
child.on("error", (e) => {
|
|
7152
|
+
log4("failed to launch command:", e.message);
|
|
7153
|
+
shutdown();
|
|
7154
|
+
process.exit(1);
|
|
7155
|
+
});
|
|
7156
|
+
for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => {
|
|
7157
|
+
try {
|
|
7158
|
+
child.kill(sig);
|
|
7159
|
+
} catch {
|
|
7160
|
+
}
|
|
7161
|
+
});
|
|
7162
|
+
}
|
|
7163
|
+
var log4, DLP_PATTERNS;
|
|
7164
|
+
var init_shield = __esm({
|
|
7165
|
+
"src/shield.ts"() {
|
|
7166
|
+
"use strict";
|
|
7167
|
+
log4 = (...a) => process.stderr.write(`[SolonGate shield] ${a.map(String).join(" ")}
|
|
7168
|
+
`);
|
|
7169
|
+
DLP_PATTERNS = [
|
|
7170
|
+
{ name: "AWS access key", re: /AKIA[0-9A-Z]{16}/g },
|
|
7171
|
+
{ name: "private key block", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----/g },
|
|
7172
|
+
{ name: "Anthropic key", re: /sk-ant-[A-Za-z0-9_-]{20,}/g },
|
|
7173
|
+
{ name: "OpenAI key", re: /sk-(proj-)?[A-Za-z0-9_-]{20,}/g },
|
|
7174
|
+
{ name: "GitHub token", re: /gh[pousr]_[A-Za-z0-9]{20,}/g },
|
|
7175
|
+
{ name: "GitHub fine-grained PAT", re: /github_pat_[A-Za-z0-9_]{20,}/g },
|
|
7176
|
+
{ name: "GitLab token", re: /glpat-[A-Za-z0-9_-]{20,}/g },
|
|
7177
|
+
{ name: "Slack token", re: /xox[baprs]-[A-Za-z0-9-]{10,}/g },
|
|
7178
|
+
{ name: "Google API key", re: /AIza[0-9A-Za-z_-]{35}/g },
|
|
7179
|
+
{ name: "Stripe key", re: /[sr]k_(live|test)_[A-Za-z0-9]{20,}/g },
|
|
7180
|
+
{ name: "SendGrid key", re: /SG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}/g },
|
|
7181
|
+
{ name: "Twilio key", re: /SK[0-9a-fA-F]{32}/g },
|
|
7182
|
+
{ name: "npm token", re: /npm_[A-Za-z0-9]{36}/g },
|
|
7183
|
+
{ name: "JWT", re: /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g },
|
|
7184
|
+
{ name: "Bearer token", re: /bearer\s+[A-Za-z0-9._-]{20,}/gi },
|
|
7185
|
+
{ name: "secret assignment", re: /(api[_-]?key|secret|token|password|passwd|access[_-]?key)["']?\s*[:=]\s*["']?[A-Za-z0-9/+_.-]{12,}/gi }
|
|
7186
|
+
];
|
|
7187
|
+
}
|
|
7188
|
+
});
|
|
7189
|
+
|
|
6928
7190
|
// src/inject.ts
|
|
6929
7191
|
var inject_exports = {};
|
|
6930
|
-
import { readFileSync as
|
|
6931
|
-
import { resolve as
|
|
7192
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync6, copyFileSync } from "fs";
|
|
7193
|
+
import { resolve as resolve5 } from "path";
|
|
6932
7194
|
import { execSync } from "child_process";
|
|
6933
7195
|
function parseInjectArgs(argv) {
|
|
6934
7196
|
const args = argv.slice(2);
|
|
@@ -6985,9 +7247,9 @@ WHAT IT DOES
|
|
|
6985
7247
|
`);
|
|
6986
7248
|
}
|
|
6987
7249
|
function detectProject() {
|
|
6988
|
-
if (!
|
|
7250
|
+
if (!existsSync6(resolve5("package.json"))) return false;
|
|
6989
7251
|
try {
|
|
6990
|
-
const pkg = JSON.parse(
|
|
7252
|
+
const pkg = JSON.parse(readFileSync7(resolve5("package.json"), "utf-8"));
|
|
6991
7253
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
6992
7254
|
return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
|
|
6993
7255
|
} catch {
|
|
@@ -6996,18 +7258,18 @@ function detectProject() {
|
|
|
6996
7258
|
}
|
|
6997
7259
|
function findTsEntryFile() {
|
|
6998
7260
|
try {
|
|
6999
|
-
const pkg = JSON.parse(
|
|
7261
|
+
const pkg = JSON.parse(readFileSync7(resolve5("package.json"), "utf-8"));
|
|
7000
7262
|
if (pkg.bin) {
|
|
7001
7263
|
const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
|
|
7002
7264
|
if (typeof binPath === "string") {
|
|
7003
7265
|
const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
7004
|
-
if (
|
|
7005
|
-
if (
|
|
7266
|
+
if (existsSync6(resolve5(srcPath))) return resolve5(srcPath);
|
|
7267
|
+
if (existsSync6(resolve5(binPath))) return resolve5(binPath);
|
|
7006
7268
|
}
|
|
7007
7269
|
}
|
|
7008
7270
|
if (pkg.main) {
|
|
7009
7271
|
const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
|
|
7010
|
-
if (
|
|
7272
|
+
if (existsSync6(resolve5(srcPath))) return resolve5(srcPath);
|
|
7011
7273
|
}
|
|
7012
7274
|
} catch {
|
|
7013
7275
|
}
|
|
@@ -7020,10 +7282,10 @@ function findTsEntryFile() {
|
|
|
7020
7282
|
"main.ts"
|
|
7021
7283
|
];
|
|
7022
7284
|
for (const c3 of candidates) {
|
|
7023
|
-
const full =
|
|
7024
|
-
if (
|
|
7285
|
+
const full = resolve5(c3);
|
|
7286
|
+
if (existsSync6(full)) {
|
|
7025
7287
|
try {
|
|
7026
|
-
const content =
|
|
7288
|
+
const content = readFileSync7(full, "utf-8");
|
|
7027
7289
|
if (content.includes("McpServer") || content.includes("McpServer")) {
|
|
7028
7290
|
return full;
|
|
7029
7291
|
}
|
|
@@ -7032,18 +7294,18 @@ function findTsEntryFile() {
|
|
|
7032
7294
|
}
|
|
7033
7295
|
}
|
|
7034
7296
|
for (const c3 of candidates) {
|
|
7035
|
-
if (
|
|
7297
|
+
if (existsSync6(resolve5(c3))) return resolve5(c3);
|
|
7036
7298
|
}
|
|
7037
7299
|
return null;
|
|
7038
7300
|
}
|
|
7039
7301
|
function detectPackageManager() {
|
|
7040
|
-
if (
|
|
7041
|
-
if (
|
|
7302
|
+
if (existsSync6(resolve5("pnpm-lock.yaml"))) return "pnpm";
|
|
7303
|
+
if (existsSync6(resolve5("yarn.lock"))) return "yarn";
|
|
7042
7304
|
return "npm";
|
|
7043
7305
|
}
|
|
7044
7306
|
function installSdk() {
|
|
7045
7307
|
try {
|
|
7046
|
-
const pkg = JSON.parse(
|
|
7308
|
+
const pkg = JSON.parse(readFileSync7(resolve5("package.json"), "utf-8"));
|
|
7047
7309
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
7048
7310
|
if (allDeps["@solongate/proxy"]) {
|
|
7049
7311
|
log3(" @solongate/proxy already installed");
|
|
@@ -7064,7 +7326,7 @@ function installSdk() {
|
|
|
7064
7326
|
}
|
|
7065
7327
|
}
|
|
7066
7328
|
function injectTypeScript(filePath) {
|
|
7067
|
-
const original =
|
|
7329
|
+
const original = readFileSync7(filePath, "utf-8");
|
|
7068
7330
|
const changes = [];
|
|
7069
7331
|
let modified = original;
|
|
7070
7332
|
if (modified.includes("SecureMcpServer")) {
|
|
@@ -7180,8 +7442,8 @@ async function main2() {
|
|
|
7180
7442
|
process.exit(1);
|
|
7181
7443
|
}
|
|
7182
7444
|
log3(" Language: TypeScript");
|
|
7183
|
-
const entryFile = opts.file ?
|
|
7184
|
-
if (!entryFile || !
|
|
7445
|
+
const entryFile = opts.file ? resolve5(opts.file) : findTsEntryFile();
|
|
7446
|
+
if (!entryFile || !existsSync6(entryFile)) {
|
|
7185
7447
|
log3(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
|
|
7186
7448
|
log3("");
|
|
7187
7449
|
log3(" Specify it manually: --file <path>");
|
|
@@ -7194,7 +7456,7 @@ async function main2() {
|
|
|
7194
7456
|
log3("");
|
|
7195
7457
|
const backupPath = entryFile + ".solongate-backup";
|
|
7196
7458
|
if (opts.restore) {
|
|
7197
|
-
if (!
|
|
7459
|
+
if (!existsSync6(backupPath)) {
|
|
7198
7460
|
log3(" No backup found. Nothing to restore.");
|
|
7199
7461
|
process.exit(1);
|
|
7200
7462
|
}
|
|
@@ -7230,7 +7492,7 @@ async function main2() {
|
|
|
7230
7492
|
log3(" To apply: npx @solongate/proxy inject");
|
|
7231
7493
|
process.exit(0);
|
|
7232
7494
|
}
|
|
7233
|
-
if (!
|
|
7495
|
+
if (!existsSync6(backupPath)) {
|
|
7234
7496
|
copyFileSync(entryFile, backupPath);
|
|
7235
7497
|
log3("");
|
|
7236
7498
|
log3(` Backup: ${backupPath}`);
|
|
@@ -7264,8 +7526,8 @@ var init_inject = __esm({
|
|
|
7264
7526
|
|
|
7265
7527
|
// src/create.ts
|
|
7266
7528
|
var create_exports = {};
|
|
7267
|
-
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, existsSync as
|
|
7268
|
-
import { resolve as
|
|
7529
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
|
|
7530
|
+
import { resolve as resolve6, join as join5 } from "path";
|
|
7269
7531
|
import { execSync as execSync2 } from "child_process";
|
|
7270
7532
|
function withSpinner(message, fn) {
|
|
7271
7533
|
const frames = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
|
|
@@ -7474,9 +7736,9 @@ dist/
|
|
|
7474
7736
|
}
|
|
7475
7737
|
async function main3() {
|
|
7476
7738
|
const opts = parseCreateArgs(process.argv);
|
|
7477
|
-
const dir =
|
|
7739
|
+
const dir = resolve6(opts.name);
|
|
7478
7740
|
printBanner("Create MCP Server");
|
|
7479
|
-
if (
|
|
7741
|
+
if (existsSync7(dir)) {
|
|
7480
7742
|
log3(` ${c.red}Error:${c.reset} Directory "${opts.name}" already exists.`);
|
|
7481
7743
|
process.exit(1);
|
|
7482
7744
|
}
|
|
@@ -7555,14 +7817,14 @@ var init_create = __esm({
|
|
|
7555
7817
|
|
|
7556
7818
|
// src/pull-push.ts
|
|
7557
7819
|
var pull_push_exports = {};
|
|
7558
|
-
import { readFileSync as
|
|
7559
|
-
import { resolve as
|
|
7820
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync8 } from "fs";
|
|
7821
|
+
import { resolve as resolve7 } from "path";
|
|
7560
7822
|
function loadEnv() {
|
|
7561
7823
|
if (process.env.SOLONGATE_API_KEY) return;
|
|
7562
|
-
const envPath =
|
|
7563
|
-
if (!
|
|
7824
|
+
const envPath = resolve7(".env");
|
|
7825
|
+
if (!existsSync8(envPath)) return;
|
|
7564
7826
|
try {
|
|
7565
|
-
const content =
|
|
7827
|
+
const content = readFileSync8(envPath, "utf-8");
|
|
7566
7828
|
for (const line of content.split("\n")) {
|
|
7567
7829
|
const trimmed = line.trim();
|
|
7568
7830
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -7604,20 +7866,20 @@ function parseCliArgs() {
|
|
|
7604
7866
|
}
|
|
7605
7867
|
}
|
|
7606
7868
|
if (!apiKey) {
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7869
|
+
log5(red("ERROR: API key not found."));
|
|
7870
|
+
log5("");
|
|
7871
|
+
log5("Set it in .env file:");
|
|
7872
|
+
log5(" SOLONGATE_API_KEY=sg_live_...");
|
|
7873
|
+
log5("");
|
|
7874
|
+
log5("Or pass via environment:");
|
|
7875
|
+
log5(` SOLONGATE_API_KEY=sg_live_... solongate-proxy ${command}`);
|
|
7614
7876
|
process.exit(1);
|
|
7615
7877
|
}
|
|
7616
7878
|
if (!apiKey.startsWith("sg_live_")) {
|
|
7617
|
-
|
|
7879
|
+
log5(red("ERROR: Pull/push/list requires a live API key (sg_live_...)."));
|
|
7618
7880
|
process.exit(1);
|
|
7619
7881
|
}
|
|
7620
|
-
return { command, apiKey, file:
|
|
7882
|
+
return { command, apiKey, file: resolve7(file), policyId };
|
|
7621
7883
|
}
|
|
7622
7884
|
async function listPolicies(apiKey) {
|
|
7623
7885
|
const res = await fetch(`${API_URL}/api/v1/policies`, {
|
|
@@ -7630,18 +7892,18 @@ async function listPolicies(apiKey) {
|
|
|
7630
7892
|
async function list(apiKey, policyId) {
|
|
7631
7893
|
const policies = await listPolicies(apiKey);
|
|
7632
7894
|
if (policies.length === 0) {
|
|
7633
|
-
|
|
7634
|
-
|
|
7895
|
+
log5(yellow("No policies found. Create one in the dashboard first."));
|
|
7896
|
+
log5(dim(" https://dashboard.solongate.com/policies"));
|
|
7635
7897
|
return;
|
|
7636
7898
|
}
|
|
7637
7899
|
if (policyId) {
|
|
7638
7900
|
const match = policies.find((p) => p.id === policyId);
|
|
7639
7901
|
if (!match) {
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7902
|
+
log5(red(`Policy not found: ${policyId}`));
|
|
7903
|
+
log5("");
|
|
7904
|
+
log5("Available policies:");
|
|
7643
7905
|
for (const p of policies) {
|
|
7644
|
-
|
|
7906
|
+
log5(` ${dim("\u2022")} ${p.id}`);
|
|
7645
7907
|
}
|
|
7646
7908
|
process.exit(1);
|
|
7647
7909
|
}
|
|
@@ -7649,10 +7911,10 @@ async function list(apiKey, policyId) {
|
|
|
7649
7911
|
printPolicyDetail(full);
|
|
7650
7912
|
return;
|
|
7651
7913
|
}
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7914
|
+
log5("");
|
|
7915
|
+
log5(bold(` Policies (${policies.length})`));
|
|
7916
|
+
log5(dim(" \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"));
|
|
7917
|
+
log5("");
|
|
7656
7918
|
const fullPolicies = await Promise.all(
|
|
7657
7919
|
policies.map(
|
|
7658
7920
|
(p) => fetchCloudPolicy(apiKey, API_URL, p.id).then((full) => ({ policy: p, rules: full.rules })).catch(() => ({ policy: p, rules: [] }))
|
|
@@ -7661,136 +7923,136 @@ async function list(apiKey, policyId) {
|
|
|
7661
7923
|
for (const { policy, rules } of fullPolicies) {
|
|
7662
7924
|
printPolicySummary(policy, rules);
|
|
7663
7925
|
}
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7926
|
+
log5(dim(" \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"));
|
|
7927
|
+
log5("");
|
|
7928
|
+
log5(` ${dim("View details:")} solongate-proxy list --policy-id <ID>`);
|
|
7929
|
+
log5(` ${dim("Pull policy:")} solongate-proxy pull --policy-id <ID>`);
|
|
7930
|
+
log5(` ${dim("Push policy:")} solongate-proxy push --policy-id <ID>`);
|
|
7931
|
+
log5("");
|
|
7670
7932
|
}
|
|
7671
7933
|
function printPolicySummary(p, rules) {
|
|
7672
7934
|
const ruleCount = rules.length;
|
|
7673
7935
|
const allowCount = rules.filter((r) => r.effect === "ALLOW").length;
|
|
7674
7936
|
const denyCount = rules.filter((r) => r.effect === "DENY").length;
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7937
|
+
log5(` ${cyan(p.id)}`);
|
|
7938
|
+
log5(` ${bold(p.name)} ${dim(`v${p.version ?? "?"}`)}`);
|
|
7939
|
+
log5(` ${dim("Rules:")} ${ruleCount} ${green(`${allowCount} ALLOW`)} ${red(`${denyCount} DENY`)}`);
|
|
7678
7940
|
if (p.created_at) {
|
|
7679
|
-
|
|
7941
|
+
log5(` ${dim("Updated:")} ${new Date(p.created_at).toLocaleString()}`);
|
|
7680
7942
|
}
|
|
7681
|
-
|
|
7943
|
+
log5("");
|
|
7682
7944
|
}
|
|
7683
7945
|
function printPolicyDetail(policy) {
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7946
|
+
log5("");
|
|
7947
|
+
log5(bold(` ${policy.name}`));
|
|
7948
|
+
log5(` ${dim("ID:")} ${cyan(policy.id)} ${dim("Version:")} ${policy.version} ${dim("Rules:")} ${policy.rules.length}`);
|
|
7949
|
+
log5("");
|
|
7688
7950
|
if (policy.rules.length === 0) {
|
|
7689
|
-
|
|
7690
|
-
|
|
7951
|
+
log5(yellow(" No rules defined."));
|
|
7952
|
+
log5("");
|
|
7691
7953
|
return;
|
|
7692
7954
|
}
|
|
7693
|
-
|
|
7955
|
+
log5(dim(" \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"));
|
|
7694
7956
|
for (const rule of policy.rules) {
|
|
7695
7957
|
const effectColor = rule.effect === "ALLOW" ? green : red;
|
|
7696
|
-
|
|
7697
|
-
|
|
7958
|
+
log5("");
|
|
7959
|
+
log5(` ${effectColor(rule.effect.padEnd(5))} ${bold(rule.toolPattern)} ${dim(`P:${rule.priority}`)}`);
|
|
7698
7960
|
if (rule.description) {
|
|
7699
|
-
|
|
7961
|
+
log5(` ${dim(rule.description)}`);
|
|
7700
7962
|
}
|
|
7701
|
-
|
|
7963
|
+
log5(` ${dim(`${rule.permission} trust:${rule.minimumTrustLevel || "UNTRUSTED"}`)}`);
|
|
7702
7964
|
if (rule.pathConstraints) {
|
|
7703
7965
|
const pc = rule.pathConstraints;
|
|
7704
|
-
if (pc.rootDirectory)
|
|
7705
|
-
if (pc.allowed?.length)
|
|
7706
|
-
if (pc.denied?.length)
|
|
7966
|
+
if (pc.rootDirectory) log5(` ${magenta("ROOT")} ${pc.rootDirectory}`);
|
|
7967
|
+
if (pc.allowed?.length) log5(` ${green("PATHS")} ${pc.allowed.join(", ")}`);
|
|
7968
|
+
if (pc.denied?.length) log5(` ${red("DENY")} ${pc.denied.join(", ")}`);
|
|
7707
7969
|
}
|
|
7708
7970
|
if (rule.commandConstraints) {
|
|
7709
7971
|
const cc = rule.commandConstraints;
|
|
7710
|
-
if (cc.allowed?.length)
|
|
7711
|
-
if (cc.denied?.length)
|
|
7972
|
+
if (cc.allowed?.length) log5(` ${green("CMDS")} ${cc.allowed.join(", ")}`);
|
|
7973
|
+
if (cc.denied?.length) log5(` ${red("DENY")} ${cc.denied.join(", ")}`);
|
|
7712
7974
|
}
|
|
7713
7975
|
if (rule.filenameConstraints) {
|
|
7714
7976
|
const fc = rule.filenameConstraints;
|
|
7715
|
-
if (fc.allowed?.length)
|
|
7716
|
-
if (fc.denied?.length)
|
|
7977
|
+
if (fc.allowed?.length) log5(` ${green("FILES")} ${fc.allowed.join(", ")}`);
|
|
7978
|
+
if (fc.denied?.length) log5(` ${red("DENY")} ${fc.denied.join(", ")}`);
|
|
7717
7979
|
}
|
|
7718
7980
|
if (rule.urlConstraints) {
|
|
7719
7981
|
const uc = rule.urlConstraints;
|
|
7720
|
-
if (uc.allowed?.length)
|
|
7721
|
-
if (uc.denied?.length)
|
|
7982
|
+
if (uc.allowed?.length) log5(` ${green("URLS")} ${uc.allowed.join(", ")}`);
|
|
7983
|
+
if (uc.denied?.length) log5(` ${red("DENY")} ${uc.denied.join(", ")}`);
|
|
7722
7984
|
}
|
|
7723
7985
|
}
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7986
|
+
log5("");
|
|
7987
|
+
log5(dim(" \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"));
|
|
7988
|
+
log5("");
|
|
7727
7989
|
}
|
|
7728
7990
|
async function pull(apiKey, file, policyId) {
|
|
7729
7991
|
if (!policyId) {
|
|
7730
7992
|
const policies = await listPolicies(apiKey);
|
|
7731
7993
|
if (policies.length === 0) {
|
|
7732
|
-
|
|
7994
|
+
log5(red("No policies found. Create one in the dashboard first."));
|
|
7733
7995
|
process.exit(1);
|
|
7734
7996
|
}
|
|
7735
7997
|
if (policies.length === 1) {
|
|
7736
7998
|
policyId = policies[0].id;
|
|
7737
|
-
|
|
7999
|
+
log5(dim(`Auto-selecting only policy: ${policyId}`));
|
|
7738
8000
|
} else {
|
|
7739
|
-
|
|
7740
|
-
|
|
8001
|
+
log5(yellow(`Found ${policies.length} policies:`));
|
|
8002
|
+
log5("");
|
|
7741
8003
|
for (const p of policies) {
|
|
7742
|
-
|
|
8004
|
+
log5(` ${cyan(p.id)} ${p.name} ${dim(`v${p.version ?? "?"}`)}`);
|
|
7743
8005
|
}
|
|
7744
|
-
|
|
7745
|
-
|
|
8006
|
+
log5("");
|
|
8007
|
+
log5("Use --policy-id <ID> to specify which one to pull.");
|
|
7746
8008
|
process.exit(1);
|
|
7747
8009
|
}
|
|
7748
8010
|
}
|
|
7749
|
-
|
|
8011
|
+
log5(`Pulling ${cyan(policyId)} from dashboard...`);
|
|
7750
8012
|
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
7751
8013
|
const { id: _id, ...policyWithoutId } = policy;
|
|
7752
8014
|
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
7753
8015
|
writeFileSync6(file, json, "utf-8");
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
8016
|
+
log5("");
|
|
8017
|
+
log5(green(" Saved to: ") + file);
|
|
8018
|
+
log5(` ${dim("Name:")} ${policy.name}`);
|
|
8019
|
+
log5(` ${dim("Version:")} ${policy.version}`);
|
|
8020
|
+
log5(` ${dim("Rules:")} ${policy.rules.length}`);
|
|
8021
|
+
log5("");
|
|
8022
|
+
log5(dim("The policy file does not contain an ID."));
|
|
8023
|
+
log5(dim("Use --policy-id to specify the target when pushing/pulling."));
|
|
8024
|
+
log5("");
|
|
7763
8025
|
}
|
|
7764
8026
|
async function push(apiKey, file, policyId) {
|
|
7765
|
-
if (!
|
|
7766
|
-
|
|
8027
|
+
if (!existsSync8(file)) {
|
|
8028
|
+
log5(red(`ERROR: File not found: ${file}`));
|
|
7767
8029
|
process.exit(1);
|
|
7768
8030
|
}
|
|
7769
8031
|
if (!policyId) {
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
8032
|
+
log5(red("ERROR: --policy-id is required for push."));
|
|
8033
|
+
log5("");
|
|
8034
|
+
log5("This determines which cloud policy to update.");
|
|
8035
|
+
log5("");
|
|
8036
|
+
log5("Usage:");
|
|
8037
|
+
log5(" solongate-proxy push --policy-id my-policy");
|
|
8038
|
+
log5(" solongate-proxy push --policy-id my-policy --file custom.json");
|
|
8039
|
+
log5("");
|
|
8040
|
+
log5("List your policies:");
|
|
8041
|
+
log5(" solongate-proxy list");
|
|
7780
8042
|
process.exit(1);
|
|
7781
8043
|
}
|
|
7782
|
-
const content =
|
|
8044
|
+
const content = readFileSync8(file, "utf-8");
|
|
7783
8045
|
let policy;
|
|
7784
8046
|
try {
|
|
7785
8047
|
policy = JSON.parse(content);
|
|
7786
8048
|
} catch {
|
|
7787
|
-
|
|
8049
|
+
log5(red(`ERROR: Invalid JSON in ${file}`));
|
|
7788
8050
|
process.exit(1);
|
|
7789
8051
|
}
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
8052
|
+
log5(`Pushing to ${cyan(policyId)}...`);
|
|
8053
|
+
log5(` ${dim("File:")} ${file}`);
|
|
8054
|
+
log5(` ${dim("Name:")} ${policy.name || "Unnamed"}`);
|
|
8055
|
+
log5(` ${dim("Rules:")} ${(policy.rules || []).length}`);
|
|
7794
8056
|
const checkRes = await fetch(`${API_URL}/api/v1/policies/${policyId}`, {
|
|
7795
8057
|
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
7796
8058
|
});
|
|
@@ -7812,15 +8074,15 @@ async function push(apiKey, file, policyId) {
|
|
|
7812
8074
|
});
|
|
7813
8075
|
if (!res.ok) {
|
|
7814
8076
|
const body = await res.text().catch(() => "");
|
|
7815
|
-
|
|
8077
|
+
log5(red(`ERROR: Push failed (${res.status}): ${body}`));
|
|
7816
8078
|
process.exit(1);
|
|
7817
8079
|
}
|
|
7818
8080
|
const data = await res.json();
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
8081
|
+
log5("");
|
|
8082
|
+
log5(green(` Pushed to cloud: v${data._version ?? "created"}`));
|
|
8083
|
+
log5(` ${dim("Policy ID:")} ${policyId}`);
|
|
8084
|
+
log5(` ${dim("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
|
|
8085
|
+
log5("");
|
|
7824
8086
|
}
|
|
7825
8087
|
async function main4() {
|
|
7826
8088
|
const { command, apiKey, file, policyId } = parseCliArgs();
|
|
@@ -7832,32 +8094,32 @@ async function main4() {
|
|
|
7832
8094
|
} else if (command === "list" || command === "ls") {
|
|
7833
8095
|
await list(apiKey, policyId);
|
|
7834
8096
|
} else {
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
8097
|
+
log5(red(`Unknown command: ${command}`));
|
|
8098
|
+
log5("");
|
|
8099
|
+
log5(bold("Usage:"));
|
|
8100
|
+
log5(" solongate-proxy list List all policies");
|
|
8101
|
+
log5(" solongate-proxy list --policy-id <ID> Show policy details");
|
|
8102
|
+
log5(" solongate-proxy pull --policy-id <ID> Pull policy to local file");
|
|
8103
|
+
log5(" solongate-proxy push --policy-id <ID> Push local file to cloud");
|
|
8104
|
+
log5("");
|
|
8105
|
+
log5(bold("Flags:"));
|
|
8106
|
+
log5(" --policy-id, --id <ID> Cloud policy ID (required for push)");
|
|
8107
|
+
log5(" --file, -f <path> Local file path (default: policy.json)");
|
|
8108
|
+
log5(" --api-key <key> API key (or set SOLONGATE_API_KEY)");
|
|
8109
|
+
log5("");
|
|
7848
8110
|
process.exit(1);
|
|
7849
8111
|
}
|
|
7850
8112
|
} catch (err) {
|
|
7851
|
-
|
|
8113
|
+
log5(red(`ERROR: ${err instanceof Error ? err.message : String(err)}`));
|
|
7852
8114
|
process.exit(1);
|
|
7853
8115
|
}
|
|
7854
8116
|
}
|
|
7855
|
-
var
|
|
8117
|
+
var log5, dim, bold, green, red, yellow, cyan, magenta, API_URL;
|
|
7856
8118
|
var init_pull_push = __esm({
|
|
7857
8119
|
"src/pull-push.ts"() {
|
|
7858
8120
|
"use strict";
|
|
7859
8121
|
init_config();
|
|
7860
|
-
|
|
8122
|
+
log5 = (...args) => process.stderr.write(`${args.map(String).join(" ")}
|
|
7861
8123
|
`);
|
|
7862
8124
|
dim = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
7863
8125
|
bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
@@ -10296,7 +10558,7 @@ var Mutex = class {
|
|
|
10296
10558
|
this.locked = true;
|
|
10297
10559
|
return;
|
|
10298
10560
|
}
|
|
10299
|
-
return new Promise((
|
|
10561
|
+
return new Promise((resolve8, reject) => {
|
|
10300
10562
|
const timer = setTimeout(() => {
|
|
10301
10563
|
const idx = this.queue.indexOf(onReady);
|
|
10302
10564
|
if (idx !== -1) this.queue.splice(idx, 1);
|
|
@@ -10304,7 +10566,7 @@ var Mutex = class {
|
|
|
10304
10566
|
}, timeoutMs);
|
|
10305
10567
|
const onReady = () => {
|
|
10306
10568
|
clearTimeout(timer);
|
|
10307
|
-
|
|
10569
|
+
resolve8();
|
|
10308
10570
|
};
|
|
10309
10571
|
this.queue.push(onReady);
|
|
10310
10572
|
});
|
|
@@ -10924,7 +11186,7 @@ ${msg.content.text}`;
|
|
|
10924
11186
|
|
|
10925
11187
|
// src/index.ts
|
|
10926
11188
|
init_cli_utils();
|
|
10927
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["login", "logout", "create", "inject", "pull", "push", "list", "ls"]);
|
|
11189
|
+
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["login", "logout", "shield", "create", "inject", "pull", "push", "list", "ls"]);
|
|
10928
11190
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "");
|
|
10929
11191
|
if (!IS_HUMAN_CLI) {
|
|
10930
11192
|
console.log = (...args) => {
|
|
@@ -10968,6 +11230,11 @@ async function main5() {
|
|
|
10968
11230
|
runGlobalRestore2();
|
|
10969
11231
|
return;
|
|
10970
11232
|
}
|
|
11233
|
+
if (subcommand === "shield") {
|
|
11234
|
+
const { runShield: runShield2 } = await Promise.resolve().then(() => (init_shield(), shield_exports));
|
|
11235
|
+
await runShield2();
|
|
11236
|
+
return;
|
|
11237
|
+
}
|
|
10971
11238
|
if (subcommand === "inject") {
|
|
10972
11239
|
process.argv.splice(2, 1);
|
|
10973
11240
|
await Promise.resolve().then(() => (init_inject(), inject_exports));
|