@cdot65/prisma-airs-cli 3.2.0 → 3.3.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 +10 -1
- package/dist/{chunk-TTBN7YHC.js → chunk-2VIUZRPB.js} +140 -1
- package/dist/cli/index.js +1186 -292
- package/dist/index.d.ts +106 -4
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
11
11
|
[](https://nodejs.org/)
|
|
12
12
|
|
|
13
|
-
**Full operational coverage over Palo Alto Prisma AIRS AI security — guardrail refinement, runtime scanning, AI red teaming, and model security.**
|
|
13
|
+
**Full operational coverage over Palo Alto Prisma AIRS AI security — guardrail refinement, runtime scanning, AI red teaming, AI Gateway, and model security.**
|
|
14
14
|
|
|
15
15
|
> **[Read the full documentation](https://cdot65.github.io/prisma-airs-cli/)** — installation, configuration, architecture, CLI reference, and examples.
|
|
16
16
|
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
- **Runtime Scanning** — scan prompts and responses against AIRS security profiles, single or bulk with CSV export
|
|
20
20
|
- **Guardrail Optimization** — atomic CLI commands (`create`, `apply`, `eval`, `revert`) for custom topic guardrails, designed for autonomous agent loops (see [`AGENTS.md`](AGENTS.md))
|
|
21
21
|
- **AI Red Teaming** — adversarial scanning with static, dynamic, and custom prompt set attack modes
|
|
22
|
+
- **[AI Gateway](https://cdot65.github.io/prisma-airs-cli/cli/aigateway/workspaces/)** — scoped/admin workspace management and workspace cost telemetry
|
|
22
23
|
- **Model Security** — ML model supply chain scanning with security groups, rules, and violation tracking
|
|
23
24
|
- **`airs doctor`** — one-command diagnostics for environment, credentials, and API connectivity
|
|
24
25
|
- **`airs config`** — manage `~/.prisma-airs/config.json` from the CLI (`list`, `get`, `set`, `unset`, `path`)
|
|
@@ -55,6 +56,13 @@ airs runtime topics revert --profile my-profile --name "Explosives"
|
|
|
55
56
|
airs redteam scan --target <uuid> --name "Full Scan" --type STATIC
|
|
56
57
|
airs redteam report <job-id>
|
|
57
58
|
|
|
59
|
+
# Red team custom target adapters
|
|
60
|
+
airs redteam adapter list --output json
|
|
61
|
+
|
|
62
|
+
# AI Gateway workspaces and cost telemetry
|
|
63
|
+
airs aigateway workspace list --all --output json
|
|
64
|
+
airs aigateway telemetry cost --workspace <workspace-slug> --days 30
|
|
65
|
+
|
|
58
66
|
# Model security
|
|
59
67
|
airs model-security scans create --config scan-config.json
|
|
60
68
|
```
|
|
@@ -69,6 +77,7 @@ The full guides, complete CLI reference, configuration, and architecture live on
|
|
|
69
77
|
- **[Runtime Security](https://cdot65.github.io/prisma-airs-cli/runtime/overview/)** — scanning, profiles, topics, and DLP management
|
|
70
78
|
- **[Guardrail Optimization](https://cdot65.github.io/prisma-airs-cli/runtime/guardrails/overview/)** — the agent-driven `topics create/apply/eval/revert` loop
|
|
71
79
|
- **[AI Red Teaming](https://cdot65.github.io/prisma-airs-cli/redteam/overview/)** — static, dynamic, and custom adversarial scans
|
|
80
|
+
- **[AI Gateway](https://cdot65.github.io/prisma-airs-cli/cli/aigateway/workspaces/)** — workspace CRUD, two-plane authorization, and cost telemetry
|
|
72
81
|
- **[Model Security](https://cdot65.github.io/prisma-airs-cli/model-security/overview/)** — ML model supply-chain scanning
|
|
73
82
|
- **[CLI Reference](https://cdot65.github.io/prisma-airs-cli/cli/)** — every command, flag, and example
|
|
74
83
|
|
|
@@ -1012,6 +1012,52 @@ function normalizeTargetDetail(raw) {
|
|
|
1012
1012
|
metadata: sanitizeTargetMetadata(raw.target_metadata)
|
|
1013
1013
|
};
|
|
1014
1014
|
}
|
|
1015
|
+
function normalizeAdapterListItem(raw) {
|
|
1016
|
+
return {
|
|
1017
|
+
uuid: raw.uuid,
|
|
1018
|
+
name: raw.name,
|
|
1019
|
+
status: raw.status,
|
|
1020
|
+
createdAt: raw.created_at,
|
|
1021
|
+
updatedAt: raw.updated_at,
|
|
1022
|
+
createdByUserId: raw.created_by_user_id,
|
|
1023
|
+
targetCount: raw.target_count
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
function normalizeAdapterVar(raw) {
|
|
1027
|
+
return {
|
|
1028
|
+
key: raw.key,
|
|
1029
|
+
value: raw.value,
|
|
1030
|
+
type: raw.type,
|
|
1031
|
+
isRedacted: raw.is_redacted
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
function normalizeAdapterDetail(raw) {
|
|
1035
|
+
return {
|
|
1036
|
+
uuid: raw.uuid,
|
|
1037
|
+
tsgId: raw.tsg_id,
|
|
1038
|
+
name: raw.name,
|
|
1039
|
+
scriptB64: raw.script_b64,
|
|
1040
|
+
status: raw.status,
|
|
1041
|
+
description: raw.description,
|
|
1042
|
+
networkBrokerChannelUuid: raw.network_broker_channel_uuid,
|
|
1043
|
+
variables: (raw.variables ?? []).map(normalizeAdapterVar),
|
|
1044
|
+
targetCount: raw.target_count,
|
|
1045
|
+
createdAt: raw.created_at,
|
|
1046
|
+
updatedAt: raw.updated_at,
|
|
1047
|
+
createdByUserId: raw.created_by_user_id,
|
|
1048
|
+
updatedByUserId: raw.updated_by_user_id
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
function preserveVariablesForUpdate(variables) {
|
|
1052
|
+
return variables.map((v) => ({
|
|
1053
|
+
key: v.key,
|
|
1054
|
+
value: v.isRedacted ? null : v.value ?? null,
|
|
1055
|
+
type: v.type
|
|
1056
|
+
}));
|
|
1057
|
+
}
|
|
1058
|
+
function toWireVariables(variables) {
|
|
1059
|
+
return variables.map((v) => ({ key: v.key, value: v.value, type: v.type }));
|
|
1060
|
+
}
|
|
1015
1061
|
var SdkRedTeamService = class {
|
|
1016
1062
|
client;
|
|
1017
1063
|
constructor(opts) {
|
|
@@ -1180,7 +1226,12 @@ var SdkRedTeamService = class {
|
|
|
1180
1226
|
}
|
|
1181
1227
|
async createScan(request) {
|
|
1182
1228
|
let jobMetadata = {};
|
|
1183
|
-
if (request.jobType === "STATIC"
|
|
1229
|
+
if (request.jobType === "STATIC") {
|
|
1230
|
+
if (!request.categories) {
|
|
1231
|
+
throw new Error(
|
|
1232
|
+
"STATIC scans require categories. Pass categories explicitly or use the CLI default."
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1184
1235
|
jobMetadata = { categories: request.categories };
|
|
1185
1236
|
} else if (request.jobType === "CUSTOM" && request.customPromptSets) {
|
|
1186
1237
|
jobMetadata = {
|
|
@@ -1408,6 +1459,87 @@ var SdkRedTeamService = class {
|
|
|
1408
1459
|
totalItems: pagination?.total_items
|
|
1409
1460
|
};
|
|
1410
1461
|
}
|
|
1462
|
+
// -------------------------------------------------------------------------
|
|
1463
|
+
// Custom target adapters (SDK 0.16.0)
|
|
1464
|
+
// -------------------------------------------------------------------------
|
|
1465
|
+
async listAdapters(opts) {
|
|
1466
|
+
const sdkOpts = {};
|
|
1467
|
+
if (opts?.limit != null) sdkOpts.limit = opts.limit;
|
|
1468
|
+
if (opts?.offset != null) sdkOpts.skip = opts.offset;
|
|
1469
|
+
if (opts?.search) sdkOpts.search = opts.search;
|
|
1470
|
+
const raw = await this.client.adapters.list(sdkOpts);
|
|
1471
|
+
const pagination = raw.pagination;
|
|
1472
|
+
return {
|
|
1473
|
+
adapters: (raw.data ?? []).map(normalizeAdapterListItem),
|
|
1474
|
+
totalItems: pagination?.total_items
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
async getAdapter(uuid) {
|
|
1478
|
+
const raw = await this.client.adapters.get(uuid);
|
|
1479
|
+
return normalizeAdapterDetail(raw);
|
|
1480
|
+
}
|
|
1481
|
+
async createAdapter(request, validate) {
|
|
1482
|
+
const body = {
|
|
1483
|
+
name: request.name,
|
|
1484
|
+
script_b64: request.scriptB64,
|
|
1485
|
+
prompt: request.prompt
|
|
1486
|
+
};
|
|
1487
|
+
if (request.description !== void 0) body.description = request.description;
|
|
1488
|
+
if (request.networkBrokerChannelUuid !== void 0) {
|
|
1489
|
+
body.network_broker_channel_uuid = request.networkBrokerChannelUuid;
|
|
1490
|
+
}
|
|
1491
|
+
if (request.variables !== void 0) body.variables = toWireVariables(request.variables);
|
|
1492
|
+
const raw = await this.client.adapters.create(
|
|
1493
|
+
// biome-ignore lint/suspicious/noExplicitAny: body is assembled dynamically; SDK validates the shape
|
|
1494
|
+
body,
|
|
1495
|
+
validate === void 0 ? void 0 : { validate }
|
|
1496
|
+
);
|
|
1497
|
+
return normalizeAdapterDetail(raw);
|
|
1498
|
+
}
|
|
1499
|
+
async updateAdapter(uuid, overrides, validate) {
|
|
1500
|
+
const current = await this.getAdapter(uuid);
|
|
1501
|
+
const body = {
|
|
1502
|
+
name: overrides.name ?? current.name,
|
|
1503
|
+
script_b64: overrides.scriptB64 ?? current.scriptB64,
|
|
1504
|
+
prompt: overrides.prompt,
|
|
1505
|
+
variables: overrides.variables ? toWireVariables(overrides.variables) : preserveVariablesForUpdate(current.variables)
|
|
1506
|
+
};
|
|
1507
|
+
const description = overrides.description ?? current.description;
|
|
1508
|
+
if (description != null) body.description = description;
|
|
1509
|
+
const channel = overrides.networkBrokerChannelUuid ?? current.networkBrokerChannelUuid;
|
|
1510
|
+
if (channel != null) body.network_broker_channel_uuid = channel;
|
|
1511
|
+
const raw = await this.client.adapters.update(
|
|
1512
|
+
uuid,
|
|
1513
|
+
// biome-ignore lint/suspicious/noExplicitAny: body is assembled dynamically; SDK validates the shape
|
|
1514
|
+
body,
|
|
1515
|
+
validate === void 0 ? void 0 : { validate }
|
|
1516
|
+
);
|
|
1517
|
+
return normalizeAdapterDetail(raw);
|
|
1518
|
+
}
|
|
1519
|
+
async deleteAdapter(uuid) {
|
|
1520
|
+
await this.client.adapters.delete(uuid);
|
|
1521
|
+
}
|
|
1522
|
+
async validateAdapter(request) {
|
|
1523
|
+
let variables = request.variables ? toWireVariables(request.variables) : void 0;
|
|
1524
|
+
if (variables === void 0 && request.adapterUuid) {
|
|
1525
|
+
const adapter = await this.getAdapter(request.adapterUuid);
|
|
1526
|
+
variables = preserveVariablesForUpdate(adapter.variables);
|
|
1527
|
+
}
|
|
1528
|
+
const body = {
|
|
1529
|
+
script_b64: request.scriptB64,
|
|
1530
|
+
network_broker_channel_uuid: request.networkBrokerChannelUuid,
|
|
1531
|
+
prompt: request.prompt
|
|
1532
|
+
};
|
|
1533
|
+
if (variables !== void 0) body.variables = variables;
|
|
1534
|
+
if (request.adapterUuid !== void 0) body.adapter_uuid = request.adapterUuid;
|
|
1535
|
+
const raw = await this.client.adapters.validate(body);
|
|
1536
|
+
return {
|
|
1537
|
+
validated: raw.validated,
|
|
1538
|
+
stdout: raw.stdout,
|
|
1539
|
+
stderr: raw.stderr,
|
|
1540
|
+
traceback: raw.traceback
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1411
1543
|
};
|
|
1412
1544
|
|
|
1413
1545
|
// src/airs/runtime.ts
|
|
@@ -2030,6 +2162,10 @@ var ConfigSchema = z.object({
|
|
|
2030
2162
|
modelSecDataEndpoint: z.string().optional(),
|
|
2031
2163
|
modelSecMgmtEndpoint: z.string().optional(),
|
|
2032
2164
|
modelSecTokenEndpoint: z.string().optional(),
|
|
2165
|
+
// AI Gateway (endpoints only; creds shared with mgmt*)
|
|
2166
|
+
aiGwDataEndpoint: z.string().optional(),
|
|
2167
|
+
aiGwAdminEndpoint: z.string().optional(),
|
|
2168
|
+
aiGwTokenEndpoint: z.string().optional(),
|
|
2033
2169
|
// Tuning
|
|
2034
2170
|
scanConcurrency: z.coerce.number().int().min(1).max(20).default(5),
|
|
2035
2171
|
// Persistence
|
|
@@ -2060,6 +2196,9 @@ function fromEnv() {
|
|
|
2060
2196
|
modelSecDataEndpoint: env.PANW_MODEL_SEC_DATA_ENDPOINT,
|
|
2061
2197
|
modelSecMgmtEndpoint: env.PANW_MODEL_SEC_MGMT_ENDPOINT,
|
|
2062
2198
|
modelSecTokenEndpoint: env.PANW_MODEL_SEC_TOKEN_ENDPOINT,
|
|
2199
|
+
aiGwDataEndpoint: env.PANW_AI_GW_DATA_ENDPOINT,
|
|
2200
|
+
aiGwAdminEndpoint: env.PANW_AI_GW_ADMIN_ENDPOINT,
|
|
2201
|
+
aiGwTokenEndpoint: env.PANW_AI_GW_TOKEN_ENDPOINT,
|
|
2063
2202
|
scanConcurrency: env.SCAN_CONCURRENCY,
|
|
2064
2203
|
dataDir: env.DATA_DIR
|
|
2065
2204
|
};
|