@mitre/hdf-parsers 3.1.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/index.d.ts +31 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +146 -30
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -18,13 +18,13 @@ Parse and load Heimdall Data Format (HDF) documents with validation. Provides a
|
|
|
18
18
|
|-------------|----------------|
|
|
19
19
|
| Parse JSON → typed objects | Validate JSON against schema |
|
|
20
20
|
| "Load and validate this HDF file" | "Is this valid HDF?" |
|
|
21
|
-
| Returns typed
|
|
21
|
+
| Returns typed HDFResults/HDFBaseline | Returns validation errors |
|
|
22
22
|
| One-step parse + validate | Schema validation only |
|
|
23
23
|
| Used by CLI commands and tools | Used internally by parsers |
|
|
24
24
|
|
|
25
25
|
**Example:**
|
|
26
26
|
- `validateResults(data)` → `{ valid: true, errors: [] }` (validators - just validates)
|
|
27
|
-
- `parseResults(json)` → `{ success: true, data:
|
|
27
|
+
- `parseResults(json)` → `{ success: true, data: HDFResults }` (parsers - validates AND parses)
|
|
28
28
|
|
|
29
29
|
## Installation
|
|
30
30
|
|
|
@@ -90,7 +90,7 @@ import (
|
|
|
90
90
|
"fmt"
|
|
91
91
|
"os"
|
|
92
92
|
|
|
93
|
-
parsers "github.com/mitre/hdf-libs/hdf-parsers/go"
|
|
93
|
+
parsers "github.com/mitre/hdf-libs/hdf-parsers/go/v3"
|
|
94
94
|
)
|
|
95
95
|
|
|
96
96
|
func main() {
|
|
@@ -137,23 +137,23 @@ if result.Success {
|
|
|
137
137
|
|
|
138
138
|
### TypeScript
|
|
139
139
|
|
|
140
|
-
#### `parseResults(input: string | Uint8Array): ParseResult<
|
|
140
|
+
#### `parseResults(input: string | Uint8Array): ParseResult<HDFResults>`
|
|
141
141
|
|
|
142
142
|
Parse HDF Results document from JSON string or bytes.
|
|
143
143
|
|
|
144
144
|
- **Parameters:**
|
|
145
145
|
- `input` - JSON string or Uint8Array to parse
|
|
146
|
-
- **Returns:** `ParseResult<
|
|
146
|
+
- **Returns:** `ParseResult<HDFResults>` with parsed data or error
|
|
147
147
|
|
|
148
|
-
#### `parseBaseline(input: string | Uint8Array): ParseResult<
|
|
148
|
+
#### `parseBaseline(input: string | Uint8Array): ParseResult<HDFBaseline>`
|
|
149
149
|
|
|
150
150
|
Parse HDF Baseline document from JSON string or bytes.
|
|
151
151
|
|
|
152
152
|
- **Parameters:**
|
|
153
153
|
- `input` - JSON string or Uint8Array to parse
|
|
154
|
-
- **Returns:** `ParseResult<
|
|
154
|
+
- **Returns:** `ParseResult<HDFBaseline>` with parsed data or error
|
|
155
155
|
|
|
156
|
-
#### `parse(input: string | Uint8Array): ParseResult<
|
|
156
|
+
#### `parse(input: string | Uint8Array): ParseResult<HDFResults | HDFBaseline>`
|
|
157
157
|
|
|
158
158
|
Parse HDF document with auto-detection of type (Results vs Baseline).
|
|
159
159
|
|
|
@@ -329,9 +329,9 @@ Get type-safe HDF objects:
|
|
|
329
329
|
|
|
330
330
|
```typescript
|
|
331
331
|
import { parseResults } from '@mitre/hdf-parsers';
|
|
332
|
-
import type {
|
|
332
|
+
import type { HDFResults } from '@mitre/hdf-schema';
|
|
333
333
|
|
|
334
|
-
function processResults(data:
|
|
334
|
+
function processResults(data: HDFResults) {
|
|
335
335
|
// TypeScript knows the exact structure
|
|
336
336
|
for (const baseline of data.baselines ?? []) {
|
|
337
337
|
console.log(`Baseline: ${baseline.name}`);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HDFBaseline, HDFComparison, HDFEvidencePackage, HDFPlan, HDFResults, HDFSystem } from "@mitre/hdf-schema";
|
|
2
2
|
|
|
3
3
|
//#region typescript/flatten.d.ts
|
|
4
4
|
interface FlattenResult {
|
|
5
|
-
results:
|
|
5
|
+
results: HDFResults;
|
|
6
6
|
metadata: FlattenMetadata;
|
|
7
7
|
}
|
|
8
8
|
interface FlattenMetadata {
|
|
@@ -29,9 +29,16 @@ interface BaselineMerge {
|
|
|
29
29
|
* @param results - Parsed HDF Results (from parseResults() or equivalent)
|
|
30
30
|
* @returns FlattenResult with flattened data and merge metadata
|
|
31
31
|
*/
|
|
32
|
-
declare function flattenOverlays(results:
|
|
32
|
+
declare function flattenOverlays(results: HDFResults): FlattenResult;
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region typescript/index.d.ts
|
|
35
|
+
/**
|
|
36
|
+
* Append Z (treat as UTC) to bare ISO timestamps in a JSON string so they
|
|
37
|
+
* pass schema validation. Exported so other workspace packages can use the
|
|
38
|
+
* same regex instead of re-implementing it. Matches the Go side at
|
|
39
|
+
* hdf-parsers/go/parsers.go.
|
|
40
|
+
*/
|
|
41
|
+
declare function normalizeTimestamps(input: string): string;
|
|
35
42
|
/**
|
|
36
43
|
* Result of parsing operation
|
|
37
44
|
*/
|
|
@@ -39,26 +46,42 @@ interface ParseResult<T> {
|
|
|
39
46
|
success: boolean;
|
|
40
47
|
data?: T;
|
|
41
48
|
error?: string;
|
|
42
|
-
type?: 'results' | 'baseline';
|
|
49
|
+
type?: 'results' | 'baseline' | 'system' | 'plan' | 'evidencePackage' | 'comparison';
|
|
43
50
|
}
|
|
44
51
|
/**
|
|
45
52
|
* Parse HDF Results document from string or bytes
|
|
46
53
|
* @param input - JSON string or Uint8Array to parse
|
|
47
54
|
* @returns ParseResult with parsed data or error
|
|
48
55
|
*/
|
|
49
|
-
declare function parseResults(input: string | Uint8Array): ParseResult<
|
|
56
|
+
declare function parseResults(input: string | Uint8Array): ParseResult<HDFResults>;
|
|
50
57
|
/**
|
|
51
58
|
* Parse HDF Baseline document from string or bytes
|
|
52
59
|
* @param input - JSON string or Uint8Array to parse
|
|
53
60
|
* @returns ParseResult with parsed data or error
|
|
54
61
|
*/
|
|
55
|
-
declare function parseBaseline(input: string | Uint8Array): ParseResult<
|
|
62
|
+
declare function parseBaseline(input: string | Uint8Array): ParseResult<HDFBaseline>;
|
|
63
|
+
/**
|
|
64
|
+
* Parse HDF System document from string or bytes
|
|
65
|
+
*/
|
|
66
|
+
declare function parseSystem(input: string | Uint8Array): ParseResult<HDFSystem>;
|
|
67
|
+
/**
|
|
68
|
+
* Parse HDF Plan document from string or bytes
|
|
69
|
+
*/
|
|
70
|
+
declare function parsePlan(input: string | Uint8Array): ParseResult<HDFPlan>;
|
|
71
|
+
/**
|
|
72
|
+
* Parse HDF Evidence Package document from string or bytes
|
|
73
|
+
*/
|
|
74
|
+
declare function parseEvidencePackage(input: string | Uint8Array): ParseResult<HDFEvidencePackage>;
|
|
75
|
+
/**
|
|
76
|
+
* Parse HDF Comparison document from string or bytes
|
|
77
|
+
*/
|
|
78
|
+
declare function parseComparison(input: string | Uint8Array): ParseResult<HDFComparison>;
|
|
56
79
|
/**
|
|
57
80
|
* Parse HDF document with auto-detection of type
|
|
58
81
|
* @param input - JSON string or Uint8Array to parse
|
|
59
82
|
* @returns ParseResult with parsed data, type indicator, or error
|
|
60
83
|
*/
|
|
61
|
-
declare function parse(input: string | Uint8Array): ParseResult<
|
|
84
|
+
declare function parse(input: string | Uint8Array): ParseResult<HDFResults | HDFBaseline | HDFSystem | HDFPlan | HDFEvidencePackage | HDFComparison>;
|
|
62
85
|
//#endregion
|
|
63
|
-
export { type BaselineMerge, type FlattenMetadata, type FlattenResult, ParseResult, flattenOverlays, parse, parseBaseline, parseResults };
|
|
86
|
+
export { type BaselineMerge, type FlattenMetadata, type FlattenResult, ParseResult, flattenOverlays, normalizeTimestamps, parse, parseBaseline, parseComparison, parseEvidencePackage, parsePlan, parseResults, parseSystem };
|
|
64
87
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../typescript/flatten.ts","../typescript/index.ts"],"mappings":";;;UAIiB,aAAA;EACf,OAAA,EAAS,UAAA;EACT,QAAA,EAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../typescript/flatten.ts","../typescript/index.ts"],"mappings":";;;UAIiB,aAAA;EACf,OAAA,EAAS,UAAA;EACT,QAAA,EAAU,eAAe;AAAA;AAAA,UAGV,eAAA;EACf,qBAAA;EACA,sBAAA;EACA,MAAA,EAAQ,aAAa;EACrB,QAAA;AAAA;AAAA,UAGe,aAAA;EACf,YAAA;EACA,iBAAA;EACA,cAAA;EACA,aAAA;EACA,OAAA;AAAA;;;;;;AARQ;AAGV;;;;;iBAgIgB,eAAA,CAAgB,OAAA,EAAS,UAAA,GAAa,aAAa;;;AA5InE;;;;;;AAAA,iBC2BgB,mBAAA,CAAoB,KAAa;;;ADzBtB;UCgCV,WAAA;EACf,OAAA;EACA,IAAA,GAAO,CAAC;EACR,KAAA;EACA,IAAA;AAAA;;;;;AD7BQ;iBCqCM,YAAA,CAAa,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,UAAA;;;;;;iBAmDtD,aAAA,CAAc,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,WAAA;;;;iBA6CvD,WAAA,CAAY,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,SAAA;ADFrE;;;AAAA,iBCwBgB,SAAA,CAAU,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,OAAA;;;;iBAsBnD,oBAAA,CAAqB,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,kBAAA;AD9CX;;;AAAA,iBCoEnD,eAAA,CAAgB,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,aAAA;AArLzE;;;;AAAiD;AAAjD,iBA6MgB,KAAA,CACd,KAAA,WAAgB,UAAA,GACf,WAAA,CAAY,UAAA,GAAa,WAAA,GAAc,SAAA,GAAY,OAAA,GAAU,kBAAA,GAAqB,aAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { validate, validateBaseline, validateResults } from "@mitre/hdf-validators";
|
|
1
|
+
import { validate, validateBaseline, validateComparison, validateEvidencePackage, validatePlan, validateResults, validateSystem } from "@mitre/hdf-validators";
|
|
2
2
|
//#region typescript/flatten.ts
|
|
3
3
|
/** BFS from root, returns names in top-down order. Cycle-safe. */
|
|
4
4
|
function collectTree(root, childrenMap) {
|
|
@@ -168,13 +168,23 @@ function flattenOverlays(results) {
|
|
|
168
168
|
}
|
|
169
169
|
//#endregion
|
|
170
170
|
//#region typescript/index.ts
|
|
171
|
+
const NO_TZ_TIMESTAMP_REGEX = /"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?)"/g;
|
|
172
|
+
/**
|
|
173
|
+
* Append Z (treat as UTC) to bare ISO timestamps in a JSON string so they
|
|
174
|
+
* pass schema validation. Exported so other workspace packages can use the
|
|
175
|
+
* same regex instead of re-implementing it. Matches the Go side at
|
|
176
|
+
* hdf-parsers/go/parsers.go.
|
|
177
|
+
*/
|
|
178
|
+
function normalizeTimestamps(input) {
|
|
179
|
+
return input.replace(NO_TZ_TIMESTAMP_REGEX, "\"$1Z\"");
|
|
180
|
+
}
|
|
171
181
|
/**
|
|
172
182
|
* Parse HDF Results document from string or bytes
|
|
173
183
|
* @param input - JSON string or Uint8Array to parse
|
|
174
184
|
* @returns ParseResult with parsed data or error
|
|
175
185
|
*/
|
|
176
186
|
function parseResults(input) {
|
|
177
|
-
const jsonStr = typeof input === "string" ? input : new TextDecoder().decode(input);
|
|
187
|
+
const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
|
|
178
188
|
if (jsonStr.trim().length === 0) return {
|
|
179
189
|
success: false,
|
|
180
190
|
error: "Input is empty"
|
|
@@ -188,12 +198,6 @@ function parseResults(input) {
|
|
|
188
198
|
error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
189
199
|
};
|
|
190
200
|
}
|
|
191
|
-
const serialized = JSON.stringify(data);
|
|
192
|
-
const trimmedInput = jsonStr.trim();
|
|
193
|
-
if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) return {
|
|
194
|
-
success: false,
|
|
195
|
-
error: "Invalid JSON: unexpected trailing data after end of object"
|
|
196
|
-
};
|
|
197
201
|
const validationResult = validateResults(data);
|
|
198
202
|
if (!validationResult.valid) return {
|
|
199
203
|
success: false,
|
|
@@ -210,7 +214,7 @@ function parseResults(input) {
|
|
|
210
214
|
* @returns ParseResult with parsed data or error
|
|
211
215
|
*/
|
|
212
216
|
function parseBaseline(input) {
|
|
213
|
-
const jsonStr = typeof input === "string" ? input : new TextDecoder().decode(input);
|
|
217
|
+
const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
|
|
214
218
|
if (jsonStr.trim().length === 0) return {
|
|
215
219
|
success: false,
|
|
216
220
|
error: "Input is empty"
|
|
@@ -224,13 +228,119 @@ function parseBaseline(input) {
|
|
|
224
228
|
error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
225
229
|
};
|
|
226
230
|
}
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) return {
|
|
231
|
+
const validationResult = validateBaseline(data);
|
|
232
|
+
if (!validationResult.valid) return {
|
|
230
233
|
success: false,
|
|
231
|
-
error:
|
|
234
|
+
error: `Schema validation failed: ${validationResult.getErrorMessage()}`
|
|
232
235
|
};
|
|
233
|
-
|
|
236
|
+
return {
|
|
237
|
+
success: true,
|
|
238
|
+
data
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Parse HDF System document from string or bytes
|
|
243
|
+
*/
|
|
244
|
+
function parseSystem(input) {
|
|
245
|
+
const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
|
|
246
|
+
if (jsonStr.trim().length === 0) return {
|
|
247
|
+
success: false,
|
|
248
|
+
error: "Input is empty"
|
|
249
|
+
};
|
|
250
|
+
let data;
|
|
251
|
+
try {
|
|
252
|
+
data = JSON.parse(jsonStr);
|
|
253
|
+
} catch (err) {
|
|
254
|
+
return {
|
|
255
|
+
success: false,
|
|
256
|
+
error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const validationResult = validateSystem(data);
|
|
260
|
+
if (!validationResult.valid) return {
|
|
261
|
+
success: false,
|
|
262
|
+
error: `Schema validation failed: ${validationResult.getErrorMessage()}`
|
|
263
|
+
};
|
|
264
|
+
return {
|
|
265
|
+
success: true,
|
|
266
|
+
data
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Parse HDF Plan document from string or bytes
|
|
271
|
+
*/
|
|
272
|
+
function parsePlan(input) {
|
|
273
|
+
const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
|
|
274
|
+
if (jsonStr.trim().length === 0) return {
|
|
275
|
+
success: false,
|
|
276
|
+
error: "Input is empty"
|
|
277
|
+
};
|
|
278
|
+
let data;
|
|
279
|
+
try {
|
|
280
|
+
data = JSON.parse(jsonStr);
|
|
281
|
+
} catch (err) {
|
|
282
|
+
return {
|
|
283
|
+
success: false,
|
|
284
|
+
error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
const validationResult = validatePlan(data);
|
|
288
|
+
if (!validationResult.valid) return {
|
|
289
|
+
success: false,
|
|
290
|
+
error: `Schema validation failed: ${validationResult.getErrorMessage()}`
|
|
291
|
+
};
|
|
292
|
+
return {
|
|
293
|
+
success: true,
|
|
294
|
+
data
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Parse HDF Evidence Package document from string or bytes
|
|
299
|
+
*/
|
|
300
|
+
function parseEvidencePackage(input) {
|
|
301
|
+
const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
|
|
302
|
+
if (jsonStr.trim().length === 0) return {
|
|
303
|
+
success: false,
|
|
304
|
+
error: "Input is empty"
|
|
305
|
+
};
|
|
306
|
+
let data;
|
|
307
|
+
try {
|
|
308
|
+
data = JSON.parse(jsonStr);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
return {
|
|
311
|
+
success: false,
|
|
312
|
+
error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const validationResult = validateEvidencePackage(data);
|
|
316
|
+
if (!validationResult.valid) return {
|
|
317
|
+
success: false,
|
|
318
|
+
error: `Schema validation failed: ${validationResult.getErrorMessage()}`
|
|
319
|
+
};
|
|
320
|
+
return {
|
|
321
|
+
success: true,
|
|
322
|
+
data
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Parse HDF Comparison document from string or bytes
|
|
327
|
+
*/
|
|
328
|
+
function parseComparison(input) {
|
|
329
|
+
const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
|
|
330
|
+
if (jsonStr.trim().length === 0) return {
|
|
331
|
+
success: false,
|
|
332
|
+
error: "Input is empty"
|
|
333
|
+
};
|
|
334
|
+
let data;
|
|
335
|
+
try {
|
|
336
|
+
data = JSON.parse(jsonStr);
|
|
337
|
+
} catch (err) {
|
|
338
|
+
return {
|
|
339
|
+
success: false,
|
|
340
|
+
error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
const validationResult = validateComparison(data);
|
|
234
344
|
if (!validationResult.valid) return {
|
|
235
345
|
success: false,
|
|
236
346
|
error: `Schema validation failed: ${validationResult.getErrorMessage()}`
|
|
@@ -246,7 +356,7 @@ function parseBaseline(input) {
|
|
|
246
356
|
* @returns ParseResult with parsed data, type indicator, or error
|
|
247
357
|
*/
|
|
248
358
|
function parse(input) {
|
|
249
|
-
const jsonStr = typeof input === "string" ? input : new TextDecoder().decode(input);
|
|
359
|
+
const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
|
|
250
360
|
if (jsonStr.trim().length === 0) return {
|
|
251
361
|
success: false,
|
|
252
362
|
error: "Input is empty"
|
|
@@ -260,12 +370,6 @@ function parse(input) {
|
|
|
260
370
|
error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
261
371
|
};
|
|
262
372
|
}
|
|
263
|
-
const serialized = JSON.stringify(data);
|
|
264
|
-
const trimmedInput = jsonStr.trim();
|
|
265
|
-
if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) return {
|
|
266
|
-
success: false,
|
|
267
|
-
error: "Invalid JSON: unexpected trailing data after end of object"
|
|
268
|
-
};
|
|
269
373
|
const validationResult = validate(data);
|
|
270
374
|
if (!validationResult.valid) return {
|
|
271
375
|
success: false,
|
|
@@ -278,26 +382,38 @@ function parse(input) {
|
|
|
278
382
|
data,
|
|
279
383
|
type: "results"
|
|
280
384
|
};
|
|
385
|
+
if ("requirementDiffs" in obj) return {
|
|
386
|
+
success: true,
|
|
387
|
+
data,
|
|
388
|
+
type: "comparison"
|
|
389
|
+
};
|
|
390
|
+
if ("assessments" in obj) return {
|
|
391
|
+
success: true,
|
|
392
|
+
data,
|
|
393
|
+
type: "plan"
|
|
394
|
+
};
|
|
395
|
+
if ("contents" in obj) return {
|
|
396
|
+
success: true,
|
|
397
|
+
data,
|
|
398
|
+
type: "evidencePackage"
|
|
399
|
+
};
|
|
281
400
|
if ("name" in obj && "requirements" in obj) return {
|
|
282
401
|
success: true,
|
|
283
402
|
data,
|
|
284
403
|
type: "baseline"
|
|
285
404
|
};
|
|
405
|
+
if ("components" in obj) return {
|
|
406
|
+
success: true,
|
|
407
|
+
data,
|
|
408
|
+
type: "system"
|
|
409
|
+
};
|
|
286
410
|
}
|
|
287
411
|
return {
|
|
288
412
|
success: false,
|
|
289
413
|
error: "Unable to determine HDF document type"
|
|
290
414
|
};
|
|
291
415
|
}
|
|
292
|
-
/**
|
|
293
|
-
* Check if two JSON strings are equivalent modulo whitespace
|
|
294
|
-
* This is a simple heuristic - we check if one is just whitespace-padded version of other
|
|
295
|
-
*/
|
|
296
|
-
function isWhitespaceEquivalent(a, b) {
|
|
297
|
-
const normalizeWhitespace = (s) => s.replace(/\s+/g, "");
|
|
298
|
-
return normalizeWhitespace(a) === normalizeWhitespace(b);
|
|
299
|
-
}
|
|
300
416
|
//#endregion
|
|
301
|
-
export { flattenOverlays, parse, parseBaseline, parseResults };
|
|
417
|
+
export { flattenOverlays, normalizeTimestamps, parse, parseBaseline, parseComparison, parseEvidencePackage, parsePlan, parseResults, parseSystem };
|
|
302
418
|
|
|
303
419
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["autoValidate"],"sources":["../typescript/flatten.ts","../typescript/index.ts"],"sourcesContent":["import type { HdfResults, EvaluatedBaseline, EvaluatedRequirement } from '@mitre/hdf-schema';\n\n// ── Public Types ────────────────────────────────────────────\n\nexport interface FlattenResult {\n results: HdfResults;\n metadata: FlattenMetadata;\n}\n\nexport interface FlattenMetadata {\n originalBaselineCount: number;\n flattenedBaselineCount: number;\n merges: BaselineMerge[];\n warnings: string[];\n}\n\nexport interface BaselineMerge {\n rootBaseline: string;\n absorbedBaselines: string[];\n controlsBefore: number;\n controlsAfter: number;\n pattern: 'deep' | 'wide' | 'hybrid';\n}\n\n// ── Internal Helpers ───────────────────────────────────────\n\n/** BFS from root, returns names in top-down order. Cycle-safe. */\nfunction collectTree(root: string, childrenMap: Map<string, string[]>): string[] {\n const order: string[] = [];\n const seen = new Set<string>();\n const queue = [root];\n while (queue.length > 0) {\n const name = queue.shift()!;\n if (seen.has(name)) continue;\n seen.add(name);\n order.push(name);\n for (const child of (childrenMap.get(name) || [])) {\n queue.push(child);\n }\n }\n return order;\n}\n\n/** Classify merge pattern based on tree shape */\nfunction detectPattern(root: string, childrenMap: Map<string, string[]>): 'deep' | 'wide' | 'hybrid' {\n const rootChildren = childrenMap.get(root) || [];\n if (rootChildren.length <= 1) {\n return 'deep';\n }\n for (const child of rootChildren) {\n if ((childrenMap.get(child) || []).length > 0) {\n return 'hybrid';\n }\n }\n return 'wide';\n}\n\n/** Merge incoming requirement fields onto existing */\nfunction mergeRequirement(\n existing: EvaluatedRequirement,\n incoming: EvaluatedRequirement\n): EvaluatedRequirement {\n const result: EvaluatedRequirement = { ...existing };\n\n // Impact: incoming always wins (required field, always present)\n result.impact = incoming.impact;\n\n // Results: keep whichever is non-empty (base has them, overlay doesn't)\n if (incoming.results && incoming.results.length > 0) {\n result.results = incoming.results;\n }\n\n // Code: incoming wins if non-empty\n if (incoming.code && incoming.code.trim() !== '') {\n result.code = incoming.code;\n }\n\n // Tags: shallow merge (incoming keys override)\n if (incoming.tags) {\n result.tags = { ...existing.tags, ...incoming.tags };\n }\n\n // Severity: incoming wins if present, else keep existing\n if (incoming.severity !== undefined) {\n result.severity = incoming.severity;\n }\n\n // EffectiveStatus: incoming wins only if it has results (otherwise its\n // effectiveStatus is a computed artifact from empty results, not intentional).\n // Overlays typically have empty results — the base has the real test results.\n if (incoming.effectiveStatus !== undefined && incoming.results && incoming.results.length > 0) {\n result.effectiveStatus = incoming.effectiveStatus;\n }\n\n // Descriptions: merge by label (incoming overrides same label)\n if (incoming.descriptions && incoming.descriptions.length > 0) {\n const descMap = new Map(\n (existing.descriptions || []).map(d => [d.label, d])\n );\n for (const d of incoming.descriptions) {\n descMap.set(d.label, d);\n }\n result.descriptions = [...descMap.values()];\n }\n\n return result;\n}\n\n/**\n * Resolve parentBaseline for a baseline.\n * InSpec parent_profile can use depends-name aliases (e.g., 'k8s' instead of\n * 'k8s-node-stig-baseline'). When the value isn't a direct profile name,\n * find who depends on this baseline — that's the actual parent.\n */\nfunction resolveParentBaseline(\n b: EvaluatedBaseline,\n byName: Map<string, EvaluatedBaseline>,\n allBaselines: EvaluatedBaseline[]\n): string | undefined {\n if (!b.parentBaseline) return undefined;\n if (byName.has(b.parentBaseline)) return b.parentBaseline;\n\n // Alias resolution: find the profile whose depends array includes this baseline\n for (const candidate of allBaselines) {\n if (candidate.depends?.some((d) => d.name === b.name)) {\n return candidate.name;\n }\n }\n return undefined; // orphan\n}\n\n// ── Public API ──────────────────────────────────────────────\n\n/**\n * Flatten overlay/wrapper baselines in an HDF Results document.\n *\n * Handles:\n * - Deep nesting (overlay chains with shared control IDs via parentBaseline)\n * - Wide nesting (wrapper profiles aggregating independent bases)\n * - Hybrid (both patterns in one document)\n *\n * @param results - Parsed HDF Results (from parseResults() or equivalent)\n * @returns FlattenResult with flattened data and merge metadata\n */\nexport function flattenOverlays(results: HdfResults): FlattenResult {\n const { baselines } = results;\n const warnings: string[] = [];\n const merges: BaselineMerge[] = [];\n\n if (!baselines || baselines.length === 0) {\n return {\n results: { ...results, baselines: [] },\n metadata: {\n originalBaselineCount: 0,\n flattenedBaselineCount: 0,\n merges: [],\n warnings: [],\n },\n };\n }\n\n // Index baselines by name\n const byName = new Map<string, EvaluatedBaseline>();\n for (const b of baselines) {\n if (byName.has(b.name)) {\n warnings.push(`Duplicate baseline name \"${b.name}\" — later entry overwrites earlier`);\n }\n byName.set(b.name, b);\n }\n\n // Resolve parentBaseline aliases and build parent map\n const resolvedParent = new Map<string, string | undefined>();\n for (const b of baselines) {\n const parent = resolveParentBaseline(b, byName, baselines);\n resolvedParent.set(b.name, parent);\n if (b.parentBaseline && !parent) {\n warnings.push(\n `Baseline \"${b.name}\" references nonexistent parent \"${b.parentBaseline}\"`\n );\n }\n }\n\n // Build parent → children adjacency using resolved parents\n const childrenMap = new Map<string, string[]>();\n for (const b of baselines) {\n const parent = resolvedParent.get(b.name);\n if (parent) {\n const list = childrenMap.get(parent) || [];\n list.push(b.name);\n childrenMap.set(parent, list);\n }\n }\n\n // Find roots: no resolved parent\n const roots: string[] = [];\n const visited = new Set<string>();\n\n for (const b of baselines) {\n if (!resolvedParent.get(b.name)) {\n roots.push(b.name);\n }\n }\n\n // Mark reachable from roots (iterative DFS to avoid stack overflow on deep trees)\n function markReachable(start: string): void {\n const stack = [start];\n while (stack.length > 0) {\n const name = stack.pop()!;\n if (visited.has(name)) continue;\n visited.add(name);\n const children = childrenMap.get(name);\n if (children) {\n for (const child of children) {\n stack.push(child);\n }\n }\n }\n }\n for (const r of roots) {\n markReachable(r);\n }\n\n // Detect cycles: unvisited baselines are in cycles\n for (const b of baselines) {\n if (!visited.has(b.name)) {\n warnings.push(`Circular parentBaseline detected involving \"${b.name}\"`);\n roots.push(b.name);\n markReachable(b.name);\n }\n }\n\n // Process each root tree\n const flatBaselines: EvaluatedBaseline[] = [];\n\n for (const rootName of roots) {\n const root = byName.get(rootName)!;\n const treeNames = collectTree(rootName, childrenMap);\n\n if (treeNames.length === 1) {\n // Standalone baseline — pass through unchanged (preserve depends)\n flatBaselines.push(root);\n continue;\n }\n\n // Bottom-up order: reverse top-down BFS\n const bottomUp = [...treeNames].reverse();\n\n // Merge requirements across the tree\n const merged = new Map<string, EvaluatedRequirement>();\n let controlsBefore = 0;\n const absorbed: string[] = [];\n\n for (const name of bottomUp) {\n const b = byName.get(name)!;\n controlsBefore += b.requirements.length;\n if (name !== rootName) {\n absorbed.push(name);\n }\n for (const req of b.requirements) {\n if (merged.has(req.id)) {\n merged.set(req.id, mergeRequirement(merged.get(req.id)!, req));\n } else {\n merged.set(req.id, { ...req });\n }\n }\n }\n\n const mergedReqs = [...merged.values()];\n const pattern = detectPattern(rootName, childrenMap);\n\n merges.push({\n rootBaseline: rootName,\n absorbedBaselines: absorbed,\n controlsBefore,\n controlsAfter: mergedReqs.length,\n pattern,\n });\n\n const out: EvaluatedBaseline = {\n ...root,\n requirements: mergedReqs,\n };\n delete out.parentBaseline;\n delete out.depends;\n flatBaselines.push(out);\n }\n\n return {\n results: { ...results, baselines: flatBaselines },\n metadata: {\n originalBaselineCount: baselines.length,\n flattenedBaselineCount: flatBaselines.length,\n merges,\n warnings,\n },\n };\n}\n","import type { HdfResults, HdfBaseline } from '@mitre/hdf-schema';\nexport { flattenOverlays } from './flatten.js';\nexport type { FlattenResult, FlattenMetadata, BaselineMerge } from './flatten.js';\nimport { validateResults, validateBaseline, validate as autoValidate } from '@mitre/hdf-validators';\n\n/**\n * Result of parsing operation\n */\nexport interface ParseResult<T> {\n success: boolean;\n data?: T;\n error?: string;\n type?: 'results' | 'baseline';\n}\n\n/**\n * Parse HDF Results document from string or bytes\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data or error\n */\nexport function parseResults(input: string | Uint8Array): ParseResult<HdfResults> {\n // Convert Uint8Array to string if needed\n const jsonStr = typeof input === 'string' ? input : new TextDecoder().decode(input);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Check for trailing garbage by re-serializing and comparing length\n // This catches cases like: {\"valid\":\"json\"}garbage\n const serialized = JSON.stringify(data);\n const trimmedInput = jsonStr.trim();\n if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) {\n return {\n success: false,\n error: 'Invalid JSON: unexpected trailing data after end of object'\n };\n }\n\n // Validate against schema\n const validationResult = validateResults(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n return {\n success: true,\n data: data as HdfResults\n };\n}\n\n/**\n * Parse HDF Baseline document from string or bytes\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data or error\n */\nexport function parseBaseline(input: string | Uint8Array): ParseResult<HdfBaseline> {\n // Convert Uint8Array to string if needed\n const jsonStr = typeof input === 'string' ? input : new TextDecoder().decode(input);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Check for trailing garbage\n const serialized = JSON.stringify(data);\n const trimmedInput = jsonStr.trim();\n if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) {\n return {\n success: false,\n error: 'Invalid JSON: unexpected trailing data after end of object'\n };\n }\n\n // Validate against schema\n const validationResult = validateBaseline(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n return {\n success: true,\n data: data as HdfBaseline\n };\n}\n\n/**\n * Parse HDF document with auto-detection of type\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data, type indicator, or error\n */\nexport function parse(input: string | Uint8Array): ParseResult<HdfResults | HdfBaseline> {\n // Convert Uint8Array to string if needed\n const jsonStr = typeof input === 'string' ? input : new TextDecoder().decode(input);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Check for trailing garbage\n const serialized = JSON.stringify(data);\n const trimmedInput = jsonStr.trim();\n if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) {\n return {\n success: false,\n error: 'Invalid JSON: unexpected trailing data after end of object'\n };\n }\n\n // Auto-validate and detect type\n const validationResult = autoValidate(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n // Determine type based on structure\n if (typeof data === 'object' && data !== null) {\n const obj = data as Record<string, unknown>;\n\n // HDF Results has 'baselines' array at root\n if ('baselines' in obj) {\n return {\n success: true,\n data: data as HdfResults,\n type: 'results'\n };\n }\n\n // HDF Baseline has 'name' and 'requirements' at root\n if ('name' in obj && 'requirements' in obj) {\n return {\n success: true,\n data: data as HdfBaseline,\n type: 'baseline'\n };\n }\n }\n\n return {\n success: false,\n error: 'Unable to determine HDF document type'\n };\n}\n\n/**\n * Check if two JSON strings are equivalent modulo whitespace\n * This is a simple heuristic - we check if one is just whitespace-padded version of other\n */\nfunction isWhitespaceEquivalent(a: string, b: string): boolean {\n // Remove all whitespace and compare\n const normalizeWhitespace = (s: string): string => s.replace(/\\s+/g, '');\n return normalizeWhitespace(a) === normalizeWhitespace(b);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["autoValidate"],"sources":["../typescript/flatten.ts","../typescript/index.ts"],"sourcesContent":["import type { HDFResults, EvaluatedBaseline, EvaluatedRequirement } from '@mitre/hdf-schema';\n\n// ── Public Types ────────────────────────────────────────────\n\nexport interface FlattenResult {\n results: HDFResults;\n metadata: FlattenMetadata;\n}\n\nexport interface FlattenMetadata {\n originalBaselineCount: number;\n flattenedBaselineCount: number;\n merges: BaselineMerge[];\n warnings: string[];\n}\n\nexport interface BaselineMerge {\n rootBaseline: string;\n absorbedBaselines: string[];\n controlsBefore: number;\n controlsAfter: number;\n pattern: 'deep' | 'wide' | 'hybrid';\n}\n\n// ── Internal Helpers ───────────────────────────────────────\n\n/** BFS from root, returns names in top-down order. Cycle-safe. */\nfunction collectTree(root: string, childrenMap: Map<string, string[]>): string[] {\n const order: string[] = [];\n const seen = new Set<string>();\n const queue = [root];\n while (queue.length > 0) {\n const name = queue.shift()!;\n if (seen.has(name)) continue;\n seen.add(name);\n order.push(name);\n for (const child of (childrenMap.get(name) || [])) {\n queue.push(child);\n }\n }\n return order;\n}\n\n/** Classify merge pattern based on tree shape */\nfunction detectPattern(root: string, childrenMap: Map<string, string[]>): 'deep' | 'wide' | 'hybrid' {\n const rootChildren = childrenMap.get(root) || [];\n if (rootChildren.length <= 1) {\n return 'deep';\n }\n for (const child of rootChildren) {\n if ((childrenMap.get(child) || []).length > 0) {\n return 'hybrid';\n }\n }\n return 'wide';\n}\n\n/** Merge incoming requirement fields onto existing */\nfunction mergeRequirement(\n existing: EvaluatedRequirement,\n incoming: EvaluatedRequirement\n): EvaluatedRequirement {\n const result: EvaluatedRequirement = { ...existing };\n\n // Impact: incoming always wins (required field, always present)\n result.impact = incoming.impact;\n\n // Results: keep whichever is non-empty (base has them, overlay doesn't)\n if (incoming.results && incoming.results.length > 0) {\n result.results = incoming.results;\n }\n\n // Code: incoming wins if non-empty\n if (incoming.code && incoming.code.trim() !== '') {\n result.code = incoming.code;\n }\n\n // Tags: shallow merge (incoming keys override)\n if (incoming.tags) {\n result.tags = { ...existing.tags, ...incoming.tags };\n }\n\n // Severity: incoming wins if present, else keep existing\n if (incoming.severity !== undefined) {\n result.severity = incoming.severity;\n }\n\n // EffectiveStatus: incoming wins only if it has results (otherwise its\n // effectiveStatus is a computed artifact from empty results, not intentional).\n // Overlays typically have empty results — the base has the real test results.\n if (incoming.effectiveStatus !== undefined && incoming.results && incoming.results.length > 0) {\n result.effectiveStatus = incoming.effectiveStatus;\n }\n\n // Descriptions: merge by label (incoming overrides same label)\n if (incoming.descriptions && incoming.descriptions.length > 0) {\n const descMap = new Map(\n (existing.descriptions || []).map(d => [d.label, d])\n );\n for (const d of incoming.descriptions) {\n descMap.set(d.label, d);\n }\n result.descriptions = [...descMap.values()];\n }\n\n return result;\n}\n\n/**\n * Resolve parentBaseline for a baseline.\n * InSpec parent_profile can use depends-name aliases (e.g., 'k8s' instead of\n * 'k8s-node-stig-baseline'). When the value isn't a direct profile name,\n * find who depends on this baseline — that's the actual parent.\n */\nfunction resolveParentBaseline(\n b: EvaluatedBaseline,\n byName: Map<string, EvaluatedBaseline>,\n allBaselines: EvaluatedBaseline[]\n): string | undefined {\n if (!b.parentBaseline) return undefined;\n if (byName.has(b.parentBaseline)) return b.parentBaseline;\n\n // Alias resolution: find the profile whose depends array includes this baseline\n for (const candidate of allBaselines) {\n if (candidate.depends?.some((d) => d.name === b.name)) {\n return candidate.name;\n }\n }\n return undefined; // orphan\n}\n\n// ── Public API ──────────────────────────────────────────────\n\n/**\n * Flatten overlay/wrapper baselines in an HDF Results document.\n *\n * Handles:\n * - Deep nesting (overlay chains with shared control IDs via parentBaseline)\n * - Wide nesting (wrapper profiles aggregating independent bases)\n * - Hybrid (both patterns in one document)\n *\n * @param results - Parsed HDF Results (from parseResults() or equivalent)\n * @returns FlattenResult with flattened data and merge metadata\n */\nexport function flattenOverlays(results: HDFResults): FlattenResult {\n const { baselines } = results;\n const warnings: string[] = [];\n const merges: BaselineMerge[] = [];\n\n if (!baselines || baselines.length === 0) {\n return {\n results: { ...results, baselines: [] },\n metadata: {\n originalBaselineCount: 0,\n flattenedBaselineCount: 0,\n merges: [],\n warnings: [],\n },\n };\n }\n\n // Index baselines by name\n const byName = new Map<string, EvaluatedBaseline>();\n for (const b of baselines) {\n if (byName.has(b.name)) {\n warnings.push(`Duplicate baseline name \"${b.name}\" — later entry overwrites earlier`);\n }\n byName.set(b.name, b);\n }\n\n // Resolve parentBaseline aliases and build parent map\n const resolvedParent = new Map<string, string | undefined>();\n for (const b of baselines) {\n const parent = resolveParentBaseline(b, byName, baselines);\n resolvedParent.set(b.name, parent);\n if (b.parentBaseline && !parent) {\n warnings.push(\n `Baseline \"${b.name}\" references nonexistent parent \"${b.parentBaseline}\"`\n );\n }\n }\n\n // Build parent → children adjacency using resolved parents\n const childrenMap = new Map<string, string[]>();\n for (const b of baselines) {\n const parent = resolvedParent.get(b.name);\n if (parent) {\n const list = childrenMap.get(parent) || [];\n list.push(b.name);\n childrenMap.set(parent, list);\n }\n }\n\n // Find roots: no resolved parent\n const roots: string[] = [];\n const visited = new Set<string>();\n\n for (const b of baselines) {\n if (!resolvedParent.get(b.name)) {\n roots.push(b.name);\n }\n }\n\n // Mark reachable from roots (iterative DFS to avoid stack overflow on deep trees)\n function markReachable(start: string): void {\n const stack = [start];\n while (stack.length > 0) {\n const name = stack.pop()!;\n if (visited.has(name)) continue;\n visited.add(name);\n const children = childrenMap.get(name);\n if (children) {\n for (const child of children) {\n stack.push(child);\n }\n }\n }\n }\n for (const r of roots) {\n markReachable(r);\n }\n\n // Detect cycles: unvisited baselines are in cycles\n for (const b of baselines) {\n if (!visited.has(b.name)) {\n warnings.push(`Circular parentBaseline detected involving \"${b.name}\"`);\n roots.push(b.name);\n markReachable(b.name);\n }\n }\n\n // Process each root tree\n const flatBaselines: EvaluatedBaseline[] = [];\n\n for (const rootName of roots) {\n const root = byName.get(rootName)!;\n const treeNames = collectTree(rootName, childrenMap);\n\n if (treeNames.length === 1) {\n // Standalone baseline — pass through unchanged (preserve depends)\n flatBaselines.push(root);\n continue;\n }\n\n // Bottom-up order: reverse top-down BFS\n const bottomUp = [...treeNames].reverse();\n\n // Merge requirements across the tree\n const merged = new Map<string, EvaluatedRequirement>();\n let controlsBefore = 0;\n const absorbed: string[] = [];\n\n for (const name of bottomUp) {\n const b = byName.get(name)!;\n controlsBefore += b.requirements.length;\n if (name !== rootName) {\n absorbed.push(name);\n }\n for (const req of b.requirements) {\n if (merged.has(req.id)) {\n merged.set(req.id, mergeRequirement(merged.get(req.id)!, req));\n } else {\n merged.set(req.id, { ...req });\n }\n }\n }\n\n const mergedReqs = [...merged.values()];\n const pattern = detectPattern(rootName, childrenMap);\n\n merges.push({\n rootBaseline: rootName,\n absorbedBaselines: absorbed,\n controlsBefore,\n controlsAfter: mergedReqs.length,\n pattern,\n });\n\n const out: EvaluatedBaseline = {\n ...root,\n requirements: mergedReqs,\n };\n delete out.parentBaseline;\n delete out.depends;\n flatBaselines.push(out);\n }\n\n return {\n results: { ...results, baselines: flatBaselines },\n metadata: {\n originalBaselineCount: baselines.length,\n flattenedBaselineCount: flatBaselines.length,\n merges,\n warnings,\n },\n };\n}\n","import type {\n HDFResults,\n HDFBaseline,\n HDFSystem,\n HDFPlan,\n HDFEvidencePackage,\n HDFComparison,\n} from '@mitre/hdf-schema';\nexport { flattenOverlays } from './flatten.js';\nexport type { FlattenResult, FlattenMetadata, BaselineMerge } from './flatten.js';\nimport {\n validateResults,\n validateBaseline,\n validateSystem,\n validatePlan,\n validateEvidencePackage,\n validateComparison,\n validate as autoValidate,\n} from '@mitre/hdf-validators';\n\n// JSON-quoted ISO 8601 timestamp with no trailing timezone — InSpec emits\n// these (e.g. \"2026-03-25T22:56:27.736808\"). ajv-formats requires RFC 3339\n// for `date-time` and rejects them.\nconst NO_TZ_TIMESTAMP_REGEX = /\"(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?)\"/g;\n\n/**\n * Append Z (treat as UTC) to bare ISO timestamps in a JSON string so they\n * pass schema validation. Exported so other workspace packages can use the\n * same regex instead of re-implementing it. Matches the Go side at\n * hdf-parsers/go/parsers.go.\n */\nexport function normalizeTimestamps(input: string): string {\n return input.replace(NO_TZ_TIMESTAMP_REGEX, '\"$1Z\"');\n}\n\n/**\n * Result of parsing operation\n */\nexport interface ParseResult<T> {\n success: boolean;\n data?: T;\n error?: string;\n type?: 'results' | 'baseline' | 'system' | 'plan' | 'evidencePackage' | 'comparison';\n}\n\n/**\n * Parse HDF Results document from string or bytes\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data or error\n */\nexport function parseResults(input: string | Uint8Array): ParseResult<HDFResults> {\n // Convert Uint8Array to string if needed\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // JSON.parse already rejects trailing garbage (it throws on the first\n // non-whitespace byte after the root value), so the catch above covers\n // that case. A prior length-compare heuristic here false-positived on\n // complex real-world inputs (e.g. `0.70` parsed as `0.7` would re-\n // serialize to a different length) — caught by the cross-language\n // parser parity test in typescript/parse-equivalence.test.ts.\n\n // Validate against schema\n const validationResult = validateResults(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n return {\n success: true,\n data: data as HDFResults\n };\n}\n\n/**\n * Parse HDF Baseline document from string or bytes\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data or error\n */\nexport function parseBaseline(input: string | Uint8Array): ParseResult<HDFBaseline> {\n // Convert Uint8Array to string if needed\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Trailing garbage already caught by the JSON.parse catch above; see\n // parseResults for the full rationale.\n\n // Validate against schema\n const validationResult = validateBaseline(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n return {\n success: true,\n data: data as HDFBaseline\n };\n}\n\n/**\n * Parse HDF System document from string or bytes\n */\nexport function parseSystem(input: string | Uint8Array): ParseResult<HDFSystem> {\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n if (jsonStr.trim().length === 0) {\n return { success: false, error: 'Input is empty' };\n }\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return { success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n const validationResult = validateSystem(data);\n if (!validationResult.valid) {\n return { success: false, error: `Schema validation failed: ${validationResult.getErrorMessage()}` };\n }\n return { success: true, data: data as HDFSystem };\n}\n\n/**\n * Parse HDF Plan document from string or bytes\n */\nexport function parsePlan(input: string | Uint8Array): ParseResult<HDFPlan> {\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n if (jsonStr.trim().length === 0) {\n return { success: false, error: 'Input is empty' };\n }\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return { success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n const validationResult = validatePlan(data);\n if (!validationResult.valid) {\n return { success: false, error: `Schema validation failed: ${validationResult.getErrorMessage()}` };\n }\n return { success: true, data: data as HDFPlan };\n}\n\n/**\n * Parse HDF Evidence Package document from string or bytes\n */\nexport function parseEvidencePackage(input: string | Uint8Array): ParseResult<HDFEvidencePackage> {\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n if (jsonStr.trim().length === 0) {\n return { success: false, error: 'Input is empty' };\n }\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return { success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n const validationResult = validateEvidencePackage(data);\n if (!validationResult.valid) {\n return { success: false, error: `Schema validation failed: ${validationResult.getErrorMessage()}` };\n }\n return { success: true, data: data as HDFEvidencePackage };\n}\n\n/**\n * Parse HDF Comparison document from string or bytes\n */\nexport function parseComparison(input: string | Uint8Array): ParseResult<HDFComparison> {\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n if (jsonStr.trim().length === 0) {\n return { success: false, error: 'Input is empty' };\n }\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return { success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n const validationResult = validateComparison(data);\n if (!validationResult.valid) {\n return { success: false, error: `Schema validation failed: ${validationResult.getErrorMessage()}` };\n }\n return { success: true, data: data as HDFComparison };\n}\n\n/**\n * Parse HDF document with auto-detection of type\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data, type indicator, or error\n */\nexport function parse(\n input: string | Uint8Array,\n): ParseResult<HDFResults | HDFBaseline | HDFSystem | HDFPlan | HDFEvidencePackage | HDFComparison> {\n // Convert Uint8Array to string if needed\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Trailing garbage already caught by the JSON.parse catch above; see\n // parseResults for the full rationale.\n\n // Auto-validate and detect type\n const validationResult = autoValidate(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n // Determine type based on structure\n if (typeof data === 'object' && data !== null) {\n const obj = data as Record<string, unknown>;\n\n // HDF Results has 'baselines' array at root\n if ('baselines' in obj) {\n return {\n success: true,\n data: data as HDFResults,\n type: 'results'\n };\n }\n\n // HDF Comparison has 'requirementDiffs' at root (unique discriminator)\n if ('requirementDiffs' in obj) {\n return { success: true, data: data as HDFComparison, type: 'comparison' };\n }\n\n // HDF Plan has 'assessments' at root\n if ('assessments' in obj) {\n return { success: true, data: data as HDFPlan, type: 'plan' };\n }\n\n // HDF Evidence Package has 'contents' at root\n if ('contents' in obj) {\n return { success: true, data: data as HDFEvidencePackage, type: 'evidencePackage' };\n }\n\n // HDF Baseline has 'name' and 'requirements' at root\n if ('name' in obj && 'requirements' in obj) {\n return {\n success: true,\n data: data as HDFBaseline,\n type: 'baseline'\n };\n }\n\n // HDF System has 'components' at root (Results' baselines check already ruled out)\n if ('components' in obj) {\n return { success: true, data: data as HDFSystem, type: 'system' };\n }\n }\n\n return {\n success: false,\n error: 'Unable to determine HDF document type'\n };\n}\n\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mitre/hdf-parsers",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Parse and load HDF documents with validation",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"author": "MITRE Corporation",
|
|
26
26
|
"license": "Apache-2.0",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@mitre/hdf-
|
|
29
|
-
"@mitre/hdf-
|
|
28
|
+
"@mitre/hdf-schema": "^3.3.0",
|
|
29
|
+
"@mitre/hdf-validators": "^3.3.0"
|
|
30
30
|
},
|
|
31
31
|
"engines": {
|
|
32
32
|
"node": ">=22.0.0"
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
],
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@stryker-mutator/core": "^9.5.1",
|
|
42
|
-
"@stryker-mutator/vitest-runner": "^9.5.1"
|
|
42
|
+
"@stryker-mutator/vitest-runner": "^9.5.1",
|
|
43
|
+
"@mitre/hdf-fixtures": "^3.3.0"
|
|
43
44
|
},
|
|
44
45
|
"scripts": {
|
|
45
46
|
"build": "tsdown",
|