postquant 0.1.2 → 0.3.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 (71) hide show
  1. package/README.md +101 -8
  2. package/dist/commands/analyze.d.ts +9 -0
  3. package/dist/commands/analyze.d.ts.map +1 -0
  4. package/dist/commands/analyze.js +129 -0
  5. package/dist/commands/analyze.js.map +1 -0
  6. package/dist/index.js +49 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/output/cbom.d.ts +3 -0
  9. package/dist/output/cbom.d.ts.map +1 -0
  10. package/dist/output/cbom.js +235 -0
  11. package/dist/output/cbom.js.map +1 -0
  12. package/dist/output/json-code.d.ts +3 -0
  13. package/dist/output/json-code.d.ts.map +1 -0
  14. package/dist/output/json-code.js +41 -0
  15. package/dist/output/json-code.js.map +1 -0
  16. package/dist/output/sarif.d.ts +3 -0
  17. package/dist/output/sarif.d.ts.map +1 -0
  18. package/dist/output/sarif.js +265 -0
  19. package/dist/output/sarif.js.map +1 -0
  20. package/dist/output/terminal-code.d.ts +8 -0
  21. package/dist/output/terminal-code.d.ts.map +1 -0
  22. package/dist/output/terminal-code.js +155 -0
  23. package/dist/output/terminal-code.js.map +1 -0
  24. package/dist/output/terminal.d.ts.map +1 -1
  25. package/dist/output/terminal.js +14 -2
  26. package/dist/output/terminal.js.map +1 -1
  27. package/dist/scanner/code/classifier.d.ts +9 -0
  28. package/dist/scanner/code/classifier.d.ts.map +1 -0
  29. package/dist/scanner/code/classifier.js +19 -0
  30. package/dist/scanner/code/classifier.js.map +1 -0
  31. package/dist/scanner/code/discovery.d.ts +17 -0
  32. package/dist/scanner/code/discovery.d.ts.map +1 -0
  33. package/dist/scanner/code/discovery.js +167 -0
  34. package/dist/scanner/code/discovery.js.map +1 -0
  35. package/dist/scanner/code/grader.d.ts +27 -0
  36. package/dist/scanner/code/grader.d.ts.map +1 -0
  37. package/dist/scanner/code/grader.js +169 -0
  38. package/dist/scanner/code/grader.js.map +1 -0
  39. package/dist/scanner/code/matcher.d.ts +20 -0
  40. package/dist/scanner/code/matcher.d.ts.map +1 -0
  41. package/dist/scanner/code/matcher.js +209 -0
  42. package/dist/scanner/code/matcher.js.map +1 -0
  43. package/dist/scanner/code/patterns/go.d.ts +3 -0
  44. package/dist/scanner/code/patterns/go.d.ts.map +1 -0
  45. package/dist/scanner/code/patterns/go.js +226 -0
  46. package/dist/scanner/code/patterns/go.js.map +1 -0
  47. package/dist/scanner/code/patterns/index.d.ts +11 -0
  48. package/dist/scanner/code/patterns/index.d.ts.map +1 -0
  49. package/dist/scanner/code/patterns/index.js +20 -0
  50. package/dist/scanner/code/patterns/index.js.map +1 -0
  51. package/dist/scanner/code/patterns/java.d.ts +3 -0
  52. package/dist/scanner/code/patterns/java.d.ts.map +1 -0
  53. package/dist/scanner/code/patterns/java.js +239 -0
  54. package/dist/scanner/code/patterns/java.js.map +1 -0
  55. package/dist/scanner/code/patterns/javascript.d.ts +3 -0
  56. package/dist/scanner/code/patterns/javascript.d.ts.map +1 -0
  57. package/dist/scanner/code/patterns/javascript.js +243 -0
  58. package/dist/scanner/code/patterns/javascript.js.map +1 -0
  59. package/dist/scanner/code/patterns/python.d.ts +3 -0
  60. package/dist/scanner/code/patterns/python.d.ts.map +1 -0
  61. package/dist/scanner/code/patterns/python.js +255 -0
  62. package/dist/scanner/code/patterns/python.js.map +1 -0
  63. package/dist/scanner/code/risk-assessor.d.ts +25 -0
  64. package/dist/scanner/code/risk-assessor.d.ts.map +1 -0
  65. package/dist/scanner/code/risk-assessor.js +412 -0
  66. package/dist/scanner/code/risk-assessor.js.map +1 -0
  67. package/dist/types/index.d.ts +139 -0
  68. package/dist/types/index.d.ts.map +1 -1
  69. package/dist/types/index.js +4 -1
  70. package/dist/types/index.js.map +1 -1
  71. package/package.json +4 -1
@@ -0,0 +1,167 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import { join, extname, basename } from 'node:path';
3
+ /** Extension → Language mapping. TypeScript maps to 'javascript'. */
4
+ const EXTENSION_MAP = {
5
+ '.py': 'python',
6
+ '.pyw': 'python',
7
+ '.pyi': 'python',
8
+ '.js': 'javascript',
9
+ '.mjs': 'javascript',
10
+ '.cjs': 'javascript',
11
+ '.jsx': 'javascript',
12
+ '.ts': 'javascript',
13
+ '.mts': 'javascript',
14
+ '.cts': 'javascript',
15
+ '.tsx': 'javascript',
16
+ '.go': 'go',
17
+ '.java': 'java',
18
+ };
19
+ /** Directories and patterns always ignored regardless of config. */
20
+ const DEFAULT_IGNORE_DIRS = new Set([
21
+ 'node_modules',
22
+ 'vendor',
23
+ '.git',
24
+ 'dist',
25
+ 'build',
26
+ '__pycache__',
27
+ ]);
28
+ /** File patterns always ignored (checked against basename). */
29
+ const DEFAULT_IGNORE_GLOBS = [
30
+ '*.min.js',
31
+ '*.bundle.js',
32
+ '*.map',
33
+ 'package-lock.json',
34
+ 'yarn.lock',
35
+ 'go.sum',
36
+ ];
37
+ /**
38
+ * Discover source files in a directory tree.
39
+ * Returns files with detected language, filtered by ignore patterns and options.
40
+ */
41
+ export async function discoverFiles(scanRoot, options = {}) {
42
+ const { ignore = [], ignoreFile, maxFiles = 10000, language } = options;
43
+ // Load custom ignore patterns from ignore file
44
+ const customIgnores = ignoreFile
45
+ ? await loadIgnoreFile(join(scanRoot, ignoreFile))
46
+ : [];
47
+ const allIgnorePatterns = [...DEFAULT_IGNORE_GLOBS, ...ignore, ...customIgnores];
48
+ const entries = await readdir(scanRoot, { recursive: true, withFileTypes: false });
49
+ const results = [];
50
+ for (const entry of entries) {
51
+ if (results.length >= maxFiles)
52
+ break;
53
+ const relativePath = typeof entry === 'string' ? entry : String(entry);
54
+ // Skip files in default-ignored directories
55
+ if (isInIgnoredDir(relativePath))
56
+ continue;
57
+ // Check file extension for language
58
+ const ext = extname(relativePath);
59
+ const lang = EXTENSION_MAP[ext];
60
+ if (!lang)
61
+ continue;
62
+ // Apply language filter
63
+ if (language && lang !== language)
64
+ continue;
65
+ // Check against ignore patterns
66
+ if (matchesAnyPattern(relativePath, allIgnorePatterns))
67
+ continue;
68
+ results.push({ path: relativePath, language: lang });
69
+ }
70
+ return results;
71
+ }
72
+ /**
73
+ * Check if a relative path is inside a default-ignored directory.
74
+ */
75
+ function isInIgnoredDir(relativePath) {
76
+ const parts = relativePath.split('/');
77
+ return parts.some((part) => DEFAULT_IGNORE_DIRS.has(part));
78
+ }
79
+ /**
80
+ * Simple glob matching. Supports:
81
+ * - `*` matches any characters except /
82
+ * - `**` matches any characters including /
83
+ * - Trailing `/` matches directory prefixes
84
+ * - `#` comment lines are skipped
85
+ * - Empty lines are skipped
86
+ */
87
+ function matchesAnyPattern(filePath, patterns) {
88
+ const fileName = basename(filePath);
89
+ for (const pattern of patterns) {
90
+ if (matchesPattern(filePath, fileName, pattern))
91
+ return true;
92
+ }
93
+ return false;
94
+ }
95
+ function matchesPattern(filePath, fileName, pattern) {
96
+ // Directory pattern (trailing /)
97
+ if (pattern.endsWith('/')) {
98
+ const dirName = pattern.slice(0, -1);
99
+ return filePath.startsWith(dirName + '/') || filePath.includes('/' + dirName + '/');
100
+ }
101
+ // Pattern with path separator — match against full path
102
+ if (pattern.includes('/')) {
103
+ return globMatch(pattern, filePath);
104
+ }
105
+ // Simple filename pattern — match against basename
106
+ return globMatch(pattern, fileName);
107
+ }
108
+ /**
109
+ * Minimal glob matcher. Converts glob to regex.
110
+ * Supports * (any non-/ chars) and ** (any chars including /).
111
+ */
112
+ function globMatch(pattern, str) {
113
+ let regexStr = '^';
114
+ let i = 0;
115
+ while (i < pattern.length) {
116
+ const ch = pattern[i];
117
+ if (ch === '*' && pattern[i + 1] === '*') {
118
+ // ** matches everything including /
119
+ regexStr += '.*';
120
+ i += 2;
121
+ // Skip trailing / after **
122
+ if (pattern[i] === '/')
123
+ i++;
124
+ }
125
+ else if (ch === '*') {
126
+ // * matches everything except /
127
+ regexStr += '[^/]*';
128
+ i++;
129
+ }
130
+ else if (ch === '?') {
131
+ regexStr += '[^/]';
132
+ i++;
133
+ }
134
+ else if ('.+^${}()|[]\\'.includes(ch)) {
135
+ regexStr += '\\' + ch;
136
+ i++;
137
+ }
138
+ else {
139
+ regexStr += ch;
140
+ i++;
141
+ }
142
+ }
143
+ regexStr += '$';
144
+ try {
145
+ return new RegExp(regexStr).test(str);
146
+ }
147
+ catch {
148
+ return false;
149
+ }
150
+ }
151
+ /**
152
+ * Load ignore patterns from a file. Skips blank lines and comments (#).
153
+ * Returns empty array if file doesn't exist.
154
+ */
155
+ async function loadIgnoreFile(filePath) {
156
+ try {
157
+ const content = await readFile(filePath, 'utf-8');
158
+ return content
159
+ .split('\n')
160
+ .map((line) => line.trim())
161
+ .filter((line) => line.length > 0 && !line.startsWith('#'));
162
+ }
163
+ catch {
164
+ return [];
165
+ }
166
+ }
167
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/scanner/code/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { CodeScanResult, CodeGradedResult, BaseGrade } from '../../types/index.js';
2
+ /**
3
+ * Grade a code scan result.
4
+ *
5
+ * Grading logic (from spec Section 6.1):
6
+ * 0 critical + 0 moderate → A (A+ if PQC detected)
7
+ * 0 critical + moderate only → B
8
+ * 1-5 critical → C
9
+ * 6-20 critical → D
10
+ * 21+ critical → F
11
+ *
12
+ * Special cases:
13
+ * MD5/SHA-1/DES/3DES → cap at D
14
+ *
15
+ * Modifiers (same as TLS grader):
16
+ * 0 moderate → +
17
+ * 1 moderate → (none)
18
+ * 2+ moderate → -
19
+ * A+, A, F → no modifier
20
+ */
21
+ export declare function gradeCodeScan(scan: CodeScanResult): CodeGradedResult;
22
+ /**
23
+ * Determine if a scan should fail CI based on grade threshold.
24
+ * Reuses the same logic as the TLS grader.
25
+ */
26
+ export declare function shouldFailForCodeGrade(actual: BaseGrade, threshold: BaseGrade): boolean;
27
+ //# sourceMappingURL=grader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grader.d.ts","sourceRoot":"","sources":["../../../src/scanner/code/grader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAKhB,SAAS,EAEV,MAAM,sBAAsB,CAAC;AA6B9B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,gBAAgB,CAoFpE;AAoCD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,SAAS,GACnB,OAAO,CAET"}
@@ -0,0 +1,169 @@
1
+ import { isAssessedFinding } from '../../types/index.js';
2
+ const BASE_GRADE_ORDER = ['A+', 'A', 'B', 'C', 'D', 'F'];
3
+ /** Algorithms that are already broken classically — cap grade at D. */
4
+ const BROKEN_ALGORITHMS = ['MD5', 'SHA-1', 'SHA1', 'DES', '3DES', 'TRIPLE-DES'];
5
+ /**
6
+ * Map a finding to a grade bucket using adjusted risk when available,
7
+ * falling back to the raw `risk` field for unassessed findings.
8
+ */
9
+ function getEffectiveGradeBucket(f) {
10
+ if (isAssessedFinding(f)) {
11
+ switch (f.riskContext.adjustedRisk) {
12
+ case 'critical':
13
+ case 'high':
14
+ return 'critical';
15
+ case 'medium':
16
+ return 'moderate';
17
+ case 'low':
18
+ case 'informational':
19
+ return 'excluded';
20
+ }
21
+ }
22
+ // Raw finding — use original risk
23
+ return f.risk === 'critical' ? 'critical' : f.risk === 'moderate' ? 'moderate' : 'safe';
24
+ }
25
+ /**
26
+ * Grade a code scan result.
27
+ *
28
+ * Grading logic (from spec Section 6.1):
29
+ * 0 critical + 0 moderate → A (A+ if PQC detected)
30
+ * 0 critical + moderate only → B
31
+ * 1-5 critical → C
32
+ * 6-20 critical → D
33
+ * 21+ critical → F
34
+ *
35
+ * Special cases:
36
+ * MD5/SHA-1/DES/3DES → cap at D
37
+ *
38
+ * Modifiers (same as TLS grader):
39
+ * 0 moderate → +
40
+ * 1 moderate → (none)
41
+ * 2+ moderate → -
42
+ * A+, A, F → no modifier
43
+ */
44
+ export function gradeCodeScan(scan) {
45
+ const { findings } = scan;
46
+ // Count findings by effective grade bucket (uses adjustedRisk when available)
47
+ let critical = 0;
48
+ let moderate = 0;
49
+ let safe = 0;
50
+ for (const f of findings) {
51
+ const bucket = getEffectiveGradeBucket(f);
52
+ if (bucket === 'critical')
53
+ critical++;
54
+ else if (bucket === 'moderate')
55
+ moderate++;
56
+ else if (bucket === 'safe' || bucket === 'excluded')
57
+ safe++;
58
+ }
59
+ // Determine base grade from critical/moderate counts
60
+ let baseGrade;
61
+ if (critical === 0 && moderate === 0) {
62
+ const hasPqc = findings.some((f) => f.category === 'pqc-algorithm');
63
+ baseGrade = hasPqc ? 'A+' : 'A';
64
+ }
65
+ else if (critical === 0) {
66
+ baseGrade = 'B';
67
+ }
68
+ else if (critical <= 5) {
69
+ baseGrade = 'C';
70
+ }
71
+ else if (critical <= 20) {
72
+ baseGrade = 'D';
73
+ }
74
+ else {
75
+ baseGrade = 'F';
76
+ }
77
+ // Special case: broken algorithms cap at D
78
+ // Only applies when the finding's adjusted risk is critical or high
79
+ const hasBrokenAlgo = findings.some((f) => {
80
+ const isBroken = BROKEN_ALGORITHMS.some((broken) => f.algorithm.toUpperCase() === broken.toUpperCase());
81
+ if (!isBroken)
82
+ return false;
83
+ if (isAssessedFinding(f)) {
84
+ return f.riskContext.adjustedRisk === 'critical' || f.riskContext.adjustedRisk === 'high';
85
+ }
86
+ return true; // Raw finding — cap as before
87
+ });
88
+ if (hasBrokenAlgo && gradeRank(baseGrade) < gradeRank('D')) {
89
+ baseGrade = 'D';
90
+ }
91
+ // Compute modifier (same logic as TLS grader)
92
+ let modifier = '';
93
+ if (baseGrade !== 'A+' && baseGrade !== 'A' && baseGrade !== 'F') {
94
+ if (moderate === 0) {
95
+ modifier = '+';
96
+ }
97
+ else if (moderate >= 2) {
98
+ modifier = '-';
99
+ }
100
+ }
101
+ const displayGrade = (baseGrade + modifier);
102
+ // Collect unique migration notes
103
+ const migrationSet = new Set();
104
+ for (const f of findings) {
105
+ if (f.migration)
106
+ migrationSet.add(f.migration);
107
+ }
108
+ // Build per-file breakdown
109
+ const fileBreakdown = buildFileBreakdown(findings);
110
+ return {
111
+ scanRoot: scan.scanRoot,
112
+ grade: displayGrade,
113
+ baseGrade,
114
+ modifier,
115
+ findings,
116
+ migrationNotes: [...migrationSet],
117
+ summary: {
118
+ critical,
119
+ moderate,
120
+ safe,
121
+ total: findings.length,
122
+ filesScanned: scan.filesScanned,
123
+ filesWithFindings: scan.filesWithFindings,
124
+ },
125
+ fileBreakdown,
126
+ };
127
+ }
128
+ function buildFileBreakdown(findings) {
129
+ const byFile = new Map();
130
+ for (const f of findings) {
131
+ const list = byFile.get(f.file) ?? [];
132
+ list.push(f);
133
+ byFile.set(f.file, list);
134
+ }
135
+ return [...byFile.entries()].map(([file, fileFindgs]) => {
136
+ let criticalCount = 0;
137
+ let moderateCount = 0;
138
+ let safeCount = 0;
139
+ for (const f of fileFindgs) {
140
+ const bucket = getEffectiveGradeBucket(f);
141
+ if (bucket === 'critical')
142
+ criticalCount++;
143
+ else if (bucket === 'moderate')
144
+ moderateCount++;
145
+ else
146
+ safeCount++;
147
+ }
148
+ return {
149
+ file,
150
+ language: fileFindgs[0].language,
151
+ findings: fileFindgs,
152
+ criticalCount,
153
+ moderateCount,
154
+ safeCount,
155
+ };
156
+ });
157
+ }
158
+ /** Return numeric rank for a base grade (higher = worse). */
159
+ function gradeRank(g) {
160
+ return BASE_GRADE_ORDER.indexOf(g);
161
+ }
162
+ /**
163
+ * Determine if a scan should fail CI based on grade threshold.
164
+ * Reuses the same logic as the TLS grader.
165
+ */
166
+ export function shouldFailForCodeGrade(actual, threshold) {
167
+ return gradeRank(actual) >= gradeRank(threshold);
168
+ }
169
+ //# sourceMappingURL=grader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grader.js","sourceRoot":"","sources":["../../../src/scanner/code/grader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { CodeFinding, Language } from '../../types/index.js';
2
+ /**
3
+ * Result of matching a file on disk — includes both findings and raw content
4
+ * so downstream stages (e.g. risk assessor) can inspect surrounding code
5
+ * without re-reading the file.
6
+ */
7
+ export interface MatchFileResult {
8
+ findings: CodeFinding[];
9
+ content: string;
10
+ }
11
+ /**
12
+ * Scan a file on disk and return code findings alongside the file content.
13
+ */
14
+ export declare function matchFile(filePath: string, language: Language): Promise<MatchFileResult>;
15
+ /**
16
+ * Scan file content (string) against patterns for a given language.
17
+ * Returns CodeFinding[] with line numbers, confidence, etc.
18
+ */
19
+ export declare function matchFileContent(content: string, language: Language, fileName: string): CodeFinding[];
20
+ //# sourceMappingURL=matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../../../src/scanner/code/matcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAiB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEjF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,eAAe,CAAC,CAK1B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,GACf,WAAW,EAAE,CA8If"}
@@ -0,0 +1,209 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { getPatterns } from './patterns/index.js';
4
+ /**
5
+ * Scan a file on disk and return code findings alongside the file content.
6
+ */
7
+ export async function matchFile(filePath, language) {
8
+ const content = await fs.promises.readFile(filePath, 'utf-8');
9
+ const relativeName = path.basename(filePath);
10
+ const findings = matchFileContent(content, language, relativeName);
11
+ return { findings, content };
12
+ }
13
+ /**
14
+ * Scan file content (string) against patterns for a given language.
15
+ * Returns CodeFinding[] with line numbers, confidence, etc.
16
+ */
17
+ export function matchFileContent(content, language, fileName) {
18
+ const patterns = getPatterns(language);
19
+ if (patterns.length === 0 || content.length === 0)
20
+ return [];
21
+ const lines = content.split('\n');
22
+ // Phase 1: Pre-scan for imports to determine confidence
23
+ const importHits = new Set();
24
+ for (const line of lines) {
25
+ for (const pattern of patterns) {
26
+ if (!pattern.importPatterns)
27
+ continue;
28
+ if (pattern.importPatterns.some((re) => re.test(line))) {
29
+ importHits.add(pattern.id);
30
+ }
31
+ }
32
+ }
33
+ // Phase 2: Line-by-line matching with comment filtering
34
+ const findings = [];
35
+ let inBlockComment = false;
36
+ let blockCommentStyle = null;
37
+ for (let i = 0; i < lines.length; i++) {
38
+ const rawLine = lines[i];
39
+ const trimmed = rawLine.trim();
40
+ // --- Block comment tracking ---
41
+ if (inBlockComment) {
42
+ if (blockCommentStyle === 'c' &&
43
+ trimmed.includes('*/')) {
44
+ inBlockComment = false;
45
+ blockCommentStyle = null;
46
+ }
47
+ else if (blockCommentStyle === 'python' &&
48
+ (trimmed.includes('"""') || trimmed.includes("'''"))) {
49
+ inBlockComment = false;
50
+ blockCommentStyle = null;
51
+ }
52
+ continue;
53
+ }
54
+ // Detect start of block comments
55
+ if ((language === 'javascript' || language === 'go' || language === 'java') &&
56
+ trimmed.startsWith('/*')) {
57
+ if (!trimmed.includes('*/')) {
58
+ inBlockComment = true;
59
+ blockCommentStyle = 'c';
60
+ }
61
+ continue;
62
+ }
63
+ if (language === 'python') {
64
+ if (trimmed.startsWith('"""') || trimmed.startsWith("'''")) {
65
+ const opener = trimmed.slice(0, 3);
66
+ const rest = trimmed.slice(3);
67
+ if (rest.includes(opener)) {
68
+ // Single-line triple-quoted string (e.g., """docstring""") — skip entirely
69
+ continue;
70
+ }
71
+ else {
72
+ // Multi-line docstring start
73
+ inBlockComment = true;
74
+ blockCommentStyle = 'python';
75
+ continue;
76
+ }
77
+ }
78
+ }
79
+ // Skip single-line comments
80
+ if (language === 'python' && trimmed.startsWith('#'))
81
+ continue;
82
+ if ((language === 'javascript' || language === 'go' || language === 'java') &&
83
+ trimmed.startsWith('//'))
84
+ continue;
85
+ // Skip Java block comment single-line: /** ... */
86
+ if ((language === 'javascript' || language === 'go' || language === 'java') &&
87
+ trimmed.startsWith('/*') &&
88
+ trimmed.includes('*/'))
89
+ continue;
90
+ // Strip inline comments for matching
91
+ const codeLine = stripInlineComment(trimmed, language);
92
+ // Skip lines that are pure string literals (heuristic)
93
+ if (isPureStringLiteral(codeLine, language))
94
+ continue;
95
+ // Phase 2: Match call patterns
96
+ for (const pattern of patterns) {
97
+ if (pattern.callPatterns.some((re) => re.test(codeLine))) {
98
+ const lineNumber = i + 1; // 1-indexed
99
+ // Determine confidence
100
+ let confidence = pattern.confidence;
101
+ if (pattern.importPatterns && pattern.importPatterns.length > 0) {
102
+ confidence = importHits.has(pattern.id) ? 'high' : 'medium';
103
+ }
104
+ // Extract key size if extractor defined
105
+ let keySize;
106
+ let risk = pattern.risk;
107
+ if (pattern.keySizeExtractor) {
108
+ const match = pattern.keySizeExtractor.exec(codeLine);
109
+ if (match) {
110
+ // Find first non-undefined capture group
111
+ const sizeStr = match.slice(1).find((g) => g !== undefined);
112
+ if (sizeStr) {
113
+ keySize = parseInt(sizeStr, 10);
114
+ if (pattern.keySizeRisk && !isNaN(keySize)) {
115
+ risk = pattern.keySizeRisk(keySize);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ findings.push({
121
+ patternId: pattern.id,
122
+ file: fileName,
123
+ line: lineNumber,
124
+ matchedLine: trimmed,
125
+ language,
126
+ category: pattern.category,
127
+ algorithm: pattern.algorithm,
128
+ keySize,
129
+ risk,
130
+ reason: pattern.description,
131
+ migration: pattern.migration,
132
+ confidence,
133
+ });
134
+ // Don't match the same line against more patterns of the same id
135
+ break;
136
+ }
137
+ }
138
+ }
139
+ return findings;
140
+ }
141
+ /**
142
+ * Strip inline comments from a code line.
143
+ */
144
+ function stripInlineComment(line, language) {
145
+ if (language === 'python') {
146
+ // Simple heuristic: find # not inside quotes
147
+ return stripAfterChar(line, '#');
148
+ }
149
+ if (language === 'javascript' || language === 'go' || language === 'java') {
150
+ return stripAfterStr(line, '//');
151
+ }
152
+ return line;
153
+ }
154
+ function stripAfterChar(line, char) {
155
+ let inSingle = false;
156
+ let inDouble = false;
157
+ for (let i = 0; i < line.length; i++) {
158
+ const c = line[i];
159
+ if (c === "'" && !inDouble)
160
+ inSingle = !inSingle;
161
+ else if (c === '"' && !inSingle)
162
+ inDouble = !inDouble;
163
+ else if (c === char && !inSingle && !inDouble) {
164
+ return line.slice(0, i).trim();
165
+ }
166
+ }
167
+ return line;
168
+ }
169
+ function stripAfterStr(line, str) {
170
+ let inSingle = false;
171
+ let inDouble = false;
172
+ for (let i = 0; i < line.length; i++) {
173
+ const c = line[i];
174
+ if (c === "'" && !inDouble)
175
+ inSingle = !inSingle;
176
+ else if (c === '"' && !inSingle)
177
+ inDouble = !inDouble;
178
+ else if (!inSingle &&
179
+ !inDouble &&
180
+ line.slice(i, i + str.length) === str) {
181
+ return line.slice(0, i).trim();
182
+ }
183
+ }
184
+ return line;
185
+ }
186
+ /**
187
+ * Heuristic: detect if a line is a pure string assignment (variable = "...").
188
+ */
189
+ function isPureStringLiteral(line, language) {
190
+ if (language === 'python') {
191
+ // Lines like: message = "Use rsa.generate_private_key() ..."
192
+ if (/^\w+\s*=\s*["'].*["']\s*$/.test(line))
193
+ return true;
194
+ if (/^\w+\s*=\s*['"].*['"]$/.test(line))
195
+ return true;
196
+ }
197
+ if (language === 'javascript' || language === 'java') {
198
+ // Lines like: const message = "Use ...";
199
+ if (/^(?:const|let|var|String)\s+\w+\s*=\s*["'`].*["'`]\s*;?\s*$/.test(line))
200
+ return true;
201
+ }
202
+ if (language === 'go') {
203
+ // Lines like: msg := "rsa.GenerateKey is vulnerable"
204
+ if (/^\w+\s*:?=\s*".*"\s*$/.test(line))
205
+ return true;
206
+ }
207
+ return false;
208
+ }
209
+ //# sourceMappingURL=matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matcher.js","sourceRoot":"","sources":["../../../src/scanner/code/matcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CryptoPattern } from '../../../types/index.js';
2
+ export declare const goPatterns: CryptoPattern[];
3
+ //# sourceMappingURL=go.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"go.d.ts","sourceRoot":"","sources":["../../../../src/scanner/code/patterns/go.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,eAAO,MAAM,UAAU,EAAE,aAAa,EAgOrC,CAAC"}