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.
Files changed (65) hide show
  1. package/README.md +58 -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 +119 -0
  5. package/dist/commands/analyze.js.map +1 -0
  6. package/dist/index.js +45 -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 +29 -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 +240 -0
  19. package/dist/output/sarif.js.map +1 -0
  20. package/dist/output/terminal-code.d.ts +7 -0
  21. package/dist/output/terminal-code.d.ts.map +1 -0
  22. package/dist/output/terminal-code.js +95 -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 +115 -0
  38. package/dist/scanner/code/grader.js.map +1 -0
  39. package/dist/scanner/code/matcher.d.ts +11 -0
  40. package/dist/scanner/code/matcher.d.ts.map +1 -0
  41. package/dist/scanner/code/matcher.js +208 -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/types/index.d.ts +118 -0
  64. package/dist/types/index.d.ts.map +1 -1
  65. package/package.json +1 -1
package/README.md CHANGED
@@ -1,13 +1,11 @@
1
1
  # PostQuant
2
2
 
3
- **Find quantum-vulnerable cryptography in your TLS endpoints.**
3
+ **Find quantum-vulnerable cryptography in your TLS endpoints and source code.**
4
4
 
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
6
  [![npm version](https://img.shields.io/npm/v/postquant)](https://www.npmjs.com/package/postquant)
7
7
 
8
- PostQuant scans TLS connections and reports which algorithms are vulnerable to quantum attacks. It grades endpoints A+ through F and tells you what to migrate to.
9
-
10
- > **Early development.** The TLS scanner works. Code scanning and CBOM generation are planned.
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.
11
9
 
12
10
  ## Why
13
11
 
@@ -38,8 +36,18 @@ Output:
38
36
 
39
37
  Most sites today score C+ or C. That's expected — almost nobody has deployed post-quantum cryptography yet.
40
38
 
39
+ ### Scan Source Code
40
+
41
+ ```bash
42
+ npx postquant analyze ./src
43
+ ```
44
+
45
+ Scans Python, JavaScript/TypeScript, Go, and Java files for quantum-vulnerable cryptographic patterns (RSA, ECDSA, ECDH, DH, DSA, MD5, SHA-1, DES/3DES, AES-128) and reports findings with migration recommendations.
46
+
41
47
  ## Usage
42
48
 
49
+ ### TLS Scanning
50
+
43
51
  ```bash
44
52
  # Scan a single host
45
53
  postquant scan example.com
@@ -60,6 +68,37 @@ postquant scan --file hosts.txt
60
68
  postquant scan example.com --timeout 5000
61
69
  ```
62
70
 
71
+ ### Code Scanning
72
+
73
+ ```bash
74
+ # Scan a directory
75
+ postquant analyze ./src
76
+
77
+ # Scan a single file
78
+ postquant analyze ./src/auth.py
79
+
80
+ # Filter by language
81
+ postquant analyze ./src --language python
82
+
83
+ # JSON output
84
+ postquant analyze ./src --format json
85
+
86
+ # SARIF output (for GitHub Code Scanning)
87
+ postquant analyze ./src --format sarif > results.sarif
88
+
89
+ # CycloneDX CBOM output
90
+ postquant analyze ./src --format cbom > cbom.json
91
+
92
+ # Exclude directories
93
+ postquant analyze . --ignore "vendor/**" --ignore "test/**"
94
+
95
+ # Set fail threshold for CI
96
+ postquant analyze ./src --fail-grade D
97
+
98
+ # Show all findings including safe ones
99
+ postquant analyze ./src --verbose
100
+ ```
101
+
63
102
  ## Grading
64
103
 
65
104
  | Grade | Meaning |
@@ -75,13 +114,24 @@ postquant scan example.com --timeout 5000
75
114
 
76
115
  +/- modifiers reflect classical crypto hygiene within each grade band.
77
116
 
117
+ ### GitHub Actions
118
+
119
+ ```yaml
120
+ - run: npx postquant analyze . --format sarif > results.sarif
121
+ - uses: github/codeql-action/upload-sarif@v3
122
+ with:
123
+ sarif_file: results.sarif
124
+ category: postquant
125
+ ```
126
+
78
127
  ## Development
79
128
 
80
129
  ```bash
81
130
  npm install # Install dependencies
82
131
  npm run build # Compile TypeScript
83
132
  npm test # Run tests
84
- npm run dev -- scan example.com # Run from source
133
+ npm run dev -- scan example.com # TLS scan from source
134
+ npm run dev -- analyze ./src # Code scan from source
85
135
  ```
86
136
 
87
137
  ## Roadmap
@@ -89,9 +139,9 @@ npm run dev -- scan example.com # Run from source
89
139
  | Phase | Target | Status |
90
140
  |-------|--------|--------|
91
141
  | TLS scanner CLI | March 2026 | v0.1.0 |
92
- | Code scanner (Python, JS, Go, Java) | April 2026 | Planned |
93
- | CBOM generation + risk scoring | May 2026 | Planned |
94
- | Web dashboard | June 2026 | Planned |
142
+ | Code scanner (Python, JS, Go, Java) | March 2026 | v0.2.0 |
143
+ | Migration playbook engine | April 2026 | Planned |
144
+ | Web dashboard | May 2026 | Planned |
95
145
 
96
146
  See [docs/ROADMAP.md](docs/ROADMAP.md) for details.
97
147
 
@@ -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":"AAWA,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,CAgGxB"}
@@ -0,0 +1,119 @@
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 { gradeCodeScan, shouldFailForCodeGrade } from '../scanner/code/grader.js';
8
+ import { formatCodeTerminal } from '../output/terminal-code.js';
9
+ import { formatCodeJson } from '../output/json-code.js';
10
+ import { formatSarif } from '../output/sarif.js';
11
+ import { formatCbom } from '../output/cbom.js';
12
+ /** Extension → Language mapping (duplicated from discovery for single-file mode). */
13
+ const EXTENSION_MAP = {
14
+ '.py': 'python',
15
+ '.pyw': 'python',
16
+ '.pyi': 'python',
17
+ '.js': 'javascript',
18
+ '.mjs': 'javascript',
19
+ '.cjs': 'javascript',
20
+ '.jsx': 'javascript',
21
+ '.ts': 'javascript',
22
+ '.mts': 'javascript',
23
+ '.cts': 'javascript',
24
+ '.tsx': 'javascript',
25
+ '.go': 'go',
26
+ '.java': 'java',
27
+ };
28
+ export async function analyzeCommand(targetPath, options) {
29
+ const absPath = resolve(targetPath);
30
+ let fileStat;
31
+ try {
32
+ fileStat = await stat(absPath);
33
+ }
34
+ catch {
35
+ return {
36
+ exitCode: 1,
37
+ output: chalk.red(`Error: path does not exist: ${targetPath}`),
38
+ grade: null,
39
+ };
40
+ }
41
+ const startTime = Date.now();
42
+ const allFindings = [];
43
+ let filesScanned = 0;
44
+ if (fileStat.isFile()) {
45
+ // Single file mode
46
+ const ext = extname(absPath);
47
+ const lang = EXTENSION_MAP[ext];
48
+ if (lang && (!options.language || options.language === lang)) {
49
+ const findings = await matchFile(absPath, lang);
50
+ // Normalize file paths to be relative-ish (just the basename for single files)
51
+ for (const f of findings) {
52
+ f.file = basename(absPath);
53
+ }
54
+ allFindings.push(...findings);
55
+ filesScanned = 1;
56
+ }
57
+ else {
58
+ filesScanned = 1;
59
+ }
60
+ }
61
+ else {
62
+ // Directory mode
63
+ const discovered = await discoverFiles(absPath, {
64
+ ignore: options.ignore,
65
+ ignoreFile: options.ignoreFile,
66
+ maxFiles: options.maxFiles,
67
+ language: options.language,
68
+ });
69
+ filesScanned = discovered.length;
70
+ for (const file of discovered) {
71
+ const fullPath = join(absPath, file.path);
72
+ try {
73
+ const findings = await matchFile(fullPath, file.language);
74
+ // Normalize to relative path from scan root
75
+ for (const f of findings) {
76
+ f.file = file.path;
77
+ }
78
+ allFindings.push(...findings);
79
+ }
80
+ catch {
81
+ // Skip files that can't be read
82
+ }
83
+ }
84
+ }
85
+ const durationMs = Date.now() - startTime;
86
+ const scanRoot = fileStat.isFile() ? absPath : absPath;
87
+ // Pipeline: classify → grade → format
88
+ const classified = classifyCodeFindings(allFindings, scanRoot, filesScanned, durationMs);
89
+ const graded = gradeCodeScan(classified);
90
+ // Format output
91
+ let output;
92
+ switch (options.format) {
93
+ case 'json':
94
+ output = formatCodeJson(graded);
95
+ break;
96
+ case 'sarif':
97
+ output = formatSarif(graded);
98
+ break;
99
+ case 'cbom':
100
+ output = formatCbom(graded);
101
+ break;
102
+ case 'terminal':
103
+ default:
104
+ output = formatCodeTerminal(graded, {
105
+ verbose: options.verbose,
106
+ noMigration: options.noMigration,
107
+ });
108
+ break;
109
+ }
110
+ // Determine exit code
111
+ const shouldFail = shouldFailForCodeGrade(graded.baseGrade, options.failGrade);
112
+ const exitCode = shouldFail ? 1 : 0;
113
+ return {
114
+ exitCode,
115
+ output,
116
+ grade: graded.grade,
117
+ };
118
+ }
119
+ //# 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.1.1');
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,45 @@ 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
+ .action(async (targetPath, opts) => {
55
+ const format = opts.format;
56
+ if (!VALID_ANALYZE_FORMATS.includes(format)) {
57
+ console.error(`Invalid format: ${format}. Use one of: ${VALID_ANALYZE_FORMATS.join(', ')}`);
58
+ process.exit(1);
59
+ }
60
+ if (opts.language && !VALID_LANGUAGES.includes(opts.language)) {
61
+ console.error(`Invalid language: ${opts.language}. Use one of: ${VALID_LANGUAGES.join(', ')}`);
62
+ process.exit(1);
63
+ }
64
+ const failGrade = opts.failGrade;
65
+ if (!VALID_GRADES.includes(failGrade)) {
66
+ console.error(`Invalid fail-grade: ${failGrade}. Use one of: ${VALID_GRADES.join(', ')}`);
67
+ process.exit(1);
68
+ }
69
+ const { exitCode, output } = await analyzeCommand(targetPath, {
70
+ format,
71
+ language: opts.language,
72
+ failGrade,
73
+ ignore: opts.ignore ?? [],
74
+ ignoreFile: opts.ignoreFile,
75
+ maxFiles: parseInt(opts.maxFiles, 10),
76
+ verbose: opts.verbose,
77
+ noMigration: !opts.migration,
78
+ });
79
+ console.log(output);
80
+ process.exit(exitCode);
81
+ });
39
82
  program.parse();
40
83
  //# 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;AAGjD,MAAM,YAAY,GAAgB,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAElE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,wDAAwD,CAAC;KACrE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,sDAAsD,CAAC;KACnE,QAAQ,CAAC,YAAY,EAAE,yCAAyC,CAAC;KACjE,MAAM,CAAC,uBAAuB,EAAE,gCAAgC,EAAE,UAAU,CAAC;KAC7E,MAAM,CAAC,eAAe,EAAE,qCAAqC,CAAC;KAC9D,MAAM,CAAC,gBAAgB,EAAE,oCAAoC,EAAE,OAAO,CAAC;KACvE,MAAM,CAAC,WAAW,EAAE,gCAAgC,EAAE,KAAK,CAAC;KAC5D,MAAM,CACL,sBAAsB,EACtB,sCAAsC,EACtC,GAAG,CACJ;KACA,MAAM,CAAC,KAAK,EAAE,KAAe,EAAE,IAAI,EAAE,EAAE;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAsB,CAAC;IAC3C,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,mBAAmB,MAAM,6BAA6B,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,SAAsB,CAAC;IAC9C,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,OAAO,CAAC,KAAK,CACX,uBAAuB,SAAS,iBAAiB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3E,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE;QACxC,MAAM;QACN,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QACnC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,SAAS;QACT,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CodeGradedResult } from '../types/index.js';
2
+ export declare function formatCbom(result: CodeGradedResult): string;
3
+ //# sourceMappingURL=cbom.d.ts.map
@@ -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,3 @@
1
+ import type { CodeGradedResult } from '../types/index.js';
2
+ export declare function formatCodeJson(result: CodeGradedResult): string;
3
+ //# sourceMappingURL=json-code.d.ts.map
@@ -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,EAAE,MAAM,mBAAmB,CAAC;AAc1D,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAe/D"}
@@ -0,0 +1,29 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+ function getVersion() {
5
+ try {
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf-8'));
8
+ return pkg.version;
9
+ }
10
+ catch {
11
+ return '0.1.1';
12
+ }
13
+ }
14
+ export function formatCodeJson(result) {
15
+ const output = {
16
+ version: getVersion(),
17
+ timestamp: new Date().toISOString(),
18
+ scanRoot: result.scanRoot,
19
+ grade: result.grade,
20
+ baseGrade: result.baseGrade,
21
+ modifier: result.modifier,
22
+ findings: result.findings,
23
+ summary: result.summary,
24
+ migrationNotes: result.migrationNotes,
25
+ fileBreakdown: result.fileBreakdown,
26
+ };
27
+ return JSON.stringify(output, null, 2);
28
+ }
29
+ //# sourceMappingURL=json-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-code.js","sourceRoot":"","sources":["../../src/output/json-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CACnE,CAAC;QACF,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAwB;IACrD,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,UAAU,EAAE;QACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,cAAc,EAAE,MAAM,CAAC,cAAc;QACrC,aAAa,EAAE,MAAM,CAAC,aAAa;KACpC,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CodeGradedResult } from '../types/index.js';
2
+ export declare function formatSarif(result: CodeGradedResult): string;
3
+ //# sourceMappingURL=sarif.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../../src/output/sarif.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAA0C,MAAM,mBAAmB,CAAC;AA+MlG,wBAAgB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CA0D5D"}