@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.
@@ -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)
@@ -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<{
@@ -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()),
@@ -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). " +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testchimp/cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "TestChimp CLI and MCP server — coverage, plans, EaaS, TrueCoverage (calls /api/mcp/*)",
5
5
  "type": "module",
6
6
  "main": "dist/bin/testchimp.js",