@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.
Files changed (2) hide show
  1. package/dist/cli/index.js +45 -28
  2. 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-http";
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
- const body = JSON.stringify({
6477
- state: request.state,
6478
- model: this.model,
6479
- questions: request.questions
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
- response = await this.fetch(this.url, {
6486
- method: "POST",
6487
- redirect: "error",
6488
- headers: {
6489
- Authorization: `Bearer ${this.apiKey}`,
6490
- "Content-Type": "application/json",
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 (attempt >= this.maxRetries)
6498
- throw new ProviderError(
6499
- `TypeSafe API connection failed: ${error instanceof Error ? error.name : "Error"}`
6500
- );
6501
- await this.sleep(retryDelayMs(attempt, null));
6502
- continue;
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.4",
5
- "description": "CLI and library for Palo Alto Prisma AIRS — guardrail refinement, AI red teaming, model security scanning, profile audits",
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",