farai 0.3.1 → 0.3.3
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 +211 -78
- package/dist/cli/index.js.map +12 -11
- package/docker/kali/Dockerfile +59 -3
- package/docker/kali/farai-image-contract +1 -0
- package/docker/kali/farai-image-doctor.py +14 -1
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -5398,7 +5398,7 @@ function parseManifest(value) {
|
|
|
5398
5398
|
if (!value || typeof value !== "object")
|
|
5399
5399
|
throw new Error("invalid farai tool manifest");
|
|
5400
5400
|
const candidate = value;
|
|
5401
|
-
if (
|
|
5401
|
+
if (!Array.isArray(candidate.aptPackages) || !candidate.pinnedTools || typeof candidate.pinnedTools !== "object" || !candidate.pinnedAssets || typeof candidate.pinnedAssets !== "object" || !candidate.workflows || typeof candidate.workflows !== "object") {
|
|
5402
5402
|
throw new Error("invalid farai tool manifest");
|
|
5403
5403
|
}
|
|
5404
5404
|
const aptPackages = candidate.aptPackages.filter((item) => typeof item === "string" && Boolean(item));
|
|
@@ -5445,7 +5445,6 @@ function parseManifest(value) {
|
|
|
5445
5445
|
if (!Object.keys(pinnedAssets).length)
|
|
5446
5446
|
throw new Error("empty pinned asset manifest");
|
|
5447
5447
|
return {
|
|
5448
|
-
contract: candidate.contract,
|
|
5449
5448
|
aptPackages,
|
|
5450
5449
|
pinnedTools,
|
|
5451
5450
|
pinnedAssets,
|
|
@@ -5455,11 +5454,15 @@ function parseManifest(value) {
|
|
|
5455
5454
|
function isSha256(value) {
|
|
5456
5455
|
return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
5457
5456
|
}
|
|
5458
|
-
var KALI_TOOL_MANIFEST_PATH, KALI_TOOL_MANIFEST;
|
|
5457
|
+
var KALI_TOOL_MANIFEST_PATH, KALI_IMAGE_CONTRACT_PATH, KALI_TOOL_MANIFEST, KALI_IMAGE_CONTRACT;
|
|
5459
5458
|
var init_kali_tool_manifest = __esm(() => {
|
|
5460
5459
|
init_file_read();
|
|
5461
5460
|
KALI_TOOL_MANIFEST_PATH = join4(import.meta.dir, "..", "..", "docker", "kali", "farai-tool-manifest.json");
|
|
5461
|
+
KALI_IMAGE_CONTRACT_PATH = join4(import.meta.dir, "..", "..", "docker", "kali", "farai-image-contract");
|
|
5462
5462
|
KALI_TOOL_MANIFEST = parseManifest(JSON.parse(readBoundedFileTextSync(KALI_TOOL_MANIFEST_PATH, 1024 * 1024, "kali tool manifest")));
|
|
5463
|
+
KALI_IMAGE_CONTRACT = readBoundedFileTextSync(KALI_IMAGE_CONTRACT_PATH, 1024, "kali image contract").trim();
|
|
5464
|
+
if (!KALI_IMAGE_CONTRACT)
|
|
5465
|
+
throw new Error("empty kali image contract");
|
|
5463
5466
|
});
|
|
5464
5467
|
|
|
5465
5468
|
// src/agent-tools/mcp-builtins.ts
|
|
@@ -7270,6 +7273,7 @@ class KaliContainerBackend {
|
|
|
7270
7273
|
this.workspacePath = containerWorkspacePath(this.rootWorkspace, this.workspace);
|
|
7271
7274
|
this.timeoutMs = options.timeoutMs ?? 120000;
|
|
7272
7275
|
this.processRunner = options.processRunner ?? ((command, args) => runProcess(command, args, Math.min(this.timeoutMs, 15000)));
|
|
7276
|
+
this.pullRunner = options.pullRunner ?? options.processRunner ?? ((command, args) => runProcess(command, args, KALI_IMAGE_PULL_TIMEOUT_MS));
|
|
7273
7277
|
this.signal = options.signal;
|
|
7274
7278
|
this.onOutputChunk = options.onOutputChunk;
|
|
7275
7279
|
this.lifecycle = options.lifecycle;
|
|
@@ -7280,9 +7284,86 @@ class KaliContainerBackend {
|
|
|
7280
7284
|
imageContract: KALI_IMAGE_CONTRACT
|
|
7281
7285
|
} : undefined;
|
|
7282
7286
|
}
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7287
|
+
pullImageCommand() {
|
|
7288
|
+
return ["docker", "pull", this.image];
|
|
7289
|
+
}
|
|
7290
|
+
async remoteImageDigest() {
|
|
7291
|
+
const inspect = await this.processRunner("docker", ["buildx", "imagetools", "inspect", this.image, "--format", "{{.Manifest.Digest}}"]);
|
|
7292
|
+
if (inspect.exitCode !== 0)
|
|
7293
|
+
return;
|
|
7294
|
+
return digestOf(inspect.stdout.trim());
|
|
7295
|
+
}
|
|
7296
|
+
async checkForImageUpdate() {
|
|
7297
|
+
const local = await this.resolveImage();
|
|
7298
|
+
if (!local.exists)
|
|
7299
|
+
return {
|
|
7300
|
+
exists: false,
|
|
7301
|
+
upToDate: false,
|
|
7302
|
+
...local.error ? {
|
|
7303
|
+
error: local.error
|
|
7304
|
+
} : {}
|
|
7305
|
+
};
|
|
7306
|
+
const remote = await this.remoteImageDigest();
|
|
7307
|
+
if (!remote || !local.repoDigest)
|
|
7308
|
+
return {
|
|
7309
|
+
exists: true,
|
|
7310
|
+
upToDate: true
|
|
7311
|
+
};
|
|
7312
|
+
return {
|
|
7313
|
+
exists: true,
|
|
7314
|
+
upToDate: local.repoDigest === remote
|
|
7315
|
+
};
|
|
7316
|
+
}
|
|
7317
|
+
async ensureImage() {
|
|
7318
|
+
const local = await this.resolveImage();
|
|
7319
|
+
if (local.exists) {
|
|
7320
|
+
const remote = await this.remoteImageDigest();
|
|
7321
|
+
if (!remote || local.repoDigest !== undefined && local.repoDigest === remote) {
|
|
7322
|
+
return {
|
|
7323
|
+
exitCode: 0,
|
|
7324
|
+
stdout: "image ready",
|
|
7325
|
+
stderr: "",
|
|
7326
|
+
durationMs: 0,
|
|
7327
|
+
timedOut: false
|
|
7328
|
+
};
|
|
7329
|
+
}
|
|
7330
|
+
}
|
|
7331
|
+
const started = Date.now();
|
|
7332
|
+
const pulled = await this.pullRunner("docker", ["pull", this.image]);
|
|
7333
|
+
if (pulled.exitCode !== 0) {
|
|
7334
|
+
if (local.exists) {
|
|
7335
|
+
return {
|
|
7336
|
+
exitCode: 0,
|
|
7337
|
+
stdout: pulled.stdout || "using local kali image",
|
|
7338
|
+
stderr: "",
|
|
7339
|
+
durationMs: Date.now() - started,
|
|
7340
|
+
timedOut: false
|
|
7341
|
+
};
|
|
7342
|
+
}
|
|
7343
|
+
return {
|
|
7344
|
+
...pulled,
|
|
7345
|
+
stderr: dockerFailure(pulled, `could not pull kali image ${this.image}; check network access to ${KALI_IMAGE_REPO}`),
|
|
7346
|
+
durationMs: Date.now() - started,
|
|
7347
|
+
timedOut: false
|
|
7348
|
+
};
|
|
7349
|
+
}
|
|
7350
|
+
const resolved = await this.resolveImage();
|
|
7351
|
+
if (!resolved.exists) {
|
|
7352
|
+
return {
|
|
7353
|
+
exitCode: 1,
|
|
7354
|
+
stdout: "",
|
|
7355
|
+
stderr: resolved.error ?? `kali image ${this.image} is still missing after pull`,
|
|
7356
|
+
durationMs: Date.now() - started,
|
|
7357
|
+
timedOut: false
|
|
7358
|
+
};
|
|
7359
|
+
}
|
|
7360
|
+
return {
|
|
7361
|
+
exitCode: 0,
|
|
7362
|
+
stdout: pulled.stdout || "image pulled",
|
|
7363
|
+
stderr: "",
|
|
7364
|
+
durationMs: Date.now() - started,
|
|
7365
|
+
timedOut: false
|
|
7366
|
+
};
|
|
7286
7367
|
}
|
|
7287
7368
|
async status() {
|
|
7288
7369
|
const image = await this.resolveImage();
|
|
@@ -7427,18 +7508,13 @@ class KaliContainerBackend {
|
|
|
7427
7508
|
}
|
|
7428
7509
|
async startPersistentBody() {
|
|
7429
7510
|
try {
|
|
7430
|
-
const
|
|
7431
|
-
if (
|
|
7511
|
+
const ensured = await this.ensureImage();
|
|
7512
|
+
if (ensured.exitCode !== 0) {
|
|
7432
7513
|
if (this.identity && this.lifecycle)
|
|
7433
7514
|
this.lifecycle.release(this.identity);
|
|
7434
|
-
return
|
|
7435
|
-
exitCode: 1,
|
|
7436
|
-
stdout: "",
|
|
7437
|
-
stderr: status.dockerError ?? `kali image ${this.image} is missing; run \`farai setup --no-kb\``,
|
|
7438
|
-
durationMs: 0,
|
|
7439
|
-
timedOut: false
|
|
7440
|
-
};
|
|
7515
|
+
return ensured;
|
|
7441
7516
|
}
|
|
7517
|
+
const status = await this.status();
|
|
7442
7518
|
if (status.dockerError) {
|
|
7443
7519
|
if (this.identity && this.lifecycle)
|
|
7444
7520
|
this.lifecycle.release(this.identity);
|
|
@@ -7460,17 +7536,6 @@ class KaliContainerBackend {
|
|
|
7460
7536
|
timedOut: false
|
|
7461
7537
|
};
|
|
7462
7538
|
}
|
|
7463
|
-
if (!status.imageContractCurrent) {
|
|
7464
|
-
if (this.identity && this.lifecycle)
|
|
7465
|
-
this.lifecycle.release(this.identity);
|
|
7466
|
-
return {
|
|
7467
|
-
exitCode: 1,
|
|
7468
|
-
stdout: "",
|
|
7469
|
-
stderr: `kali image ${this.image} does not satisfy the farai kali capability contract; run \`farai setup --no-kb\``,
|
|
7470
|
-
durationMs: 0,
|
|
7471
|
-
timedOut: false
|
|
7472
|
-
};
|
|
7473
|
-
}
|
|
7474
7539
|
if (status.persistentRunning && status.persistentImageCurrent && (!this.identity || status.persistentIdentityCurrent)) {
|
|
7475
7540
|
return {
|
|
7476
7541
|
exitCode: 0,
|
|
@@ -7890,6 +7955,7 @@ function parseImageInspect(raw) {
|
|
|
7890
7955
|
exists: true
|
|
7891
7956
|
};
|
|
7892
7957
|
const contract = image.Config?.Labels?.[KALI_IMAGE_CONTRACT_LABEL];
|
|
7958
|
+
const repoDigest = digestOf((image.RepoDigests ?? []).find((entry) => entry.includes("@sha256:")));
|
|
7893
7959
|
return {
|
|
7894
7960
|
exists: true,
|
|
7895
7961
|
...image.Id ? {
|
|
@@ -7897,6 +7963,9 @@ function parseImageInspect(raw) {
|
|
|
7897
7963
|
} : {},
|
|
7898
7964
|
...contract ? {
|
|
7899
7965
|
contract
|
|
7966
|
+
} : {},
|
|
7967
|
+
...repoDigest ? {
|
|
7968
|
+
repoDigest
|
|
7900
7969
|
} : {}
|
|
7901
7970
|
};
|
|
7902
7971
|
} catch {
|
|
@@ -7905,6 +7974,12 @@ function parseImageInspect(raw) {
|
|
|
7905
7974
|
};
|
|
7906
7975
|
}
|
|
7907
7976
|
}
|
|
7977
|
+
function digestOf(reference) {
|
|
7978
|
+
if (!reference)
|
|
7979
|
+
return;
|
|
7980
|
+
const match = reference.match(/sha256:[a-f0-9]{64}/i);
|
|
7981
|
+
return match ? match[0].toLowerCase() : undefined;
|
|
7982
|
+
}
|
|
7908
7983
|
function dockerFailure(result, fallback) {
|
|
7909
7984
|
const detail = `${result.stderr}
|
|
7910
7985
|
${result.stdout}`.trim().replace(/\s+/g, " ");
|
|
@@ -7928,7 +8003,7 @@ function containerDoesNotExist2(result) {
|
|
|
7928
8003
|
return /no such (container|object)/i.test(`${result.stdout}
|
|
7929
8004
|
${result.stderr}`);
|
|
7930
8005
|
}
|
|
7931
|
-
var CONTAINER_WORKSPACE_MOUNT = "/workspace", CONTAINER_WORKTREES_MOUNT = "/worktrees", kaliSessions, kaliPtySessions, containerStartLocks, globalContainerStartChain, CONTAINER_EXEC_MARKER_DIR = "/tmp/farai-exec", CONTAINER_EXEC_WRAPPER, CONTAINER_EXEC_KILLER, CONTAINER_PREFIX,
|
|
8006
|
+
var CONTAINER_WORKSPACE_MOUNT = "/workspace", CONTAINER_WORKTREES_MOUNT = "/worktrees", kaliSessions, kaliPtySessions, containerStartLocks, globalContainerStartChain, CONTAINER_EXEC_MARKER_DIR = "/tmp/farai-exec", CONTAINER_EXEC_WRAPPER, CONTAINER_EXEC_KILLER, CONTAINER_PREFIX, KALI_IMAGE_REPO = "ghcr.io/pajarori/farai-kali", KALI_IMAGE_TAG = "latest", DEFAULT_KALI_IMAGE, KALI_IMAGE_CONTRACT_LABEL = "org.farai.kali.contract", KALI_IMAGE_PULL_TIMEOUT_MS;
|
|
7932
8007
|
var init_kali = __esm(() => {
|
|
7933
8008
|
init_spawn_session();
|
|
7934
8009
|
init_pty_session();
|
|
@@ -7946,7 +8021,8 @@ var init_kali = __esm(() => {
|
|
|
7946
8021
|
CONTAINER_EXEC_KILLER = ["import os, signal, sys, time", "path = sys.argv[1]", "root = None", "marker_deadline = time.monotonic() + 0.25", "while root is None and time.monotonic() < marker_deadline:", " try:", " with open(path, encoding='ascii') as handle:", " root = int(handle.read().strip())", " except (FileNotFoundError, OSError, ValueError):", " time.sleep(0.01)", "if root is None:", " raise SystemExit(0)", "def direct_children(pid):", " try:", " with open(f'/proc/{pid}/task/{pid}/children', encoding='ascii') as handle:", " return [int(value) for value in handle.read().split()]", " except (FileNotFoundError, OSError, ValueError):", " return []", "def descendants(pid):", " found = []", " pending = direct_children(pid)", " seen = set()", " while pending:", " child = pending.pop()", " if child in seen:", " continue", " seen.add(child)", " found.append(child)", " pending.extend(direct_children(child))", " return found", "def alive(pid):", " try:", " os.kill(pid, 0)", " return True", " except ProcessLookupError:", " return False", " except PermissionError:", " return True", "targets = descendants(root)", "for pid in [*reversed(targets), root]:", " try:", " os.kill(pid, signal.SIGTERM)", " except (ProcessLookupError, PermissionError):", " pass", "deadline = time.monotonic() + 1.0", "while time.monotonic() < deadline and any(alive(pid) for pid in [root, *targets]):", " time.sleep(0.025)", "targets = list(dict.fromkeys([*targets, *descendants(root)]))", "for pid in [*reversed(targets), root]:", " try:", " os.kill(pid, signal.SIGKILL)", " except (ProcessLookupError, PermissionError):", " pass", "try:", " os.unlink(path)", "except FileNotFoundError:", " pass"].join(`
|
|
7947
8022
|
`);
|
|
7948
8023
|
CONTAINER_PREFIX = FARAI_CONTAINER_NAME_PREFIX;
|
|
7949
|
-
|
|
8024
|
+
DEFAULT_KALI_IMAGE = `${KALI_IMAGE_REPO}:${KALI_IMAGE_TAG}`;
|
|
8025
|
+
KALI_IMAGE_PULL_TIMEOUT_MS = 30 * 60 * 1000;
|
|
7950
8026
|
});
|
|
7951
8027
|
|
|
7952
8028
|
// src/agent-tools/shared/backend.ts
|
|
@@ -8698,8 +8774,8 @@ var init_process_output = __esm(() => {
|
|
|
8698
8774
|
|
|
8699
8775
|
// src/version.ts
|
|
8700
8776
|
function resolveFaraiVersion() {
|
|
8701
|
-
if ("0.3.
|
|
8702
|
-
return "0.3.
|
|
8777
|
+
if ("0.3.3")
|
|
8778
|
+
return "0.3.3";
|
|
8703
8779
|
try {
|
|
8704
8780
|
const parsed = JSON.parse(readBoundedFileTextSync(new URL("../package.json", import.meta.url), 1024 * 1024, "package metadata"));
|
|
8705
8781
|
if (typeof parsed.version === "string" && parsed.version)
|
|
@@ -19996,15 +20072,15 @@ var init_add_finding = __esm(() => {
|
|
|
19996
20072
|
},
|
|
19997
20073
|
impact: {
|
|
19998
20074
|
type: "string",
|
|
19999
|
-
description: "security impact demonstrated by the evidence"
|
|
20075
|
+
description: "security impact demonstrated by the evidence. rendered as markdown in the findings tab and reports"
|
|
20000
20076
|
},
|
|
20001
20077
|
reproduction: {
|
|
20002
20078
|
type: "string",
|
|
20003
|
-
description: "minimal reproducible steps and observed result"
|
|
20079
|
+
description: "minimal reproducible steps and observed result. rendered as markdown, so write it well: use an ordered list for steps, fenced code blocks for requests, responses, payloads, and commands, and tables where they clarify"
|
|
20004
20080
|
},
|
|
20005
20081
|
remediation: {
|
|
20006
20082
|
type: "string",
|
|
20007
|
-
description: "specific corrective action"
|
|
20083
|
+
description: "specific corrective action. rendered as markdown in the findings tab and reports"
|
|
20008
20084
|
},
|
|
20009
20085
|
campaignId: {
|
|
20010
20086
|
type: "string",
|
|
@@ -20151,15 +20227,15 @@ var init_update_finding = __esm(() => {
|
|
|
20151
20227
|
},
|
|
20152
20228
|
impact: {
|
|
20153
20229
|
type: "string",
|
|
20154
|
-
description: "updated demonstrated security impact"
|
|
20230
|
+
description: "updated demonstrated security impact. rendered as markdown in the findings tab and reports"
|
|
20155
20231
|
},
|
|
20156
20232
|
reproduction: {
|
|
20157
20233
|
type: "string",
|
|
20158
|
-
description: "updated minimal reproducible steps and observed result"
|
|
20234
|
+
description: "updated minimal reproducible steps and observed result. rendered as markdown, so write it well: use an ordered list for steps, fenced code blocks for requests, responses, payloads, and commands, and tables where they clarify"
|
|
20159
20235
|
},
|
|
20160
20236
|
remediation: {
|
|
20161
20237
|
type: "string",
|
|
20162
|
-
description: "updated specific corrective action"
|
|
20238
|
+
description: "updated specific corrective action. rendered as markdown in the findings tab and reports"
|
|
20163
20239
|
}
|
|
20164
20240
|
},
|
|
20165
20241
|
additionalProperties: false,
|
|
@@ -43713,6 +43789,81 @@ var init_preflight = __esm(() => {
|
|
|
43713
43789
|
init_updater();
|
|
43714
43790
|
});
|
|
43715
43791
|
|
|
43792
|
+
// src/agent-container/preflight.ts
|
|
43793
|
+
var exports_preflight2 = {};
|
|
43794
|
+
__export(exports_preflight2, {
|
|
43795
|
+
runStartupContainerPreflight: () => runStartupContainerPreflight
|
|
43796
|
+
});
|
|
43797
|
+
import { createInterface as createInterface2 } from "readline";
|
|
43798
|
+
async function runStartupContainerPreflight(workspace) {
|
|
43799
|
+
const backend2 = new KaliContainerBackend({
|
|
43800
|
+
workspace
|
|
43801
|
+
});
|
|
43802
|
+
const update = await backend2.checkForImageUpdate().catch(() => {
|
|
43803
|
+
return;
|
|
43804
|
+
});
|
|
43805
|
+
if (!update || update.error)
|
|
43806
|
+
return "continue";
|
|
43807
|
+
if (update.exists && update.upToDate)
|
|
43808
|
+
return "continue";
|
|
43809
|
+
const config = loadConfig(workspace);
|
|
43810
|
+
if (config.updates?.prompt === false || !process.stdin.isTTY || !process.stdout.isTTY)
|
|
43811
|
+
return "continue";
|
|
43812
|
+
const answer = await promptForImagePull(update.exists);
|
|
43813
|
+
if (answer === "cancelled")
|
|
43814
|
+
return "cancelled";
|
|
43815
|
+
if (answer === "later")
|
|
43816
|
+
return "continue";
|
|
43817
|
+
console.log(`pulling ${DEFAULT_KALI_IMAGE}...`);
|
|
43818
|
+
const pulled = await spawnPull();
|
|
43819
|
+
if (pulled !== 0) {
|
|
43820
|
+
console.error("kali image pull failed; farai will retry when the container is first needed");
|
|
43821
|
+
}
|
|
43822
|
+
return "continue";
|
|
43823
|
+
}
|
|
43824
|
+
async function promptForImagePull(exists) {
|
|
43825
|
+
console.log("");
|
|
43826
|
+
console.log(FARAI_BANNER);
|
|
43827
|
+
console.log("");
|
|
43828
|
+
console.log(exists ? "a newer kali container image is available" : "kali container image is not installed");
|
|
43829
|
+
const interfaceHandle = createInterface2({
|
|
43830
|
+
input: process.stdin,
|
|
43831
|
+
output: process.stdout
|
|
43832
|
+
});
|
|
43833
|
+
return await new Promise((resolve10) => {
|
|
43834
|
+
let settled = false;
|
|
43835
|
+
const finish = (value) => {
|
|
43836
|
+
if (settled)
|
|
43837
|
+
return;
|
|
43838
|
+
settled = true;
|
|
43839
|
+
interfaceHandle.close();
|
|
43840
|
+
resolve10(value);
|
|
43841
|
+
};
|
|
43842
|
+
interfaceHandle.once("SIGINT", () => finish("cancelled"));
|
|
43843
|
+
interfaceHandle.question("pull before starting? [enter=yes, n=later] ", (value) => {
|
|
43844
|
+
const normalized = value.trim().toLowerCase();
|
|
43845
|
+
if (normalized === "n" || normalized === "no" || normalized === "later")
|
|
43846
|
+
finish("later");
|
|
43847
|
+
else
|
|
43848
|
+
finish("apply");
|
|
43849
|
+
});
|
|
43850
|
+
});
|
|
43851
|
+
}
|
|
43852
|
+
async function spawnPull() {
|
|
43853
|
+
const proc = Bun.spawn(["docker", "pull", DEFAULT_KALI_IMAGE], {
|
|
43854
|
+
stdout: "inherit",
|
|
43855
|
+
stderr: "inherit",
|
|
43856
|
+
env: faraiDockerEnvironment()
|
|
43857
|
+
});
|
|
43858
|
+
return await proc.exited;
|
|
43859
|
+
}
|
|
43860
|
+
var init_preflight2 = __esm(() => {
|
|
43861
|
+
init_branding();
|
|
43862
|
+
init_config();
|
|
43863
|
+
init_docker_environment();
|
|
43864
|
+
init_kali();
|
|
43865
|
+
});
|
|
43866
|
+
|
|
43716
43867
|
// node_modules/solid-js/dist/solid.js
|
|
43717
43868
|
function getContextId(count2) {
|
|
43718
43869
|
const num2 = String(count2), len = num2.length - 1;
|
|
@@ -65250,8 +65401,8 @@ function FindingsEmpty(props) {
|
|
|
65250
65401
|
}
|
|
65251
65402
|
function findingMarkdown(finding) {
|
|
65252
65403
|
const evidence = finding.evidenceIds.length > 0 ? finding.evidenceIds.map((id2) => `- \`${id2}\``) : ["_no linked evidence._"];
|
|
65253
|
-
const technical = [finding.cvssVector ? `-
|
|
65254
|
-
return ["## impact", "", finding.impact.trim() || "_not recorded._", "", "## reproduction", "", finding.reproduction.trim() || "_not recorded._", "", "##
|
|
65404
|
+
const technical = [finding.cvssVector ? `- CVSS 3.1 : \`${finding.cvssVector}\`` : "", finding.campaignId ? `- campaign : \`${finding.campaignId}\`` : "", finding.hypothesisId ? `- hypothesis: \`${finding.hypothesisId}\`` : "", finding.duplicateOf ? `- duplicate of: \`${finding.duplicateOf}\`` : ""].filter(Boolean);
|
|
65405
|
+
return [...technical.length > 0 ? ["## technical details", "", ...technical, ""] : [], "## impact", "", finding.impact.trim() || "_not recorded._", "", "## reproduction", "", finding.reproduction.trim() || "_not recorded._", "", "## remediation", "", finding.remediation.trim() || "_not recorded._", "", "## evidence", "", ...evidence].join(`
|
|
65255
65406
|
`);
|
|
65256
65407
|
}
|
|
65257
65408
|
function filteredFindings(findings, query) {
|
|
@@ -71890,11 +72041,15 @@ class BenchmarkDockerLifecycle {
|
|
|
71890
72041
|
}
|
|
71891
72042
|
async startUnlocked() {
|
|
71892
72043
|
const processRunner = (command, args2) => this.runner(command, args2);
|
|
71893
|
-
const
|
|
72044
|
+
const provisioner = new KaliContainerBackend({
|
|
71894
72045
|
workspace: this.workspace,
|
|
71895
72046
|
image: DEFAULT_KALI_IMAGE,
|
|
71896
72047
|
processRunner
|
|
71897
|
-
})
|
|
72048
|
+
});
|
|
72049
|
+
const ensured = await provisioner.ensureImage();
|
|
72050
|
+
if (ensured.exitCode !== 0)
|
|
72051
|
+
throw new Error(ensured.stderr || `benchmark agent image is unavailable: ${DEFAULT_KALI_IMAGE}`);
|
|
72052
|
+
const image = await provisioner.resolveImage();
|
|
71898
72053
|
if (!image.exists)
|
|
71899
72054
|
throw new Error(image.error ?? `benchmark agent image is missing: ${DEFAULT_KALI_IMAGE}`);
|
|
71900
72055
|
if (image.error)
|
|
@@ -73204,7 +73359,6 @@ var init_suite = __esm(() => {
|
|
|
73204
73359
|
// src/cli/index.ts
|
|
73205
73360
|
init_runtime();
|
|
73206
73361
|
init_kali();
|
|
73207
|
-
init_docker_environment();
|
|
73208
73362
|
init_model_registry();
|
|
73209
73363
|
init_model_catalog();
|
|
73210
73364
|
init_model_profiles();
|
|
@@ -73254,9 +73408,6 @@ function parseSetupArguments(args) {
|
|
|
73254
73408
|
"api-key-stdin": {
|
|
73255
73409
|
type: "boolean"
|
|
73256
73410
|
},
|
|
73257
|
-
"no-docker": {
|
|
73258
|
-
type: "boolean"
|
|
73259
|
-
},
|
|
73260
73411
|
"no-kb": {
|
|
73261
73412
|
type: "boolean"
|
|
73262
73413
|
},
|
|
@@ -73277,7 +73428,6 @@ function parseSetupArguments(args) {
|
|
|
73277
73428
|
if (!model && (baseUrl || apiKeyEnv || apiKeyStdin))
|
|
73278
73429
|
throw new Error("--base-url and api key options require --model");
|
|
73279
73430
|
return {
|
|
73280
|
-
skipDocker: optionalBoolean(values, "no-docker"),
|
|
73281
73431
|
skipKnowledge: aliasedBoolean(values, "no-kb", "no-knowledge"),
|
|
73282
73432
|
...optionalProperty("model", model),
|
|
73283
73433
|
...optionalProperty("baseUrl", baseUrl),
|
|
@@ -73764,16 +73914,17 @@ async function doctor() {
|
|
|
73764
73914
|
const backend2 = new KaliContainerBackend({
|
|
73765
73915
|
workspace: process.cwd()
|
|
73766
73916
|
});
|
|
73767
|
-
const
|
|
73768
|
-
|
|
73769
|
-
|
|
73770
|
-
|
|
73917
|
+
const update = await backend2.checkForImageUpdate().catch(() => {
|
|
73918
|
+
return;
|
|
73919
|
+
});
|
|
73920
|
+
const status = !update ? "unknown (docker unavailable)" : !update.exists ? "not installed (pulled on first run)" : update.upToDate ? "up to date" : "update available (pulled on first run)";
|
|
73921
|
+
console.log(`kali image: ${backend2.image}`);
|
|
73922
|
+
console.log(`kali image status: ${status}`);
|
|
73771
73923
|
const {
|
|
73772
73924
|
contentStatus: contentStatus2
|
|
73773
73925
|
} = await Promise.resolve().then(() => (init_updater(), exports_updater));
|
|
73774
73926
|
const content = contentStatus2();
|
|
73775
73927
|
console.log(`content: ${content.active?.version ?? "local fallback"}`);
|
|
73776
|
-
console.log(`setup command: farai setup`);
|
|
73777
73928
|
}
|
|
73778
73929
|
async function setup(args2) {
|
|
73779
73930
|
const parsed = parseSetupArguments(args2);
|
|
@@ -73787,17 +73938,7 @@ async function setup(args2) {
|
|
|
73787
73938
|
const addArgs = [parsed.model, ...parsed.baseUrl ? ["--base-url", parsed.baseUrl] : [], ...parsed.apiKeyEnv ? ["--api-key-env", parsed.apiKeyEnv] : [], ...parsed.apiKeyStdin ? ["--api-key-stdin"] : [], "--set-default"];
|
|
73788
73939
|
await addModel(addArgs);
|
|
73789
73940
|
}
|
|
73790
|
-
|
|
73791
|
-
console.log("[*] building Farai Kali image");
|
|
73792
|
-
const code = await buildContainer();
|
|
73793
|
-
if (code !== 0) {
|
|
73794
|
-
process.exitCode = code;
|
|
73795
|
-
console.error("[!] docker image build failed; rerun `farai setup --no-kb` after fixing Docker");
|
|
73796
|
-
return;
|
|
73797
|
-
}
|
|
73798
|
-
} else {
|
|
73799
|
-
console.log("[*] skipping Docker image build");
|
|
73800
|
-
}
|
|
73941
|
+
console.log(`[*] kali image: ${DEFAULT_KALI_IMAGE} (pulled on first run)`);
|
|
73801
73942
|
if (!parsed.skipKnowledge) {
|
|
73802
73943
|
const contentInstalled = await syncContentForSetup(process.cwd());
|
|
73803
73944
|
if (!contentInstalled) {
|
|
@@ -73937,11 +74078,18 @@ async function launchTui(workspace, sessionId) {
|
|
|
73937
74078
|
const {
|
|
73938
74079
|
runStartupContentPreflight: runStartupContentPreflight2
|
|
73939
74080
|
} = await Promise.resolve().then(() => (init_preflight(), exports_preflight));
|
|
74081
|
+
const {
|
|
74082
|
+
runStartupContainerPreflight: runStartupContainerPreflight2
|
|
74083
|
+
} = await Promise.resolve().then(() => (init_preflight2(), exports_preflight2));
|
|
73940
74084
|
const effectiveWorkspace = sessionId ? resolveSessionLocation(sessionId)?.workspace ?? workspace : workspace;
|
|
73941
74085
|
if (await runStartupContentPreflight2(effectiveWorkspace) === "cancelled") {
|
|
73942
74086
|
process.exitCode = 130;
|
|
73943
74087
|
return;
|
|
73944
74088
|
}
|
|
74089
|
+
if (await runStartupContainerPreflight2(effectiveWorkspace) === "cancelled") {
|
|
74090
|
+
process.exitCode = 130;
|
|
74091
|
+
return;
|
|
74092
|
+
}
|
|
73945
74093
|
if (import.meta.path.endsWith(".ts")) {
|
|
73946
74094
|
const sourceTuiPreload = "@opentui/solid/preload";
|
|
73947
74095
|
await import(sourceTuiPreload);
|
|
@@ -74047,20 +74195,6 @@ async function benchmark(args2) {
|
|
|
74047
74195
|
return;
|
|
74048
74196
|
}
|
|
74049
74197
|
}
|
|
74050
|
-
async function buildContainer() {
|
|
74051
|
-
const backend2 = new KaliContainerBackend({
|
|
74052
|
-
workspace: process.cwd()
|
|
74053
|
-
});
|
|
74054
|
-
console.log(backend2.buildImageCommand().join(" "));
|
|
74055
|
-
const proc = Bun.spawn(backend2.buildImageCommand(), {
|
|
74056
|
-
stdout: "inherit",
|
|
74057
|
-
stderr: "inherit",
|
|
74058
|
-
env: faraiDockerEnvironment()
|
|
74059
|
-
});
|
|
74060
|
-
const code = await proc.exited;
|
|
74061
|
-
process.exitCode = code;
|
|
74062
|
-
return code;
|
|
74063
|
-
}
|
|
74064
74198
|
function wantsHelp(args2) {
|
|
74065
74199
|
return args2.includes("--help") || args2.includes("-h") || args2[0] === "help";
|
|
74066
74200
|
}
|
|
@@ -74076,7 +74210,6 @@ Options:
|
|
|
74076
74210
|
--base-url <url> OpenAI-compatible provider URL
|
|
74077
74211
|
--api-key-env <ENV> Environment variable containing the API key
|
|
74078
74212
|
--api-key-stdin Read the API key from stdin
|
|
74079
|
-
--no-docker Skip Farai Kali image build
|
|
74080
74213
|
--no-kb, --no-knowledge Skip knowledge base content sync
|
|
74081
74214
|
|
|
74082
74215
|
Examples:
|
|
@@ -74148,7 +74281,7 @@ Usage:
|
|
|
74148
74281
|
farai
|
|
74149
74282
|
farai resume [session-name-or-id]
|
|
74150
74283
|
farai run <prompt> [--session <id>] [--json]
|
|
74151
|
-
farai setup [--model provider:model] [--base-url url] [--api-key-env ENV | --api-key-stdin] [--no-
|
|
74284
|
+
farai setup [--model provider:model] [--base-url url] [--api-key-env ENV | --api-key-stdin] [--no-kb]
|
|
74152
74285
|
farai init [--target <ip-or-host>] [--name <name>] [--model provider:model]
|
|
74153
74286
|
farai doctor
|
|
74154
74287
|
farai model
|
|
@@ -74170,5 +74303,5 @@ Examples:
|
|
|
74170
74303
|
`);
|
|
74171
74304
|
}
|
|
74172
74305
|
|
|
74173
|
-
//# debugId=
|
|
74306
|
+
//# debugId=11DF5F38873B6FC764756E2164756E21
|
|
74174
74307
|
//# sourceMappingURL=index.js.map
|