@kernlang/review 2.0.0 → 3.1.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 (118) hide show
  1. package/dist/concept-rules/boundary-mutation.d.ts +13 -0
  2. package/dist/concept-rules/boundary-mutation.js +40 -0
  3. package/dist/concept-rules/boundary-mutation.js.map +1 -0
  4. package/dist/concept-rules/ignored-error.d.ts +13 -0
  5. package/dist/concept-rules/ignored-error.js +40 -0
  6. package/dist/concept-rules/ignored-error.js.map +1 -0
  7. package/dist/concept-rules/illegal-dependency.d.ts +13 -0
  8. package/dist/concept-rules/illegal-dependency.js +49 -0
  9. package/dist/concept-rules/illegal-dependency.js.map +1 -0
  10. package/dist/concept-rules/index.d.ts +15 -0
  11. package/dist/concept-rules/index.js +27 -0
  12. package/dist/concept-rules/index.js.map +1 -0
  13. package/dist/concept-rules/unguarded-effect.d.ts +13 -0
  14. package/dist/concept-rules/unguarded-effect.js +58 -0
  15. package/dist/concept-rules/unguarded-effect.js.map +1 -0
  16. package/dist/concept-rules/unrecovered-effect.d.ts +13 -0
  17. package/dist/concept-rules/unrecovered-effect.js +61 -0
  18. package/dist/concept-rules/unrecovered-effect.js.map +1 -0
  19. package/dist/confidence.d.ts +92 -0
  20. package/dist/confidence.js +263 -0
  21. package/dist/confidence.js.map +1 -0
  22. package/dist/differ.js +4 -2
  23. package/dist/differ.js.map +1 -1
  24. package/dist/external-tools.js +7 -3
  25. package/dist/external-tools.js.map +1 -1
  26. package/dist/file-role.d.ts +10 -0
  27. package/dist/file-role.js +80 -0
  28. package/dist/file-role.js.map +1 -0
  29. package/dist/graph.d.ts +11 -0
  30. package/dist/graph.js +152 -0
  31. package/dist/graph.js.map +1 -0
  32. package/dist/index.d.ts +46 -3
  33. package/dist/index.js +313 -27
  34. package/dist/index.js.map +1 -1
  35. package/dist/inferrer.js +123 -25
  36. package/dist/inferrer.js.map +1 -1
  37. package/dist/kern-lint.d.ts +18 -0
  38. package/dist/kern-lint.js +24 -0
  39. package/dist/kern-lint.js.map +1 -0
  40. package/dist/llm-bridge.d.ts +42 -0
  41. package/dist/llm-bridge.js +176 -0
  42. package/dist/llm-bridge.js.map +1 -0
  43. package/dist/llm-review.d.ts +8 -1
  44. package/dist/llm-review.js +20 -7
  45. package/dist/llm-review.js.map +1 -1
  46. package/dist/mappers/ts-concepts.d.ts +9 -0
  47. package/dist/mappers/ts-concepts.js +518 -0
  48. package/dist/mappers/ts-concepts.js.map +1 -0
  49. package/dist/quality-rules.d.ts +3 -3
  50. package/dist/quality-rules.js +3 -11
  51. package/dist/quality-rules.js.map +1 -1
  52. package/dist/reporter.d.ts +19 -3
  53. package/dist/reporter.js +232 -20
  54. package/dist/reporter.js.map +1 -1
  55. package/dist/rules/base.js +167 -15
  56. package/dist/rules/base.js.map +1 -1
  57. package/dist/rules/confidence.d.ts +37 -0
  58. package/dist/rules/confidence.js +159 -0
  59. package/dist/rules/confidence.js.map +1 -0
  60. package/dist/rules/dead-logic.d.ts +13 -0
  61. package/dist/rules/dead-logic.js +393 -0
  62. package/dist/rules/dead-logic.js.map +1 -0
  63. package/dist/rules/express.js +69 -2
  64. package/dist/rules/express.js.map +1 -1
  65. package/dist/rules/ground-layer.d.ts +23 -0
  66. package/dist/rules/ground-layer.js +132 -0
  67. package/dist/rules/ground-layer.js.map +1 -0
  68. package/dist/rules/index.d.ts +1 -1
  69. package/dist/rules/index.js +8 -2
  70. package/dist/rules/index.js.map +1 -1
  71. package/dist/rules/kern-source.d.ts +16 -0
  72. package/dist/rules/kern-source.js +726 -0
  73. package/dist/rules/kern-source.js.map +1 -0
  74. package/dist/rules/nextjs.js +38 -10
  75. package/dist/rules/nextjs.js.map +1 -1
  76. package/dist/rules/null-safety.d.ts +12 -0
  77. package/dist/rules/null-safety.js +123 -0
  78. package/dist/rules/null-safety.js.map +1 -0
  79. package/dist/rules/react.js +64 -1
  80. package/dist/rules/react.js.map +1 -1
  81. package/dist/rules/security-v2.d.ts +12 -0
  82. package/dist/rules/security-v2.js +415 -0
  83. package/dist/rules/security-v2.js.map +1 -0
  84. package/dist/rules/security-v3.d.ts +12 -0
  85. package/dist/rules/security-v3.js +397 -0
  86. package/dist/rules/security-v3.js.map +1 -0
  87. package/dist/rules/security-v4.d.ts +22 -0
  88. package/dist/rules/security-v4.js +688 -0
  89. package/dist/rules/security-v4.js.map +1 -0
  90. package/dist/rules/security.d.ts +12 -0
  91. package/dist/rules/security.js +286 -0
  92. package/dist/rules/security.js.map +1 -0
  93. package/dist/rules/utils.d.ts +7 -0
  94. package/dist/rules/utils.js +21 -0
  95. package/dist/rules/utils.js.map +1 -0
  96. package/dist/rules/vue.js +1 -1
  97. package/dist/rules/vue.js.map +1 -1
  98. package/dist/spec-checker.d.ts +83 -0
  99. package/dist/spec-checker.js +405 -0
  100. package/dist/spec-checker.js.map +1 -0
  101. package/dist/suppression/apply-suppression.d.ts +17 -0
  102. package/dist/suppression/apply-suppression.js +94 -0
  103. package/dist/suppression/apply-suppression.js.map +1 -0
  104. package/dist/suppression/index.d.ts +6 -0
  105. package/dist/suppression/index.js +6 -0
  106. package/dist/suppression/index.js.map +1 -0
  107. package/dist/suppression/parse-directives.d.ts +25 -0
  108. package/dist/suppression/parse-directives.js +161 -0
  109. package/dist/suppression/parse-directives.js.map +1 -0
  110. package/dist/suppression/types.d.ts +32 -0
  111. package/dist/suppression/types.js +5 -0
  112. package/dist/suppression/types.js.map +1 -0
  113. package/dist/taint.d.ts +115 -0
  114. package/dist/taint.js +1052 -0
  115. package/dist/taint.js.map +1 -0
  116. package/dist/types.d.ts +71 -0
  117. package/dist/types.js.map +1 -1
  118. package/package.json +7 -4
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Parse kern-ignore directives from source text.
3
+ *
4
+ * Supported syntax:
5
+ * // kern-ignore <rule-id>[, <rule-id>...] — suppress on same or next non-comment line
6
+ * // kern-ignore-file <rule-id>[, <rule-id>...] — suppress for entire file (first 5 lines)
7
+ * # kern-ignore <rule-id>[, <rule-id>...] — Python variant
8
+ * # kern-ignore-file <rule-id>[, <rule-id>...] — Python variant
9
+ */
10
+ import { createFingerprint } from '../types.js';
11
+ /** Known concept rule IDs — these only support file-level suppression */
12
+ const CONCEPT_RULE_IDS = new Set([
13
+ 'unguarded-effect',
14
+ 'unrecovered-effect',
15
+ 'ignored-error',
16
+ 'boundary-mutation',
17
+ 'illegal-dependency',
18
+ ]);
19
+ /** Matches: // kern-ignore[-file] rule1, rule2 */
20
+ const TS_DIRECTIVE = /\/\/\s*kern-ignore(?:-(file))?\s+([\w-][\w,-\s]*)/;
21
+ /** Matches: # kern-ignore[-file] rule1, rule2 */
22
+ const PY_DIRECTIVE = /#\s*kern-ignore(?:-(file))?\s+([\w-][\w,-\s]*)/;
23
+ /** Matches bare: // kern-ignore (no rule IDs) */
24
+ const TS_BARE = /\/\/\s*kern-ignore\s*$/;
25
+ const PY_BARE = /#\s*kern-ignore\s*$/;
26
+ export function isConceptRule(ruleId) {
27
+ return CONCEPT_RULE_IDS.has(ruleId);
28
+ }
29
+ /**
30
+ * Parse all suppression directives from source text.
31
+ * Returns directives + any warnings (e.g., bare kern-ignore, concept rule on line-level).
32
+ */
33
+ export function parseDirectives(source, filePath) {
34
+ const lines = source.split('\n');
35
+ const isPython = filePath.endsWith('.py');
36
+ const directivePattern = isPython ? PY_DIRECTIVE : TS_DIRECTIVE;
37
+ const barePattern = isPython ? PY_BARE : TS_BARE;
38
+ const isCommentLine = isPython
39
+ ? (line) => line.trimStart().startsWith('#')
40
+ : (line) => line.trimStart().startsWith('//');
41
+ const directives = [];
42
+ const warnings = [];
43
+ for (let i = 0; i < lines.length; i++) {
44
+ const line = lines[i];
45
+ const lineNum = i + 1;
46
+ // Check for bare kern-ignore (no rule ID) — emit warning
47
+ if (barePattern.test(line)) {
48
+ warnings.push({
49
+ source: 'kern',
50
+ ruleId: 'kern-ignore-bare',
51
+ severity: 'warning',
52
+ category: 'style',
53
+ message: `Bare kern-ignore without rule ID — specify rules: // kern-ignore <rule-id>`,
54
+ primarySpan: { file: filePath, startLine: lineNum, startCol: 1, endLine: lineNum, endCol: line.length },
55
+ fingerprint: createFingerprint('kern-ignore-bare', lineNum, 1),
56
+ });
57
+ continue;
58
+ }
59
+ const match = directivePattern.exec(line);
60
+ if (!match)
61
+ continue;
62
+ const isFileLevel = match[1] === 'file';
63
+ const ruleIds = match[2].split(',').map(r => r.trim()).filter(Boolean);
64
+ if (ruleIds.length === 0)
65
+ continue;
66
+ // File-level directives must appear in the first 5 lines
67
+ if (isFileLevel && lineNum > 5) {
68
+ warnings.push({
69
+ source: 'kern',
70
+ ruleId: 'kern-ignore-position',
71
+ severity: 'warning',
72
+ category: 'style',
73
+ message: `kern-ignore-file must appear in the first 5 lines of the file (found at line ${lineNum})`,
74
+ primarySpan: { file: filePath, startLine: lineNum, startCol: 1, endLine: lineNum, endCol: line.length },
75
+ fingerprint: createFingerprint('kern-ignore-position', lineNum, 1),
76
+ });
77
+ continue;
78
+ }
79
+ // Concept rules with line-level suppression — emit warning, suggest file-level
80
+ if (!isFileLevel) {
81
+ const conceptRules = ruleIds.filter(isConceptRule);
82
+ if (conceptRules.length > 0) {
83
+ warnings.push({
84
+ source: 'kern',
85
+ ruleId: 'kern-ignore-concept',
86
+ severity: 'warning',
87
+ category: 'style',
88
+ message: `'${conceptRules.join(', ')}' ${conceptRules.length === 1 ? 'is a' : 'are'} concept rule${conceptRules.length === 1 ? '' : 's'} — use '// kern-ignore-file ${conceptRules.join(', ')}' at the top of the file instead`,
89
+ primarySpan: { file: filePath, startLine: lineNum, startCol: 1, endLine: lineNum, endCol: line.length },
90
+ fingerprint: createFingerprint('kern-ignore-concept', lineNum, 1),
91
+ });
92
+ // Still process non-concept rules on this line
93
+ const nonConcept = ruleIds.filter(r => !isConceptRule(r));
94
+ if (nonConcept.length === 0)
95
+ continue;
96
+ // Fall through with non-concept rules only
97
+ ruleIds.length = 0;
98
+ ruleIds.push(...nonConcept);
99
+ }
100
+ }
101
+ if (isFileLevel) {
102
+ directives.push({
103
+ type: 'file',
104
+ ruleIds,
105
+ file: filePath,
106
+ source: 'inline',
107
+ commentLine: lineNum,
108
+ });
109
+ }
110
+ else {
111
+ // Same-line: check if the directive is on a line with actual code
112
+ // If the line is comment-only, it applies to the next non-comment, non-blank line
113
+ const trimmed = line.trimStart();
114
+ const isCommentOnly = isPython
115
+ ? trimmed.startsWith('#') && !trimmed.replace(/#.*/, '').trim()
116
+ : trimmed.startsWith('//');
117
+ let targetLine;
118
+ if (isCommentOnly) {
119
+ // Find next non-comment, non-blank line
120
+ targetLine = lineNum; // fallback
121
+ for (let j = i + 1; j < lines.length; j++) {
122
+ const nextLine = lines[j].trim();
123
+ if (nextLine === '')
124
+ continue;
125
+ if (isCommentLine(nextLine))
126
+ continue;
127
+ targetLine = j + 1;
128
+ break;
129
+ }
130
+ }
131
+ else {
132
+ // Inline comment on same line as code — suppress this line
133
+ targetLine = lineNum;
134
+ }
135
+ directives.push({
136
+ type: 'line',
137
+ ruleIds,
138
+ file: filePath,
139
+ line: targetLine,
140
+ source: 'inline',
141
+ commentLine: lineNum,
142
+ });
143
+ }
144
+ }
145
+ return { directives, warnings };
146
+ }
147
+ /**
148
+ * Create config-level suppression directives from disabledRules.
149
+ * These apply to all files (file field is '*').
150
+ */
151
+ export function configDirectives(disabledRules) {
152
+ if (disabledRules.length === 0)
153
+ return [];
154
+ return [{
155
+ type: 'file',
156
+ ruleIds: disabledRules,
157
+ file: '*',
158
+ source: 'config',
159
+ }];
160
+ }
161
+ //# sourceMappingURL=parse-directives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-directives.js","sourceRoot":"","sources":["../../src/suppression/parse-directives.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Types for the review suppression system.
3
+ */
4
+ import type { ReviewFinding } from '../types.js';
5
+ /** A parsed suppression directive from source comments or config */
6
+ export interface SuppressionDirective {
7
+ /** 'line' = suppress on a specific line, 'file' = suppress entire file */
8
+ type: 'line' | 'file';
9
+ /** Rule IDs to suppress (always explicit — no blanket suppression) */
10
+ ruleIds: string[];
11
+ /** File this directive applies to */
12
+ file: string;
13
+ /** Target line (for 'line' type — the line whose findings are suppressed) */
14
+ line?: number;
15
+ /** Where this directive came from */
16
+ source: 'inline' | 'config';
17
+ /** The raw line number where the comment was found (for unused-directive warnings) */
18
+ commentLine?: number;
19
+ }
20
+ /** Result of applying suppression to a set of findings */
21
+ export interface SuppressionResult {
22
+ /** Findings that passed (not suppressed) */
23
+ findings: ReviewFinding[];
24
+ /** Findings that were suppressed */
25
+ suppressed: ReviewFinding[];
26
+ /** All parsed directives */
27
+ directives: SuppressionDirective[];
28
+ /** Directives that matched no findings (potential stale comments) */
29
+ unusedDirectives: SuppressionDirective[];
30
+ }
31
+ /** Strict mode levels for CI */
32
+ export type StrictMode = false | 'inline' | 'all';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Types for the review suppression system.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/suppression/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Taint Tracking — source→sink analysis on KERN IR.
3
+ *
4
+ * Phase 2 of the security pipeline. Works on InferResult[] handler bodies.
5
+ *
6
+ * Two modes:
7
+ * analyzeTaint() — intra-procedural (single file)
8
+ * analyzeTaintCrossFile() — inter-procedural (follows imports across files)
9
+ *
10
+ * Also validates sanitizer sufficiency: parseInt stops SQL injection on
11
+ * numeric values but NOT command injection. DOMPurify stops XSS but
12
+ * NOT SQL injection. The sufficiency matrix catches these mismatches.
13
+ */
14
+ import { type SourceFile } from 'ts-morph';
15
+ import type { InferResult, ReviewFinding } from './types.js';
16
+ export interface TaintSource {
17
+ name: string;
18
+ origin: string;
19
+ line?: number;
20
+ }
21
+ export interface TaintSink {
22
+ name: string;
23
+ category: 'command' | 'fs' | 'sql' | 'redirect' | 'eval' | 'template';
24
+ taintedArg: string;
25
+ line?: number;
26
+ }
27
+ export interface TaintPath {
28
+ source: TaintSource;
29
+ sink: TaintSink;
30
+ sanitized: boolean;
31
+ sanitizer?: string;
32
+ insufficientSanitizer?: string;
33
+ }
34
+ export interface TaintResult {
35
+ fnName: string;
36
+ filePath: string;
37
+ startLine: number;
38
+ paths: TaintPath[];
39
+ }
40
+ type SinkCategory = TaintSink['category'];
41
+ /**
42
+ * Check if a sanitizer is actually sufficient for a given sink category.
43
+ * Returns true if the sanitizer protects against the sink, false if it's
44
+ * a mismatch (e.g., parseInt used to "sanitize" command injection).
45
+ */
46
+ export declare function isSanitizerSufficient(sanitizerName: string, sinkCategory: SinkCategory): boolean;
47
+ export interface CrossFileTaintResult {
48
+ callerFile: string;
49
+ callerFn: string;
50
+ callerLine: number;
51
+ calleeFile: string;
52
+ calleeFn: string;
53
+ taintedArgs: string[];
54
+ sinkInCallee: TaintSink;
55
+ source: TaintSource;
56
+ }
57
+ /** Map of exported function names → file path + param info */
58
+ export interface ExportedFunction {
59
+ filePath: string;
60
+ fnName: string;
61
+ params: string;
62
+ hasSink: boolean;
63
+ sinks: TaintSink[];
64
+ }
65
+ /**
66
+ * Run taint analysis on all fn nodes in inferred results.
67
+ * When sourceFile is provided, uses AST-based analysis (more accurate).
68
+ * Falls back to regex-based analysis when no SourceFile available.
69
+ */
70
+ export declare function analyzeTaint(inferred: InferResult[], filePath: string, sourceFile?: SourceFile): TaintResult[];
71
+ /**
72
+ * Multi-hop taint propagation using worklist algorithm.
73
+ * Propagates until fixed point or configurable depth limit.
74
+ *
75
+ * Handles all assignment patterns:
76
+ * - const b = a
77
+ * - const b = a.trim()
78
+ * - const {x} = obj
79
+ * - let b; b = a
80
+ *
81
+ * @param code - Handler code string
82
+ * @param initialTainted - Set of initially tainted variable names
83
+ * @param maxDepth - Maximum propagation depth (default: 3)
84
+ * @returns Set of all tainted variable names after fixed point or depth limit
85
+ */
86
+ export declare function propagateTaintMultiHop(code: string, initialTainted: Set<string>, maxDepth?: number): Set<string>;
87
+ /**
88
+ * Convert taint results into ReviewFinding[] for the unified pipeline.
89
+ */
90
+ export declare function taintToFindings(results: TaintResult[]): ReviewFinding[];
91
+ /**
92
+ * Build a map of exported functions across all files.
93
+ * Maps "filePath::fnName" → ExportedFunction with sink info.
94
+ */
95
+ export declare function buildExportMap(inferredPerFile: Map<string, InferResult[]>): Map<string, ExportedFunction>;
96
+ /**
97
+ * Build import→function resolution map.
98
+ * Maps "importingFile::importedName" → absolute file path of the definition.
99
+ */
100
+ export declare function buildImportMap(inferredPerFile: Map<string, InferResult[]>, graphImports: Map<string, string[]>): Map<string, string>;
101
+ /**
102
+ * Cross-file taint analysis.
103
+ *
104
+ * For each handler function with tainted params:
105
+ * 1. Find calls to imported functions in the handler body
106
+ * 2. Check if tainted data is passed as an argument
107
+ * 3. Look up the target function — does it have a dangerous sink?
108
+ * 4. If yes and no sanitizer in between → cross-file taint path
109
+ */
110
+ export declare function analyzeTaintCrossFile(inferredPerFile: Map<string, InferResult[]>, graphImports: Map<string, string[]>): CrossFileTaintResult[];
111
+ /**
112
+ * Convert cross-file taint results into ReviewFinding[].
113
+ */
114
+ export declare function crossFileTaintToFindings(results: CrossFileTaintResult[]): ReviewFinding[];
115
+ export {};