postquant 0.1.2 → 0.2.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.
- package/README.md +58 -8
- package/dist/commands/analyze.d.ts +9 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +119 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/index.js +45 -2
- package/dist/index.js.map +1 -1
- package/dist/output/cbom.d.ts +3 -0
- package/dist/output/cbom.d.ts.map +1 -0
- package/dist/output/cbom.js +235 -0
- package/dist/output/cbom.js.map +1 -0
- package/dist/output/json-code.d.ts +3 -0
- package/dist/output/json-code.d.ts.map +1 -0
- package/dist/output/json-code.js +29 -0
- package/dist/output/json-code.js.map +1 -0
- package/dist/output/sarif.d.ts +3 -0
- package/dist/output/sarif.d.ts.map +1 -0
- package/dist/output/sarif.js +240 -0
- package/dist/output/sarif.js.map +1 -0
- package/dist/output/terminal-code.d.ts +7 -0
- package/dist/output/terminal-code.d.ts.map +1 -0
- package/dist/output/terminal-code.js +95 -0
- package/dist/output/terminal-code.js.map +1 -0
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +14 -2
- package/dist/output/terminal.js.map +1 -1
- package/dist/scanner/code/classifier.d.ts +9 -0
- package/dist/scanner/code/classifier.d.ts.map +1 -0
- package/dist/scanner/code/classifier.js +19 -0
- package/dist/scanner/code/classifier.js.map +1 -0
- package/dist/scanner/code/discovery.d.ts +17 -0
- package/dist/scanner/code/discovery.d.ts.map +1 -0
- package/dist/scanner/code/discovery.js +167 -0
- package/dist/scanner/code/discovery.js.map +1 -0
- package/dist/scanner/code/grader.d.ts +27 -0
- package/dist/scanner/code/grader.d.ts.map +1 -0
- package/dist/scanner/code/grader.js +115 -0
- package/dist/scanner/code/grader.js.map +1 -0
- package/dist/scanner/code/matcher.d.ts +11 -0
- package/dist/scanner/code/matcher.d.ts.map +1 -0
- package/dist/scanner/code/matcher.js +208 -0
- package/dist/scanner/code/matcher.js.map +1 -0
- package/dist/scanner/code/patterns/go.d.ts +3 -0
- package/dist/scanner/code/patterns/go.d.ts.map +1 -0
- package/dist/scanner/code/patterns/go.js +226 -0
- package/dist/scanner/code/patterns/go.js.map +1 -0
- package/dist/scanner/code/patterns/index.d.ts +11 -0
- package/dist/scanner/code/patterns/index.d.ts.map +1 -0
- package/dist/scanner/code/patterns/index.js +20 -0
- package/dist/scanner/code/patterns/index.js.map +1 -0
- package/dist/scanner/code/patterns/java.d.ts +3 -0
- package/dist/scanner/code/patterns/java.d.ts.map +1 -0
- package/dist/scanner/code/patterns/java.js +239 -0
- package/dist/scanner/code/patterns/java.js.map +1 -0
- package/dist/scanner/code/patterns/javascript.d.ts +3 -0
- package/dist/scanner/code/patterns/javascript.d.ts.map +1 -0
- package/dist/scanner/code/patterns/javascript.js +243 -0
- package/dist/scanner/code/patterns/javascript.js.map +1 -0
- package/dist/scanner/code/patterns/python.d.ts +3 -0
- package/dist/scanner/code/patterns/python.d.ts.map +1 -0
- package/dist/scanner/code/patterns/python.js +255 -0
- package/dist/scanner/code/patterns/python.js.map +1 -0
- package/dist/types/index.d.ts +118 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -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,EAIhB,SAAS,EAEV,MAAM,sBAAsB,CAAC;AAO9B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,gBAAgB,CAuEpE;AAyBD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,SAAS,GACnB,OAAO,CAET"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const BASE_GRADE_ORDER = ['A+', 'A', 'B', 'C', 'D', 'F'];
|
|
2
|
+
/** Algorithms that are already broken classically — cap grade at D. */
|
|
3
|
+
const BROKEN_ALGORITHMS = ['MD5', 'SHA-1', 'SHA1', 'DES', '3DES', 'TRIPLE-DES'];
|
|
4
|
+
/**
|
|
5
|
+
* Grade a code scan result.
|
|
6
|
+
*
|
|
7
|
+
* Grading logic (from spec Section 6.1):
|
|
8
|
+
* 0 critical + 0 moderate → A (A+ if PQC detected)
|
|
9
|
+
* 0 critical + moderate only → B
|
|
10
|
+
* 1-5 critical → C
|
|
11
|
+
* 6-20 critical → D
|
|
12
|
+
* 21+ critical → F
|
|
13
|
+
*
|
|
14
|
+
* Special cases:
|
|
15
|
+
* MD5/SHA-1/DES/3DES → cap at D
|
|
16
|
+
*
|
|
17
|
+
* Modifiers (same as TLS grader):
|
|
18
|
+
* 0 moderate → +
|
|
19
|
+
* 1 moderate → (none)
|
|
20
|
+
* 2+ moderate → -
|
|
21
|
+
* A+, A, F → no modifier
|
|
22
|
+
*/
|
|
23
|
+
export function gradeCodeScan(scan) {
|
|
24
|
+
const { findings } = scan;
|
|
25
|
+
const critical = findings.filter((f) => f.risk === 'critical');
|
|
26
|
+
const moderate = findings.filter((f) => f.risk === 'moderate');
|
|
27
|
+
const safe = findings.filter((f) => f.risk === 'safe');
|
|
28
|
+
// Determine base grade from critical/moderate counts
|
|
29
|
+
let baseGrade;
|
|
30
|
+
if (critical.length === 0 && moderate.length === 0) {
|
|
31
|
+
const hasPqc = findings.some((f) => f.category === 'pqc-algorithm');
|
|
32
|
+
baseGrade = hasPqc ? 'A+' : 'A';
|
|
33
|
+
}
|
|
34
|
+
else if (critical.length === 0) {
|
|
35
|
+
baseGrade = 'B';
|
|
36
|
+
}
|
|
37
|
+
else if (critical.length <= 5) {
|
|
38
|
+
baseGrade = 'C';
|
|
39
|
+
}
|
|
40
|
+
else if (critical.length <= 20) {
|
|
41
|
+
baseGrade = 'D';
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
baseGrade = 'F';
|
|
45
|
+
}
|
|
46
|
+
// Special case: broken algorithms cap at D
|
|
47
|
+
const hasBrokenAlgo = findings.some((f) => BROKEN_ALGORITHMS.some((broken) => f.algorithm.toUpperCase() === broken.toUpperCase()));
|
|
48
|
+
if (hasBrokenAlgo && gradeRank(baseGrade) < gradeRank('D')) {
|
|
49
|
+
baseGrade = 'D';
|
|
50
|
+
}
|
|
51
|
+
// Compute modifier (same logic as TLS grader)
|
|
52
|
+
let modifier = '';
|
|
53
|
+
if (baseGrade !== 'A+' && baseGrade !== 'A' && baseGrade !== 'F') {
|
|
54
|
+
if (moderate.length === 0) {
|
|
55
|
+
modifier = '+';
|
|
56
|
+
}
|
|
57
|
+
else if (moderate.length >= 2) {
|
|
58
|
+
modifier = '-';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const displayGrade = (baseGrade + modifier);
|
|
62
|
+
// Collect unique migration notes
|
|
63
|
+
const migrationSet = new Set();
|
|
64
|
+
for (const f of findings) {
|
|
65
|
+
if (f.migration)
|
|
66
|
+
migrationSet.add(f.migration);
|
|
67
|
+
}
|
|
68
|
+
// Build per-file breakdown
|
|
69
|
+
const fileBreakdown = buildFileBreakdown(findings);
|
|
70
|
+
return {
|
|
71
|
+
scanRoot: scan.scanRoot,
|
|
72
|
+
grade: displayGrade,
|
|
73
|
+
baseGrade,
|
|
74
|
+
modifier,
|
|
75
|
+
findings,
|
|
76
|
+
migrationNotes: [...migrationSet],
|
|
77
|
+
summary: {
|
|
78
|
+
critical: critical.length,
|
|
79
|
+
moderate: moderate.length,
|
|
80
|
+
safe: safe.length,
|
|
81
|
+
total: findings.length,
|
|
82
|
+
filesScanned: scan.filesScanned,
|
|
83
|
+
filesWithFindings: scan.filesWithFindings,
|
|
84
|
+
},
|
|
85
|
+
fileBreakdown,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function buildFileBreakdown(findings) {
|
|
89
|
+
const byFile = new Map();
|
|
90
|
+
for (const f of findings) {
|
|
91
|
+
const list = byFile.get(f.file) ?? [];
|
|
92
|
+
list.push(f);
|
|
93
|
+
byFile.set(f.file, list);
|
|
94
|
+
}
|
|
95
|
+
return [...byFile.entries()].map(([file, fileFindgs]) => ({
|
|
96
|
+
file,
|
|
97
|
+
language: fileFindgs[0].language,
|
|
98
|
+
findings: fileFindgs,
|
|
99
|
+
criticalCount: fileFindgs.filter((f) => f.risk === 'critical').length,
|
|
100
|
+
moderateCount: fileFindgs.filter((f) => f.risk === 'moderate').length,
|
|
101
|
+
safeCount: fileFindgs.filter((f) => f.risk === 'safe').length,
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
/** Return numeric rank for a base grade (higher = worse). */
|
|
105
|
+
function gradeRank(g) {
|
|
106
|
+
return BASE_GRADE_ORDER.indexOf(g);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Determine if a scan should fail CI based on grade threshold.
|
|
110
|
+
* Reuses the same logic as the TLS grader.
|
|
111
|
+
*/
|
|
112
|
+
export function shouldFailForCodeGrade(actual, threshold) {
|
|
113
|
+
return gradeRank(actual) >= gradeRank(threshold);
|
|
114
|
+
}
|
|
115
|
+
//# 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,11 @@
|
|
|
1
|
+
import type { CodeFinding, Language } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Scan a file on disk and return code findings.
|
|
4
|
+
*/
|
|
5
|
+
export declare function matchFile(filePath: string, language: Language): Promise<CodeFinding[]>;
|
|
6
|
+
/**
|
|
7
|
+
* Scan file content (string) against patterns for a given language.
|
|
8
|
+
* Returns CodeFinding[] with line numbers, confidence, etc.
|
|
9
|
+
*/
|
|
10
|
+
export declare function matchFileContent(content: string, language: Language, fileName: string): CodeFinding[];
|
|
11
|
+
//# 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;;GAEG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,WAAW,EAAE,CAAC,CAIxB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,GACf,WAAW,EAAE,CA8If"}
|
|
@@ -0,0 +1,208 @@
|
|
|
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.
|
|
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
|
+
return matchFileContent(content, language, relativeName);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Scan file content (string) against patterns for a given language.
|
|
14
|
+
* Returns CodeFinding[] with line numbers, confidence, etc.
|
|
15
|
+
*/
|
|
16
|
+
export function matchFileContent(content, language, fileName) {
|
|
17
|
+
const patterns = getPatterns(language);
|
|
18
|
+
if (patterns.length === 0 || content.length === 0)
|
|
19
|
+
return [];
|
|
20
|
+
const lines = content.split('\n');
|
|
21
|
+
// Phase 1: Pre-scan for imports to determine confidence
|
|
22
|
+
const importHits = new Set();
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
for (const pattern of patterns) {
|
|
25
|
+
if (!pattern.importPatterns)
|
|
26
|
+
continue;
|
|
27
|
+
if (pattern.importPatterns.some((re) => re.test(line))) {
|
|
28
|
+
importHits.add(pattern.id);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Phase 2: Line-by-line matching with comment filtering
|
|
33
|
+
const findings = [];
|
|
34
|
+
let inBlockComment = false;
|
|
35
|
+
let blockCommentStyle = null;
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
const rawLine = lines[i];
|
|
38
|
+
const trimmed = rawLine.trim();
|
|
39
|
+
// --- Block comment tracking ---
|
|
40
|
+
if (inBlockComment) {
|
|
41
|
+
if (blockCommentStyle === 'c' &&
|
|
42
|
+
trimmed.includes('*/')) {
|
|
43
|
+
inBlockComment = false;
|
|
44
|
+
blockCommentStyle = null;
|
|
45
|
+
}
|
|
46
|
+
else if (blockCommentStyle === 'python' &&
|
|
47
|
+
(trimmed.includes('"""') || trimmed.includes("'''"))) {
|
|
48
|
+
inBlockComment = false;
|
|
49
|
+
blockCommentStyle = null;
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
// Detect start of block comments
|
|
54
|
+
if ((language === 'javascript' || language === 'go' || language === 'java') &&
|
|
55
|
+
trimmed.startsWith('/*')) {
|
|
56
|
+
if (!trimmed.includes('*/')) {
|
|
57
|
+
inBlockComment = true;
|
|
58
|
+
blockCommentStyle = 'c';
|
|
59
|
+
}
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (language === 'python') {
|
|
63
|
+
if (trimmed.startsWith('"""') || trimmed.startsWith("'''")) {
|
|
64
|
+
const opener = trimmed.slice(0, 3);
|
|
65
|
+
const rest = trimmed.slice(3);
|
|
66
|
+
if (rest.includes(opener)) {
|
|
67
|
+
// Single-line triple-quoted string (e.g., """docstring""") — skip entirely
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// Multi-line docstring start
|
|
72
|
+
inBlockComment = true;
|
|
73
|
+
blockCommentStyle = 'python';
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Skip single-line comments
|
|
79
|
+
if (language === 'python' && trimmed.startsWith('#'))
|
|
80
|
+
continue;
|
|
81
|
+
if ((language === 'javascript' || language === 'go' || language === 'java') &&
|
|
82
|
+
trimmed.startsWith('//'))
|
|
83
|
+
continue;
|
|
84
|
+
// Skip Java block comment single-line: /** ... */
|
|
85
|
+
if ((language === 'javascript' || language === 'go' || language === 'java') &&
|
|
86
|
+
trimmed.startsWith('/*') &&
|
|
87
|
+
trimmed.includes('*/'))
|
|
88
|
+
continue;
|
|
89
|
+
// Strip inline comments for matching
|
|
90
|
+
const codeLine = stripInlineComment(trimmed, language);
|
|
91
|
+
// Skip lines that are pure string literals (heuristic)
|
|
92
|
+
if (isPureStringLiteral(codeLine, language))
|
|
93
|
+
continue;
|
|
94
|
+
// Phase 2: Match call patterns
|
|
95
|
+
for (const pattern of patterns) {
|
|
96
|
+
if (pattern.callPatterns.some((re) => re.test(codeLine))) {
|
|
97
|
+
const lineNumber = i + 1; // 1-indexed
|
|
98
|
+
// Determine confidence
|
|
99
|
+
let confidence = pattern.confidence;
|
|
100
|
+
if (pattern.importPatterns && pattern.importPatterns.length > 0) {
|
|
101
|
+
confidence = importHits.has(pattern.id) ? 'high' : 'medium';
|
|
102
|
+
}
|
|
103
|
+
// Extract key size if extractor defined
|
|
104
|
+
let keySize;
|
|
105
|
+
let risk = pattern.risk;
|
|
106
|
+
if (pattern.keySizeExtractor) {
|
|
107
|
+
const match = pattern.keySizeExtractor.exec(codeLine);
|
|
108
|
+
if (match) {
|
|
109
|
+
// Find first non-undefined capture group
|
|
110
|
+
const sizeStr = match.slice(1).find((g) => g !== undefined);
|
|
111
|
+
if (sizeStr) {
|
|
112
|
+
keySize = parseInt(sizeStr, 10);
|
|
113
|
+
if (pattern.keySizeRisk && !isNaN(keySize)) {
|
|
114
|
+
risk = pattern.keySizeRisk(keySize);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
findings.push({
|
|
120
|
+
patternId: pattern.id,
|
|
121
|
+
file: fileName,
|
|
122
|
+
line: lineNumber,
|
|
123
|
+
matchedLine: trimmed,
|
|
124
|
+
language,
|
|
125
|
+
category: pattern.category,
|
|
126
|
+
algorithm: pattern.algorithm,
|
|
127
|
+
keySize,
|
|
128
|
+
risk,
|
|
129
|
+
reason: pattern.description,
|
|
130
|
+
migration: pattern.migration,
|
|
131
|
+
confidence,
|
|
132
|
+
});
|
|
133
|
+
// Don't match the same line against more patterns of the same id
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return findings;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Strip inline comments from a code line.
|
|
142
|
+
*/
|
|
143
|
+
function stripInlineComment(line, language) {
|
|
144
|
+
if (language === 'python') {
|
|
145
|
+
// Simple heuristic: find # not inside quotes
|
|
146
|
+
return stripAfterChar(line, '#');
|
|
147
|
+
}
|
|
148
|
+
if (language === 'javascript' || language === 'go' || language === 'java') {
|
|
149
|
+
return stripAfterStr(line, '//');
|
|
150
|
+
}
|
|
151
|
+
return line;
|
|
152
|
+
}
|
|
153
|
+
function stripAfterChar(line, char) {
|
|
154
|
+
let inSingle = false;
|
|
155
|
+
let inDouble = false;
|
|
156
|
+
for (let i = 0; i < line.length; i++) {
|
|
157
|
+
const c = line[i];
|
|
158
|
+
if (c === "'" && !inDouble)
|
|
159
|
+
inSingle = !inSingle;
|
|
160
|
+
else if (c === '"' && !inSingle)
|
|
161
|
+
inDouble = !inDouble;
|
|
162
|
+
else if (c === char && !inSingle && !inDouble) {
|
|
163
|
+
return line.slice(0, i).trim();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return line;
|
|
167
|
+
}
|
|
168
|
+
function stripAfterStr(line, str) {
|
|
169
|
+
let inSingle = false;
|
|
170
|
+
let inDouble = false;
|
|
171
|
+
for (let i = 0; i < line.length; i++) {
|
|
172
|
+
const c = line[i];
|
|
173
|
+
if (c === "'" && !inDouble)
|
|
174
|
+
inSingle = !inSingle;
|
|
175
|
+
else if (c === '"' && !inSingle)
|
|
176
|
+
inDouble = !inDouble;
|
|
177
|
+
else if (!inSingle &&
|
|
178
|
+
!inDouble &&
|
|
179
|
+
line.slice(i, i + str.length) === str) {
|
|
180
|
+
return line.slice(0, i).trim();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return line;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Heuristic: detect if a line is a pure string assignment (variable = "...").
|
|
187
|
+
*/
|
|
188
|
+
function isPureStringLiteral(line, language) {
|
|
189
|
+
if (language === 'python') {
|
|
190
|
+
// Lines like: message = "Use rsa.generate_private_key() ..."
|
|
191
|
+
if (/^\w+\s*=\s*["'].*["']\s*$/.test(line))
|
|
192
|
+
return true;
|
|
193
|
+
if (/^\w+\s*=\s*['"].*['"]$/.test(line))
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
if (language === 'javascript' || language === 'java') {
|
|
197
|
+
// Lines like: const message = "Use ...";
|
|
198
|
+
if (/^(?:const|let|var|String)\s+\w+\s*=\s*["'`].*["'`]\s*;?\s*$/.test(line))
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
if (language === 'go') {
|
|
202
|
+
// Lines like: msg := "rsa.GenerateKey is vulnerable"
|
|
203
|
+
if (/^\w+\s*:?=\s*".*"\s*$/.test(line))
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
//# 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 @@
|
|
|
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"}
|