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 +21 -0
- package/README.md +248 -0
- package/bin/cra-audit.js +17 -0
- package/package.json +45 -0
- package/src/cli.js +217 -0
- package/src/commands/audit.js +62 -0
- package/src/commands/sbom.js +100 -0
- package/src/commands/visualize.js +188 -0
- package/src/core/auditor.js +128 -0
- package/src/core/enrich.js +220 -0
- package/src/core/license-checker.js +102 -0
- package/src/core/lockfile-parser.js +198 -0
- package/src/core/policy.js +76 -0
- package/src/core/sbom-generator.js +146 -0
- package/src/core/sbom-validator.js +124 -0
- package/src/core/vuln-scanner.js +148 -0
- package/src/index.js +33 -0
- package/src/reporters/console.js +137 -0
- package/src/reporters/html.js +267 -0
- package/src/reporters/json.js +20 -0
- package/src/utils/exec.js +57 -0
- package/src/utils/fs.js +44 -0
- package/src/utils/http.js +63 -0
- package/src/utils/logger.js +85 -0
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
|
package/bin/cra-audit.js
ADDED
|
@@ -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 };
|