cra-audit 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 cra-audit contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,248 @@
1
+ # cra-audit
2
+
3
+ > Compliance audit for the **Cyber Resilience Act** (Regulation EU 2024/2847) and the **BSI TR-03183** technical guideline, for npm projects.
4
+
5
+ `cra-audit` audits the installed dependencies of an npm project and checks the key requirements that the CRA imposes on "products with digital elements". It runs directly with `npx`, **without installation**, and has **no production dependencies** to minimize its own supply-chain surface.
6
+
7
+ ```bash
8
+ # Run ALL the law's checks (Vulnerabilities + Licenses + SBOM)
9
+ npx cra-audit
10
+
11
+ # Interactive visual report (HTML) with maintenance data
12
+ npx cra-audit --visualize
13
+
14
+ # Just the SBOM part
15
+ npx cra-audit --sbom
16
+ npx cra-audit sbom check
17
+ ```
18
+
19
+ ---
20
+
21
+ ## What it checks and why (mapping to the regulation)
22
+
23
+ Under the hood, the package runs the checks derived from the CRA legal obligations and the TR-03183 technical guideline:
24
+
25
+ ### 1. Automatic SBOM validation
26
+
27
+ Generates and validates a **Software Bill of Materials (SBOM)** in a machine-readable format —**CycloneDX 1.5** or **SPDX 2.3**— from the `package-lock.json` / `npm-shrinkwrap.json`. It verifies the **minimum elements** required by TR-03183 §6 for every component: name, version, unique identifier (`purl`), cryptographic integrity hash and license.
28
+
29
+ > CRA Annex I · TR-03183 Part 2 — *"Transparency through SBOM"*.
30
+
31
+ ### 2. "Zero known vulnerabilities" audit
32
+
33
+ Scans **direct and transitive** dependencies (from the lockfile) with `npm audit` and blocks the audit if there are exploitable vulnerabilities above the configured threshold.
34
+
35
+ > CRA Art. 13 — *products must be placed on the market without known exploitable vulnerabilities*.
36
+
37
+ ### 3. Third-party component check
38
+
39
+ Identifies every third-party open-source library present in the dependency tree and cross-references it against known security advisories, flagging vulnerable components and whether a fix is available.
40
+
41
+ > CRA — special attention to third-party developed components.
42
+
43
+ ### 4. License and hash management
44
+
45
+ Verifies that **all** dependencies have their license documented and compliant with the policy (allowlist / denylist), and that they carry unique identifiers (`purl`) and integrity hashes (SHA-512/384/256) as recommended by TR-03183.
46
+
47
+ > TR-03183 §6 — license governance and hash integrity.
48
+
49
+ ### 5. Visualization (`--visualize`)
50
+
51
+ Generates an **interactive, self-contained HTML report** (no external CDNs, works offline) that gathers, per package: SBOM, installed vs. latest published version, license, vulnerabilities and **maintenance signals** to assess how well each project is maintained:
52
+
53
+ - Last npm publish and number of maintainers.
54
+ - Associated repository.
55
+ - (Optional, with `--github`) **last commit** date, number of **contributors** and **stars**.
56
+ - **Deprecated** / **archived** indicators.
57
+ - A **maintenance score** (0-100) with a label *well-maintained / moderate / at-risk*.
58
+
59
+ The report includes summary cards, search, filters (vulnerable, outdated, license issues, at risk) and column sorting.
60
+
61
+ ---
62
+
63
+ ## Usage
64
+
65
+ ```bash
66
+ # Full audit (default)
67
+ npx cra-audit
68
+ npx cra-audit audit
69
+
70
+ # Visual report
71
+ npx cra-audit --visualize # shortcut
72
+ npx cra-audit visualize # long form
73
+ npx cra-audit visualize --github # adds last commit, contributors and stars
74
+ npx cra-audit visualize --offline # no network (skips maintenance metadata)
75
+ npx cra-audit visualize --no-open -o report.html
76
+
77
+ # SBOM
78
+ npx cra-audit --sbom # = sbom check
79
+ npx cra-audit sbom check
80
+ npx cra-audit sbom generate -o sbom.cdx.json # CycloneDX (default)
81
+ npx cra-audit sbom generate --format spdx -o sbom.spdx.json
82
+ npx cra-audit sbom check -i sbom.cdx.json # validate an existing SBOM
83
+
84
+ # Individual checks
85
+ npx cra-audit vulnerabilities # alias: vuln
86
+ npx cra-audit licenses
87
+ ```
88
+
89
+ ### Global installation (optional)
90
+
91
+ ```bash
92
+ npm install -g cra-audit
93
+ cra-audit --help
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Commands
99
+
100
+ | Command | Description |
101
+ | --- | --- |
102
+ | `cra-audit` / `cra-audit audit` | Full CRA compliance audit (vulnerabilities + SBOM + licenses). **Default.** |
103
+ | `cra-audit visualize` (aliases `view`, `report`) | Interactive HTML report with SBOM, licenses, versions and maintenance. |
104
+ | `cra-audit sbom generate` | Generate an SBOM (CycloneDX/SPDX). |
105
+ | `cra-audit sbom check` | Validate the SBOM against the TR-03183 minimum elements. |
106
+ | `cra-audit vulnerabilities` (alias `vuln`) | Vulnerability analysis only. |
107
+ | `cra-audit licenses` | License analysis only. |
108
+ | `cra-audit help` | Show help. |
109
+
110
+ ## Options
111
+
112
+ | Option | Description |
113
+ | --- | --- |
114
+ | `--visualize`, `-V` | Shortcut to generate and open the interactive HTML report. |
115
+ | `--github` | Enrich the visual report with GitHub data (last commit, contributors, stars). |
116
+ | `--offline` | Do not query the network when visualizing (skips maintenance metadata). |
117
+ | `--no-open` | Do not open the HTML report in the browser automatically. |
118
+ | `--sbom` | Shortcut equivalent to `sbom check`. |
119
+ | `--format <fmt>` | SBOM format: `cyclonedx` (default) or `spdx`. |
120
+ | `--fail-on <sev>` | Minimum severity that fails the audit: `info`, `low`, `moderate`, `high`, `critical`. |
121
+ | `--production`, `--prod` | Audit production dependencies only. |
122
+ | `--no-sbom` | Do not require an SBOM in the full audit. |
123
+ | `--json` | Machine-readable JSON output. |
124
+ | `--output`, `-o <path>` | Write the result / SBOM / HTML to a file. |
125
+ | `--input`, `-i <path>` | Existing SBOM to validate (for `sbom check`). |
126
+ | `--config`, `-c <path>` | Path to the security policy. |
127
+ | `--cwd <path>` | Project directory to audit. |
128
+ | `--no-color` | Disable colors. |
129
+ | `--version`, `-v` · `--help`, `-h` | Version / help. |
130
+
131
+ ### GitHub data and rate limits
132
+
133
+ With `--github`, the tool queries the public GitHub API to fetch the last commit, contributors and stars. Unauthenticated, GitHub limits to **60 requests/hour**. For large projects, set a read-only token:
134
+
135
+ ```bash
136
+ # PowerShell
137
+ $env:GITHUB_TOKEN = "ghp_xxx"; npx cra-audit visualize --github
138
+ # bash
139
+ GITHUB_TOKEN=ghp_xxx npx cra-audit visualize --github
140
+ ```
141
+
142
+ The token is only used to add the `Authorization` header on calls to `api.github.com`; it is not stored or sent anywhere else.
143
+
144
+ ---
145
+
146
+ ## The visual report in detail
147
+
148
+ `cra-audit visualize` writes `cra-audit-report.html` (or the `-o` path) and opens it in the browser. The report is a **single HTML file** with all data embedded and the filtering/sorting logic in its own vanilla JavaScript (no third-party scripts), so it is safe to share and works offline.
149
+
150
+ | Column | Meaning |
151
+ | --- | --- |
152
+ | Package | Component name (flags `deprecated` / `archived`). |
153
+ | Version | Installed version + `up to date` / `→ latest` indicator. |
154
+ | Latest | Latest version published on npm. |
155
+ | License | Detected license (red badge if missing or denied). |
156
+ | Vulnerability | Highest known severity (`clean` if none). |
157
+ | Last activity | Last commit date (with `--github`) or last publish date. |
158
+ | Maint. | Number of npm maintainers. |
159
+ | Contrib. | Number of GitHub contributors (with `--github`). |
160
+ | Maintenance | Score 0-100 based on recency, maintainers, contributors and status. |
161
+
162
+ Summary cards: total components, vulnerable, license issues, outdated and at risk.
163
+
164
+ ---
165
+
166
+ ## Security policy
167
+
168
+ Create a `.cra-audit.json` file at the project root to customize the rules (there is an example in `.cra-audit.example.json`):
169
+
170
+ ```json
171
+ {
172
+ "failOn": "high",
173
+ "requireSbom": true,
174
+ "sbomFormat": "cyclonedx",
175
+ "productionOnly": false,
176
+ "vulnerabilities": {
177
+ "allowlist": []
178
+ },
179
+ "licenses": {
180
+ "allow": [],
181
+ "deny": ["GPL-3.0", "AGPL-3.0"],
182
+ "failOnMissing": true
183
+ }
184
+ }
185
+ ```
186
+
187
+ - `failOn`: minimum severity that blocks the audit.
188
+ - `requireSbom`: require the SBOM to meet the TR-03183 minimum elements.
189
+ - `sbomFormat`: `cyclonedx` or `spdx`.
190
+ - `productionOnly`: audit production dependencies only.
191
+ - `vulnerabilities.allowlist`: advisory/CVE identifiers accepted with documented justification.
192
+ - `licenses.allow` / `licenses.deny`: allowed / denied lists (SPDX id).
193
+ - `licenses.failOnMissing`: treat undocumented licenses as a failure.
194
+
195
+ Command-line options take precedence over the policy file.
196
+
197
+ ---
198
+
199
+ ## Exit codes
200
+
201
+ | Code | Meaning |
202
+ | --- | --- |
203
+ | `0` | Audit passed (or report generated successfully). |
204
+ | `1` | Audit failed or execution error. |
205
+
206
+ Suitable for CI/CD: a non-`0` code blocks the pipeline.
207
+
208
+ ```yaml
209
+ # Example in GitHub Actions
210
+ - name: CRA compliance audit
211
+ run: npx cra-audit --fail-on high --production --json -o cra-report.json
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Programmatic API
217
+
218
+ ```js
219
+ const {
220
+ runAudit, loadPolicy, generateSbom, validateSbom,
221
+ scanVulnerabilities, checkLicenses, parseLockfile,
222
+ enrichComponents, buildHtml,
223
+ } = require('cra-audit');
224
+
225
+ const { policy, source } = loadPolicy(process.cwd());
226
+ const report = runAudit(process.cwd(), policy, source);
227
+ console.log(report.gate.passed ? 'OK' : 'FAILED');
228
+
229
+ // Maintenance data + custom HTML report
230
+ const { components } = parseLockfile(process.cwd());
231
+ const signals = await enrichComponents(components, { network: true, github: true });
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Requirements
237
+
238
+ - Node.js >= 18 (uses native `fetch` and `node --test`).
239
+ - `npm` available on the `PATH` (for `npm audit`).
240
+ - A `package-lock.json` or `npm-shrinkwrap.json` present (run `npm install` if missing).
241
+
242
+ ## Legal notice
243
+
244
+ `cra-audit` is a technical support tool. It helps verify controls associated with the CRA and TR-03183, but it **does not constitute legal advice** nor does it guarantee regulatory compliance on its own.
245
+
246
+ ## License
247
+
248
+ MIT
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { main } = require('../src/cli');
5
+
6
+ Promise.resolve()
7
+ .then(() => main(process.argv.slice(2)))
8
+ .then((exitCode) => {
9
+ process.exitCode = typeof exitCode === 'number' ? exitCode : 0;
10
+ })
11
+ .catch((err) => {
12
+ process.stderr.write(`\x1b[31m✖ Error inesperado: ${err && err.message ? err.message : err}\x1b[0m\n`);
13
+ if (process.env.CRA_AUDIT_DEBUG) {
14
+ process.stderr.write(String(err && err.stack) + '\n');
15
+ }
16
+ process.exitCode = 1;
17
+ });
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "cra-audit",
3
+ "version": "0.1.0",
4
+ "description": "Audits npm projects for compliance with the European Cyber Resilience Act (CRA, EU Regulation 2024/2847) and the BSI TR-03183 technical guideline: SBOM (CycloneDX/SPDX), known vulnerabilities, third-party components, and licenses.",
5
+ "author": "Miguel Gonzalez Herrera",
6
+ "keywords": [
7
+ "cra",
8
+ "cyber-resilience-act",
9
+ "tr-03183",
10
+ "bsi",
11
+ "sbom",
12
+ "cyclonedx",
13
+ "spdx",
14
+ "security",
15
+ "audit",
16
+ "compliance",
17
+ "vulnerabilities",
18
+ "licenses",
19
+ "supply-chain"
20
+ ],
21
+ "license": "MIT",
22
+ "type": "commonjs",
23
+ "bin": {
24
+ "cra-audit": "bin/cra-audit.js"
25
+ },
26
+ "main": "src/index.js",
27
+ "exports": {
28
+ ".": "./src/index.js"
29
+ },
30
+ "files": [
31
+ "bin",
32
+ "src",
33
+ "README.md",
34
+ "LICENSE"
35
+ ],
36
+ "scripts": {
37
+ "start": "node bin/cra-audit.js",
38
+ "test": "node --test"
39
+ },
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "dependencies": {},
44
+ "preferGlobal": true
45
+ }
package/src/cli.js ADDED
@@ -0,0 +1,217 @@
1
+ 'use strict';
2
+
3
+ const { logger, color } = require('./utils/logger');
4
+ const { auditCommand } = require('./commands/audit');
5
+ const { sbomCommand } = require('./commands/sbom');
6
+ const { visualizeCommand } = require('./commands/visualize');
7
+
8
+ const VERSION = require('../package.json').version;
9
+
10
+ const FLAG_ALIASES = {
11
+ '-h': '--help',
12
+ '-v': '--version',
13
+ '-o': '--output',
14
+ '-i': '--input',
15
+ '-c': '--config',
16
+ '-V': '--visualize',
17
+ };
18
+
19
+ const BOOLEAN_FLAGS = new Set([
20
+ '--help', '--version', '--json', '--sbom', '--no-sbom',
21
+ '--production', '--prod', '--no-color',
22
+ '--visualize', '--offline', '--github', '--no-open',
23
+ ]);
24
+
25
+ /**
26
+ * Entry point invoked from bin/cra-audit.js.
27
+ * @param {string[]} argv Arguments after `node script`.
28
+ * @returns {Promise<number>} exit code.
29
+ */
30
+ async function main(argv) {
31
+ const { positionals, flags } = parseArgs(argv);
32
+
33
+ if (flags.noColor) logger.setColor(false);
34
+
35
+ if (flags.help) {
36
+ printHelp();
37
+ return 0;
38
+ }
39
+ if (flags.version) {
40
+ logger.log(VERSION);
41
+ return 0;
42
+ }
43
+
44
+ const command = positionals[0] || 'audit';
45
+
46
+ // `--visualize` is a shortcut for the visual HTML report.
47
+ if (flags.visualize && command === 'audit') {
48
+ return visualizeCommand(flags);
49
+ }
50
+ // `--sbom` is a shortcut for "sbom check" regardless of the (default) command.
51
+ if (flags.sbom && command === 'audit') {
52
+ return sbomCommand('check', flags);
53
+ }
54
+
55
+ switch (command) {
56
+ case 'audit':
57
+ return auditCommand(flags);
58
+
59
+ case 'visualize':
60
+ case 'view':
61
+ case 'report':
62
+ return visualizeCommand(flags);
63
+
64
+ case 'sbom':
65
+ // `cra-audit --sbom` is handled below; here we route the subcommand form.
66
+ return sbomCommand(positionals[1], flags);
67
+
68
+ case 'vulnerabilities':
69
+ case 'vuln':
70
+ case 'vulns':
71
+ return auditCommand(flags, 'vulnerabilities');
72
+
73
+ case 'licenses':
74
+ case 'license':
75
+ return auditCommand(flags, 'licenses');
76
+
77
+ case 'help':
78
+ printHelp();
79
+ return 0;
80
+
81
+ default:
82
+ logger.error(`Comando desconocido: "${command}".`);
83
+ logger.log(`Ejecuta ${color.cyan('cra-audit --help')} para ver los comandos disponibles.`);
84
+ return 1;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Minimal, dependency-free argument parser.
90
+ * Supports `--flag`, `--flag value`, `--flag=value`, short aliases and `--no-*`.
91
+ */
92
+ function parseArgs(argv) {
93
+ const positionals = [];
94
+ const flags = {};
95
+
96
+ for (let i = 0; i < argv.length; i++) {
97
+ let arg = argv[i];
98
+
99
+ if (!arg.startsWith('-')) {
100
+ positionals.push(arg);
101
+ continue;
102
+ }
103
+
104
+ let value;
105
+ const eq = arg.indexOf('=');
106
+ if (eq !== -1) {
107
+ value = arg.slice(eq + 1);
108
+ arg = arg.slice(0, eq);
109
+ }
110
+
111
+ const canonical = FLAG_ALIASES[arg] || arg;
112
+
113
+ if (BOOLEAN_FLAGS.has(canonical)) {
114
+ setFlag(flags, canonical, true);
115
+ continue;
116
+ }
117
+
118
+ // Value flag: take inline `=value` or the next argument.
119
+ if (value === undefined) {
120
+ const next = argv[i + 1];
121
+ if (next !== undefined && !next.startsWith('-')) {
122
+ value = next;
123
+ i++;
124
+ } else {
125
+ value = true;
126
+ }
127
+ }
128
+ setFlag(flags, canonical, value);
129
+ }
130
+
131
+ return { positionals, flags };
132
+ }
133
+
134
+ function setFlag(flags, name, value) {
135
+ switch (name) {
136
+ case '--help': flags.help = value; break;
137
+ case '--version': flags.version = value; break;
138
+ case '--json': flags.json = value; break;
139
+ case '--sbom': flags.sbom = value; break;
140
+ case '--no-sbom': flags.noSbom = value; break;
141
+ case '--no-color': flags.noColor = value; break;
142
+ case '--visualize': flags.visualize = value; break;
143
+ case '--offline': flags.offline = value; break;
144
+ case '--github': flags.github = value; break;
145
+ case '--no-open': flags.noOpen = value; break;
146
+ case '--production':
147
+ case '--prod': flags.production = value; break;
148
+ case '--output': flags.output = value; break;
149
+ case '--input': flags.input = value; break;
150
+ case '--config': flags.config = value; break;
151
+ case '--format': flags.format = String(value).toLowerCase(); break;
152
+ case '--fail-on': flags.failOn = String(value).toLowerCase(); break;
153
+ case '--cwd': flags.cwd = value; break;
154
+ default:
155
+ // Unknown flag stored under its raw name for forward compatibility.
156
+ flags[name.replace(/^--/, '')] = value;
157
+ }
158
+ }
159
+
160
+ function printHelp() {
161
+ const c = color;
162
+ logger.log(`
163
+ ${c.bold('cra-audit')} — Auditoría de cumplimiento del Cyber Resilience Act (UE 2024/2847)
164
+ y la directriz técnica BSI TR-03183 para proyectos npm.
165
+
166
+ ${c.bold('USO')}
167
+ npx cra-audit [comando] [opciones]
168
+
169
+ ${c.bold('COMANDOS')}
170
+ ${c.cyan('audit')} Ejecuta TODAS las comprobaciones (vulnerabilidades + SBOM + licencias). Por defecto.
171
+ ${c.cyan('visualize')} Genera un informe HTML interactivo (SBOM, licencias, versiones y mantenimiento).
172
+ ${c.cyan('sbom generate')} Genera un SBOM (CycloneDX o SPDX) y lo imprime o guarda.
173
+ ${c.cyan('sbom check')} Valida que el SBOM cumple los elementos mínimos de TR-03183.
174
+ ${c.cyan('vulnerabilities')} Analiza solo vulnerabilidades conocidas (alias: vuln).
175
+ ${c.cyan('licenses')} Analiza solo las licencias de las dependencias.
176
+ ${c.cyan('help')} Muestra esta ayuda.
177
+
178
+ ${c.bold('OPCIONES')}
179
+ ${c.cyan('--visualize, -V')} Atajo para generar y abrir el informe HTML interactivo.
180
+ ${c.cyan('--github')} Enriquece el informe visual con datos de GitHub (último commit, contribuidores, stars).
181
+ ${c.cyan('--offline')} No consulta la red al visualizar (omite metadatos de mantenimiento).
182
+ ${c.cyan('--no-open')} No abre el informe HTML en el navegador automáticamente.
183
+ ${c.cyan('--sbom')} Atajo equivalente a "sbom check".
184
+ ${c.cyan('--format <fmt>')} Formato del SBOM: cyclonedx (def.) | spdx.
185
+ ${c.cyan('--fail-on <sev>')} Severidad mínima que hace fallar la auditoría: info|low|moderate|high|critical.
186
+ ${c.cyan('--production, --prod')} Audita solo dependencias de producción (omite devDependencies).
187
+ ${c.cyan('--no-sbom')} No exige SBOM en la auditoría completa.
188
+ ${c.cyan('--json')} Salida en JSON legible por máquina.
189
+ ${c.cyan('--output, -o <ruta>')} Escribe el resultado/SBOM/HTML en un archivo.
190
+ ${c.cyan('--input, -i <ruta>')} SBOM existente a validar (para "sbom check").
191
+ ${c.cyan('--config, -c <ruta>')} Ruta a la política de seguridad (.cra-audit.json).
192
+ ${c.cyan('--cwd <ruta>')} Directorio del proyecto a auditar.
193
+ ${c.cyan('--no-color')} Desactiva los colores.
194
+ ${c.cyan('--version, -v')} Muestra la versión.
195
+ ${c.cyan('--help, -h')} Muestra esta ayuda.
196
+
197
+ ${c.bold('EJEMPLOS')}
198
+ ${c.gray('# Auditoría completa de cumplimiento CRA')}
199
+ npx cra-audit
200
+
201
+ ${c.gray('# Informe visual interactivo (HTML) con datos de mantenimiento')}
202
+ npx cra-audit --visualize
203
+ npx cra-audit visualize --github
204
+
205
+ ${c.gray('# Solo la parte del SBOM')}
206
+ npx cra-audit --sbom
207
+ npx cra-audit sbom check
208
+
209
+ ${c.gray('# Generar un SBOM CycloneDX en disco')}
210
+ npx cra-audit sbom generate -o sbom.cdx.json
211
+
212
+ ${c.gray('# Fallar solo ante vulnerabilidades críticas, en CI')}
213
+ npx cra-audit --fail-on critical --production --json -o cra-report.json
214
+ `);
215
+ }
216
+
217
+ module.exports = { main, parseArgs };
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ const { findProjectRoot } = require('../utils/fs');
4
+ const { logger } = require('../utils/logger');
5
+ const { loadPolicy } = require('../core/policy');
6
+ const { runAudit } = require('../core/auditor');
7
+ const { reportConsole } = require('../reporters/console');
8
+ const { reportJson } = require('../reporters/json');
9
+
10
+ /**
11
+ * `cra-audit [audit]` — runs the full compliance audit (vulnerabilities + SBOM
12
+ * + licenses) or a single section via `only`.
13
+ *
14
+ * @param {object} flags Parsed CLI flags.
15
+ * @param {'vulnerabilities'|'sbom'|'licenses'} [only]
16
+ * @returns {number} Process exit code.
17
+ */
18
+ function auditCommand(flags, only) {
19
+ const projectRoot = resolveRoot(flags);
20
+ if (!projectRoot) return 1;
21
+
22
+ let policyResult;
23
+ try {
24
+ policyResult = loadPolicy(projectRoot, flags.config);
25
+ } catch (err) {
26
+ logger.error(err.message);
27
+ return 1;
28
+ }
29
+
30
+ const policy = applyFlagOverrides(policyResult.policy, flags);
31
+ const report = runAudit(projectRoot, policy, policyResult.source, { only });
32
+
33
+ if (flags.json) {
34
+ reportJson(report, { outputPath: flags.output });
35
+ } else {
36
+ reportConsole(report);
37
+ }
38
+
39
+ return report.gate.passed ? 0 : 1;
40
+ }
41
+
42
+ function resolveRoot(flags) {
43
+ const start = flags.cwd || process.cwd();
44
+ const root = findProjectRoot(start);
45
+ if (!root) {
46
+ logger.error('No se encontró ningún package.json. Ejecuta el comando dentro de un proyecto npm.');
47
+ return null;
48
+ }
49
+ return root;
50
+ }
51
+
52
+ /** CLI flags take precedence over the file-based policy. */
53
+ function applyFlagOverrides(policy, flags) {
54
+ const merged = { ...policy };
55
+ if (flags.failOn) merged.failOn = flags.failOn;
56
+ if (flags.production) merged.productionOnly = true;
57
+ if (flags.format) merged.sbomFormat = flags.format;
58
+ if (flags.noSbom) merged.requireSbom = false;
59
+ return merged;
60
+ }
61
+
62
+ module.exports = { auditCommand };