claude-crap 0.3.0 → 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/CHANGELOG.md +45 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +8 -3
- package/dist/dashboard/server.js.map +1 -1
- package/dist/scanner/auto-scan.d.ts.map +1 -1
- package/dist/scanner/auto-scan.js +36 -0
- package/dist/scanner/auto-scan.js.map +1 -1
- package/dist/scanner/bootstrap.d.ts +1 -1
- package/dist/scanner/bootstrap.d.ts.map +1 -1
- package/dist/scanner/bootstrap.js +111 -26
- package/dist/scanner/bootstrap.js.map +1 -1
- package/dist/scanner/runner.d.ts.map +1 -1
- package/dist/scanner/runner.js +7 -2
- package/dist/scanner/runner.js.map +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/bundle/mcp-server.mjs +259 -138
- package/plugin/bundle/mcp-server.mjs.map +4 -4
- package/plugin/package.json +1 -1
- package/src/dashboard/server.ts +8 -3
- package/src/scanner/auto-scan.ts +43 -0
- package/src/scanner/bootstrap.ts +123 -28
- package/src/scanner/runner.ts +8 -2
|
@@ -7414,16 +7414,18 @@ async function startDashboard(options) {
|
|
|
7414
7414
|
});
|
|
7415
7415
|
await fastify.register(fastifyStatic, {
|
|
7416
7416
|
root: publicRoot,
|
|
7417
|
-
prefix: "/"
|
|
7418
|
-
decorateReply: false
|
|
7417
|
+
prefix: "/"
|
|
7419
7418
|
});
|
|
7420
|
-
fastify.get("/api/health", async () => ({ status: "ok", server: "claude-crap", version: "0.
|
|
7419
|
+
fastify.get("/api/health", async () => ({ status: "ok", server: "claude-crap", version: "0.3.2" }));
|
|
7421
7420
|
fastify.get("/api/score", async () => {
|
|
7422
7421
|
const stats = await workspaceStatsProvider();
|
|
7423
7422
|
const score = await buildScore(config, sarifStore, stats, urlOf(fastify, config));
|
|
7424
7423
|
return score;
|
|
7425
7424
|
});
|
|
7426
7425
|
fastify.get("/api/sarif", async () => sarifStore.toSarifDocument());
|
|
7426
|
+
fastify.get("/", async (_request, reply) => {
|
|
7427
|
+
return reply.sendFile("index.html");
|
|
7428
|
+
});
|
|
7427
7429
|
await fastify.listen({ port: config.dashboardPort, host: "127.0.0.1" });
|
|
7428
7430
|
const url = `http://127.0.0.1:${config.dashboardPort}`;
|
|
7429
7431
|
logger2.info({ url, publicRoot }, "claude-crap dashboard listening");
|
|
@@ -8083,6 +8085,10 @@ function resolveWithinWorkspace(workspaceRoot, filePath) {
|
|
|
8083
8085
|
return candidate;
|
|
8084
8086
|
}
|
|
8085
8087
|
|
|
8088
|
+
// src/scanner/auto-scan.ts
|
|
8089
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
8090
|
+
import { join as join9 } from "node:path";
|
|
8091
|
+
|
|
8086
8092
|
// src/scanner/detector.ts
|
|
8087
8093
|
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
8088
8094
|
import { join as join6 } from "node:path";
|
|
@@ -8264,7 +8270,8 @@ function runScanner(scanner, workspaceRoot) {
|
|
|
8264
8270
|
},
|
|
8265
8271
|
(err, stdout, stderr) => {
|
|
8266
8272
|
const durationMs = Date.now() - start;
|
|
8267
|
-
|
|
8273
|
+
const isFatalError = cmd.nonZeroIsNormal && err && (!stdout?.trim() || stderr?.includes("Oops!") || stderr?.includes("couldn't find"));
|
|
8274
|
+
if (err && (!cmd.nonZeroIsNormal || isFatalError)) {
|
|
8268
8275
|
if (cmd.outputFile && existsSync2(cmd.outputFile)) {
|
|
8269
8276
|
try {
|
|
8270
8277
|
const fileOutput = readFileSync3(cmd.outputFile, "utf-8");
|
|
@@ -8340,120 +8347,6 @@ function runScanner(scanner, workspaceRoot) {
|
|
|
8340
8347
|
});
|
|
8341
8348
|
}
|
|
8342
8349
|
|
|
8343
|
-
// src/scanner/auto-scan.ts
|
|
8344
|
-
function ingestScannerRun(scanner, rawOutput, sarifStore) {
|
|
8345
|
-
let parsed;
|
|
8346
|
-
try {
|
|
8347
|
-
parsed = JSON.parse(rawOutput);
|
|
8348
|
-
} catch {
|
|
8349
|
-
parsed = rawOutput;
|
|
8350
|
-
}
|
|
8351
|
-
const adapted = adaptScannerOutput(scanner, parsed);
|
|
8352
|
-
const stats = sarifStore.ingestRun(adapted.document, adapted.sourceTool);
|
|
8353
|
-
return { accepted: stats.accepted };
|
|
8354
|
-
}
|
|
8355
|
-
async function autoScan(workspaceRoot, sarifStore, logger2) {
|
|
8356
|
-
const start = Date.now();
|
|
8357
|
-
const detected = await detectScanners(workspaceRoot);
|
|
8358
|
-
const available = detected.filter((d) => d.available);
|
|
8359
|
-
logger2.info(
|
|
8360
|
-
{
|
|
8361
|
-
detected: detected.map((d) => `${d.scanner}:${d.available}`),
|
|
8362
|
-
available: available.length
|
|
8363
|
-
},
|
|
8364
|
-
"auto-scan: detection complete"
|
|
8365
|
-
);
|
|
8366
|
-
if (available.length === 0) {
|
|
8367
|
-
return {
|
|
8368
|
-
detected,
|
|
8369
|
-
results: [],
|
|
8370
|
-
totalFindings: 0,
|
|
8371
|
-
totalDurationMs: Date.now() - start
|
|
8372
|
-
};
|
|
8373
|
-
}
|
|
8374
|
-
const runResults = await Promise.allSettled(
|
|
8375
|
-
available.map((d) => runScanner(d.scanner, workspaceRoot))
|
|
8376
|
-
);
|
|
8377
|
-
const results = [];
|
|
8378
|
-
let totalFindings = 0;
|
|
8379
|
-
let persistNeeded = false;
|
|
8380
|
-
for (let i = 0; i < available.length; i++) {
|
|
8381
|
-
const detection = available[i];
|
|
8382
|
-
const settled = runResults[i];
|
|
8383
|
-
if (settled.status === "rejected") {
|
|
8384
|
-
const error = String(settled.reason);
|
|
8385
|
-
logger2.warn(
|
|
8386
|
-
{ scanner: detection.scanner, error },
|
|
8387
|
-
"auto-scan: scanner execution rejected"
|
|
8388
|
-
);
|
|
8389
|
-
results.push({
|
|
8390
|
-
scanner: detection.scanner,
|
|
8391
|
-
success: false,
|
|
8392
|
-
findingsIngested: 0,
|
|
8393
|
-
durationMs: 0,
|
|
8394
|
-
error
|
|
8395
|
-
});
|
|
8396
|
-
continue;
|
|
8397
|
-
}
|
|
8398
|
-
const runResult = settled.value;
|
|
8399
|
-
if (!runResult.success) {
|
|
8400
|
-
logger2.warn(
|
|
8401
|
-
{ scanner: runResult.scanner, error: runResult.error },
|
|
8402
|
-
"auto-scan: scanner returned failure"
|
|
8403
|
-
);
|
|
8404
|
-
results.push({
|
|
8405
|
-
scanner: runResult.scanner,
|
|
8406
|
-
success: false,
|
|
8407
|
-
findingsIngested: 0,
|
|
8408
|
-
durationMs: runResult.durationMs,
|
|
8409
|
-
error: runResult.error ?? "unknown error"
|
|
8410
|
-
});
|
|
8411
|
-
continue;
|
|
8412
|
-
}
|
|
8413
|
-
try {
|
|
8414
|
-
const { accepted } = ingestScannerRun(
|
|
8415
|
-
runResult.scanner,
|
|
8416
|
-
runResult.rawOutput,
|
|
8417
|
-
sarifStore
|
|
8418
|
-
);
|
|
8419
|
-
totalFindings += accepted;
|
|
8420
|
-
persistNeeded = true;
|
|
8421
|
-
logger2.info(
|
|
8422
|
-
{ scanner: runResult.scanner, accepted, durationMs: runResult.durationMs },
|
|
8423
|
-
"auto-scan: scanner ingested"
|
|
8424
|
-
);
|
|
8425
|
-
results.push({
|
|
8426
|
-
scanner: runResult.scanner,
|
|
8427
|
-
success: true,
|
|
8428
|
-
findingsIngested: accepted,
|
|
8429
|
-
durationMs: runResult.durationMs
|
|
8430
|
-
});
|
|
8431
|
-
} catch (err) {
|
|
8432
|
-
const error = err.message;
|
|
8433
|
-
logger2.warn(
|
|
8434
|
-
{ scanner: runResult.scanner, error },
|
|
8435
|
-
"auto-scan: adapter/ingestion failed"
|
|
8436
|
-
);
|
|
8437
|
-
results.push({
|
|
8438
|
-
scanner: runResult.scanner,
|
|
8439
|
-
success: false,
|
|
8440
|
-
findingsIngested: 0,
|
|
8441
|
-
durationMs: runResult.durationMs,
|
|
8442
|
-
error
|
|
8443
|
-
});
|
|
8444
|
-
}
|
|
8445
|
-
}
|
|
8446
|
-
if (persistNeeded) {
|
|
8447
|
-
await sarifStore.persist();
|
|
8448
|
-
}
|
|
8449
|
-
return {
|
|
8450
|
-
detected,
|
|
8451
|
-
results,
|
|
8452
|
-
totalFindings,
|
|
8453
|
-
totalDurationMs: Date.now() - start
|
|
8454
|
-
};
|
|
8455
|
-
}
|
|
8456
|
-
|
|
8457
8350
|
// src/scanner/bootstrap.ts
|
|
8458
8351
|
import { existsSync as existsSync3, writeFileSync, readdirSync } from "node:fs";
|
|
8459
8352
|
import { join as join8 } from "node:path";
|
|
@@ -8489,7 +8382,14 @@ export default tseslint.config(
|
|
|
8489
8382
|
js.configs.recommended,
|
|
8490
8383
|
...tseslint.configs.recommended,
|
|
8491
8384
|
{
|
|
8492
|
-
ignores: [
|
|
8385
|
+
ignores: [
|
|
8386
|
+
"dist/",
|
|
8387
|
+
"node_modules/",
|
|
8388
|
+
"coverage/",
|
|
8389
|
+
"**/bundle/",
|
|
8390
|
+
"**/vendor/",
|
|
8391
|
+
"**/*.min.js",
|
|
8392
|
+
],
|
|
8493
8393
|
},
|
|
8494
8394
|
);
|
|
8495
8395
|
`;
|
|
@@ -8499,7 +8399,14 @@ export default tseslint.config(
|
|
|
8499
8399
|
export default [
|
|
8500
8400
|
js.configs.recommended,
|
|
8501
8401
|
{
|
|
8502
|
-
ignores: [
|
|
8402
|
+
ignores: [
|
|
8403
|
+
"dist/",
|
|
8404
|
+
"node_modules/",
|
|
8405
|
+
"coverage/",
|
|
8406
|
+
"**/bundle/",
|
|
8407
|
+
"**/vendor/",
|
|
8408
|
+
"**/*.min.js",
|
|
8409
|
+
],
|
|
8503
8410
|
},
|
|
8504
8411
|
];
|
|
8505
8412
|
`;
|
|
@@ -8589,7 +8496,8 @@ function getRecommendation(projectType) {
|
|
|
8589
8496
|
async function bootstrapScanner(workspaceRoot, sarifStore, logger2) {
|
|
8590
8497
|
const detections = await detectScanners(workspaceRoot);
|
|
8591
8498
|
const available = detections.filter((d) => d.available);
|
|
8592
|
-
|
|
8499
|
+
const eslintNeedsConfig = available.some((d) => d.scanner === "eslint") && !detections.some((d) => d.scanner === "eslint" && d.configPath);
|
|
8500
|
+
if (available.length > 0 && !eslintNeedsConfig) {
|
|
8593
8501
|
const existingScanners = available.map((d) => d.scanner);
|
|
8594
8502
|
logger2.info(
|
|
8595
8503
|
{ existingScanners },
|
|
@@ -8614,13 +8522,23 @@ async function bootstrapScanner(workspaceRoot, sarifStore, logger2) {
|
|
|
8614
8522
|
);
|
|
8615
8523
|
if (recommendation.canAutoInstall) {
|
|
8616
8524
|
const isTypeScript = projectType === "typescript";
|
|
8617
|
-
const
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8525
|
+
const eslintAlreadyInstalled = available.some((d) => d.scanner === "eslint");
|
|
8526
|
+
if (!eslintAlreadyInstalled) {
|
|
8527
|
+
const packages = isTypeScript ? ["eslint", "@eslint/js", "typescript-eslint"] : ["eslint", "@eslint/js"];
|
|
8528
|
+
const installStep = await npmInstall(workspaceRoot, packages);
|
|
8529
|
+
steps.push(installStep);
|
|
8530
|
+
if (!installStep.success) {
|
|
8531
|
+
return buildResult(projectType, steps, null);
|
|
8532
|
+
}
|
|
8533
|
+
} else {
|
|
8534
|
+
steps.push({
|
|
8535
|
+
action: "npm install eslint",
|
|
8536
|
+
success: true,
|
|
8537
|
+
detail: "eslint already in package.json \u2014 skipped install"
|
|
8538
|
+
});
|
|
8623
8539
|
}
|
|
8540
|
+
const configStep = writeEslintConfigFile(workspaceRoot, isTypeScript);
|
|
8541
|
+
steps.push(configStep);
|
|
8624
8542
|
} else {
|
|
8625
8543
|
steps.push({
|
|
8626
8544
|
action: `suggest ${recommendation.scanner} install`,
|
|
@@ -8632,25 +8550,73 @@ async function bootstrapScanner(workspaceRoot, sarifStore, logger2) {
|
|
|
8632
8550
|
let autoScanResult = null;
|
|
8633
8551
|
if (installSucceeded && recommendation.canAutoInstall) {
|
|
8634
8552
|
try {
|
|
8635
|
-
|
|
8553
|
+
const scanStart = Date.now();
|
|
8554
|
+
const postDetections = await detectScanners(workspaceRoot);
|
|
8555
|
+
const postAvailable = postDetections.filter((d) => d.available);
|
|
8556
|
+
const scanResults = [];
|
|
8557
|
+
let scanFindings = 0;
|
|
8558
|
+
const settled = await Promise.allSettled(
|
|
8559
|
+
postAvailable.map((d) => runScanner(d.scanner, workspaceRoot))
|
|
8560
|
+
);
|
|
8561
|
+
for (let i = 0; i < postAvailable.length; i++) {
|
|
8562
|
+
const det = postAvailable[i];
|
|
8563
|
+
const res = settled[i];
|
|
8564
|
+
if (res.status === "rejected" || !res.value.success) {
|
|
8565
|
+
scanResults.push({
|
|
8566
|
+
scanner: det.scanner,
|
|
8567
|
+
success: false,
|
|
8568
|
+
findingsIngested: 0,
|
|
8569
|
+
durationMs: res.status === "fulfilled" ? res.value.durationMs : 0,
|
|
8570
|
+
error: res.status === "rejected" ? String(res.reason) : res.value.error ?? "unknown error"
|
|
8571
|
+
});
|
|
8572
|
+
continue;
|
|
8573
|
+
}
|
|
8574
|
+
const runResult = res.value;
|
|
8575
|
+
let parsed;
|
|
8576
|
+
try {
|
|
8577
|
+
parsed = JSON.parse(runResult.rawOutput);
|
|
8578
|
+
} catch {
|
|
8579
|
+
parsed = runResult.rawOutput;
|
|
8580
|
+
}
|
|
8581
|
+
const adapted = adaptScannerOutput(runResult.scanner, parsed);
|
|
8582
|
+
const stats = sarifStore.ingestRun(adapted.document, adapted.sourceTool);
|
|
8583
|
+
scanFindings += stats.accepted;
|
|
8584
|
+
scanResults.push({
|
|
8585
|
+
scanner: runResult.scanner,
|
|
8586
|
+
success: true,
|
|
8587
|
+
findingsIngested: stats.accepted,
|
|
8588
|
+
durationMs: runResult.durationMs
|
|
8589
|
+
});
|
|
8590
|
+
}
|
|
8591
|
+
if (scanFindings > 0) await sarifStore.persist();
|
|
8592
|
+
autoScanResult = {
|
|
8593
|
+
detected: postDetections,
|
|
8594
|
+
results: scanResults,
|
|
8595
|
+
totalFindings: scanFindings,
|
|
8596
|
+
totalDurationMs: Date.now() - scanStart
|
|
8597
|
+
};
|
|
8636
8598
|
} catch (err) {
|
|
8637
8599
|
logger2.warn(
|
|
8638
8600
|
{ err: err.message },
|
|
8639
|
-
"bootstrap:
|
|
8601
|
+
"bootstrap: scan after install failed"
|
|
8640
8602
|
);
|
|
8641
8603
|
}
|
|
8642
8604
|
}
|
|
8605
|
+
return buildResult(projectType, steps, autoScanResult, recommendation);
|
|
8606
|
+
}
|
|
8607
|
+
function buildResult(projectType, steps, autoScanResult, recommendation) {
|
|
8608
|
+
const success = steps.every((s) => s.success);
|
|
8643
8609
|
const findings = autoScanResult?.totalFindings ?? 0;
|
|
8644
|
-
const
|
|
8610
|
+
const scanner = recommendation?.scanner ?? "unknown";
|
|
8645
8611
|
let summary;
|
|
8646
|
-
if (
|
|
8647
|
-
summary = `
|
|
8648
|
-
} else if (
|
|
8649
|
-
summary = `
|
|
8650
|
-
} else if (
|
|
8651
|
-
summary = `
|
|
8612
|
+
if (success && autoScanResult) {
|
|
8613
|
+
summary = `Configured ${scanner} for ${projectType} project. Scan found ${findings} finding(s).`;
|
|
8614
|
+
} else if (success && recommendation && !recommendation.canAutoInstall) {
|
|
8615
|
+
summary = `Detected ${projectType} project. Install ${scanner} manually: ${recommendation.installInstructions}`;
|
|
8616
|
+
} else if (success) {
|
|
8617
|
+
summary = `Configured ${scanner} for ${projectType} project.`;
|
|
8652
8618
|
} else {
|
|
8653
|
-
summary = `Failed to
|
|
8619
|
+
summary = `Failed to configure ${scanner}. Check the error details in the steps.`;
|
|
8654
8620
|
}
|
|
8655
8621
|
return {
|
|
8656
8622
|
projectType,
|
|
@@ -8658,11 +8624,166 @@ async function bootstrapScanner(workspaceRoot, sarifStore, logger2) {
|
|
|
8658
8624
|
existingScanners: [],
|
|
8659
8625
|
steps,
|
|
8660
8626
|
autoScanResult,
|
|
8661
|
-
success
|
|
8627
|
+
success,
|
|
8662
8628
|
summary
|
|
8663
8629
|
};
|
|
8664
8630
|
}
|
|
8665
8631
|
|
|
8632
|
+
// src/scanner/auto-scan.ts
|
|
8633
|
+
function ingestScannerRun(scanner, rawOutput, sarifStore) {
|
|
8634
|
+
let parsed;
|
|
8635
|
+
try {
|
|
8636
|
+
parsed = JSON.parse(rawOutput);
|
|
8637
|
+
} catch {
|
|
8638
|
+
parsed = rawOutput;
|
|
8639
|
+
}
|
|
8640
|
+
const adapted = adaptScannerOutput(scanner, parsed);
|
|
8641
|
+
const stats = sarifStore.ingestRun(adapted.document, adapted.sourceTool);
|
|
8642
|
+
return { accepted: stats.accepted };
|
|
8643
|
+
}
|
|
8644
|
+
async function autoScan(workspaceRoot, sarifStore, logger2) {
|
|
8645
|
+
const start = Date.now();
|
|
8646
|
+
const detected = await detectScanners(workspaceRoot);
|
|
8647
|
+
const available = detected.filter((d) => d.available);
|
|
8648
|
+
logger2.info(
|
|
8649
|
+
{
|
|
8650
|
+
detected: detected.map((d) => `${d.scanner}:${d.available}`),
|
|
8651
|
+
available: available.length
|
|
8652
|
+
},
|
|
8653
|
+
"auto-scan: detection complete"
|
|
8654
|
+
);
|
|
8655
|
+
const eslintConfigFiles = [
|
|
8656
|
+
"eslint.config.js",
|
|
8657
|
+
"eslint.config.mjs",
|
|
8658
|
+
"eslint.config.cjs",
|
|
8659
|
+
"eslint.config.ts",
|
|
8660
|
+
"eslint.config.mts",
|
|
8661
|
+
"eslint.config.cts",
|
|
8662
|
+
".eslintrc.js",
|
|
8663
|
+
".eslintrc.cjs",
|
|
8664
|
+
".eslintrc.yaml",
|
|
8665
|
+
".eslintrc.yml",
|
|
8666
|
+
".eslintrc.json"
|
|
8667
|
+
];
|
|
8668
|
+
const eslintDetected = available.some((d) => d.scanner === "eslint");
|
|
8669
|
+
const hasEslintConfig = eslintConfigFiles.some((f) => existsSync4(join9(workspaceRoot, f)));
|
|
8670
|
+
if (eslintDetected && !hasEslintConfig) {
|
|
8671
|
+
logger2.info("auto-scan: ESLint detected but no config \u2014 running bootstrap");
|
|
8672
|
+
try {
|
|
8673
|
+
const bootstrapResult = await bootstrapScanner(workspaceRoot, sarifStore, logger2);
|
|
8674
|
+
if (bootstrapResult.autoScanResult) {
|
|
8675
|
+
return bootstrapResult.autoScanResult;
|
|
8676
|
+
}
|
|
8677
|
+
} catch (err) {
|
|
8678
|
+
logger2.warn(
|
|
8679
|
+
{ err: err.message },
|
|
8680
|
+
"auto-scan: bootstrap config creation failed"
|
|
8681
|
+
);
|
|
8682
|
+
}
|
|
8683
|
+
}
|
|
8684
|
+
if (available.length === 0) {
|
|
8685
|
+
logger2.info("auto-scan: no scanners found, attempting bootstrap");
|
|
8686
|
+
try {
|
|
8687
|
+
const bootstrapResult = await bootstrapScanner(workspaceRoot, sarifStore, logger2);
|
|
8688
|
+
if (bootstrapResult.autoScanResult) {
|
|
8689
|
+
return bootstrapResult.autoScanResult;
|
|
8690
|
+
}
|
|
8691
|
+
} catch (err) {
|
|
8692
|
+
logger2.warn(
|
|
8693
|
+
{ err: err.message },
|
|
8694
|
+
"auto-scan: bootstrap failed \u2014 continuing with empty results"
|
|
8695
|
+
);
|
|
8696
|
+
}
|
|
8697
|
+
return {
|
|
8698
|
+
detected,
|
|
8699
|
+
results: [],
|
|
8700
|
+
totalFindings: 0,
|
|
8701
|
+
totalDurationMs: Date.now() - start
|
|
8702
|
+
};
|
|
8703
|
+
}
|
|
8704
|
+
const runResults = await Promise.allSettled(
|
|
8705
|
+
available.map((d) => runScanner(d.scanner, workspaceRoot))
|
|
8706
|
+
);
|
|
8707
|
+
const results = [];
|
|
8708
|
+
let totalFindings = 0;
|
|
8709
|
+
let persistNeeded = false;
|
|
8710
|
+
for (let i = 0; i < available.length; i++) {
|
|
8711
|
+
const detection = available[i];
|
|
8712
|
+
const settled = runResults[i];
|
|
8713
|
+
if (settled.status === "rejected") {
|
|
8714
|
+
const error = String(settled.reason);
|
|
8715
|
+
logger2.warn(
|
|
8716
|
+
{ scanner: detection.scanner, error },
|
|
8717
|
+
"auto-scan: scanner execution rejected"
|
|
8718
|
+
);
|
|
8719
|
+
results.push({
|
|
8720
|
+
scanner: detection.scanner,
|
|
8721
|
+
success: false,
|
|
8722
|
+
findingsIngested: 0,
|
|
8723
|
+
durationMs: 0,
|
|
8724
|
+
error
|
|
8725
|
+
});
|
|
8726
|
+
continue;
|
|
8727
|
+
}
|
|
8728
|
+
const runResult = settled.value;
|
|
8729
|
+
if (!runResult.success) {
|
|
8730
|
+
logger2.warn(
|
|
8731
|
+
{ scanner: runResult.scanner, error: runResult.error },
|
|
8732
|
+
"auto-scan: scanner returned failure"
|
|
8733
|
+
);
|
|
8734
|
+
results.push({
|
|
8735
|
+
scanner: runResult.scanner,
|
|
8736
|
+
success: false,
|
|
8737
|
+
findingsIngested: 0,
|
|
8738
|
+
durationMs: runResult.durationMs,
|
|
8739
|
+
error: runResult.error ?? "unknown error"
|
|
8740
|
+
});
|
|
8741
|
+
continue;
|
|
8742
|
+
}
|
|
8743
|
+
try {
|
|
8744
|
+
const { accepted } = ingestScannerRun(
|
|
8745
|
+
runResult.scanner,
|
|
8746
|
+
runResult.rawOutput,
|
|
8747
|
+
sarifStore
|
|
8748
|
+
);
|
|
8749
|
+
totalFindings += accepted;
|
|
8750
|
+
persistNeeded = true;
|
|
8751
|
+
logger2.info(
|
|
8752
|
+
{ scanner: runResult.scanner, accepted, durationMs: runResult.durationMs },
|
|
8753
|
+
"auto-scan: scanner ingested"
|
|
8754
|
+
);
|
|
8755
|
+
results.push({
|
|
8756
|
+
scanner: runResult.scanner,
|
|
8757
|
+
success: true,
|
|
8758
|
+
findingsIngested: accepted,
|
|
8759
|
+
durationMs: runResult.durationMs
|
|
8760
|
+
});
|
|
8761
|
+
} catch (err) {
|
|
8762
|
+
const error = err.message;
|
|
8763
|
+
logger2.warn(
|
|
8764
|
+
{ scanner: runResult.scanner, error },
|
|
8765
|
+
"auto-scan: adapter/ingestion failed"
|
|
8766
|
+
);
|
|
8767
|
+
results.push({
|
|
8768
|
+
scanner: runResult.scanner,
|
|
8769
|
+
success: false,
|
|
8770
|
+
findingsIngested: 0,
|
|
8771
|
+
durationMs: runResult.durationMs,
|
|
8772
|
+
error
|
|
8773
|
+
});
|
|
8774
|
+
}
|
|
8775
|
+
}
|
|
8776
|
+
if (persistNeeded) {
|
|
8777
|
+
await sarifStore.persist();
|
|
8778
|
+
}
|
|
8779
|
+
return {
|
|
8780
|
+
detected,
|
|
8781
|
+
results,
|
|
8782
|
+
totalFindings,
|
|
8783
|
+
totalDurationMs: Date.now() - start
|
|
8784
|
+
};
|
|
8785
|
+
}
|
|
8786
|
+
|
|
8666
8787
|
// src/schemas/tool-schemas.ts
|
|
8667
8788
|
var computeCrapSchema = {
|
|
8668
8789
|
type: "object",
|