ghagga-core 2.3.0 → 2.4.1

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.
Files changed (111) hide show
  1. package/dist/format.d.ts.map +1 -1
  2. package/dist/format.js +23 -1
  3. package/dist/format.js.map +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/pipeline.d.ts.map +1 -1
  9. package/dist/pipeline.js +36 -19
  10. package/dist/pipeline.js.map +1 -1
  11. package/dist/tools/budget.d.ts +26 -0
  12. package/dist/tools/budget.d.ts.map +1 -0
  13. package/dist/tools/budget.js +78 -0
  14. package/dist/tools/budget.js.map +1 -0
  15. package/dist/tools/execution.d.ts +18 -0
  16. package/dist/tools/execution.d.ts.map +1 -0
  17. package/dist/tools/execution.js +82 -0
  18. package/dist/tools/execution.js.map +1 -0
  19. package/dist/tools/index.d.ts +16 -0
  20. package/dist/tools/index.d.ts.map +1 -0
  21. package/dist/tools/index.js +20 -0
  22. package/dist/tools/index.js.map +1 -0
  23. package/dist/tools/orchestrator.d.ts +24 -0
  24. package/dist/tools/orchestrator.d.ts.map +1 -0
  25. package/dist/tools/orchestrator.js +127 -0
  26. package/dist/tools/orchestrator.js.map +1 -0
  27. package/dist/tools/plugins/bandit.d.ts +22 -0
  28. package/dist/tools/plugins/bandit.d.ts.map +1 -0
  29. package/dist/tools/plugins/bandit.js +79 -0
  30. package/dist/tools/plugins/bandit.js.map +1 -0
  31. package/dist/tools/plugins/biome.d.ts +22 -0
  32. package/dist/tools/plugins/biome.d.ts.map +1 -0
  33. package/dist/tools/plugins/biome.js +80 -0
  34. package/dist/tools/plugins/biome.js.map +1 -0
  35. package/dist/tools/plugins/clippy.d.ts +25 -0
  36. package/dist/tools/plugins/clippy.d.ts.map +1 -0
  37. package/dist/tools/plugins/clippy.js +95 -0
  38. package/dist/tools/plugins/clippy.js.map +1 -0
  39. package/dist/tools/plugins/cpd.d.ts +20 -0
  40. package/dist/tools/plugins/cpd.d.ts.map +1 -0
  41. package/dist/tools/plugins/cpd.js +111 -0
  42. package/dist/tools/plugins/cpd.js.map +1 -0
  43. package/dist/tools/plugins/gitleaks.d.ts +18 -0
  44. package/dist/tools/plugins/gitleaks.d.ts.map +1 -0
  45. package/dist/tools/plugins/gitleaks.js +81 -0
  46. package/dist/tools/plugins/gitleaks.js.map +1 -0
  47. package/dist/tools/plugins/golangci-lint.d.ts +27 -0
  48. package/dist/tools/plugins/golangci-lint.d.ts.map +1 -0
  49. package/dist/tools/plugins/golangci-lint.js +87 -0
  50. package/dist/tools/plugins/golangci-lint.js.map +1 -0
  51. package/dist/tools/plugins/hadolint.d.ts +22 -0
  52. package/dist/tools/plugins/hadolint.d.ts.map +1 -0
  53. package/dist/tools/plugins/hadolint.js +99 -0
  54. package/dist/tools/plugins/hadolint.js.map +1 -0
  55. package/dist/tools/plugins/index.d.ts +37 -0
  56. package/dist/tools/plugins/index.d.ts.map +1 -0
  57. package/dist/tools/plugins/index.js +93 -0
  58. package/dist/tools/plugins/index.js.map +1 -0
  59. package/dist/tools/plugins/lizard.d.ts +24 -0
  60. package/dist/tools/plugins/lizard.d.ts.map +1 -0
  61. package/dist/tools/plugins/lizard.js +83 -0
  62. package/dist/tools/plugins/lizard.js.map +1 -0
  63. package/dist/tools/plugins/markdownlint.d.ts +17 -0
  64. package/dist/tools/plugins/markdownlint.d.ts.map +1 -0
  65. package/dist/tools/plugins/markdownlint.js +70 -0
  66. package/dist/tools/plugins/markdownlint.js.map +1 -0
  67. package/dist/tools/plugins/pmd.d.ts +23 -0
  68. package/dist/tools/plugins/pmd.d.ts.map +1 -0
  69. package/dist/tools/plugins/pmd.js +108 -0
  70. package/dist/tools/plugins/pmd.js.map +1 -0
  71. package/dist/tools/plugins/psalm.d.ts +24 -0
  72. package/dist/tools/plugins/psalm.d.ts.map +1 -0
  73. package/dist/tools/plugins/psalm.js +85 -0
  74. package/dist/tools/plugins/psalm.js.map +1 -0
  75. package/dist/tools/plugins/ruff.d.ts +22 -0
  76. package/dist/tools/plugins/ruff.d.ts.map +1 -0
  77. package/dist/tools/plugins/ruff.js +80 -0
  78. package/dist/tools/plugins/ruff.js.map +1 -0
  79. package/dist/tools/plugins/semgrep.d.ts +23 -0
  80. package/dist/tools/plugins/semgrep.d.ts.map +1 -0
  81. package/dist/tools/plugins/semgrep.js +82 -0
  82. package/dist/tools/plugins/semgrep.js.map +1 -0
  83. package/dist/tools/plugins/shellcheck.d.ts +23 -0
  84. package/dist/tools/plugins/shellcheck.d.ts.map +1 -0
  85. package/dist/tools/plugins/shellcheck.js +87 -0
  86. package/dist/tools/plugins/shellcheck.js.map +1 -0
  87. package/dist/tools/plugins/trivy.d.ts +25 -0
  88. package/dist/tools/plugins/trivy.d.ts.map +1 -0
  89. package/dist/tools/plugins/trivy.js +108 -0
  90. package/dist/tools/plugins/trivy.js.map +1 -0
  91. package/dist/tools/registry.d.ts +37 -0
  92. package/dist/tools/registry.d.ts.map +1 -0
  93. package/dist/tools/registry.js +61 -0
  94. package/dist/tools/registry.js.map +1 -0
  95. package/dist/tools/resolve.d.ts +37 -0
  96. package/dist/tools/resolve.d.ts.map +1 -0
  97. package/dist/tools/resolve.js +67 -0
  98. package/dist/tools/resolve.js.map +1 -0
  99. package/dist/tools/runner.d.ts +15 -1
  100. package/dist/tools/runner.d.ts.map +1 -1
  101. package/dist/tools/runner.js +76 -6
  102. package/dist/tools/runner.js.map +1 -1
  103. package/dist/tools/types.d.ts +83 -0
  104. package/dist/tools/types.d.ts.map +1 -0
  105. package/dist/tools/types.js +11 -0
  106. package/dist/tools/types.js.map +1 -0
  107. package/dist/types.d.ts +15 -3
  108. package/dist/types.d.ts.map +1 -1
  109. package/dist/types.js +2 -0
  110. package/dist/types.js.map +1 -1
  111. package/package.json +1 -1
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Tool Orchestrator — runs tools sequentially with failure isolation.
3
+ *
4
+ * - Sequential install → run → parse loop
5
+ * - Per-tool try/catch for failure isolation
6
+ * - Timeout enforcement per tool
7
+ * - Budget rollover from fast tools
8
+ * - Legacy keys (semgrep, trivy, cpd) always present
9
+ */
10
+ import { allocateTimeBudget, getEffectiveBudget } from './budget.js';
11
+ /** Skipped result for tools that didn't run */
12
+ const SKIPPED_RESULT = {
13
+ status: 'skipped',
14
+ findings: [],
15
+ error: undefined,
16
+ executionTimeMs: 0,
17
+ };
18
+ /** Legacy tool names that must always be present in results */
19
+ const LEGACY_TOOL_NAMES = ['semgrep', 'trivy', 'cpd'];
20
+ /**
21
+ * Run all activated tools sequentially with budget management and failure isolation.
22
+ *
23
+ * @param ctx - Execution context (Node, Actions, or Mock)
24
+ * @param activatedTools - Tools to execute (from resolveActivatedTools)
25
+ * @param targetDir - Repository directory to scan
26
+ * @param files - List of changed file paths
27
+ * @param totalBudgetMs - Total time budget in ms (default 600_000)
28
+ * @returns Record of tool name → ToolResult
29
+ */
30
+ export async function runTools(ctx, activatedTools, targetDir, files, totalBudgetMs = 600_000) {
31
+ const results = {};
32
+ const budget = allocateTimeBudget(activatedTools, totalBudgetMs);
33
+ const elapsedByTool = new Map();
34
+ let totalElapsed = 0;
35
+ ctx.log('info', `[ghagga:tools] Running ${activatedTools.length} tools sequentially...`);
36
+ for (const activated of activatedTools) {
37
+ const tool = activated.definition;
38
+ // Check if total budget is exhausted
39
+ if (totalElapsed >= budget.totalMs) {
40
+ ctx.log('warn', `[ghagga:tools] Total budget exhausted, skipping ${tool.name}`);
41
+ results[tool.name] = {
42
+ status: 'skipped',
43
+ findings: [],
44
+ error: 'total-budget-exhausted',
45
+ executionTimeMs: 0,
46
+ };
47
+ continue;
48
+ }
49
+ const effectiveBudget = getEffectiveBudget(tool.name, budget, elapsedByTool);
50
+ const start = Date.now();
51
+ try {
52
+ // Install
53
+ await tool.install(ctx);
54
+ // Run
55
+ const raw = await tool.run(ctx, targetDir, files, effectiveBudget);
56
+ // Check for timeout
57
+ if (raw.timedOut) {
58
+ const durationMs = Date.now() - start;
59
+ ctx.log('warn', `[ghagga:tools] ${tool.name}: timeout after ${durationMs}ms`);
60
+ results[tool.name] = {
61
+ status: 'error',
62
+ findings: [],
63
+ error: 'timeout',
64
+ executionTimeMs: durationMs,
65
+ };
66
+ elapsedByTool.set(tool.name, durationMs);
67
+ totalElapsed += durationMs;
68
+ continue;
69
+ }
70
+ // Parse
71
+ const findings = parseSafe(tool, raw, targetDir, ctx);
72
+ const durationMs = Date.now() - start;
73
+ ctx.log('info', `[ghagga:tools] ${tool.name}: success (${findings.length} findings, ${durationMs}ms)`);
74
+ results[tool.name] = {
75
+ status: 'success',
76
+ findings,
77
+ executionTimeMs: durationMs,
78
+ };
79
+ elapsedByTool.set(tool.name, durationMs);
80
+ totalElapsed += durationMs;
81
+ }
82
+ catch (error) {
83
+ const durationMs = Date.now() - start;
84
+ const errorMessage = error instanceof Error ? error.message : String(error);
85
+ ctx.log('error', `[ghagga:tools] ${tool.name}: error — ${errorMessage}`);
86
+ results[tool.name] = {
87
+ status: 'error',
88
+ findings: [],
89
+ error: errorMessage,
90
+ executionTimeMs: durationMs,
91
+ };
92
+ elapsedByTool.set(tool.name, durationMs);
93
+ totalElapsed += durationMs;
94
+ }
95
+ }
96
+ // Ensure legacy keys always present
97
+ ensureLegacyKeys(results);
98
+ // Log summary
99
+ const totalFindings = Object.values(results).reduce((sum, r) => sum + r.findings.length, 0);
100
+ ctx.log('info', `[ghagga:tools] Complete: ${activatedTools.length} tools, ${totalFindings} findings, ${totalElapsed}ms total`);
101
+ return results;
102
+ }
103
+ /**
104
+ * Parse raw output safely — if parse throws, return empty findings.
105
+ */
106
+ function parseSafe(tool, raw, repoDir, ctx) {
107
+ try {
108
+ return tool.parse(raw, repoDir);
109
+ }
110
+ catch (error) {
111
+ const msg = error instanceof Error ? error.message : String(error);
112
+ ctx.log('warn', `[ghagga:tools] ${tool.name}: parse error — ${msg}`);
113
+ return [];
114
+ }
115
+ }
116
+ /**
117
+ * Ensure semgrep, trivy, cpd keys are always present in results.
118
+ * Missing legacy tools get a skipped status.
119
+ */
120
+ function ensureLegacyKeys(results) {
121
+ for (const name of LEGACY_TOOL_NAMES) {
122
+ if (!results[name]) {
123
+ results[name] = { ...SKIPPED_RESULT };
124
+ }
125
+ }
126
+ }
127
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/tools/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAIrE,+CAA+C;AAC/C,MAAM,cAAc,GAAe;IACjC,MAAM,EAAE,SAAS;IACjB,QAAQ,EAAE,EAAE;IACZ,KAAK,EAAE,SAAS;IAChB,eAAe,EAAE,CAAC;CACnB,CAAC;AAEF,+DAA+D;AAC/D,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAU,CAAC;AAE/D;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAqB,EACrB,cAA+B,EAC/B,SAAiB,EACjB,KAAe,EACf,gBAAwB,OAAO;IAE/B,MAAM,OAAO,GAA+B,EAAE,CAAC;IAC/C,MAAM,MAAM,GAAG,kBAAkB,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;IACjE,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,0BAA0B,cAAc,CAAC,MAAM,wBAAwB,CAAC,CAAC;IAEzF,KAAK,MAAM,SAAS,IAAI,cAAc,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,CAAC;QAElC,qCAAqC;QACrC,IAAI,YAAY,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,mDAAmD,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAChF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACnB,MAAM,EAAE,SAAS;gBACjB,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,wBAAwB;gBAC/B,eAAe,EAAE,CAAC;aACnB,CAAC;YACF,SAAS;QACX,CAAC;QAED,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;QAC7E,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,IAAI,CAAC;YACH,UAAU;YACV,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAExB,MAAM;YACN,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;YAEnE,oBAAoB;YACpB,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACjB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;gBACtC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,kBAAkB,IAAI,CAAC,IAAI,mBAAmB,UAAU,IAAI,CAAC,CAAC;gBAC9E,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;oBACnB,MAAM,EAAE,OAAO;oBACf,QAAQ,EAAE,EAAE;oBACZ,KAAK,EAAE,SAAS;oBAChB,eAAe,EAAE,UAAU;iBAC5B,CAAC;gBACF,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBACzC,YAAY,IAAI,UAAU,CAAC;gBAC3B,SAAS;YACX,CAAC;YAED,QAAQ;YACR,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;YAEtD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACtC,GAAG,CAAC,GAAG,CACL,MAAM,EACN,kBAAkB,IAAI,CAAC,IAAI,cAAc,QAAQ,CAAC,MAAM,cAAc,UAAU,KAAK,CACtF,CAAC;YAEF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACnB,MAAM,EAAE,SAAS;gBACjB,QAAQ;gBACR,eAAe,EAAE,UAAU;aAC5B,CAAC;YACF,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YACzC,YAAY,IAAI,UAAU,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACtC,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,kBAAkB,IAAI,CAAC,IAAI,aAAa,YAAY,EAAE,CAAC,CAAC;YAEzE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACnB,MAAM,EAAE,OAAO;gBACf,QAAQ,EAAE,EAAE;gBACZ,KAAK,EAAE,YAAY;gBACnB,eAAe,EAAE,UAAU;aAC5B,CAAC;YACF,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YACzC,YAAY,IAAI,UAAU,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,oCAAoC;IACpC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE1B,cAAc;IACd,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5F,GAAG,CAAC,GAAG,CACL,MAAM,EACN,4BAA4B,cAAc,CAAC,MAAM,WAAW,aAAa,cAAc,YAAY,UAAU,CAC9G,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAChB,IAAoB,EACpB,GAAkB,EAClB,OAAe,EACf,GAAqB;IAErB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,kBAAkB,IAAI,CAAC,IAAI,mBAAmB,GAAG,EAAE,CAAC,CAAC;QACrE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAmC;IAC3D,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,EAAE,CAAC;QACxC,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Bandit plugin — Python security analysis (auto-detect).
3
+ *
4
+ * Scans Python code for common security issues.
5
+ * Activates when Python files are detected.
6
+ *
7
+ * Uses ExecutionContext for DI instead of direct child_process.
8
+ */
9
+ import type { FindingSeverity, ReviewFinding } from '../../types.js';
10
+ import type { RawToolOutput, ToolDefinition } from '../types.js';
11
+ /**
12
+ * Map Bandit severity to GHAGGA FindingSeverity.
13
+ * HIGH→high, MEDIUM→medium, LOW→low, default→info
14
+ */
15
+ export declare function mapBanditSeverity(banditSeverity: string): FindingSeverity;
16
+ /**
17
+ * Parse Bandit JSON output into ReviewFinding[].
18
+ * Exported for direct testing with fixture data.
19
+ */
20
+ export declare function parseBanditOutput(raw: RawToolOutput, repoDir: string): ReviewFinding[];
21
+ export declare const banditPlugin: ToolDefinition;
22
+ //# sourceMappingURL=bandit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bandit.d.ts","sourceRoot":"","sources":["../../../src/tools/plugins/bandit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAoB,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAInF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,eAAe,CAWzE;AAcD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAiBtF;AAED,eAAO,MAAM,YAAY,EAAE,cAuC1B,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Bandit plugin — Python security analysis (auto-detect).
3
+ *
4
+ * Scans Python code for common security issues.
5
+ * Activates when Python files are detected.
6
+ *
7
+ * Uses ExecutionContext for DI instead of direct child_process.
8
+ */
9
+ const BANDIT_VERSION = '1.8.3';
10
+ /**
11
+ * Map Bandit severity to GHAGGA FindingSeverity.
12
+ * HIGH→high, MEDIUM→medium, LOW→low, default→info
13
+ */
14
+ export function mapBanditSeverity(banditSeverity) {
15
+ switch (banditSeverity.toUpperCase()) {
16
+ case 'HIGH':
17
+ return 'high';
18
+ case 'MEDIUM':
19
+ return 'medium';
20
+ case 'LOW':
21
+ return 'low';
22
+ default:
23
+ return 'info';
24
+ }
25
+ }
26
+ /**
27
+ * Parse Bandit JSON output into ReviewFinding[].
28
+ * Exported for direct testing with fixture data.
29
+ */
30
+ export function parseBanditOutput(raw, repoDir) {
31
+ if (raw.timedOut)
32
+ return [];
33
+ try {
34
+ const result = JSON.parse(raw.stdout);
35
+ return (result.results ?? []).map((r) => ({
36
+ severity: mapBanditSeverity(r.issue_severity),
37
+ category: 'security',
38
+ file: r.filename.replace(`${repoDir}/`, ''),
39
+ line: r.line_number,
40
+ message: `${r.test_id}: ${r.issue_text} (confidence: ${r.issue_confidence})`,
41
+ source: 'bandit',
42
+ }));
43
+ }
44
+ catch {
45
+ return [];
46
+ }
47
+ }
48
+ export const banditPlugin = {
49
+ name: 'bandit',
50
+ displayName: 'Bandit',
51
+ category: 'security',
52
+ tier: 'auto-detect',
53
+ version: BANDIT_VERSION,
54
+ outputFormat: 'json',
55
+ detect(files) {
56
+ return files.some((f) => f.endsWith('.py'));
57
+ },
58
+ async install(ctx) {
59
+ try {
60
+ await ctx.exec('bandit', ['--version'], { timeoutMs: 10_000 });
61
+ return;
62
+ }
63
+ catch {
64
+ ctx.log('info', 'Bandit not found, installing...');
65
+ }
66
+ await ctx.exec('pip', ['install', '--quiet', `bandit==${BANDIT_VERSION}`], {
67
+ timeoutMs: 120_000,
68
+ });
69
+ await ctx.exec('bandit', ['--version'], { timeoutMs: 10_000 });
70
+ },
71
+ async run(ctx, repoDir, _files, timeout) {
72
+ return ctx.exec('bandit', ['-r', repoDir, '-f', 'json', '--quiet'], {
73
+ timeoutMs: timeout,
74
+ allowExitCodes: [1], // bandit returns 1 when findings are present
75
+ });
76
+ },
77
+ parse: parseBanditOutput,
78
+ };
79
+ //# sourceMappingURL=bandit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bandit.js","sourceRoot":"","sources":["../../../src/tools/plugins/bandit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,cAAsB;IACtD,QAAQ,cAAc,CAAC,WAAW,EAAE,EAAE,CAAC;QACrC,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf;YACE,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC;AAcD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAkB,EAAE,OAAe;IACnE,IAAI,GAAG,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAE5B,IAAI,CAAC;QACH,MAAM,MAAM,GAAiB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEpD,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxC,QAAQ,EAAE,iBAAiB,CAAC,CAAC,CAAC,cAAc,CAAC;YAC7C,QAAQ,EAAE,UAAU;YACpB,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,EAAE,EAAE,CAAC;YAC3C,IAAI,EAAE,CAAC,CAAC,WAAW;YACnB,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,UAAU,iBAAiB,CAAC,CAAC,gBAAgB,GAAG;YAC5E,MAAM,EAAE,QAAiB;SAC1B,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAmB;IAC1C,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,cAAc;IACvB,YAAY,EAAE,MAAM;IAEpB,MAAM,CAAC,KAAe;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAqB;QACjC,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,cAAc,EAAE,CAAC,EAAE;YACzE,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;QACH,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,GAAG,CACP,GAAqB,EACrB,OAAe,EACf,MAAgB,EAChB,OAAe;QAEf,OAAO,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE;YAClE,SAAS,EAAE,OAAO;YAClB,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,6CAA6C;SACnE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,EAAE,iBAAiB;CACzB,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Biome plugin — JavaScript/TypeScript linting (auto-detect).
3
+ *
4
+ * Fast linter and formatter for JS/TS. Activates when JS/TS files are detected.
5
+ * Maps diagnostic severity to FindingSeverity.
6
+ *
7
+ * Uses ExecutionContext for DI instead of direct child_process.
8
+ */
9
+ import type { FindingSeverity, ReviewFinding } from '../../types.js';
10
+ import type { RawToolOutput, ToolDefinition } from '../types.js';
11
+ /**
12
+ * Map Biome diagnostic severity to GHAGGA FindingSeverity.
13
+ * error→high, warning→medium, information→low, hint→info
14
+ */
15
+ export declare function mapBiomeSeverity(severity: string): FindingSeverity;
16
+ /**
17
+ * Parse Biome JSON output into ReviewFinding[].
18
+ * Exported for direct testing with fixture data.
19
+ */
20
+ export declare function parseBiomeOutput(raw: RawToolOutput, repoDir: string): ReviewFinding[];
21
+ export declare const biomePlugin: ToolDefinition;
22
+ //# sourceMappingURL=biome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome.d.ts","sourceRoot":"","sources":["../../../src/tools/plugins/biome.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAoB,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAInF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAalE;AAoBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAgBrF;AAED,eAAO,MAAM,WAAW,EAAE,cAuCzB,CAAC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Biome plugin — JavaScript/TypeScript linting (auto-detect).
3
+ *
4
+ * Fast linter and formatter for JS/TS. Activates when JS/TS files are detected.
5
+ * Maps diagnostic severity to FindingSeverity.
6
+ *
7
+ * Uses ExecutionContext for DI instead of direct child_process.
8
+ */
9
+ const BIOME_VERSION = '1.9.4';
10
+ /**
11
+ * Map Biome diagnostic severity to GHAGGA FindingSeverity.
12
+ * error→high, warning→medium, information→low, hint→info
13
+ */
14
+ export function mapBiomeSeverity(severity) {
15
+ switch (severity.toLowerCase()) {
16
+ case 'error':
17
+ return 'high';
18
+ case 'warning':
19
+ return 'medium';
20
+ case 'information':
21
+ return 'low';
22
+ case 'hint':
23
+ return 'info';
24
+ default:
25
+ return 'low';
26
+ }
27
+ }
28
+ /**
29
+ * Parse Biome JSON output into ReviewFinding[].
30
+ * Exported for direct testing with fixture data.
31
+ */
32
+ export function parseBiomeOutput(raw, repoDir) {
33
+ if (raw.timedOut)
34
+ return [];
35
+ try {
36
+ const result = JSON.parse(raw.stdout);
37
+ return (result.diagnostics ?? []).map((d) => ({
38
+ severity: mapBiomeSeverity(d.severity),
39
+ category: 'quality',
40
+ file: d.location.path.file.replace(`${repoDir}/`, ''),
41
+ message: `${d.category}: ${d.description}`,
42
+ source: 'biome',
43
+ }));
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ }
49
+ export const biomePlugin = {
50
+ name: 'biome',
51
+ displayName: 'Biome',
52
+ category: 'quality',
53
+ tier: 'auto-detect',
54
+ version: BIOME_VERSION,
55
+ outputFormat: 'json',
56
+ detect(files) {
57
+ return files.some((f) => /\.(ts|js|tsx|jsx|mts|mjs|cts|cjs)$/.test(f));
58
+ },
59
+ async install(ctx) {
60
+ try {
61
+ await ctx.exec('biome', ['--version'], { timeoutMs: 10_000 });
62
+ return;
63
+ }
64
+ catch {
65
+ ctx.log('info', 'Biome not found, installing...');
66
+ }
67
+ await ctx.exec('npm', ['install', '-g', `@biomejs/biome@${BIOME_VERSION}`], {
68
+ timeoutMs: 120_000,
69
+ });
70
+ await ctx.exec('biome', ['--version'], { timeoutMs: 10_000 });
71
+ },
72
+ async run(ctx, repoDir, _files, timeout) {
73
+ return ctx.exec('biome', ['lint', '--reporter', 'json', repoDir], {
74
+ timeoutMs: timeout,
75
+ allowExitCodes: [1], // biome returns 1 when findings are present
76
+ });
77
+ },
78
+ parse: parseBiomeOutput,
79
+ };
80
+ //# sourceMappingURL=biome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"biome.js","sourceRoot":"","sources":["../../../src/tools/plugins/biome.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,aAAa,GAAG,OAAO,CAAC;AAE9B;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,QAAQ,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QAC/B,KAAK,OAAO;YACV,OAAO,MAAM,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,QAAQ,CAAC;QAClB,KAAK,aAAa;YAChB,OAAO,KAAK,CAAC;QACf,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAoBD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAkB,EAAE,OAAe;IAClE,IAAI,GAAG,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAE5B,IAAI,CAAC;QACH,MAAM,MAAM,GAAgB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEnD,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5C,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC;YACtC,QAAQ,EAAE,SAAS;YACnB,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,EAAE,EAAE,CAAC;YACrD,OAAO,EAAE,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,WAAW,EAAE;YAC1C,MAAM,EAAE,OAAgB;SACzB,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAmB;IACzC,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,OAAO;IACpB,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,aAAa;IACnB,OAAO,EAAE,aAAa;IACtB,YAAY,EAAE,MAAM;IAEpB,MAAM,CAAC,KAAe;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oCAAoC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAqB;QACjC,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,gCAAgC,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,kBAAkB,aAAa,EAAE,CAAC,EAAE;YAC1E,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;QACH,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,GAAG,CACP,GAAqB,EACrB,OAAe,EACf,MAAgB,EAChB,OAAe;QAEf,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;YAChE,SAAS,EAAE,OAAO;YAClB,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,4CAA4C;SAClE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,EAAE,gBAAgB;CACxB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Clippy plugin — Rust linting (auto-detect).
3
+ *
4
+ * Runs cargo clippy for Rust code analysis.
5
+ * Activates when Cargo.toml or .rs files are detected.
6
+ * Parses line-delimited JSON (compiler messages).
7
+ *
8
+ * Uses ExecutionContext for DI instead of direct child_process.
9
+ */
10
+ import type { FindingSeverity, ReviewFinding } from '../../types.js';
11
+ import type { RawToolOutput, ToolDefinition } from '../types.js';
12
+ /**
13
+ * Map Rust compiler message level to GHAGGA FindingSeverity.
14
+ * error→high, warning→medium, note→low, help→info
15
+ */
16
+ export declare function mapClippySeverity(level: string): FindingSeverity;
17
+ /**
18
+ * Parse Clippy line-delimited JSON output into ReviewFinding[].
19
+ * Each line is a separate JSON object (not a JSON array).
20
+ * Only includes compiler-message entries with spans.
21
+ * Exported for direct testing with fixture data.
22
+ */
23
+ export declare function parseClippyOutput(raw: RawToolOutput, repoDir: string): ReviewFinding[];
24
+ export declare const clippyPlugin: ToolDefinition;
25
+ //# sourceMappingURL=clippy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clippy.d.ts","sourceRoot":"","sources":["../../../src/tools/plugins/clippy.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAoB,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEnF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAahE;AAeD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAiCtF;AAED,eAAO,MAAM,YAAY,EAAE,cAsC1B,CAAC"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Clippy plugin — Rust linting (auto-detect).
3
+ *
4
+ * Runs cargo clippy for Rust code analysis.
5
+ * Activates when Cargo.toml or .rs files are detected.
6
+ * Parses line-delimited JSON (compiler messages).
7
+ *
8
+ * Uses ExecutionContext for DI instead of direct child_process.
9
+ */
10
+ /**
11
+ * Map Rust compiler message level to GHAGGA FindingSeverity.
12
+ * error→high, warning→medium, note→low, help→info
13
+ */
14
+ export function mapClippySeverity(level) {
15
+ switch (level.toLowerCase()) {
16
+ case 'error':
17
+ return 'high';
18
+ case 'warning':
19
+ return 'medium';
20
+ case 'note':
21
+ return 'low';
22
+ case 'help':
23
+ return 'info';
24
+ default:
25
+ return 'low';
26
+ }
27
+ }
28
+ /**
29
+ * Parse Clippy line-delimited JSON output into ReviewFinding[].
30
+ * Each line is a separate JSON object (not a JSON array).
31
+ * Only includes compiler-message entries with spans.
32
+ * Exported for direct testing with fixture data.
33
+ */
34
+ export function parseClippyOutput(raw, repoDir) {
35
+ if (raw.timedOut)
36
+ return [];
37
+ try {
38
+ const findings = [];
39
+ const lines = raw.stdout.trim().split('\n');
40
+ for (const line of lines) {
41
+ if (!line.trim())
42
+ continue;
43
+ const entry = JSON.parse(line);
44
+ // Only process compiler messages with spans
45
+ if (entry.reason !== 'compiler-message' || !entry.message?.spans?.length)
46
+ continue;
47
+ const msg = entry.message;
48
+ const span = msg.spans[0];
49
+ if (!span)
50
+ continue;
51
+ findings.push({
52
+ severity: mapClippySeverity(msg.level),
53
+ category: 'quality',
54
+ file: span.file_name.replace(`${repoDir}/`, ''),
55
+ line: span.line_start,
56
+ message: msg.message,
57
+ source: 'clippy',
58
+ });
59
+ }
60
+ return findings;
61
+ }
62
+ catch {
63
+ return [];
64
+ }
65
+ }
66
+ export const clippyPlugin = {
67
+ name: 'clippy',
68
+ displayName: 'Clippy',
69
+ category: 'quality',
70
+ tier: 'auto-detect',
71
+ version: 'toolchain',
72
+ outputFormat: 'json',
73
+ detect(files) {
74
+ return files.some((f) => f === 'Cargo.toml' || f.endsWith('.rs'));
75
+ },
76
+ async install(ctx) {
77
+ // Clippy comes with rustup — just verify cargo is available
78
+ try {
79
+ await ctx.exec('cargo', ['--version'], { timeoutMs: 10_000 });
80
+ return;
81
+ }
82
+ catch {
83
+ throw new Error('Rust toolchain (cargo) is not available. clippy requires a Rust installation.');
84
+ }
85
+ },
86
+ async run(ctx, repoDir, _files, timeout) {
87
+ return ctx.exec('cargo', ['clippy', '--message-format=json', '--', '-W', 'clippy::all'], {
88
+ timeoutMs: timeout,
89
+ cwd: repoDir,
90
+ allowExitCodes: [1, 101], // clippy may return non-zero on findings or compilation errors
91
+ });
92
+ },
93
+ parse: parseClippyOutput,
94
+ };
95
+ //# sourceMappingURL=clippy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clippy.js","sourceRoot":"","sources":["../../../src/tools/plugins/clippy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CPD plugin — duplication detection (always-on).
3
+ *
4
+ * Adapted from:
5
+ * - packages/core/src/tools/cpd.ts (parseCpdXml logic)
6
+ * - apps/action/src/tools/cpd.ts (install/run flow)
7
+ *
8
+ * Uses ExecutionContext for DI instead of direct child_process.
9
+ * CPD exits with code 4 when duplications are found — successExitCodes: [4].
10
+ */
11
+ import type { ReviewFinding } from '../../types.js';
12
+ import type { RawToolOutput, ToolDefinition } from '../types.js';
13
+ /**
14
+ * Parse CPD XML output into ReviewFinding[].
15
+ * Regex-based XML parsing — same logic as packages/core/src/tools/cpd.ts.
16
+ * Exported for direct testing with fixture data.
17
+ */
18
+ export declare function parseCpdOutput(raw: RawToolOutput, repoDir: string): ReviewFinding[];
19
+ export declare const cpdPlugin: ToolDefinition;
20
+ //# sourceMappingURL=cpd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cpd.d.ts","sourceRoot":"","sources":["../../../src/tools/plugins/cpd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAoB,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAMnF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CA8CnF;AAED,eAAO,MAAM,SAAS,EAAE,cA+DvB,CAAC"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * CPD plugin — duplication detection (always-on).
3
+ *
4
+ * Adapted from:
5
+ * - packages/core/src/tools/cpd.ts (parseCpdXml logic)
6
+ * - apps/action/src/tools/cpd.ts (install/run flow)
7
+ *
8
+ * Uses ExecutionContext for DI instead of direct child_process.
9
+ * CPD exits with code 4 when duplications are found — successExitCodes: [4].
10
+ */
11
+ const PMD_VERSION = '7.8.0';
12
+ const PMD_HOME = '/opt/pmd';
13
+ const PMD_BIN = `${PMD_HOME}/bin/pmd`;
14
+ /**
15
+ * Parse CPD XML output into ReviewFinding[].
16
+ * Regex-based XML parsing — same logic as packages/core/src/tools/cpd.ts.
17
+ * Exported for direct testing with fixture data.
18
+ */
19
+ export function parseCpdOutput(raw, repoDir) {
20
+ if (raw.timedOut)
21
+ return [];
22
+ const xml = raw.stdout;
23
+ if (!xml)
24
+ return [];
25
+ try {
26
+ const findings = [];
27
+ const dupRegex = /<duplication lines="(\d+)" tokens="(\d+)">([\s\S]*?)<\/duplication>/g;
28
+ const fileRegex = /<file\s+path="([^"]+)"\s+line="(\d+)"/g;
29
+ let dupMatch = dupRegex.exec(xml);
30
+ while (dupMatch !== null) {
31
+ const lines = parseInt(dupMatch[1] ?? '0', 10);
32
+ const tokens = parseInt(dupMatch[2] ?? '0', 10);
33
+ const inner = dupMatch[3] ?? '';
34
+ const files = [];
35
+ fileRegex.lastIndex = 0;
36
+ let fileMatch = fileRegex.exec(inner);
37
+ while (fileMatch !== null) {
38
+ files.push({
39
+ path: (fileMatch[1] ?? '').replace(`${repoDir}/`, ''),
40
+ line: parseInt(fileMatch[2] ?? '0', 10),
41
+ });
42
+ fileMatch = fileRegex.exec(inner);
43
+ }
44
+ if (files.length >= 2) {
45
+ const locations = files.map((f) => `${f.path}:${f.line}`).join(', ');
46
+ findings.push({
47
+ severity: 'medium',
48
+ category: 'duplication',
49
+ file: files[0]?.path,
50
+ line: files[0]?.line,
51
+ message: `Duplicated code block (${lines} lines, ${tokens} tokens) found in: ${locations}`,
52
+ source: 'cpd',
53
+ });
54
+ }
55
+ dupMatch = dupRegex.exec(xml);
56
+ }
57
+ return findings;
58
+ }
59
+ catch {
60
+ return [];
61
+ }
62
+ }
63
+ export const cpdPlugin = {
64
+ name: 'cpd',
65
+ displayName: 'PMD/CPD',
66
+ category: 'duplication',
67
+ tier: 'always-on',
68
+ version: PMD_VERSION,
69
+ outputFormat: 'xml',
70
+ cachePaths: [PMD_HOME],
71
+ successExitCodes: [4], // CPD returns 4 when duplications are found
72
+ async install(ctx) {
73
+ const cached = await ctx.cacheRestore('cpd', [PMD_HOME]);
74
+ if (cached) {
75
+ try {
76
+ await ctx.exec(PMD_BIN, ['--version'], { timeoutMs: 10_000 });
77
+ return;
78
+ }
79
+ catch {
80
+ ctx.log('warn', 'PMD cache restored but binary not functional, reinstalling');
81
+ }
82
+ }
83
+ // Download PMD zip from GitHub Releases and extract to /opt/pmd/
84
+ await ctx.exec('bash', [
85
+ '-c',
86
+ `curl -sL "https://github.com/pmd/pmd/releases/download/pmd_releases%2F${PMD_VERSION}/pmd-dist-${PMD_VERSION}-bin.zip" -o /tmp/pmd.zip && ` +
87
+ `unzip -q /tmp/pmd.zip -d /opt && ` +
88
+ `mv /opt/pmd-bin-${PMD_VERSION} ${PMD_HOME} && ` +
89
+ `rm -f /tmp/pmd.zip`,
90
+ ], { timeoutMs: 120_000 });
91
+ await ctx.exec(PMD_BIN, ['--version'], { timeoutMs: 10_000 });
92
+ await ctx.cacheSave('cpd', [PMD_HOME]);
93
+ },
94
+ async run(ctx, repoDir, _files, timeout) {
95
+ return ctx.exec(PMD_BIN, [
96
+ 'cpd',
97
+ '--format',
98
+ 'xml',
99
+ '--minimum-tokens',
100
+ '100',
101
+ '--dir',
102
+ repoDir,
103
+ '--skip-lexical-errors',
104
+ ], {
105
+ timeoutMs: timeout,
106
+ allowExitCodes: [4], // CPD returns 4 when duplications are found
107
+ });
108
+ },
109
+ parse: parseCpdOutput,
110
+ };
111
+ //# sourceMappingURL=cpd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cpd.js","sourceRoot":"","sources":["../../../src/tools/plugins/cpd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Gitleaks plugin — secret detection (always-on).
3
+ *
4
+ * Scans the repository for hardcoded secrets, API keys, and credentials.
5
+ * All secret findings are reported as critical severity.
6
+ *
7
+ * Uses ExecutionContext for DI instead of direct child_process.
8
+ */
9
+ import type { ReviewFinding } from '../../types.js';
10
+ import type { RawToolOutput, ToolDefinition } from '../types.js';
11
+ /**
12
+ * Parse Gitleaks JSON output into ReviewFinding[].
13
+ * Gitleaks writes results to a report file; we read from stdout or the report.
14
+ * Exported for direct testing with fixture data.
15
+ */
16
+ export declare function parseGitleaksOutput(raw: RawToolOutput, repoDir: string): ReviewFinding[];
17
+ export declare const gitleaksPlugin: ToolDefinition;
18
+ //# sourceMappingURL=gitleaks.d.ts.map