blitzstrike 1.0.23 → 1.0.24
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/index.js +539 -58
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -14822,10 +14822,10 @@ var require_src = __commonJS(function(exports, module) {
|
|
|
14822
14822
|
});
|
|
14823
14823
|
|
|
14824
14824
|
// src/sync.ts
|
|
14825
|
-
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readFileSync as
|
|
14826
|
-
import { join as
|
|
14825
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readFileSync as readFileSync11, readdirSync as readdirSync5, statSync as statSync3, rmSync } from "node:fs";
|
|
14826
|
+
import { join as join9 } from "node:path";
|
|
14827
14827
|
import { homedir as homedir4 } from "node:os";
|
|
14828
|
-
import { fileURLToPath as
|
|
14828
|
+
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
14829
14829
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
14830
14830
|
function dirExists(p) {
|
|
14831
14831
|
try {
|
|
@@ -14838,9 +14838,9 @@ function countFiles(dir) {
|
|
|
14838
14838
|
try {
|
|
14839
14839
|
let n = 0;
|
|
14840
14840
|
const walk = (d) => {
|
|
14841
|
-
for (const e of
|
|
14841
|
+
for (const e of readdirSync5(d, { withFileTypes: true })) {
|
|
14842
14842
|
if (e.isDirectory())
|
|
14843
|
-
walk(
|
|
14843
|
+
walk(join9(d, e.name));
|
|
14844
14844
|
else
|
|
14845
14845
|
n++;
|
|
14846
14846
|
}
|
|
@@ -14854,8 +14854,8 @@ function countFiles(dir) {
|
|
|
14854
14854
|
function syncData() {
|
|
14855
14855
|
if (!dirExists(DATA_ROOT2))
|
|
14856
14856
|
mkdirSync3(DATA_ROOT2, { recursive: true });
|
|
14857
|
-
const payloadsPath =
|
|
14858
|
-
const templatesPath =
|
|
14857
|
+
const payloadsPath = join9(DATA_ROOT2, "payloads");
|
|
14858
|
+
const templatesPath = join9(DATA_ROOT2, "templates");
|
|
14859
14859
|
const hasPayloads = dirExists(payloadsPath) && countFiles(payloadsPath) > 0;
|
|
14860
14860
|
const hasTemplates = dirExists(templatesPath) && countFiles(templatesPath) > 0;
|
|
14861
14861
|
if (hasPayloads && hasTemplates) {
|
|
@@ -14865,8 +14865,8 @@ function syncData() {
|
|
|
14865
14865
|
data_root: DATA_ROOT2
|
|
14866
14866
|
};
|
|
14867
14867
|
}
|
|
14868
|
-
const localPayloads =
|
|
14869
|
-
const localTemplates =
|
|
14868
|
+
const localPayloads = join9(ROOT6, "payloads");
|
|
14869
|
+
const localTemplates = join9(ROOT6, "templates");
|
|
14870
14870
|
let payloadsSynced = false;
|
|
14871
14871
|
let templatesSynced = false;
|
|
14872
14872
|
if (!hasPayloads && dirExists(localPayloads)) {
|
|
@@ -14879,7 +14879,7 @@ function syncData() {
|
|
|
14879
14879
|
}
|
|
14880
14880
|
const gitOk = spawnSync3("git", ["--version"]).status === 0;
|
|
14881
14881
|
if (gitOk && (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0 || !dirExists(templatesPath) || countFiles(templatesPath) === 0)) {
|
|
14882
|
-
const tmp =
|
|
14882
|
+
const tmp = join9(DATA_ROOT2, ".tmp-clone");
|
|
14883
14883
|
if (dirExists(tmp))
|
|
14884
14884
|
rmSync(tmp, { recursive: true, force: true });
|
|
14885
14885
|
const r = spawnSync3("git", ["clone", "--depth", "1", "--filter=blob:none", "--sparse", GITHUB_REPO, tmp], { timeout: 120000 });
|
|
@@ -14887,11 +14887,11 @@ function syncData() {
|
|
|
14887
14887
|
const sparse = spawnSync3("git", ["-C", tmp, "sparse-checkout", "set", "payloads", "templates"], { timeout: 120000 });
|
|
14888
14888
|
if (sparse.status === 0) {
|
|
14889
14889
|
if (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0) {
|
|
14890
|
-
copyDir(
|
|
14890
|
+
copyDir(join9(tmp, "payloads"), payloadsPath);
|
|
14891
14891
|
payloadsSynced = true;
|
|
14892
14892
|
}
|
|
14893
14893
|
if (!dirExists(templatesPath) || countFiles(templatesPath) === 0) {
|
|
14894
|
-
copyDir(
|
|
14894
|
+
copyDir(join9(tmp, "templates"), templatesPath);
|
|
14895
14895
|
templatesSynced = true;
|
|
14896
14896
|
}
|
|
14897
14897
|
}
|
|
@@ -14912,19 +14912,19 @@ function copyDir(src, dst) {
|
|
|
14912
14912
|
}
|
|
14913
14913
|
function manualCopy(src, dst) {
|
|
14914
14914
|
mkdirSync3(dst, { recursive: true });
|
|
14915
|
-
for (const e of
|
|
14916
|
-
const s =
|
|
14917
|
-
const d =
|
|
14915
|
+
for (const e of readdirSync5(src, { withFileTypes: true })) {
|
|
14916
|
+
const s = join9(src, e.name);
|
|
14917
|
+
const d = join9(dst, e.name);
|
|
14918
14918
|
if (e.isDirectory())
|
|
14919
14919
|
manualCopy(s, d);
|
|
14920
14920
|
else
|
|
14921
|
-
writeFileSync2(d,
|
|
14921
|
+
writeFileSync2(d, readFileSync11(s));
|
|
14922
14922
|
}
|
|
14923
14923
|
}
|
|
14924
|
-
var
|
|
14924
|
+
var ROOT6, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
|
|
14925
14925
|
var init_sync = __esm(() => {
|
|
14926
|
-
|
|
14927
|
-
DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ??
|
|
14926
|
+
ROOT6 = join9(fileURLToPath7(new URL(".", import.meta.url)), "..");
|
|
14927
|
+
DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join9(homedir4(), ".blitzstrike", "data");
|
|
14928
14928
|
});
|
|
14929
14929
|
|
|
14930
14930
|
// node_modules/zod/v3/helpers/util.js
|
|
@@ -50392,6 +50392,421 @@ function resolveFinding(finding, verdict) {
|
|
|
50392
50392
|
}
|
|
50393
50393
|
}
|
|
50394
50394
|
|
|
50395
|
+
// src/cvss.ts
|
|
50396
|
+
var AV_WEIGHT = { N: 0.85, A: 0.62, L: 0.55, P: 0.2 };
|
|
50397
|
+
var AC_WEIGHT = { L: 0.77, H: 0.44 };
|
|
50398
|
+
var PR_WEIGHT = {
|
|
50399
|
+
U: { N: 0.85, L: 0.62, H: 0.27 },
|
|
50400
|
+
C: { N: 0.85, L: 0.68, H: 0.5 }
|
|
50401
|
+
};
|
|
50402
|
+
var UI_WEIGHT = { N: 0.85, R: 0.62 };
|
|
50403
|
+
var CIA_WEIGHT = { H: 0.56, L: 0.22, N: 0 };
|
|
50404
|
+
function roundup(value) {
|
|
50405
|
+
return Math.ceil(value * 10) / 10;
|
|
50406
|
+
}
|
|
50407
|
+
function cvssBaseScore(input) {
|
|
50408
|
+
const AV = input.AV ?? "N";
|
|
50409
|
+
const AC = input.AC ?? "L";
|
|
50410
|
+
const PR = input.PR ?? "N";
|
|
50411
|
+
const UI = input.UI ?? "N";
|
|
50412
|
+
const S = input.S ?? "U";
|
|
50413
|
+
const C = input.C ?? "N";
|
|
50414
|
+
const I = input.I ?? "N";
|
|
50415
|
+
const A = input.A ?? "N";
|
|
50416
|
+
const iscBase = 1 - (1 - CIA_WEIGHT[C]) * (1 - CIA_WEIGHT[I]) * (1 - CIA_WEIGHT[A]);
|
|
50417
|
+
let impact;
|
|
50418
|
+
if (S === "U") {
|
|
50419
|
+
impact = 6.42 * iscBase;
|
|
50420
|
+
} else {
|
|
50421
|
+
impact = 7.52 * (iscBase - 0.029) - 3.25 * Math.pow(iscBase - 0.02, 15);
|
|
50422
|
+
}
|
|
50423
|
+
const exploitability = 8.22 * AV_WEIGHT[AV] * AC_WEIGHT[AC] * PR_WEIGHT[S][PR] * UI_WEIGHT[UI];
|
|
50424
|
+
if (impact <= 0)
|
|
50425
|
+
return 0;
|
|
50426
|
+
if (S === "U") {
|
|
50427
|
+
return roundup(Math.min(impact + exploitability, 10));
|
|
50428
|
+
}
|
|
50429
|
+
return roundup(Math.min(1.08 * (impact + exploitability), 10));
|
|
50430
|
+
}
|
|
50431
|
+
function cvssVector(input) {
|
|
50432
|
+
const order = [
|
|
50433
|
+
["AV", input.AV ?? "N"],
|
|
50434
|
+
["AC", input.AC ?? "L"],
|
|
50435
|
+
["PR", input.PR ?? "N"],
|
|
50436
|
+
["UI", input.UI ?? "N"],
|
|
50437
|
+
["S", input.S ?? "U"],
|
|
50438
|
+
["C", input.C ?? "N"],
|
|
50439
|
+
["I", input.I ?? "N"],
|
|
50440
|
+
["A", input.A ?? "N"]
|
|
50441
|
+
];
|
|
50442
|
+
return "CVSS:3.1/" + order.map(([k, v]) => `${k}:${v}`).join("/");
|
|
50443
|
+
}
|
|
50444
|
+
function cvssSeverity(score) {
|
|
50445
|
+
if (score === 0)
|
|
50446
|
+
return "none";
|
|
50447
|
+
if (score < 4)
|
|
50448
|
+
return "low";
|
|
50449
|
+
if (score < 7)
|
|
50450
|
+
return "medium";
|
|
50451
|
+
if (score < 9)
|
|
50452
|
+
return "high";
|
|
50453
|
+
return "critical";
|
|
50454
|
+
}
|
|
50455
|
+
function cvssAssess(input) {
|
|
50456
|
+
const score = cvssBaseScore(input);
|
|
50457
|
+
return { score, vector: cvssVector(input), severity: cvssSeverity(score) };
|
|
50458
|
+
}
|
|
50459
|
+
|
|
50460
|
+
// src/dedup.ts
|
|
50461
|
+
function rootCauseSignature(finding) {
|
|
50462
|
+
const sinkType = (finding.sink?.type ?? "unknown").toLowerCase();
|
|
50463
|
+
const sourceType = (finding.source?.type ?? "unknown").toLowerCase();
|
|
50464
|
+
const cwe = (finding.classification?.cwe ?? "").toUpperCase();
|
|
50465
|
+
return [sinkType, sourceType, cwe].filter(Boolean).join("|");
|
|
50466
|
+
}
|
|
50467
|
+
function dedupFindings(findings) {
|
|
50468
|
+
const groups = new Map;
|
|
50469
|
+
for (const f of findings) {
|
|
50470
|
+
const sig = rootCauseSignature(f);
|
|
50471
|
+
const existing = groups.get(sig);
|
|
50472
|
+
if (existing) {
|
|
50473
|
+
existing.count += 1;
|
|
50474
|
+
existing.findings.push(f);
|
|
50475
|
+
} else {
|
|
50476
|
+
groups.set(sig, { signature: sig, count: 1, representative: f, findings: [f] });
|
|
50477
|
+
}
|
|
50478
|
+
}
|
|
50479
|
+
return [...groups.values()];
|
|
50480
|
+
}
|
|
50481
|
+
|
|
50482
|
+
// src/report.ts
|
|
50483
|
+
function summarize(findings) {
|
|
50484
|
+
const byStatus = {};
|
|
50485
|
+
const bySeverity = {};
|
|
50486
|
+
let evidenceArtifacts = 0;
|
|
50487
|
+
for (const f of findings) {
|
|
50488
|
+
byStatus[f.status] = (byStatus[f.status] ?? 0) + 1;
|
|
50489
|
+
const sev = f.classification?.severity ?? "informational";
|
|
50490
|
+
bySeverity[sev] = (bySeverity[sev] ?? 0) + 1;
|
|
50491
|
+
evidenceArtifacts += f.evidence?.reduce((n, e) => n + (e.artifacts?.length ?? 0), 0) ?? 0;
|
|
50492
|
+
}
|
|
50493
|
+
const groups = dedupFindings(findings);
|
|
50494
|
+
return {
|
|
50495
|
+
total_findings: findings.length,
|
|
50496
|
+
unique_root_causes: groups.length,
|
|
50497
|
+
by_status: byStatus,
|
|
50498
|
+
by_severity: bySeverity,
|
|
50499
|
+
confirmed: byStatus["confirmed"] ?? 0,
|
|
50500
|
+
false_positives: byStatus["false_positive"] ?? 0,
|
|
50501
|
+
evidence_artifacts: evidenceArtifacts
|
|
50502
|
+
};
|
|
50503
|
+
}
|
|
50504
|
+
function severityLabel(sev) {
|
|
50505
|
+
const s = sev.toUpperCase();
|
|
50506
|
+
if (s === "CRITICAL")
|
|
50507
|
+
return "\uD83D\uDD34 CRITICAL";
|
|
50508
|
+
if (s === "HIGH")
|
|
50509
|
+
return "\uD83D\uDFE0 HIGH";
|
|
50510
|
+
if (s === "MEDIUM")
|
|
50511
|
+
return "\uD83D\uDFE1 MEDIUM";
|
|
50512
|
+
if (s === "LOW")
|
|
50513
|
+
return "\uD83D\uDD35 LOW";
|
|
50514
|
+
return "⚪ INFORMATIONAL";
|
|
50515
|
+
}
|
|
50516
|
+
function reportMarkdown(findings, opts = {}) {
|
|
50517
|
+
const summary = summarize(findings);
|
|
50518
|
+
const lines = [];
|
|
50519
|
+
lines.push(`# ${opts.title ?? "Blitz Strike — Security Assessment Report"}`);
|
|
50520
|
+
lines.push("");
|
|
50521
|
+
lines.push(`- Scope: ${opts.scope ?? "(unset)"}`);
|
|
50522
|
+
lines.push(`- Blitz Strike version: ${opts.version ?? "unknown"}`);
|
|
50523
|
+
if (opts.include_timestamp)
|
|
50524
|
+
lines.push(`- Generated: ${new Date().toISOString()}`);
|
|
50525
|
+
lines.push("");
|
|
50526
|
+
lines.push("## Summary");
|
|
50527
|
+
lines.push("");
|
|
50528
|
+
lines.push(`| Metric | Value |`);
|
|
50529
|
+
lines.push(`|--------|-------|`);
|
|
50530
|
+
lines.push(`| Total findings | ${summary.total_findings} |`);
|
|
50531
|
+
lines.push(`| Unique root causes | ${summary.unique_root_causes} |`);
|
|
50532
|
+
lines.push(`| Confirmed | ${summary.confirmed} |`);
|
|
50533
|
+
lines.push(`| False positives | ${summary.false_positives} |`);
|
|
50534
|
+
lines.push(`| Evidence artifacts | ${summary.evidence_artifacts} |`);
|
|
50535
|
+
lines.push("");
|
|
50536
|
+
lines.push("### By status");
|
|
50537
|
+
lines.push("");
|
|
50538
|
+
for (const [status, n] of Object.entries(summary.by_status).sort()) {
|
|
50539
|
+
lines.push(`- ${status}: ${n}`);
|
|
50540
|
+
}
|
|
50541
|
+
lines.push("");
|
|
50542
|
+
lines.push("### By severity");
|
|
50543
|
+
lines.push("");
|
|
50544
|
+
for (const [sev, n] of Object.entries(summary.by_severity).sort()) {
|
|
50545
|
+
lines.push(`- ${sev}: ${n}`);
|
|
50546
|
+
}
|
|
50547
|
+
lines.push("");
|
|
50548
|
+
lines.push("## Findings");
|
|
50549
|
+
lines.push("");
|
|
50550
|
+
if (findings.length === 0) {
|
|
50551
|
+
lines.push("_No findings._");
|
|
50552
|
+
return lines.join(`
|
|
50553
|
+
`) + `
|
|
50554
|
+
`;
|
|
50555
|
+
}
|
|
50556
|
+
for (const f of findings) {
|
|
50557
|
+
lines.push(`### ${f.id} — ${f.title} [${severityLabel(f.classification?.severity ?? "informational")}]`);
|
|
50558
|
+
lines.push("");
|
|
50559
|
+
lines.push(`- **Status**: \`${f.status}\``);
|
|
50560
|
+
lines.push(`- **Confidence**: ${f.confidence} (${f.confidence_level})`);
|
|
50561
|
+
if (f.classification?.cwe)
|
|
50562
|
+
lines.push(`- **CWE**: ${f.classification.cwe}`);
|
|
50563
|
+
if (f.classification?.cvss_score != null)
|
|
50564
|
+
lines.push(`- **CVSS**: ${f.classification.cvss_score} (${f.classification.cvss_vector ?? ""}) — ${cvssSeverity(f.classification.cvss_score)}`);
|
|
50565
|
+
lines.push(`- **Source**: ${f.source?.type} \`${f.source?.name ?? ""}\``);
|
|
50566
|
+
lines.push(`- **Sink**: ${f.sink?.type}${f.sink?.symbol ? ` \`${f.sink.symbol}\`` : ""}`);
|
|
50567
|
+
if (f.target?.host || f.target?.endpoint)
|
|
50568
|
+
lines.push(`- **Target**: ${[f.target.host, f.target.endpoint].filter(Boolean).join("")}`);
|
|
50569
|
+
lines.push(`- **Evidence**: ${f.evidence?.length ?? 0} record(s)`);
|
|
50570
|
+
if (f.remediation && Object.keys(f.remediation).length) {
|
|
50571
|
+
lines.push(`- **Note**: ${JSON.stringify(f.remediation)}`);
|
|
50572
|
+
}
|
|
50573
|
+
lines.push("");
|
|
50574
|
+
}
|
|
50575
|
+
return lines.join(`
|
|
50576
|
+
`) + `
|
|
50577
|
+
`;
|
|
50578
|
+
}
|
|
50579
|
+
function reportJson(findings, opts = {}) {
|
|
50580
|
+
const summary = summarize(findings);
|
|
50581
|
+
const payload = {
|
|
50582
|
+
title: opts.title ?? "Blitz Strike — Security Assessment Report",
|
|
50583
|
+
scope: opts.scope ?? null,
|
|
50584
|
+
version: opts.version ?? null,
|
|
50585
|
+
summary,
|
|
50586
|
+
findings,
|
|
50587
|
+
integrity: sha256(JSON.stringify({ summary, findings }))
|
|
50588
|
+
};
|
|
50589
|
+
return JSON.stringify(payload, null, 2);
|
|
50590
|
+
}
|
|
50591
|
+
|
|
50592
|
+
// src/benchmark.ts
|
|
50593
|
+
import { readFileSync as readFileSync9, readdirSync as readdirSync4 } from "node:fs";
|
|
50594
|
+
import { join as join7 } from "node:path";
|
|
50595
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
50596
|
+
var ROOT4 = join7(fileURLToPath5(new URL(".", import.meta.url)), "..");
|
|
50597
|
+
var CORPUS = join7(ROOT4, "bench", "corpus");
|
|
50598
|
+
function parseCorpusFile(path) {
|
|
50599
|
+
let text;
|
|
50600
|
+
try {
|
|
50601
|
+
text = readFileSync9(path, "utf8");
|
|
50602
|
+
} catch {
|
|
50603
|
+
return null;
|
|
50604
|
+
}
|
|
50605
|
+
const lines = text.split(`
|
|
50606
|
+
`);
|
|
50607
|
+
let id = "";
|
|
50608
|
+
let language = "php";
|
|
50609
|
+
let vulnerable = true;
|
|
50610
|
+
let sinkType;
|
|
50611
|
+
let code = "";
|
|
50612
|
+
let inCode = false;
|
|
50613
|
+
let codeLang = "";
|
|
50614
|
+
for (const line of lines) {
|
|
50615
|
+
const m = line.match(/^\s*-\s*(id|language|vulnerable|sink_type)\s*:\s*(.+)$/i);
|
|
50616
|
+
if (!inCode && m) {
|
|
50617
|
+
const key = m[1].toLowerCase();
|
|
50618
|
+
const val = m[2].trim();
|
|
50619
|
+
if (key === "id")
|
|
50620
|
+
id = val;
|
|
50621
|
+
else if (key === "language")
|
|
50622
|
+
language = val.toLowerCase();
|
|
50623
|
+
else if (key === "vulnerable")
|
|
50624
|
+
vulnerable = val === "true";
|
|
50625
|
+
else if (key === "sink_type")
|
|
50626
|
+
sinkType = val;
|
|
50627
|
+
continue;
|
|
50628
|
+
}
|
|
50629
|
+
const start = line.match(/^```(\w*)/);
|
|
50630
|
+
if (start && !inCode) {
|
|
50631
|
+
inCode = true;
|
|
50632
|
+
codeLang = start[1] || "php";
|
|
50633
|
+
continue;
|
|
50634
|
+
}
|
|
50635
|
+
if (inCode && line.trim() === "```")
|
|
50636
|
+
break;
|
|
50637
|
+
if (inCode)
|
|
50638
|
+
code += line + `
|
|
50639
|
+
`;
|
|
50640
|
+
}
|
|
50641
|
+
if (!id)
|
|
50642
|
+
id = path.split("/").pop().replace(/\.md$/, "");
|
|
50643
|
+
return { id, language: language || codeLang || "php", vulnerable, sink_type: sinkType, code: code.trim() };
|
|
50644
|
+
}
|
|
50645
|
+
function loadCorpus() {
|
|
50646
|
+
let entries = [];
|
|
50647
|
+
try {
|
|
50648
|
+
for (const f of readdirSync4(CORPUS)) {
|
|
50649
|
+
if (!f.endsWith(".md"))
|
|
50650
|
+
continue;
|
|
50651
|
+
const e = parseCorpusFile(join7(CORPUS, f));
|
|
50652
|
+
if (e)
|
|
50653
|
+
entries.push(e);
|
|
50654
|
+
}
|
|
50655
|
+
} catch {
|
|
50656
|
+
entries = [];
|
|
50657
|
+
}
|
|
50658
|
+
return entries;
|
|
50659
|
+
}
|
|
50660
|
+
function detect(entry) {
|
|
50661
|
+
const lang = entry.language;
|
|
50662
|
+
if (lang === "php") {
|
|
50663
|
+
const tmp = join7(ROOT4, "bench", ".tmp.php");
|
|
50664
|
+
const { writeFileSync, rmSync } = __require("node:fs");
|
|
50665
|
+
writeFileSync(tmp, entry.code);
|
|
50666
|
+
const r = analyzeTaint(tmp);
|
|
50667
|
+
rmSync(tmp, { force: true });
|
|
50668
|
+
if (r.findings.length > 0)
|
|
50669
|
+
return { detected: true, sinkKind: r.findings[0].sink };
|
|
50670
|
+
return { detected: false };
|
|
50671
|
+
}
|
|
50672
|
+
const ext = { javascript: ".js", typescript: ".ts", python: ".py", java: ".java" }[lang] ?? ".php";
|
|
50673
|
+
const r = analyzeTaintUniversal(entry.code, "bench." + ext);
|
|
50674
|
+
if (r.findings.length > 0)
|
|
50675
|
+
return { detected: true, sinkKind: r.findings[0].sink };
|
|
50676
|
+
return { detected: false };
|
|
50677
|
+
}
|
|
50678
|
+
function runBenchmark() {
|
|
50679
|
+
const entries = loadCorpus();
|
|
50680
|
+
const results = entries.map((entry) => {
|
|
50681
|
+
const { detected, sinkKind } = detect(entry);
|
|
50682
|
+
const outcome = entry.vulnerable ? detected ? "tp" : "fn" : detected ? "fp" : "tn";
|
|
50683
|
+
return { entry, detected, sink_kind: sinkKind, outcome };
|
|
50684
|
+
});
|
|
50685
|
+
const tp = results.filter((r) => r.outcome === "tp").length;
|
|
50686
|
+
const tn = results.filter((r) => r.outcome === "tn").length;
|
|
50687
|
+
const fp = results.filter((r) => r.outcome === "fp").length;
|
|
50688
|
+
const fn = results.filter((r) => r.outcome === "fn").length;
|
|
50689
|
+
const total = results.length;
|
|
50690
|
+
const detectionRate = tp + fn > 0 ? tp / (tp + fn) : 0;
|
|
50691
|
+
const falsePositiveRate = fp + tn > 0 ? fp / (fp + tn) : 0;
|
|
50692
|
+
const precision = tp + fp > 0 ? tp / (tp + fp) : 0;
|
|
50693
|
+
return {
|
|
50694
|
+
total_cases: total,
|
|
50695
|
+
tp,
|
|
50696
|
+
tn,
|
|
50697
|
+
fp,
|
|
50698
|
+
fn,
|
|
50699
|
+
detection_rate: Number(detectionRate.toFixed(3)),
|
|
50700
|
+
false_positive_rate: Number(falsePositiveRate.toFixed(3)),
|
|
50701
|
+
precision: Number(precision.toFixed(3)),
|
|
50702
|
+
results: results.map((r) => ({ id: r.entry.id, language: r.entry.language, outcome: r.outcome, sink: r.sink_kind }))
|
|
50703
|
+
};
|
|
50704
|
+
}
|
|
50705
|
+
|
|
50706
|
+
// src/coverage.ts
|
|
50707
|
+
var SINK_CLASSES = [
|
|
50708
|
+
"sql_execution",
|
|
50709
|
+
"code_execution",
|
|
50710
|
+
"command_execution",
|
|
50711
|
+
"file_operations",
|
|
50712
|
+
"file_inclusion",
|
|
50713
|
+
"deserialization",
|
|
50714
|
+
"http_request",
|
|
50715
|
+
"redirect",
|
|
50716
|
+
"html_render",
|
|
50717
|
+
"xml_processing",
|
|
50718
|
+
"archive_extraction",
|
|
50719
|
+
"path_traversal"
|
|
50720
|
+
];
|
|
50721
|
+
var PHP_SINKS2 = {
|
|
50722
|
+
sql_execution: true,
|
|
50723
|
+
code_execution: true,
|
|
50724
|
+
command_execution: true,
|
|
50725
|
+
file_operations: true,
|
|
50726
|
+
file_inclusion: true,
|
|
50727
|
+
deserialization: true,
|
|
50728
|
+
http_request: true,
|
|
50729
|
+
redirect: true,
|
|
50730
|
+
html_render: true,
|
|
50731
|
+
xml_processing: false,
|
|
50732
|
+
archive_extraction: false,
|
|
50733
|
+
path_traversal: true
|
|
50734
|
+
};
|
|
50735
|
+
var JS_SINKS2 = {
|
|
50736
|
+
sql_execution: true,
|
|
50737
|
+
code_execution: true,
|
|
50738
|
+
command_execution: true,
|
|
50739
|
+
file_operations: true,
|
|
50740
|
+
file_inclusion: true,
|
|
50741
|
+
deserialization: false,
|
|
50742
|
+
http_request: true,
|
|
50743
|
+
redirect: true,
|
|
50744
|
+
html_render: true,
|
|
50745
|
+
xml_processing: false,
|
|
50746
|
+
archive_extraction: false,
|
|
50747
|
+
path_traversal: true
|
|
50748
|
+
};
|
|
50749
|
+
var PY_SINKS2 = {
|
|
50750
|
+
sql_execution: true,
|
|
50751
|
+
code_execution: true,
|
|
50752
|
+
command_execution: true,
|
|
50753
|
+
file_operations: true,
|
|
50754
|
+
file_inclusion: false,
|
|
50755
|
+
deserialization: true,
|
|
50756
|
+
http_request: false,
|
|
50757
|
+
redirect: true,
|
|
50758
|
+
html_render: true,
|
|
50759
|
+
xml_processing: false,
|
|
50760
|
+
archive_extraction: false,
|
|
50761
|
+
path_traversal: true
|
|
50762
|
+
};
|
|
50763
|
+
var JAVA_SINKS2 = {
|
|
50764
|
+
sql_execution: true,
|
|
50765
|
+
code_execution: false,
|
|
50766
|
+
command_execution: true,
|
|
50767
|
+
file_operations: true,
|
|
50768
|
+
file_inclusion: false,
|
|
50769
|
+
deserialization: true,
|
|
50770
|
+
http_request: true,
|
|
50771
|
+
redirect: true,
|
|
50772
|
+
html_render: true,
|
|
50773
|
+
xml_processing: false,
|
|
50774
|
+
archive_extraction: false,
|
|
50775
|
+
path_traversal: true
|
|
50776
|
+
};
|
|
50777
|
+
var SINK_BY_LANG = {
|
|
50778
|
+
php: PHP_SINKS2,
|
|
50779
|
+
javascript: JS_SINKS2,
|
|
50780
|
+
python: PY_SINKS2,
|
|
50781
|
+
java: JAVA_SINKS2
|
|
50782
|
+
};
|
|
50783
|
+
function coverageMatrix() {
|
|
50784
|
+
const langs = listLanguages();
|
|
50785
|
+
const sinkCoverage = SINK_CLASSES.map((sink) => {
|
|
50786
|
+
const covered = langs.map((l) => l.language).filter((lang) => SINK_BY_LANG[lang]?.[sink] === true);
|
|
50787
|
+
return { sink, languages: covered };
|
|
50788
|
+
});
|
|
50789
|
+
let coveredPairs = 0;
|
|
50790
|
+
for (const lang of langs) {
|
|
50791
|
+
for (const sink of SINK_CLASSES) {
|
|
50792
|
+
if (SINK_BY_LANG[lang.language]?.[sink])
|
|
50793
|
+
coveredPairs += 1;
|
|
50794
|
+
}
|
|
50795
|
+
}
|
|
50796
|
+
const totalPairs = langs.length * SINK_CLASSES.length;
|
|
50797
|
+
return {
|
|
50798
|
+
languages: langs,
|
|
50799
|
+
sink_coverage: sinkCoverage,
|
|
50800
|
+
counts: {
|
|
50801
|
+
languages: langs.length,
|
|
50802
|
+
sink_classes: SINK_CLASSES.length,
|
|
50803
|
+
covered_pairs: coveredPairs,
|
|
50804
|
+
total_pairs: totalPairs
|
|
50805
|
+
},
|
|
50806
|
+
coverage_ratio: Number((coveredPairs / totalPairs).toFixed(3))
|
|
50807
|
+
};
|
|
50808
|
+
}
|
|
50809
|
+
|
|
50395
50810
|
// src/server.ts
|
|
50396
50811
|
function createServer() {
|
|
50397
50812
|
const server = new McpServer({
|
|
@@ -51084,6 +51499,72 @@ function createServer() {
|
|
|
51084
51499
|
});
|
|
51085
51500
|
return { content: [{ type: "text", text: JSON.stringify({ ...r, next_steps: guidance }) }] };
|
|
51086
51501
|
});
|
|
51502
|
+
server.registerTool("cvss_score", {
|
|
51503
|
+
title: "Compute CVSS v3.1 base score",
|
|
51504
|
+
description: "CVSS: compute a deterministic CVSS v3.1 base score + vector + severity from metric values (AV/AC/PR/UI/S/C/I/A). Self-computed, not read from NVD.",
|
|
51505
|
+
inputSchema: {
|
|
51506
|
+
AV: string2().optional().describe("Attack Vector: N/A/L/P"),
|
|
51507
|
+
AC: string2().optional().describe("Attack Complexity: L/H"),
|
|
51508
|
+
PR: string2().optional().describe("Privileges Required: N/L/H"),
|
|
51509
|
+
UI: string2().optional().describe("User Interaction: N/R"),
|
|
51510
|
+
S: string2().optional().describe("Scope: U/C"),
|
|
51511
|
+
C: string2().optional().describe("Confidentiality: H/L/N"),
|
|
51512
|
+
I: string2().optional().describe("Integrity: H/L/N"),
|
|
51513
|
+
A: string2().optional().describe("Availability: H/L/N")
|
|
51514
|
+
}
|
|
51515
|
+
}, async (input) => {
|
|
51516
|
+
return { content: [{ type: "text", text: JSON.stringify(cvssAssess(input)) }] };
|
|
51517
|
+
});
|
|
51518
|
+
server.registerTool("dedup_findings", {
|
|
51519
|
+
title: "Deduplicate findings by root cause",
|
|
51520
|
+
description: "FINDINGS: collapse a list of findings that share a root cause (sink type + source type + CWE) into one group per root cause.",
|
|
51521
|
+
inputSchema: {
|
|
51522
|
+
findings: string2().describe("JSON array of Finding objects")
|
|
51523
|
+
}
|
|
51524
|
+
}, async ({ findings }) => {
|
|
51525
|
+
let list;
|
|
51526
|
+
try {
|
|
51527
|
+
list = JSON.parse(findings);
|
|
51528
|
+
} catch {
|
|
51529
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid JSON" }) }] };
|
|
51530
|
+
}
|
|
51531
|
+
const groups = dedupFindings(list);
|
|
51532
|
+
return { content: [{ type: "text", text: JSON.stringify(groups.map((g) => ({ signature: g.signature, count: g.count, representative: g.representative.id }))) }] };
|
|
51533
|
+
});
|
|
51534
|
+
server.registerTool("generate_report", {
|
|
51535
|
+
title: "Generate a reproducible report",
|
|
51536
|
+
description: "REPORT: emit a deterministic markdown (or JSON) report from canonical Findings, with summary + integrity hash. Reproducible: same findings -> byte-identical output.",
|
|
51537
|
+
inputSchema: {
|
|
51538
|
+
findings: string2().describe("JSON array of Finding objects"),
|
|
51539
|
+
format: _enum(["markdown", "json"]).optional().describe("Report format"),
|
|
51540
|
+
title: string2().optional().describe("Report title"),
|
|
51541
|
+
scope: string2().optional().describe("Scope description")
|
|
51542
|
+
}
|
|
51543
|
+
}, async ({ findings, format, title, scope }) => {
|
|
51544
|
+
let list;
|
|
51545
|
+
try {
|
|
51546
|
+
list = JSON.parse(findings);
|
|
51547
|
+
} catch {
|
|
51548
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "invalid JSON" }) }] };
|
|
51549
|
+
}
|
|
51550
|
+
const opts = { title, scope, version: "1.0.23" };
|
|
51551
|
+
const out = (format ?? "markdown") === "json" ? reportJson(list, opts) : reportMarkdown(list, opts);
|
|
51552
|
+
return { content: [{ type: "text", text: out }] };
|
|
51553
|
+
});
|
|
51554
|
+
server.registerTool("run_benchmark", {
|
|
51555
|
+
title: "Run the benchmark suite",
|
|
51556
|
+
description: "BENCHMARK: run the labelled corpus and report detection rate, false-positive rate, and precision. The quality metric, not the tool count.",
|
|
51557
|
+
inputSchema: {}
|
|
51558
|
+
}, async () => {
|
|
51559
|
+
return { content: [{ type: "text", text: JSON.stringify(runBenchmark()) }] };
|
|
51560
|
+
});
|
|
51561
|
+
server.registerTool("coverage_matrix", {
|
|
51562
|
+
title: "Report coverage matrix",
|
|
51563
|
+
description: "BENCHMARK: enumerate language × sink-class coverage (which languages detect which sink types), plus the coverage ratio.",
|
|
51564
|
+
inputSchema: {}
|
|
51565
|
+
}, async () => {
|
|
51566
|
+
return { content: [{ type: "text", text: JSON.stringify(coverageMatrix()) }] };
|
|
51567
|
+
});
|
|
51087
51568
|
return server;
|
|
51088
51569
|
}
|
|
51089
51570
|
async function serve() {
|
|
@@ -51093,12 +51574,12 @@ async function serve() {
|
|
|
51093
51574
|
}
|
|
51094
51575
|
|
|
51095
51576
|
// src/cli.ts
|
|
51096
|
-
import { readFileSync as
|
|
51097
|
-
import { join as
|
|
51577
|
+
import { readFileSync as readFileSync10, existsSync as existsSync5, writeFileSync, mkdirSync as mkdirSync2 } from "node:fs";
|
|
51578
|
+
import { join as join8, dirname } from "node:path";
|
|
51098
51579
|
import { homedir as homedir3 } from "node:os";
|
|
51099
|
-
import { fileURLToPath as
|
|
51580
|
+
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
51100
51581
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
51101
|
-
var
|
|
51582
|
+
var ROOT5 = join8(fileURLToPath6(new URL(".", import.meta.url)), "..");
|
|
51102
51583
|
function which(cmd) {
|
|
51103
51584
|
return spawnSync2(`command -v ${cmd}`, { shell: true }).status === 0;
|
|
51104
51585
|
}
|
|
@@ -51133,7 +51614,7 @@ function runDoctor() {
|
|
|
51133
51614
|
detail: fofa ? "set" : "FOFA_EMAIL/FOFA_KEY not set",
|
|
51134
51615
|
fix: fofa ? undefined : "export FOFA_EMAIL=... && export FOFA_KEY=... (enables fofa_search)"
|
|
51135
51616
|
});
|
|
51136
|
-
const dataOk = existsSync5(
|
|
51617
|
+
const dataOk = existsSync5(join8(ROOT5, "chains.json")) && existsSync5(join8(ROOT5, "tools-catalog.json"));
|
|
51137
51618
|
issues.push({
|
|
51138
51619
|
name: "Data layers (chains + tools-catalog)",
|
|
51139
51620
|
status: dataOk ? "ok" : "fail",
|
|
@@ -51161,21 +51642,21 @@ BlitzStrike — ${verdict}`);
|
|
|
51161
51642
|
function resolveCommand() {
|
|
51162
51643
|
if (which("blitzstrike"))
|
|
51163
51644
|
return { command: "blitzstrike", args: ["serve", "--mcp"] };
|
|
51164
|
-
const src =
|
|
51645
|
+
const src = join8(ROOT5, "src", "index.ts");
|
|
51165
51646
|
if (which("bun") && existsSync5(src))
|
|
51166
51647
|
return { command: "bun", args: ["run", src, "serve", "--mcp"] };
|
|
51167
51648
|
if (which("npx"))
|
|
51168
51649
|
return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
|
|
51169
51650
|
if (which("bunx"))
|
|
51170
51651
|
return { command: "bunx", args: ["blitzstrike", "serve", "--mcp"] };
|
|
51171
|
-
const dist =
|
|
51652
|
+
const dist = join8(ROOT5, "dist", "index.js");
|
|
51172
51653
|
if (existsSync5(dist))
|
|
51173
51654
|
return { command: "bun", args: [dist, "serve", "--mcp"] };
|
|
51174
51655
|
return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
|
|
51175
51656
|
}
|
|
51176
51657
|
function readJson(p) {
|
|
51177
51658
|
try {
|
|
51178
|
-
return JSON.parse(
|
|
51659
|
+
return JSON.parse(readFileSync10(p, "utf8"));
|
|
51179
51660
|
} catch {
|
|
51180
51661
|
return null;
|
|
51181
51662
|
}
|
|
@@ -51208,17 +51689,17 @@ function opencodeWrite(p) {
|
|
|
51208
51689
|
};
|
|
51209
51690
|
}
|
|
51210
51691
|
function copyOpenCodeAgents() {
|
|
51211
|
-
const srcDir =
|
|
51212
|
-
const dstDir =
|
|
51692
|
+
const srcDir = join8(ROOT5, "opencode-agents");
|
|
51693
|
+
const dstDir = join8(homedir3(), ".config", "opencode", "agents");
|
|
51213
51694
|
if (!existsSync5(srcDir))
|
|
51214
51695
|
return;
|
|
51215
51696
|
if (!existsSync5(dstDir))
|
|
51216
51697
|
mkdirSync2(dstDir, { recursive: true });
|
|
51217
51698
|
for (const f of ["Blitz Strike.md", "Blitz.md", "Eagle Eye.md", "Strike.md"]) {
|
|
51218
|
-
const src =
|
|
51219
|
-
const dst =
|
|
51699
|
+
const src = join8(srcDir, f);
|
|
51700
|
+
const dst = join8(dstDir, f);
|
|
51220
51701
|
if (existsSync5(src)) {
|
|
51221
|
-
writeFileSync(dst,
|
|
51702
|
+
writeFileSync(dst, readFileSync10(src, "utf8"));
|
|
51222
51703
|
}
|
|
51223
51704
|
}
|
|
51224
51705
|
}
|
|
@@ -51227,7 +51708,7 @@ function codexWrite(p) {
|
|
|
51227
51708
|
const dir = dirname(p);
|
|
51228
51709
|
if (!existsSync5(dir))
|
|
51229
51710
|
mkdirSync2(dir, { recursive: true });
|
|
51230
|
-
let existing = existsSync5(p) ?
|
|
51711
|
+
let existing = existsSync5(p) ? readFileSync10(p, "utf8") : "";
|
|
51231
51712
|
if (!existing.trimEnd().endsWith(`
|
|
51232
51713
|
`))
|
|
51233
51714
|
existing += `
|
|
@@ -51246,7 +51727,7 @@ function hermesWrite(p) {
|
|
|
51246
51727
|
const dir = dirname(p);
|
|
51247
51728
|
if (!existsSync5(dir))
|
|
51248
51729
|
mkdirSync2(dir, { recursive: true });
|
|
51249
|
-
let existing = existsSync5(p) ?
|
|
51730
|
+
let existing = existsSync5(p) ? readFileSync10(p, "utf8") : "";
|
|
51250
51731
|
existing = existing.replace(/^ blitzstrike:\n(?: .*\n?)*/m, "");
|
|
51251
51732
|
if (!existing.trimEnd().endsWith(`
|
|
51252
51733
|
`))
|
|
@@ -51273,74 +51754,74 @@ mcp_servers:
|
|
|
51273
51754
|
function detectAgents() {
|
|
51274
51755
|
const home = homedir3();
|
|
51275
51756
|
const agents = [];
|
|
51276
|
-
const claudeJson =
|
|
51757
|
+
const claudeJson = join8(home, ".claude.json");
|
|
51277
51758
|
agents.push({
|
|
51278
51759
|
name: "Claude Code",
|
|
51279
51760
|
detectPath: claudeJson,
|
|
51280
51761
|
installed: () => existsSync5(claudeJson) || which("claude"),
|
|
51281
51762
|
write: jsonMcpServersWrite(claudeJson)
|
|
51282
51763
|
});
|
|
51283
|
-
const claudeDesktop =
|
|
51764
|
+
const claudeDesktop = join8(home, ".config", "Claude", "claude_desktop_config.json");
|
|
51284
51765
|
agents.push({
|
|
51285
51766
|
name: "Claude Desktop",
|
|
51286
51767
|
detectPath: claudeDesktop,
|
|
51287
51768
|
installed: () => existsSync5(claudeDesktop),
|
|
51288
51769
|
write: jsonMcpServersWrite(claudeDesktop)
|
|
51289
51770
|
});
|
|
51290
|
-
const cursor =
|
|
51771
|
+
const cursor = join8(home, ".cursor", "mcp.json");
|
|
51291
51772
|
agents.push({
|
|
51292
51773
|
name: "Cursor",
|
|
51293
51774
|
detectPath: cursor,
|
|
51294
|
-
installed: () => existsSync5(
|
|
51775
|
+
installed: () => existsSync5(join8(home, ".cursor")) || which("cursor"),
|
|
51295
51776
|
write: jsonMcpServersWrite(cursor)
|
|
51296
51777
|
});
|
|
51297
|
-
const opencode =
|
|
51778
|
+
const opencode = join8(home, ".config", "opencode", "opencode.jsonc");
|
|
51298
51779
|
agents.push({
|
|
51299
51780
|
name: "OpenCode",
|
|
51300
51781
|
detectPath: opencode,
|
|
51301
|
-
installed: () => existsSync5(
|
|
51782
|
+
installed: () => existsSync5(join8(home, ".config", "opencode")) || which("opencode"),
|
|
51302
51783
|
write: opencodeWrite(opencode)
|
|
51303
51784
|
});
|
|
51304
|
-
const codex =
|
|
51785
|
+
const codex = join8(home, ".codex", "config.toml");
|
|
51305
51786
|
agents.push({
|
|
51306
51787
|
name: "Codex",
|
|
51307
51788
|
detectPath: codex,
|
|
51308
|
-
installed: () => existsSync5(
|
|
51789
|
+
installed: () => existsSync5(join8(home, ".codex")) || which("codex"),
|
|
51309
51790
|
write: codexWrite(codex)
|
|
51310
51791
|
});
|
|
51311
|
-
const hermes =
|
|
51792
|
+
const hermes = join8(home, ".hermes", "config.yaml");
|
|
51312
51793
|
agents.push({
|
|
51313
51794
|
name: "Hermes",
|
|
51314
51795
|
detectPath: hermes,
|
|
51315
|
-
installed: () => existsSync5(
|
|
51796
|
+
installed: () => existsSync5(join8(home, ".hermes")) || which("hermes"),
|
|
51316
51797
|
write: hermesWrite(hermes)
|
|
51317
51798
|
});
|
|
51318
|
-
const gemini =
|
|
51799
|
+
const gemini = join8(home, ".gemini", "settings.json");
|
|
51319
51800
|
agents.push({
|
|
51320
51801
|
name: "Gemini CLI",
|
|
51321
51802
|
detectPath: gemini,
|
|
51322
|
-
installed: () => existsSync5(
|
|
51803
|
+
installed: () => existsSync5(join8(home, ".gemini")) || which("gemini"),
|
|
51323
51804
|
write: jsonMcpServersWrite(gemini)
|
|
51324
51805
|
});
|
|
51325
|
-
const windsurf =
|
|
51806
|
+
const windsurf = join8(home, ".codeium", "windsurf", "mcp_config.json");
|
|
51326
51807
|
agents.push({
|
|
51327
51808
|
name: "Windsurf",
|
|
51328
51809
|
detectPath: windsurf,
|
|
51329
|
-
installed: () => existsSync5(
|
|
51810
|
+
installed: () => existsSync5(join8(home, ".codeium")) || which("windsurf"),
|
|
51330
51811
|
write: jsonMcpServersWrite(windsurf)
|
|
51331
51812
|
});
|
|
51332
|
-
const copilot =
|
|
51813
|
+
const copilot = join8(home, ".copilot", "mcp.json");
|
|
51333
51814
|
agents.push({
|
|
51334
51815
|
name: "Copilot",
|
|
51335
51816
|
detectPath: copilot,
|
|
51336
|
-
installed: () => existsSync5(
|
|
51817
|
+
installed: () => existsSync5(join8(home, ".copilot")),
|
|
51337
51818
|
write: jsonMcpServersWrite(copilot)
|
|
51338
51819
|
});
|
|
51339
|
-
const cline =
|
|
51820
|
+
const cline = join8(home, ".cline", "mcp_settings.json");
|
|
51340
51821
|
agents.push({
|
|
51341
51822
|
name: "Cline",
|
|
51342
51823
|
detectPath: cline,
|
|
51343
|
-
installed: () => existsSync5(
|
|
51824
|
+
installed: () => existsSync5(join8(home, ".cline")),
|
|
51344
51825
|
write: jsonMcpServersWrite(cline)
|
|
51345
51826
|
});
|
|
51346
51827
|
return agents;
|
|
@@ -51384,15 +51865,15 @@ Registered with ${ok}/${installed.length} agent(s).`);
|
|
|
51384
51865
|
}
|
|
51385
51866
|
|
|
51386
51867
|
// src/index.ts
|
|
51387
|
-
import { readFileSync as
|
|
51388
|
-
import { join as
|
|
51389
|
-
import { fileURLToPath as
|
|
51390
|
-
var
|
|
51868
|
+
import { readFileSync as readFileSync12, existsSync as existsSync6 } from "node:fs";
|
|
51869
|
+
import { join as join10 } from "node:path";
|
|
51870
|
+
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
51871
|
+
var ROOT7 = join10(fileURLToPath8(new URL(".", import.meta.url)), "..");
|
|
51391
51872
|
function readVersion() {
|
|
51392
51873
|
try {
|
|
51393
|
-
const p =
|
|
51874
|
+
const p = join10(ROOT7, "package.json");
|
|
51394
51875
|
if (existsSync6(p))
|
|
51395
|
-
return JSON.parse(
|
|
51876
|
+
return JSON.parse(readFileSync12(p, "utf8")).version ?? "1.0.0";
|
|
51396
51877
|
} catch {}
|
|
51397
51878
|
return "1.0.0";
|
|
51398
51879
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blitzstrike",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.24",
|
|
4
4
|
"description": "Blitz Strike — a universal MCP security-audit toolbelt. BLITZ sweeps the attack surface, EAGLE-EYE traces source-to-sink, STRIKE verifies live. 57 attack chains, 130-tool catalog, intelligence data layer. One server, every agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,8 +29,9 @@
|
|
|
29
29
|
"serve": "bun run src/index.ts serve",
|
|
30
30
|
"doctor": "bun run src/index.ts doctor",
|
|
31
31
|
"compile": "bun build src/index.ts --compile --outfile dist/blitzstrike",
|
|
32
|
-
"test": "bun test",
|
|
33
|
-
"prepublishOnly": "bun run typecheck && bun run build"
|
|
32
|
+
"test": "bun run test/verify.ts",
|
|
33
|
+
"prepublishOnly": "bun run typecheck && bun run build",
|
|
34
|
+
"bench": "bun run test/verify.ts"
|
|
34
35
|
},
|
|
35
36
|
"keywords": [
|
|
36
37
|
"mcp",
|