@cdot65/prisma-airs-cli 3.3.0 → 4.0.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/README.md +26 -2
- package/dist/{chunk-2VIUZRPB.js → chunk-W5YDJS7H.js} +124 -34
- package/dist/cli/index.js +773 -434
- package/dist/index.d.ts +83 -1
- package/dist/index.js +1 -1
- package/package.json +15 -3
package/dist/cli/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
sanitizeFilename,
|
|
21
21
|
validateTopic,
|
|
22
22
|
writeBackupFile
|
|
23
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-W5YDJS7H.js";
|
|
24
24
|
|
|
25
25
|
// src/cli/index.ts
|
|
26
26
|
import "dotenv/config";
|
|
@@ -187,9 +187,15 @@ var SdkAiGatewayService = class {
|
|
|
187
187
|
workspaceSlug,
|
|
188
188
|
days,
|
|
189
189
|
totalCents: raw.data.total,
|
|
190
|
+
totalUsd: raw.data.total / 100,
|
|
190
191
|
avgCents: raw.data.avg,
|
|
192
|
+
avgUsd: raw.data.avg / 100,
|
|
191
193
|
quotaExceeded: raw.data.isQuotaExceeded,
|
|
192
|
-
records: raw.data.records.map((r) => ({
|
|
194
|
+
records: raw.data.records.map((r) => ({
|
|
195
|
+
date: r.x,
|
|
196
|
+
costCents: r.y,
|
|
197
|
+
costUsd: r.y / 100
|
|
198
|
+
}))
|
|
193
199
|
};
|
|
194
200
|
}
|
|
195
201
|
/** Re-read after a write, falling back to the (partial) write response if the get fails. */
|
|
@@ -249,7 +255,11 @@ import { dump as yamlDump } from "js-yaml";
|
|
|
249
255
|
|
|
250
256
|
// src/cli/renderer/common.ts
|
|
251
257
|
import chalk2 from "chalk";
|
|
258
|
+
import { dump } from "js-yaml";
|
|
259
|
+
var CliUsageError = class extends Error {
|
|
260
|
+
};
|
|
252
261
|
function fail(err) {
|
|
262
|
+
if (err instanceof CliUsageError) usageError(err.message);
|
|
253
263
|
const message = err instanceof Error ? err.message : String(err);
|
|
254
264
|
const status = err?.status ?? err?.statusCode;
|
|
255
265
|
console.error(chalk2.red(`
|
|
@@ -267,44 +277,81 @@ function usageError(message) {
|
|
|
267
277
|
`));
|
|
268
278
|
process.exit(2);
|
|
269
279
|
}
|
|
270
|
-
var OUTPUT_FORMATS = [
|
|
280
|
+
var OUTPUT_FORMATS = [
|
|
281
|
+
"pretty",
|
|
282
|
+
"table",
|
|
283
|
+
"markdown",
|
|
284
|
+
"csv",
|
|
285
|
+
"json",
|
|
286
|
+
"yaml"
|
|
287
|
+
];
|
|
288
|
+
async function resolveOutput(command, opts, resolution = {}) {
|
|
289
|
+
const localIsExplicit = command.getOptionValueSource?.("output") === "cli";
|
|
290
|
+
const root = command.parent ? command.optsWithGlobals() : command.opts();
|
|
291
|
+
let configured;
|
|
292
|
+
try {
|
|
293
|
+
configured = (await loadConfig()).defaultOutput;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
if (process.env.PANW_CLI_OUTPUT !== void 0) configured = process.env.PANW_CLI_OUTPUT;
|
|
296
|
+
else throw error;
|
|
297
|
+
}
|
|
298
|
+
const candidate = String(localIsExplicit ? opts.output : root.output ?? configured ?? "pretty");
|
|
299
|
+
if (!OUTPUT_FORMATS.includes(candidate))
|
|
300
|
+
throw new CliUsageError(
|
|
301
|
+
`Invalid output format '${candidate}'. Expected: ${OUTPUT_FORMATS.join(", ")}`
|
|
302
|
+
);
|
|
303
|
+
const format = candidate;
|
|
304
|
+
const allowed = resolution.allowed ?? OUTPUT_FORMATS;
|
|
305
|
+
if (!allowed.includes(format))
|
|
306
|
+
throw new CliUsageError(
|
|
307
|
+
`Output format '${format}' is not supported here. Expected: ${allowed.join(", ")}`
|
|
308
|
+
);
|
|
309
|
+
return format;
|
|
310
|
+
}
|
|
311
|
+
function displayValue(value) {
|
|
312
|
+
if (value == null) return "";
|
|
313
|
+
return typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
314
|
+
}
|
|
315
|
+
function csvCell(value) {
|
|
316
|
+
const text = displayValue(value);
|
|
317
|
+
return /[",\r\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
|
|
318
|
+
}
|
|
319
|
+
function markdownCell(value) {
|
|
320
|
+
return displayValue(value).replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
|
|
321
|
+
}
|
|
271
322
|
function formatOutput(rows, columns, format) {
|
|
272
|
-
if (rows.length === 0) return "";
|
|
273
|
-
const
|
|
323
|
+
if (rows.length === 0) return format === "json" ? "[]" : "";
|
|
324
|
+
const projected = rows.map((row) => columns.map((column) => row[column.key]));
|
|
274
325
|
switch (format) {
|
|
275
326
|
case "json":
|
|
276
|
-
return JSON.stringify(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
);
|
|
293
|
-
return [header, ...lines].join("\n");
|
|
294
|
-
}
|
|
295
|
-
case "yaml": {
|
|
296
|
-
return rows.map((r) => columns.map((c) => `${c.key}: ${vals(r, c.key)}`).join("\n")).join("\n---\n");
|
|
327
|
+
return JSON.stringify(rows, null, 2);
|
|
328
|
+
case "yaml":
|
|
329
|
+
return dump(rows, { noRefs: true, lineWidth: -1 }).trimEnd();
|
|
330
|
+
case "csv":
|
|
331
|
+
return [
|
|
332
|
+
columns.map((column) => csvCell(column.label)).join(","),
|
|
333
|
+
...projected.map((values) => values.map(csvCell).join(","))
|
|
334
|
+
].join("\n");
|
|
335
|
+
case "markdown": {
|
|
336
|
+
const header = `| ${columns.map((column) => markdownCell(column.label)).join(" | ")} |`;
|
|
337
|
+
const divider = `| ${columns.map(() => "---").join(" | ")} |`;
|
|
338
|
+
return [
|
|
339
|
+
header,
|
|
340
|
+
divider,
|
|
341
|
+
...projected.map((values) => `| ${values.map(markdownCell).join(" | ")} |`)
|
|
342
|
+
].join("\n");
|
|
297
343
|
}
|
|
298
344
|
case "table": {
|
|
345
|
+
const values = projected.map((row) => row.map(displayValue));
|
|
299
346
|
const widths = columns.map(
|
|
300
|
-
(
|
|
347
|
+
(column, index) => Math.max(column.label.length, ...values.map((row) => row[index].length))
|
|
301
348
|
);
|
|
302
|
-
const
|
|
303
|
-
const header = columns.map((
|
|
304
|
-
const body =
|
|
305
|
-
(
|
|
349
|
+
const separator = widths.map((width) => "\u2500".repeat(width + 2)).join("\u253C");
|
|
350
|
+
const header = columns.map((column, index) => ` ${column.label.padEnd(widths[index])} `).join("\u2502");
|
|
351
|
+
const body = values.map(
|
|
352
|
+
(row) => row.map((value, index) => ` ${value.padEnd(widths[index])} `).join("\u2502")
|
|
306
353
|
);
|
|
307
|
-
return [header,
|
|
354
|
+
return [header, separator, ...body].join("\n");
|
|
308
355
|
}
|
|
309
356
|
default:
|
|
310
357
|
return "";
|
|
@@ -403,6 +450,65 @@ ${INDENT}${chalk3.bold(label)}
|
|
|
403
450
|
}
|
|
404
451
|
};
|
|
405
452
|
|
|
453
|
+
// src/cli/renderer/view.ts
|
|
454
|
+
import { dump as dump2 } from "js-yaml";
|
|
455
|
+
function asRecord(item) {
|
|
456
|
+
return item;
|
|
457
|
+
}
|
|
458
|
+
function project(view, item) {
|
|
459
|
+
const source = asRecord(item);
|
|
460
|
+
return Object.fromEntries(
|
|
461
|
+
view.columns.map((column) => [column.key, column.get ? column.get(item) : source[column.key]])
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
function renderPageStatus(page) {
|
|
465
|
+
if (!page) return;
|
|
466
|
+
if (page.all) ui.status(`Showing all ${page.total ?? page.returned}`);
|
|
467
|
+
else if (page.total !== void 0)
|
|
468
|
+
ui.status(
|
|
469
|
+
`Showing ${page.returned} of ${page.total}${page.next !== void 0 ? ` (next --offset ${page.next})` : ""}`
|
|
470
|
+
);
|
|
471
|
+
else if (page.next !== void 0) ui.status(`Showing ${page.returned} (more available)`);
|
|
472
|
+
else ui.status(`Showing ${page.returned}`);
|
|
473
|
+
}
|
|
474
|
+
function emitList(view, items, format, opts = {}) {
|
|
475
|
+
if (format === "pretty") {
|
|
476
|
+
if (items.length === 0) ui.emptyList(view.name);
|
|
477
|
+
else view.pretty.list(items);
|
|
478
|
+
} else {
|
|
479
|
+
const rows = format === "json" || format === "yaml" ? items.map((item) => view.structured?.(item) ?? asRecord(item)) : items.map((item) => project(view, item));
|
|
480
|
+
const rendered = formatOutput(rows, view.columns, format);
|
|
481
|
+
if (rendered) console.log(rendered);
|
|
482
|
+
}
|
|
483
|
+
renderPageStatus(opts.page);
|
|
484
|
+
}
|
|
485
|
+
function emitDetail(view, item, format) {
|
|
486
|
+
if (format === "pretty") {
|
|
487
|
+
view.pretty.detail(item);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const structured = view.structured?.(item) ?? asRecord(item);
|
|
491
|
+
if (format === "json") console.log(JSON.stringify(structured, null, 2));
|
|
492
|
+
else if (format === "yaml")
|
|
493
|
+
console.log(dump2(structured, { noRefs: true, lineWidth: -1 }).trimEnd());
|
|
494
|
+
else {
|
|
495
|
+
const rows = Object.entries(structured).map(([key, value]) => ({
|
|
496
|
+
key,
|
|
497
|
+
value: value != null && typeof value === "object" ? JSON.stringify(value) : value
|
|
498
|
+
}));
|
|
499
|
+
console.log(
|
|
500
|
+
formatOutput(
|
|
501
|
+
rows,
|
|
502
|
+
[
|
|
503
|
+
{ key: "key", label: "Key" },
|
|
504
|
+
{ key: "value", label: "Value" }
|
|
505
|
+
],
|
|
506
|
+
format
|
|
507
|
+
)
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
406
512
|
// src/cli/renderer/aigateway.ts
|
|
407
513
|
function renderAiGatewayHeader() {
|
|
408
514
|
ui.header("Prisma AIRS \u2014 AI Gateway", "Gateway workspace operations");
|
|
@@ -498,7 +604,17 @@ function renderWorkspaceDetail(workspace, format = "pretty") {
|
|
|
498
604
|
}
|
|
499
605
|
function renderCostReport(report, format = "pretty") {
|
|
500
606
|
if (format !== "pretty") {
|
|
501
|
-
|
|
607
|
+
emitDetail(
|
|
608
|
+
{
|
|
609
|
+
name: "cost report",
|
|
610
|
+
columns: [],
|
|
611
|
+
pretty: { list() {
|
|
612
|
+
}, detail() {
|
|
613
|
+
} }
|
|
614
|
+
},
|
|
615
|
+
report,
|
|
616
|
+
format
|
|
617
|
+
);
|
|
502
618
|
return;
|
|
503
619
|
}
|
|
504
620
|
const dollars = (cents) => `$${(cents / 100).toFixed(2)}`;
|
|
@@ -597,60 +713,67 @@ function pageMeta(page, returned) {
|
|
|
597
713
|
returned
|
|
598
714
|
};
|
|
599
715
|
}
|
|
600
|
-
function
|
|
601
|
-
|
|
602
|
-
const rows = content.map(toRow);
|
|
603
|
-
if (fmt === "json" || fmt === "yaml") {
|
|
604
|
-
emitStructured({ items: rows, page: pageMeta(page, content.length) }, fmt);
|
|
605
|
-
return;
|
|
606
|
-
}
|
|
607
|
-
if (content.length === 0) {
|
|
608
|
-
ui.emptyList(header.toLowerCase());
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
if (fmt === "pretty") {
|
|
612
|
-
ui.section(`${header}:`);
|
|
613
|
-
for (const item of content) console.log(prettyLine(item));
|
|
614
|
-
const meta = pageMeta(page, content.length);
|
|
615
|
-
console.log();
|
|
616
|
-
ui.dim(
|
|
617
|
-
`page=${meta.number} size=${meta.size} returned=${meta.returned} total=${meta.total ?? "?"}`
|
|
618
|
-
);
|
|
619
|
-
console.log();
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
console.log(formatOutput(rows, columns, fmt));
|
|
716
|
+
function camelKey(key) {
|
|
717
|
+
return key.replace(/[_-]([a-z0-9])/g, (_, char) => char.toUpperCase());
|
|
623
718
|
}
|
|
624
|
-
function
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
719
|
+
function camelize(value) {
|
|
720
|
+
if (Array.isArray(value)) return value.map(camelize);
|
|
721
|
+
if (value && typeof value === "object") {
|
|
722
|
+
return Object.fromEntries(
|
|
723
|
+
Object.entries(value).map(([key, child]) => [
|
|
724
|
+
camelKey(key),
|
|
725
|
+
camelize(child)
|
|
726
|
+
])
|
|
727
|
+
);
|
|
629
728
|
}
|
|
630
|
-
return
|
|
631
|
-
}
|
|
632
|
-
function toKey(label) {
|
|
633
|
-
return label.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
729
|
+
return value;
|
|
634
730
|
}
|
|
635
|
-
function
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
731
|
+
function emitList2(page, fmt, header, toRow, columns, prettyLine) {
|
|
732
|
+
const content = Array.isArray(page?.content) ? page.content : [];
|
|
733
|
+
const meta = pageMeta(page, content.length);
|
|
734
|
+
const view = {
|
|
735
|
+
name: header.toLowerCase(),
|
|
736
|
+
columns: columns.map((column) => ({
|
|
737
|
+
...column,
|
|
738
|
+
get: (item) => toRow(item)[column.key]
|
|
739
|
+
})),
|
|
740
|
+
structured: (item) => camelize(item),
|
|
741
|
+
pretty: {
|
|
742
|
+
list(items) {
|
|
743
|
+
ui.section(`${header}:`);
|
|
744
|
+
for (const item of items) console.log(prettyLine(item));
|
|
745
|
+
console.log();
|
|
746
|
+
},
|
|
747
|
+
detail() {
|
|
748
|
+
}
|
|
646
749
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
750
|
+
};
|
|
751
|
+
const total = typeof meta.total === "number" ? meta.total : void 0;
|
|
752
|
+
const number = Number(meta.number ?? 0);
|
|
753
|
+
const size = Number(meta.size ?? content.length);
|
|
754
|
+
const next = total !== void 0 && (number + 1) * size < total ? (number + 1) * size : void 0;
|
|
755
|
+
emitList(view, content, fmt, { page: { returned: content.length, total, next } });
|
|
756
|
+
}
|
|
757
|
+
function emitDetail2(item, fmt, fields, title) {
|
|
758
|
+
const view = {
|
|
759
|
+
name: title.toLowerCase(),
|
|
760
|
+
columns: [],
|
|
761
|
+
structured: (value) => camelize(value),
|
|
762
|
+
pretty: {
|
|
763
|
+
list() {
|
|
764
|
+
},
|
|
765
|
+
detail() {
|
|
766
|
+
ui.section(`${title}:`);
|
|
767
|
+
ui.keyValue(
|
|
768
|
+
fields.filter(
|
|
769
|
+
(field) => field.value !== void 0 && field.value !== null && field.value !== ""
|
|
770
|
+
).map((field) => [field.label, field.value])
|
|
771
|
+
);
|
|
772
|
+
console.log();
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
emitDetail(view, item, fmt);
|
|
654
777
|
}
|
|
655
778
|
function ackObject(verb, item) {
|
|
656
779
|
const out = { action: verb };
|
|
@@ -681,7 +804,7 @@ function emitIdAck(verb, id) {
|
|
|
681
804
|
}
|
|
682
805
|
var dlpFilteringProfiles = {
|
|
683
806
|
renderList(page, fmt) {
|
|
684
|
-
|
|
807
|
+
emitList2(
|
|
685
808
|
page,
|
|
686
809
|
fmt,
|
|
687
810
|
"Data Filtering Profiles",
|
|
@@ -711,7 +834,7 @@ var dlpFilteringProfiles = {
|
|
|
711
834
|
);
|
|
712
835
|
},
|
|
713
836
|
renderGet(item, fmt) {
|
|
714
|
-
|
|
837
|
+
emitDetail2(
|
|
715
838
|
item,
|
|
716
839
|
fmt,
|
|
717
840
|
[
|
|
@@ -740,7 +863,7 @@ var dlpFilteringProfiles = {
|
|
|
740
863
|
};
|
|
741
864
|
var dlpPatterns = {
|
|
742
865
|
renderList(page, fmt) {
|
|
743
|
-
|
|
866
|
+
emitList2(
|
|
744
867
|
page,
|
|
745
868
|
fmt,
|
|
746
869
|
"Data Patterns",
|
|
@@ -769,7 +892,7 @@ var dlpPatterns = {
|
|
|
769
892
|
);
|
|
770
893
|
},
|
|
771
894
|
renderGet(item, fmt) {
|
|
772
|
-
|
|
895
|
+
emitDetail2(
|
|
773
896
|
item,
|
|
774
897
|
fmt,
|
|
775
898
|
[
|
|
@@ -808,7 +931,7 @@ var dlpPatterns = {
|
|
|
808
931
|
};
|
|
809
932
|
var dlpProfiles = {
|
|
810
933
|
renderList(page, fmt) {
|
|
811
|
-
|
|
934
|
+
emitList2(
|
|
812
935
|
page,
|
|
813
936
|
fmt,
|
|
814
937
|
"Data Profiles",
|
|
@@ -837,7 +960,7 @@ var dlpProfiles = {
|
|
|
837
960
|
);
|
|
838
961
|
},
|
|
839
962
|
renderGet(item, fmt) {
|
|
840
|
-
|
|
963
|
+
emitDetail2(
|
|
841
964
|
item,
|
|
842
965
|
fmt,
|
|
843
966
|
[
|
|
@@ -865,7 +988,7 @@ var dlpProfiles = {
|
|
|
865
988
|
};
|
|
866
989
|
var dlpDictionaries = {
|
|
867
990
|
renderList(page, fmt) {
|
|
868
|
-
|
|
991
|
+
emitList2(
|
|
869
992
|
page,
|
|
870
993
|
fmt,
|
|
871
994
|
"Data Dictionaries",
|
|
@@ -894,7 +1017,7 @@ var dlpDictionaries = {
|
|
|
894
1017
|
);
|
|
895
1018
|
},
|
|
896
1019
|
renderGet(item, fmt) {
|
|
897
|
-
|
|
1020
|
+
emitDetail2(
|
|
898
1021
|
item,
|
|
899
1022
|
fmt,
|
|
900
1023
|
[
|
|
@@ -989,7 +1112,15 @@ function renderEvalTerminal(output) {
|
|
|
989
1112
|
|
|
990
1113
|
// src/cli/renderer/modelsecurity.ts
|
|
991
1114
|
import chalk7 from "chalk";
|
|
992
|
-
|
|
1115
|
+
function resourceView(name, columns, pretty) {
|
|
1116
|
+
return { name, columns, pretty };
|
|
1117
|
+
}
|
|
1118
|
+
function structuredList(name, items, columns, format, pretty) {
|
|
1119
|
+
emitList(resourceView(name, columns, { list: pretty, detail: () => void 0 }), items, format);
|
|
1120
|
+
}
|
|
1121
|
+
function structuredDetail(name, item, format, pretty) {
|
|
1122
|
+
emitDetail(resourceView(name, [], { list: () => void 0, detail: pretty }), item, format);
|
|
1123
|
+
}
|
|
993
1124
|
function renderModelSecurityHeader() {
|
|
994
1125
|
ui.header("Prisma AIRS \u2014 Model Security", "ML model supply chain security");
|
|
995
1126
|
}
|
|
@@ -1012,31 +1143,25 @@ function stateColor(state) {
|
|
|
1012
1143
|
}
|
|
1013
1144
|
}
|
|
1014
1145
|
function renderGroupList(groups, format = "pretty") {
|
|
1015
|
-
if (groups.length === 0) {
|
|
1016
|
-
ui.emptyList("security groups");
|
|
1017
|
-
return;
|
|
1018
|
-
}
|
|
1019
1146
|
if (format !== "pretty") {
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
{ key: "name", label: "Name" },
|
|
1032
|
-
{ key: "state", label: "State" },
|
|
1033
|
-
{ key: "sourceType", label: "Source Type" }
|
|
1034
|
-
],
|
|
1035
|
-
format
|
|
1036
|
-
)
|
|
1147
|
+
structuredList(
|
|
1148
|
+
"security groups",
|
|
1149
|
+
groups,
|
|
1150
|
+
[
|
|
1151
|
+
{ key: "uuid", label: "ID" },
|
|
1152
|
+
{ key: "name", label: "Name" },
|
|
1153
|
+
{ key: "state", label: "State" },
|
|
1154
|
+
{ key: "sourceType", label: "Source Type" }
|
|
1155
|
+
],
|
|
1156
|
+
format,
|
|
1157
|
+
() => void 0
|
|
1037
1158
|
);
|
|
1038
1159
|
return;
|
|
1039
1160
|
}
|
|
1161
|
+
if (groups.length === 0) {
|
|
1162
|
+
ui.emptyList("security groups");
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1040
1165
|
ui.section("Security Groups:");
|
|
1041
1166
|
for (const g of groups) {
|
|
1042
1167
|
ui.dim(g.uuid);
|
|
@@ -1046,12 +1171,8 @@ function renderGroupList(groups, format = "pretty") {
|
|
|
1046
1171
|
console.log();
|
|
1047
1172
|
}
|
|
1048
1173
|
function renderGroupDetail(group, format = "pretty") {
|
|
1049
|
-
if (format
|
|
1050
|
-
|
|
1051
|
-
return;
|
|
1052
|
-
}
|
|
1053
|
-
if (format === "yaml") {
|
|
1054
|
-
console.log(yamlDump3(group));
|
|
1174
|
+
if (format !== "pretty") {
|
|
1175
|
+
structuredDetail("security group", group, format, () => void 0);
|
|
1055
1176
|
return;
|
|
1056
1177
|
}
|
|
1057
1178
|
ui.section("Security Group Detail:");
|
|
@@ -1068,33 +1189,30 @@ function renderGroupDetail(group, format = "pretty") {
|
|
|
1068
1189
|
console.log();
|
|
1069
1190
|
}
|
|
1070
1191
|
function renderRuleList(rules, format = "pretty") {
|
|
1071
|
-
if (rules.length === 0) {
|
|
1072
|
-
ui.emptyList("security rules");
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
1192
|
if (format !== "pretty") {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
],
|
|
1093
|
-
format
|
|
1094
|
-
)
|
|
1193
|
+
structuredList(
|
|
1194
|
+
"security rules",
|
|
1195
|
+
rules,
|
|
1196
|
+
[
|
|
1197
|
+
{ key: "uuid", label: "ID" },
|
|
1198
|
+
{ key: "name", label: "Name" },
|
|
1199
|
+
{ key: "ruleType", label: "Type" },
|
|
1200
|
+
{ key: "defaultState", label: "Default State" },
|
|
1201
|
+
{
|
|
1202
|
+
key: "compatibleSources",
|
|
1203
|
+
label: "Sources",
|
|
1204
|
+
get: (rule) => rule.compatibleSources.join(", ")
|
|
1205
|
+
}
|
|
1206
|
+
],
|
|
1207
|
+
format,
|
|
1208
|
+
() => void 0
|
|
1095
1209
|
);
|
|
1096
1210
|
return;
|
|
1097
1211
|
}
|
|
1212
|
+
if (rules.length === 0) {
|
|
1213
|
+
ui.emptyList("security rules");
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1098
1216
|
ui.section("Security Rules:");
|
|
1099
1217
|
for (const r of rules) {
|
|
1100
1218
|
ui.dim(r.uuid);
|
|
@@ -1106,7 +1224,11 @@ function renderRuleList(rules, format = "pretty") {
|
|
|
1106
1224
|
}
|
|
1107
1225
|
console.log();
|
|
1108
1226
|
}
|
|
1109
|
-
function renderRuleDetail(rule) {
|
|
1227
|
+
function renderRuleDetail(rule, format = "pretty") {
|
|
1228
|
+
if (format !== "pretty") {
|
|
1229
|
+
structuredDetail("security rule", rule, format, () => void 0);
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1110
1232
|
ui.section("Security Rule Detail:");
|
|
1111
1233
|
ui.keyValue([
|
|
1112
1234
|
["UUID", rule.uuid],
|
|
@@ -1137,7 +1259,21 @@ function renderRuleDetail(rule) {
|
|
|
1137
1259
|
}
|
|
1138
1260
|
console.log();
|
|
1139
1261
|
}
|
|
1140
|
-
function renderRuleInstanceList(instances) {
|
|
1262
|
+
function renderRuleInstanceList(instances, format = "pretty") {
|
|
1263
|
+
if (format !== "pretty") {
|
|
1264
|
+
structuredList(
|
|
1265
|
+
"rule instances",
|
|
1266
|
+
instances,
|
|
1267
|
+
[
|
|
1268
|
+
{ key: "uuid", label: "ID" },
|
|
1269
|
+
{ key: "securityRuleUuid", label: "Rule ID" },
|
|
1270
|
+
{ key: "state", label: "State" }
|
|
1271
|
+
],
|
|
1272
|
+
format,
|
|
1273
|
+
() => void 0
|
|
1274
|
+
);
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1141
1277
|
if (instances.length === 0) {
|
|
1142
1278
|
ui.emptyList("rule instances");
|
|
1143
1279
|
return;
|
|
@@ -1150,7 +1286,11 @@ function renderRuleInstanceList(instances) {
|
|
|
1150
1286
|
}
|
|
1151
1287
|
console.log();
|
|
1152
1288
|
}
|
|
1153
|
-
function renderRuleInstanceDetail(instance) {
|
|
1289
|
+
function renderRuleInstanceDetail(instance, format = "pretty") {
|
|
1290
|
+
if (format !== "pretty") {
|
|
1291
|
+
structuredDetail("rule instance", instance, format, () => void 0);
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1154
1294
|
ui.section("Rule Instance Detail:");
|
|
1155
1295
|
const pairs = [
|
|
1156
1296
|
["UUID", instance.uuid],
|
|
@@ -1175,37 +1315,26 @@ function renderRuleInstanceDetail(instance) {
|
|
|
1175
1315
|
console.log();
|
|
1176
1316
|
}
|
|
1177
1317
|
function renderMsScanList(scans, format = "pretty") {
|
|
1178
|
-
if (scans.length === 0) {
|
|
1179
|
-
ui.emptyList("scans");
|
|
1180
|
-
return;
|
|
1181
|
-
}
|
|
1182
1318
|
if (format !== "pretty") {
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
[
|
|
1196
|
-
{ key: "id", label: "ID" },
|
|
1197
|
-
{ key: "outcome", label: "Outcome" },
|
|
1198
|
-
{ key: "origin", label: "Origin" },
|
|
1199
|
-
{ key: "modelUri", label: "Model URI" },
|
|
1200
|
-
{ key: "passed", label: "Passed" },
|
|
1201
|
-
{ key: "failed", label: "Failed" },
|
|
1202
|
-
{ key: "createdAt", label: "Created" }
|
|
1203
|
-
],
|
|
1204
|
-
format
|
|
1205
|
-
)
|
|
1319
|
+
structuredList(
|
|
1320
|
+
"scans",
|
|
1321
|
+
scans,
|
|
1322
|
+
[
|
|
1323
|
+
{ key: "uuid", label: "ID" },
|
|
1324
|
+
{ key: "evalOutcome", label: "Outcome" },
|
|
1325
|
+
{ key: "scanOrigin", label: "Origin" },
|
|
1326
|
+
{ key: "modelUri", label: "Model URI" },
|
|
1327
|
+
{ key: "createdAt", label: "Created" }
|
|
1328
|
+
],
|
|
1329
|
+
format,
|
|
1330
|
+
() => void 0
|
|
1206
1331
|
);
|
|
1207
1332
|
return;
|
|
1208
1333
|
}
|
|
1334
|
+
if (scans.length === 0) {
|
|
1335
|
+
ui.emptyList("scans");
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1209
1338
|
ui.section("Model Security Scans:");
|
|
1210
1339
|
for (const s of scans) {
|
|
1211
1340
|
ui.dim(s.uuid);
|
|
@@ -1222,7 +1351,11 @@ function renderMsScanList(scans, format = "pretty") {
|
|
|
1222
1351
|
}
|
|
1223
1352
|
console.log();
|
|
1224
1353
|
}
|
|
1225
|
-
function renderMsScanDetail(scan) {
|
|
1354
|
+
function renderMsScanDetail(scan, format = "pretty") {
|
|
1355
|
+
if (format !== "pretty") {
|
|
1356
|
+
structuredDetail("scan", scan, format, () => void 0);
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1226
1359
|
ui.section("Scan Detail:");
|
|
1227
1360
|
const pairs = [
|
|
1228
1361
|
["UUID", scan.uuid],
|
|
@@ -1248,7 +1381,22 @@ function renderMsScanDetail(scan) {
|
|
|
1248
1381
|
}
|
|
1249
1382
|
console.log();
|
|
1250
1383
|
}
|
|
1251
|
-
function renderEvaluationList(evaluations) {
|
|
1384
|
+
function renderEvaluationList(evaluations, format = "pretty") {
|
|
1385
|
+
if (format !== "pretty") {
|
|
1386
|
+
structuredList(
|
|
1387
|
+
"evaluations",
|
|
1388
|
+
evaluations,
|
|
1389
|
+
[
|
|
1390
|
+
{ key: "uuid", label: "ID" },
|
|
1391
|
+
{ key: "ruleName", label: "Rule" },
|
|
1392
|
+
{ key: "result", label: "Result" },
|
|
1393
|
+
{ key: "ruleInstanceState", label: "State" }
|
|
1394
|
+
],
|
|
1395
|
+
format,
|
|
1396
|
+
() => void 0
|
|
1397
|
+
);
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1252
1400
|
if (evaluations.length === 0) {
|
|
1253
1401
|
ui.emptyList("evaluations");
|
|
1254
1402
|
return;
|
|
@@ -1262,7 +1410,11 @@ function renderEvaluationList(evaluations) {
|
|
|
1262
1410
|
}
|
|
1263
1411
|
console.log();
|
|
1264
1412
|
}
|
|
1265
|
-
function renderEvaluationDetail(evaluation) {
|
|
1413
|
+
function renderEvaluationDetail(evaluation, format = "pretty") {
|
|
1414
|
+
if (format !== "pretty") {
|
|
1415
|
+
structuredDetail("evaluation", evaluation, format, () => void 0);
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1266
1418
|
ui.section("Evaluation Detail:");
|
|
1267
1419
|
ui.keyValue([
|
|
1268
1420
|
["UUID", evaluation.uuid],
|
|
@@ -1275,7 +1427,22 @@ function renderEvaluationDetail(evaluation) {
|
|
|
1275
1427
|
]);
|
|
1276
1428
|
console.log();
|
|
1277
1429
|
}
|
|
1278
|
-
function renderViolationList(violations) {
|
|
1430
|
+
function renderViolationList(violations, format = "pretty") {
|
|
1431
|
+
if (format !== "pretty") {
|
|
1432
|
+
structuredList(
|
|
1433
|
+
"violations",
|
|
1434
|
+
violations,
|
|
1435
|
+
[
|
|
1436
|
+
{ key: "uuid", label: "ID" },
|
|
1437
|
+
{ key: "ruleName", label: "Rule" },
|
|
1438
|
+
{ key: "file", label: "File" },
|
|
1439
|
+
{ key: "threat", label: "Threat" }
|
|
1440
|
+
],
|
|
1441
|
+
format,
|
|
1442
|
+
() => void 0
|
|
1443
|
+
);
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1279
1446
|
if (violations.length === 0) {
|
|
1280
1447
|
ui.emptyList("violations");
|
|
1281
1448
|
return;
|
|
@@ -1289,7 +1456,11 @@ function renderViolationList(violations) {
|
|
|
1289
1456
|
}
|
|
1290
1457
|
console.log();
|
|
1291
1458
|
}
|
|
1292
|
-
function renderViolationDetail(violation) {
|
|
1459
|
+
function renderViolationDetail(violation, format = "pretty") {
|
|
1460
|
+
if (format !== "pretty") {
|
|
1461
|
+
structuredDetail("violation", violation, format, () => void 0);
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1293
1464
|
ui.section("Violation Detail:");
|
|
1294
1465
|
ui.keyValue([
|
|
1295
1466
|
["UUID", violation.uuid],
|
|
@@ -1302,7 +1473,22 @@ function renderViolationDetail(violation) {
|
|
|
1302
1473
|
]);
|
|
1303
1474
|
console.log();
|
|
1304
1475
|
}
|
|
1305
|
-
function renderFileList(files) {
|
|
1476
|
+
function renderFileList(files, format = "pretty") {
|
|
1477
|
+
if (format !== "pretty") {
|
|
1478
|
+
structuredList(
|
|
1479
|
+
"files",
|
|
1480
|
+
files,
|
|
1481
|
+
[
|
|
1482
|
+
{ key: "uuid", label: "ID" },
|
|
1483
|
+
{ key: "path", label: "Path" },
|
|
1484
|
+
{ key: "type", label: "Type" },
|
|
1485
|
+
{ key: "result", label: "Result" }
|
|
1486
|
+
],
|
|
1487
|
+
format,
|
|
1488
|
+
() => void 0
|
|
1489
|
+
);
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1306
1492
|
if (files.length === 0) {
|
|
1307
1493
|
ui.emptyList("files");
|
|
1308
1494
|
return;
|
|
@@ -1338,33 +1524,30 @@ function renderLabelValues(key, values) {
|
|
|
1338
1524
|
console.log();
|
|
1339
1525
|
}
|
|
1340
1526
|
function renderModelList(models, format = "pretty") {
|
|
1341
|
-
if (models.length === 0) {
|
|
1342
|
-
ui.emptyList("models");
|
|
1343
|
-
return;
|
|
1344
|
-
}
|
|
1345
1527
|
if (format !== "pretty") {
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
],
|
|
1363
|
-
format
|
|
1364
|
-
)
|
|
1528
|
+
structuredList(
|
|
1529
|
+
"models",
|
|
1530
|
+
models,
|
|
1531
|
+
[
|
|
1532
|
+
{ key: "uuid", label: "ID" },
|
|
1533
|
+
{ key: "name", label: "Name" },
|
|
1534
|
+
{ key: "latestVersionOutcome", label: "Outcome" },
|
|
1535
|
+
{
|
|
1536
|
+
key: "latestVersionFormats",
|
|
1537
|
+
label: "Formats",
|
|
1538
|
+
get: (model) => (model.latestVersionFormats ?? []).join(", ")
|
|
1539
|
+
},
|
|
1540
|
+
{ key: "latestVersionScanTime", label: "Last Scan" }
|
|
1541
|
+
],
|
|
1542
|
+
format,
|
|
1543
|
+
() => void 0
|
|
1365
1544
|
);
|
|
1366
1545
|
return;
|
|
1367
1546
|
}
|
|
1547
|
+
if (models.length === 0) {
|
|
1548
|
+
ui.emptyList("models");
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1368
1551
|
ui.section("Models:");
|
|
1369
1552
|
for (const m of models) {
|
|
1370
1553
|
ui.dim(m.uuid);
|
|
@@ -1376,7 +1559,7 @@ function renderModelList(models, format = "pretty") {
|
|
|
1376
1559
|
}
|
|
1377
1560
|
function renderModelDetail(model, format = "pretty") {
|
|
1378
1561
|
if (format !== "pretty") {
|
|
1379
|
-
|
|
1562
|
+
structuredDetail("model", model, format, () => void 0);
|
|
1380
1563
|
return;
|
|
1381
1564
|
}
|
|
1382
1565
|
ui.section("Model Detail:");
|
|
@@ -1403,33 +1586,26 @@ function renderModelDetail(model, format = "pretty") {
|
|
|
1403
1586
|
console.log();
|
|
1404
1587
|
}
|
|
1405
1588
|
function renderModelVersionList(versions, format = "pretty") {
|
|
1406
|
-
if (versions.length === 0) {
|
|
1407
|
-
ui.emptyList("versions");
|
|
1408
|
-
return;
|
|
1409
|
-
}
|
|
1410
1589
|
if (format !== "pretty") {
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
{ key: "revision", label: "Revision" },
|
|
1424
|
-
{ key: "files", label: "Files" },
|
|
1425
|
-
{ key: "outcome", label: "Outcome" },
|
|
1426
|
-
{ key: "scanned", label: "Last Scan" }
|
|
1427
|
-
],
|
|
1428
|
-
format
|
|
1429
|
-
)
|
|
1590
|
+
structuredList(
|
|
1591
|
+
"versions",
|
|
1592
|
+
versions,
|
|
1593
|
+
[
|
|
1594
|
+
{ key: "uuid", label: "ID" },
|
|
1595
|
+
{ key: "revision", label: "Revision" },
|
|
1596
|
+
{ key: "fileCount", label: "Files" },
|
|
1597
|
+
{ key: "lastEvalOutcome", label: "Outcome" },
|
|
1598
|
+
{ key: "latestScanTime", label: "Last Scan" }
|
|
1599
|
+
],
|
|
1600
|
+
format,
|
|
1601
|
+
() => void 0
|
|
1430
1602
|
);
|
|
1431
1603
|
return;
|
|
1432
1604
|
}
|
|
1605
|
+
if (versions.length === 0) {
|
|
1606
|
+
ui.emptyList("versions");
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1433
1609
|
ui.section("Model Versions:");
|
|
1434
1610
|
for (const v of versions) {
|
|
1435
1611
|
ui.dim(v.uuid);
|
|
@@ -1441,7 +1617,7 @@ function renderModelVersionList(versions, format = "pretty") {
|
|
|
1441
1617
|
}
|
|
1442
1618
|
function renderModelVersionDetail(version, format = "pretty") {
|
|
1443
1619
|
if (format !== "pretty") {
|
|
1444
|
-
|
|
1620
|
+
structuredDetail("model version", version, format, () => void 0);
|
|
1445
1621
|
return;
|
|
1446
1622
|
}
|
|
1447
1623
|
ui.section("Model Version Detail:");
|
|
@@ -1473,31 +1649,12 @@ function renderModelVersionDetail(version, format = "pretty") {
|
|
|
1473
1649
|
console.log();
|
|
1474
1650
|
}
|
|
1475
1651
|
function renderModelFileList(files, format = "pretty") {
|
|
1476
|
-
if (
|
|
1477
|
-
|
|
1652
|
+
if (format !== "pretty") {
|
|
1653
|
+
renderFileList(files, format);
|
|
1478
1654
|
return;
|
|
1479
1655
|
}
|
|
1480
|
-
if (
|
|
1481
|
-
|
|
1482
|
-
id: f.uuid,
|
|
1483
|
-
path: f.path,
|
|
1484
|
-
type: f.type,
|
|
1485
|
-
formats: f.formats.join(", "),
|
|
1486
|
-
result: f.result
|
|
1487
|
-
}));
|
|
1488
|
-
console.log(
|
|
1489
|
-
formatOutput(
|
|
1490
|
-
rows,
|
|
1491
|
-
[
|
|
1492
|
-
{ key: "id", label: "ID" },
|
|
1493
|
-
{ key: "path", label: "Path" },
|
|
1494
|
-
{ key: "type", label: "Type" },
|
|
1495
|
-
{ key: "formats", label: "Formats" },
|
|
1496
|
-
{ key: "result", label: "Result" }
|
|
1497
|
-
],
|
|
1498
|
-
format
|
|
1499
|
-
)
|
|
1500
|
-
);
|
|
1656
|
+
if (files.length === 0) {
|
|
1657
|
+
ui.emptyList("files");
|
|
1501
1658
|
return;
|
|
1502
1659
|
}
|
|
1503
1660
|
renderFileList(files);
|
|
@@ -1505,7 +1662,7 @@ function renderModelFileList(files, format = "pretty") {
|
|
|
1505
1662
|
|
|
1506
1663
|
// src/cli/renderer/redteam.ts
|
|
1507
1664
|
import chalk8 from "chalk";
|
|
1508
|
-
import { dump as
|
|
1665
|
+
import { dump as yamlDump3 } from "js-yaml";
|
|
1509
1666
|
function renderRedteamHeader() {
|
|
1510
1667
|
ui.header("Prisma AIRS \u2014 AI Red Team", "Adversarial scan operations");
|
|
1511
1668
|
}
|
|
@@ -1825,7 +1982,7 @@ function renderTargetDetail(target, format = "pretty") {
|
|
|
1825
1982
|
if (format === "json") {
|
|
1826
1983
|
console.log(JSON.stringify(target, null, 2));
|
|
1827
1984
|
} else if (format === "yaml") {
|
|
1828
|
-
console.log(
|
|
1985
|
+
console.log(yamlDump3(target));
|
|
1829
1986
|
}
|
|
1830
1987
|
return;
|
|
1831
1988
|
}
|
|
@@ -1857,7 +2014,7 @@ function renderPromptSetDetail(ps, format = "pretty", info) {
|
|
|
1857
2014
|
if (format === "json") {
|
|
1858
2015
|
console.log(JSON.stringify(payload, null, 2));
|
|
1859
2016
|
} else if (format === "yaml") {
|
|
1860
|
-
console.log(
|
|
2017
|
+
console.log(yamlDump3(payload));
|
|
1861
2018
|
}
|
|
1862
2019
|
return;
|
|
1863
2020
|
}
|
|
@@ -1894,7 +2051,7 @@ function renderPromptList(prompts, format = "pretty") {
|
|
|
1894
2051
|
if (format === "json") {
|
|
1895
2052
|
console.log(JSON.stringify(prompts, null, 2));
|
|
1896
2053
|
} else if (format === "yaml") {
|
|
1897
|
-
console.log(
|
|
2054
|
+
console.log(yamlDump3(prompts));
|
|
1898
2055
|
}
|
|
1899
2056
|
return;
|
|
1900
2057
|
}
|
|
@@ -1917,7 +2074,7 @@ function renderPromptDetail(p, format = "pretty") {
|
|
|
1917
2074
|
if (format === "json") {
|
|
1918
2075
|
console.log(JSON.stringify(p, null, 2));
|
|
1919
2076
|
} else if (format === "yaml") {
|
|
1920
|
-
console.log(
|
|
2077
|
+
console.log(yamlDump3(p));
|
|
1921
2078
|
}
|
|
1922
2079
|
return;
|
|
1923
2080
|
}
|
|
@@ -1937,7 +2094,7 @@ function renderPropertyNames(names, format = "pretty") {
|
|
|
1937
2094
|
if (format === "json") {
|
|
1938
2095
|
console.log(JSON.stringify(names, null, 2));
|
|
1939
2096
|
} else if (format === "yaml") {
|
|
1940
|
-
console.log(
|
|
2097
|
+
console.log(yamlDump3(names));
|
|
1941
2098
|
} else {
|
|
1942
2099
|
const rows = names.map((n) => ({ name: n }));
|
|
1943
2100
|
console.log(formatOutput(rows, [{ key: "name", label: "Name" }], format));
|
|
@@ -1992,7 +2149,7 @@ function renderPropertyValues(payload, format = "pretty") {
|
|
|
1992
2149
|
if (format === "json") {
|
|
1993
2150
|
console.log(JSON.stringify(payload, null, 2));
|
|
1994
2151
|
} else if (format === "yaml") {
|
|
1995
|
-
console.log(
|
|
2152
|
+
console.log(yamlDump3(payload));
|
|
1996
2153
|
}
|
|
1997
2154
|
return;
|
|
1998
2155
|
}
|
|
@@ -2023,7 +2180,7 @@ function renderInstanceDetail(inst, format = "pretty") {
|
|
|
2023
2180
|
if (format === "json") {
|
|
2024
2181
|
console.log(JSON.stringify(inst, null, 2));
|
|
2025
2182
|
} else if (format === "yaml") {
|
|
2026
|
-
console.log(
|
|
2183
|
+
console.log(yamlDump3(inst));
|
|
2027
2184
|
}
|
|
2028
2185
|
return;
|
|
2029
2186
|
}
|
|
@@ -2041,7 +2198,7 @@ function renderRegistryCredentials(creds, format = "pretty") {
|
|
|
2041
2198
|
if (format === "json") {
|
|
2042
2199
|
console.log(JSON.stringify(creds, null, 2));
|
|
2043
2200
|
} else if (format === "yaml") {
|
|
2044
|
-
console.log(
|
|
2201
|
+
console.log(yamlDump3(creds));
|
|
2045
2202
|
}
|
|
2046
2203
|
return;
|
|
2047
2204
|
}
|
|
@@ -2103,7 +2260,7 @@ function renderChannelList(channels, format = "pretty") {
|
|
|
2103
2260
|
}
|
|
2104
2261
|
function renderChannelDetail(channel, format = "pretty") {
|
|
2105
2262
|
if (format !== "pretty") {
|
|
2106
|
-
console.log(format === "json" ? JSON.stringify(channel, null, 2) :
|
|
2263
|
+
console.log(format === "json" ? JSON.stringify(channel, null, 2) : yamlDump3(channel));
|
|
2107
2264
|
return;
|
|
2108
2265
|
}
|
|
2109
2266
|
ui.section("Channel Detail:");
|
|
@@ -2129,7 +2286,7 @@ function renderChannelDetail(channel, format = "pretty") {
|
|
|
2129
2286
|
}
|
|
2130
2287
|
function renderChannelStats(stats, format = "pretty") {
|
|
2131
2288
|
if (format !== "pretty") {
|
|
2132
|
-
console.log(format === "json" ? JSON.stringify(stats, null, 2) :
|
|
2289
|
+
console.log(format === "json" ? JSON.stringify(stats, null, 2) : yamlDump3(stats));
|
|
2133
2290
|
return;
|
|
2134
2291
|
}
|
|
2135
2292
|
ui.section("Network Broker Stats:");
|
|
@@ -2147,7 +2304,7 @@ function renderChannelStats(stats, format = "pretty") {
|
|
|
2147
2304
|
function renderLanguages(data, format = "pretty") {
|
|
2148
2305
|
if (format !== "pretty") {
|
|
2149
2306
|
if (format === "json" || format === "yaml") {
|
|
2150
|
-
console.log(format === "json" ? JSON.stringify(data, null, 2) :
|
|
2307
|
+
console.log(format === "json" ? JSON.stringify(data, null, 2) : yamlDump3(data));
|
|
2151
2308
|
return;
|
|
2152
2309
|
}
|
|
2153
2310
|
console.log(
|
|
@@ -2256,7 +2413,7 @@ function renderAdapterList(adapters, format = "pretty", totalItems) {
|
|
|
2256
2413
|
}
|
|
2257
2414
|
function renderAdapterDetail(adapter, format = "pretty") {
|
|
2258
2415
|
if (format !== "pretty") {
|
|
2259
|
-
console.log(format === "json" ? JSON.stringify(adapter, null, 2) :
|
|
2416
|
+
console.log(format === "json" ? JSON.stringify(adapter, null, 2) : yamlDump3(adapter));
|
|
2260
2417
|
return;
|
|
2261
2418
|
}
|
|
2262
2419
|
ui.section("Adapter Detail:");
|
|
@@ -2289,7 +2446,7 @@ function renderAdapterDetail(adapter, format = "pretty") {
|
|
|
2289
2446
|
}
|
|
2290
2447
|
function renderAdapterValidation(result, format = "pretty") {
|
|
2291
2448
|
if (format !== "pretty") {
|
|
2292
|
-
console.log(format === "json" ? JSON.stringify(result, null, 2) :
|
|
2449
|
+
console.log(format === "json" ? JSON.stringify(result, null, 2) : yamlDump3(result));
|
|
2293
2450
|
return;
|
|
2294
2451
|
}
|
|
2295
2452
|
if (result.validated) {
|
|
@@ -2980,9 +3137,9 @@ function registerAiGatewayCommand(program) {
|
|
|
2980
3137
|
}
|
|
2981
3138
|
});
|
|
2982
3139
|
const telemetry = aigateway.command("telemetry").description("AI Gateway runtime telemetry (data plane)");
|
|
2983
|
-
telemetry.command("cost").description(
|
|
3140
|
+
const cost = telemetry.command("cost").description(
|
|
2984
3141
|
"Total and per-day spend for a workspace (API reports cents; pretty output shows dollars)"
|
|
2985
|
-
).requiredOption("--workspace <slug>", "Workspace slug (not UUID), e.g. ws-main-a-349e0e").option("--days <n>", "Rolling window in days, counted back from now", "7").option("--output <format>", "Output format: pretty, json, yaml"
|
|
3142
|
+
).requiredOption("--workspace <slug>", "Workspace slug (not UUID), e.g. ws-main-a-349e0e").option("--days <n>", "Rolling window in days, counted back from now", "7").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").addHelpText(
|
|
2986
3143
|
"after",
|
|
2987
3144
|
examples(
|
|
2988
3145
|
"airs aigateway telemetry cost --workspace ws-main-a-349e0e",
|
|
@@ -2990,7 +3147,7 @@ function registerAiGatewayCommand(program) {
|
|
|
2990
3147
|
)
|
|
2991
3148
|
).action(async (opts) => {
|
|
2992
3149
|
try {
|
|
2993
|
-
const fmt = opts
|
|
3150
|
+
const fmt = await resolveOutput(cost, opts);
|
|
2994
3151
|
if (fmt === "pretty") renderAiGatewayHeader();
|
|
2995
3152
|
const days = Number.parseInt(opts.days, 10);
|
|
2996
3153
|
if (!Number.isFinite(days) || days <= 0) {
|
|
@@ -3194,13 +3351,6 @@ function assertKnownKey(key) {
|
|
|
3194
3351
|
usageError(`Unknown config key '${key}'. Valid keys: ${CONFIG_KEYS.join(", ")}`);
|
|
3195
3352
|
}
|
|
3196
3353
|
}
|
|
3197
|
-
var LIST_FORMATS = ["pretty", "json", "yaml"];
|
|
3198
|
-
function parseListFormat(value) {
|
|
3199
|
-
if (!LIST_FORMATS.includes(value)) {
|
|
3200
|
-
usageError(`Invalid --output '${value}'. Valid formats: ${LIST_FORMATS.join(", ")}`);
|
|
3201
|
-
}
|
|
3202
|
-
return value;
|
|
3203
|
-
}
|
|
3204
3354
|
var COLUMNS = [
|
|
3205
3355
|
{ key: "key", label: "Key" },
|
|
3206
3356
|
{ key: "value", label: "Value" },
|
|
@@ -3215,9 +3365,9 @@ function registerConfigCommand(program) {
|
|
|
3215
3365
|
"airs config get mgmtTsgId"
|
|
3216
3366
|
)
|
|
3217
3367
|
);
|
|
3218
|
-
config.command("list").description("Show effective configuration with per-key source (env/file/default)").option("--output <format>", "Output format: pretty,
|
|
3368
|
+
const configList = config.command("list").description("Show effective configuration with per-key source (env/file/default)").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").option("--reveal", "Show secret values in full").action(async (opts) => {
|
|
3219
3369
|
try {
|
|
3220
|
-
const fmt =
|
|
3370
|
+
const fmt = await resolveOutput(configList, opts);
|
|
3221
3371
|
const filePath = resolveConfigFilePath();
|
|
3222
3372
|
const rows = buildConfigRows(await inspectConfig(), Boolean(opts.reveal));
|
|
3223
3373
|
if (fmt === "pretty") {
|
|
@@ -3232,12 +3382,18 @@ function registerConfigCommand(program) {
|
|
|
3232
3382
|
fail(err);
|
|
3233
3383
|
}
|
|
3234
3384
|
});
|
|
3235
|
-
config.command("get <key>").description("Print a single effective config value").option("--reveal", "Show the real value of a secret key").action(async (key, opts) => {
|
|
3385
|
+
const configGet = config.command("get <key>").description("Print a single effective config value").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").option("--reveal", "Show the real value of a secret key").action(async (key, opts) => {
|
|
3236
3386
|
try {
|
|
3237
3387
|
assertKnownKey(key);
|
|
3238
3388
|
const inspected = await inspectConfig();
|
|
3239
3389
|
const entry = inspected[key];
|
|
3240
3390
|
const raw = entry.value == null ? "" : String(entry.value);
|
|
3391
|
+
const fmt = await resolveOutput(configGet, opts);
|
|
3392
|
+
const value = raw !== "" && isSecretKey(key) && !opts.reveal ? maskSecret(raw) : raw;
|
|
3393
|
+
if (fmt !== "pretty") {
|
|
3394
|
+
console.log(formatOutput([{ key, value, source: entry.source }], COLUMNS, fmt));
|
|
3395
|
+
return;
|
|
3396
|
+
}
|
|
3241
3397
|
if (raw !== "" && isSecretKey(key)) {
|
|
3242
3398
|
if (opts.reveal) {
|
|
3243
3399
|
ui.status(`Warning: printing secret value for '${key}'`);
|
|
@@ -3590,20 +3746,6 @@ var STATUS_KIND = {
|
|
|
3590
3746
|
warn: "warn",
|
|
3591
3747
|
fail: "error"
|
|
3592
3748
|
};
|
|
3593
|
-
var DOCTOR_FORMATS = ["pretty", "json", "yaml"];
|
|
3594
|
-
function parseDoctorFormat(value) {
|
|
3595
|
-
if (!DOCTOR_FORMATS.includes(value)) {
|
|
3596
|
-
usageError(`Invalid --output '${value}'. Valid formats: ${DOCTOR_FORMATS.join(", ")}`);
|
|
3597
|
-
}
|
|
3598
|
-
return value;
|
|
3599
|
-
}
|
|
3600
|
-
function toYaml(checks) {
|
|
3601
|
-
return checks.map((c) => {
|
|
3602
|
-
const lines = [`name: ${c.name}`, `status: ${c.status}`, `detail: ${c.detail}`];
|
|
3603
|
-
if (c.hint) lines.push(`hint: ${c.hint}`);
|
|
3604
|
-
return lines.join("\n");
|
|
3605
|
-
}).join("\n---\n");
|
|
3606
|
-
}
|
|
3607
3749
|
function renderPretty(checks) {
|
|
3608
3750
|
ui.header("Doctor", "Prisma AIRS CLI preflight checks");
|
|
3609
3751
|
for (const check of checks) {
|
|
@@ -3623,18 +3765,27 @@ function renderPretty(checks) {
|
|
|
3623
3765
|
console.log("");
|
|
3624
3766
|
}
|
|
3625
3767
|
function registerDoctorCommand(program) {
|
|
3626
|
-
program.command("doctor").description("Check credentials, config, and API connectivity (preflight)").option("--output <format>", "Output format: pretty,
|
|
3768
|
+
const doctor = program.command("doctor").description("Check credentials, config, and API connectivity (preflight)").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").addHelpText(
|
|
3627
3769
|
"after",
|
|
3628
3770
|
examples("airs doctor", `airs doctor --output json | jq '.[] | select(.status != "pass")'`)
|
|
3629
3771
|
).action(async (opts) => {
|
|
3630
|
-
const fmt =
|
|
3772
|
+
const fmt = await resolveOutput(doctor, opts);
|
|
3631
3773
|
const checks = await runDoctor();
|
|
3632
|
-
if (fmt === "
|
|
3633
|
-
console.log(JSON.stringify(checks, null, 2));
|
|
3634
|
-
} else if (fmt === "yaml") {
|
|
3635
|
-
console.log(toYaml(checks));
|
|
3636
|
-
} else {
|
|
3774
|
+
if (fmt === "pretty") {
|
|
3637
3775
|
renderPretty(checks);
|
|
3776
|
+
} else {
|
|
3777
|
+
console.log(
|
|
3778
|
+
formatOutput(
|
|
3779
|
+
checks.map((check) => ({ ...check })),
|
|
3780
|
+
[
|
|
3781
|
+
{ key: "name", label: "Name" },
|
|
3782
|
+
{ key: "status", label: "Status" },
|
|
3783
|
+
{ key: "detail", label: "Detail" },
|
|
3784
|
+
{ key: "hint", label: "Hint" }
|
|
3785
|
+
],
|
|
3786
|
+
fmt
|
|
3787
|
+
)
|
|
3788
|
+
);
|
|
3638
3789
|
}
|
|
3639
3790
|
process.exit(hasFailure(checks) ? 1 : 0);
|
|
3640
3791
|
});
|
|
@@ -3674,15 +3825,17 @@ function registerModelSecurityCommand(program) {
|
|
|
3674
3825
|
const fmt = opts.output;
|
|
3675
3826
|
if (fmt === "pretty") renderModelSecurityHeader();
|
|
3676
3827
|
const service = await createService2();
|
|
3677
|
-
const
|
|
3828
|
+
const listOptions = {
|
|
3678
3829
|
sourceTypes: opts.sourceTypes ? opts.sourceTypes.split(",").map((s) => s.trim()) : void 0,
|
|
3679
3830
|
searchQuery: opts.search,
|
|
3680
3831
|
sortField: opts.sortField,
|
|
3681
3832
|
sortDir: opts.sortDir,
|
|
3682
3833
|
enabledRules: opts.enabledRules ? opts.enabledRules.split(",").map((s) => s.trim()) : void 0,
|
|
3683
|
-
limit: Number.parseInt(opts.limit, 10)
|
|
3684
|
-
|
|
3685
|
-
|
|
3834
|
+
limit: Number.parseInt(opts.limit, 10),
|
|
3835
|
+
skip: Number(opts.offset ?? 0)
|
|
3836
|
+
};
|
|
3837
|
+
const rows = opts.all ? await service.listAllGroups({ ...listOptions, max: Number(opts.max) }) : (await service.listGroups(listOptions)).groups;
|
|
3838
|
+
renderGroupList(rows, fmt);
|
|
3686
3839
|
} catch (err) {
|
|
3687
3840
|
fail(err);
|
|
3688
3841
|
}
|
|
@@ -3877,24 +4030,26 @@ function registerModelSecurityCommand(program) {
|
|
|
3877
4030
|
const ruleInstances = ms.command("rule-instances").description("Manage rule instances in groups");
|
|
3878
4031
|
ruleInstances.command("list <groupUuid>").description("List rule instances in a security group").option("--security-rule-uuid <uuid>", "Filter by security rule UUID").option("--state <state>", "Filter by state (DISABLED, ALLOWING, BLOCKING)").option("--limit <n>", "Max results", "20").action(async (groupUuid, opts) => {
|
|
3879
4032
|
try {
|
|
3880
|
-
|
|
4033
|
+
const fmt = opts.output;
|
|
4034
|
+
if (fmt === "pretty") renderModelSecurityHeader();
|
|
3881
4035
|
const service = await createService2();
|
|
3882
4036
|
const result = await service.listRuleInstances(groupUuid, {
|
|
3883
4037
|
securityRuleUuid: opts.securityRuleUuid,
|
|
3884
4038
|
state: opts.state,
|
|
3885
4039
|
limit: Number.parseInt(opts.limit, 10)
|
|
3886
4040
|
});
|
|
3887
|
-
renderRuleInstanceList(result.ruleInstances);
|
|
4041
|
+
renderRuleInstanceList(result.ruleInstances, fmt);
|
|
3888
4042
|
} catch (err) {
|
|
3889
4043
|
fail(err);
|
|
3890
4044
|
}
|
|
3891
4045
|
});
|
|
3892
|
-
ruleInstances.command("get <groupUuid> <instanceUuid>").description("Get rule instance details").action(async (groupUuid, instanceUuid) => {
|
|
4046
|
+
ruleInstances.command("get <groupUuid> <instanceUuid>").description("Get rule instance details").action(async (groupUuid, instanceUuid, opts) => {
|
|
3893
4047
|
try {
|
|
3894
|
-
|
|
4048
|
+
const fmt = opts.output;
|
|
4049
|
+
if (fmt === "pretty") renderModelSecurityHeader();
|
|
3895
4050
|
const service = await createService2();
|
|
3896
4051
|
const instance = await service.getRuleInstance(groupUuid, instanceUuid);
|
|
3897
|
-
renderRuleInstanceDetail(instance);
|
|
4052
|
+
renderRuleInstanceDetail(instance, fmt);
|
|
3898
4053
|
} catch (err) {
|
|
3899
4054
|
fail(err);
|
|
3900
4055
|
}
|
|
@@ -3920,22 +4075,25 @@ function registerModelSecurityCommand(program) {
|
|
|
3920
4075
|
const fmt = opts.output;
|
|
3921
4076
|
if (fmt === "pretty") renderModelSecurityHeader();
|
|
3922
4077
|
const service = await createService2();
|
|
3923
|
-
const
|
|
4078
|
+
const listOptions = {
|
|
3924
4079
|
sourceType: opts.sourceType,
|
|
3925
4080
|
searchQuery: opts.search,
|
|
3926
|
-
limit: Number.parseInt(opts.limit, 10)
|
|
3927
|
-
|
|
3928
|
-
|
|
4081
|
+
limit: Number.parseInt(opts.limit, 10),
|
|
4082
|
+
skip: Number(opts.offset ?? 0)
|
|
4083
|
+
};
|
|
4084
|
+
const rows = opts.all ? await service.listAllRules({ ...listOptions, max: Number(opts.max) }) : (await service.listRules(listOptions)).rules;
|
|
4085
|
+
renderRuleList(rows, fmt);
|
|
3929
4086
|
} catch (err) {
|
|
3930
4087
|
fail(err);
|
|
3931
4088
|
}
|
|
3932
4089
|
});
|
|
3933
|
-
rules.command("get <uuid>").description("Get security rule details").action(async (uuid) => {
|
|
4090
|
+
rules.command("get <uuid>").description("Get security rule details").action(async (uuid, opts) => {
|
|
3934
4091
|
try {
|
|
3935
|
-
|
|
4092
|
+
const fmt = opts.output;
|
|
4093
|
+
if (fmt === "pretty") renderModelSecurityHeader();
|
|
3936
4094
|
const service = await createService2();
|
|
3937
4095
|
const rule = await service.getRule(uuid);
|
|
3938
|
-
renderRuleDetail(rule);
|
|
4096
|
+
renderRuleDetail(rule, fmt);
|
|
3939
4097
|
} catch (err) {
|
|
3940
4098
|
fail(err);
|
|
3941
4099
|
}
|
|
@@ -3953,24 +4111,27 @@ function registerModelSecurityCommand(program) {
|
|
|
3953
4111
|
const fmt = opts.output;
|
|
3954
4112
|
if (fmt === "pretty") renderModelSecurityHeader();
|
|
3955
4113
|
const service = await createService2();
|
|
3956
|
-
const
|
|
4114
|
+
const listOptions = {
|
|
3957
4115
|
evalOutcome: opts.evalOutcome,
|
|
3958
4116
|
sourceType: opts.sourceType,
|
|
3959
4117
|
scanOrigin: opts.scanOrigin,
|
|
3960
4118
|
search: opts.search,
|
|
3961
|
-
limit: Number.parseInt(opts.limit, 10)
|
|
3962
|
-
|
|
3963
|
-
|
|
4119
|
+
limit: Number.parseInt(opts.limit, 10),
|
|
4120
|
+
skip: Number(opts.offset ?? 0)
|
|
4121
|
+
};
|
|
4122
|
+
const rows = opts.all ? await service.listAllScans({ ...listOptions, max: Number(opts.max) }) : (await service.listScans(listOptions)).scans;
|
|
4123
|
+
renderMsScanList(rows, fmt);
|
|
3964
4124
|
} catch (err) {
|
|
3965
4125
|
fail(err);
|
|
3966
4126
|
}
|
|
3967
4127
|
});
|
|
3968
|
-
scans.command("get <uuid>").description("Get scan details").action(async (uuid) => {
|
|
4128
|
+
scans.command("get <uuid>").description("Get scan details").action(async (uuid, opts) => {
|
|
3969
4129
|
try {
|
|
3970
|
-
|
|
4130
|
+
const fmt = opts.output;
|
|
4131
|
+
if (fmt === "pretty") renderModelSecurityHeader();
|
|
3971
4132
|
const service = await createService2();
|
|
3972
4133
|
const scan = await service.getScan(uuid);
|
|
3973
|
-
renderMsScanDetail(scan);
|
|
4134
|
+
renderMsScanDetail(scan, fmt);
|
|
3974
4135
|
} catch (err) {
|
|
3975
4136
|
fail(err);
|
|
3976
4137
|
}
|
|
@@ -4051,15 +4212,16 @@ function registerModelSecurityCommand(program) {
|
|
|
4051
4212
|
const fmt = opts.output;
|
|
4052
4213
|
if (fmt === "pretty") renderModelSecurityHeader();
|
|
4053
4214
|
const service = await createService2();
|
|
4054
|
-
const
|
|
4215
|
+
const listOptions = {
|
|
4055
4216
|
search: opts.search,
|
|
4056
4217
|
searchQuery: opts.searchQuery,
|
|
4057
4218
|
sortField: opts.sortField,
|
|
4058
4219
|
sortOrder: opts.sortOrder,
|
|
4059
4220
|
limit: opts.limit ? Number.parseInt(opts.limit, 10) : void 0,
|
|
4060
4221
|
skip: opts.offset ? Number.parseInt(opts.offset, 10) : void 0
|
|
4061
|
-
}
|
|
4062
|
-
|
|
4222
|
+
};
|
|
4223
|
+
const rows = opts.all ? await service.listAllModels({ ...listOptions, max: Number(opts.max) }) : (await service.listModels(listOptions)).models;
|
|
4224
|
+
renderModelList(rows, fmt);
|
|
4063
4225
|
} catch (err) {
|
|
4064
4226
|
fail(err);
|
|
4065
4227
|
}
|
|
@@ -4352,8 +4514,12 @@ function parseAttackGoals(input) {
|
|
|
4352
4514
|
return parsed;
|
|
4353
4515
|
}
|
|
4354
4516
|
function sliceClientSide(items, opts) {
|
|
4355
|
-
|
|
4356
|
-
|
|
4517
|
+
if (opts.all) {
|
|
4518
|
+
const max = opts.max === void 0 ? 1e4 : Number(opts.max);
|
|
4519
|
+
return max === 0 ? items : items.slice(0, max);
|
|
4520
|
+
}
|
|
4521
|
+
const offset = opts.offset !== void 0 ? Number.parseInt(String(opts.offset), 10) : 0;
|
|
4522
|
+
const limit = opts.limit !== void 0 ? Number.parseInt(String(opts.limit), 10) : void 0;
|
|
4357
4523
|
return items.slice(offset, limit === void 0 ? void 0 : offset + limit);
|
|
4358
4524
|
}
|
|
4359
4525
|
function parsePositiveInt(input, flag) {
|
|
@@ -4634,12 +4800,14 @@ function registerRedteamCommand(program) {
|
|
|
4634
4800
|
const fmt = opts.output;
|
|
4635
4801
|
if (fmt === "pretty") renderRedteamHeader();
|
|
4636
4802
|
const service = await createService3();
|
|
4637
|
-
const
|
|
4803
|
+
const listOptions = {
|
|
4638
4804
|
status: opts.status,
|
|
4639
4805
|
jobType: opts.type,
|
|
4640
4806
|
targetId: opts.target,
|
|
4641
|
-
limit: Number.parseInt(opts.limit, 10)
|
|
4642
|
-
|
|
4807
|
+
limit: Number.parseInt(opts.limit, 10),
|
|
4808
|
+
offset: Number(opts.offset ?? 0)
|
|
4809
|
+
};
|
|
4810
|
+
const scans = opts.all ? await service.listAllScans({ ...listOptions, max: Number(opts.max) }) : await service.listScans(listOptions);
|
|
4643
4811
|
renderScanList(scans, fmt);
|
|
4644
4812
|
} catch (err) {
|
|
4645
4813
|
fail(err);
|
|
@@ -5142,12 +5310,18 @@ function registerRedteamCommand(program) {
|
|
|
5142
5310
|
fail(err);
|
|
5143
5311
|
}
|
|
5144
5312
|
});
|
|
5145
|
-
const targetsBackup = targets.command("backup").description("Backup red team targets to local JSON/YAML files").option("--output-dir <path>", "Output directory").option("--
|
|
5313
|
+
const targetsBackup = targets.command("backup").description("Backup red team targets to local JSON/YAML files").option("--output-dir <path>", "Output directory").option("--file-format <format>", "Backup file format: json or yaml", "json").option("--name <targetName>", "Backup a single target by name");
|
|
5314
|
+
registerDeprecatedAlias(targetsBackup, {
|
|
5315
|
+
oldFlag: "--output <format>",
|
|
5316
|
+
oldKey: "output",
|
|
5317
|
+
canonicalFlag: "--file-format",
|
|
5318
|
+
canonicalKey: "fileFormat"
|
|
5319
|
+
});
|
|
5146
5320
|
registerDeprecatedAlias(targetsBackup, {
|
|
5147
5321
|
oldFlag: "--format <format>",
|
|
5148
5322
|
oldKey: "format",
|
|
5149
|
-
canonicalFlag: "--
|
|
5150
|
-
canonicalKey: "
|
|
5323
|
+
canonicalFlag: "--file-format",
|
|
5324
|
+
canonicalKey: "fileFormat"
|
|
5151
5325
|
});
|
|
5152
5326
|
targetsBackup.action(async (opts) => {
|
|
5153
5327
|
resolveDeprecatedAliases(targetsBackup, opts);
|
|
@@ -5156,7 +5330,7 @@ function registerRedteamCommand(program) {
|
|
|
5156
5330
|
const outputDir = resolveOutputDir(opts.outputDir, "targets");
|
|
5157
5331
|
const results = await backupTargets({
|
|
5158
5332
|
outputDir,
|
|
5159
|
-
format: opts.
|
|
5333
|
+
format: opts.fileFormat ?? "json",
|
|
5160
5334
|
name: opts.name
|
|
5161
5335
|
});
|
|
5162
5336
|
renderBackupSummary(results, outputDir);
|
|
@@ -5221,11 +5395,13 @@ function registerRedteamCommand(program) {
|
|
|
5221
5395
|
const fmt = opts.output;
|
|
5222
5396
|
if (fmt === "pretty") renderRedteamHeader();
|
|
5223
5397
|
const service = await createService3();
|
|
5224
|
-
const
|
|
5398
|
+
const listOptions = {
|
|
5225
5399
|
limit: opts.limit ? parsePositiveInt(opts.limit, "--limit") : void 0,
|
|
5226
5400
|
offset: opts.offset ? Number.parseInt(opts.offset, 10) : void 0,
|
|
5227
5401
|
search: opts.search
|
|
5228
|
-
}
|
|
5402
|
+
};
|
|
5403
|
+
const result = opts.all ? { adapters: await service.listAllAdapters({ ...listOptions, max: Number(opts.max) }) } : await service.listAdapters(listOptions);
|
|
5404
|
+
const { adapters, totalItems } = result;
|
|
5229
5405
|
renderAdapterList(adapters, fmt, totalItems);
|
|
5230
5406
|
} catch (err) {
|
|
5231
5407
|
fail(err);
|
|
@@ -5367,12 +5543,13 @@ function registerRedteamCommand(program) {
|
|
|
5367
5543
|
const fmt = opts.output;
|
|
5368
5544
|
if (fmt === "pretty") renderRedteamHeader();
|
|
5369
5545
|
const service = await createService3();
|
|
5370
|
-
const
|
|
5546
|
+
const listOptions = {
|
|
5371
5547
|
limit: opts.limit ? parsePositiveInt(opts.limit, "--limit") : void 0,
|
|
5372
5548
|
offset: opts.offset ? Number.parseInt(opts.offset, 10) : void 0,
|
|
5373
5549
|
search: opts.search,
|
|
5374
5550
|
status: opts.status
|
|
5375
|
-
}
|
|
5551
|
+
};
|
|
5552
|
+
const list = opts.all ? await service.listAllChannels({ ...listOptions, max: Number(opts.max) }) : (await service.listChannels(listOptions)).channels;
|
|
5376
5553
|
renderChannelList(list, fmt);
|
|
5377
5554
|
} catch (err) {
|
|
5378
5555
|
fail(err);
|
|
@@ -5914,6 +6091,31 @@ async function loadBulkScanState(filePath) {
|
|
|
5914
6091
|
|
|
5915
6092
|
// src/cli/pagination.ts
|
|
5916
6093
|
var DEFAULT_PAGE_SIZE = 50;
|
|
6094
|
+
var DEFAULT_OFFSET_LIMIT = 100;
|
|
6095
|
+
var DEFAULT_MAX_ITEMS = 1e4;
|
|
6096
|
+
function registerListFlags(command, options) {
|
|
6097
|
+
const defaultLimit = options.dialect === "offset" ? DEFAULT_OFFSET_LIMIT : DEFAULT_PAGE_SIZE;
|
|
6098
|
+
return command.option("--limit <n>", `Items per page (default: ${defaultLimit})`, Number, defaultLimit).option("--offset <n>", "Item offset (default: 0)", Number, 0).option("--all", "Walk all pages").option("--max <n>", "Maximum items with --all; 0 removes the cap", Number, DEFAULT_MAX_ITEMS);
|
|
6099
|
+
}
|
|
6100
|
+
function integerFlag(name, value, minimum) {
|
|
6101
|
+
const parsed = Number(value);
|
|
6102
|
+
if (!Number.isSafeInteger(parsed) || parsed < minimum) {
|
|
6103
|
+
const qualifier = minimum === 1 ? "a positive integer" : "a non-negative integer";
|
|
6104
|
+
throw new CliUsageError(`${name} must be ${qualifier}`);
|
|
6105
|
+
}
|
|
6106
|
+
return parsed;
|
|
6107
|
+
}
|
|
6108
|
+
function resolveListParams(command, opts, options) {
|
|
6109
|
+
const defaultLimit = options.dialect === "offset" ? DEFAULT_OFFSET_LIMIT : DEFAULT_PAGE_SIZE;
|
|
6110
|
+
const limit = integerFlag("--limit", opts.limit ?? defaultLimit, 1);
|
|
6111
|
+
const offset = integerFlag("--offset", opts.offset ?? 0, 0);
|
|
6112
|
+
const max = integerFlag("--max", opts.max ?? DEFAULT_MAX_ITEMS, 0);
|
|
6113
|
+
const all = Boolean(opts.all);
|
|
6114
|
+
if (all && command.getOptionValueSource?.("offset") === "cli") {
|
|
6115
|
+
throw new CliUsageError("--all cannot be combined with --offset");
|
|
6116
|
+
}
|
|
6117
|
+
return { limit, offset, all, max };
|
|
6118
|
+
}
|
|
5917
6119
|
function registerPageAliases(cmd, opts) {
|
|
5918
6120
|
registerDeprecatedAlias(cmd, {
|
|
5919
6121
|
oldFlag: `${opts.sizeFlag} <n>`,
|
|
@@ -6035,6 +6237,71 @@ function parseQuotedField(content, start, len) {
|
|
|
6035
6237
|
return { value, nextIndex: i };
|
|
6036
6238
|
}
|
|
6037
6239
|
|
|
6240
|
+
// src/cli/renderer/views/runtime.ts
|
|
6241
|
+
var profilesView = {
|
|
6242
|
+
name: "profiles",
|
|
6243
|
+
columns: [
|
|
6244
|
+
{ key: "profileId", label: "ID" },
|
|
6245
|
+
{ key: "profileName", label: "Name" },
|
|
6246
|
+
{ key: "active", label: "Active" },
|
|
6247
|
+
{ key: "revision", label: "Revision" }
|
|
6248
|
+
],
|
|
6249
|
+
pretty: {
|
|
6250
|
+
list: (items) => renderProfileList(items, "pretty"),
|
|
6251
|
+
detail: renderProfileDetail
|
|
6252
|
+
}
|
|
6253
|
+
};
|
|
6254
|
+
var apiKeysView = {
|
|
6255
|
+
name: "API keys",
|
|
6256
|
+
columns: [
|
|
6257
|
+
{ key: "id", label: "ID" },
|
|
6258
|
+
{ key: "name", label: "Name" },
|
|
6259
|
+
{ key: "last8", label: "Last 8" },
|
|
6260
|
+
{ key: "expiresAt", label: "Expires" }
|
|
6261
|
+
],
|
|
6262
|
+
pretty: {
|
|
6263
|
+
list: (items) => renderApiKeyList(items, "pretty"),
|
|
6264
|
+
detail: renderApiKeyDetail
|
|
6265
|
+
}
|
|
6266
|
+
};
|
|
6267
|
+
var customerAppsView = {
|
|
6268
|
+
name: "customer apps",
|
|
6269
|
+
columns: [
|
|
6270
|
+
{ key: "id", label: "ID" },
|
|
6271
|
+
{ key: "name", label: "Name" },
|
|
6272
|
+
{ key: "description", label: "Description" }
|
|
6273
|
+
],
|
|
6274
|
+
pretty: {
|
|
6275
|
+
list: (items) => renderCustomerAppList(items, "pretty"),
|
|
6276
|
+
detail: renderCustomerAppDetail
|
|
6277
|
+
}
|
|
6278
|
+
};
|
|
6279
|
+
var topicsView = {
|
|
6280
|
+
name: "topics",
|
|
6281
|
+
columns: [
|
|
6282
|
+
{ key: "topic_id", label: "ID" },
|
|
6283
|
+
{ key: "topic_name", label: "Name" },
|
|
6284
|
+
{ key: "revision", label: "Revision" },
|
|
6285
|
+
{ key: "description", label: "Description" }
|
|
6286
|
+
],
|
|
6287
|
+
structured: (topic) => ({
|
|
6288
|
+
topicId: topic.topic_id,
|
|
6289
|
+
topicName: topic.topic_name,
|
|
6290
|
+
revision: topic.revision,
|
|
6291
|
+
active: topic.active,
|
|
6292
|
+
description: topic.description,
|
|
6293
|
+
examples: topic.examples,
|
|
6294
|
+
createdBy: topic.created_by,
|
|
6295
|
+
updatedBy: topic.updated_by,
|
|
6296
|
+
lastModifiedTs: topic.last_modified_ts,
|
|
6297
|
+
createdTs: topic.created_ts
|
|
6298
|
+
}),
|
|
6299
|
+
pretty: {
|
|
6300
|
+
list: (items) => renderTopicList(items, "pretty"),
|
|
6301
|
+
detail: renderTopicDetail
|
|
6302
|
+
}
|
|
6303
|
+
};
|
|
6304
|
+
|
|
6038
6305
|
// src/cli/commands/dlp/dictionaries.ts
|
|
6039
6306
|
import { readFile as readFile6 } from "fs/promises";
|
|
6040
6307
|
import { basename as basename2 } from "path";
|
|
@@ -6048,6 +6315,9 @@ var SdkDictionariesService = class {
|
|
|
6048
6315
|
async list(params) {
|
|
6049
6316
|
return this.client.list(params);
|
|
6050
6317
|
}
|
|
6318
|
+
async listAll(params) {
|
|
6319
|
+
return this.client.listAll(params);
|
|
6320
|
+
}
|
|
6051
6321
|
async create(params) {
|
|
6052
6322
|
return this.client.create(params);
|
|
6053
6323
|
}
|
|
@@ -6155,20 +6425,22 @@ function register(dlp) {
|
|
|
6155
6425
|
"--offset <n>",
|
|
6156
6426
|
"Starting offset \u2014 rounds down to a page boundary",
|
|
6157
6427
|
(v) => Number.parseInt(v, 10)
|
|
6158
|
-
).option("--sort <field,dir>", "(repeatable)", (v, p = []) => [...p, v]).option("--keywords", "Include keyword list in response").option("--include-keywords", "Alias for --keywords").option("--output <fmt>", "Output format
|
|
6428
|
+
).option("--sort <field,dir>", "(repeatable)", (v, p = []) => [...p, v]).option("--keywords", "Include keyword list in response").option("--include-keywords", "Alias for --keywords").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml");
|
|
6159
6429
|
registerPageAliases(listCmd, { sizeFlag: "--size", sizeKey: "size" });
|
|
6160
6430
|
listCmd.action(async (opts) => {
|
|
6161
6431
|
try {
|
|
6162
6432
|
const { page, size } = resolvePageParams(listCmd, opts);
|
|
6163
6433
|
const includeKeywords = opts.keywords || opts.includeKeywords;
|
|
6434
|
+
const svc = new SdkDictionariesService();
|
|
6435
|
+
const params = {
|
|
6436
|
+
size,
|
|
6437
|
+
sort: opts.sort,
|
|
6438
|
+
keywords: includeKeywords ? true : void 0
|
|
6439
|
+
};
|
|
6440
|
+
const all = opts.all ? await svc.listAll({ ...params, max: Number(opts.max) }) : void 0;
|
|
6164
6441
|
dlpDictionaries.renderList(
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
size,
|
|
6168
|
-
sort: opts.sort,
|
|
6169
|
-
keywords: includeKeywords ? true : void 0
|
|
6170
|
-
}),
|
|
6171
|
-
opts.output
|
|
6442
|
+
all ? { content: all, totalElements: all.length } : await svc.list({ ...params, page }),
|
|
6443
|
+
await resolveOutput(listCmd, opts)
|
|
6172
6444
|
);
|
|
6173
6445
|
} catch (err) {
|
|
6174
6446
|
fail(err);
|
|
@@ -6189,12 +6461,12 @@ function register(dlp) {
|
|
|
6189
6461
|
usageError(err instanceof Error ? err.message : String(err));
|
|
6190
6462
|
}
|
|
6191
6463
|
});
|
|
6192
|
-
group.command("get <id>").option("--keywords", "").option("--include-keywords", "Alias for --keywords").option("--output <fmt>", "Output format
|
|
6464
|
+
const getCmd = group.command("get <id>").option("--keywords", "").option("--include-keywords", "Alias for --keywords").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (id, opts) => {
|
|
6193
6465
|
try {
|
|
6194
6466
|
const includeKeywords = opts.keywords || opts.includeKeywords;
|
|
6195
6467
|
dlpDictionaries.renderGet(
|
|
6196
6468
|
await new SdkDictionariesService().get(id, { includeKeywords }),
|
|
6197
|
-
opts
|
|
6469
|
+
await resolveOutput(getCmd, opts)
|
|
6198
6470
|
);
|
|
6199
6471
|
} catch (err) {
|
|
6200
6472
|
fail(err);
|
|
@@ -6255,6 +6527,9 @@ var SdkDataFilteringProfilesService = class {
|
|
|
6255
6527
|
async list(params) {
|
|
6256
6528
|
return this.client.list(params);
|
|
6257
6529
|
}
|
|
6530
|
+
async listAll(params) {
|
|
6531
|
+
return this.client.listAll(params);
|
|
6532
|
+
}
|
|
6258
6533
|
async get(id) {
|
|
6259
6534
|
return this.client.get(id);
|
|
6260
6535
|
}
|
|
@@ -6388,7 +6663,7 @@ function listFlags(cmd) {
|
|
|
6388
6663
|
"--offset <n>",
|
|
6389
6664
|
"Starting offset \u2014 rounds down to a page boundary",
|
|
6390
6665
|
(v) => Number.parseInt(v, 10)
|
|
6391
|
-
).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format
|
|
6666
|
+
).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml");
|
|
6392
6667
|
registerPageAliases(cmd, { sizeFlag: "--size", sizeKey: "size" });
|
|
6393
6668
|
return cmd;
|
|
6394
6669
|
}
|
|
@@ -6409,16 +6684,17 @@ function register2(dlp) {
|
|
|
6409
6684
|
try {
|
|
6410
6685
|
const { page, size } = resolvePageParams(listCmd, opts);
|
|
6411
6686
|
const svc = new SdkDataFilteringProfilesService();
|
|
6412
|
-
const
|
|
6413
|
-
|
|
6687
|
+
const all = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) : void 0;
|
|
6688
|
+
const r = all ? { content: all, totalElements: all.length } : await svc.list({ page, size, sort: opts.sort });
|
|
6689
|
+
dlpFilteringProfiles.renderList(r, await resolveOutput(listCmd, opts));
|
|
6414
6690
|
} catch (err) {
|
|
6415
6691
|
fail(err);
|
|
6416
6692
|
}
|
|
6417
6693
|
});
|
|
6418
|
-
group.command("get <id>").description("Get a filtering profile by id").option("--output <fmt>", "Output format
|
|
6694
|
+
const getCmd = group.command("get <id>").description("Get a filtering profile by id").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (id, opts) => {
|
|
6419
6695
|
try {
|
|
6420
6696
|
const svc = new SdkDataFilteringProfilesService();
|
|
6421
|
-
dlpFilteringProfiles.renderGet(await svc.get(id), opts
|
|
6697
|
+
dlpFilteringProfiles.renderGet(await svc.get(id), await resolveOutput(getCmd, opts));
|
|
6422
6698
|
} catch (err) {
|
|
6423
6699
|
fail(err);
|
|
6424
6700
|
}
|
|
@@ -6514,6 +6790,9 @@ var SdkDataPatternsService = class {
|
|
|
6514
6790
|
async list(params) {
|
|
6515
6791
|
return this.client.list(params);
|
|
6516
6792
|
}
|
|
6793
|
+
async listAll(params) {
|
|
6794
|
+
return this.client.listAll(params);
|
|
6795
|
+
}
|
|
6517
6796
|
async create(body) {
|
|
6518
6797
|
return this.client.create(body);
|
|
6519
6798
|
}
|
|
@@ -6537,7 +6816,7 @@ function listFlags2(cmd) {
|
|
|
6537
6816
|
"--offset <n>",
|
|
6538
6817
|
"Starting offset \u2014 rounds down to a page boundary",
|
|
6539
6818
|
(v) => Number.parseInt(v, 10)
|
|
6540
|
-
).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format
|
|
6819
|
+
).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml");
|
|
6541
6820
|
registerPageAliases(cmd, { sizeFlag: "--size", sizeKey: "size" });
|
|
6542
6821
|
return cmd;
|
|
6543
6822
|
}
|
|
@@ -6559,9 +6838,10 @@ function register4(dlp) {
|
|
|
6559
6838
|
try {
|
|
6560
6839
|
const { page, size } = resolvePageParams(listCmd, opts);
|
|
6561
6840
|
const svc = new SdkDataPatternsService();
|
|
6841
|
+
const result = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) : void 0;
|
|
6562
6842
|
dlpPatterns.renderList(
|
|
6563
|
-
await svc.list({ page, size, sort: opts.sort }),
|
|
6564
|
-
opts
|
|
6843
|
+
result ? { content: result, totalElements: result.length } : await svc.list({ page, size, sort: opts.sort }),
|
|
6844
|
+
await resolveOutput(listCmd, opts)
|
|
6565
6845
|
);
|
|
6566
6846
|
} catch (err) {
|
|
6567
6847
|
fail(err);
|
|
@@ -6579,11 +6859,11 @@ function register4(dlp) {
|
|
|
6579
6859
|
usageError(err instanceof Error ? err.message : String(err));
|
|
6580
6860
|
}
|
|
6581
6861
|
});
|
|
6582
|
-
group.command("get <id>").description("Get a data pattern by id").option("--output <fmt>", "Output format
|
|
6862
|
+
const getCmd = group.command("get <id>").description("Get a data pattern by id").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (id, opts) => {
|
|
6583
6863
|
try {
|
|
6584
6864
|
dlpPatterns.renderGet(
|
|
6585
6865
|
await new SdkDataPatternsService().get(id),
|
|
6586
|
-
opts
|
|
6866
|
+
await resolveOutput(getCmd, opts)
|
|
6587
6867
|
);
|
|
6588
6868
|
} catch (err) {
|
|
6589
6869
|
fail(err);
|
|
@@ -6639,6 +6919,9 @@ var SdkDataProfilesService = class {
|
|
|
6639
6919
|
async list(params) {
|
|
6640
6920
|
return this.client.list(params);
|
|
6641
6921
|
}
|
|
6922
|
+
async listAll(params) {
|
|
6923
|
+
return this.client.listAll(params);
|
|
6924
|
+
}
|
|
6642
6925
|
async create(body) {
|
|
6643
6926
|
return this.client.create(body);
|
|
6644
6927
|
}
|
|
@@ -6659,7 +6942,7 @@ function listFlags3(cmd) {
|
|
|
6659
6942
|
"--offset <n>",
|
|
6660
6943
|
"Starting offset \u2014 rounds down to a page boundary",
|
|
6661
6944
|
(v) => Number.parseInt(v, 10)
|
|
6662
|
-
).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format
|
|
6945
|
+
).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml");
|
|
6663
6946
|
registerPageAliases(cmd, { sizeFlag: "--size", sizeKey: "size" });
|
|
6664
6947
|
return cmd;
|
|
6665
6948
|
}
|
|
@@ -6693,9 +6976,10 @@ function register5(dlp) {
|
|
|
6693
6976
|
try {
|
|
6694
6977
|
const { page, size } = resolvePageParams(listCmd, opts);
|
|
6695
6978
|
const svc = new SdkDataProfilesService();
|
|
6979
|
+
const result = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) : void 0;
|
|
6696
6980
|
dlpProfiles.renderList(
|
|
6697
|
-
await svc.list({ page, size, sort: opts.sort }),
|
|
6698
|
-
opts
|
|
6981
|
+
result ? { content: result, totalElements: result.length } : await svc.list({ page, size, sort: opts.sort }),
|
|
6982
|
+
await resolveOutput(listCmd, opts)
|
|
6699
6983
|
);
|
|
6700
6984
|
} catch (err) {
|
|
6701
6985
|
fail(err);
|
|
@@ -6713,11 +6997,11 @@ function register5(dlp) {
|
|
|
6713
6997
|
usageError(err instanceof Error ? err.message : String(err));
|
|
6714
6998
|
}
|
|
6715
6999
|
});
|
|
6716
|
-
group.command("get <id>").description("Get a data profile by id").option("--output <fmt>", "Output format
|
|
7000
|
+
const getCmd = group.command("get <id>").description("Get a data profile by id").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (id, opts) => {
|
|
6717
7001
|
try {
|
|
6718
7002
|
dlpProfiles.renderGet(
|
|
6719
7003
|
await new SdkDataProfilesService().get(id),
|
|
6720
|
-
opts
|
|
7004
|
+
await resolveOutput(getCmd, opts)
|
|
6721
7005
|
);
|
|
6722
7006
|
} catch (err) {
|
|
6723
7007
|
fail(err);
|
|
@@ -7365,15 +7649,26 @@ async function createMgmtService() {
|
|
|
7365
7649
|
function registerRuntimeCommand(program) {
|
|
7366
7650
|
const runtime = program.command("runtime").description("Runtime prompt scanning against AIRS profiles");
|
|
7367
7651
|
const apiKeys = runtime.command("api-keys").description("Manage AIRS API keys");
|
|
7368
|
-
apiKeys.command("list").description("List API keys").option("--
|
|
7652
|
+
const apiKeysList = registerListFlags(apiKeys.command("list"), { dialect: "offset" }).description("List API keys").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (opts) => {
|
|
7369
7653
|
try {
|
|
7370
|
-
const fmt = opts
|
|
7654
|
+
const fmt = await resolveOutput(apiKeysList, opts);
|
|
7655
|
+
const page = resolveListParams(apiKeysList, opts, { dialect: "offset" });
|
|
7371
7656
|
if (fmt === "pretty") renderRuntimeConfigHeader();
|
|
7372
7657
|
const service = await createMgmtService();
|
|
7658
|
+
if (page.all) {
|
|
7659
|
+
const items = await service.listAllApiKeys({ limit: page.limit, max: page.max });
|
|
7660
|
+
emitList(apiKeysView, items, fmt, {
|
|
7661
|
+
page: { returned: items.length, total: items.length, all: true }
|
|
7662
|
+
});
|
|
7663
|
+
return;
|
|
7664
|
+
}
|
|
7373
7665
|
const result = await service.listApiKeys({
|
|
7374
|
-
limit:
|
|
7666
|
+
limit: page.limit,
|
|
7667
|
+
offset: page.offset
|
|
7668
|
+
});
|
|
7669
|
+
emitList(apiKeysView, result.apiKeys, fmt, {
|
|
7670
|
+
page: { returned: result.apiKeys.length, next: result.nextOffset }
|
|
7375
7671
|
});
|
|
7376
|
-
renderApiKeyList(result.apiKeys, fmt);
|
|
7377
7672
|
} catch (err) {
|
|
7378
7673
|
fail(err);
|
|
7379
7674
|
}
|
|
@@ -7560,25 +7855,37 @@ function registerRuntimeCommand(program) {
|
|
|
7560
7855
|
}
|
|
7561
7856
|
});
|
|
7562
7857
|
const customerApps = runtime.command("customer-apps").description("Manage AIRS customer apps");
|
|
7563
|
-
customerApps.command("list").description("List customer apps").option("--
|
|
7858
|
+
const customerAppsList = registerListFlags(customerApps.command("list"), { dialect: "offset" }).description("List customer apps").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (opts) => {
|
|
7564
7859
|
try {
|
|
7565
|
-
const fmt = opts
|
|
7860
|
+
const fmt = await resolveOutput(customerAppsList, opts);
|
|
7861
|
+
const page = resolveListParams(customerAppsList, opts, { dialect: "offset" });
|
|
7566
7862
|
if (fmt === "pretty") renderRuntimeConfigHeader();
|
|
7567
7863
|
const service = await createMgmtService();
|
|
7864
|
+
if (page.all) {
|
|
7865
|
+
const items = await service.listAllCustomerApps({ limit: page.limit, max: page.max });
|
|
7866
|
+
emitList(customerAppsView, items, fmt, {
|
|
7867
|
+
page: { returned: items.length, total: items.length, all: true }
|
|
7868
|
+
});
|
|
7869
|
+
return;
|
|
7870
|
+
}
|
|
7568
7871
|
const result = await service.listCustomerApps({
|
|
7569
|
-
limit:
|
|
7872
|
+
limit: page.limit,
|
|
7873
|
+
offset: page.offset
|
|
7874
|
+
});
|
|
7875
|
+
emitList(customerAppsView, result.apps, fmt, {
|
|
7876
|
+
page: { returned: result.apps.length, next: result.nextOffset }
|
|
7570
7877
|
});
|
|
7571
|
-
renderCustomerAppList(result.apps, fmt);
|
|
7572
7878
|
} catch (err) {
|
|
7573
7879
|
fail(err);
|
|
7574
7880
|
}
|
|
7575
7881
|
});
|
|
7576
|
-
customerApps.command("get <appName>").description("Get customer app details").action(async (appName) => {
|
|
7882
|
+
const customerAppsGet = customerApps.command("get <appName>").description("Get customer app details").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (appName, opts) => {
|
|
7577
7883
|
try {
|
|
7578
|
-
|
|
7884
|
+
const fmt = await resolveOutput(customerAppsGet, opts);
|
|
7885
|
+
if (fmt === "pretty") renderRuntimeConfigHeader();
|
|
7579
7886
|
const service = await createMgmtService();
|
|
7580
7887
|
const app = await service.getCustomerApp(appName);
|
|
7581
|
-
|
|
7888
|
+
emitDetail(customerAppsView, app, fmt);
|
|
7582
7889
|
} catch (err) {
|
|
7583
7890
|
fail(err);
|
|
7584
7891
|
}
|
|
@@ -7660,7 +7967,7 @@ function registerRuntimeCommand(program) {
|
|
|
7660
7967
|
}
|
|
7661
7968
|
});
|
|
7662
7969
|
const profiles = runtime.command("profiles").description("Manage AIRS security profiles");
|
|
7663
|
-
profiles.command("list").description("List security profiles").option("--
|
|
7970
|
+
const profilesList = registerListFlags(profiles.command("list"), { dialect: "offset" }).description("List security profiles").option("--all-versions", "Include every profile revision").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").addHelpText(
|
|
7664
7971
|
"after",
|
|
7665
7972
|
examples(
|
|
7666
7973
|
"airs runtime profiles list",
|
|
@@ -7669,49 +7976,55 @@ function registerRuntimeCommand(program) {
|
|
|
7669
7976
|
)
|
|
7670
7977
|
).action(async (opts) => {
|
|
7671
7978
|
try {
|
|
7672
|
-
const fmt = opts
|
|
7673
|
-
|
|
7674
|
-
usageError(`Invalid output format "${fmt}". Valid: ${OUTPUT_FORMATS.join(", ")}`);
|
|
7675
|
-
}
|
|
7979
|
+
const fmt = await resolveOutput(profilesList, opts);
|
|
7980
|
+
const page = resolveListParams(profilesList, opts, { dialect: "offset" });
|
|
7676
7981
|
if (fmt === "pretty") renderRuntimeConfigHeader();
|
|
7677
7982
|
const service = await createMgmtService();
|
|
7983
|
+
if (page.all) {
|
|
7984
|
+
const items = await service.listAllProfiles({
|
|
7985
|
+
limit: page.limit,
|
|
7986
|
+
latest: !opts.allVersions,
|
|
7987
|
+
max: page.max
|
|
7988
|
+
});
|
|
7989
|
+
emitList(profilesView, items, fmt, {
|
|
7990
|
+
page: { returned: items.length, total: items.length, all: true }
|
|
7991
|
+
});
|
|
7992
|
+
return;
|
|
7993
|
+
}
|
|
7678
7994
|
const result = await service.listProfiles({
|
|
7679
|
-
limit:
|
|
7680
|
-
offset:
|
|
7995
|
+
limit: page.limit,
|
|
7996
|
+
offset: page.offset,
|
|
7997
|
+
latest: !opts.allVersions
|
|
7998
|
+
});
|
|
7999
|
+
emitList(profilesView, result.profiles, fmt, {
|
|
8000
|
+
page: {
|
|
8001
|
+
returned: result.profiles.length,
|
|
8002
|
+
next: result.nextOffset
|
|
8003
|
+
}
|
|
7681
8004
|
});
|
|
7682
|
-
renderProfileList(result.profiles, fmt);
|
|
7683
|
-
if (fmt === "pretty" && result.nextOffset != null) {
|
|
7684
|
-
ui.dim(`Next offset: ${result.nextOffset}`);
|
|
7685
|
-
}
|
|
7686
8005
|
} catch (err) {
|
|
7687
8006
|
fail(err);
|
|
7688
8007
|
}
|
|
7689
8008
|
});
|
|
7690
|
-
profiles.command("get <nameOrId>").description("Get a security profile by name or UUID").option("--output <format>", "Output format: pretty, json, yaml"
|
|
8009
|
+
const profilesGet = profiles.command("get <nameOrId>").description("Get a security profile by name or UUID").option("--revision <n>", "Select an exact revision", Number).option("--all-versions", "Return every matching revision").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (nameOrId, opts) => {
|
|
7691
8010
|
try {
|
|
7692
|
-
const fmt = opts
|
|
7693
|
-
if (fmt !== "pretty" && fmt !== "json" && fmt !== "yaml") {
|
|
7694
|
-
usageError(`Invalid output format "${fmt}". Valid: pretty, json, yaml`);
|
|
7695
|
-
}
|
|
8011
|
+
const fmt = await resolveOutput(profilesGet, opts);
|
|
7696
8012
|
if (fmt === "pretty") renderRuntimeConfigHeader();
|
|
7697
8013
|
const service = await createMgmtService();
|
|
7698
8014
|
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
|
|
7699
8015
|
nameOrId
|
|
7700
8016
|
);
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
const
|
|
7706
|
-
if (
|
|
7707
|
-
if (
|
|
7708
|
-
|
|
7709
|
-
if (profile.updatedBy) lines.push(`updatedBy: ${profile.updatedBy}`);
|
|
7710
|
-
if (profile.lastModifiedTs) lines.push(`lastModifiedTs: ${profile.lastModifiedTs}`);
|
|
7711
|
-
if (profile.policy) lines.push(`policy: ${JSON.stringify(profile.policy, null, 2)}`);
|
|
7712
|
-
console.log(lines.join("\n"));
|
|
8017
|
+
if (opts.revision !== void 0 || opts.allVersions) {
|
|
8018
|
+
const profiles2 = (await service.listAllProfiles({ latest: false })).filter(
|
|
8019
|
+
(profile) => isUuid ? profile.profileId === nameOrId : profile.profileName === nameOrId
|
|
8020
|
+
);
|
|
8021
|
+
const selected = opts.revision === void 0 ? profiles2 : profiles2.filter((profile) => profile.revision === opts.revision);
|
|
8022
|
+
if (selected.length === 0) throw new Error(`Profile ${nameOrId} not found`);
|
|
8023
|
+
if (opts.allVersions) emitList(profilesView, selected, fmt);
|
|
8024
|
+
else emitDetail(profilesView, selected[0], fmt);
|
|
7713
8025
|
} else {
|
|
7714
|
-
|
|
8026
|
+
const profile = isUuid ? await service.getProfile(nameOrId) : await service.getProfileByName(nameOrId);
|
|
8027
|
+
emitDetail(profilesView, profile, fmt);
|
|
7715
8028
|
}
|
|
7716
8029
|
} catch (err) {
|
|
7717
8030
|
fail(err);
|
|
@@ -8036,52 +8349,47 @@ function registerRuntimeCommand(program) {
|
|
|
8036
8349
|
}
|
|
8037
8350
|
});
|
|
8038
8351
|
registerEvalCommand(topics);
|
|
8039
|
-
topics.command("get <nameOrId>").description("Get a custom topic by name or UUID").option("--output <format>", "Output format: pretty, json, yaml"
|
|
8352
|
+
const topicsGet = topics.command("get <nameOrId>").description("Get a custom topic by name or UUID").option("--revision <n>", "Select an exact revision", Number).option("--all-versions", "Return every matching revision").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (nameOrId, opts) => {
|
|
8040
8353
|
try {
|
|
8041
|
-
const fmt = opts
|
|
8042
|
-
if (fmt !== "pretty" && fmt !== "json" && fmt !== "yaml") {
|
|
8043
|
-
usageError(`Invalid output format "${fmt}". Valid: pretty, json, yaml`);
|
|
8044
|
-
}
|
|
8354
|
+
const fmt = await resolveOutput(topicsGet, opts);
|
|
8045
8355
|
if (fmt === "pretty") renderRuntimeConfigHeader();
|
|
8046
8356
|
const service = await createMgmtService();
|
|
8047
8357
|
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
|
|
8048
8358
|
nameOrId
|
|
8049
8359
|
);
|
|
8050
|
-
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
const
|
|
8055
|
-
if (
|
|
8056
|
-
if (
|
|
8057
|
-
|
|
8058
|
-
lines.push("examples:");
|
|
8059
|
-
for (const ex of topic.examples) lines.push(` - ${ex}`);
|
|
8060
|
-
}
|
|
8061
|
-
if (topic.created_by) lines.push(`created_by: ${topic.created_by}`);
|
|
8062
|
-
if (topic.updated_by) lines.push(`updated_by: ${topic.updated_by}`);
|
|
8063
|
-
if (topic.last_modified_ts) lines.push(`last_modified_ts: ${topic.last_modified_ts}`);
|
|
8064
|
-
console.log(lines.join("\n"));
|
|
8360
|
+
if (opts.revision !== void 0 || opts.allVersions) {
|
|
8361
|
+
const topics2 = (await service.listTopics()).filter(
|
|
8362
|
+
(topic) => isUuid ? topic.topic_id === nameOrId : topic.topic_name === nameOrId
|
|
8363
|
+
);
|
|
8364
|
+
const selected = opts.revision === void 0 ? topics2 : topics2.filter((topic) => topic.revision === opts.revision);
|
|
8365
|
+
if (selected.length === 0) throw new Error(`Topic ${nameOrId} not found`);
|
|
8366
|
+
if (opts.allVersions) emitList(topicsView, selected, fmt);
|
|
8367
|
+
else emitDetail(topicsView, selected[0], fmt);
|
|
8065
8368
|
} else {
|
|
8066
|
-
|
|
8369
|
+
const topic = isUuid ? await service.getTopic(nameOrId) : await service.getTopicByName(nameOrId);
|
|
8370
|
+
emitDetail(topicsView, topic, fmt);
|
|
8067
8371
|
}
|
|
8068
8372
|
} catch (err) {
|
|
8069
8373
|
fail(err);
|
|
8070
8374
|
}
|
|
8071
8375
|
});
|
|
8072
|
-
topics.command("list").description("List custom topics").option("--
|
|
8376
|
+
const topicsList = registerListFlags(topics.command("list"), { dialect: "offset" }).description("List custom topics").option("--all-versions", "Include every topic revision").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (opts) => {
|
|
8073
8377
|
try {
|
|
8074
|
-
const fmt = opts
|
|
8378
|
+
const fmt = await resolveOutput(topicsList, opts);
|
|
8379
|
+
const params = resolveListParams(topicsList, opts, { dialect: "offset" });
|
|
8075
8380
|
if (fmt === "pretty") renderRuntimeConfigHeader();
|
|
8076
8381
|
const service = await createMgmtService();
|
|
8077
|
-
const allTopics = await service.listTopics()
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
const page = allTopics.slice(offset, offset + limit);
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8382
|
+
const allTopics = opts.allVersions ? await service.listTopics() : await service.listLatestTopics(
|
|
8383
|
+
params.all ? { offset: 0, limit: params.max === 0 ? 1e4 : params.max } : { offset: params.offset, limit: params.limit }
|
|
8384
|
+
);
|
|
8385
|
+
const page = opts.allVersions && !params.all ? allTopics.slice(params.offset, params.offset + params.limit) : allTopics;
|
|
8386
|
+
emitList(topicsView, page, fmt, {
|
|
8387
|
+
page: params.all ? { returned: page.length, total: page.length, all: true } : {
|
|
8388
|
+
returned: page.length,
|
|
8389
|
+
total: opts.allVersions ? allTopics.length : void 0,
|
|
8390
|
+
next: opts.allVersions && params.offset + params.limit < allTopics.length ? params.offset + params.limit : void 0
|
|
8391
|
+
}
|
|
8392
|
+
});
|
|
8085
8393
|
} catch (err) {
|
|
8086
8394
|
fail(err);
|
|
8087
8395
|
}
|
|
@@ -8290,16 +8598,45 @@ function applyListDeleteAliases(cmd) {
|
|
|
8290
8598
|
applyListDeleteAliases(sub);
|
|
8291
8599
|
}
|
|
8292
8600
|
}
|
|
8601
|
+
function applyReadContractFlags(cmd) {
|
|
8602
|
+
for (const sub of cmd.commands) {
|
|
8603
|
+
const flags = () => sub.options.map((option) => option.long);
|
|
8604
|
+
if ((sub.name() === "list" || sub.name() === "get") && !flags().includes("--output")) {
|
|
8605
|
+
sub.option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml");
|
|
8606
|
+
}
|
|
8607
|
+
if (sub.name() === "list" && (flags().includes("--limit") || flags().includes("--offset"))) {
|
|
8608
|
+
if (!flags().includes("--limit")) sub.option("--limit <n>", "Items per page", Number, 50);
|
|
8609
|
+
if (!flags().includes("--offset")) sub.option("--offset <n>", "Item offset", Number, 0);
|
|
8610
|
+
if (!flags().includes("--all")) sub.option("--all", "Walk all pages");
|
|
8611
|
+
if (!flags().includes("--max")) {
|
|
8612
|
+
sub.option("--max <n>", "Maximum items with --all; 0 removes the cap", Number, 1e4);
|
|
8613
|
+
}
|
|
8614
|
+
}
|
|
8615
|
+
applyReadContractFlags(sub);
|
|
8616
|
+
}
|
|
8617
|
+
}
|
|
8618
|
+
function applySortedHelp(cmd) {
|
|
8619
|
+
cmd.configureHelp({ sortOptions: true, sortSubcommands: true });
|
|
8620
|
+
for (const sub of cmd.commands) applySortedHelp(sub);
|
|
8621
|
+
}
|
|
8293
8622
|
function buildProgram() {
|
|
8294
8623
|
const here = dirname4(fileURLToPath(import.meta.url));
|
|
8295
8624
|
const pkg = JSON.parse(readFileSync4(join4(here, "../../package.json"), "utf-8"));
|
|
8296
8625
|
const program = new Command();
|
|
8297
8626
|
program.name("airs").description(
|
|
8298
8627
|
"CLI and library for Palo Alto Prisma AIRS \u2014 guardrail refinement, AI red teaming, model security scanning, profile audits"
|
|
8299
|
-
).version(pkg.version).option("--debug", "Log all AIRS/SCM API requests and responses to a JSONL file").option("--quiet", "Suppress status and decorative output (data and errors still print)");
|
|
8300
|
-
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
8628
|
+
).version(pkg.version).option("--debug", "Log all AIRS/SCM API requests and responses to a JSONL file").option("--output <format>", "Default output format for read commands").option("--quiet", "Suppress status and decorative output (data and errors still print)");
|
|
8629
|
+
program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
8301
8630
|
const root = actionCommand.optsWithGlobals?.() ?? _thisCommand.opts();
|
|
8302
8631
|
setQuiet(Boolean(root.quiet));
|
|
8632
|
+
if ((actionCommand.name() === "list" || actionCommand.name() === "get") && actionCommand.options.some((option) => option.long === "--output")) {
|
|
8633
|
+
try {
|
|
8634
|
+
const format = await resolveOutput(actionCommand, actionCommand.opts());
|
|
8635
|
+
actionCommand.setOptionValueWithSource("output", format, "implied");
|
|
8636
|
+
} catch (error) {
|
|
8637
|
+
fail(error);
|
|
8638
|
+
}
|
|
8639
|
+
}
|
|
8303
8640
|
if (root.debug) {
|
|
8304
8641
|
const logPath = join4(homedir(), ".prisma-airs", `debug-api-${Date.now()}.jsonl`);
|
|
8305
8642
|
installDebugLogger(logPath);
|
|
@@ -8314,6 +8651,8 @@ function buildProgram() {
|
|
|
8314
8651
|
registerDoctorCommand(program);
|
|
8315
8652
|
registerCompletionCommand(program);
|
|
8316
8653
|
applyListDeleteAliases(program);
|
|
8654
|
+
applyReadContractFlags(program);
|
|
8655
|
+
applySortedHelp(program);
|
|
8317
8656
|
return program;
|
|
8318
8657
|
}
|
|
8319
8658
|
|