@mitre/hdf-diff 3.0.1 → 3.1.0-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/LICENSE.md +55 -0
- package/README.md +49 -17
- package/dist/index.d.ts +622 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2037 -18
- package/dist/index.js.map +1 -1
- package/package.json +19 -19
- package/dist/diff.d.ts +0 -49
- package/dist/diff.d.ts.map +0 -1
- package/dist/diff.js +0 -791
- package/dist/diff.js.map +0 -1
- package/dist/exit-codes.d.ts +0 -42
- package/dist/exit-codes.d.ts.map +0 -1
- package/dist/exit-codes.js +0 -74
- package/dist/exit-codes.js.map +0 -1
- package/dist/matching/cci-match.d.ts +0 -14
- package/dist/matching/cci-match.d.ts.map +0 -1
- package/dist/matching/cci-match.js +0 -102
- package/dist/matching/cci-match.js.map +0 -1
- package/dist/matching/exact-id.d.ts +0 -9
- package/dist/matching/exact-id.d.ts.map +0 -1
- package/dist/matching/exact-id.js +0 -88
- package/dist/matching/exact-id.js.map +0 -1
- package/dist/matching/fuzzy-match.d.ts +0 -26
- package/dist/matching/fuzzy-match.d.ts.map +0 -1
- package/dist/matching/fuzzy-match.js +0 -145
- package/dist/matching/fuzzy-match.js.map +0 -1
- package/dist/matching/index.d.ts +0 -36
- package/dist/matching/index.d.ts.map +0 -1
- package/dist/matching/index.js +0 -71
- package/dist/matching/index.js.map +0 -1
- package/dist/matching/mapped-id.d.ts +0 -13
- package/dist/matching/mapped-id.d.ts.map +0 -1
- package/dist/matching/mapped-id.js +0 -101
- package/dist/matching/mapped-id.js.map +0 -1
- package/dist/matching/types.d.ts +0 -34
- package/dist/matching/types.d.ts.map +0 -1
- package/dist/matching/types.js +0 -2
- package/dist/matching/types.js.map +0 -1
- package/dist/normalize.d.ts +0 -20
- package/dist/normalize.d.ts.map +0 -1
- package/dist/normalize.js +0 -120
- package/dist/normalize.js.map +0 -1
- package/dist/renderers/csv.d.ts +0 -15
- package/dist/renderers/csv.d.ts.map +0 -1
- package/dist/renderers/csv.js +0 -77
- package/dist/renderers/csv.js.map +0 -1
- package/dist/renderers/filter.d.ts +0 -11
- package/dist/renderers/filter.d.ts.map +0 -1
- package/dist/renderers/filter.js +0 -29
- package/dist/renderers/filter.js.map +0 -1
- package/dist/renderers/index.d.ts +0 -17
- package/dist/renderers/index.d.ts.map +0 -1
- package/dist/renderers/index.js +0 -29
- package/dist/renderers/index.js.map +0 -1
- package/dist/renderers/json.d.ts +0 -13
- package/dist/renderers/json.d.ts.map +0 -1
- package/dist/renderers/json.js +0 -41
- package/dist/renderers/json.js.map +0 -1
- package/dist/renderers/markdown.d.ts +0 -13
- package/dist/renderers/markdown.d.ts.map +0 -1
- package/dist/renderers/markdown.js +0 -133
- package/dist/renderers/markdown.js.map +0 -1
- package/dist/renderers/terminal.d.ts +0 -14
- package/dist/renderers/terminal.d.ts.map +0 -1
- package/dist/renderers/terminal.js +0 -173
- package/dist/renderers/terminal.js.map +0 -1
- package/dist/renderers/types.d.ts +0 -12
- package/dist/renderers/types.d.ts.map +0 -1
- package/dist/renderers/types.js +0 -2
- package/dist/renderers/types.js.map +0 -1
- package/dist/sbom.d.ts +0 -42
- package/dist/sbom.d.ts.map +0 -1
- package/dist/sbom.js +0 -203
- package/dist/sbom.js.map +0 -1
- package/dist/status.d.ts +0 -27
- package/dist/status.d.ts.map +0 -1
- package/dist/status.js +0 -137
- package/dist/status.js.map +0 -1
- package/dist/summary.d.ts +0 -6
- package/dist/summary.d.ts.map +0 -1
- package/dist/summary.js +0 -47
- package/dist/summary.js.map +0 -1
- package/dist/types.d.ts +0 -208
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/validate.d.ts +0 -20
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -19
- package/dist/validate.js.map +0 -1
package/dist/sbom.js
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SBOM comparison for the HDF diff engine.
|
|
3
|
-
*
|
|
4
|
-
* Compares two SBOM documents (CycloneDX or SPDX JSON) and produces
|
|
5
|
-
* package-level diffs: added, removed, updated, unchanged packages.
|
|
6
|
-
*
|
|
7
|
-
* Format auto-detection:
|
|
8
|
-
* - CycloneDX: has `bomFormat: "CycloneDX"`, packages in `components[]`
|
|
9
|
-
* - SPDX: has `spdxVersion`, packages in `packages[]`
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Compare two SBOM documents (CycloneDX or SPDX JSON strings) and return
|
|
13
|
-
* package-level diffs.
|
|
14
|
-
*
|
|
15
|
-
* @param oldJson - JSON string of the old SBOM document
|
|
16
|
-
* @param newJson - JSON string of the new SBOM document
|
|
17
|
-
* @returns Structured diff result with per-package state and aggregate counts
|
|
18
|
-
* @throws Error if either input is not valid JSON or not a recognized SBOM format
|
|
19
|
-
*/
|
|
20
|
-
export function diffSboms(oldJson, newJson) {
|
|
21
|
-
const oldParsed = JSON.parse(oldJson);
|
|
22
|
-
const newParsed = JSON.parse(newJson);
|
|
23
|
-
const oldPackages = extractPackages(oldParsed);
|
|
24
|
-
const newPackages = extractPackages(newParsed);
|
|
25
|
-
const oldMap = buildPackageMap(oldPackages);
|
|
26
|
-
const newMap = buildPackageMap(newPackages);
|
|
27
|
-
const diffs = [];
|
|
28
|
-
const seen = new Set();
|
|
29
|
-
// Check old packages against new
|
|
30
|
-
for (const [key, oldPkg] of oldMap) {
|
|
31
|
-
seen.add(key);
|
|
32
|
-
const newPkg = newMap.get(key);
|
|
33
|
-
if (newPkg) {
|
|
34
|
-
if (oldPkg.version !== newPkg.version) {
|
|
35
|
-
diffs.push({
|
|
36
|
-
purl: newPkg.purl || newPkg.name,
|
|
37
|
-
name: newPkg.name,
|
|
38
|
-
state: 'updated',
|
|
39
|
-
oldVersion: oldPkg.version,
|
|
40
|
-
newVersion: newPkg.version,
|
|
41
|
-
licenses: newPkg.licenses.length > 0 ? newPkg.licenses : undefined,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
diffs.push({
|
|
46
|
-
purl: oldPkg.purl || oldPkg.name,
|
|
47
|
-
name: oldPkg.name,
|
|
48
|
-
state: 'unchanged',
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
diffs.push({
|
|
54
|
-
purl: oldPkg.purl || oldPkg.name,
|
|
55
|
-
name: oldPkg.name,
|
|
56
|
-
state: 'removed',
|
|
57
|
-
oldVersion: oldPkg.version,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// Check for added packages
|
|
62
|
-
for (const [key, newPkg] of newMap) {
|
|
63
|
-
if (!seen.has(key)) {
|
|
64
|
-
diffs.push({
|
|
65
|
-
purl: newPkg.purl || newPkg.name,
|
|
66
|
-
name: newPkg.name,
|
|
67
|
-
state: 'added',
|
|
68
|
-
newVersion: newPkg.version,
|
|
69
|
-
licenses: newPkg.licenses.length > 0 ? newPkg.licenses : undefined,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// Sort by name for deterministic output
|
|
74
|
-
diffs.sort((a, b) => a.name.localeCompare(b.name));
|
|
75
|
-
// Count states
|
|
76
|
-
let added = 0;
|
|
77
|
-
let removed = 0;
|
|
78
|
-
let updated = 0;
|
|
79
|
-
let unchanged = 0;
|
|
80
|
-
for (const d of diffs) {
|
|
81
|
-
switch (d.state) {
|
|
82
|
-
case 'added':
|
|
83
|
-
added++;
|
|
84
|
-
break;
|
|
85
|
-
case 'removed':
|
|
86
|
-
removed++;
|
|
87
|
-
break;
|
|
88
|
-
case 'updated':
|
|
89
|
-
updated++;
|
|
90
|
-
break;
|
|
91
|
-
case 'unchanged':
|
|
92
|
-
unchanged++;
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return { packageDiffs: diffs, added, removed, updated, unchanged };
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Extract packages from an SBOM document, auto-detecting the format.
|
|
100
|
-
*/
|
|
101
|
-
function extractPackages(doc) {
|
|
102
|
-
if (doc['bomFormat'] === 'CycloneDX') {
|
|
103
|
-
return extractCycloneDXPackages(doc);
|
|
104
|
-
}
|
|
105
|
-
if (typeof doc['spdxVersion'] === 'string') {
|
|
106
|
-
return extractSPDXPackages(doc);
|
|
107
|
-
}
|
|
108
|
-
throw new Error('Unrecognized SBOM format: expected CycloneDX (bomFormat) or SPDX (spdxVersion)');
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Extract packages from a CycloneDX document.
|
|
112
|
-
* Reads components[] with purl, name, version fields.
|
|
113
|
-
*/
|
|
114
|
-
function extractCycloneDXPackages(doc) {
|
|
115
|
-
const components = doc['components'];
|
|
116
|
-
if (!Array.isArray(components)) {
|
|
117
|
-
return [];
|
|
118
|
-
}
|
|
119
|
-
return components.map((comp) => {
|
|
120
|
-
const licenses = extractCycloneDXLicenses(comp);
|
|
121
|
-
return {
|
|
122
|
-
purl: comp['purl'] ?? '',
|
|
123
|
-
name: comp['name'] ?? '',
|
|
124
|
-
version: comp['version'] ?? '',
|
|
125
|
-
licenses,
|
|
126
|
-
};
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Extract license strings from a CycloneDX component.
|
|
131
|
-
* CycloneDX licenses can be in `licenses[].license.id` or `licenses[].license.name`.
|
|
132
|
-
*/
|
|
133
|
-
function extractCycloneDXLicenses(comp) {
|
|
134
|
-
const licensesArr = comp['licenses'];
|
|
135
|
-
if (!Array.isArray(licensesArr)) {
|
|
136
|
-
return [];
|
|
137
|
-
}
|
|
138
|
-
const result = [];
|
|
139
|
-
for (const entry of licensesArr) {
|
|
140
|
-
const license = entry['license'];
|
|
141
|
-
if (license) {
|
|
142
|
-
const id = license['id'];
|
|
143
|
-
const name = license['name'];
|
|
144
|
-
if (id) {
|
|
145
|
-
result.push(id);
|
|
146
|
-
}
|
|
147
|
-
else if (name) {
|
|
148
|
-
result.push(name);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return result;
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Extract packages from an SPDX document.
|
|
156
|
-
* Reads packages[] with name, versionInfo, and externalRefs (for PURL).
|
|
157
|
-
*/
|
|
158
|
-
function extractSPDXPackages(doc) {
|
|
159
|
-
const packages = doc['packages'];
|
|
160
|
-
if (!Array.isArray(packages)) {
|
|
161
|
-
return [];
|
|
162
|
-
}
|
|
163
|
-
return packages.map((pkg) => {
|
|
164
|
-
const purl = extractSPDXPurl(pkg);
|
|
165
|
-
const license = pkg['licenseConcluded'] ?? pkg['licenseDeclared'] ?? '';
|
|
166
|
-
return {
|
|
167
|
-
purl,
|
|
168
|
-
name: pkg['name'] ?? '',
|
|
169
|
-
version: pkg['versionInfo'] ?? '',
|
|
170
|
-
licenses: license && license !== 'NOASSERTION' ? [license] : [],
|
|
171
|
-
};
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Extract a PURL from an SPDX package's externalRefs array.
|
|
176
|
-
*/
|
|
177
|
-
function extractSPDXPurl(pkg) {
|
|
178
|
-
const refs = pkg['externalRefs'];
|
|
179
|
-
if (!Array.isArray(refs)) {
|
|
180
|
-
return '';
|
|
181
|
-
}
|
|
182
|
-
for (const ref of refs) {
|
|
183
|
-
const refType = ref['referenceType'];
|
|
184
|
-
if (refType === 'purl') {
|
|
185
|
-
return ref['referenceLocator'] ?? '';
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return '';
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Build a lookup map of packages indexed by name (version-independent key).
|
|
192
|
-
*/
|
|
193
|
-
function buildPackageMap(packages) {
|
|
194
|
-
const map = new Map();
|
|
195
|
-
for (const pkg of packages) {
|
|
196
|
-
const key = pkg.name || pkg.purl;
|
|
197
|
-
if (key) {
|
|
198
|
-
map.set(key, pkg);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return map;
|
|
202
|
-
}
|
|
203
|
-
//# sourceMappingURL=sbom.js.map
|
package/dist/sbom.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sbom.js","sourceRoot":"","sources":["../src/sbom.ts"],"names":[],"mappings":"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"}
|
package/dist/status.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { ChangeReason, RequirementState } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Determine the effective status of a requirement from its results and overrides.
|
|
4
|
-
*
|
|
5
|
-
* Priority:
|
|
6
|
-
* 1. impact === 0 → notApplicable (regardless of results)
|
|
7
|
-
* 2. effectiveStatus field set (and no statusOverrides) → use it
|
|
8
|
-
* 3. Non-expired statusOverrides → use first non-expired
|
|
9
|
-
* 4. Aggregate results using worst-wins
|
|
10
|
-
* 5. Empty results → notReviewed
|
|
11
|
-
*/
|
|
12
|
-
export declare function computeEffectiveStatus(requirement: Record<string, unknown>, referenceTimestamp?: string): string;
|
|
13
|
-
/**
|
|
14
|
-
* Classify why the status changed between two requirements.
|
|
15
|
-
* Returns an array of change reasons (a status change can have multiple causes).
|
|
16
|
-
*/
|
|
17
|
-
export declare function classifyChangeReasons(oldReq: Record<string, unknown>, newReq: Record<string, unknown>, oldTimestamp?: string, newTimestamp?: string): ChangeReason[];
|
|
18
|
-
/**
|
|
19
|
-
* Classify the overall diff status based on old and new effective statuses.
|
|
20
|
-
*
|
|
21
|
-
* - If old is failing and new is passing → 'fixed'
|
|
22
|
-
* - If old is passing and new is failing → 'regressed'
|
|
23
|
-
* - If statuses are equal → 'unchanged'
|
|
24
|
-
* - Otherwise → 'updated'
|
|
25
|
-
*/
|
|
26
|
-
export declare function classifyDiffStatus(oldEffectiveStatus: string, newEffectiveStatus: string): RequirementState;
|
|
27
|
-
//# sourceMappingURL=status.d.ts.map
|
package/dist/status.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA0BjE;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,kBAAkB,CAAC,EAAE,MAAM,GAC1B,MAAM,CAyCR;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,GACpB,YAAY,EAAE,CAuDhB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,kBAAkB,EAAE,MAAM,EAC1B,kBAAkB,EAAE,MAAM,GACzB,gBAAgB,CAkBlB"}
|
package/dist/status.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
/** Status severity ranking — higher index = worse */
|
|
2
|
-
const STATUS_SEVERITY = [
|
|
3
|
-
'notApplicable',
|
|
4
|
-
'notReviewed',
|
|
5
|
-
'passed',
|
|
6
|
-
'failed',
|
|
7
|
-
'error',
|
|
8
|
-
];
|
|
9
|
-
/** Statuses that count as "passing" for fixed/regressed classification */
|
|
10
|
-
const PASSING_STATUSES = new Set(['passed']);
|
|
11
|
-
/** Statuses that count as "failing" for fixed/regressed classification */
|
|
12
|
-
const FAILING_STATUSES = new Set(['failed', 'error', 'notReviewed']);
|
|
13
|
-
/**
|
|
14
|
-
* Determine the effective status of a requirement from its results and overrides.
|
|
15
|
-
*
|
|
16
|
-
* Priority:
|
|
17
|
-
* 1. impact === 0 → notApplicable (regardless of results)
|
|
18
|
-
* 2. effectiveStatus field set (and no statusOverrides) → use it
|
|
19
|
-
* 3. Non-expired statusOverrides → use first non-expired
|
|
20
|
-
* 4. Aggregate results using worst-wins
|
|
21
|
-
* 5. Empty results → notReviewed
|
|
22
|
-
*/
|
|
23
|
-
export function computeEffectiveStatus(requirement, referenceTimestamp) {
|
|
24
|
-
const impact = requirement['impact'];
|
|
25
|
-
if (impact === 0) {
|
|
26
|
-
return 'notApplicable';
|
|
27
|
-
}
|
|
28
|
-
const overrides = requirement['statusOverrides'];
|
|
29
|
-
if (overrides && overrides.length > 0) {
|
|
30
|
-
const refTime = referenceTimestamp ? new Date(referenceTimestamp).getTime() : Date.now();
|
|
31
|
-
for (const override of overrides) {
|
|
32
|
-
const expiresAt = new Date(override.expiresAt).getTime();
|
|
33
|
-
if (expiresAt > refTime) {
|
|
34
|
-
return override.status;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// All overrides expired — fall through to results
|
|
38
|
-
}
|
|
39
|
-
// If effectiveStatus is set and there are no overrides, use it
|
|
40
|
-
const effectiveStatus = requirement['effectiveStatus'];
|
|
41
|
-
if (effectiveStatus && (!overrides || overrides.length === 0)) {
|
|
42
|
-
return effectiveStatus;
|
|
43
|
-
}
|
|
44
|
-
const results = requirement['results'];
|
|
45
|
-
if (!results || results.length === 0) {
|
|
46
|
-
return 'notReviewed';
|
|
47
|
-
}
|
|
48
|
-
// Worst-wins: find the status with the highest severity index
|
|
49
|
-
let worstIndex = -1;
|
|
50
|
-
let worstStatus = 'notReviewed';
|
|
51
|
-
for (const result of results) {
|
|
52
|
-
const idx = STATUS_SEVERITY.indexOf(result.status);
|
|
53
|
-
if (idx > worstIndex) {
|
|
54
|
-
worstIndex = idx;
|
|
55
|
-
worstStatus = result.status;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return worstStatus;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Classify why the status changed between two requirements.
|
|
62
|
-
* Returns an array of change reasons (a status change can have multiple causes).
|
|
63
|
-
*/
|
|
64
|
-
export function classifyChangeReasons(oldReq, newReq, oldTimestamp, newTimestamp) {
|
|
65
|
-
const reasons = [];
|
|
66
|
-
// Check result status changes
|
|
67
|
-
const oldResults = oldReq['results'] ?? [];
|
|
68
|
-
const newResults = newReq['results'] ?? [];
|
|
69
|
-
const oldResultStatuses = oldResults.map((r) => r.status).sort();
|
|
70
|
-
const newResultStatuses = newResults.map((r) => r.status).sort();
|
|
71
|
-
if (JSON.stringify(oldResultStatuses) !== JSON.stringify(newResultStatuses)) {
|
|
72
|
-
reasons.push('resultChanged');
|
|
73
|
-
}
|
|
74
|
-
// Check override changes
|
|
75
|
-
const oldOverrides = oldReq['statusOverrides'] ?? [];
|
|
76
|
-
const newOverrides = newReq['statusOverrides'] ?? [];
|
|
77
|
-
if (newOverrides.length > oldOverrides.length) {
|
|
78
|
-
reasons.push('overrideAdded');
|
|
79
|
-
}
|
|
80
|
-
else if (newOverrides.length < oldOverrides.length) {
|
|
81
|
-
reasons.push('overrideRemoved');
|
|
82
|
-
}
|
|
83
|
-
// Check for override expiration between scans
|
|
84
|
-
if (oldTimestamp && newTimestamp && oldOverrides.length > 0) {
|
|
85
|
-
const oldTime = new Date(oldTimestamp).getTime();
|
|
86
|
-
const newTime = new Date(newTimestamp).getTime();
|
|
87
|
-
for (const override of oldOverrides) {
|
|
88
|
-
const expiresAt = new Date(override.expiresAt).getTime();
|
|
89
|
-
if (expiresAt > oldTime && expiresAt <= newTime) {
|
|
90
|
-
reasons.push('overrideExpired');
|
|
91
|
-
break; // Only report once
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
// Check impact changes
|
|
96
|
-
const oldImpact = oldReq['impact'];
|
|
97
|
-
const newImpact = newReq['impact'];
|
|
98
|
-
if (oldImpact !== newImpact) {
|
|
99
|
-
reasons.push('impactChanged');
|
|
100
|
-
}
|
|
101
|
-
// Check baseline metadata changes (tags, descriptions, title)
|
|
102
|
-
const oldTags = JSON.stringify(oldReq['tags'] ?? {});
|
|
103
|
-
const newTags = JSON.stringify(newReq['tags'] ?? {});
|
|
104
|
-
const oldDescs = JSON.stringify(oldReq['descriptions'] ?? []);
|
|
105
|
-
const newDescs = JSON.stringify(newReq['descriptions'] ?? []);
|
|
106
|
-
const oldTitle = oldReq['title'];
|
|
107
|
-
const newTitle = newReq['title'];
|
|
108
|
-
if (oldTags !== newTags || oldDescs !== newDescs || oldTitle !== newTitle) {
|
|
109
|
-
reasons.push('metadataChanged');
|
|
110
|
-
}
|
|
111
|
-
return reasons;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Classify the overall diff status based on old and new effective statuses.
|
|
115
|
-
*
|
|
116
|
-
* - If old is failing and new is passing → 'fixed'
|
|
117
|
-
* - If old is passing and new is failing → 'regressed'
|
|
118
|
-
* - If statuses are equal → 'unchanged'
|
|
119
|
-
* - Otherwise → 'updated'
|
|
120
|
-
*/
|
|
121
|
-
export function classifyDiffStatus(oldEffectiveStatus, newEffectiveStatus) {
|
|
122
|
-
if (oldEffectiveStatus === newEffectiveStatus) {
|
|
123
|
-
return 'unchanged';
|
|
124
|
-
}
|
|
125
|
-
const oldIsFailing = FAILING_STATUSES.has(oldEffectiveStatus);
|
|
126
|
-
const newIsPassing = PASSING_STATUSES.has(newEffectiveStatus);
|
|
127
|
-
const oldIsPassing = PASSING_STATUSES.has(oldEffectiveStatus);
|
|
128
|
-
const newIsFailing = FAILING_STATUSES.has(newEffectiveStatus);
|
|
129
|
-
if (oldIsFailing && newIsPassing) {
|
|
130
|
-
return 'fixed';
|
|
131
|
-
}
|
|
132
|
-
if (oldIsPassing && newIsFailing) {
|
|
133
|
-
return 'regressed';
|
|
134
|
-
}
|
|
135
|
-
return 'updated';
|
|
136
|
-
}
|
|
137
|
-
//# sourceMappingURL=status.js.map
|
package/dist/status.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"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"}
|
package/dist/summary.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { ComparisonSummary, RequirementDiff } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Compute summary counts from an array of RequirementDiff entries.
|
|
4
|
-
*/
|
|
5
|
-
export declare function computeSummary(requirements: RequirementDiff[]): ComparisonSummary;
|
|
6
|
-
//# sourceMappingURL=summary.d.ts.map
|
package/dist/summary.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE;;GAEG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,eAAe,EAAE,GAAG,iBAAiB,CA4CjF"}
|
package/dist/summary.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compute summary counts from an array of RequirementDiff entries.
|
|
3
|
-
*/
|
|
4
|
-
export function computeSummary(requirements) {
|
|
5
|
-
const summary = {
|
|
6
|
-
fixed: 0,
|
|
7
|
-
regressed: 0,
|
|
8
|
-
new: 0,
|
|
9
|
-
absent: 0,
|
|
10
|
-
unchanged: 0,
|
|
11
|
-
updated: 0,
|
|
12
|
-
total: requirements.length,
|
|
13
|
-
matchedCount: 0,
|
|
14
|
-
unmatchedOldCount: 0,
|
|
15
|
-
unmatchedNewCount: 0,
|
|
16
|
-
};
|
|
17
|
-
for (const req of requirements) {
|
|
18
|
-
switch (req.state) {
|
|
19
|
-
case 'fixed':
|
|
20
|
-
summary.fixed++;
|
|
21
|
-
summary.matchedCount++;
|
|
22
|
-
break;
|
|
23
|
-
case 'regressed':
|
|
24
|
-
summary.regressed++;
|
|
25
|
-
summary.matchedCount++;
|
|
26
|
-
break;
|
|
27
|
-
case 'new':
|
|
28
|
-
summary.new++;
|
|
29
|
-
summary.unmatchedNewCount++;
|
|
30
|
-
break;
|
|
31
|
-
case 'absent':
|
|
32
|
-
summary.absent++;
|
|
33
|
-
summary.unmatchedOldCount++;
|
|
34
|
-
break;
|
|
35
|
-
case 'unchanged':
|
|
36
|
-
summary.unchanged++;
|
|
37
|
-
summary.matchedCount++;
|
|
38
|
-
break;
|
|
39
|
-
case 'updated':
|
|
40
|
-
summary.updated++;
|
|
41
|
-
summary.matchedCount++;
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return summary;
|
|
46
|
-
}
|
|
47
|
-
//# sourceMappingURL=summary.js.map
|
package/dist/summary.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,YAA+B;IAC5D,MAAM,OAAO,GAAsB;QACjC,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,GAAG,EAAE,CAAC;QACN,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,YAAY,CAAC,MAAM;QAC1B,YAAY,EAAE,CAAC;QACf,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;KACrB,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,QAAQ,GAAG,CAAC,KAAK,EAAE,CAAC;YAClB,KAAK,OAAO;gBACV,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,OAAO,CAAC,YAAY,EAAE,CAAC;gBACvB,MAAM;YACR,KAAK,WAAW;gBACd,OAAO,CAAC,SAAS,EAAE,CAAC;gBACpB,OAAO,CAAC,YAAY,EAAE,CAAC;gBACvB,MAAM;YACR,KAAK,KAAK;gBACR,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,iBAAiB,EAAE,CAAC;gBAC5B,MAAM;YACR,KAAK,QAAQ;gBACX,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjB,OAAO,CAAC,iBAAiB,EAAE,CAAC;gBAC5B,MAAM;YACR,KAAK,WAAW;gBACd,OAAO,CAAC,SAAS,EAAE,CAAC;gBACpB,OAAO,CAAC,YAAY,EAAE,CAAC;gBACvB,MAAM;YACR,KAAK,SAAS;gBACZ,OAAO,CAAC,OAAO,EAAE,CAAC;gBAClB,OAAO,CAAC,YAAY,EAAE,CAAC;gBACvB,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/types.d.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Why a requirement's effective status changed between two evaluations.
|
|
3
|
-
*
|
|
4
|
-
* Aligned with the hdf-comparison schema's Change_Reason enum:
|
|
5
|
-
* - resultChanged: The underlying test results differ (e.g., a fix was deployed)
|
|
6
|
-
* - overrideAdded: A new statusOverride (waiver/attestation) was added
|
|
7
|
-
* - overrideExpired: A statusOverride present in the old scan has expired by the new scan's timestamp
|
|
8
|
-
* - overrideRemoved: A statusOverride was removed between scans
|
|
9
|
-
* - overrideModified: An existing statusOverride was modified (reserved for future use)
|
|
10
|
-
* - impactChanged: The impact score changed (e.g., from 0.7 to 0.0 means N/A)
|
|
11
|
-
* - baselineUpgraded: The baseline version changed (reserved for future use)
|
|
12
|
-
* - controlMapped: A control was mapped to a different framework (reserved for future use)
|
|
13
|
-
* - scannerChanged: A different scanner was used (reserved for future use)
|
|
14
|
-
* - targetChanged: The scan target changed (reserved for future use)
|
|
15
|
-
* - configChanged: The scan configuration changed (reserved for future use)
|
|
16
|
-
* - metadataChanged: Non-impact baseline metadata changed (tags, descriptions, title, etc.)
|
|
17
|
-
*/
|
|
18
|
-
export type ChangeReason = 'resultChanged' | 'overrideAdded' | 'overrideExpired' | 'overrideRemoved' | 'overrideModified' | 'impactChanged' | 'baselineUpgraded' | 'controlMapped' | 'scannerChanged' | 'targetChanged' | 'configChanged' | 'metadataChanged';
|
|
19
|
-
/**
|
|
20
|
-
* Classification of how a requirement's state changed between evaluations.
|
|
21
|
-
* Uses SARIF-inspired vocabulary.
|
|
22
|
-
*
|
|
23
|
-
* - new: Requirement exists only in the new evaluation (was "added")
|
|
24
|
-
* - absent: Requirement exists only in the old evaluation (was "removed")
|
|
25
|
-
* - unchanged: Same effective status in both evaluations
|
|
26
|
-
* - updated: Status changed but doesn't fit fixed/regressed (was "changed")
|
|
27
|
-
* - fixed: Was failing/error, now passing
|
|
28
|
-
* - regressed: Was passing, now failing/error
|
|
29
|
-
* - moved: Requirement ID changed but content is the same (future use)
|
|
30
|
-
* - split: One requirement became multiple (future use)
|
|
31
|
-
* - merged: Multiple requirements became one (future use)
|
|
32
|
-
*/
|
|
33
|
-
export type RequirementState = 'new' | 'absent' | 'unchanged' | 'updated' | 'fixed' | 'regressed' | 'moved' | 'split' | 'merged';
|
|
34
|
-
/**
|
|
35
|
-
* A field-level difference on a requirement, following JSON Patch-like conventions.
|
|
36
|
-
*/
|
|
37
|
-
export interface FieldChange {
|
|
38
|
-
/** The operation type: add, remove, or replace */
|
|
39
|
-
op: 'add' | 'remove' | 'replace';
|
|
40
|
-
/** Dot-notation path to the changed field (e.g., 'impact', 'tags.cci') */
|
|
41
|
-
path: string;
|
|
42
|
-
/** Value in the old evaluation (undefined for 'add' operations) */
|
|
43
|
-
oldValue?: unknown;
|
|
44
|
-
/** Value in the new evaluation (undefined for 'remove' operations) */
|
|
45
|
-
newValue?: unknown;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* The diff for a single requirement across two evaluations.
|
|
49
|
-
*/
|
|
50
|
-
export interface RequirementDiff {
|
|
51
|
-
/** The requirement ID (e.g., 'SV-238196') */
|
|
52
|
-
id: string;
|
|
53
|
-
/** Classification of the change */
|
|
54
|
-
state: RequirementState;
|
|
55
|
-
/** Why the status changed — empty array if unchanged */
|
|
56
|
-
changeReasons: ChangeReason[];
|
|
57
|
-
/** Full snapshot of the requirement from the old evaluation (null when state = 'new') */
|
|
58
|
-
before: Record<string, unknown> | null;
|
|
59
|
-
/** Full snapshot of the requirement from the new evaluation (null when state = 'absent') */
|
|
60
|
-
after: Record<string, unknown> | null;
|
|
61
|
-
/** The requirement title (from whichever evaluation has it) */
|
|
62
|
-
title?: string;
|
|
63
|
-
/** Effective status in the old evaluation (undefined if new) */
|
|
64
|
-
oldEffectiveStatus?: string;
|
|
65
|
-
/** Effective status in the new evaluation (undefined if absent) */
|
|
66
|
-
newEffectiveStatus?: string;
|
|
67
|
-
/** Impact in the old evaluation */
|
|
68
|
-
oldImpact?: number;
|
|
69
|
-
/** Impact in the new evaluation */
|
|
70
|
-
newImpact?: number;
|
|
71
|
-
/** Field-level diffs for non-status fields */
|
|
72
|
-
fieldChanges: FieldChange[];
|
|
73
|
-
/** The matching strategy that paired this requirement (e.g., 'exactId') */
|
|
74
|
-
matchStrategy?: string;
|
|
75
|
-
/** Confidence of the match (0.0-1.0) */
|
|
76
|
-
matchConfidence?: number;
|
|
77
|
-
/** Index into the sources array for fleet mode */
|
|
78
|
-
sourceIndex?: number;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Summary counts for the comparison.
|
|
82
|
-
*/
|
|
83
|
-
export interface ComparisonSummary {
|
|
84
|
-
/** Requirements that went from failing/error to passing */
|
|
85
|
-
fixed: number;
|
|
86
|
-
/** Requirements that went from passing to failing/error */
|
|
87
|
-
regressed: number;
|
|
88
|
-
/** Requirements present only in the new evaluation (was "added") */
|
|
89
|
-
new: number;
|
|
90
|
-
/** Requirements present only in the old evaluation (was "removed") */
|
|
91
|
-
absent: number;
|
|
92
|
-
/** Requirements with the same effective status */
|
|
93
|
-
unchanged: number;
|
|
94
|
-
/** Requirements whose status changed in a way other than fixed/regressed (was "changed") */
|
|
95
|
-
updated: number;
|
|
96
|
-
/** Total unique requirements across both evaluations */
|
|
97
|
-
total: number;
|
|
98
|
-
/** Number of requirements matched between old and new */
|
|
99
|
-
matchedCount: number;
|
|
100
|
-
/** Number of requirements only in old (unmatched) */
|
|
101
|
-
unmatchedOldCount: number;
|
|
102
|
-
/** Number of requirements only in new (unmatched) */
|
|
103
|
-
unmatchedNewCount: number;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* The diff for a single component across two system documents.
|
|
107
|
-
* Used in systemDrift comparison mode.
|
|
108
|
-
*/
|
|
109
|
-
export interface ComponentDiff {
|
|
110
|
-
/** Component name */
|
|
111
|
-
name: string;
|
|
112
|
-
/** Classification of the change: new, absent, unchanged, or updated */
|
|
113
|
-
state: 'new' | 'absent' | 'unchanged' | 'updated';
|
|
114
|
-
/** Component snapshot from the old system (null when state = 'new') */
|
|
115
|
-
before: Record<string, unknown> | null;
|
|
116
|
-
/** Component snapshot from the new system (null when state = 'absent') */
|
|
117
|
-
after: Record<string, unknown> | null;
|
|
118
|
-
/** Field-level diffs between old and new component */
|
|
119
|
-
fieldChanges: FieldChange[];
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* The diff for a single baseline across two evaluations.
|
|
123
|
-
*/
|
|
124
|
-
export interface BaselineDiff {
|
|
125
|
-
/** Baseline name */
|
|
126
|
-
name: string;
|
|
127
|
-
/** Version in the old evaluation */
|
|
128
|
-
oldVersion?: string;
|
|
129
|
-
/** Version in the new evaluation */
|
|
130
|
-
newVersion?: string;
|
|
131
|
-
/** Whether this baseline was new, absent, updated, or unchanged */
|
|
132
|
-
state: 'new' | 'absent' | 'updated' | 'unchanged';
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Metadata about a source document used in the comparison.
|
|
136
|
-
*/
|
|
137
|
-
export interface Source {
|
|
138
|
-
/** Role of the source in the comparison */
|
|
139
|
-
role: 'old' | 'new' | 'golden' | 'reference' | 'system';
|
|
140
|
-
/** Human-readable label */
|
|
141
|
-
label: string;
|
|
142
|
-
/** URI to the source document */
|
|
143
|
-
uri?: string;
|
|
144
|
-
/** Original format of the source (e.g., 'hdf-results-v2', 'inspec-exec-json-v1') */
|
|
145
|
-
originalFormat?: string;
|
|
146
|
-
/** Assessment timestamp from the source document */
|
|
147
|
-
assessmentTimestamp?: string;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* An annotation attached to a requirement diff.
|
|
151
|
-
*/
|
|
152
|
-
export interface Annotation {
|
|
153
|
-
/** Human-readable label */
|
|
154
|
-
label: string;
|
|
155
|
-
/** Description of the annotation */
|
|
156
|
-
text: string;
|
|
157
|
-
/** When the annotation was created */
|
|
158
|
-
timestamp?: string;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* The top-level comparison result comparing two or more HDF evaluations.
|
|
162
|
-
*/
|
|
163
|
-
export interface HdfComparison {
|
|
164
|
-
/** Schema version for the comparison format */
|
|
165
|
-
formatVersion: '1.0.0';
|
|
166
|
-
/** The mode of comparison */
|
|
167
|
-
comparisonMode: 'temporal' | 'baseline' | 'fleet' | 'multiSource' | 'baselineEvolution' | 'systemDrift';
|
|
168
|
-
/** When the comparison was generated */
|
|
169
|
-
timestamp?: string;
|
|
170
|
-
/** Source documents used in the comparison */
|
|
171
|
-
sources: Source[];
|
|
172
|
-
/** Matching configuration used */
|
|
173
|
-
matching?: MatchingConfig;
|
|
174
|
-
/** Aggregate counts */
|
|
175
|
-
summary: ComparisonSummary;
|
|
176
|
-
/** Per-baseline diffs */
|
|
177
|
-
baselineDiffs: BaselineDiff[];
|
|
178
|
-
/** Per-requirement diffs, sorted by id */
|
|
179
|
-
requirementDiffs: RequirementDiff[];
|
|
180
|
-
/** Per-component diffs (systemDrift mode only) */
|
|
181
|
-
componentDiffs?: ComponentDiff[];
|
|
182
|
-
/** Per-package diffs from embedded SBOM comparison (systemDrift mode only) */
|
|
183
|
-
packageDiffs?: import('./sbom.js').PackageDiff[];
|
|
184
|
-
/** URI identifying the system being compared (systemDrift mode only) */
|
|
185
|
-
systemRef?: string;
|
|
186
|
-
/** Requirements that drifted from a golden baseline (future use) */
|
|
187
|
-
drift?: RequirementDiff[];
|
|
188
|
-
/** Annotations keyed by requirement ID */
|
|
189
|
-
annotations?: Record<string, Annotation>;
|
|
190
|
-
/** Extension data for custom integrations */
|
|
191
|
-
extensions?: Record<string, unknown>;
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Configuration for how requirements are matched between evaluations.
|
|
195
|
-
*/
|
|
196
|
-
export interface MatchingConfig {
|
|
197
|
-
/** The primary strategy used for matching requirements across sources */
|
|
198
|
-
primaryStrategy: string;
|
|
199
|
-
/** Minimum confidence threshold for a match */
|
|
200
|
-
confidenceThreshold?: number;
|
|
201
|
-
}
|
|
202
|
-
/** @deprecated Use RequirementState instead */
|
|
203
|
-
export type DiffStatus = RequirementState;
|
|
204
|
-
/** @deprecated Use ComparisonSummary instead */
|
|
205
|
-
export type DiffSummary = ComparisonSummary;
|
|
206
|
-
/** @deprecated Use HdfComparison instead */
|
|
207
|
-
export type HdfDiff = HdfComparison;
|
|
208
|
-
//# sourceMappingURL=types.d.ts.map
|