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
package/README.md CHANGED
@@ -1,13 +1,29 @@
1
1
  # PostQuant
2
2
 
3
- **Find quantum-vulnerable cryptography in your TLS endpoints.**
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: 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.
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
- > **Early development.** The TLS scanner works. Code scanning and CBOM generation are planned.
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 # Run from source
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.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 |
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.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,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;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":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,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,+DAA+D;AAE/D,SAAS,mBAAmB,CAAC,QAAwB;IACnD,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,uBAAuB;YAC1B,OAAO,KAAK,CAAC;QACf,KAAK,mBAAmB;YACtB,OAAO,WAAW,CAAC;QACrB,KAAK,cAAc;YACjB,OAAO,KAAK,CAAC;QACf,KAAK,gBAAgB,CAAC;QACtB,KAAK,gBAAgB,CAAC;QACtB,KAAK,eAAe;YAClB,OAAO,IAAI,CAAC;QACd,KAAK,WAAW,CAAC;QACjB,KAAK,WAAW;YACd,OAAO,MAAM,CAAC;QAChB,KAAK,eAAe;YAClB,OAAO,KAAK,CAAC,CAAC,2CAA2C;IAC7D,CAAC;AACH,CAAC;AAED,4DAA4D;AAE5D,SAAS,wBAAwB,CAAC,OAAoB;IACpD,0FAA0F;IAC1F,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC;IAE1C,sDAAsD;IACtD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IAClD,IACE,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC7B,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC7B,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC7B,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC1B,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC3B,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAC9B,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,uDAAuD;IACvD,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,CAAC,CAAC;IAE5C,iBAAiB;IACjB,IAAI,OAAO,CAAC,QAAQ,KAAK,eAAe,EAAE,CAAC;QACzC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACrE,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACrE,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACtE,OAAO,CAAC,CAAC,CAAC,cAAc;IAC1B,CAAC;IAED,+BAA+B;IAC/B,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,CAAC,CAAC;IAEtC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,qBAAqB;AAErB,MAAM,UAAU,UAAU,CAAC,MAAwB;IACjD,mCAAmC;IACnC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAyB,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACb,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,mBAAmB;IACnB,MAAM,UAAU,GAA8B,EAAE,CAAC;IACjD,MAAM,aAAa,GAAa,EAAE,CAAC;IAEnC,KAAK,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,WAAW,EAAE,CAAC;QAChD,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;QACzB,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAExB,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,QAAQ,EAAE,CAAC,CAAC,IAAI;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,iBAAiB,EAAE,CAAC,CAAC,WAAW;SACjC,CAAC,CAAC,CAAC;QAEJ,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,qBAAqB;YAC3B,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,GAAG;YACd,QAAQ,EAAE,EAAE,WAAW,EAAE;YACzB,gBAAgB,EAAE;gBAChB,SAAS,EAAE,WAAW;gBACtB,mBAAmB,EAAE;oBACnB,SAAS,EAAE,mBAAmB,CAAC,cAAc,CAAC,QAAQ,CAAC;oBACvD,sBAAsB,EAAE,mBAAmB,CAAC,cAAc,CAAC;oBAC3D,eAAe,EAAE,oBAAoB,CAAC,cAAc,CAAC;oBACrD,sBAAsB,EAAE,sBAAsB,CAAC,cAAc,CAAC;oBAC9D,wBAAwB,EAAE,wBAAwB,CAAC,cAAc,CAAC;iBACnE;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG;QACX,SAAS,EAAE,WAAW;QACtB,WAAW,EAAE,KAAK;QAClB,OAAO,EAAE,CAAC;QACV,YAAY,EAAE,YAAY,UAAU,EAAE,EAAE;QACxC,QAAQ,EAAE;YACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,KAAK,EAAE;gBACL,UAAU,EAAE;oBACV;wBACE,IAAI,EAAE,aAAa;wBACnB,IAAI,EAAE,WAAW;wBACjB,OAAO,EAAE,UAAU,EAAE;wBACrB,WAAW,EAAE,2BAA2B;wBACxC,kBAAkB,EAAE;4BAClB;gCACE,IAAI,EAAE,SAAS;gCACf,GAAG,EAAE,uBAAuB;6BAC7B;yBACF;qBACF;iBACF;aACF;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC;gBACzC,SAAS,EAAE,iBAAiB;aAC7B;SACF;QACD,UAAU;QACV,YAAY,EAAE;YACZ;gBACE,GAAG,EAAE,iBAAiB;gBACtB,SAAS,EAAE,aAAa;aACzB;SACF;KACF,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,kBAAkB;AAElB,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClD,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,iBAAiB,CAAC;AACtD,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAoB;IAC/C,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,sEAAsE;IACtE,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,oBAAoB,CAAC,OAAoB;IAChD,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxE,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACnD,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnF,IAAI,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChG,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvF,4BAA4B;IAC5B,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,KAAK,uBAAuB;YAC1B,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAC1C,KAAK,mBAAmB;YACtB,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5B,KAAK,cAAc;YACjB,OAAO,CAAC,aAAa,CAAC,CAAC;QACzB,KAAK,WAAW,CAAC;QACjB,KAAK,WAAW;YACd,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,KAAK,gBAAgB,CAAC;QACtB,KAAK,gBAAgB,CAAC;QACtB,KAAK,eAAe;YAClB,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAChC,KAAK,eAAe;YAClB,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB;YACE,OAAO,CAAC,SAAS,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAoB;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IAClD,gBAAgB;IAChB,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,GAAG,CAAC;QAC3C,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,GAAG,CAAC;QAC3C,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,GAAG,CAAC;QAC3C,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC;IACD,aAAa;IACb,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,GAAG,CAAC;IAC7E,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,GAAG,CAAC;IAC7E,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,GAAG,CAAC;IAC9I,YAAY;IACZ,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,GAAG,CAAC;IAChF,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,GAAG,CAAC;IAC9C,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,GAAG,CAAC;IAC9C,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,GAAG,CAAC;IAC3C,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACzC,SAAS;IACT,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,GAAG,CAAC;IAChF,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,GAAG,CAAC;IAChF,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,GAAG,CAAC;IAChF,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,SAAS,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IACnE,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACzC,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -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,EAAmB,MAAM,mBAAmB,CAAC;AAe3E,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CA4B/D"}