cbom-tools 0.2.5 → 0.2.7-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -2
- package/cbom-diff.js +32 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,7 +77,22 @@ Exit codes:
|
|
|
77
77
|
- `0` — no changes
|
|
78
78
|
- `1` — informational changes (algorithm properties moved)
|
|
79
79
|
- `2` — warnings (algorithm removed, new classical reference), or file/parse error
|
|
80
|
-
- `3` —
|
|
80
|
+
- `3` — a quantum-vulnerable algorithm was newly introduced (requires both CBOMs)
|
|
81
|
+
|
|
82
|
+
Exit 3 follows the definition agreed in [#43](https://github.com/Lennonhaha/fibemate-tools/issues/43):
|
|
83
|
+
an algorithm whose `fibemate:quantumSecurity:level` is `vulnerable` appears in the
|
|
84
|
+
after CBOM but not in the before CBOM. Two consequences are deliberate:
|
|
85
|
+
|
|
86
|
+
- An algorithm that was already vulnerable and stays vulnerable is not a
|
|
87
|
+
regression, so it never turns the build red.
|
|
88
|
+
- A single-CBOM scan has no baseline to compare against, so it stays at exit 1.
|
|
89
|
+
Otherwise the first scan of a legacy codebase would light up every historical
|
|
90
|
+
finding at once.
|
|
91
|
+
|
|
92
|
+
The level is read from `component.properties` (`fibemate:quantumSecurity:level`),
|
|
93
|
+
which is where `cbom-scan` writes it; `cryptoProperties.quantumSecurity.level` is
|
|
94
|
+
accepted as a fallback for hand-written CBOMs. A missing or malformed level stays
|
|
95
|
+
unknown — it is never inferred from the algorithm name.
|
|
81
96
|
|
|
82
97
|
## Testing
|
|
83
98
|
|
|
@@ -85,7 +100,7 @@ Exit codes:
|
|
|
85
100
|
npm test
|
|
86
101
|
```
|
|
87
102
|
|
|
88
|
-
|
|
103
|
+
76 tests (Node built-in `node:test`, zero dependencies). Both binaries are
|
|
89
104
|
spawned as child processes and checked against edge inputs — empty directory,
|
|
90
105
|
dependencies-only, source-only, an 800-file tree (occurrence cap,
|
|
91
106
|
`node_modules` / `.git` / dotfile skipping), unreachable directories, missing
|
package/cbom-diff.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* 0 — 无变更
|
|
18
18
|
* 1 — 有信息性变更(算法属性升级等)
|
|
19
19
|
* 2 — 有警告性变更(算法删除、新经典算法引用等)
|
|
20
|
-
* 3 —
|
|
20
|
+
* 3 — 加密材料依赖引入了量子脆弱算法(仅在同时提供 before 与 after 时判定)
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
const { execSync } = require('child_process');
|
|
@@ -164,7 +164,7 @@ if (oldCBOM && newCBOM) {
|
|
|
164
164
|
ref,
|
|
165
165
|
name: c.name,
|
|
166
166
|
type: assetType,
|
|
167
|
-
risk: classifyRisk(crypto),
|
|
167
|
+
risk: classifyRisk(crypto, quantumLevel(c)),
|
|
168
168
|
});
|
|
169
169
|
}
|
|
170
170
|
});
|
|
@@ -196,8 +196,10 @@ if (oldCBOM && newCBOM) {
|
|
|
196
196
|
ref: c['bom-ref'],
|
|
197
197
|
name: c.name,
|
|
198
198
|
type: (c.cryptoProperties || {}).assetType || c.type,
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
// No baseline: every component is "present", but none is "newly
|
|
200
|
+
// introduced", so the exit-3 regression signal stays off here.
|
|
201
|
+
risk: 'info',
|
|
202
|
+
}));
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
// --- 依赖关系比较 ---
|
|
@@ -226,6 +228,8 @@ if (oldCBOM && newCBOM) {
|
|
|
226
228
|
}
|
|
227
229
|
|
|
228
230
|
// --- 严重性判定 ---
|
|
231
|
+
// Exit 3 fires only when an added component is quantum-vulnerable and a
|
|
232
|
+
// baseline exists to compare against (see the single-CBOM branch).
|
|
229
233
|
const hasCriticalAdd = diff.components.added.some(c => c.risk === 'critical');
|
|
230
234
|
const hasWarningAdd = diff.components.added.some(c => c.risk === 'warning');
|
|
231
235
|
const hasRemoval = diff.components.removed.length > 0;
|
|
@@ -249,7 +253,30 @@ if (hasCriticalAdd) {
|
|
|
249
253
|
// ════════════════════════════
|
|
250
254
|
// 算法风险分类
|
|
251
255
|
// ════════════════════════════
|
|
252
|
-
|
|
256
|
+
// Quantum level lives in `component.properties` as a name/value pair:
|
|
257
|
+
// cbom-scan emits `fibemate:quantumSecurity:level`. Hand-written CBOMs may
|
|
258
|
+
// instead put it under `cryptoProperties.quantumSecurity.level`, so accept
|
|
259
|
+
// both, properties first. Never guess a level from the algorithm name: an
|
|
260
|
+
// unknown level must stay unknown, otherwise exit 3 becomes a name-match.
|
|
261
|
+
function quantumLevel(component) {
|
|
262
|
+
const props = component && Array.isArray(component.properties) ? component.properties : [];
|
|
263
|
+
// Literal, not a module-level const: the diff runs at the top of this script,
|
|
264
|
+
// long before this line is evaluated, so a module-level binding would still be
|
|
265
|
+
// in its temporal dead zone when quantumLevel() is first called.
|
|
266
|
+
const fromProps = props.find((entry) => entry && entry.name === 'fibemate:quantumSecurity:level');
|
|
267
|
+
if (fromProps && typeof fromProps.value === 'string') return fromProps.value;
|
|
268
|
+
const cryptoProps = (component && component.cryptoProperties) || {};
|
|
269
|
+
const fromCrypto = cryptoProps.quantumSecurity && cryptoProps.quantumSecurity.level;
|
|
270
|
+
return typeof fromCrypto === 'string' ? fromCrypto : null;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Risk of a component that is *added* by this diff. Definition 2 from #43:
|
|
274
|
+
// exit 3 means "a quantum-vulnerable algorithm was newly introduced", and the
|
|
275
|
+
// caller only classifies added components, so "present here and absent before"
|
|
276
|
+
// is already established by the time we get here. A vulnerable algorithm that
|
|
277
|
+
// merely stays present is not a regression and must not turn the build red.
|
|
278
|
+
function classifyRisk(cryptoProps, quantum) {
|
|
279
|
+
if (quantum === 'vulnerable') return 'critical';
|
|
253
280
|
const type = ((cryptoProps && cryptoProps.assetType) || '').toLowerCase();
|
|
254
281
|
// PQC algorithms: safe additions
|
|
255
282
|
if (/kem|sign|signature|post.quantum|pqc|mlkem|mldsa|slh/i.test(type)) return 'info';
|
|
@@ -259,8 +286,6 @@ function classifyRisk(cryptoProps) {
|
|
|
259
286
|
if (/ecc|ecdh|p-256|sm2|curve/i.test(type)) return 'warning';
|
|
260
287
|
// Classic symmetric: info (still safe with large keys)
|
|
261
288
|
if (/sym|sm4|aes|gcm/i.test(type)) return 'info';
|
|
262
|
-
// TODO(v0.2.0): add 'critical' exit code for quantum-vulnerable algorithms
|
|
263
|
-
// using cryptoProps.quantumSecurity?.level
|
|
264
289
|
// Unknown: treat as warning
|
|
265
290
|
return 'warning';
|
|
266
291
|
}
|