@solongate/proxy 0.82.39 → 0.82.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/index.js +10 -11
- package/dist/index.js +401 -741
- package/dist/tui/index.js +2 -4
- package/package.json +1 -1
- package/dist/pull-push.d.ts +0 -17
- package/dist/pull-push.js +0 -358
package/dist/index.js
CHANGED
|
@@ -32,361 +32,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
32
32
|
mod
|
|
33
33
|
));
|
|
34
34
|
|
|
35
|
-
// src/config.ts
|
|
36
|
-
import { readFileSync, existsSync } from "fs";
|
|
37
|
-
import { appendFile } from "fs/promises";
|
|
38
|
-
import { resolve, join } from "path";
|
|
39
|
-
import { homedir } from "os";
|
|
40
|
-
function loginCredential() {
|
|
41
|
-
try {
|
|
42
|
-
const p = join(homedir(), ".solongate", "cloud-guard.json");
|
|
43
|
-
if (!existsSync(p)) return {};
|
|
44
|
-
const c2 = JSON.parse(readFileSync(p, "utf-8"));
|
|
45
|
-
return c2 && typeof c2 === "object" ? c2 : {};
|
|
46
|
-
} catch {
|
|
47
|
-
return {};
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
async function fetchCloudPolicy(apiKey, apiUrl, policyId) {
|
|
51
|
-
let resolvedId = policyId;
|
|
52
|
-
if (!resolvedId) {
|
|
53
|
-
const listRes = await fetch(`${apiUrl}/api/v1/policies`, {
|
|
54
|
-
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
55
|
-
signal: AbortSignal.timeout(1e4)
|
|
56
|
-
});
|
|
57
|
-
if (!listRes.ok) {
|
|
58
|
-
const body = await listRes.text().catch(() => "");
|
|
59
|
-
throw new Error(`Failed to list policies from cloud (${listRes.status}): ${body}`);
|
|
60
|
-
}
|
|
61
|
-
const listData = await listRes.json();
|
|
62
|
-
const policies = listData.policies ?? [];
|
|
63
|
-
if (policies.length === 0) {
|
|
64
|
-
throw new Error("No policies found in cloud. Create one in the dashboard first.");
|
|
65
|
-
}
|
|
66
|
-
resolvedId = policies[0].id;
|
|
67
|
-
}
|
|
68
|
-
const url = `${apiUrl}/api/v1/policies/${resolvedId}`;
|
|
69
|
-
const res = await fetch(url, {
|
|
70
|
-
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
71
|
-
signal: AbortSignal.timeout(1e4)
|
|
72
|
-
});
|
|
73
|
-
if (!res.ok) {
|
|
74
|
-
const body = await res.text().catch(() => "");
|
|
75
|
-
throw new Error(`Failed to fetch policy from cloud (${res.status}): ${body}`);
|
|
76
|
-
}
|
|
77
|
-
const data = await res.json();
|
|
78
|
-
return {
|
|
79
|
-
id: String(data.id ?? "cloud"),
|
|
80
|
-
name: String(data.name ?? "Cloud Policy"),
|
|
81
|
-
description: String(data.description ?? ""),
|
|
82
|
-
version: Number(data._version ?? 1),
|
|
83
|
-
rules: data.rules ?? [],
|
|
84
|
-
createdAt: String(data._created_at ?? ""),
|
|
85
|
-
updatedAt: ""
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
async function fetchCloudPolicyWasm(apiKey, apiUrl, policyId) {
|
|
89
|
-
try {
|
|
90
|
-
const res = await fetch(`${apiUrl}/api/v1/policies/${policyId}/wasm`, {
|
|
91
|
-
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
92
|
-
signal: AbortSignal.timeout(1e4)
|
|
93
|
-
});
|
|
94
|
-
if (!res.ok) return null;
|
|
95
|
-
return new Uint8Array(await res.arrayBuffer());
|
|
96
|
-
} catch {
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
async function sendAuditLog(apiKey, apiUrl, entry) {
|
|
101
|
-
const url = `${apiUrl}/api/v1/audit-logs`;
|
|
102
|
-
const body = JSON.stringify({
|
|
103
|
-
...entry,
|
|
104
|
-
agent_id: entry.agent_id,
|
|
105
|
-
agent_name: entry.agent_name
|
|
106
|
-
});
|
|
107
|
-
for (let attempt = 0; attempt < AUDIT_MAX_RETRIES; attempt++) {
|
|
108
|
-
try {
|
|
109
|
-
const res = await fetch(url, {
|
|
110
|
-
method: "POST",
|
|
111
|
-
headers: {
|
|
112
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
113
|
-
"Content-Type": "application/json"
|
|
114
|
-
},
|
|
115
|
-
body,
|
|
116
|
-
signal: AbortSignal.timeout(5e3)
|
|
117
|
-
});
|
|
118
|
-
if (res.ok) return;
|
|
119
|
-
if (res.status >= 400 && res.status < 500) {
|
|
120
|
-
const resBody = await res.text().catch(() => "");
|
|
121
|
-
process.stderr.write(`[SolonGate] Audit log rejected (${res.status}): ${resBody}
|
|
122
|
-
`);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
} catch {
|
|
126
|
-
}
|
|
127
|
-
if (attempt < AUDIT_MAX_RETRIES - 1) {
|
|
128
|
-
await new Promise((r) => setTimeout(r, 500 * Math.pow(2, attempt)));
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
process.stderr.write(`[SolonGate] Audit log failed after ${AUDIT_MAX_RETRIES} retries, saving to local backup.
|
|
132
|
-
`);
|
|
133
|
-
try {
|
|
134
|
-
const line = JSON.stringify({ ...entry, timestamp: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
|
|
135
|
-
appendFile(AUDIT_LOG_BACKUP_PATH, line, "utf-8").catch((err2) => {
|
|
136
|
-
process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
|
|
137
|
-
`);
|
|
138
|
-
});
|
|
139
|
-
} catch (err2) {
|
|
140
|
-
process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
|
|
141
|
-
`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
function ensureCatchAllAllow(policy) {
|
|
145
|
-
const hasCatchAllAllow = policy.rules.some(
|
|
146
|
-
(r) => r.effect === "ALLOW" && r.toolPattern === "*" && r.enabled !== false
|
|
147
|
-
);
|
|
148
|
-
if (hasCatchAllAllow) return policy;
|
|
149
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
150
|
-
return {
|
|
151
|
-
...policy,
|
|
152
|
-
rules: [
|
|
153
|
-
...policy.rules,
|
|
154
|
-
{
|
|
155
|
-
id: "_solongate-catch-all-allow",
|
|
156
|
-
description: "Auto-added: allow everything not explicitly denied",
|
|
157
|
-
effect: "ALLOW",
|
|
158
|
-
priority: 9999,
|
|
159
|
-
toolPattern: "*",
|
|
160
|
-
minimumTrustLevel: "UNTRUSTED",
|
|
161
|
-
enabled: true,
|
|
162
|
-
createdAt: now,
|
|
163
|
-
updatedAt: now
|
|
164
|
-
}
|
|
165
|
-
]
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
function loadPolicy(source) {
|
|
169
|
-
let policy;
|
|
170
|
-
if (typeof source === "object") {
|
|
171
|
-
policy = source;
|
|
172
|
-
} else {
|
|
173
|
-
const filePath = resolve(source);
|
|
174
|
-
if (existsSync(filePath)) {
|
|
175
|
-
const content = readFileSync(filePath, "utf-8");
|
|
176
|
-
policy = JSON.parse(content);
|
|
177
|
-
} else {
|
|
178
|
-
return DEFAULT_POLICY;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return ensureCatchAllAllow(policy);
|
|
182
|
-
}
|
|
183
|
-
function parseArgs(argv) {
|
|
184
|
-
const args = argv.slice(2);
|
|
185
|
-
let policySource;
|
|
186
|
-
let name = "solongate-proxy";
|
|
187
|
-
let verbose = false;
|
|
188
|
-
let rateLimitPerTool;
|
|
189
|
-
let globalRateLimit;
|
|
190
|
-
let configFile;
|
|
191
|
-
let apiKey;
|
|
192
|
-
let apiUrl;
|
|
193
|
-
let upstreamUrl;
|
|
194
|
-
let upstreamTransport;
|
|
195
|
-
let port;
|
|
196
|
-
let policyId;
|
|
197
|
-
let agentName;
|
|
198
|
-
let separatorIndex = args.indexOf("--");
|
|
199
|
-
const flags = separatorIndex >= 0 ? args.slice(0, separatorIndex) : args;
|
|
200
|
-
let upstreamArgs = separatorIndex >= 0 ? args.slice(separatorIndex + 1) : [];
|
|
201
|
-
for (let i = 0; i < flags.length; i++) {
|
|
202
|
-
if (!flags[i].startsWith("--")) {
|
|
203
|
-
if (upstreamArgs.length === 0) {
|
|
204
|
-
upstreamArgs.push(...flags.slice(i));
|
|
205
|
-
}
|
|
206
|
-
break;
|
|
207
|
-
}
|
|
208
|
-
switch (flags[i]) {
|
|
209
|
-
case "--policy":
|
|
210
|
-
policySource = flags[++i];
|
|
211
|
-
break;
|
|
212
|
-
case "--name":
|
|
213
|
-
name = flags[++i];
|
|
214
|
-
break;
|
|
215
|
-
case "--verbose":
|
|
216
|
-
verbose = true;
|
|
217
|
-
break;
|
|
218
|
-
case "--rate-limit":
|
|
219
|
-
rateLimitPerTool = parseInt(flags[++i], 10);
|
|
220
|
-
break;
|
|
221
|
-
case "--global-rate-limit":
|
|
222
|
-
globalRateLimit = parseInt(flags[++i], 10);
|
|
223
|
-
break;
|
|
224
|
-
case "--config":
|
|
225
|
-
configFile = flags[++i];
|
|
226
|
-
break;
|
|
227
|
-
case "--api-key":
|
|
228
|
-
apiKey = flags[++i];
|
|
229
|
-
break;
|
|
230
|
-
case "--api-url":
|
|
231
|
-
apiUrl = flags[++i];
|
|
232
|
-
break;
|
|
233
|
-
case "--upstream-url":
|
|
234
|
-
upstreamUrl = flags[++i];
|
|
235
|
-
break;
|
|
236
|
-
case "--upstream-transport":
|
|
237
|
-
upstreamTransport = flags[++i];
|
|
238
|
-
break;
|
|
239
|
-
case "--port":
|
|
240
|
-
port = parseInt(flags[++i], 10);
|
|
241
|
-
break;
|
|
242
|
-
case "--policy-id":
|
|
243
|
-
case "--id":
|
|
244
|
-
policyId = flags[++i];
|
|
245
|
-
break;
|
|
246
|
-
case "--agent-name":
|
|
247
|
-
agentName = flags[++i];
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
if (apiKey && /^\$\{.+\}$/.test(apiKey)) {
|
|
252
|
-
apiKey = void 0;
|
|
253
|
-
}
|
|
254
|
-
if (!apiKey) {
|
|
255
|
-
const dotenvPath = resolve(".env");
|
|
256
|
-
if (existsSync(dotenvPath)) {
|
|
257
|
-
const dotenvContent = readFileSync(dotenvPath, "utf-8");
|
|
258
|
-
const match = dotenvContent.match(/^SOLONGATE_API_KEY=(sg_(?:live|test)_\w+)/m);
|
|
259
|
-
if (match) apiKey = match[1];
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
if (!apiKey) {
|
|
263
|
-
const envKey = process.env.SOLONGATE_API_KEY;
|
|
264
|
-
if (envKey && !/^\$\{.+\}$/.test(envKey)) {
|
|
265
|
-
apiKey = envKey;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
if (!apiKey) {
|
|
269
|
-
const cred = loginCredential();
|
|
270
|
-
if (cred.apiKey) apiKey = cred.apiKey;
|
|
271
|
-
}
|
|
272
|
-
if (!apiKey) {
|
|
273
|
-
throw new Error(
|
|
274
|
-
"Not logged in. Run this once to get started:\n\n solongate\n\n then add your account from the Accounts panel.\n"
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
if (!apiKey.startsWith("sg_live_") && !apiKey.startsWith("sg_test_")) {
|
|
278
|
-
throw new Error(
|
|
279
|
-
"Invalid API key format. Keys must start with 'sg_live_' or 'sg_test_'.\nGet your API key at https://solongate.com\n"
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
const resolvedPolicyPath = policySource ? resolvePolicyPath(policySource) : null;
|
|
283
|
-
if (configFile) {
|
|
284
|
-
const filePath = resolve(configFile);
|
|
285
|
-
const content = readFileSync(filePath, "utf-8");
|
|
286
|
-
const fileConfig = JSON.parse(content);
|
|
287
|
-
if (!fileConfig.upstream) {
|
|
288
|
-
throw new Error('Config file must include "upstream" with at least "command" or "url"');
|
|
289
|
-
}
|
|
290
|
-
const cfgPolicySource = fileConfig.policy ?? policySource ?? "policy.json";
|
|
291
|
-
return {
|
|
292
|
-
upstream: fileConfig.upstream,
|
|
293
|
-
policy: loadPolicy(cfgPolicySource),
|
|
294
|
-
name: fileConfig.name ?? name,
|
|
295
|
-
verbose: fileConfig.verbose ?? verbose,
|
|
296
|
-
rateLimitPerTool: fileConfig.rateLimitPerTool ?? rateLimitPerTool,
|
|
297
|
-
globalRateLimit: fileConfig.globalRateLimit ?? globalRateLimit,
|
|
298
|
-
apiKey: apiKey ?? fileConfig.apiKey,
|
|
299
|
-
apiUrl: apiUrl ?? fileConfig.apiUrl,
|
|
300
|
-
port: port ?? fileConfig.port,
|
|
301
|
-
policyPath: resolvePolicyPath(cfgPolicySource) ?? void 0,
|
|
302
|
-
policyId: policyId ?? fileConfig.policyId,
|
|
303
|
-
agentName
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
if (upstreamUrl) {
|
|
307
|
-
const transport = upstreamTransport ?? (upstreamUrl.includes("/sse") ? "sse" : "http");
|
|
308
|
-
return {
|
|
309
|
-
upstream: {
|
|
310
|
-
transport,
|
|
311
|
-
command: "",
|
|
312
|
-
// not used for URL-based transports
|
|
313
|
-
url: upstreamUrl
|
|
314
|
-
},
|
|
315
|
-
policy: loadPolicy(policySource ?? "policy.json"),
|
|
316
|
-
name,
|
|
317
|
-
verbose,
|
|
318
|
-
rateLimitPerTool,
|
|
319
|
-
globalRateLimit,
|
|
320
|
-
apiKey,
|
|
321
|
-
apiUrl,
|
|
322
|
-
port,
|
|
323
|
-
policyPath: resolvedPolicyPath ?? void 0,
|
|
324
|
-
policyId,
|
|
325
|
-
agentName
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
if (upstreamArgs.length === 0) {
|
|
329
|
-
throw new Error(
|
|
330
|
-
"No upstream server command provided.\n\nIf you just want to get started, run:\n solongate\n"
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
const [command, ...commandArgs] = upstreamArgs;
|
|
334
|
-
return {
|
|
335
|
-
upstream: {
|
|
336
|
-
transport: upstreamTransport ?? "stdio",
|
|
337
|
-
command,
|
|
338
|
-
args: commandArgs,
|
|
339
|
-
env: { PATH: process.env.PATH ?? "", HOME: process.env.HOME ?? "", USERPROFILE: process.env.USERPROFILE ?? "" }
|
|
340
|
-
},
|
|
341
|
-
policy: loadPolicy(policySource ?? "policy.json"),
|
|
342
|
-
name,
|
|
343
|
-
verbose,
|
|
344
|
-
rateLimitPerTool,
|
|
345
|
-
globalRateLimit,
|
|
346
|
-
apiKey,
|
|
347
|
-
apiUrl,
|
|
348
|
-
port,
|
|
349
|
-
policyPath: resolvedPolicyPath ?? void 0,
|
|
350
|
-
policyId,
|
|
351
|
-
agentName
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
function resolvePolicyPath(source) {
|
|
355
|
-
const filePath = resolve(source);
|
|
356
|
-
if (existsSync(filePath)) return filePath;
|
|
357
|
-
return null;
|
|
358
|
-
}
|
|
359
|
-
var DEFAULT_API_URL, AUDIT_MAX_RETRIES, AUDIT_LOG_BACKUP_PATH, DEFAULT_POLICY;
|
|
360
|
-
var init_config = __esm({
|
|
361
|
-
"src/config.ts"() {
|
|
362
|
-
"use strict";
|
|
363
|
-
DEFAULT_API_URL = "https://api.solongate.com";
|
|
364
|
-
AUDIT_MAX_RETRIES = 3;
|
|
365
|
-
AUDIT_LOG_BACKUP_PATH = resolve(".solongate-audit-backup.jsonl");
|
|
366
|
-
DEFAULT_POLICY = {
|
|
367
|
-
id: "default",
|
|
368
|
-
name: "Default (Allow All)",
|
|
369
|
-
description: "Allows all tools by default. Add DENY rules from the dashboard to restrict.",
|
|
370
|
-
version: 1,
|
|
371
|
-
rules: [
|
|
372
|
-
{
|
|
373
|
-
id: "_default-allow-all",
|
|
374
|
-
description: "Allow all tools by default",
|
|
375
|
-
effect: "ALLOW",
|
|
376
|
-
priority: 9999,
|
|
377
|
-
toolPattern: "*",
|
|
378
|
-
minimumTrustLevel: "UNTRUSTED",
|
|
379
|
-
enabled: true,
|
|
380
|
-
createdAt: "",
|
|
381
|
-
updatedAt: ""
|
|
382
|
-
}
|
|
383
|
-
],
|
|
384
|
-
createdAt: "",
|
|
385
|
-
updatedAt: ""
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
|
|
390
35
|
// ../../node_modules/.pnpm/@open-policy-agent+opa-wasm@1.10.0/node_modules/@open-policy-agent/opa-wasm/src/builtins/json.js
|
|
391
36
|
var require_json = __commonJS({
|
|
392
37
|
"../../node_modules/.pnpm/@open-policy-agent+opa-wasm@1.10.0/node_modules/@open-policy-agent/opa-wasm/src/builtins/json.js"(exports, module) {
|
|
@@ -3398,12 +3043,12 @@ ${ctx.indent}`;
|
|
|
3398
3043
|
for (const {
|
|
3399
3044
|
format,
|
|
3400
3045
|
test,
|
|
3401
|
-
resolve:
|
|
3046
|
+
resolve: resolve6
|
|
3402
3047
|
} of tags) {
|
|
3403
3048
|
if (test) {
|
|
3404
3049
|
const match = str.match(test);
|
|
3405
3050
|
if (match) {
|
|
3406
|
-
let res =
|
|
3051
|
+
let res = resolve6.apply(null, match);
|
|
3407
3052
|
if (!(res instanceof Scalar)) res = new Scalar(res);
|
|
3408
3053
|
if (format) res.format = format;
|
|
3409
3054
|
return res;
|
|
@@ -6610,9 +6255,9 @@ async function fetchLatest() {
|
|
|
6610
6255
|
function spawnGlobalInstall(version) {
|
|
6611
6256
|
try {
|
|
6612
6257
|
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6613
|
-
const
|
|
6258
|
+
const log3 = openSync(LOG_FILE, "a");
|
|
6614
6259
|
const p = spawn("npm", ["install", "-g", `${PKG}@${version}`], {
|
|
6615
|
-
stdio: ["ignore",
|
|
6260
|
+
stdio: ["ignore", log3, log3],
|
|
6616
6261
|
detached: true,
|
|
6617
6262
|
windowsHide: true,
|
|
6618
6263
|
shell: process.platform === "win32"
|
|
@@ -6626,7 +6271,7 @@ function spawnGlobalInstall(version) {
|
|
|
6626
6271
|
}
|
|
6627
6272
|
}
|
|
6628
6273
|
function runGlobalInstall(version) {
|
|
6629
|
-
return new Promise((
|
|
6274
|
+
return new Promise((resolve6) => {
|
|
6630
6275
|
try {
|
|
6631
6276
|
mkdirSync3(join4(homedir2(), ".solongate"), { recursive: true });
|
|
6632
6277
|
execFile(
|
|
@@ -6641,11 +6286,11 @@ ${stderr}
|
|
|
6641
6286
|
`, { flag: "a" });
|
|
6642
6287
|
} catch {
|
|
6643
6288
|
}
|
|
6644
|
-
|
|
6289
|
+
resolve6(!err2);
|
|
6645
6290
|
}
|
|
6646
6291
|
);
|
|
6647
6292
|
} catch {
|
|
6648
|
-
|
|
6293
|
+
resolve6(false);
|
|
6649
6294
|
}
|
|
6650
6295
|
});
|
|
6651
6296
|
}
|
|
@@ -6760,11 +6405,11 @@ function startLogsServerDaemon() {
|
|
|
6760
6405
|
}
|
|
6761
6406
|
try {
|
|
6762
6407
|
mkdirSync4(DIR, { recursive: true });
|
|
6763
|
-
const
|
|
6408
|
+
const log3 = openSync2(LOG_FILE2, "a");
|
|
6764
6409
|
const cli = join5(dirname2(fileURLToPath2(import.meta.url)), "index.js");
|
|
6765
6410
|
const p = spawn2(process.execPath, [cli, "logs-server"], {
|
|
6766
6411
|
detached: true,
|
|
6767
|
-
stdio: ["ignore",
|
|
6412
|
+
stdio: ["ignore", log3, log3],
|
|
6768
6413
|
windowsHide: true
|
|
6769
6414
|
});
|
|
6770
6415
|
p.on("error", () => {
|
|
@@ -6826,7 +6471,7 @@ function loadConfig() {
|
|
|
6826
6471
|
return cached;
|
|
6827
6472
|
}
|
|
6828
6473
|
var cached;
|
|
6829
|
-
var
|
|
6474
|
+
var init_config = __esm({
|
|
6830
6475
|
"src/tui/config.ts"() {
|
|
6831
6476
|
"use strict";
|
|
6832
6477
|
cached = null;
|
|
@@ -6881,7 +6526,7 @@ var accent, theme;
|
|
|
6881
6526
|
var init_theme = __esm({
|
|
6882
6527
|
"src/tui/theme.ts"() {
|
|
6883
6528
|
"use strict";
|
|
6884
|
-
|
|
6529
|
+
init_config();
|
|
6885
6530
|
accent = loadConfig().accent;
|
|
6886
6531
|
theme = {
|
|
6887
6532
|
accent: accent || "white",
|
|
@@ -7071,21 +6716,21 @@ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSy
|
|
|
7071
6716
|
import { resolve as resolve3, join as join8 } from "path";
|
|
7072
6717
|
import { homedir as homedir6 } from "os";
|
|
7073
6718
|
function listAccounts() {
|
|
7074
|
-
let
|
|
6719
|
+
let list5 = [];
|
|
7075
6720
|
try {
|
|
7076
6721
|
const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
|
|
7077
|
-
if (Array.isArray(raw))
|
|
6722
|
+
if (Array.isArray(raw)) list5 = raw.filter((a) => a && typeof a.apiKey === "string");
|
|
7078
6723
|
} catch {
|
|
7079
6724
|
}
|
|
7080
6725
|
const active2 = loginCredentialFile();
|
|
7081
|
-
if (active2.apiKey && !
|
|
7082
|
-
|
|
6726
|
+
if (active2.apiKey && !list5.some((a) => a.apiKey === active2.apiKey)) {
|
|
6727
|
+
list5.unshift({ apiKey: active2.apiKey, apiUrl: active2.apiUrl || DEFAULT_API_URL2 });
|
|
7083
6728
|
}
|
|
7084
|
-
return
|
|
6729
|
+
return list5;
|
|
7085
6730
|
}
|
|
7086
6731
|
function saveAccount(acc) {
|
|
7087
6732
|
try {
|
|
7088
|
-
const
|
|
6733
|
+
const list5 = (() => {
|
|
7089
6734
|
try {
|
|
7090
6735
|
const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
|
|
7091
6736
|
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
@@ -7093,7 +6738,7 @@ function saveAccount(acc) {
|
|
|
7093
6738
|
return [];
|
|
7094
6739
|
}
|
|
7095
6740
|
})();
|
|
7096
|
-
const next =
|
|
6741
|
+
const next = list5.filter((a) => a.apiKey !== acc.apiKey);
|
|
7097
6742
|
next.unshift({ ...acc, addedAt: acc.addedAt ?? Date.now() });
|
|
7098
6743
|
mkdirSync5(join8(homedir6(), ".solongate"), { recursive: true });
|
|
7099
6744
|
writeFileSync6(accountsFile(), JSON.stringify(next, null, 2));
|
|
@@ -7102,7 +6747,7 @@ function saveAccount(acc) {
|
|
|
7102
6747
|
}
|
|
7103
6748
|
function removeAccount(apiKey) {
|
|
7104
6749
|
try {
|
|
7105
|
-
const
|
|
6750
|
+
const list5 = (() => {
|
|
7106
6751
|
try {
|
|
7107
6752
|
const raw = JSON.parse(readFileSync8(accountsFile(), "utf-8"));
|
|
7108
6753
|
return Array.isArray(raw) ? raw.filter((a) => a && a.apiKey) : [];
|
|
@@ -7110,7 +6755,7 @@ function removeAccount(apiKey) {
|
|
|
7110
6755
|
return [];
|
|
7111
6756
|
}
|
|
7112
6757
|
})();
|
|
7113
|
-
writeFileSync6(accountsFile(), JSON.stringify(
|
|
6758
|
+
writeFileSync6(accountsFile(), JSON.stringify(list5.filter((a) => a.apiKey !== apiKey), null, 2));
|
|
7114
6759
|
} catch {
|
|
7115
6760
|
}
|
|
7116
6761
|
}
|
|
@@ -7846,7 +7491,7 @@ function LivePanel({ active: active2 }) {
|
|
|
7846
7491
|
const [localBuf, setLocalBuf] = useState2([]);
|
|
7847
7492
|
const [localOn, setLocalOn] = useState2(null);
|
|
7848
7493
|
const [ring, setRing] = useState2(null);
|
|
7849
|
-
const [
|
|
7494
|
+
const [log3, setLog] = useState2([]);
|
|
7850
7495
|
const [filter, setFilter] = useState2("all");
|
|
7851
7496
|
const [signal, setSignal] = useState2("none");
|
|
7852
7497
|
const [search, setSearch] = useState2("");
|
|
@@ -8449,9 +8094,9 @@ function LivePanel({ active: active2 }) {
|
|
|
8449
8094
|
const allHits = ins.dlpByPattern ?? [];
|
|
8450
8095
|
const maxHit = allHits[0]?.count ?? 1;
|
|
8451
8096
|
const L = [];
|
|
8452
|
-
const
|
|
8453
|
-
const blank = () =>
|
|
8454
|
-
const section = (label, m, note) =>
|
|
8097
|
+
const push = (el) => L.push(/* @__PURE__ */ jsx2(Box2, { children: el }, L.length));
|
|
8098
|
+
const blank = () => push(/* @__PURE__ */ jsx2(Text2, { children: " " }));
|
|
8099
|
+
const section = (label, m, note) => push(
|
|
8455
8100
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8456
8101
|
/* @__PURE__ */ jsxs2(Text2, { bold: true, color: theme.accentBright, children: [
|
|
8457
8102
|
"\u258E",
|
|
@@ -8461,7 +8106,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8461
8106
|
note ? /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: note }) : null
|
|
8462
8107
|
] })
|
|
8463
8108
|
);
|
|
8464
|
-
const kv = (k, v) =>
|
|
8109
|
+
const kv = (k, v) => push(
|
|
8465
8110
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8466
8111
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: (" " + k).padEnd(16) }),
|
|
8467
8112
|
v
|
|
@@ -8470,18 +8115,18 @@ function LivePanel({ active: active2 }) {
|
|
|
8470
8115
|
section("RATELIMIT", rl?.mode, rl?.mode === "block" ? "over-limit calls are DENIED" : rl?.mode === "detect" ? "over-limit calls are observed & flagged rl:yes" : "no limit enforcement");
|
|
8471
8116
|
kv("limits", /* @__PURE__ */ jsx2(Text2, { children: rl?.perMinute || rl?.perHour || rl?.perDay ? `${rl?.perMinute || "\u2014"}/min \xB7 ${rl?.perHour || "\u2014"}/hour \xB7 ${rl?.perDay || "\u2014"}/day` : "none configured" }));
|
|
8472
8117
|
kv("load now", /* @__PURE__ */ jsx2(Text2, { children: `${minuteNow} calls in the last 60s` }));
|
|
8473
|
-
if (rl?.perMinute)
|
|
8118
|
+
if (rl?.perMinute) push(/* @__PURE__ */ jsx2(HBar, { label: " load/min", value: minuteNow, max: rl.perMinute, width: barW, color: minuteNow > rl.perMinute ? theme.bad : theme.accent }));
|
|
8474
8119
|
kv("bursts", /* @__PURE__ */ jsx2(Text2, { color: burstsInBuf ? theme.warn : theme.dim, children: `${burstsInBuf} flagged in the live buffer` }));
|
|
8475
8120
|
blank();
|
|
8476
8121
|
section("DLP", dl?.mode, dl?.mode === "block" ? "secrets in arguments are DENIED + redacted" : dl?.mode === "detect" ? "secrets observed & flagged dlp:yes, output redacted" : "no secret scanning");
|
|
8477
8122
|
kv("hits", /* @__PURE__ */ jsx2(Text2, { color: dlpInBuf ? theme.bad : theme.dim, children: `${dlpInBuf} flagged in the live buffer` }));
|
|
8478
8123
|
const builtin = dl?.patterns ?? [];
|
|
8479
8124
|
kv("builtin", /* @__PURE__ */ jsx2(Text2, { children: builtin.length ? `${builtin.length} patterns enabled` : "none enabled" }));
|
|
8480
|
-
for (const line of wrapLines(builtin.join(" \xB7 "), Math.max(20, innerW - 18)))
|
|
8125
|
+
for (const line of wrapLines(builtin.join(" \xB7 "), Math.max(20, innerW - 18))) push(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
|
|
8481
8126
|
const custom = dl?.custom ?? [];
|
|
8482
8127
|
kv("custom", /* @__PURE__ */ jsx2(Text2, { children: custom.length ? `${custom.length} patterns` : "none" }));
|
|
8483
8128
|
for (const c2 of custom)
|
|
8484
|
-
|
|
8129
|
+
push(
|
|
8485
8130
|
/* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8486
8131
|
/* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: " " }),
|
|
8487
8132
|
/* @__PURE__ */ jsx2(Text2, { color: theme.accent, children: truncate2(c2.name ?? "custom", 24).padEnd(25) }),
|
|
@@ -8489,12 +8134,12 @@ function LivePanel({ active: active2 }) {
|
|
|
8489
8134
|
] })
|
|
8490
8135
|
);
|
|
8491
8136
|
kv("pattern hits", /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: allHits.length ? "last 7 days" : "none in the last 7 days" }));
|
|
8492
|
-
for (const h of allHits)
|
|
8137
|
+
for (const h of allHits) push(/* @__PURE__ */ jsx2(HBar, { label: " " + truncate2(h.pattern, 10), value: h.count, max: maxHit, width: barW, color: theme.bad }));
|
|
8493
8138
|
blank();
|
|
8494
8139
|
section("GHOST", gh?.mode, gh?.mode === "on" ? "matching paths are hidden from agents" : "no hidden paths");
|
|
8495
8140
|
const ghostPats = gh?.patterns ?? [];
|
|
8496
8141
|
kv("patterns", /* @__PURE__ */ jsx2(Text2, { children: ghostPats.length ? `${ghostPats.length}` : "none" }));
|
|
8497
|
-
for (const line of wrapLines(ghostPats.join(" \xB7 "), Math.max(20, innerW - 18)))
|
|
8142
|
+
for (const line of wrapLines(ghostPats.join(" \xB7 "), Math.max(20, innerW - 18))) push(/* @__PURE__ */ jsx2(Text2, { wrap: "truncate", color: theme.dim, children: " " + line }));
|
|
8498
8143
|
blank();
|
|
8499
8144
|
section("GUARD", guard.data ? guard.data.up_to_date ? "ok" : "stale" : "?", "the PreToolUse hook enforcing all of the above");
|
|
8500
8145
|
kv(
|
|
@@ -8690,7 +8335,7 @@ function LivePanel({ active: active2 }) {
|
|
|
8690
8335
|
] }),
|
|
8691
8336
|
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", width: colW, overflow: "hidden", children: [
|
|
8692
8337
|
/* @__PURE__ */ jsx2(PaneTitle, { label: "EVENT LOG", extra: "system heartbeat", width: colW }),
|
|
8693
|
-
|
|
8338
|
+
log3.slice(-(colH - 1)).map((l, i) => /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", children: [
|
|
8694
8339
|
/* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
|
|
8695
8340
|
hhmmss(l.ts),
|
|
8696
8341
|
" "
|
|
@@ -8733,7 +8378,7 @@ var init_Live = __esm({
|
|
|
8733
8378
|
"use strict";
|
|
8734
8379
|
init_local_log();
|
|
8735
8380
|
init_api_client();
|
|
8736
|
-
|
|
8381
|
+
init_config();
|
|
8737
8382
|
init_notify();
|
|
8738
8383
|
init_hooks();
|
|
8739
8384
|
init_components();
|
|
@@ -8807,8 +8452,8 @@ function requestDryRun(policyId) {
|
|
|
8807
8452
|
pendingPolicyId = policyId;
|
|
8808
8453
|
}
|
|
8809
8454
|
function DryRunPanel({ focused }) {
|
|
8810
|
-
const
|
|
8811
|
-
const policies =
|
|
8455
|
+
const list5 = useLoader(() => api.policies.list());
|
|
8456
|
+
const policies = list5.data?.policies ?? [];
|
|
8812
8457
|
const [pi, setPi] = useState3(0);
|
|
8813
8458
|
const [limit, setLimit] = useState3(DEFAULT_LIMIT);
|
|
8814
8459
|
const [editLogs, setEditLogs] = useState3(null);
|
|
@@ -8863,7 +8508,7 @@ function DryRunPanel({ focused }) {
|
|
|
8863
8508
|
const w = Math.max(40, cols);
|
|
8864
8509
|
const lines = [];
|
|
8865
8510
|
const head = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: t }, `h${lines.length}`));
|
|
8866
|
-
const
|
|
8511
|
+
const dim2 = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { color: theme.dim, wrap: "truncate", children: t }, `d${lines.length}`));
|
|
8867
8512
|
const row = (t) => lines.push(/* @__PURE__ */ jsx3(Text3, { wrap: "truncate", children: t }, `r${lines.length}`));
|
|
8868
8513
|
const blank = () => lines.push(/* @__PURE__ */ jsx3(Text3, { children: " " }, `b${lines.length}`));
|
|
8869
8514
|
if (res) {
|
|
@@ -8889,7 +8534,7 @@ function DryRunPanel({ focused }) {
|
|
|
8889
8534
|
blank();
|
|
8890
8535
|
if (res.per_rule.length) {
|
|
8891
8536
|
head("Per-rule impact");
|
|
8892
|
-
|
|
8537
|
+
dim2(` ${"RULE".padEnd(38)}${"MATCHED".padEnd(9)}${"%".padEnd(8)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
|
|
8893
8538
|
for (const r of res.per_rule.slice(0, 30)) {
|
|
8894
8539
|
row(` ${truncate2(r.rule_id, 36).padEnd(38)}${String(r.matched).padEnd(9)}${pct(r.matched, s.evaluated).padEnd(8)}${String(r.newly_blocked).padEnd(9)}${r.newly_allowed}`);
|
|
8895
8540
|
}
|
|
@@ -8897,7 +8542,7 @@ function DryRunPanel({ focused }) {
|
|
|
8897
8542
|
}
|
|
8898
8543
|
if (res.per_agent.length) {
|
|
8899
8544
|
head("Per-agent impact");
|
|
8900
|
-
|
|
8545
|
+
dim2(` ${"AGENT".padEnd(24)}${"EVALUATED".padEnd(11)}${"CHANGED".padEnd(9)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
|
|
8901
8546
|
for (const a of res.per_agent) {
|
|
8902
8547
|
row(` ${truncate2(a.agent || "-", 22).padEnd(24)}${String(a.evaluated).padEnd(11)}${String(a.changed).padEnd(9)}${String(a.newly_blocked).padEnd(9)}${a.newly_allowed}`);
|
|
8903
8548
|
}
|
|
@@ -8905,7 +8550,7 @@ function DryRunPanel({ focused }) {
|
|
|
8905
8550
|
}
|
|
8906
8551
|
if (res.per_tool.length) {
|
|
8907
8552
|
head("Per-tool breakdown");
|
|
8908
|
-
|
|
8553
|
+
dim2(` ${"TOOL".padEnd(24)}${"EVALUATED".padEnd(11)}${"CHANGED".padEnd(9)}${"NEW-BLK".padEnd(9)}NEW-ALW`);
|
|
8909
8554
|
for (const t of res.per_tool) {
|
|
8910
8555
|
row(` ${truncate2(t.tool || "-", 22).padEnd(24)}${String(t.evaluated).padEnd(11)}${String(t.changed).padEnd(9)}${String(t.newly_blocked).padEnd(9)}${t.newly_allowed}`);
|
|
8911
8556
|
}
|
|
@@ -8935,7 +8580,7 @@ function DryRunPanel({ focused }) {
|
|
|
8935
8580
|
const win = lines.slice(start, start + budget);
|
|
8936
8581
|
const above = start;
|
|
8937
8582
|
const below = Math.max(0, lines.length - (start + budget));
|
|
8938
|
-
return /* @__PURE__ */ jsx3(DataView, { loading:
|
|
8583
|
+
return /* @__PURE__ */ jsx3(DataView, { loading: list5.loading && !list5.data, error: list5.error, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
8939
8584
|
/* @__PURE__ */ jsx3(Text3, { bold: true, color: theme.accentBright, children: "Policy Dry Run" }),
|
|
8940
8585
|
/* @__PURE__ */ jsxs3(Text3, { wrap: "truncate", children: [
|
|
8941
8586
|
/* @__PURE__ */ jsx3(Text3, { color: theme.dim, children: " policy " }),
|
|
@@ -9014,8 +8659,8 @@ function ruleSummary(r) {
|
|
|
9014
8659
|
return bits.join(" ");
|
|
9015
8660
|
}
|
|
9016
8661
|
function PoliciesPanel({ focused }) {
|
|
9017
|
-
const
|
|
9018
|
-
const policies =
|
|
8662
|
+
const list5 = useLoader(() => api.policies.list());
|
|
8663
|
+
const policies = list5.data?.policies ?? [];
|
|
9019
8664
|
const activeQ = useLoader(() => api.policies.active());
|
|
9020
8665
|
const activeId = activeQ.data?.policy?.id ?? null;
|
|
9021
8666
|
const activeBy = activeQ.data?.matched_by;
|
|
@@ -9041,7 +8686,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9041
8686
|
}
|
|
9042
8687
|
}, [detail.data]);
|
|
9043
8688
|
usePoll(() => {
|
|
9044
|
-
|
|
8689
|
+
list5.reloadQuiet();
|
|
9045
8690
|
activeQ.reloadQuiet();
|
|
9046
8691
|
}, 3e3);
|
|
9047
8692
|
const mutate = (nextRules, nextMode = mode) => {
|
|
@@ -9065,7 +8710,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9065
8710
|
setRules(res.rules);
|
|
9066
8711
|
setDirty(false);
|
|
9067
8712
|
setStatus("\u2713 Saved");
|
|
9068
|
-
|
|
8713
|
+
list5.reload();
|
|
9069
8714
|
} catch (e) {
|
|
9070
8715
|
setStatus("\u2717 " + (e instanceof Error ? e.message : String(e)));
|
|
9071
8716
|
}
|
|
@@ -9086,14 +8731,14 @@ function PoliciesPanel({ focused }) {
|
|
|
9086
8731
|
setStatus("Creating\u2026");
|
|
9087
8732
|
void api.policies.create({ id: `policy-${Date.now()}`, name: n, rules: [], mode: "denylist" }).then(() => {
|
|
9088
8733
|
setStatus(`\u2713 created "${n}" - open it and press n to add rules`);
|
|
9089
|
-
|
|
8734
|
+
list5.reload();
|
|
9090
8735
|
}).catch((e) => setStatus("\u2717 " + (e instanceof Error ? e.message : String(e))));
|
|
9091
8736
|
}
|
|
9092
8737
|
useInput3(
|
|
9093
8738
|
(input, key) => {
|
|
9094
8739
|
if (creating !== null) return;
|
|
9095
8740
|
if (key.ctrl && input === "r" && !editing) {
|
|
9096
|
-
|
|
8741
|
+
list5.reload();
|
|
9097
8742
|
activeQ.reload();
|
|
9098
8743
|
detail.reload();
|
|
9099
8744
|
setStatus(`\u27F3 refreshed ${(/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false })}`);
|
|
@@ -9189,7 +8834,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9189
8834
|
const lWin = policies.slice(lStart, lStart + lBudget);
|
|
9190
8835
|
const lAbove = lStart;
|
|
9191
8836
|
const lBelow = Math.max(0, policies.length - (lStart + lBudget));
|
|
9192
|
-
return /* @__PURE__ */ jsx4(DataView, { loading:
|
|
8837
|
+
return /* @__PURE__ */ jsx4(DataView, { loading: list5.loading && !list5.data, error: list5.error, empty: !!list5.data && policies.length === 0, emptyText: "No policies.", children: /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
9193
8838
|
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
9194
8839
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "active: " }),
|
|
9195
8840
|
activeQ.loading && !activeQ.data ? /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: "\u2026" }) : activeName ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
@@ -9248,8 +8893,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9248
8893
|
{ header: "ON", width: 2 },
|
|
9249
8894
|
{ header: "EFFECT", width: 7 },
|
|
9250
8895
|
{ header: "PRIO", width: 4 },
|
|
9251
|
-
{ header: "
|
|
9252
|
-
{ header: "DESCRIPTION", width: 30 },
|
|
8896
|
+
{ header: "DESCRIPTION", width: 38 },
|
|
9253
8897
|
{ header: "CONSTRAINTS", width: 14 }
|
|
9254
8898
|
],
|
|
9255
8899
|
rows: rWin.map((r, wi) => {
|
|
@@ -9259,8 +8903,7 @@ function PoliciesPanel({ focused }) {
|
|
|
9259
8903
|
{ value: r.enabled ? "\u25CF" : "\u25CB", color: r.enabled ? theme.ok : theme.dim },
|
|
9260
8904
|
{ value: r.effect, color: r.effect === "ALLOW" ? theme.ok : theme.bad, dim: !r.enabled },
|
|
9261
8905
|
{ value: String(r.priority), dim: true },
|
|
9262
|
-
{ value: truncate2(r.
|
|
9263
|
-
{ value: truncate2(r.description || "-", 30), dim: !r.enabled },
|
|
8906
|
+
{ value: truncate2(r.description || "-", 38), dim: !r.enabled },
|
|
9264
8907
|
{ value: ruleSummary(r) || "-", dim: true }
|
|
9265
8908
|
];
|
|
9266
8909
|
})
|
|
@@ -11418,9 +11061,9 @@ function App() {
|
|
|
11418
11061
|
viewAccount(accounts[(acctIdx + 1) % accounts.length]);
|
|
11419
11062
|
};
|
|
11420
11063
|
const syncAccounts = () => {
|
|
11421
|
-
const
|
|
11422
|
-
setAccounts(
|
|
11423
|
-
const next =
|
|
11064
|
+
const list5 = listAccounts();
|
|
11065
|
+
setAccounts(list5);
|
|
11066
|
+
const next = list5.find((a) => a.apiKey === viewKey) ?? list5[0];
|
|
11424
11067
|
setViewCredentials(next ? { apiKey: next.apiKey, apiUrl: next.apiUrl } : null);
|
|
11425
11068
|
setViewKey(next?.apiKey);
|
|
11426
11069
|
setViewNonce((n) => n + 1);
|
|
@@ -11755,8 +11398,8 @@ async function run(argv) {
|
|
|
11755
11398
|
case "deny": {
|
|
11756
11399
|
const effect = sub === "allow" ? "ALLOW" : "DENY";
|
|
11757
11400
|
const id = positionals[1];
|
|
11758
|
-
if (!id) return err(` Usage: policy ${sub} <id>
|
|
11759
|
-
const toolPattern =
|
|
11401
|
+
if (!id) return err(` Usage: policy ${sub} <id> [--command|--path|--url <val>]`), 1;
|
|
11402
|
+
const toolPattern = "*";
|
|
11760
11403
|
let kind = "tool";
|
|
11761
11404
|
let value;
|
|
11762
11405
|
for (const k of ["command", "path", "url"]) {
|
|
@@ -11839,11 +11482,10 @@ async function run(argv) {
|
|
|
11839
11482
|
function printRules(rules) {
|
|
11840
11483
|
if (rules.length === 0) return void err(dim(" (no rules)"));
|
|
11841
11484
|
table(
|
|
11842
|
-
["EFFECT", "PRIO", "
|
|
11485
|
+
["EFFECT", "PRIO", "ID", "DESCRIPTION"],
|
|
11843
11486
|
rules.map((r) => [
|
|
11844
11487
|
r.effect === "ALLOW" ? green("ALLOW") : decisionColor2("DENY"),
|
|
11845
11488
|
String(r.priority),
|
|
11846
|
-
cyan(truncate3(r.toolPattern, 24)),
|
|
11847
11489
|
dim(r.id),
|
|
11848
11490
|
truncate3(r.description || "-", 40)
|
|
11849
11491
|
])
|
|
@@ -11867,8 +11509,8 @@ var init_policy = __esm({
|
|
|
11867
11509
|
USAGE = usage("solongate policy", "manage cloud policies", [
|
|
11868
11510
|
["policy list", "list all policies"],
|
|
11869
11511
|
["policy show <id>", "show one policy (rules, mode)"],
|
|
11870
|
-
["policy allow <id>
|
|
11871
|
-
["policy deny <id>
|
|
11512
|
+
["policy allow <id> [--command|--path|--url <val>]", "append an ALLOW rule"],
|
|
11513
|
+
["policy deny <id> [--command|--path|--url <val>]", "append a DENY rule"],
|
|
11872
11514
|
["policy revoke <id> <ruleId>", "remove a rule"],
|
|
11873
11515
|
["policy active", "show the resolved active policy"],
|
|
11874
11516
|
["policy activate <id> | --clear", "pin / unpin the active policy"],
|
|
@@ -12196,7 +11838,7 @@ async function runAgents(argv) {
|
|
|
12196
11838
|
const res = await api.agents.live({ limit: flagNum(flags, "limit"), includeDeactivated: flagBool(flags, "all") });
|
|
12197
11839
|
if (json) return printJson(res), 0;
|
|
12198
11840
|
err("");
|
|
12199
|
-
err(`
|
|
11841
|
+
err(` Sessions ${green(String(res.counts.active))} active ${yellow(String(res.counts.idle))} idle ${dim(String(res.counts.deactivated) + " off")}`);
|
|
12200
11842
|
if (!res.agents.length) return err(dim(" No agent sessions.")), 0;
|
|
12201
11843
|
table(
|
|
12202
11844
|
["STATUS", "AGENT", "CALLS", "DENY", "DLP", "TRUST", "CHARACTER"],
|
|
@@ -12216,7 +11858,7 @@ async function runAgent(argv) {
|
|
|
12216
11858
|
const { positionals, flags } = parse(argv);
|
|
12217
11859
|
const json = flagBool(flags, "json");
|
|
12218
11860
|
const id = positionals[0];
|
|
12219
|
-
if (!id) return err(" Usage: solongate
|
|
11861
|
+
if (!id) return err(" Usage: solongate session <id> [--json]"), 1;
|
|
12220
11862
|
const a = await api.agents.get(id);
|
|
12221
11863
|
if (json) return printJson(a), 0;
|
|
12222
11864
|
err("");
|
|
@@ -12571,9 +12213,9 @@ async function dispatch(command, argv) {
|
|
|
12571
12213
|
return run4(argv);
|
|
12572
12214
|
case "audit":
|
|
12573
12215
|
return run5(argv);
|
|
12574
|
-
case "
|
|
12216
|
+
case "sessions":
|
|
12575
12217
|
return runAgents(argv);
|
|
12576
|
-
case "
|
|
12218
|
+
case "session":
|
|
12577
12219
|
return runAgent(argv);
|
|
12578
12220
|
case "doctor":
|
|
12579
12221
|
return run6(argv);
|
|
@@ -12621,7 +12263,7 @@ var init_commands = __esm({
|
|
|
12621
12263
|
init_watch();
|
|
12622
12264
|
init_alerts();
|
|
12623
12265
|
init_webhooks();
|
|
12624
|
-
COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "
|
|
12266
|
+
COMMAND_NAMES = ["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"];
|
|
12625
12267
|
}
|
|
12626
12268
|
});
|
|
12627
12269
|
|
|
@@ -12829,331 +12471,361 @@ var init_logs_server = __esm({
|
|
|
12829
12471
|
LOG_FILENAME = "solongate-audit.jsonl";
|
|
12830
12472
|
DEFAULT_PORT = 8788;
|
|
12831
12473
|
}
|
|
12832
|
-
});
|
|
12833
|
-
|
|
12834
|
-
// src/
|
|
12835
|
-
|
|
12836
|
-
import {
|
|
12837
|
-
import {
|
|
12838
|
-
|
|
12839
|
-
|
|
12840
|
-
|
|
12841
|
-
|
|
12842
|
-
|
|
12843
|
-
|
|
12844
|
-
|
|
12845
|
-
|
|
12846
|
-
|
|
12847
|
-
|
|
12848
|
-
|
|
12849
|
-
|
|
12850
|
-
|
|
12851
|
-
|
|
12852
|
-
|
|
12853
|
-
|
|
12474
|
+
});
|
|
12475
|
+
|
|
12476
|
+
// src/index.ts
|
|
12477
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
12478
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
12479
|
+
import { dirname as dirname4, join as join16 } from "path";
|
|
12480
|
+
|
|
12481
|
+
// src/config.ts
|
|
12482
|
+
import { readFileSync, existsSync } from "fs";
|
|
12483
|
+
import { appendFile } from "fs/promises";
|
|
12484
|
+
import { resolve, join } from "path";
|
|
12485
|
+
import { homedir } from "os";
|
|
12486
|
+
function loginCredential() {
|
|
12487
|
+
try {
|
|
12488
|
+
const p = join(homedir(), ".solongate", "cloud-guard.json");
|
|
12489
|
+
if (!existsSync(p)) return {};
|
|
12490
|
+
const c2 = JSON.parse(readFileSync(p, "utf-8"));
|
|
12491
|
+
return c2 && typeof c2 === "object" ? c2 : {};
|
|
12492
|
+
} catch {
|
|
12493
|
+
return {};
|
|
12494
|
+
}
|
|
12495
|
+
}
|
|
12496
|
+
var DEFAULT_API_URL = "https://api.solongate.com";
|
|
12497
|
+
async function fetchCloudPolicy(apiKey, apiUrl, policyId) {
|
|
12498
|
+
let resolvedId = policyId;
|
|
12499
|
+
if (!resolvedId) {
|
|
12500
|
+
const listRes = await fetch(`${apiUrl}/api/v1/policies`, {
|
|
12501
|
+
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
12502
|
+
signal: AbortSignal.timeout(1e4)
|
|
12503
|
+
});
|
|
12504
|
+
if (!listRes.ok) {
|
|
12505
|
+
const body = await listRes.text().catch(() => "");
|
|
12506
|
+
throw new Error(`Failed to list policies from cloud (${listRes.status}): ${body}`);
|
|
12507
|
+
}
|
|
12508
|
+
const listData = await listRes.json();
|
|
12509
|
+
const policies = listData.policies ?? [];
|
|
12510
|
+
if (policies.length === 0) {
|
|
12511
|
+
throw new Error("No policies found in cloud. Create one in the dashboard first.");
|
|
12512
|
+
}
|
|
12513
|
+
resolvedId = policies[0].id;
|
|
12514
|
+
}
|
|
12515
|
+
const url = `${apiUrl}/api/v1/policies/${resolvedId}`;
|
|
12516
|
+
const res = await fetch(url, {
|
|
12517
|
+
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
12518
|
+
signal: AbortSignal.timeout(1e4)
|
|
12519
|
+
});
|
|
12520
|
+
if (!res.ok) {
|
|
12521
|
+
const body = await res.text().catch(() => "");
|
|
12522
|
+
throw new Error(`Failed to fetch policy from cloud (${res.status}): ${body}`);
|
|
12523
|
+
}
|
|
12524
|
+
const data = await res.json();
|
|
12525
|
+
return {
|
|
12526
|
+
id: String(data.id ?? "cloud"),
|
|
12527
|
+
name: String(data.name ?? "Cloud Policy"),
|
|
12528
|
+
description: String(data.description ?? ""),
|
|
12529
|
+
version: Number(data._version ?? 1),
|
|
12530
|
+
rules: data.rules ?? [],
|
|
12531
|
+
createdAt: String(data._created_at ?? ""),
|
|
12532
|
+
updatedAt: ""
|
|
12533
|
+
};
|
|
12534
|
+
}
|
|
12535
|
+
async function fetchCloudPolicyWasm(apiKey, apiUrl, policyId) {
|
|
12536
|
+
try {
|
|
12537
|
+
const res = await fetch(`${apiUrl}/api/v1/policies/${policyId}/wasm`, {
|
|
12538
|
+
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
12539
|
+
signal: AbortSignal.timeout(1e4)
|
|
12540
|
+
});
|
|
12541
|
+
if (!res.ok) return null;
|
|
12542
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
12543
|
+
} catch {
|
|
12544
|
+
return null;
|
|
12545
|
+
}
|
|
12546
|
+
}
|
|
12547
|
+
var AUDIT_MAX_RETRIES = 3;
|
|
12548
|
+
var AUDIT_LOG_BACKUP_PATH = resolve(".solongate-audit-backup.jsonl");
|
|
12549
|
+
async function sendAuditLog(apiKey, apiUrl, entry) {
|
|
12550
|
+
const url = `${apiUrl}/api/v1/audit-logs`;
|
|
12551
|
+
const body = JSON.stringify({
|
|
12552
|
+
...entry,
|
|
12553
|
+
agent_id: entry.agent_id,
|
|
12554
|
+
agent_name: entry.agent_name
|
|
12555
|
+
});
|
|
12556
|
+
for (let attempt = 0; attempt < AUDIT_MAX_RETRIES; attempt++) {
|
|
12557
|
+
try {
|
|
12558
|
+
const res = await fetch(url, {
|
|
12559
|
+
method: "POST",
|
|
12560
|
+
headers: {
|
|
12561
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
12562
|
+
"Content-Type": "application/json"
|
|
12563
|
+
},
|
|
12564
|
+
body,
|
|
12565
|
+
signal: AbortSignal.timeout(5e3)
|
|
12566
|
+
});
|
|
12567
|
+
if (res.ok) return;
|
|
12568
|
+
if (res.status >= 400 && res.status < 500) {
|
|
12569
|
+
const resBody = await res.text().catch(() => "");
|
|
12570
|
+
process.stderr.write(`[SolonGate] Audit log rejected (${res.status}): ${resBody}
|
|
12571
|
+
`);
|
|
12572
|
+
return;
|
|
12573
|
+
}
|
|
12574
|
+
} catch {
|
|
12575
|
+
}
|
|
12576
|
+
if (attempt < AUDIT_MAX_RETRIES - 1) {
|
|
12577
|
+
await new Promise((r) => setTimeout(r, 500 * Math.pow(2, attempt)));
|
|
12578
|
+
}
|
|
12579
|
+
}
|
|
12580
|
+
process.stderr.write(`[SolonGate] Audit log failed after ${AUDIT_MAX_RETRIES} retries, saving to local backup.
|
|
12581
|
+
`);
|
|
12582
|
+
try {
|
|
12583
|
+
const line = JSON.stringify({ ...entry, timestamp: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
|
|
12584
|
+
appendFile(AUDIT_LOG_BACKUP_PATH, line, "utf-8").catch((err2) => {
|
|
12585
|
+
process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
|
|
12586
|
+
`);
|
|
12587
|
+
});
|
|
12588
|
+
} catch (err2) {
|
|
12589
|
+
process.stderr.write(`[SolonGate] Audit backup write error: ${err2 instanceof Error ? err2.message : String(err2)}
|
|
12590
|
+
`);
|
|
12591
|
+
}
|
|
12592
|
+
}
|
|
12593
|
+
var DEFAULT_POLICY = {
|
|
12594
|
+
id: "default",
|
|
12595
|
+
name: "Default (Allow All)",
|
|
12596
|
+
description: "Allows all tools by default. Add DENY rules from the dashboard to restrict.",
|
|
12597
|
+
version: 1,
|
|
12598
|
+
rules: [
|
|
12599
|
+
{
|
|
12600
|
+
id: "_default-allow-all",
|
|
12601
|
+
description: "Allow all tools by default",
|
|
12602
|
+
effect: "ALLOW",
|
|
12603
|
+
priority: 9999,
|
|
12604
|
+
toolPattern: "*",
|
|
12605
|
+
minimumTrustLevel: "UNTRUSTED",
|
|
12606
|
+
enabled: true,
|
|
12607
|
+
createdAt: "",
|
|
12608
|
+
updatedAt: ""
|
|
12609
|
+
}
|
|
12610
|
+
],
|
|
12611
|
+
createdAt: "",
|
|
12612
|
+
updatedAt: ""
|
|
12613
|
+
};
|
|
12614
|
+
function ensureCatchAllAllow(policy) {
|
|
12615
|
+
const hasCatchAllAllow = policy.rules.some(
|
|
12616
|
+
(r) => r.effect === "ALLOW" && r.toolPattern === "*" && r.enabled !== false
|
|
12617
|
+
);
|
|
12618
|
+
if (hasCatchAllAllow) return policy;
|
|
12619
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12620
|
+
return {
|
|
12621
|
+
...policy,
|
|
12622
|
+
rules: [
|
|
12623
|
+
...policy.rules,
|
|
12624
|
+
{
|
|
12625
|
+
id: "_solongate-catch-all-allow",
|
|
12626
|
+
description: "Auto-added: allow everything not explicitly denied",
|
|
12627
|
+
effect: "ALLOW",
|
|
12628
|
+
priority: 9999,
|
|
12629
|
+
toolPattern: "*",
|
|
12630
|
+
minimumTrustLevel: "UNTRUSTED",
|
|
12631
|
+
enabled: true,
|
|
12632
|
+
createdAt: now,
|
|
12633
|
+
updatedAt: now
|
|
12854
12634
|
}
|
|
12635
|
+
]
|
|
12636
|
+
};
|
|
12637
|
+
}
|
|
12638
|
+
function loadPolicy(source) {
|
|
12639
|
+
let policy;
|
|
12640
|
+
if (typeof source === "object") {
|
|
12641
|
+
policy = source;
|
|
12642
|
+
} else {
|
|
12643
|
+
const filePath = resolve(source);
|
|
12644
|
+
if (existsSync(filePath)) {
|
|
12645
|
+
const content = readFileSync(filePath, "utf-8");
|
|
12646
|
+
policy = JSON.parse(content);
|
|
12647
|
+
} else {
|
|
12648
|
+
return DEFAULT_POLICY;
|
|
12855
12649
|
}
|
|
12856
|
-
} catch {
|
|
12857
12650
|
}
|
|
12651
|
+
return ensureCatchAllAllow(policy);
|
|
12858
12652
|
}
|
|
12859
|
-
function
|
|
12860
|
-
|
|
12861
|
-
|
|
12862
|
-
|
|
12863
|
-
let
|
|
12864
|
-
let
|
|
12653
|
+
function parseArgs(argv) {
|
|
12654
|
+
const args = argv.slice(2);
|
|
12655
|
+
let policySource;
|
|
12656
|
+
let name = "solongate-proxy";
|
|
12657
|
+
let verbose = false;
|
|
12658
|
+
let rateLimitPerTool;
|
|
12659
|
+
let globalRateLimit;
|
|
12660
|
+
let configFile;
|
|
12661
|
+
let apiKey;
|
|
12662
|
+
let apiUrl;
|
|
12663
|
+
let upstreamUrl;
|
|
12664
|
+
let upstreamTransport;
|
|
12665
|
+
let port;
|
|
12865
12666
|
let policyId;
|
|
12866
|
-
|
|
12867
|
-
|
|
12667
|
+
let agentName;
|
|
12668
|
+
let separatorIndex = args.indexOf("--");
|
|
12669
|
+
const flags = separatorIndex >= 0 ? args.slice(0, separatorIndex) : args;
|
|
12670
|
+
let upstreamArgs = separatorIndex >= 0 ? args.slice(separatorIndex + 1) : [];
|
|
12671
|
+
for (let i = 0; i < flags.length; i++) {
|
|
12672
|
+
if (!flags[i].startsWith("--")) {
|
|
12673
|
+
if (upstreamArgs.length === 0) {
|
|
12674
|
+
upstreamArgs.push(...flags.slice(i));
|
|
12675
|
+
}
|
|
12676
|
+
break;
|
|
12677
|
+
}
|
|
12678
|
+
switch (flags[i]) {
|
|
12679
|
+
case "--policy":
|
|
12680
|
+
policySource = flags[++i];
|
|
12681
|
+
break;
|
|
12682
|
+
case "--name":
|
|
12683
|
+
name = flags[++i];
|
|
12684
|
+
break;
|
|
12685
|
+
case "--verbose":
|
|
12686
|
+
verbose = true;
|
|
12687
|
+
break;
|
|
12688
|
+
case "--rate-limit":
|
|
12689
|
+
rateLimitPerTool = parseInt(flags[++i], 10);
|
|
12690
|
+
break;
|
|
12691
|
+
case "--global-rate-limit":
|
|
12692
|
+
globalRateLimit = parseInt(flags[++i], 10);
|
|
12693
|
+
break;
|
|
12694
|
+
case "--config":
|
|
12695
|
+
configFile = flags[++i];
|
|
12696
|
+
break;
|
|
12868
12697
|
case "--api-key":
|
|
12869
|
-
apiKey =
|
|
12698
|
+
apiKey = flags[++i];
|
|
12870
12699
|
break;
|
|
12871
|
-
case "--
|
|
12872
|
-
|
|
12873
|
-
|
|
12874
|
-
case "-
|
|
12875
|
-
|
|
12876
|
-
|
|
12700
|
+
case "--api-url":
|
|
12701
|
+
apiUrl = flags[++i];
|
|
12702
|
+
break;
|
|
12703
|
+
case "--upstream-url":
|
|
12704
|
+
upstreamUrl = flags[++i];
|
|
12705
|
+
break;
|
|
12706
|
+
case "--upstream-transport":
|
|
12707
|
+
upstreamTransport = flags[++i];
|
|
12708
|
+
break;
|
|
12709
|
+
case "--port":
|
|
12710
|
+
port = parseInt(flags[++i], 10);
|
|
12877
12711
|
break;
|
|
12878
12712
|
case "--policy-id":
|
|
12879
12713
|
case "--id":
|
|
12880
|
-
policyId =
|
|
12714
|
+
policyId = flags[++i];
|
|
12715
|
+
break;
|
|
12716
|
+
case "--agent-name":
|
|
12717
|
+
agentName = flags[++i];
|
|
12881
12718
|
break;
|
|
12882
12719
|
}
|
|
12883
12720
|
}
|
|
12721
|
+
if (apiKey && /^\$\{.+\}$/.test(apiKey)) {
|
|
12722
|
+
apiKey = void 0;
|
|
12723
|
+
}
|
|
12884
12724
|
if (!apiKey) {
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
|
|
12890
|
-
|
|
12891
|
-
log3(` SOLONGATE_API_KEY=sg_live_... solongate-proxy ${command}`);
|
|
12892
|
-
process.exit(1);
|
|
12725
|
+
const dotenvPath = resolve(".env");
|
|
12726
|
+
if (existsSync(dotenvPath)) {
|
|
12727
|
+
const dotenvContent = readFileSync(dotenvPath, "utf-8");
|
|
12728
|
+
const match = dotenvContent.match(/^SOLONGATE_API_KEY=(sg_(?:live|test)_\w+)/m);
|
|
12729
|
+
if (match) apiKey = match[1];
|
|
12730
|
+
}
|
|
12893
12731
|
}
|
|
12894
|
-
if (!apiKey
|
|
12895
|
-
|
|
12896
|
-
|
|
12732
|
+
if (!apiKey) {
|
|
12733
|
+
const envKey = process.env.SOLONGATE_API_KEY;
|
|
12734
|
+
if (envKey && !/^\$\{.+\}$/.test(envKey)) {
|
|
12735
|
+
apiKey = envKey;
|
|
12736
|
+
}
|
|
12897
12737
|
}
|
|
12898
|
-
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
const res = await fetch(`${API_URL}/api/v1/policies`, {
|
|
12902
|
-
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
12903
|
-
});
|
|
12904
|
-
if (!res.ok) throw new Error(`Failed to list policies (${res.status})`);
|
|
12905
|
-
const data = await res.json();
|
|
12906
|
-
return data.policies ?? [];
|
|
12907
|
-
}
|
|
12908
|
-
async function list5(apiKey, policyId) {
|
|
12909
|
-
const policies = await listPolicies(apiKey);
|
|
12910
|
-
if (policies.length === 0) {
|
|
12911
|
-
log3(yellow2("No policies found. Create one in the dashboard first."));
|
|
12912
|
-
log3(dim2(" https://dashboard.solongate.com/policies"));
|
|
12913
|
-
return;
|
|
12738
|
+
if (!apiKey) {
|
|
12739
|
+
const cred = loginCredential();
|
|
12740
|
+
if (cred.apiKey) apiKey = cred.apiKey;
|
|
12914
12741
|
}
|
|
12915
|
-
if (
|
|
12916
|
-
|
|
12917
|
-
|
|
12918
|
-
|
|
12919
|
-
log3("");
|
|
12920
|
-
log3("Available policies:");
|
|
12921
|
-
for (const p of policies) {
|
|
12922
|
-
log3(` ${dim2("\u2022")} ${p.id}`);
|
|
12923
|
-
}
|
|
12924
|
-
process.exit(1);
|
|
12925
|
-
}
|
|
12926
|
-
const full = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
12927
|
-
printPolicyDetail(full);
|
|
12928
|
-
return;
|
|
12742
|
+
if (!apiKey) {
|
|
12743
|
+
throw new Error(
|
|
12744
|
+
"Not logged in. Run this once to get started:\n\n solongate\n\n then add your account from the Accounts panel.\n"
|
|
12745
|
+
);
|
|
12929
12746
|
}
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
const fullPolicies = await Promise.all(
|
|
12935
|
-
policies.map(
|
|
12936
|
-
(p) => fetchCloudPolicy(apiKey, API_URL, p.id).then((full) => ({ policy: p, rules: full.rules })).catch(() => ({ policy: p, rules: [] }))
|
|
12937
|
-
)
|
|
12938
|
-
);
|
|
12939
|
-
for (const { policy, rules } of fullPolicies) {
|
|
12940
|
-
printPolicySummary(policy, [...rules]);
|
|
12941
|
-
}
|
|
12942
|
-
log3(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
12943
|
-
log3("");
|
|
12944
|
-
log3(` ${dim2("View details:")} solongate-proxy list --policy-id <ID>`);
|
|
12945
|
-
log3(` ${dim2("Pull policy:")} solongate-proxy pull --policy-id <ID>`);
|
|
12946
|
-
log3(` ${dim2("Push policy:")} solongate-proxy push --policy-id <ID>`);
|
|
12947
|
-
log3("");
|
|
12948
|
-
}
|
|
12949
|
-
function printPolicySummary(p, rules) {
|
|
12950
|
-
const ruleCount = rules.length;
|
|
12951
|
-
const allowCount = rules.filter((r) => r.effect === "ALLOW").length;
|
|
12952
|
-
const denyCount = rules.filter((r) => r.effect === "DENY").length;
|
|
12953
|
-
log3(` ${cyan2(p.id)}`);
|
|
12954
|
-
log3(` ${bold2(p.name)} ${dim2(`v${p.version ?? "?"}`)}`);
|
|
12955
|
-
log3(` ${dim2("Rules:")} ${ruleCount} ${green2(`${allowCount} ALLOW`)} ${red2(`${denyCount} DENY`)}`);
|
|
12956
|
-
if (p.created_at) {
|
|
12957
|
-
log3(` ${dim2("Updated:")} ${new Date(p.created_at).toLocaleString()}`);
|
|
12958
|
-
}
|
|
12959
|
-
log3("");
|
|
12960
|
-
}
|
|
12961
|
-
function printPolicyDetail(policy) {
|
|
12962
|
-
log3("");
|
|
12963
|
-
log3(bold2(` ${policy.name}`));
|
|
12964
|
-
log3(` ${dim2("ID:")} ${cyan2(policy.id)} ${dim2("Version:")} ${policy.version} ${dim2("Rules:")} ${policy.rules.length}`);
|
|
12965
|
-
log3("");
|
|
12966
|
-
if (policy.rules.length === 0) {
|
|
12967
|
-
log3(yellow2(" No rules defined."));
|
|
12968
|
-
log3("");
|
|
12969
|
-
return;
|
|
12747
|
+
if (!apiKey.startsWith("sg_live_") && !apiKey.startsWith("sg_test_")) {
|
|
12748
|
+
throw new Error(
|
|
12749
|
+
"Invalid API key format. Keys must start with 'sg_live_' or 'sg_test_'.\nGet your API key at https://solongate.com\n"
|
|
12750
|
+
);
|
|
12970
12751
|
}
|
|
12971
|
-
|
|
12972
|
-
|
|
12973
|
-
const
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
if (
|
|
12977
|
-
|
|
12978
|
-
}
|
|
12979
|
-
log3(` ${dim2(`${rule.permission} trust:${rule.minimumTrustLevel || "UNTRUSTED"}`)}`);
|
|
12980
|
-
if (rule.pathConstraints) {
|
|
12981
|
-
const pc = rule.pathConstraints;
|
|
12982
|
-
if (pc.rootDirectory) log3(` ${magenta("ROOT")} ${pc.rootDirectory}`);
|
|
12983
|
-
if (pc.allowed?.length) log3(` ${green2("PATHS")} ${pc.allowed.join(", ")}`);
|
|
12984
|
-
if (pc.denied?.length) log3(` ${red2("DENY")} ${pc.denied.join(", ")}`);
|
|
12985
|
-
}
|
|
12986
|
-
if (rule.commandConstraints) {
|
|
12987
|
-
const cc = rule.commandConstraints;
|
|
12988
|
-
if (cc.allowed?.length) log3(` ${green2("CMDS")} ${cc.allowed.join(", ")}`);
|
|
12989
|
-
if (cc.denied?.length) log3(` ${red2("DENY")} ${cc.denied.join(", ")}`);
|
|
12990
|
-
}
|
|
12991
|
-
if (rule.filenameConstraints) {
|
|
12992
|
-
const fc = rule.filenameConstraints;
|
|
12993
|
-
if (fc.allowed?.length) log3(` ${green2("FILES")} ${fc.allowed.join(", ")}`);
|
|
12994
|
-
if (fc.denied?.length) log3(` ${red2("DENY")} ${fc.denied.join(", ")}`);
|
|
12995
|
-
}
|
|
12996
|
-
if (rule.urlConstraints) {
|
|
12997
|
-
const uc = rule.urlConstraints;
|
|
12998
|
-
if (uc.allowed?.length) log3(` ${green2("URLS")} ${uc.allowed.join(", ")}`);
|
|
12999
|
-
if (uc.denied?.length) log3(` ${red2("DENY")} ${uc.denied.join(", ")}`);
|
|
13000
|
-
}
|
|
13001
|
-
}
|
|
13002
|
-
log3("");
|
|
13003
|
-
log3(dim2(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
13004
|
-
log3("");
|
|
13005
|
-
}
|
|
13006
|
-
async function pull(apiKey, file, policyId) {
|
|
13007
|
-
if (!policyId) {
|
|
13008
|
-
const policies = await listPolicies(apiKey);
|
|
13009
|
-
if (policies.length === 0) {
|
|
13010
|
-
log3(red2("No policies found. Create one in the dashboard first."));
|
|
13011
|
-
process.exit(1);
|
|
12752
|
+
const resolvedPolicyPath = policySource ? resolvePolicyPath(policySource) : null;
|
|
12753
|
+
if (configFile) {
|
|
12754
|
+
const filePath = resolve(configFile);
|
|
12755
|
+
const content = readFileSync(filePath, "utf-8");
|
|
12756
|
+
const fileConfig = JSON.parse(content);
|
|
12757
|
+
if (!fileConfig.upstream) {
|
|
12758
|
+
throw new Error('Config file must include "upstream" with at least "command" or "url"');
|
|
13012
12759
|
}
|
|
13013
|
-
|
|
13014
|
-
|
|
13015
|
-
|
|
13016
|
-
|
|
13017
|
-
|
|
13018
|
-
|
|
13019
|
-
|
|
13020
|
-
|
|
13021
|
-
|
|
13022
|
-
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
|
|
13026
|
-
|
|
13027
|
-
|
|
13028
|
-
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
13029
|
-
const { id: _id, ...policyWithoutId } = policy;
|
|
13030
|
-
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
13031
|
-
writeFileSync10(file, json, "utf-8");
|
|
13032
|
-
log3("");
|
|
13033
|
-
log3(green2(" Saved to: ") + file);
|
|
13034
|
-
log3(` ${dim2("Name:")} ${policy.name}`);
|
|
13035
|
-
log3(` ${dim2("Version:")} ${policy.version}`);
|
|
13036
|
-
log3(` ${dim2("Rules:")} ${policy.rules.length}`);
|
|
13037
|
-
log3("");
|
|
13038
|
-
log3(dim2("The policy file does not contain an ID."));
|
|
13039
|
-
log3(dim2("Use --policy-id to specify the target when pushing/pulling."));
|
|
13040
|
-
log3("");
|
|
13041
|
-
}
|
|
13042
|
-
async function push(apiKey, file, policyId) {
|
|
13043
|
-
if (!existsSync7(file)) {
|
|
13044
|
-
log3(red2(`ERROR: File not found: ${file}`));
|
|
13045
|
-
process.exit(1);
|
|
12760
|
+
const cfgPolicySource = fileConfig.policy ?? policySource ?? "policy.json";
|
|
12761
|
+
return {
|
|
12762
|
+
upstream: fileConfig.upstream,
|
|
12763
|
+
policy: loadPolicy(cfgPolicySource),
|
|
12764
|
+
name: fileConfig.name ?? name,
|
|
12765
|
+
verbose: fileConfig.verbose ?? verbose,
|
|
12766
|
+
rateLimitPerTool: fileConfig.rateLimitPerTool ?? rateLimitPerTool,
|
|
12767
|
+
globalRateLimit: fileConfig.globalRateLimit ?? globalRateLimit,
|
|
12768
|
+
apiKey: apiKey ?? fileConfig.apiKey,
|
|
12769
|
+
apiUrl: apiUrl ?? fileConfig.apiUrl,
|
|
12770
|
+
port: port ?? fileConfig.port,
|
|
12771
|
+
policyPath: resolvePolicyPath(cfgPolicySource) ?? void 0,
|
|
12772
|
+
policyId: policyId ?? fileConfig.policyId,
|
|
12773
|
+
agentName
|
|
12774
|
+
};
|
|
13046
12775
|
}
|
|
13047
|
-
if (
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13058
|
-
|
|
12776
|
+
if (upstreamUrl) {
|
|
12777
|
+
const transport = upstreamTransport ?? (upstreamUrl.includes("/sse") ? "sse" : "http");
|
|
12778
|
+
return {
|
|
12779
|
+
upstream: {
|
|
12780
|
+
transport,
|
|
12781
|
+
command: "",
|
|
12782
|
+
// not used for URL-based transports
|
|
12783
|
+
url: upstreamUrl
|
|
12784
|
+
},
|
|
12785
|
+
policy: loadPolicy(policySource ?? "policy.json"),
|
|
12786
|
+
name,
|
|
12787
|
+
verbose,
|
|
12788
|
+
rateLimitPerTool,
|
|
12789
|
+
globalRateLimit,
|
|
12790
|
+
apiKey,
|
|
12791
|
+
apiUrl,
|
|
12792
|
+
port,
|
|
12793
|
+
policyPath: resolvedPolicyPath ?? void 0,
|
|
12794
|
+
policyId,
|
|
12795
|
+
agentName
|
|
12796
|
+
};
|
|
13059
12797
|
}
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
} catch {
|
|
13065
|
-
log3(red2(`ERROR: Invalid JSON in ${file}`));
|
|
13066
|
-
process.exit(1);
|
|
12798
|
+
if (upstreamArgs.length === 0) {
|
|
12799
|
+
throw new Error(
|
|
12800
|
+
"No upstream server command provided.\n\nIf you just want to get started, run:\n solongate\n"
|
|
12801
|
+
);
|
|
13067
12802
|
}
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
const method = checkRes.ok ? "PUT" : "POST";
|
|
13076
|
-
const url = checkRes.ok ? `${API_URL}/api/v1/policies/${policyId}` : `${API_URL}/api/v1/policies`;
|
|
13077
|
-
const res = await fetch(url, {
|
|
13078
|
-
method,
|
|
13079
|
-
headers: {
|
|
13080
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
13081
|
-
"Content-Type": "application/json"
|
|
12803
|
+
const [command, ...commandArgs] = upstreamArgs;
|
|
12804
|
+
return {
|
|
12805
|
+
upstream: {
|
|
12806
|
+
transport: upstreamTransport ?? "stdio",
|
|
12807
|
+
command,
|
|
12808
|
+
args: commandArgs,
|
|
12809
|
+
env: { PATH: process.env.PATH ?? "", HOME: process.env.HOME ?? "", USERPROFILE: process.env.USERPROFILE ?? "" }
|
|
13082
12810
|
},
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
}
|
|
13096
|
-
const data = await res.json();
|
|
13097
|
-
log3("");
|
|
13098
|
-
log3(green2(` Pushed to cloud: v${data._version ?? "created"}`));
|
|
13099
|
-
log3(` ${dim2("Policy ID:")} ${policyId}`);
|
|
13100
|
-
log3(` ${dim2("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
|
|
13101
|
-
log3("");
|
|
12811
|
+
policy: loadPolicy(policySource ?? "policy.json"),
|
|
12812
|
+
name,
|
|
12813
|
+
verbose,
|
|
12814
|
+
rateLimitPerTool,
|
|
12815
|
+
globalRateLimit,
|
|
12816
|
+
apiKey,
|
|
12817
|
+
apiUrl,
|
|
12818
|
+
port,
|
|
12819
|
+
policyPath: resolvedPolicyPath ?? void 0,
|
|
12820
|
+
policyId,
|
|
12821
|
+
agentName
|
|
12822
|
+
};
|
|
13102
12823
|
}
|
|
13103
|
-
|
|
13104
|
-
const
|
|
13105
|
-
|
|
13106
|
-
|
|
13107
|
-
await pull(apiKey, file, policyId);
|
|
13108
|
-
} else if (command === "push") {
|
|
13109
|
-
await push(apiKey, file, policyId);
|
|
13110
|
-
} else if (command === "list" || command === "ls") {
|
|
13111
|
-
await list5(apiKey, policyId);
|
|
13112
|
-
} else {
|
|
13113
|
-
log3(red2(`Unknown command: ${command}`));
|
|
13114
|
-
log3("");
|
|
13115
|
-
log3(bold2("Usage:"));
|
|
13116
|
-
log3(" solongate-proxy list List all policies");
|
|
13117
|
-
log3(" solongate-proxy list --policy-id <ID> Show policy details");
|
|
13118
|
-
log3(" solongate-proxy pull --policy-id <ID> Pull policy to local file");
|
|
13119
|
-
log3(" solongate-proxy push --policy-id <ID> Push local file to cloud");
|
|
13120
|
-
log3("");
|
|
13121
|
-
log3(bold2("Flags:"));
|
|
13122
|
-
log3(" --policy-id, --id <ID> Cloud policy ID (required for push)");
|
|
13123
|
-
log3(" --file, -f <path> Local file path (default: policy.json)");
|
|
13124
|
-
log3(" --api-key <key> API key (or set SOLONGATE_API_KEY)");
|
|
13125
|
-
log3("");
|
|
13126
|
-
process.exit(1);
|
|
13127
|
-
}
|
|
13128
|
-
} catch (err2) {
|
|
13129
|
-
log3(red2(`ERROR: ${err2 instanceof Error ? err2.message : String(err2)}`));
|
|
13130
|
-
process.exit(1);
|
|
13131
|
-
}
|
|
12824
|
+
function resolvePolicyPath(source) {
|
|
12825
|
+
const filePath = resolve(source);
|
|
12826
|
+
if (existsSync(filePath)) return filePath;
|
|
12827
|
+
return null;
|
|
13132
12828
|
}
|
|
13133
|
-
var log3, dim2, bold2, green2, red2, yellow2, cyan2, magenta, API_URL;
|
|
13134
|
-
var init_pull_push = __esm({
|
|
13135
|
-
"src/pull-push.ts"() {
|
|
13136
|
-
"use strict";
|
|
13137
|
-
init_config();
|
|
13138
|
-
log3 = (...args) => process.stderr.write(`${args.map(String).join(" ")}
|
|
13139
|
-
`);
|
|
13140
|
-
dim2 = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
13141
|
-
bold2 = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
13142
|
-
green2 = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
13143
|
-
red2 = (s) => `\x1B[31m${s}\x1B[0m`;
|
|
13144
|
-
yellow2 = (s) => `\x1B[33m${s}\x1B[0m`;
|
|
13145
|
-
cyan2 = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
13146
|
-
magenta = (s) => `\x1B[35m${s}\x1B[0m`;
|
|
13147
|
-
API_URL = "https://api.solongate.com";
|
|
13148
|
-
main();
|
|
13149
|
-
}
|
|
13150
|
-
});
|
|
13151
|
-
|
|
13152
|
-
// src/index.ts
|
|
13153
|
-
init_config();
|
|
13154
|
-
import { readFileSync as readFileSync13 } from "fs";
|
|
13155
|
-
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13156
|
-
import { dirname as dirname4, join as join16 } from "path";
|
|
13157
12829
|
|
|
13158
12830
|
// src/proxy.ts
|
|
13159
12831
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -15348,11 +15020,7 @@ var SolonGate = class {
|
|
|
15348
15020
|
}
|
|
15349
15021
|
};
|
|
15350
15022
|
|
|
15351
|
-
// src/proxy.ts
|
|
15352
|
-
init_config();
|
|
15353
|
-
|
|
15354
15023
|
// src/sync.ts
|
|
15355
|
-
init_config();
|
|
15356
15024
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, watch, existsSync as existsSync2 } from "fs";
|
|
15357
15025
|
var log = (...args) => process.stderr.write(`[SolonGate Sync] ${args.map(String).join(" ")}
|
|
15358
15026
|
`);
|
|
@@ -15577,7 +15245,7 @@ var Mutex = class {
|
|
|
15577
15245
|
this.locked = true;
|
|
15578
15246
|
return;
|
|
15579
15247
|
}
|
|
15580
|
-
return new Promise((
|
|
15248
|
+
return new Promise((resolve6, reject) => {
|
|
15581
15249
|
const timer = setTimeout(() => {
|
|
15582
15250
|
const idx = this.queue.indexOf(onReady);
|
|
15583
15251
|
if (idx !== -1) this.queue.splice(idx, 1);
|
|
@@ -15585,7 +15253,7 @@ var Mutex = class {
|
|
|
15585
15253
|
}, timeoutMs);
|
|
15586
15254
|
const onReady = () => {
|
|
15587
15255
|
clearTimeout(timer);
|
|
15588
|
-
|
|
15256
|
+
resolve6();
|
|
15589
15257
|
};
|
|
15590
15258
|
this.queue.push(onReady);
|
|
15591
15259
|
});
|
|
@@ -16176,7 +15844,7 @@ ${msg.content.text}`;
|
|
|
16176
15844
|
|
|
16177
15845
|
// src/index.ts
|
|
16178
15846
|
init_cli_utils();
|
|
16179
|
-
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["
|
|
15847
|
+
var CLI_SUBCOMMANDS = /* @__PURE__ */ new Set(["logs-server", "local-logs", "policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks", "dataroom"]);
|
|
16180
15848
|
var CLI_INFO_ARGS = /* @__PURE__ */ new Set(["login", "help", "--help", "-h", "--version", "-v", "version"]);
|
|
16181
15849
|
var IS_HUMAN_CLI = process.argv.length <= 2 || CLI_SUBCOMMANDS.has(process.argv[2] ?? "") || CLI_INFO_ARGS.has(process.argv[2] ?? "");
|
|
16182
15850
|
if (!IS_HUMAN_CLI) {
|
|
@@ -16196,7 +15864,7 @@ if (!IS_HUMAN_CLI) {
|
|
|
16196
15864
|
var PKG_VERSION = (() => {
|
|
16197
15865
|
try {
|
|
16198
15866
|
const p = join16(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
16199
|
-
return JSON.parse(
|
|
15867
|
+
return JSON.parse(readFileSync12(p, "utf-8")).version || "unknown";
|
|
16200
15868
|
} catch {
|
|
16201
15869
|
return "unknown";
|
|
16202
15870
|
}
|
|
@@ -16245,8 +15913,8 @@ function printHelp() {
|
|
|
16245
15913
|
head("Policies");
|
|
16246
15914
|
cmd("policy list", "list all policies");
|
|
16247
15915
|
cmd("policy show <id>", "show one policy (rules, mode)");
|
|
16248
|
-
cmd("policy allow <id>
|
|
16249
|
-
cmd("policy deny <id>
|
|
15916
|
+
cmd("policy allow <id> [--command|--path|--url <val>]", "add an ALLOW rule");
|
|
15917
|
+
cmd("policy deny <id> [--command|--path|--url <val>]", "add a DENY rule");
|
|
16250
15918
|
cmd("policy revoke <id> <ruleId>", "remove a rule");
|
|
16251
15919
|
cmd("policy activate <id> | --clear", "pin / unpin the active policy");
|
|
16252
15920
|
cmd("policy active", "show the resolved active policy");
|
|
@@ -16268,8 +15936,8 @@ function printHelp() {
|
|
|
16268
15936
|
cmd("audit block <logId> [--scope exact|tool]", "turn a call into a DENY rule");
|
|
16269
15937
|
cmd("stats [timeseries|drift]", "traffic & security statistics");
|
|
16270
15938
|
cmd("watch [--filter DENY] [--tool <s>]", "live-tail tool calls (Ctrl+C to stop)");
|
|
16271
|
-
cmd("
|
|
16272
|
-
cmd("
|
|
15939
|
+
cmd("sessions [--all]", "live agent-session feed (calls, denies, trust)");
|
|
15940
|
+
cmd("session <id>", "one session's detail");
|
|
16273
15941
|
head("Alerts & webhooks");
|
|
16274
15942
|
cmd("alerts list");
|
|
16275
15943
|
cmd("alerts add --signal deny|dlp|ratelimit|any --threshold N --window S (--email <a> | --telegram <id> | --slack <url>)", "spike alert");
|
|
@@ -16277,16 +15945,12 @@ function printHelp() {
|
|
|
16277
15945
|
cmd("webhooks list");
|
|
16278
15946
|
cmd("webhooks add --url <https://\u2026> [--events denials|allowed|all]", "event webhook");
|
|
16279
15947
|
cmd("webhooks remove <id>");
|
|
16280
|
-
head("Policy sync");
|
|
16281
|
-
cmd("list [--policy-id <ID>]", "list cloud policies (or show one)");
|
|
16282
|
-
cmd("pull --policy-id <ID> [--file f]", "pull a cloud policy to a local file");
|
|
16283
|
-
cmd("push --policy-id <ID> [--file f]", "push a local policy file to the cloud");
|
|
16284
15948
|
console.log("");
|
|
16285
15949
|
console.log(` ${c.dim}Add ${c.reset}${c.cyan}--json${c.reset}${c.dim} to most read commands for machine output.${c.reset}`);
|
|
16286
15950
|
console.log(` ${c.dim}Details for a command: ${c.reset}${c.cyan}solongate <command> help${c.reset}${c.dim} \xB7 Dashboard: ${c.reset}${c.cyan}https://dashboard.solongate.com${c.reset}`);
|
|
16287
15951
|
console.log("");
|
|
16288
15952
|
}
|
|
16289
|
-
async function
|
|
15953
|
+
async function main() {
|
|
16290
15954
|
const subcommand = process.argv[2];
|
|
16291
15955
|
if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
16292
15956
|
printHelp();
|
|
@@ -16321,7 +15985,7 @@ async function main2() {
|
|
|
16321
15985
|
await launchTui2();
|
|
16322
15986
|
return;
|
|
16323
15987
|
}
|
|
16324
|
-
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "
|
|
15988
|
+
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
|
|
16325
15989
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
16326
15990
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
16327
15991
|
const code = await runCommand2(subcommand, process.argv.slice(3));
|
|
@@ -16339,10 +16003,6 @@ async function main2() {
|
|
|
16339
16003
|
await runLogsServer2();
|
|
16340
16004
|
return;
|
|
16341
16005
|
}
|
|
16342
|
-
if (subcommand === "pull" || subcommand === "push" || subcommand === "list" || subcommand === "ls") {
|
|
16343
|
-
await Promise.resolve().then(() => (init_pull_push(), pull_push_exports));
|
|
16344
|
-
return;
|
|
16345
|
-
}
|
|
16346
16006
|
const hasProxySeparator = process.argv.includes("--");
|
|
16347
16007
|
const looksLikeProxyFlag = (subcommand ?? "").startsWith("-");
|
|
16348
16008
|
if (subcommand && !hasProxySeparator && !looksLikeProxyFlag) {
|
|
@@ -16365,4 +16025,4 @@ async function main2() {
|
|
|
16365
16025
|
process.exit(1);
|
|
16366
16026
|
}
|
|
16367
16027
|
}
|
|
16368
|
-
|
|
16028
|
+
main();
|