@cdot65/prisma-airs-cli 5.8.5 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +60 -11
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -8870,6 +8870,17 @@ async function parseBody(opts) {
|
|
|
8870
8870
|
}
|
|
8871
8871
|
}
|
|
8872
8872
|
|
|
8873
|
+
// src/cli/commands/dlp/visibility.ts
|
|
8874
|
+
function predefinedFlag(cmd) {
|
|
8875
|
+
return cmd.option(
|
|
8876
|
+
"--include-predefined",
|
|
8877
|
+
"Include predefined (PANW-shipped) records; listings show only tenant-created records by default"
|
|
8878
|
+
);
|
|
8879
|
+
}
|
|
8880
|
+
function visibleRecords(records, includePredefined) {
|
|
8881
|
+
return includePredefined ? records : records.filter((record) => record.type !== "predefined");
|
|
8882
|
+
}
|
|
8883
|
+
|
|
8873
8884
|
// src/cli/commands/dlp/dictionaries.ts
|
|
8874
8885
|
async function buildMetadata(opts) {
|
|
8875
8886
|
if (opts.metadataFile) {
|
|
@@ -8894,6 +8905,7 @@ function register(dlp) {
|
|
|
8894
8905
|
"Starting offset \u2014 rounds down to a page boundary",
|
|
8895
8906
|
(v) => Number.parseInt(v, 10)
|
|
8896
8907
|
).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");
|
|
8908
|
+
predefinedFlag(listCmd);
|
|
8897
8909
|
registerPageAliases(listCmd, { sizeFlag: "--size", sizeKey: "size" });
|
|
8898
8910
|
listCmd.action(async (opts) => {
|
|
8899
8911
|
try {
|
|
@@ -8905,9 +8917,10 @@ function register(dlp) {
|
|
|
8905
8917
|
sort: opts.sort,
|
|
8906
8918
|
keywords: includeKeywords ? true : void 0
|
|
8907
8919
|
};
|
|
8908
|
-
const all = opts.all ? await svc.listAll({ ...params, max: Number(opts.max) }) :
|
|
8920
|
+
const all = opts.all ? await svc.listAll({ ...params, max: Number(opts.max) }) : (await svc.list({ ...params, page })).content;
|
|
8921
|
+
const visible = visibleRecords(all, opts.includePredefined);
|
|
8909
8922
|
dlpDictionaries.renderList(
|
|
8910
|
-
|
|
8923
|
+
{ content: visible, totalElements: visible.length },
|
|
8911
8924
|
await resolveOutput(listCmd, opts)
|
|
8912
8925
|
);
|
|
8913
8926
|
} catch (err) {
|
|
@@ -9321,14 +9334,17 @@ async function resolveWriteBody(opts) {
|
|
|
9321
9334
|
}
|
|
9322
9335
|
function register4(dlp) {
|
|
9323
9336
|
const group = dlp.command("patterns").description("DLP data patterns (full CRUD)");
|
|
9324
|
-
const listCmd =
|
|
9337
|
+
const listCmd = predefinedFlag(
|
|
9338
|
+
listFlags2(group.command("list").description("List data patterns (tenant-created by default)"))
|
|
9339
|
+
);
|
|
9325
9340
|
listCmd.action(async (opts) => {
|
|
9326
9341
|
try {
|
|
9327
9342
|
const { page, size } = resolvePageParams(listCmd, opts);
|
|
9328
9343
|
const svc = new SdkDataPatternsService(await loadDlpClientOptions());
|
|
9329
|
-
const result = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) :
|
|
9344
|
+
const result = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) : (await svc.list({ page, size, sort: opts.sort })).content;
|
|
9345
|
+
const visible = visibleRecords(result, opts.includePredefined);
|
|
9330
9346
|
dlpPatterns.renderList(
|
|
9331
|
-
|
|
9347
|
+
{ content: visible, totalElements: visible.length },
|
|
9332
9348
|
await resolveOutput(listCmd, opts)
|
|
9333
9349
|
);
|
|
9334
9350
|
} catch (err) {
|
|
@@ -9467,14 +9483,17 @@ function register5(dlp) {
|
|
|
9467
9483
|
const group = dlp.command("profiles").description(
|
|
9468
9484
|
"DLP data profiles. No supported DELETE; status-based retirement is not live-verified."
|
|
9469
9485
|
);
|
|
9470
|
-
const listCmd =
|
|
9486
|
+
const listCmd = predefinedFlag(
|
|
9487
|
+
listFlags3(group.command("list").description("List data profiles (tenant-created by default)"))
|
|
9488
|
+
);
|
|
9471
9489
|
listCmd.action(async (opts) => {
|
|
9472
9490
|
try {
|
|
9473
9491
|
const { page, size } = resolvePageParams(listCmd, opts);
|
|
9474
9492
|
const svc = new SdkDataProfilesService(await loadDlpClientOptions());
|
|
9475
|
-
const result = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) :
|
|
9493
|
+
const result = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) : (await svc.list({ page, size, sort: opts.sort })).content;
|
|
9494
|
+
const visible = visibleRecords(result, opts.includePredefined);
|
|
9476
9495
|
dlpProfiles.renderList(
|
|
9477
|
-
|
|
9496
|
+
{ content: visible, totalElements: visible.length },
|
|
9478
9497
|
await resolveOutput(listCmd, opts)
|
|
9479
9498
|
);
|
|
9480
9499
|
} catch (err) {
|
|
@@ -9752,6 +9771,10 @@ async function backupDlpResources(api, tsgId, options = {}) {
|
|
|
9752
9771
|
if (RETIRED_PROFILE.has(profile.profile_status ?? "active")) continue;
|
|
9753
9772
|
const name = profile.name ?? "(unnamed)";
|
|
9754
9773
|
try {
|
|
9774
|
+
if (!profile.detection_rules?.length)
|
|
9775
|
+
throw new Error(
|
|
9776
|
+
"has no exported detection rules (the API does not expose basic data profile content)"
|
|
9777
|
+
);
|
|
9755
9778
|
for (const leaf of ruleLeaves(profile)) {
|
|
9756
9779
|
const id = leaf.value.id;
|
|
9757
9780
|
if (id == null || id === "") {
|
|
@@ -9769,6 +9792,8 @@ async function backupDlpResources(api, tsgId, options = {}) {
|
|
|
9769
9792
|
} else {
|
|
9770
9793
|
const record = patternById.get(id);
|
|
9771
9794
|
if (!record) throw new Error(`references an unknown data pattern: ${id}`);
|
|
9795
|
+
if (RETIRED_PATTERN.has(record.status ?? "active"))
|
|
9796
|
+
throw new Error(`references a retired data pattern: ${record.name ?? id}`);
|
|
9772
9797
|
if (leaf.value.version != null && record.version !== leaf.value.version)
|
|
9773
9798
|
throw new Error(
|
|
9774
9799
|
`references data pattern version ${leaf.value.version}, but the catalog holds version ${record.version ?? "unknown"}: ${id}`
|
|
@@ -9822,6 +9847,10 @@ function compareEcho(request, readBack) {
|
|
|
9822
9847
|
differences.push(path3);
|
|
9823
9848
|
return;
|
|
9824
9849
|
}
|
|
9850
|
+
if (path3.endsWith(".supported_confidence_levels") && Array.isArray(a) && Array.isArray(b) && a.every((level) => b.includes(level))) {
|
|
9851
|
+
if (a.length !== b.length) serverAdded.push(path3);
|
|
9852
|
+
return;
|
|
9853
|
+
}
|
|
9825
9854
|
if (Array.isArray(a) || Array.isArray(b)) {
|
|
9826
9855
|
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
|
|
9827
9856
|
differences.push(path3);
|
|
@@ -10049,6 +10078,20 @@ async function planDlpResourcesRestore(api, input2, destinationTsgId, options =
|
|
|
10049
10078
|
`Data pattern uses a tenant-bound detection technique: ${source.name}; provision it in the destination and bind it with --pattern-map "${source.name}=<destination-name>"`
|
|
10050
10079
|
);
|
|
10051
10080
|
}
|
|
10081
|
+
if (["regex", "weighted_regex"].includes(source.detection_config?.technique ?? "") && !(Array.isArray(source.matching_rules?.regexes) && source.matching_rules.regexes.length)) {
|
|
10082
|
+
if (options.skipUnresolved) {
|
|
10083
|
+
unresolved.push({
|
|
10084
|
+
kind: "pattern",
|
|
10085
|
+
sourceId: source.id,
|
|
10086
|
+
name: source.name,
|
|
10087
|
+
reason: "detection content is not exported by the API (copy of a predefined pattern)"
|
|
10088
|
+
});
|
|
10089
|
+
continue;
|
|
10090
|
+
}
|
|
10091
|
+
throw new Error(
|
|
10092
|
+
`Data pattern has no exported detection content (a copy of a predefined pattern): ${source.name}; bind an equivalent with --pattern-map "${source.name}=<destination-name>" or exclude dependents with --skip-unresolved`
|
|
10093
|
+
);
|
|
10094
|
+
}
|
|
10052
10095
|
const name = `${prefix}${source.name}`;
|
|
10053
10096
|
assertName(name);
|
|
10054
10097
|
const body = patternRequest(source, name);
|
|
@@ -10271,7 +10314,9 @@ async function restoreDlpResources(api, plan, options = {}) {
|
|
|
10271
10314
|
const readBack = await api.dictionaries.get(created.id, { includeKeywords: true });
|
|
10272
10315
|
const echo = dictionaryEcho(item.metadata, readBack, item.keywords);
|
|
10273
10316
|
if (!echo.matches || readBack.name !== item.name)
|
|
10274
|
-
throw new Error(
|
|
10317
|
+
throw new Error(
|
|
10318
|
+
`Restored dictionary did not verify: ${item.name} (created id ${created.id}; inspect it before retrying)`
|
|
10319
|
+
);
|
|
10275
10320
|
if (echo.serverAdded.length)
|
|
10276
10321
|
result.serverAdded.push({ resource: `dictionary ${item.name}`, fields: echo.serverAdded });
|
|
10277
10322
|
bindings.set(item.sourceId, { id: created.id, name: item.name });
|
|
@@ -10306,7 +10351,9 @@ async function restoreDlpResources(api, plan, options = {}) {
|
|
|
10306
10351
|
const readBack = await api.patterns.get(created.id);
|
|
10307
10352
|
const echo = compareEcho(item.body, readBack);
|
|
10308
10353
|
if (!echo.matches || readBack.name !== item.name || RETIRED_PATTERN.has(readBack.status ?? "active"))
|
|
10309
|
-
throw new Error(
|
|
10354
|
+
throw new Error(
|
|
10355
|
+
`Restored data pattern did not verify: ${item.name} (created id ${created.id}; inspect it before retrying)`
|
|
10356
|
+
);
|
|
10310
10357
|
if (echo.serverAdded.length)
|
|
10311
10358
|
result.serverAdded.push({
|
|
10312
10359
|
resource: `data pattern ${item.name}`,
|
|
@@ -10357,7 +10404,9 @@ async function restoreDlpResources(api, plan, options = {}) {
|
|
|
10357
10404
|
const readBack = await api.profiles.get(created.id);
|
|
10358
10405
|
const echo = compareEcho(body, readBack);
|
|
10359
10406
|
if (!echo.matches || readBack.name !== item.name || RETIRED_PROFILE.has(readBack.profile_status ?? "active"))
|
|
10360
|
-
throw new Error(
|
|
10407
|
+
throw new Error(
|
|
10408
|
+
`Restored data profile did not verify: ${item.name} (created id ${created.id}; inspect it before retrying)`
|
|
10409
|
+
);
|
|
10361
10410
|
if (echo.serverAdded.length)
|
|
10362
10411
|
result.serverAdded.push({
|
|
10363
10412
|
resource: `data profile ${item.name}`,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdot65/prisma-airs-cli",
|
|
3
3
|
"packageManager": "pnpm@10.6.5",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.9.0",
|
|
5
5
|
"description": "CLI and library for Palo Alto Prisma AIRS — guardrail refinement, AI red teaming, model security scanning, profile audits",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|