@cdot65/prisma-airs-cli 7.1.4 → 7.1.5
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 +45 -28
- package/package.json +3 -2
package/dist/cli/index.js
CHANGED
|
@@ -6419,6 +6419,7 @@ import pLimit2 from "p-limit";
|
|
|
6419
6419
|
|
|
6420
6420
|
// src/redteam/judge/providers.ts
|
|
6421
6421
|
import { createHash as createHash2 } from "crypto";
|
|
6422
|
+
import { TypeSafeClient } from "@typesafe-ai/sdk";
|
|
6422
6423
|
var ProviderError = class extends Error {
|
|
6423
6424
|
constructor(message) {
|
|
6424
6425
|
super(message);
|
|
@@ -6455,7 +6456,7 @@ function typesafeEndpoint(baseUrl, path3) {
|
|
|
6455
6456
|
return `${url.toString().replace(/\/+$/, "")}${path3}`;
|
|
6456
6457
|
}
|
|
6457
6458
|
var TypeSafeHttpProvider = class {
|
|
6458
|
-
name = "typesafe-
|
|
6459
|
+
name = "typesafe-sdk";
|
|
6459
6460
|
model;
|
|
6460
6461
|
url;
|
|
6461
6462
|
apiKey;
|
|
@@ -6473,33 +6474,41 @@ var TypeSafeHttpProvider = class {
|
|
|
6473
6474
|
this.sleep = options.sleep ?? defaultSleep;
|
|
6474
6475
|
}
|
|
6475
6476
|
async judge(request) {
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6477
|
+
let received;
|
|
6478
|
+
const client = new TypeSafeClient({
|
|
6479
|
+
apiKey: this.apiKey,
|
|
6480
|
+
baseURL: this.url.slice(0, -"/v1/systemone".length),
|
|
6481
|
+
timeout: this.timeoutMs,
|
|
6482
|
+
retry: { maxRetries: 0 },
|
|
6483
|
+
// One retry owner: the adapter below.
|
|
6484
|
+
logLevel: "off",
|
|
6485
|
+
// Do not allow SDK environment settings to log scan text.
|
|
6486
|
+
fetch: async (input2, init2) => {
|
|
6487
|
+
received = await this.fetch(input2, { ...init2, redirect: "error" });
|
|
6488
|
+
return received;
|
|
6489
|
+
}
|
|
6480
6490
|
});
|
|
6481
6491
|
for (let attempt = 0; ; attempt += 1) {
|
|
6482
6492
|
const started = performance.now();
|
|
6483
6493
|
let response;
|
|
6484
6494
|
try {
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
Accept: "application/json"
|
|
6492
|
-
},
|
|
6493
|
-
body,
|
|
6494
|
-
signal: AbortSignal.timeout(this.timeoutMs)
|
|
6495
|
-
});
|
|
6495
|
+
received = void 0;
|
|
6496
|
+
response = await client.systemOne({
|
|
6497
|
+
state: request.state,
|
|
6498
|
+
model: this.model,
|
|
6499
|
+
questions: request.questions
|
|
6500
|
+
}).asResponse();
|
|
6496
6501
|
} catch (error) {
|
|
6497
|
-
if (
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
)
|
|
6501
|
-
|
|
6502
|
-
|
|
6502
|
+
if (received && !received.ok) {
|
|
6503
|
+
response = received;
|
|
6504
|
+
} else {
|
|
6505
|
+
if (attempt >= this.maxRetries)
|
|
6506
|
+
throw new ProviderError(
|
|
6507
|
+
`TypeSafe API connection failed: ${error instanceof Error ? error.name : "Error"}`
|
|
6508
|
+
);
|
|
6509
|
+
await this.sleep(retryDelayMs(attempt, null));
|
|
6510
|
+
continue;
|
|
6511
|
+
}
|
|
6503
6512
|
}
|
|
6504
6513
|
if (response.ok) {
|
|
6505
6514
|
let decoded;
|
|
@@ -6847,6 +6856,13 @@ function renderSummary(results) {
|
|
|
6847
6856
|
"| Category | Judged | Judge ASR | AIRS ASR | Agreement |",
|
|
6848
6857
|
"|---|---|---|---|---|"
|
|
6849
6858
|
];
|
|
6859
|
+
if (results.provider === "replay")
|
|
6860
|
+
lines.splice(
|
|
6861
|
+
2,
|
|
6862
|
+
0,
|
|
6863
|
+
"REPLAY ONLY: reused recorded answers; no new Jev evaluation or credential check was performed.",
|
|
6864
|
+
""
|
|
6865
|
+
);
|
|
6850
6866
|
for (const [name, block] of Object.entries(results.by_category))
|
|
6851
6867
|
lines.push(
|
|
6852
6868
|
`| ${name} | ${block.judged} | ${pct(block.asr)} | ${pct(block.agreement.airs_asr_from_threat_flags)} | ${pct(block.agreement.agreement_rate)} |`
|
|
@@ -8047,6 +8063,7 @@ async function backupTargets(opts) {
|
|
|
8047
8063
|
import { lstat as lstat3, mkdir, readFile as readFile5 } from "fs/promises";
|
|
8048
8064
|
import { join as join2, resolve as resolve3 } from "path";
|
|
8049
8065
|
import { RedTeamClient } from "@cdot65/prisma-airs-sdk";
|
|
8066
|
+
import { Option as Option2 } from "commander";
|
|
8050
8067
|
var JUDGE_PROVIDER_ERROR_EXIT_CODE = 4;
|
|
8051
8068
|
var JUDGE_OUTPUT_FILES = ["results.json", "judgments.json", "summary.md"];
|
|
8052
8069
|
function probability(raw, flag) {
|
|
@@ -8098,7 +8115,7 @@ function safeContext2() {
|
|
|
8098
8115
|
function registerRedTeamJudgeCommand(redteam) {
|
|
8099
8116
|
const command = redteam.command("judge [scanFile]").description(
|
|
8100
8117
|
"Judge red-team attack outputs with TypeSafe Jev and compute an independent attack success rate"
|
|
8101
|
-
).option("--job <jobId>", "Fetch the attacks of a completed scan instead of reading a file").requiredOption("--out <dir>", "Directory for results.json, judgments.json and summary.md").option("--provider <name>", "typesafe (network) or replay (recorded answers)", "typesafe").option("--replay <file>", "Recorded judgments file for --provider replay").option("--record <file>", "Write raw provider answers here for later replay").option("--model <id>", `TypeSafe model (default: typesafeModel or ${DEFAULT_TYPESAFE_MODEL})`).option(
|
|
8118
|
+
).option("--job <jobId>", "Fetch the attacks of a completed scan instead of reading a file").requiredOption("--out <dir>", "Directory for results.json, judgments.json and summary.md").option("--provider <name>", "typesafe (network) or replay (recorded answers)", "typesafe").option("--replay <file>", "Recorded judgments file for --provider replay").option("--record <file>", "Write raw provider answers here for later replay").addOption(new Option2("--harness-credentials").hideHelp()).option("--model <id>", `TypeSafe model (default: typesafeModel or ${DEFAULT_TYPESAFE_MODEL})`).option(
|
|
8102
8119
|
"--base-url <url>",
|
|
8103
8120
|
`TypeSafe API base URL (default: typesafeBaseUrl or ${DEFAULT_TYPESAFE_BASE_URL})`
|
|
8104
8121
|
).option(
|
|
@@ -8144,7 +8161,7 @@ async function runJudge(command, scanFile, opts) {
|
|
|
8144
8161
|
const maxRetries = opts.maxRetries === "0" ? 0 : integer3(opts.maxRetries, "--max-retries", 10);
|
|
8145
8162
|
const timeoutMs = integer3(opts.timeout, "--timeout");
|
|
8146
8163
|
if (!opts.out.trim()) throw new CliUsageError("--out cannot be empty");
|
|
8147
|
-
const needsConfig = opts.job !== void 0 || opts.provider === "typesafe" && !opts.dryRun;
|
|
8164
|
+
const needsConfig = opts.job !== void 0 || opts.provider === "typesafe" && !opts.dryRun && !opts.harnessCredentials;
|
|
8148
8165
|
const config = needsConfig ? await loadConfig() : await loadConfig().catch(() => void 0);
|
|
8149
8166
|
const format = await resolveOutput(command, opts, {
|
|
8150
8167
|
allowed: ["pretty", "json"],
|
|
@@ -8183,8 +8200,8 @@ async function runJudge(command, scanFile, opts) {
|
|
|
8183
8200
|
);
|
|
8184
8201
|
}
|
|
8185
8202
|
const { units, notes } = normalized;
|
|
8186
|
-
const model = opts.model ?? config?.typesafeModel ?? DEFAULT_TYPESAFE_MODEL;
|
|
8187
|
-
const baseUrl = opts.baseUrl ?? config?.typesafeBaseUrl ?? DEFAULT_TYPESAFE_BASE_URL;
|
|
8203
|
+
const model = opts.model ?? (opts.harnessCredentials ? process.env.TYPESAFE_DEFAULT_MODEL : config?.typesafeModel) ?? DEFAULT_TYPESAFE_MODEL;
|
|
8204
|
+
const baseUrl = opts.baseUrl ?? (opts.harnessCredentials ? process.env.TYPESAFE_BASE_URL : config?.typesafeBaseUrl) ?? DEFAULT_TYPESAFE_BASE_URL;
|
|
8188
8205
|
if (opts.dryRun) {
|
|
8189
8206
|
const first = units.find((unit) => !unit.is_error);
|
|
8190
8207
|
const payload = {
|
|
@@ -8204,10 +8221,10 @@ async function runJudge(command, scanFile, opts) {
|
|
|
8204
8221
|
throw new CliUsageError("--replay must contain a JSON object");
|
|
8205
8222
|
provider = new ReplayProvider(recorded);
|
|
8206
8223
|
} else {
|
|
8207
|
-
const apiKey = config?.typesafeApiKey;
|
|
8224
|
+
const apiKey = opts.harnessCredentials ? process.env.TYPESAFE_API_KEY : config?.typesafeApiKey;
|
|
8208
8225
|
if (typeof apiKey !== "string" || !apiKey.trim())
|
|
8209
8226
|
throw new Error(
|
|
8210
|
-
`TypeSafe API key is not configured (typesafeApiKey). ${settingRemedy(["typesafeApiKey"], safeContext2())}`
|
|
8227
|
+
opts.harnessCredentials ? "No TypeSafe key reached the judge from its AIRS environment. Check airs env typesafe status, or save a key with airs env typesafe set. No live judgment was performed; replay was not substituted." : `TypeSafe API key is not configured (typesafeApiKey). ${settingRemedy(["typesafeApiKey"], safeContext2())}`
|
|
8211
8228
|
);
|
|
8212
8229
|
provider = new TypeSafeHttpProvider({ apiKey, model, baseUrl, maxRetries, timeoutMs });
|
|
8213
8230
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdot65/prisma-airs-cli",
|
|
3
3
|
"packageManager": "pnpm@10.6.5",
|
|
4
|
-
"version": "7.1.
|
|
5
|
-
"description": "CLI and library for Palo Alto Prisma AIRS
|
|
4
|
+
"version": "7.1.5",
|
|
5
|
+
"description": "CLI and library for Palo Alto Prisma AIRS \u2014 guardrail refinement, AI red teaming, model security scanning, profile audits",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@cdot65/prisma-airs-sdk": "0.33.0",
|
|
63
63
|
"@inquirer/prompts": "^8.3.0",
|
|
64
|
+
"@typesafe-ai/sdk": "0.6.0",
|
|
64
65
|
"chalk": "^5.6.2",
|
|
65
66
|
"commander": "^14.0.3",
|
|
66
67
|
"js-yaml": "^4.3.2",
|