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.
- package/README.md +101 -8
- package/dist/commands/analyze.d.ts +9 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +129 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/index.js +49 -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 +41 -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 +265 -0
- package/dist/output/sarif.js.map +1 -0
- package/dist/output/terminal-code.d.ts +8 -0
- package/dist/output/terminal-code.d.ts.map +1 -0
- package/dist/output/terminal-code.js +155 -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 +169 -0
- package/dist/scanner/code/grader.js.map +1 -0
- package/dist/scanner/code/matcher.d.ts +20 -0
- package/dist/scanner/code/matcher.d.ts.map +1 -0
- package/dist/scanner/code/matcher.js +209 -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/scanner/code/risk-assessor.d.ts +25 -0
- package/dist/scanner/code/risk-assessor.d.ts.map +1 -0
- package/dist/scanner/code/risk-assessor.js +412 -0
- package/dist/scanner/code/risk-assessor.js.map +1 -0
- package/dist/types/index.d.ts +139 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +4 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
# PostQuant
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Scan your TLS endpoints and source code for quantum-vulnerable cryptography. Get a letter grade. Know your risk. Plan your migration.**
|
|
4
4
|
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
[](https://www.npmjs.com/package/postquant)
|
|
7
7
|
|
|
8
|
-
PostQuant scans TLS connections and reports which algorithms are vulnerable to quantum attacks
|
|
8
|
+
PostQuant scans TLS connections and source code, reports which algorithms are vulnerable to quantum attacks, grades them A+ through F, and tells you what to migrate to. Supports Python, JavaScript/TypeScript, Go, and Java.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Framework Scan Results
|
|
11
|
+
|
|
12
|
+
We scanned popular open-source frameworks with PostQuant v0.2.0. Here's what we found:
|
|
13
|
+
|
|
14
|
+
| Project | Language | Grade | Critical Findings | What We Found |
|
|
15
|
+
|---------|----------|-------|-------------------|---------------|
|
|
16
|
+
| Go stdlib | Go | F | 161 | ECDSA, RSA, DH throughout the crypto package |
|
|
17
|
+
| Spring Boot | Java | D+ | 7 | RSA in OAuth2 auth server, SHA-1 in DevTools |
|
|
18
|
+
| Django | Python | D+ | 7 | MD5 in auth hashers, SHA-1 in template caching |
|
|
19
|
+
| Next.js | JS | D+ | 4 | MD5 + SHA-1 in Turbopack runtime |
|
|
20
|
+
| Node.js | JS | D+ | 6 | DH + ECDH in crypto.js, SHA-1 in TLS |
|
|
21
|
+
| Flask | Python | D+ | 1 | SHA-1 in session management |
|
|
22
|
+
| FastAPI | Python | A | 0 | No quantum-vulnerable crypto detected |
|
|
23
|
+
| Express | JS | A | 0 | No quantum-vulnerable crypto detected |
|
|
24
|
+
| Gin | Go | A | 0 | No quantum-vulnerable crypto detected |
|
|
25
|
+
|
|
26
|
+
> Scanned with PostQuant v0.2.0 on March 2, 2026. Run `npx postquant analyze <path>` to scan your own projects.
|
|
11
27
|
|
|
12
28
|
## Why
|
|
13
29
|
|
|
@@ -17,6 +33,8 @@ PostQuant shows you what's exposed.
|
|
|
17
33
|
|
|
18
34
|
## Quick Start
|
|
19
35
|
|
|
36
|
+
### TLS Scanning
|
|
37
|
+
|
|
20
38
|
```bash
|
|
21
39
|
npx postquant scan example.com
|
|
22
40
|
```
|
|
@@ -38,8 +56,28 @@ Output:
|
|
|
38
56
|
|
|
39
57
|
Most sites today score C+ or C. That's expected — almost nobody has deployed post-quantum cryptography yet.
|
|
40
58
|
|
|
59
|
+
### Code Scanner
|
|
60
|
+
|
|
61
|
+
Scan source code for quantum-vulnerable cryptographic patterns. 54 detection patterns across 4 languages (Python, JavaScript/TypeScript, Go, Java) with zero new runtime dependencies.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Scan your project
|
|
65
|
+
npx postquant analyze .
|
|
66
|
+
|
|
67
|
+
# SARIF output for GitHub Code Scanning
|
|
68
|
+
npx postquant analyze ./src --format sarif
|
|
69
|
+
|
|
70
|
+
# CycloneDX CBOM for compliance
|
|
71
|
+
npx postquant analyze . --format cbom
|
|
72
|
+
|
|
73
|
+
# Filter by language with verbose output
|
|
74
|
+
npx postquant analyze . --language python --verbose
|
|
75
|
+
```
|
|
76
|
+
|
|
41
77
|
## Usage
|
|
42
78
|
|
|
79
|
+
### TLS Scanning
|
|
80
|
+
|
|
43
81
|
```bash
|
|
44
82
|
# Scan a single host
|
|
45
83
|
postquant scan example.com
|
|
@@ -60,6 +98,37 @@ postquant scan --file hosts.txt
|
|
|
60
98
|
postquant scan example.com --timeout 5000
|
|
61
99
|
```
|
|
62
100
|
|
|
101
|
+
### Code Scanning
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Scan a directory
|
|
105
|
+
postquant analyze ./src
|
|
106
|
+
|
|
107
|
+
# Scan a single file
|
|
108
|
+
postquant analyze ./src/auth.py
|
|
109
|
+
|
|
110
|
+
# Filter by language
|
|
111
|
+
postquant analyze ./src --language python
|
|
112
|
+
|
|
113
|
+
# JSON output
|
|
114
|
+
postquant analyze ./src --format json
|
|
115
|
+
|
|
116
|
+
# SARIF output (for GitHub Code Scanning)
|
|
117
|
+
postquant analyze ./src --format sarif > results.sarif
|
|
118
|
+
|
|
119
|
+
# CycloneDX CBOM output
|
|
120
|
+
postquant analyze ./src --format cbom > cbom.json
|
|
121
|
+
|
|
122
|
+
# Exclude directories
|
|
123
|
+
postquant analyze . --ignore "vendor/**" --ignore "test/**"
|
|
124
|
+
|
|
125
|
+
# Set fail threshold for CI
|
|
126
|
+
postquant analyze ./src --fail-grade D
|
|
127
|
+
|
|
128
|
+
# Show all findings including safe ones
|
|
129
|
+
postquant analyze ./src --verbose
|
|
130
|
+
```
|
|
131
|
+
|
|
63
132
|
## Grading
|
|
64
133
|
|
|
65
134
|
| Grade | Meaning |
|
|
@@ -75,23 +144,47 @@ postquant scan example.com --timeout 5000
|
|
|
75
144
|
|
|
76
145
|
+/- modifiers reflect classical crypto hygiene within each grade band.
|
|
77
146
|
|
|
147
|
+
## GitHub Actions
|
|
148
|
+
|
|
149
|
+
Add quantum vulnerability scanning to your CI/CD pipeline:
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
name: PostQuant Scan
|
|
153
|
+
on: [push, pull_request]
|
|
154
|
+
jobs:
|
|
155
|
+
quantum-check:
|
|
156
|
+
runs-on: ubuntu-latest
|
|
157
|
+
permissions:
|
|
158
|
+
security-events: write
|
|
159
|
+
steps:
|
|
160
|
+
- uses: actions/checkout@v4
|
|
161
|
+
- run: npx postquant analyze . --format sarif > postquant.sarif
|
|
162
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
163
|
+
with:
|
|
164
|
+
sarif_file: postquant.sarif
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Results appear directly in GitHub's **Security > Code scanning alerts** tab.
|
|
168
|
+
|
|
78
169
|
## Development
|
|
79
170
|
|
|
80
171
|
```bash
|
|
81
172
|
npm install # Install dependencies
|
|
82
173
|
npm run build # Compile TypeScript
|
|
83
174
|
npm test # Run tests
|
|
84
|
-
npm run dev -- scan example.com
|
|
175
|
+
npm run dev -- scan example.com # TLS scan from source
|
|
176
|
+
npm run dev -- analyze ./src # Code scan from source
|
|
85
177
|
```
|
|
86
178
|
|
|
87
179
|
## Roadmap
|
|
88
180
|
|
|
89
181
|
| Phase | Target | Status |
|
|
90
182
|
|-------|--------|--------|
|
|
91
|
-
| TLS scanner CLI | March 2026 | v0.
|
|
92
|
-
| Code scanner
|
|
93
|
-
|
|
|
94
|
-
| Web dashboard |
|
|
183
|
+
| TLS scanner CLI | March 2026 | v0.2.0 |
|
|
184
|
+
| Code scanner + CBOM | March 2026 | v0.2.0 |
|
|
185
|
+
| Migration playbook engine | April 2026 | Planned |
|
|
186
|
+
| Web dashboard + Enterprise tier | May 2026 | Planned |
|
|
187
|
+
| GitHub Actions Marketplace + CI/CD | June 2026 | Planned |
|
|
95
188
|
|
|
96
189
|
See [docs/ROADMAP.md](docs/ROADMAP.md) for details.
|
|
97
190
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AnalyzeOptions, Grade } from '../types/index.js';
|
|
2
|
+
interface AnalyzeResult {
|
|
3
|
+
exitCode: number;
|
|
4
|
+
output: string;
|
|
5
|
+
grade: Grade | null;
|
|
6
|
+
}
|
|
7
|
+
export declare function analyzeCommand(targetPath: string, options: AnalyzeOptions): Promise<AnalyzeResult>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=analyze.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAyB,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAmBtF,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC,CA2GxB"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { join, resolve, basename, extname } from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { discoverFiles } from '../scanner/code/discovery.js';
|
|
5
|
+
import { matchFile } from '../scanner/code/matcher.js';
|
|
6
|
+
import { classifyCodeFindings } from '../scanner/code/classifier.js';
|
|
7
|
+
import { assessFindings } from '../scanner/code/risk-assessor.js';
|
|
8
|
+
import { gradeCodeScan, shouldFailForCodeGrade } from '../scanner/code/grader.js';
|
|
9
|
+
import { formatCodeTerminal } from '../output/terminal-code.js';
|
|
10
|
+
import { formatCodeJson } from '../output/json-code.js';
|
|
11
|
+
import { formatSarif } from '../output/sarif.js';
|
|
12
|
+
import { formatCbom } from '../output/cbom.js';
|
|
13
|
+
/** Extension → Language mapping (duplicated from discovery for single-file mode). */
|
|
14
|
+
const EXTENSION_MAP = {
|
|
15
|
+
'.py': 'python',
|
|
16
|
+
'.pyw': 'python',
|
|
17
|
+
'.pyi': 'python',
|
|
18
|
+
'.js': 'javascript',
|
|
19
|
+
'.mjs': 'javascript',
|
|
20
|
+
'.cjs': 'javascript',
|
|
21
|
+
'.jsx': 'javascript',
|
|
22
|
+
'.ts': 'javascript',
|
|
23
|
+
'.mts': 'javascript',
|
|
24
|
+
'.cts': 'javascript',
|
|
25
|
+
'.tsx': 'javascript',
|
|
26
|
+
'.go': 'go',
|
|
27
|
+
'.java': 'java',
|
|
28
|
+
};
|
|
29
|
+
export async function analyzeCommand(targetPath, options) {
|
|
30
|
+
const absPath = resolve(targetPath);
|
|
31
|
+
let fileStat;
|
|
32
|
+
try {
|
|
33
|
+
fileStat = await stat(absPath);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return {
|
|
37
|
+
exitCode: 1,
|
|
38
|
+
output: chalk.red(`Error: path does not exist: ${targetPath}`),
|
|
39
|
+
grade: null,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
const allFindings = [];
|
|
44
|
+
const fileContents = new Map();
|
|
45
|
+
let filesScanned = 0;
|
|
46
|
+
if (fileStat.isFile()) {
|
|
47
|
+
// Single file mode
|
|
48
|
+
const ext = extname(absPath);
|
|
49
|
+
const lang = EXTENSION_MAP[ext];
|
|
50
|
+
if (lang && (!options.language || options.language === lang)) {
|
|
51
|
+
const { findings, content } = await matchFile(absPath, lang);
|
|
52
|
+
const normalizedName = basename(absPath);
|
|
53
|
+
// Normalize file paths to be relative-ish (just the basename for single files)
|
|
54
|
+
for (const f of findings) {
|
|
55
|
+
f.file = normalizedName;
|
|
56
|
+
}
|
|
57
|
+
allFindings.push(...findings);
|
|
58
|
+
fileContents.set(normalizedName, content);
|
|
59
|
+
filesScanned = 1;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
filesScanned = 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// Directory mode
|
|
67
|
+
const discovered = await discoverFiles(absPath, {
|
|
68
|
+
ignore: options.ignore,
|
|
69
|
+
ignoreFile: options.ignoreFile,
|
|
70
|
+
maxFiles: options.maxFiles,
|
|
71
|
+
language: options.language,
|
|
72
|
+
});
|
|
73
|
+
filesScanned = discovered.length;
|
|
74
|
+
for (const file of discovered) {
|
|
75
|
+
const fullPath = join(absPath, file.path);
|
|
76
|
+
try {
|
|
77
|
+
const { findings, content } = await matchFile(fullPath, file.language);
|
|
78
|
+
// Normalize to relative path from scan root
|
|
79
|
+
for (const f of findings) {
|
|
80
|
+
f.file = file.path;
|
|
81
|
+
}
|
|
82
|
+
allFindings.push(...findings);
|
|
83
|
+
fileContents.set(file.path, content);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Skip files that can't be read
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const durationMs = Date.now() - startTime;
|
|
91
|
+
const scanRoot = fileStat.isFile() ? absPath : absPath;
|
|
92
|
+
// Pipeline: classify → assess → grade → format
|
|
93
|
+
const classified = classifyCodeFindings(allFindings, scanRoot, filesScanned, durationMs);
|
|
94
|
+
let gradingFindings = classified.findings;
|
|
95
|
+
if (!options.noContext) {
|
|
96
|
+
gradingFindings = assessFindings(classified.findings, fileContents);
|
|
97
|
+
}
|
|
98
|
+
const graded = gradeCodeScan({ ...classified, findings: gradingFindings });
|
|
99
|
+
// Format output
|
|
100
|
+
let output;
|
|
101
|
+
switch (options.format) {
|
|
102
|
+
case 'json':
|
|
103
|
+
output = formatCodeJson(graded);
|
|
104
|
+
break;
|
|
105
|
+
case 'sarif':
|
|
106
|
+
output = formatSarif(graded);
|
|
107
|
+
break;
|
|
108
|
+
case 'cbom':
|
|
109
|
+
output = formatCbom(graded);
|
|
110
|
+
break;
|
|
111
|
+
case 'terminal':
|
|
112
|
+
default:
|
|
113
|
+
output = formatCodeTerminal(graded, {
|
|
114
|
+
verbose: options.verbose,
|
|
115
|
+
noMigration: options.noMigration,
|
|
116
|
+
showAll: options.showAll,
|
|
117
|
+
});
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
// Determine exit code
|
|
121
|
+
const shouldFail = shouldFailForCodeGrade(graded.baseGrade, options.failGrade);
|
|
122
|
+
const exitCode = shouldFail ? 1 : 0;
|
|
123
|
+
return {
|
|
124
|
+
exitCode,
|
|
125
|
+
output,
|
|
126
|
+
grade: graded.grade,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { scanCommand } from './commands/scan.js';
|
|
4
|
+
import { analyzeCommand } from './commands/analyze.js';
|
|
4
5
|
const VALID_GRADES = ['A+', 'A', 'B', 'C', 'D', 'F'];
|
|
6
|
+
const VALID_ANALYZE_FORMATS = ['terminal', 'json', 'sarif', 'cbom'];
|
|
7
|
+
const VALID_LANGUAGES = ['python', 'javascript', 'go', 'java'];
|
|
5
8
|
const program = new Command();
|
|
6
9
|
program
|
|
7
10
|
.name('postquant')
|
|
8
|
-
.description('Scan TLS endpoints for quantum-vulnerable cryptography')
|
|
9
|
-
.version('0.
|
|
11
|
+
.description('Scan TLS endpoints and source code for quantum-vulnerable cryptography')
|
|
12
|
+
.version('0.2.0');
|
|
10
13
|
program
|
|
11
14
|
.command('scan')
|
|
12
15
|
.description('Scan one or more TLS endpoints for quantum readiness')
|
|
@@ -36,5 +39,49 @@ program
|
|
|
36
39
|
});
|
|
37
40
|
process.exit(exitCode);
|
|
38
41
|
});
|
|
42
|
+
program
|
|
43
|
+
.command('analyze')
|
|
44
|
+
.description('Scan source code for quantum-vulnerable cryptography')
|
|
45
|
+
.argument('<path>', 'Directory or file to scan')
|
|
46
|
+
.option('-f, --format <format>', 'Output format (terminal, json, sarif, cbom)', 'terminal')
|
|
47
|
+
.option('-l, --language <language>', 'Filter by language (python, javascript, go, java)')
|
|
48
|
+
.option('--fail-grade <grade>', 'Exit non-zero at this grade or worse', 'C')
|
|
49
|
+
.option('--ignore <patterns...>', 'Glob patterns to exclude')
|
|
50
|
+
.option('--ignore-file <path>', 'File with ignore patterns', '.postquantignore')
|
|
51
|
+
.option('--max-files <count>', 'Maximum files to scan', '10000')
|
|
52
|
+
.option('--verbose', 'Show all findings including safe ones', false)
|
|
53
|
+
.option('--no-migration', 'Hide migration recommendations')
|
|
54
|
+
.option('--show-all', 'Show all findings including low and informational risk')
|
|
55
|
+
.option('--no-context', 'Skip risk assessment, use raw pattern matching only')
|
|
56
|
+
.action(async (targetPath, opts) => {
|
|
57
|
+
const format = opts.format;
|
|
58
|
+
if (!VALID_ANALYZE_FORMATS.includes(format)) {
|
|
59
|
+
console.error(`Invalid format: ${format}. Use one of: ${VALID_ANALYZE_FORMATS.join(', ')}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
if (opts.language && !VALID_LANGUAGES.includes(opts.language)) {
|
|
63
|
+
console.error(`Invalid language: ${opts.language}. Use one of: ${VALID_LANGUAGES.join(', ')}`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const failGrade = opts.failGrade;
|
|
67
|
+
if (!VALID_GRADES.includes(failGrade)) {
|
|
68
|
+
console.error(`Invalid fail-grade: ${failGrade}. Use one of: ${VALID_GRADES.join(', ')}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
const { exitCode, output } = await analyzeCommand(targetPath, {
|
|
72
|
+
format,
|
|
73
|
+
language: opts.language,
|
|
74
|
+
failGrade,
|
|
75
|
+
ignore: opts.ignore ?? [],
|
|
76
|
+
ignoreFile: opts.ignoreFile,
|
|
77
|
+
maxFiles: parseInt(opts.maxFiles, 10),
|
|
78
|
+
verbose: opts.verbose,
|
|
79
|
+
noMigration: !opts.migration,
|
|
80
|
+
showAll: opts.showAll ?? false,
|
|
81
|
+
noContext: !opts.context,
|
|
82
|
+
});
|
|
83
|
+
console.log(output);
|
|
84
|
+
process.exit(exitCode);
|
|
85
|
+
});
|
|
39
86
|
program.parse();
|
|
40
87
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cbom.d.ts","sourceRoot":"","sources":["../../src/output/cbom.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAA+B,MAAM,mBAAmB,CAAC;AA0EvF,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAiF3D"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
function getVersion() {
|
|
6
|
+
try {
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf-8'));
|
|
9
|
+
return pkg.version;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return '0.1.1';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// --- Category → CycloneDX primitive mapping (Section 7.3) ---
|
|
16
|
+
function categoryToPrimitive(category) {
|
|
17
|
+
switch (category) {
|
|
18
|
+
case 'asymmetric-encryption':
|
|
19
|
+
return 'pke';
|
|
20
|
+
case 'digital-signature':
|
|
21
|
+
return 'signature';
|
|
22
|
+
case 'key-exchange':
|
|
23
|
+
return 'kex';
|
|
24
|
+
case 'weak-symmetric':
|
|
25
|
+
case 'safe-symmetric':
|
|
26
|
+
case 'broken-cipher':
|
|
27
|
+
return 'ae';
|
|
28
|
+
case 'weak-hash':
|
|
29
|
+
case 'safe-hash':
|
|
30
|
+
return 'hash';
|
|
31
|
+
case 'pqc-algorithm':
|
|
32
|
+
return 'kem'; // default for PQC; could vary by algorithm
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// --- NIST Quantum Security Level mapping (Section 7.4) ---
|
|
36
|
+
function nistQuantumSecurityLevel(finding) {
|
|
37
|
+
// Level 0: broken by quantum computer (all critical asymmetric, weak-hash, broken-cipher)
|
|
38
|
+
if (finding.risk === 'critical')
|
|
39
|
+
return 0;
|
|
40
|
+
// Level 5: AES-256, SHA-384, SHA-512, SHA-3, ChaCha20
|
|
41
|
+
const algoUpper = finding.algorithm.toUpperCase();
|
|
42
|
+
if (algoUpper.includes('AES-256') ||
|
|
43
|
+
algoUpper.includes('SHA-384') ||
|
|
44
|
+
algoUpper.includes('SHA-512') ||
|
|
45
|
+
algoUpper.includes('SHA3') ||
|
|
46
|
+
algoUpper.includes('SHA-3') ||
|
|
47
|
+
algoUpper.includes('CHACHA20')) {
|
|
48
|
+
return 5;
|
|
49
|
+
}
|
|
50
|
+
// Moderate (AES-128): effectively ~level 1 post-Grover
|
|
51
|
+
if (algoUpper.includes('AES-128'))
|
|
52
|
+
return 1;
|
|
53
|
+
// PQC algorithms
|
|
54
|
+
if (finding.category === 'pqc-algorithm') {
|
|
55
|
+
if (algoUpper.includes('512') || algoUpper.includes('-44'))
|
|
56
|
+
return 1;
|
|
57
|
+
if (algoUpper.includes('768') || algoUpper.includes('-65'))
|
|
58
|
+
return 3;
|
|
59
|
+
if (algoUpper.includes('1024') || algoUpper.includes('-87'))
|
|
60
|
+
return 5;
|
|
61
|
+
return 3; // default PQC
|
|
62
|
+
}
|
|
63
|
+
// Safe hash/symmetric defaults
|
|
64
|
+
if (finding.risk === 'safe')
|
|
65
|
+
return 5;
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
// --- Public API ---
|
|
69
|
+
export function formatCbom(result) {
|
|
70
|
+
// Group findings by algorithm name
|
|
71
|
+
const byAlgorithm = new Map();
|
|
72
|
+
for (const f of result.findings) {
|
|
73
|
+
const list = byAlgorithm.get(f.algorithm) ?? [];
|
|
74
|
+
list.push(f);
|
|
75
|
+
byAlgorithm.set(f.algorithm, list);
|
|
76
|
+
}
|
|
77
|
+
// Build components
|
|
78
|
+
const components = [];
|
|
79
|
+
const componentRefs = [];
|
|
80
|
+
for (const [algorithm, findings] of byAlgorithm) {
|
|
81
|
+
const ref = randomUUID();
|
|
82
|
+
componentRefs.push(ref);
|
|
83
|
+
const representative = findings[0];
|
|
84
|
+
const occurrences = findings.map((f) => ({
|
|
85
|
+
location: f.file,
|
|
86
|
+
line: f.line,
|
|
87
|
+
additionalContext: f.matchedLine,
|
|
88
|
+
}));
|
|
89
|
+
components.push({
|
|
90
|
+
type: 'cryptographic-asset',
|
|
91
|
+
name: algorithm,
|
|
92
|
+
'bom-ref': ref,
|
|
93
|
+
evidence: { occurrences },
|
|
94
|
+
cryptoProperties: {
|
|
95
|
+
assetType: 'algorithm',
|
|
96
|
+
algorithmProperties: {
|
|
97
|
+
primitive: categoryToPrimitive(representative.category),
|
|
98
|
+
parameterSetIdentifier: extractParameterSet(representative),
|
|
99
|
+
cryptoFunctions: inferCryptoFunctions(representative),
|
|
100
|
+
classicalSecurityLevel: classicalSecurityLevel(representative),
|
|
101
|
+
nistQuantumSecurityLevel: nistQuantumSecurityLevel(representative),
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const cbom = {
|
|
107
|
+
bomFormat: 'CycloneDX',
|
|
108
|
+
specVersion: '1.6',
|
|
109
|
+
version: 1,
|
|
110
|
+
serialNumber: `urn:uuid:${randomUUID()}`,
|
|
111
|
+
metadata: {
|
|
112
|
+
timestamp: new Date().toISOString(),
|
|
113
|
+
tools: {
|
|
114
|
+
components: [
|
|
115
|
+
{
|
|
116
|
+
type: 'application',
|
|
117
|
+
name: 'postquant',
|
|
118
|
+
version: getVersion(),
|
|
119
|
+
description: 'Quantum readiness scanner',
|
|
120
|
+
externalReferences: [
|
|
121
|
+
{
|
|
122
|
+
type: 'website',
|
|
123
|
+
url: 'https://postquant.dev',
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
component: {
|
|
130
|
+
type: 'application',
|
|
131
|
+
name: extractProjectName(result.scanRoot),
|
|
132
|
+
'bom-ref': 'scanned-project',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
components,
|
|
136
|
+
dependencies: [
|
|
137
|
+
{
|
|
138
|
+
ref: 'scanned-project',
|
|
139
|
+
dependsOn: componentRefs,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
return JSON.stringify(cbom, null, 2);
|
|
144
|
+
}
|
|
145
|
+
// --- Helpers ---
|
|
146
|
+
function extractProjectName(scanRoot) {
|
|
147
|
+
const parts = scanRoot.split('/').filter(Boolean);
|
|
148
|
+
return parts[parts.length - 1] || 'unknown-project';
|
|
149
|
+
}
|
|
150
|
+
function extractParameterSet(finding) {
|
|
151
|
+
if (finding.keySize)
|
|
152
|
+
return String(finding.keySize);
|
|
153
|
+
// Try to pull numbers from algorithm name (e.g., "RSA-2048" → "2048")
|
|
154
|
+
const match = finding.algorithm.match(/(\d+)/);
|
|
155
|
+
return match ? match[1] : '';
|
|
156
|
+
}
|
|
157
|
+
function inferCryptoFunctions(finding) {
|
|
158
|
+
const id = finding.patternId.toLowerCase();
|
|
159
|
+
if (id.includes('keygen') || id.includes('generate'))
|
|
160
|
+
return ['keygen'];
|
|
161
|
+
if (id.includes('sign'))
|
|
162
|
+
return ['sign', 'verify'];
|
|
163
|
+
if (id.includes('encrypt') || id.includes('cipher'))
|
|
164
|
+
return ['encrypt', 'decrypt'];
|
|
165
|
+
if (id.includes('exchange') || id.includes('dh') || id.includes('ecdh'))
|
|
166
|
+
return ['keyexchange'];
|
|
167
|
+
if (id.includes('hash') || id.includes('md5') || id.includes('sha'))
|
|
168
|
+
return ['digest'];
|
|
169
|
+
// Default based on category
|
|
170
|
+
switch (finding.category) {
|
|
171
|
+
case 'asymmetric-encryption':
|
|
172
|
+
return ['keygen', 'encrypt', 'decrypt'];
|
|
173
|
+
case 'digital-signature':
|
|
174
|
+
return ['sign', 'verify'];
|
|
175
|
+
case 'key-exchange':
|
|
176
|
+
return ['keyexchange'];
|
|
177
|
+
case 'weak-hash':
|
|
178
|
+
case 'safe-hash':
|
|
179
|
+
return ['digest'];
|
|
180
|
+
case 'weak-symmetric':
|
|
181
|
+
case 'safe-symmetric':
|
|
182
|
+
case 'broken-cipher':
|
|
183
|
+
return ['encrypt', 'decrypt'];
|
|
184
|
+
case 'pqc-algorithm':
|
|
185
|
+
return ['keygen'];
|
|
186
|
+
default:
|
|
187
|
+
return ['unknown'];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function classicalSecurityLevel(finding) {
|
|
191
|
+
const algoUpper = finding.algorithm.toUpperCase();
|
|
192
|
+
// RSA key sizes
|
|
193
|
+
if (algoUpper.includes('RSA')) {
|
|
194
|
+
if (algoUpper.includes('4096'))
|
|
195
|
+
return 140;
|
|
196
|
+
if (algoUpper.includes('3072'))
|
|
197
|
+
return 128;
|
|
198
|
+
if (algoUpper.includes('2048'))
|
|
199
|
+
return 112;
|
|
200
|
+
if (algoUpper.includes('1024'))
|
|
201
|
+
return 80;
|
|
202
|
+
return 112;
|
|
203
|
+
}
|
|
204
|
+
// ECC curves
|
|
205
|
+
if (algoUpper.includes('P-521') || algoUpper.includes('SECP521'))
|
|
206
|
+
return 256;
|
|
207
|
+
if (algoUpper.includes('P-384') || algoUpper.includes('SECP384'))
|
|
208
|
+
return 192;
|
|
209
|
+
if (algoUpper.includes('P-256') || algoUpper.includes('SECP256') || algoUpper.includes('ED25519') || algoUpper.includes('X25519'))
|
|
210
|
+
return 128;
|
|
211
|
+
// Symmetric
|
|
212
|
+
if (algoUpper.includes('AES-256') || algoUpper.includes('CHACHA20'))
|
|
213
|
+
return 256;
|
|
214
|
+
if (algoUpper.includes('AES-192'))
|
|
215
|
+
return 192;
|
|
216
|
+
if (algoUpper.includes('AES-128'))
|
|
217
|
+
return 128;
|
|
218
|
+
if (algoUpper.includes('3DES'))
|
|
219
|
+
return 112;
|
|
220
|
+
if (algoUpper.includes('DES'))
|
|
221
|
+
return 56;
|
|
222
|
+
// Hashes
|
|
223
|
+
if (algoUpper.includes('SHA-512') || algoUpper.includes('SHA3-512'))
|
|
224
|
+
return 256;
|
|
225
|
+
if (algoUpper.includes('SHA-384') || algoUpper.includes('SHA3-384'))
|
|
226
|
+
return 192;
|
|
227
|
+
if (algoUpper.includes('SHA-256') || algoUpper.includes('SHA3-256'))
|
|
228
|
+
return 128;
|
|
229
|
+
if (algoUpper.includes('SHA-1') || algoUpper === 'SHA1')
|
|
230
|
+
return 80;
|
|
231
|
+
if (algoUpper.includes('MD5'))
|
|
232
|
+
return 64;
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=cbom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cbom.js","sourceRoot":"","sources":["../../src/output/cbom.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-code.d.ts","sourceRoot":"","sources":["../../src/output/json-code.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAmB,MAAM,mBAAmB,CAAC;AAe3E,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CA4B/D"}
|