@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/tui/index.js
CHANGED
|
@@ -2359,8 +2359,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2359
2359
|
{ header: "ON", width: 2 },
|
|
2360
2360
|
{ header: "EFFECT", width: 7 },
|
|
2361
2361
|
{ header: "PRIO", width: 4 },
|
|
2362
|
-
{ header: "
|
|
2363
|
-
{ header: "DESCRIPTION", width: 30 },
|
|
2362
|
+
{ header: "DESCRIPTION", width: 38 },
|
|
2364
2363
|
{ header: "CONSTRAINTS", width: 14 }
|
|
2365
2364
|
],
|
|
2366
2365
|
rows: rWin.map((r, wi) => {
|
|
@@ -2370,8 +2369,7 @@ function PoliciesPanel({ focused }) {
|
|
|
2370
2369
|
{ value: r.enabled ? "\u25CF" : "\u25CB", color: r.enabled ? theme.ok : theme.dim },
|
|
2371
2370
|
{ value: r.effect, color: r.effect === "ALLOW" ? theme.ok : theme.bad, dim: !r.enabled },
|
|
2372
2371
|
{ value: String(r.priority), dim: true },
|
|
2373
|
-
{ value: truncate(r.
|
|
2374
|
-
{ value: truncate(r.description || "-", 30), dim: !r.enabled },
|
|
2372
|
+
{ value: truncate(r.description || "-", 38), dim: !r.enabled },
|
|
2375
2373
|
{ value: ruleSummary(r) || "-", dim: true }
|
|
2376
2374
|
];
|
|
2377
2375
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.82.
|
|
3
|
+
"version": "0.82.41",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/dist/pull-push.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* solongate-proxy pull — Pull a policy from dashboard to local file
|
|
4
|
-
* solongate-proxy push — Push a local policy file to dashboard
|
|
5
|
-
* solongate-proxy list — List all policies with details
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* solongate-proxy list
|
|
9
|
-
* solongate-proxy list --policy-id <ID>
|
|
10
|
-
* solongate-proxy pull --policy-id <ID>
|
|
11
|
-
* solongate-proxy push --policy-id <ID>
|
|
12
|
-
* solongate-proxy pull --policy-id <ID> --file my-policy.json
|
|
13
|
-
*
|
|
14
|
-
* The --policy-id flag determines WHICH cloud policy to work with.
|
|
15
|
-
* API key is read from .env file (SOLONGATE_API_KEY) or environment variable.
|
|
16
|
-
*/
|
|
17
|
-
export {};
|
package/dist/pull-push.js
DELETED
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/pull-push.ts
|
|
4
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2 } from "fs";
|
|
5
|
-
import { resolve as resolve2 } from "path";
|
|
6
|
-
|
|
7
|
-
// src/config.ts
|
|
8
|
-
import { readFileSync, existsSync } from "fs";
|
|
9
|
-
import { appendFile } from "fs/promises";
|
|
10
|
-
import { resolve, join } from "path";
|
|
11
|
-
import { homedir } from "os";
|
|
12
|
-
async function fetchCloudPolicy(apiKey, apiUrl, policyId) {
|
|
13
|
-
let resolvedId = policyId;
|
|
14
|
-
if (!resolvedId) {
|
|
15
|
-
const listRes = await fetch(`${apiUrl}/api/v1/policies`, {
|
|
16
|
-
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
17
|
-
signal: AbortSignal.timeout(1e4)
|
|
18
|
-
});
|
|
19
|
-
if (!listRes.ok) {
|
|
20
|
-
const body = await listRes.text().catch(() => "");
|
|
21
|
-
throw new Error(`Failed to list policies from cloud (${listRes.status}): ${body}`);
|
|
22
|
-
}
|
|
23
|
-
const listData = await listRes.json();
|
|
24
|
-
const policies = listData.policies ?? [];
|
|
25
|
-
if (policies.length === 0) {
|
|
26
|
-
throw new Error("No policies found in cloud. Create one in the dashboard first.");
|
|
27
|
-
}
|
|
28
|
-
resolvedId = policies[0].id;
|
|
29
|
-
}
|
|
30
|
-
const url = `${apiUrl}/api/v1/policies/${resolvedId}`;
|
|
31
|
-
const res = await fetch(url, {
|
|
32
|
-
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
33
|
-
signal: AbortSignal.timeout(1e4)
|
|
34
|
-
});
|
|
35
|
-
if (!res.ok) {
|
|
36
|
-
const body = await res.text().catch(() => "");
|
|
37
|
-
throw new Error(`Failed to fetch policy from cloud (${res.status}): ${body}`);
|
|
38
|
-
}
|
|
39
|
-
const data = await res.json();
|
|
40
|
-
return {
|
|
41
|
-
id: String(data.id ?? "cloud"),
|
|
42
|
-
name: String(data.name ?? "Cloud Policy"),
|
|
43
|
-
description: String(data.description ?? ""),
|
|
44
|
-
version: Number(data._version ?? 1),
|
|
45
|
-
rules: data.rules ?? [],
|
|
46
|
-
createdAt: String(data._created_at ?? ""),
|
|
47
|
-
updatedAt: ""
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
var AUDIT_LOG_BACKUP_PATH = resolve(".solongate-audit-backup.jsonl");
|
|
51
|
-
|
|
52
|
-
// src/pull-push.ts
|
|
53
|
-
var log = (...args) => process.stderr.write(`${args.map(String).join(" ")}
|
|
54
|
-
`);
|
|
55
|
-
var dim = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
56
|
-
var bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
57
|
-
var green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
58
|
-
var red = (s) => `\x1B[31m${s}\x1B[0m`;
|
|
59
|
-
var yellow = (s) => `\x1B[33m${s}\x1B[0m`;
|
|
60
|
-
var cyan = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
61
|
-
var magenta = (s) => `\x1B[35m${s}\x1B[0m`;
|
|
62
|
-
function loadEnv() {
|
|
63
|
-
if (process.env.SOLONGATE_API_KEY) return;
|
|
64
|
-
const envPath = resolve2(".env");
|
|
65
|
-
if (!existsSync2(envPath)) return;
|
|
66
|
-
try {
|
|
67
|
-
const content = readFileSync2(envPath, "utf-8");
|
|
68
|
-
for (const line of content.split("\n")) {
|
|
69
|
-
const trimmed = line.trim();
|
|
70
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
71
|
-
const eq = trimmed.indexOf("=");
|
|
72
|
-
if (eq === -1) continue;
|
|
73
|
-
const key = trimmed.slice(0, eq).trim();
|
|
74
|
-
const val = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
75
|
-
if (key === "SOLONGATE_API_KEY") {
|
|
76
|
-
process.env.SOLONGATE_API_KEY = val;
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
} catch {
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function parseCliArgs() {
|
|
84
|
-
loadEnv();
|
|
85
|
-
const args = process.argv.slice(2);
|
|
86
|
-
const command = args[0];
|
|
87
|
-
let apiKey = process.env.SOLONGATE_API_KEY || "";
|
|
88
|
-
let file = "policy.json";
|
|
89
|
-
let policyId;
|
|
90
|
-
for (let i = 1; i < args.length; i++) {
|
|
91
|
-
switch (args[i]) {
|
|
92
|
-
case "--api-key":
|
|
93
|
-
apiKey = args[++i];
|
|
94
|
-
break;
|
|
95
|
-
case "--policy":
|
|
96
|
-
case "--output":
|
|
97
|
-
case "--file":
|
|
98
|
-
case "-f":
|
|
99
|
-
case "-o":
|
|
100
|
-
file = args[++i];
|
|
101
|
-
break;
|
|
102
|
-
case "--policy-id":
|
|
103
|
-
case "--id":
|
|
104
|
-
policyId = args[++i];
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (!apiKey) {
|
|
109
|
-
log(red("ERROR: API key not found."));
|
|
110
|
-
log("");
|
|
111
|
-
log("Set it in .env file:");
|
|
112
|
-
log(" SOLONGATE_API_KEY=sg_live_...");
|
|
113
|
-
log("");
|
|
114
|
-
log("Or pass via environment:");
|
|
115
|
-
log(` SOLONGATE_API_KEY=sg_live_... solongate-proxy ${command}`);
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
if (!apiKey.startsWith("sg_live_")) {
|
|
119
|
-
log(red("ERROR: Pull/push/list requires a live API key (sg_live_...)."));
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
return { command, apiKey, file: resolve2(file), policyId };
|
|
123
|
-
}
|
|
124
|
-
var API_URL = "https://api.solongate.com";
|
|
125
|
-
async function listPolicies(apiKey) {
|
|
126
|
-
const res = await fetch(`${API_URL}/api/v1/policies`, {
|
|
127
|
-
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
128
|
-
});
|
|
129
|
-
if (!res.ok) throw new Error(`Failed to list policies (${res.status})`);
|
|
130
|
-
const data = await res.json();
|
|
131
|
-
return data.policies ?? [];
|
|
132
|
-
}
|
|
133
|
-
async function list(apiKey, policyId) {
|
|
134
|
-
const policies = await listPolicies(apiKey);
|
|
135
|
-
if (policies.length === 0) {
|
|
136
|
-
log(yellow("No policies found. Create one in the dashboard first."));
|
|
137
|
-
log(dim(" https://dashboard.solongate.com/policies"));
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
if (policyId) {
|
|
141
|
-
const match = policies.find((p) => p.id === policyId);
|
|
142
|
-
if (!match) {
|
|
143
|
-
log(red(`Policy not found: ${policyId}`));
|
|
144
|
-
log("");
|
|
145
|
-
log("Available policies:");
|
|
146
|
-
for (const p of policies) {
|
|
147
|
-
log(` ${dim("\u2022")} ${p.id}`);
|
|
148
|
-
}
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
151
|
-
const full = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
152
|
-
printPolicyDetail(full);
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
log("");
|
|
156
|
-
log(bold(` Policies (${policies.length})`));
|
|
157
|
-
log(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"));
|
|
158
|
-
log("");
|
|
159
|
-
const fullPolicies = await Promise.all(
|
|
160
|
-
policies.map(
|
|
161
|
-
(p) => fetchCloudPolicy(apiKey, API_URL, p.id).then((full) => ({ policy: p, rules: full.rules })).catch(() => ({ policy: p, rules: [] }))
|
|
162
|
-
)
|
|
163
|
-
);
|
|
164
|
-
for (const { policy, rules } of fullPolicies) {
|
|
165
|
-
printPolicySummary(policy, [...rules]);
|
|
166
|
-
}
|
|
167
|
-
log(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"));
|
|
168
|
-
log("");
|
|
169
|
-
log(` ${dim("View details:")} solongate-proxy list --policy-id <ID>`);
|
|
170
|
-
log(` ${dim("Pull policy:")} solongate-proxy pull --policy-id <ID>`);
|
|
171
|
-
log(` ${dim("Push policy:")} solongate-proxy push --policy-id <ID>`);
|
|
172
|
-
log("");
|
|
173
|
-
}
|
|
174
|
-
function printPolicySummary(p, rules) {
|
|
175
|
-
const ruleCount = rules.length;
|
|
176
|
-
const allowCount = rules.filter((r) => r.effect === "ALLOW").length;
|
|
177
|
-
const denyCount = rules.filter((r) => r.effect === "DENY").length;
|
|
178
|
-
log(` ${cyan(p.id)}`);
|
|
179
|
-
log(` ${bold(p.name)} ${dim(`v${p.version ?? "?"}`)}`);
|
|
180
|
-
log(` ${dim("Rules:")} ${ruleCount} ${green(`${allowCount} ALLOW`)} ${red(`${denyCount} DENY`)}`);
|
|
181
|
-
if (p.created_at) {
|
|
182
|
-
log(` ${dim("Updated:")} ${new Date(p.created_at).toLocaleString()}`);
|
|
183
|
-
}
|
|
184
|
-
log("");
|
|
185
|
-
}
|
|
186
|
-
function printPolicyDetail(policy) {
|
|
187
|
-
log("");
|
|
188
|
-
log(bold(` ${policy.name}`));
|
|
189
|
-
log(` ${dim("ID:")} ${cyan(policy.id)} ${dim("Version:")} ${policy.version} ${dim("Rules:")} ${policy.rules.length}`);
|
|
190
|
-
log("");
|
|
191
|
-
if (policy.rules.length === 0) {
|
|
192
|
-
log(yellow(" No rules defined."));
|
|
193
|
-
log("");
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
log(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"));
|
|
197
|
-
for (const rule of policy.rules) {
|
|
198
|
-
const effectColor = rule.effect === "ALLOW" ? green : red;
|
|
199
|
-
log("");
|
|
200
|
-
log(` ${effectColor(rule.effect.padEnd(5))} ${bold(rule.toolPattern)} ${dim(`P:${rule.priority}`)}`);
|
|
201
|
-
if (rule.description) {
|
|
202
|
-
log(` ${dim(rule.description)}`);
|
|
203
|
-
}
|
|
204
|
-
log(` ${dim(`${rule.permission} trust:${rule.minimumTrustLevel || "UNTRUSTED"}`)}`);
|
|
205
|
-
if (rule.pathConstraints) {
|
|
206
|
-
const pc = rule.pathConstraints;
|
|
207
|
-
if (pc.rootDirectory) log(` ${magenta("ROOT")} ${pc.rootDirectory}`);
|
|
208
|
-
if (pc.allowed?.length) log(` ${green("PATHS")} ${pc.allowed.join(", ")}`);
|
|
209
|
-
if (pc.denied?.length) log(` ${red("DENY")} ${pc.denied.join(", ")}`);
|
|
210
|
-
}
|
|
211
|
-
if (rule.commandConstraints) {
|
|
212
|
-
const cc = rule.commandConstraints;
|
|
213
|
-
if (cc.allowed?.length) log(` ${green("CMDS")} ${cc.allowed.join(", ")}`);
|
|
214
|
-
if (cc.denied?.length) log(` ${red("DENY")} ${cc.denied.join(", ")}`);
|
|
215
|
-
}
|
|
216
|
-
if (rule.filenameConstraints) {
|
|
217
|
-
const fc = rule.filenameConstraints;
|
|
218
|
-
if (fc.allowed?.length) log(` ${green("FILES")} ${fc.allowed.join(", ")}`);
|
|
219
|
-
if (fc.denied?.length) log(` ${red("DENY")} ${fc.denied.join(", ")}`);
|
|
220
|
-
}
|
|
221
|
-
if (rule.urlConstraints) {
|
|
222
|
-
const uc = rule.urlConstraints;
|
|
223
|
-
if (uc.allowed?.length) log(` ${green("URLS")} ${uc.allowed.join(", ")}`);
|
|
224
|
-
if (uc.denied?.length) log(` ${red("DENY")} ${uc.denied.join(", ")}`);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
log("");
|
|
228
|
-
log(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"));
|
|
229
|
-
log("");
|
|
230
|
-
}
|
|
231
|
-
async function pull(apiKey, file, policyId) {
|
|
232
|
-
if (!policyId) {
|
|
233
|
-
const policies = await listPolicies(apiKey);
|
|
234
|
-
if (policies.length === 0) {
|
|
235
|
-
log(red("No policies found. Create one in the dashboard first."));
|
|
236
|
-
process.exit(1);
|
|
237
|
-
}
|
|
238
|
-
if (policies.length === 1) {
|
|
239
|
-
policyId = policies[0].id;
|
|
240
|
-
log(dim(`Auto-selecting only policy: ${policyId}`));
|
|
241
|
-
} else {
|
|
242
|
-
log(yellow(`Found ${policies.length} policies:`));
|
|
243
|
-
log("");
|
|
244
|
-
for (const p of policies) {
|
|
245
|
-
log(` ${cyan(p.id)} ${p.name} ${dim(`v${p.version ?? "?"}`)}`);
|
|
246
|
-
}
|
|
247
|
-
log("");
|
|
248
|
-
log("Use --policy-id <ID> to specify which one to pull.");
|
|
249
|
-
process.exit(1);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
log(`Pulling ${cyan(policyId)} from dashboard...`);
|
|
253
|
-
const policy = await fetchCloudPolicy(apiKey, API_URL, policyId);
|
|
254
|
-
const { id: _id, ...policyWithoutId } = policy;
|
|
255
|
-
const json = JSON.stringify(policyWithoutId, null, 2) + "\n";
|
|
256
|
-
writeFileSync(file, json, "utf-8");
|
|
257
|
-
log("");
|
|
258
|
-
log(green(" Saved to: ") + file);
|
|
259
|
-
log(` ${dim("Name:")} ${policy.name}`);
|
|
260
|
-
log(` ${dim("Version:")} ${policy.version}`);
|
|
261
|
-
log(` ${dim("Rules:")} ${policy.rules.length}`);
|
|
262
|
-
log("");
|
|
263
|
-
log(dim("The policy file does not contain an ID."));
|
|
264
|
-
log(dim("Use --policy-id to specify the target when pushing/pulling."));
|
|
265
|
-
log("");
|
|
266
|
-
}
|
|
267
|
-
async function push(apiKey, file, policyId) {
|
|
268
|
-
if (!existsSync2(file)) {
|
|
269
|
-
log(red(`ERROR: File not found: ${file}`));
|
|
270
|
-
process.exit(1);
|
|
271
|
-
}
|
|
272
|
-
if (!policyId) {
|
|
273
|
-
log(red("ERROR: --policy-id is required for push."));
|
|
274
|
-
log("");
|
|
275
|
-
log("This determines which cloud policy to update.");
|
|
276
|
-
log("");
|
|
277
|
-
log("Usage:");
|
|
278
|
-
log(" solongate-proxy push --policy-id my-policy");
|
|
279
|
-
log(" solongate-proxy push --policy-id my-policy --file custom.json");
|
|
280
|
-
log("");
|
|
281
|
-
log("List your policies:");
|
|
282
|
-
log(" solongate-proxy list");
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
285
|
-
const content = readFileSync2(file, "utf-8");
|
|
286
|
-
let policy;
|
|
287
|
-
try {
|
|
288
|
-
policy = JSON.parse(content);
|
|
289
|
-
} catch {
|
|
290
|
-
log(red(`ERROR: Invalid JSON in ${file}`));
|
|
291
|
-
process.exit(1);
|
|
292
|
-
}
|
|
293
|
-
log(`Pushing to ${cyan(policyId)}...`);
|
|
294
|
-
log(` ${dim("File:")} ${file}`);
|
|
295
|
-
log(` ${dim("Name:")} ${policy.name || "Unnamed"}`);
|
|
296
|
-
log(` ${dim("Rules:")} ${(policy.rules || []).length}`);
|
|
297
|
-
const checkRes = await fetch(`${API_URL}/api/v1/policies/${policyId}`, {
|
|
298
|
-
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
299
|
-
});
|
|
300
|
-
const method = checkRes.ok ? "PUT" : "POST";
|
|
301
|
-
const url = checkRes.ok ? `${API_URL}/api/v1/policies/${policyId}` : `${API_URL}/api/v1/policies`;
|
|
302
|
-
const res = await fetch(url, {
|
|
303
|
-
method,
|
|
304
|
-
headers: {
|
|
305
|
-
"Authorization": `Bearer ${apiKey}`,
|
|
306
|
-
"Content-Type": "application/json"
|
|
307
|
-
},
|
|
308
|
-
body: JSON.stringify({
|
|
309
|
-
id: policyId,
|
|
310
|
-
name: policy.name || "Local Policy",
|
|
311
|
-
description: policy.description || "Pushed from local file",
|
|
312
|
-
version: policy.version || 1,
|
|
313
|
-
rules: policy.rules || []
|
|
314
|
-
})
|
|
315
|
-
});
|
|
316
|
-
if (!res.ok) {
|
|
317
|
-
const body = await res.text().catch(() => "");
|
|
318
|
-
log(red(`ERROR: Push failed (${res.status}): ${body}`));
|
|
319
|
-
process.exit(1);
|
|
320
|
-
}
|
|
321
|
-
const data = await res.json();
|
|
322
|
-
log("");
|
|
323
|
-
log(green(` Pushed to cloud: v${data._version ?? "created"}`));
|
|
324
|
-
log(` ${dim("Policy ID:")} ${policyId}`);
|
|
325
|
-
log(` ${dim("Method:")} ${method === "PUT" ? "Updated existing" : "Created new"}`);
|
|
326
|
-
log("");
|
|
327
|
-
}
|
|
328
|
-
async function main() {
|
|
329
|
-
const { command, apiKey, file, policyId } = parseCliArgs();
|
|
330
|
-
try {
|
|
331
|
-
if (command === "pull") {
|
|
332
|
-
await pull(apiKey, file, policyId);
|
|
333
|
-
} else if (command === "push") {
|
|
334
|
-
await push(apiKey, file, policyId);
|
|
335
|
-
} else if (command === "list" || command === "ls") {
|
|
336
|
-
await list(apiKey, policyId);
|
|
337
|
-
} else {
|
|
338
|
-
log(red(`Unknown command: ${command}`));
|
|
339
|
-
log("");
|
|
340
|
-
log(bold("Usage:"));
|
|
341
|
-
log(" solongate-proxy list List all policies");
|
|
342
|
-
log(" solongate-proxy list --policy-id <ID> Show policy details");
|
|
343
|
-
log(" solongate-proxy pull --policy-id <ID> Pull policy to local file");
|
|
344
|
-
log(" solongate-proxy push --policy-id <ID> Push local file to cloud");
|
|
345
|
-
log("");
|
|
346
|
-
log(bold("Flags:"));
|
|
347
|
-
log(" --policy-id, --id <ID> Cloud policy ID (required for push)");
|
|
348
|
-
log(" --file, -f <path> Local file path (default: policy.json)");
|
|
349
|
-
log(" --api-key <key> API key (or set SOLONGATE_API_KEY)");
|
|
350
|
-
log("");
|
|
351
|
-
process.exit(1);
|
|
352
|
-
}
|
|
353
|
-
} catch (err) {
|
|
354
|
-
log(red(`ERROR: ${err instanceof Error ? err.message : String(err)}`));
|
|
355
|
-
process.exit(1);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
main();
|