@testchimp/cli 0.1.13 → 0.1.15
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/program.js +126 -0
- package/dist/core/schemas.d.ts +28 -0
- package/dist/core/schemas.js +28 -0
- package/dist/core/tools.js +90 -0
- package/package.json +1 -1
package/dist/cli/program.js
CHANGED
|
@@ -573,6 +573,132 @@ export function buildCliProgram() {
|
|
|
573
573
|
const out = await runTool("get-release", { version: String(merged.version).trim() }, { postMcp });
|
|
574
574
|
console.log(out);
|
|
575
575
|
});
|
|
576
|
+
program
|
|
577
|
+
.command("get-security-scan-config")
|
|
578
|
+
.description(TOOL_DEFINITIONS.find((t) => t.kebab === "get-security-scan-config").description)
|
|
579
|
+
.addOption(jsonInputOption())
|
|
580
|
+
.option("--id <scanId>", "Security scan id")
|
|
581
|
+
.action(async (opts) => {
|
|
582
|
+
const body = {};
|
|
583
|
+
if (opts.id)
|
|
584
|
+
body.id = String(opts.id);
|
|
585
|
+
const merged = mergeBodies(body, opts.jsonInput);
|
|
586
|
+
if (!merged.id || String(merged.id).trim() === "") {
|
|
587
|
+
throw new Error("id is required (--id or --json-input {\"id\":\"...\"})");
|
|
588
|
+
}
|
|
589
|
+
const out = await runTool("get-security-scan-config", { id: String(merged.id).trim() }, { postMcp });
|
|
590
|
+
console.log(out);
|
|
591
|
+
});
|
|
592
|
+
program
|
|
593
|
+
.command("update-scan-progress")
|
|
594
|
+
.description(TOOL_DEFINITIONS.find((t) => t.kebab === "update-scan-progress").description)
|
|
595
|
+
.addOption(jsonInputOption())
|
|
596
|
+
.option("--id <scanId>", "Security scan id")
|
|
597
|
+
.option("--status <status>", "QUEUED | IN_PROGRESS | COMPLETED | EXCEPTION")
|
|
598
|
+
.action(async (opts) => {
|
|
599
|
+
const body = {};
|
|
600
|
+
if (opts.id)
|
|
601
|
+
body.id = String(opts.id);
|
|
602
|
+
if (opts.status)
|
|
603
|
+
body.status = String(opts.status);
|
|
604
|
+
const merged = mergeBodies(body, opts.jsonInput);
|
|
605
|
+
if (!merged.id || String(merged.id).trim() === "") {
|
|
606
|
+
throw new Error("id is required");
|
|
607
|
+
}
|
|
608
|
+
if (!merged.status || String(merged.status).trim() === "") {
|
|
609
|
+
throw new Error("status is required (QUEUED | IN_PROGRESS | COMPLETED | EXCEPTION)");
|
|
610
|
+
}
|
|
611
|
+
const out = await runTool("update-scan-progress", { id: String(merged.id).trim(), status: String(merged.status).trim() }, { postMcp });
|
|
612
|
+
console.log(out);
|
|
613
|
+
});
|
|
614
|
+
program
|
|
615
|
+
.command("report-dast-findings")
|
|
616
|
+
.description(TOOL_DEFINITIONS.find((t) => t.kebab === "report-dast-findings").description)
|
|
617
|
+
.addOption(jsonInputOption())
|
|
618
|
+
.option("--id <scanId>", "Security scan id")
|
|
619
|
+
.option("--report-file <path>", "Path to ZAP Traditional JSON report")
|
|
620
|
+
.action(async (opts) => {
|
|
621
|
+
const body = {};
|
|
622
|
+
if (opts.id)
|
|
623
|
+
body.id = String(opts.id);
|
|
624
|
+
if (opts.reportFile)
|
|
625
|
+
body.reportFile = String(opts.reportFile);
|
|
626
|
+
const merged = mergeBodies(body, opts.jsonInput);
|
|
627
|
+
if (!merged.id || String(merged.id).trim() === "") {
|
|
628
|
+
throw new Error("id is required");
|
|
629
|
+
}
|
|
630
|
+
if (!merged.reportFile || String(merged.reportFile).trim() === "") {
|
|
631
|
+
throw new Error("reportFile is required (--report-file)");
|
|
632
|
+
}
|
|
633
|
+
const out = await runTool("report-dast-findings", { id: String(merged.id).trim(), reportFile: String(merged.reportFile).trim() }, { postMcp });
|
|
634
|
+
console.log(out);
|
|
635
|
+
});
|
|
636
|
+
program
|
|
637
|
+
.command("report-sast-findings")
|
|
638
|
+
.description(TOOL_DEFINITIONS.find((t) => t.kebab === "report-sast-findings").description)
|
|
639
|
+
.addOption(jsonInputOption())
|
|
640
|
+
.option("--id <scanId>", "Security scan id")
|
|
641
|
+
.option("--report-file <path>", "Path to full Semgrep CLI JSON report")
|
|
642
|
+
.action(async (opts) => {
|
|
643
|
+
const body = {};
|
|
644
|
+
if (opts.id)
|
|
645
|
+
body.id = String(opts.id);
|
|
646
|
+
if (opts.reportFile)
|
|
647
|
+
body.reportFile = String(opts.reportFile);
|
|
648
|
+
const merged = mergeBodies(body, opts.jsonInput);
|
|
649
|
+
if (!merged.id || String(merged.id).trim() === "") {
|
|
650
|
+
throw new Error("id is required");
|
|
651
|
+
}
|
|
652
|
+
if (!merged.reportFile || String(merged.reportFile).trim() === "") {
|
|
653
|
+
throw new Error("reportFile is required (--report-file)");
|
|
654
|
+
}
|
|
655
|
+
const out = await runTool("report-sast-findings", { id: String(merged.id).trim(), reportFile: String(merged.reportFile).trim() }, { postMcp });
|
|
656
|
+
console.log(out);
|
|
657
|
+
});
|
|
658
|
+
program
|
|
659
|
+
.command("report-secrets-findings")
|
|
660
|
+
.description(TOOL_DEFINITIONS.find((t) => t.kebab === "report-secrets-findings").description)
|
|
661
|
+
.addOption(jsonInputOption())
|
|
662
|
+
.option("--id <scanId>", "Security scan id")
|
|
663
|
+
.option("--report-file <path>", "Path to full Gitleaks JSON report")
|
|
664
|
+
.action(async (opts) => {
|
|
665
|
+
const body = {};
|
|
666
|
+
if (opts.id)
|
|
667
|
+
body.id = String(opts.id);
|
|
668
|
+
if (opts.reportFile)
|
|
669
|
+
body.reportFile = String(opts.reportFile);
|
|
670
|
+
const merged = mergeBodies(body, opts.jsonInput);
|
|
671
|
+
if (!merged.id || String(merged.id).trim() === "") {
|
|
672
|
+
throw new Error("id is required");
|
|
673
|
+
}
|
|
674
|
+
if (!merged.reportFile || String(merged.reportFile).trim() === "") {
|
|
675
|
+
throw new Error("reportFile is required (--report-file)");
|
|
676
|
+
}
|
|
677
|
+
const out = await runTool("report-secrets-findings", { id: String(merged.id).trim(), reportFile: String(merged.reportFile).trim() }, { postMcp });
|
|
678
|
+
console.log(out);
|
|
679
|
+
});
|
|
680
|
+
program
|
|
681
|
+
.command("report-deps-findings")
|
|
682
|
+
.description(TOOL_DEFINITIONS.find((t) => t.kebab === "report-deps-findings").description)
|
|
683
|
+
.addOption(jsonInputOption())
|
|
684
|
+
.option("--id <scanId>", "Security scan id")
|
|
685
|
+
.option("--report-file <path>", "Path to full Trivy JSON report")
|
|
686
|
+
.action(async (opts) => {
|
|
687
|
+
const body = {};
|
|
688
|
+
if (opts.id)
|
|
689
|
+
body.id = String(opts.id);
|
|
690
|
+
if (opts.reportFile)
|
|
691
|
+
body.reportFile = String(opts.reportFile);
|
|
692
|
+
const merged = mergeBodies(body, opts.jsonInput);
|
|
693
|
+
if (!merged.id || String(merged.id).trim() === "") {
|
|
694
|
+
throw new Error("id is required");
|
|
695
|
+
}
|
|
696
|
+
if (!merged.reportFile || String(merged.reportFile).trim() === "") {
|
|
697
|
+
throw new Error("reportFile is required (--report-file)");
|
|
698
|
+
}
|
|
699
|
+
const out = await runTool("report-deps-findings", { id: String(merged.id).trim(), reportFile: String(merged.reportFile).trim() }, { postMcp });
|
|
700
|
+
console.log(out);
|
|
701
|
+
});
|
|
576
702
|
program
|
|
577
703
|
.command("upsert-screen-states")
|
|
578
704
|
.description(TOOL_DEFINITIONS.find((t) => t.kebab === "upsert-screen-states").description)
|
package/dist/core/schemas.d.ts
CHANGED
|
@@ -561,6 +561,34 @@ export declare const listScreenStatesInput: z.ZodObject<{
|
|
|
561
561
|
export declare const getReleaseInput: z.ZodObject<{
|
|
562
562
|
version: z.ZodString;
|
|
563
563
|
}, z.core.$strip>;
|
|
564
|
+
export declare const getSecurityScanConfigInput: z.ZodObject<{
|
|
565
|
+
id: z.ZodString;
|
|
566
|
+
}, z.core.$strip>;
|
|
567
|
+
export declare const updateScanProgressInput: z.ZodObject<{
|
|
568
|
+
id: z.ZodString;
|
|
569
|
+
status: z.ZodEnum<{
|
|
570
|
+
QUEUED: "QUEUED";
|
|
571
|
+
IN_PROGRESS: "IN_PROGRESS";
|
|
572
|
+
COMPLETED: "COMPLETED";
|
|
573
|
+
EXCEPTION: "EXCEPTION";
|
|
574
|
+
}>;
|
|
575
|
+
}, z.core.$strip>;
|
|
576
|
+
export declare const reportDastFindingsInput: z.ZodObject<{
|
|
577
|
+
id: z.ZodString;
|
|
578
|
+
reportFile: z.ZodString;
|
|
579
|
+
}, z.core.$strip>;
|
|
580
|
+
export declare const reportSastFindingsInput: z.ZodObject<{
|
|
581
|
+
id: z.ZodString;
|
|
582
|
+
reportFile: z.ZodString;
|
|
583
|
+
}, z.core.$strip>;
|
|
584
|
+
export declare const reportSecretsFindingsInput: z.ZodObject<{
|
|
585
|
+
id: z.ZodString;
|
|
586
|
+
reportFile: z.ZodString;
|
|
587
|
+
}, z.core.$strip>;
|
|
588
|
+
export declare const reportDepsFindingsInput: z.ZodObject<{
|
|
589
|
+
id: z.ZodString;
|
|
590
|
+
reportFile: z.ZodString;
|
|
591
|
+
}, z.core.$strip>;
|
|
564
592
|
/** UpsertScreenStatesRequest JSON (proto camelCase). */
|
|
565
593
|
export declare const upsertScreenStatesInput: z.ZodObject<{
|
|
566
594
|
screenStates: z.ZodArray<z.ZodObject<{
|
package/dist/core/schemas.js
CHANGED
|
@@ -239,6 +239,34 @@ export const getReleaseInput = z.object({
|
|
|
239
239
|
/** Release catalog version / label — maps to McpGetReleaseRequest.version */
|
|
240
240
|
version: z.string().min(1),
|
|
241
241
|
});
|
|
242
|
+
export const getSecurityScanConfigInput = z.object({
|
|
243
|
+
id: z.string().min(1),
|
|
244
|
+
});
|
|
245
|
+
export const updateScanProgressInput = z.object({
|
|
246
|
+
id: z.string().min(1),
|
|
247
|
+
/** ScanStatus enum name: QUEUED | IN_PROGRESS | COMPLETED | EXCEPTION */
|
|
248
|
+
status: z.enum(["QUEUED", "IN_PROGRESS", "COMPLETED", "EXCEPTION"]),
|
|
249
|
+
});
|
|
250
|
+
export const reportDastFindingsInput = z.object({
|
|
251
|
+
id: z.string().min(1),
|
|
252
|
+
/** Path to ZAP Traditional JSON report file */
|
|
253
|
+
reportFile: z.string().min(1),
|
|
254
|
+
});
|
|
255
|
+
export const reportSastFindingsInput = z.object({
|
|
256
|
+
id: z.string().min(1),
|
|
257
|
+
/** Path to full Semgrep CLI JSON report file */
|
|
258
|
+
reportFile: z.string().min(1),
|
|
259
|
+
});
|
|
260
|
+
export const reportSecretsFindingsInput = z.object({
|
|
261
|
+
id: z.string().min(1),
|
|
262
|
+
/** Path to full Gitleaks JSON report file */
|
|
263
|
+
reportFile: z.string().min(1),
|
|
264
|
+
});
|
|
265
|
+
export const reportDepsFindingsInput = z.object({
|
|
266
|
+
id: z.string().min(1),
|
|
267
|
+
/** Path to full Trivy JSON report file */
|
|
268
|
+
reportFile: z.string().min(1),
|
|
269
|
+
});
|
|
242
270
|
const screenStatesEntrySchema = z.object({
|
|
243
271
|
screen: z.string().optional(),
|
|
244
272
|
states: z.array(z.string()),
|
package/dist/core/tools.js
CHANGED
|
@@ -479,6 +479,96 @@ export const TOOL_DEFINITIONS = [
|
|
|
479
479
|
return postMcp("/api/mcp/get_release", body);
|
|
480
480
|
},
|
|
481
481
|
},
|
|
482
|
+
{
|
|
483
|
+
kebab: "get-security-scan-config",
|
|
484
|
+
description: "Fetch security scan config by scan id (detail.dastCheckConfig / detail.sastCheckConfig / " +
|
|
485
|
+
"detail.depsCheckConfig / detail.leaksCheckConfig, release label, status). Pass id (CLI: --id). " +
|
|
486
|
+
"Used by /testchimp run security scan. For DAST honour allowActiveScan / useEphemeralSandbox / scope " +
|
|
487
|
+
"on dastCheckConfig.",
|
|
488
|
+
inputSchema: S.getSecurityScanConfigInput,
|
|
489
|
+
execute: async (args, { postMcp }) => {
|
|
490
|
+
const a = args;
|
|
491
|
+
return postMcp("/api/mcp/get_security_scan_config", { scanId: a.id.trim() });
|
|
492
|
+
},
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
kebab: "update-scan-progress",
|
|
496
|
+
description: "Update a scan's status. status must be one of: QUEUED, IN_PROGRESS, COMPLETED, EXCEPTION. " +
|
|
497
|
+
"Call IN_PROGRESS when starting. Each scan is a single checker type: the category playbook " +
|
|
498
|
+
"sets COMPLETED after a successful report-*-findings (or EXCEPTION on hard failure).",
|
|
499
|
+
inputSchema: S.updateScanProgressInput,
|
|
500
|
+
execute: async (args, { postMcp }) => {
|
|
501
|
+
const a = args;
|
|
502
|
+
return postMcp("/api/mcp/update_scan_progress", {
|
|
503
|
+
scanId: a.id.trim(),
|
|
504
|
+
status: a.status,
|
|
505
|
+
});
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
kebab: "report-dast-findings",
|
|
510
|
+
description: "Upload a ZAP Traditional JSON report for a security scan. Pass --id and --report-file <path>. " +
|
|
511
|
+
"Backend parses alerts, dedupes by bug hash, and inserts new SECURITY bugs linked to the scan. " +
|
|
512
|
+
"Does not mark the scan COMPLETED — the DAST playbook calls update-scan-progress COMPLETED after this.",
|
|
513
|
+
inputSchema: S.reportDastFindingsInput,
|
|
514
|
+
execute: async (args, { postMcp }) => {
|
|
515
|
+
const a = args;
|
|
516
|
+
const { readFile } = await import("node:fs/promises");
|
|
517
|
+
const reportJson = await readFile(a.reportFile, "utf8");
|
|
518
|
+
return postMcp("/api/mcp/report_dast_findings", {
|
|
519
|
+
scanId: a.id.trim(),
|
|
520
|
+
reportJson,
|
|
521
|
+
});
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
kebab: "report-sast-findings",
|
|
526
|
+
description: "Upload a full Semgrep CLI JSON report for a SAST security scan. Pass --id and --report-file <path>. " +
|
|
527
|
+
"Backend stores the raw report, parses results, dedupes by bug hash, and inserts new SECURITY bugs. " +
|
|
528
|
+
"Does not mark the scan COMPLETED — the SAST playbook calls update-scan-progress COMPLETED after this.",
|
|
529
|
+
inputSchema: S.reportSastFindingsInput,
|
|
530
|
+
execute: async (args, { postMcp }) => {
|
|
531
|
+
const a = args;
|
|
532
|
+
const { readFile } = await import("node:fs/promises");
|
|
533
|
+
const reportJson = await readFile(a.reportFile, "utf8");
|
|
534
|
+
return postMcp("/api/mcp/report_sast_findings", {
|
|
535
|
+
scanId: a.id.trim(),
|
|
536
|
+
reportJson,
|
|
537
|
+
});
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
kebab: "report-secrets-findings",
|
|
542
|
+
description: "Upload a full Gitleaks JSON report for a secrets security scan. Pass --id and --report-file <path>. " +
|
|
543
|
+
"Backend redacts secret payloads, stores the report, dedupes by bug hash, and inserts SECURITY bugs. " +
|
|
544
|
+
"Does not mark the scan COMPLETED — the secrets playbook calls update-scan-progress COMPLETED after this.",
|
|
545
|
+
inputSchema: S.reportSecretsFindingsInput,
|
|
546
|
+
execute: async (args, { postMcp }) => {
|
|
547
|
+
const a = args;
|
|
548
|
+
const { readFile } = await import("node:fs/promises");
|
|
549
|
+
const reportJson = await readFile(a.reportFile, "utf8");
|
|
550
|
+
return postMcp("/api/mcp/report_secrets_findings", {
|
|
551
|
+
scanId: a.id.trim(),
|
|
552
|
+
reportJson,
|
|
553
|
+
});
|
|
554
|
+
},
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
kebab: "report-deps-findings",
|
|
558
|
+
description: "Upload a full Trivy JSON report for a dependency security scan. Pass --id and --report-file <path>. " +
|
|
559
|
+
"Backend stores the report, filters by security profile / ignore-unfixed, dedupes, and inserts SECURITY bugs. " +
|
|
560
|
+
"Does not mark the scan COMPLETED — the deps playbook calls update-scan-progress COMPLETED after this.",
|
|
561
|
+
inputSchema: S.reportDepsFindingsInput,
|
|
562
|
+
execute: async (args, { postMcp }) => {
|
|
563
|
+
const a = args;
|
|
564
|
+
const { readFile } = await import("node:fs/promises");
|
|
565
|
+
const reportJson = await readFile(a.reportFile, "utf8");
|
|
566
|
+
return postMcp("/api/mcp/report_deps_findings", {
|
|
567
|
+
scanId: a.id.trim(),
|
|
568
|
+
reportJson,
|
|
569
|
+
});
|
|
570
|
+
},
|
|
571
|
+
},
|
|
482
572
|
{
|
|
483
573
|
kebab: "upsert-screen-states",
|
|
484
574
|
description: "Merge screen names and state strings into the project's relational atlas (idempotent upsert). " +
|