ghagga-core 2.6.0 → 2.8.0

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 (153) hide show
  1. package/dist/agents/consensus.d.ts +2 -0
  2. package/dist/agents/consensus.d.ts.map +1 -1
  3. package/dist/agents/consensus.js +1 -0
  4. package/dist/agents/consensus.js.map +1 -1
  5. package/dist/agents/diagnostic.d.ts +2 -0
  6. package/dist/agents/diagnostic.d.ts.map +1 -1
  7. package/dist/agents/diagnostic.js +1 -0
  8. package/dist/agents/diagnostic.js.map +1 -1
  9. package/dist/agents/fan-out-lenses.d.ts +92 -0
  10. package/dist/agents/fan-out-lenses.d.ts.map +1 -0
  11. package/dist/agents/fan-out-lenses.js +424 -0
  12. package/dist/agents/fan-out-lenses.js.map +1 -0
  13. package/dist/agents/simple.d.ts +2 -0
  14. package/dist/agents/simple.d.ts.map +1 -1
  15. package/dist/agents/simple.js +1 -0
  16. package/dist/agents/simple.js.map +1 -1
  17. package/dist/agents/workflow.d.ts +2 -0
  18. package/dist/agents/workflow.d.ts.map +1 -1
  19. package/dist/agents/workflow.js +2 -1
  20. package/dist/agents/workflow.js.map +1 -1
  21. package/dist/checklist/config.d.ts +22 -0
  22. package/dist/checklist/config.d.ts.map +1 -0
  23. package/dist/checklist/config.js +85 -0
  24. package/dist/checklist/config.js.map +1 -0
  25. package/dist/checklist/context.d.ts +22 -0
  26. package/dist/checklist/context.d.ts.map +1 -0
  27. package/dist/checklist/context.js +76 -0
  28. package/dist/checklist/context.js.map +1 -0
  29. package/dist/checklist/defaults.d.ts +12 -0
  30. package/dist/checklist/defaults.d.ts.map +1 -0
  31. package/dist/checklist/defaults.js +172 -0
  32. package/dist/checklist/defaults.js.map +1 -0
  33. package/dist/checklist/index.d.ts +14 -0
  34. package/dist/checklist/index.d.ts.map +1 -0
  35. package/dist/checklist/index.js +15 -0
  36. package/dist/checklist/index.js.map +1 -0
  37. package/dist/checklist/scorer.d.ts +58 -0
  38. package/dist/checklist/scorer.d.ts.map +1 -0
  39. package/dist/checklist/scorer.js +142 -0
  40. package/dist/checklist/scorer.js.map +1 -0
  41. package/dist/checklist/types.d.ts +39 -0
  42. package/dist/checklist/types.d.ts.map +1 -0
  43. package/dist/checklist/types.js +17 -0
  44. package/dist/checklist/types.js.map +1 -0
  45. package/dist/exploitability/analyzer.d.ts +75 -0
  46. package/dist/exploitability/analyzer.d.ts.map +1 -0
  47. package/dist/exploitability/analyzer.js +299 -0
  48. package/dist/exploitability/analyzer.js.map +1 -0
  49. package/dist/exploitability/index.d.ts +10 -0
  50. package/dist/exploitability/index.d.ts.map +1 -0
  51. package/dist/exploitability/index.js +10 -0
  52. package/dist/exploitability/index.js.map +1 -0
  53. package/dist/exploitability/types.d.ts +32 -0
  54. package/dist/exploitability/types.d.ts.map +1 -0
  55. package/dist/exploitability/types.js +9 -0
  56. package/dist/exploitability/types.js.map +1 -0
  57. package/dist/index.d.ts +15 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +9 -2
  60. package/dist/index.js.map +1 -1
  61. package/dist/memory/context.d.ts +2 -0
  62. package/dist/memory/context.d.ts.map +1 -1
  63. package/dist/memory/context.js +2 -1
  64. package/dist/memory/context.js.map +1 -1
  65. package/dist/memory/contradiction.d.ts +46 -0
  66. package/dist/memory/contradiction.d.ts.map +1 -0
  67. package/dist/memory/contradiction.js +110 -0
  68. package/dist/memory/contradiction.js.map +1 -0
  69. package/dist/memory/decay.d.ts +25 -0
  70. package/dist/memory/decay.d.ts.map +1 -0
  71. package/dist/memory/decay.js +51 -0
  72. package/dist/memory/decay.js.map +1 -0
  73. package/dist/memory/search.d.ts.map +1 -1
  74. package/dist/memory/search.js +1 -0
  75. package/dist/memory/search.js.map +1 -1
  76. package/dist/memory/sqlite.d.ts +21 -0
  77. package/dist/memory/sqlite.d.ts.map +1 -1
  78. package/dist/memory/sqlite.js +82 -7
  79. package/dist/memory/sqlite.js.map +1 -1
  80. package/dist/memory/versioning.d.ts +94 -0
  81. package/dist/memory/versioning.d.ts.map +1 -0
  82. package/dist/memory/versioning.js +350 -0
  83. package/dist/memory/versioning.js.map +1 -0
  84. package/dist/pipeline.d.ts.map +1 -1
  85. package/dist/pipeline.js +117 -0
  86. package/dist/pipeline.js.map +1 -1
  87. package/dist/providers/index.d.ts.map +1 -1
  88. package/dist/providers/index.js +7 -2
  89. package/dist/providers/index.js.map +1 -1
  90. package/dist/recursive/index.d.ts +45 -0
  91. package/dist/recursive/index.d.ts.map +1 -0
  92. package/dist/recursive/index.js +159 -0
  93. package/dist/recursive/index.js.map +1 -0
  94. package/dist/recursive/patch-extractor.d.ts +49 -0
  95. package/dist/recursive/patch-extractor.d.ts.map +1 -0
  96. package/dist/recursive/patch-extractor.js +133 -0
  97. package/dist/recursive/patch-extractor.js.map +1 -0
  98. package/dist/recursive/re-reviewer.d.ts +31 -0
  99. package/dist/recursive/re-reviewer.d.ts.map +1 -0
  100. package/dist/recursive/re-reviewer.js +66 -0
  101. package/dist/recursive/re-reviewer.js.map +1 -0
  102. package/dist/recursive/types.d.ts +62 -0
  103. package/dist/recursive/types.d.ts.map +1 -0
  104. package/dist/recursive/types.js +11 -0
  105. package/dist/recursive/types.js.map +1 -0
  106. package/dist/scope/context-builder.d.ts +37 -0
  107. package/dist/scope/context-builder.d.ts.map +1 -0
  108. package/dist/scope/context-builder.js +108 -0
  109. package/dist/scope/context-builder.js.map +1 -0
  110. package/dist/scope/diff-mapper.d.ts +29 -0
  111. package/dist/scope/diff-mapper.d.ts.map +1 -0
  112. package/dist/scope/diff-mapper.js +76 -0
  113. package/dist/scope/diff-mapper.js.map +1 -0
  114. package/dist/scope/extractor.d.ts +25 -0
  115. package/dist/scope/extractor.d.ts.map +1 -0
  116. package/dist/scope/extractor.js +264 -0
  117. package/dist/scope/extractor.js.map +1 -0
  118. package/dist/scope/index.d.ts +13 -0
  119. package/dist/scope/index.d.ts.map +1 -0
  120. package/dist/scope/index.js +16 -0
  121. package/dist/scope/index.js.map +1 -0
  122. package/dist/scope/parser.d.ts +47 -0
  123. package/dist/scope/parser.d.ts.map +1 -0
  124. package/dist/scope/parser.js +97 -0
  125. package/dist/scope/parser.js.map +1 -0
  126. package/dist/scope/queries.d.ts +23 -0
  127. package/dist/scope/queries.d.ts.map +1 -0
  128. package/dist/scope/queries.js +134 -0
  129. package/dist/scope/queries.js.map +1 -0
  130. package/dist/scope/types.d.ts +55 -0
  131. package/dist/scope/types.d.ts.map +1 -0
  132. package/dist/scope/types.js +8 -0
  133. package/dist/scope/types.js.map +1 -0
  134. package/dist/tools/execution.d.ts.map +1 -1
  135. package/dist/tools/execution.js +2 -0
  136. package/dist/tools/execution.js.map +1 -1
  137. package/dist/tools/plugins/index.d.ts +1 -0
  138. package/dist/tools/plugins/index.d.ts.map +1 -1
  139. package/dist/tools/plugins/index.js +6 -5
  140. package/dist/tools/plugins/index.js.map +1 -1
  141. package/dist/tools/plugins/sonarqube.d.ts +54 -0
  142. package/dist/tools/plugins/sonarqube.d.ts.map +1 -0
  143. package/dist/tools/plugins/sonarqube.js +145 -0
  144. package/dist/tools/plugins/sonarqube.js.map +1 -0
  145. package/dist/tools/plugins/trivy.js +1 -1
  146. package/dist/tools/plugins/trivy.js.map +1 -1
  147. package/dist/tools/types.d.ts +7 -1
  148. package/dist/tools/types.d.ts.map +1 -1
  149. package/dist/types.d.ts +80 -1
  150. package/dist/types.d.ts.map +1 -1
  151. package/dist/types.js +9 -0
  152. package/dist/types.js.map +1 -1
  153. package/package.json +3 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../../src/checklist/scorer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,KAAK,EAAkB,eAAe,EAAsB,MAAM,YAAY,CAAC;AAItF,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IAErB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IAEpB,4FAA4F;IAC5F,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IAEpB,uCAAuC;IACvC,kBAAkB,EAAE,MAAM,CAAC;IAE3B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IAEnB,4EAA4E;IAC5E,QAAQ,EAAE,aAAa,EAAE,CAAC;IAE1B,mCAAmC;IACnC,eAAe,EAAE,cAAc,EAAE,CAAC;CACnC;AAED,4CAA4C;AAC5C,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AA+CD,gDAAgD;AAChD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,SAAS,eAAe,EAAE,EACpC,MAAM,EAAE,eAAe,GACtB,oBAAoB,CAuDtB"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Checklist scoring engine — evaluates review findings against weighted checks.
3
+ *
4
+ * Maps each finding to the most relevant checklist dimension/check using
5
+ * keyword matching, then produces a weighted score sorted by severity.
6
+ */
7
+ import { SEVERITY_MULTIPLIER } from './types.js';
8
+ // ─── Keyword Maps ─────────────────────────────────────────────
9
+ /**
10
+ * Keywords that map finding categories/messages to dimension IDs.
11
+ * Checked in order: first match wins.
12
+ */
13
+ const DIMENSION_KEYWORDS = new Map([
14
+ ['solid', ['solid', 'single responsibility', 'srp', 'open closed', 'ocp', 'liskov', 'lsp', 'interface segregation', 'isp', 'dependency inversion', 'dip', 'coupling', 'cohesion', 'god class', 'fat interface']],
15
+ ['error-handling', ['error', 'exception', 'catch', 'throw', 'try', 'finally', 'unhandled', 'silent failure', 'swallow', 'propagat']],
16
+ ['boundary-conditions', ['boundary', 'null', 'undefined', 'empty', 'overflow', 'underflow', 'division by zero', 'nan', 'unicode', 'encoding', 'race condition', 'concurrent', 'off-by-one']],
17
+ ['security', ['security', 'injection', 'xss', 'csrf', 'auth', 'token', 'password', 'secret', 'credential', 'sensitive', 'sanitiz', 'validat', 'vulnerab', 'cve', 'exploit']],
18
+ ]);
19
+ /**
20
+ * Keywords that map to specific check IDs within a dimension.
21
+ */
22
+ const CHECK_KEYWORDS = new Map([
23
+ // SOLID
24
+ ['single-responsibility', ['single responsibility', 'srp', 'one reason to change', 'god class', 'too many responsibilities']],
25
+ ['open-closed', ['open closed', 'ocp', 'open for extension', 'closed for modification']],
26
+ ['liskov-substitution', ['liskov', 'lsp', 'substitut', 'subtype', 'base type']],
27
+ ['interface-segregation', ['interface segregation', 'isp', 'fat interface', 'too many methods']],
28
+ ['dependency-inversion', ['dependency inversion', 'dip', 'depend on abstraction', 'concrete dependency', 'coupling']],
29
+ // Error handling
30
+ ['error-propagation', ['error propagat', 'error context', 'wrap error', 'error chain']],
31
+ ['error-recovery', ['error recovery', 'graceful', 'fallback', 'retry', 'degrad']],
32
+ ['error-types', ['error type', 'specific error', 'generic error', 'custom error']],
33
+ ['silent-failures', ['silent', 'swallow', 'empty catch', 'ignore error']],
34
+ ['async-error-handling', ['async error', 'promise', 'unhandled rejection', 'await', '.catch']],
35
+ // Boundary conditions
36
+ ['null-undefined', ['null', 'undefined', 'nil', 'optional', 'nullable', 'nullish']],
37
+ ['empty-collections', ['empty array', 'empty list', 'empty map', 'empty string', 'length 0', 'size 0']],
38
+ ['numeric-limits', ['overflow', 'underflow', 'division by zero', 'nan', 'infinity', 'max safe integer']],
39
+ ['string-encoding', ['unicode', 'utf', 'encoding', 'multi-byte', 'special character']],
40
+ ['concurrency-bounds', ['race condition', 'concurrent', 'mutex', 'lock', 'deadlock', 'thread safe']],
41
+ // Security
42
+ ['input-validation', ['input validat', 'sanitiz', 'untrusted input', 'user input']],
43
+ ['auth-checks', ['auth', 'authentication', 'authorization', 'permission', 'access control']],
44
+ ['sensitive-data', ['sensitive data', 'password', 'token', 'secret', 'pii', 'credential', 'api key']],
45
+ ['injection-prevention', ['injection', 'xss', 'sql inject', 'command inject', 'path traversal']],
46
+ ['dependency-safety', ['dependency', 'vulnerab', 'cve', 'outdated', 'known vulnerab']],
47
+ ]);
48
+ // ─── Scoring ──────────────────────────────────────────────────
49
+ /**
50
+ * Score an array of findings against a resolved checklist configuration.
51
+ *
52
+ * Each finding is matched to the most relevant dimension and check
53
+ * using keyword analysis of its category and message fields.
54
+ * Unmatched findings are excluded from the score.
55
+ *
56
+ * @param findings - Array of findings to score
57
+ * @param config - Resolved checklist configuration (must be non-null and enabled)
58
+ * @returns Scored results sorted by weighted score descending
59
+ */
60
+ export function scoreFindings(findings, config) {
61
+ const activeDimensions = config.dimensions.filter((d) => d.enabled);
62
+ if (activeDimensions.length === 0) {
63
+ return { totalScore: 0, findings: [], dimensionScores: [] };
64
+ }
65
+ const scored = [];
66
+ for (let i = 0; i < findings.length; i++) {
67
+ const finding = findings[i];
68
+ const match = matchFinding(finding, activeDimensions);
69
+ if (!match)
70
+ continue;
71
+ const severityMultiplier = SEVERITY_MULTIPLIER[finding.severity] ?? 1;
72
+ const score = match.weight * severityMultiplier;
73
+ scored.push({
74
+ findingIndex: i,
75
+ dimensionId: match.dimensionId,
76
+ checkId: match.checkId,
77
+ checkWeight: match.weight,
78
+ severityMultiplier,
79
+ score,
80
+ });
81
+ }
82
+ // Sort by score descending (highest severity first)
83
+ scored.sort((a, b) => b.score - a.score);
84
+ // Build dimension summaries
85
+ const dimMap = new Map();
86
+ for (const dim of activeDimensions) {
87
+ dimMap.set(dim.id, {
88
+ dimensionId: dim.id,
89
+ dimensionName: dim.name,
90
+ totalScore: 0,
91
+ findingCount: 0,
92
+ });
93
+ }
94
+ for (const sf of scored) {
95
+ const ds = dimMap.get(sf.dimensionId);
96
+ if (ds) {
97
+ ds.totalScore += sf.score;
98
+ ds.findingCount += 1;
99
+ }
100
+ }
101
+ const dimensionScores = Array.from(dimMap.values())
102
+ .filter((ds) => ds.findingCount > 0)
103
+ .sort((a, b) => b.totalScore - a.totalScore);
104
+ const totalScore = scored.reduce((sum, sf) => sum + sf.score, 0);
105
+ return { totalScore, findings: scored, dimensionScores };
106
+ }
107
+ const DEFAULT_DIMENSION_WEIGHT = 5;
108
+ /**
109
+ * Match a finding to the best dimension and check using keyword analysis.
110
+ * Returns null if no dimension matches.
111
+ */
112
+ function matchFinding(finding, dimensions) {
113
+ const text = `${finding.category} ${finding.message}`.toLowerCase();
114
+ // Try to match a specific check first (more precise)
115
+ for (const dim of dimensions) {
116
+ if (!dim.enabled)
117
+ continue;
118
+ const activeChecks = dim.checks.filter((c) => c.enabled);
119
+ for (const check of activeChecks) {
120
+ const keywords = CHECK_KEYWORDS.get(check.id);
121
+ if (keywords && keywords.some((kw) => text.includes(kw))) {
122
+ return { dimensionId: dim.id, checkId: check.id, weight: check.weight };
123
+ }
124
+ }
125
+ }
126
+ // Fallback: match at dimension level
127
+ for (const dim of dimensions) {
128
+ if (!dim.enabled)
129
+ continue;
130
+ const keywords = DIMENSION_KEYWORDS.get(dim.id);
131
+ if (keywords && keywords.some((kw) => text.includes(kw))) {
132
+ // Use average weight of active checks in this dimension
133
+ const activeChecks = dim.checks.filter((c) => c.enabled);
134
+ const avgWeight = activeChecks.length > 0
135
+ ? Math.round(activeChecks.reduce((s, c) => s + c.weight, 0) / activeChecks.length)
136
+ : DEFAULT_DIMENSION_WEIGHT;
137
+ return { dimensionId: dim.id, checkId: null, weight: avgWeight };
138
+ }
139
+ }
140
+ return null;
141
+ }
142
+ //# sourceMappingURL=scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scorer.js","sourceRoot":"","sources":["../../src/checklist/scorer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Checklist types — configurable review dimensions with weighted checks.
3
+ *
4
+ * Each dimension (e.g., SOLID, error handling) contains named checks
5
+ * that guide AI agents during code review. Checks have weights (1-10)
6
+ * used for severity scoring.
7
+ */
8
+ /** A single review check within a dimension. */
9
+ export interface ChecklistCheck {
10
+ /** Unique kebab-case identifier (e.g., "single-responsibility") */
11
+ id: string;
12
+ /** Human-readable question the AI should evaluate (e.g., "Does this class have one reason to change?") */
13
+ description: string;
14
+ /** Importance weight (1-10). Higher = more severe when violated. */
15
+ weight: number;
16
+ /** Whether this check is active. Default: true. */
17
+ enabled: boolean;
18
+ }
19
+ /** A review dimension grouping related checks. */
20
+ export interface ChecklistDimension {
21
+ /** Unique kebab-case identifier (e.g., "solid", "error-handling") */
22
+ id: string;
23
+ /** Human-readable name (e.g., "SOLID Principles") */
24
+ name: string;
25
+ /** Whether this dimension is active. Default: true. */
26
+ enabled: boolean;
27
+ /** Ordered list of checks in this dimension. */
28
+ checks: ChecklistCheck[];
29
+ }
30
+ /** Top-level checklist configuration. */
31
+ export interface ChecklistConfig {
32
+ /** Master switch. When false, checklist is skipped entirely. */
33
+ enabled: boolean;
34
+ /** Review dimensions with their checks. */
35
+ dimensions: ChecklistDimension[];
36
+ }
37
+ /** Multipliers for finding severity when computing weighted scores. */
38
+ export declare const SEVERITY_MULTIPLIER: Record<string, number>;
39
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/checklist/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IAEX,0GAA0G;IAC1G,WAAW,EAAE,MAAM,CAAC;IAEpB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IAEf,mDAAmD;IACnD,OAAO,EAAE,OAAO,CAAC;CAClB;AAID,kDAAkD;AAClD,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IAEX,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IAEb,uDAAuD;IACvD,OAAO,EAAE,OAAO,CAAC;IAEjB,gDAAgD;IAChD,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAID,yCAAyC;AACzC,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IAEjB,2CAA2C;IAC3C,UAAU,EAAE,kBAAkB,EAAE,CAAC;CAClC;AAID,uEAAuE;AACvE,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMtD,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Checklist types — configurable review dimensions with weighted checks.
3
+ *
4
+ * Each dimension (e.g., SOLID, error handling) contains named checks
5
+ * that guide AI agents during code review. Checks have weights (1-10)
6
+ * used for severity scoring.
7
+ */
8
+ // ─── Severity Multipliers ──────────────────────────────────────
9
+ /** Multipliers for finding severity when computing weighted scores. */
10
+ export const SEVERITY_MULTIPLIER = {
11
+ critical: 5,
12
+ high: 3,
13
+ medium: 2,
14
+ low: 1,
15
+ info: 0.5,
16
+ };
17
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/checklist/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA+CH,kEAAkE;AAElE,uEAAuE;AACvE,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IACzD,QAAQ,EAAE,CAAC;IACX,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,GAAG;CACV,CAAC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Exploitability Analyzer
3
+ *
4
+ * Determines whether CVE findings from Trivy are actually exploitable
5
+ * by checking if the vulnerable package is imported and reachable
6
+ * from the project's entry points.
7
+ *
8
+ * Analysis flow:
9
+ * 1. Extract package names from Trivy CVE findings
10
+ * 2. Trace which project files import each vulnerable package
11
+ * 3. Find entry points (files with no importers)
12
+ * 4. BFS forward from entry points to check reachability
13
+ * 5. Label each finding based on reachability
14
+ */
15
+ import type { DependencyGraph } from '../graph/schema.js';
16
+ import type { ReviewFinding } from '../types.js';
17
+ /**
18
+ * Extract unique vulnerable package names from Trivy CVE findings.
19
+ *
20
+ * Only processes findings with source === 'trivy' and
21
+ * category === 'dependency-vulnerability'.
22
+ *
23
+ * @param findings - All review findings
24
+ * @returns Map of package name → array of finding indices that reference it
25
+ */
26
+ export declare function extractVulnPackages(findings: ReviewFinding[]): Map<string, number[]>;
27
+ /**
28
+ * Find which project files import a given external package.
29
+ *
30
+ * Searches the DependencyGraph for nodes whose `imports` array
31
+ * contains the package name (non-relative imports that match).
32
+ *
33
+ * @param graph - The project's dependency graph
34
+ * @param packageName - External package name (e.g., "lodash", "@angular/core")
35
+ * @returns Array of file paths that import the package
36
+ */
37
+ export declare function tracePackageImports(graph: DependencyGraph, packageName: string): string[];
38
+ /**
39
+ * Find entry point files in the dependency graph.
40
+ *
41
+ * An entry point is a non-test file that is NOT imported by any other
42
+ * project file. These are the "roots" of the dependency tree.
43
+ *
44
+ * @param graph - The project's dependency graph
45
+ * @returns Array of file paths that are entry points
46
+ */
47
+ export declare function findEntryPoints(graph: DependencyGraph): string[];
48
+ /**
49
+ * Check if any of the import sites are reachable from entry points
50
+ * via forward BFS through the dependency graph.
51
+ *
52
+ * Forward traversal: follows import edges from entry points outward.
53
+ *
54
+ * @param graph - The project's dependency graph
55
+ * @param entryPoints - Root files (no importers)
56
+ * @param importSites - Files that import the vulnerable package
57
+ * @returns Map of import site → entry points that can reach it
58
+ */
59
+ export declare function checkReachability(graph: DependencyGraph, entryPoints: string[], importSites: string[]): Map<string, string[]>;
60
+ /**
61
+ * Analyze exploitability of CVE findings from Trivy.
62
+ *
63
+ * Enriches each Trivy vulnerability finding with an exploitability
64
+ * label and detail based on import reachability analysis.
65
+ *
66
+ * Degrades gracefully:
67
+ * - No graph → all CVEs labeled `potentially-exploitable`
68
+ * - No CVE findings → returns findings unchanged (no-op)
69
+ *
70
+ * @param findings - All review findings (will mutate Trivy CVE findings in place)
71
+ * @param graph - The project's dependency graph (null if unavailable)
72
+ * @returns The same findings array with exploitability fields added to CVE findings
73
+ */
74
+ export declare function analyzeExploitability(findings: ReviewFinding[], graph: DependencyGraph | null): ReviewFinding[];
75
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/exploitability/analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBjD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAyBpF;AAID;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBzF;AAID;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,EAAE,CAsBhE;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,MAAM,EAAE,GACpB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA8CvB;AAoDD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,aAAa,EAAE,EACzB,KAAK,EAAE,eAAe,GAAG,IAAI,GAC5B,aAAa,EAAE,CAqFjB"}
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Exploitability Analyzer
3
+ *
4
+ * Determines whether CVE findings from Trivy are actually exploitable
5
+ * by checking if the vulnerable package is imported and reachable
6
+ * from the project's entry points.
7
+ *
8
+ * Analysis flow:
9
+ * 1. Extract package names from Trivy CVE findings
10
+ * 2. Trace which project files import each vulnerable package
11
+ * 3. Find entry points (files with no importers)
12
+ * 4. BFS forward from entry points to check reachability
13
+ * 5. Label each finding based on reachability
14
+ */
15
+ // ─── Package Extraction ────────────────────────────────────────
16
+ /**
17
+ * Regex to extract package name from a Trivy vulnerability finding message.
18
+ *
19
+ * Matches patterns like:
20
+ * "CVE-2024-1234: lodash@4.17.20 - Known vulnerability (fix: upgrade to 4.17.21)"
21
+ * "CVE-2024-5678: @angular/core@16.0.0 - XSS vulnerability (no fix available)"
22
+ *
23
+ * Captures: packageName (group 1)
24
+ */
25
+ const TRIVY_VULN_PACKAGE_RE = /:\s+(@?[a-zA-Z0-9][\w./-]*)@/;
26
+ /**
27
+ * Extract unique vulnerable package names from Trivy CVE findings.
28
+ *
29
+ * Only processes findings with source === 'trivy' and
30
+ * category === 'dependency-vulnerability'.
31
+ *
32
+ * @param findings - All review findings
33
+ * @returns Map of package name → array of finding indices that reference it
34
+ */
35
+ export function extractVulnPackages(findings) {
36
+ const packages = new Map();
37
+ for (let i = 0; i < findings.length; i++) {
38
+ const finding = findings[i];
39
+ if (!finding)
40
+ continue;
41
+ if (finding.source !== 'trivy' || finding.category !== 'dependency-vulnerability') {
42
+ continue;
43
+ }
44
+ const match = TRIVY_VULN_PACKAGE_RE.exec(finding.message);
45
+ if (!match?.[1]) {
46
+ // Can't parse package name — will be labeled potentially-exploitable
47
+ const key = `__unparseable_${i}`;
48
+ packages.set(key, [i]);
49
+ continue;
50
+ }
51
+ const packageName = match[1];
52
+ const indices = packages.get(packageName) ?? [];
53
+ indices.push(i);
54
+ packages.set(packageName, indices);
55
+ }
56
+ return packages;
57
+ }
58
+ // ─── Import Tracing ────────────────────────────────────────────
59
+ /**
60
+ * Find which project files import a given external package.
61
+ *
62
+ * Searches the DependencyGraph for nodes whose `imports` array
63
+ * contains the package name (non-relative imports that match).
64
+ *
65
+ * @param graph - The project's dependency graph
66
+ * @param packageName - External package name (e.g., "lodash", "@angular/core")
67
+ * @returns Array of file paths that import the package
68
+ */
69
+ export function tracePackageImports(graph, packageName) {
70
+ const importSites = [];
71
+ for (const [filePath, node] of Object.entries(graph.nodes)) {
72
+ for (const imp of node.imports) {
73
+ // Non-relative imports: match package name exactly or as prefix for deep imports
74
+ // e.g., "lodash" matches "lodash", "lodash/get"
75
+ // e.g., "@angular/core" matches "@angular/core", "@angular/core/testing"
76
+ if (!imp.startsWith('.') && !imp.startsWith('/')) {
77
+ if (imp === packageName || imp.startsWith(`${packageName}/`)) {
78
+ importSites.push(filePath);
79
+ break; // One match per file is enough
80
+ }
81
+ }
82
+ }
83
+ }
84
+ return importSites;
85
+ }
86
+ // ─── Entry Point Detection ─────────────────────────────────────
87
+ /**
88
+ * Find entry point files in the dependency graph.
89
+ *
90
+ * An entry point is a non-test file that is NOT imported by any other
91
+ * project file. These are the "roots" of the dependency tree.
92
+ *
93
+ * @param graph - The project's dependency graph
94
+ * @returns Array of file paths that are entry points
95
+ */
96
+ export function findEntryPoints(graph) {
97
+ // Build set of all files that are imported by at least one other file
98
+ const imported = new Set();
99
+ for (const node of Object.values(graph.nodes)) {
100
+ for (const imp of node.imports) {
101
+ imported.add(imp);
102
+ }
103
+ for (const call of node.calls) {
104
+ imported.add(call.target);
105
+ }
106
+ }
107
+ // Entry points = non-test files not in the imported set
108
+ const entryPoints = [];
109
+ for (const [filePath, node] of Object.entries(graph.nodes)) {
110
+ if (!node.isTest && !imported.has(filePath)) {
111
+ entryPoints.push(filePath);
112
+ }
113
+ }
114
+ return entryPoints;
115
+ }
116
+ // ─── Reachability Analysis ─────────────────────────────────────
117
+ /**
118
+ * Check if any of the import sites are reachable from entry points
119
+ * via forward BFS through the dependency graph.
120
+ *
121
+ * Forward traversal: follows import edges from entry points outward.
122
+ *
123
+ * @param graph - The project's dependency graph
124
+ * @param entryPoints - Root files (no importers)
125
+ * @param importSites - Files that import the vulnerable package
126
+ * @returns Map of import site → entry points that can reach it
127
+ */
128
+ export function checkReachability(graph, entryPoints, importSites) {
129
+ const importSiteSet = new Set(importSites);
130
+ const result = new Map();
131
+ // Initialize result with empty arrays
132
+ for (const site of importSites) {
133
+ result.set(site, []);
134
+ }
135
+ // BFS forward from each entry point
136
+ for (const entry of entryPoints) {
137
+ const visited = new Set();
138
+ const queue = [entry];
139
+ visited.add(entry);
140
+ while (queue.length > 0) {
141
+ const current = queue.shift();
142
+ if (!current)
143
+ break;
144
+ // Check if we reached an import site
145
+ if (importSiteSet.has(current)) {
146
+ result.get(current)?.push(entry);
147
+ }
148
+ // Follow imports forward
149
+ const node = graph.nodes[current];
150
+ if (!node)
151
+ continue;
152
+ for (const imp of node.imports) {
153
+ if (!visited.has(imp) && graph.nodes[imp]) {
154
+ visited.add(imp);
155
+ queue.push(imp);
156
+ }
157
+ }
158
+ // Follow calls forward
159
+ for (const call of node.calls) {
160
+ if (!visited.has(call.target) && graph.nodes[call.target]) {
161
+ visited.add(call.target);
162
+ queue.push(call.target);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ return result;
168
+ }
169
+ // ─── Labeling ──────────────────────────────────────────────────
170
+ /**
171
+ * Determine the exploitability label based on import and reachability data.
172
+ */
173
+ function classifyExploitability(importSites, reachabilityMap) {
174
+ if (importSites.length === 0) {
175
+ return {
176
+ label: 'not-exploitable',
177
+ reachableFrom: [],
178
+ reason: 'Vulnerable package is not imported by any project file',
179
+ };
180
+ }
181
+ if (!reachabilityMap) {
182
+ return {
183
+ label: 'potentially-exploitable',
184
+ reachableFrom: [],
185
+ reason: 'Package is imported but reachability could not be determined',
186
+ };
187
+ }
188
+ // Collect all entry points that can reach any import site
189
+ const allReachableFrom = new Set();
190
+ for (const entryPoints of reachabilityMap.values()) {
191
+ for (const ep of entryPoints) {
192
+ allReachableFrom.add(ep);
193
+ }
194
+ }
195
+ if (allReachableFrom.size > 0) {
196
+ return {
197
+ label: 'exploitable',
198
+ reachableFrom: [...allReachableFrom],
199
+ reason: `Vulnerable package is imported and reachable from ${allReachableFrom.size} entry point(s)`,
200
+ };
201
+ }
202
+ return {
203
+ label: 'potentially-exploitable',
204
+ reachableFrom: [],
205
+ reason: 'Package is imported but not reachable from detected entry points',
206
+ };
207
+ }
208
+ // ─── Main Entry Point ──────────────────────────────────────────
209
+ /**
210
+ * Analyze exploitability of CVE findings from Trivy.
211
+ *
212
+ * Enriches each Trivy vulnerability finding with an exploitability
213
+ * label and detail based on import reachability analysis.
214
+ *
215
+ * Degrades gracefully:
216
+ * - No graph → all CVEs labeled `potentially-exploitable`
217
+ * - No CVE findings → returns findings unchanged (no-op)
218
+ *
219
+ * @param findings - All review findings (will mutate Trivy CVE findings in place)
220
+ * @param graph - The project's dependency graph (null if unavailable)
221
+ * @returns The same findings array with exploitability fields added to CVE findings
222
+ */
223
+ export function analyzeExploitability(findings, graph) {
224
+ // Step 1: Extract vulnerable packages
225
+ const vulnPackages = extractVulnPackages(findings);
226
+ if (vulnPackages.size === 0) {
227
+ return findings;
228
+ }
229
+ // Step 2: If no graph, label everything as potentially-exploitable
230
+ if (!graph) {
231
+ for (const [packageName, indices] of vulnPackages) {
232
+ const cleanName = packageName.startsWith('__unparseable_') ? 'unknown' : packageName;
233
+ const detail = {
234
+ label: 'potentially-exploitable',
235
+ packageName: cleanName,
236
+ importSites: [],
237
+ reachableFrom: [],
238
+ reason: 'Dependency graph unavailable — cannot determine reachability',
239
+ };
240
+ for (const idx of indices) {
241
+ const finding = findings[idx];
242
+ if (finding) {
243
+ finding.exploitability = 'potentially-exploitable';
244
+ finding.exploitabilityDetail = detail;
245
+ }
246
+ }
247
+ }
248
+ return findings;
249
+ }
250
+ // Step 3: Find entry points (once for all packages)
251
+ const entryPoints = findEntryPoints(graph);
252
+ // Step 4: Analyze each vulnerable package
253
+ for (const [packageName, indices] of vulnPackages) {
254
+ // Skip unparseable packages
255
+ if (packageName.startsWith('__unparseable_')) {
256
+ const detail = {
257
+ label: 'potentially-exploitable',
258
+ packageName: 'unknown',
259
+ importSites: [],
260
+ reachableFrom: [],
261
+ reason: 'Could not parse package name from finding',
262
+ };
263
+ for (const idx of indices) {
264
+ const finding = findings[idx];
265
+ if (finding) {
266
+ finding.exploitability = 'potentially-exploitable';
267
+ finding.exploitabilityDetail = detail;
268
+ }
269
+ }
270
+ continue;
271
+ }
272
+ // Trace imports
273
+ const importSites = tracePackageImports(graph, packageName);
274
+ // Check reachability
275
+ let reachabilityMap = null;
276
+ if (importSites.length > 0 && entryPoints.length > 0) {
277
+ reachabilityMap = checkReachability(graph, entryPoints, importSites);
278
+ }
279
+ // Classify
280
+ const { label, reachableFrom, reason } = classifyExploitability(importSites, reachabilityMap);
281
+ const detail = {
282
+ label,
283
+ packageName,
284
+ importSites,
285
+ reachableFrom,
286
+ reason,
287
+ };
288
+ // Apply to all findings for this package
289
+ for (const idx of indices) {
290
+ const finding = findings[idx];
291
+ if (finding) {
292
+ finding.exploitability = label;
293
+ finding.exploitabilityDetail = detail;
294
+ }
295
+ }
296
+ }
297
+ return findings;
298
+ }
299
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../src/exploitability/analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Exploitability module barrel export.
3
+ *
4
+ * CVE exploitability analysis based on import reachability.
5
+ * Enriches Trivy vulnerability findings with labels indicating
6
+ * whether the vulnerable code path is actually reachable.
7
+ */
8
+ export type { ExploitabilityDetail, ExploitabilityLabel } from './types.js';
9
+ export { analyzeExploitability, checkReachability, extractVulnPackages, findEntryPoints, tracePackageImports, } from './analyzer.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/exploitability/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAI5E,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,GACpB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Exploitability module barrel export.
3
+ *
4
+ * CVE exploitability analysis based on import reachability.
5
+ * Enriches Trivy vulnerability findings with labels indicating
6
+ * whether the vulnerable code path is actually reachable.
7
+ */
8
+ // ─── Analyzer ──────────────────────────────────────────────────
9
+ export { analyzeExploitability, checkReachability, extractVulnPackages, findEntryPoints, tracePackageImports, } from './analyzer.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exploitability/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,kEAAkE;AAElE,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,GACpB,MAAM,eAAe,CAAC"}