@mitre/hdf-converters 3.1.0 → 3.2.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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { n as detectConverter, t as registerAllFingerprints } from "./register-all-DaYHszLd.js";
1
+ import { n as detectConverter, t as registerAllFingerprints } from "./register-all-ik8sNfNf.js";
2
2
  import { flattenOverlays } from "@mitre/hdf-parsers";
3
3
  import { buildCsv, buildXml, parseCsv, parseJSON, parseXml, parseXmlWithArrays, sha256, stripHtml as stripHTML } from "@mitre/hdf-utilities";
4
- import { AuthorizationStatus, BoundaryDescription, CategorizationLevel, Copyright, HashAlgorithm, OverrideType, PlanType, ResultStatus, createDescription, createMinimalBaseline, createRequirement, createResult, severityToImpact } from "@mitre/hdf-schema";
4
+ import { Applicability, AuthorizationStatus, BoundaryDescription, CategorizationLevel, ControlType, Copyright, HashAlgorithm, OverrideType, PlanType, ResultStatus, VerificationMethodEnum, VerificationMethodEnum as VerificationMethodEnum$1, createDescription, createMinimalBaseline, createRequirement, createResult, severityToImpact } from "@mitre/hdf-schema";
5
5
  import { DEFAULT_COMPONENT_MANAGEMENT_NIST_TAGS, DEFAULT_REMEDIATION_NIST_TAGS, DEFAULT_STATIC_ANALYSIS_NIST_TAGS, DEFAULT_STATIC_ANALYSIS_NIST_TAGS as DEFAULT_STATIC_ANALYSIS_NIST_TAGS$1, getAwsConfigNistControlByIdentifier, getAwsConfigNistControlByName, getCCINistMappings, getCweNistControl, getNessusNistControl, getNiktoNistControl, getOwaspNistControl, getScoutsuiteNistControl, nistToCci } from "@mitre/hdf-mappings";
6
6
  //#region shared/typescript/converterutil.ts
7
7
  /**
@@ -202,6 +202,139 @@ function buildHdfResults(opts) {
202
202
  if (opts.statistics) hdf.statistics = opts.statistics;
203
203
  return JSON.stringify(hdf, null, 2);
204
204
  }
205
+ /**
206
+ * Captures a NIST 800-53 control identifier and its base sub-control number,
207
+ * ignoring enhancement suffixes like "(1)" or ".1". Mirrors the Go pattern
208
+ * in shared/go/converterutil.go.
209
+ */
210
+ const NIST_TAG_PATTERN = /^([A-Z]{2})-(\d+)/;
211
+ /**
212
+ * Maps each recognized NIST 800-53 Rev 5 family to its HDF controlType per
213
+ * SP 800-53 Appendix C / SP 800-53A classification. Unknown families resolve
214
+ * to undefined.
215
+ */
216
+ const NIST_FAMILY_CONTROL_TYPE = {
217
+ AC: ControlType.Technical,
218
+ AT: ControlType.Operational,
219
+ AU: ControlType.Operational,
220
+ CA: ControlType.Management,
221
+ CM: ControlType.Operational,
222
+ CP: ControlType.Operational,
223
+ IA: ControlType.Technical,
224
+ IR: ControlType.Operational,
225
+ MA: ControlType.Operational,
226
+ MP: ControlType.Operational,
227
+ PE: ControlType.Operational,
228
+ PL: ControlType.Management,
229
+ PM: ControlType.Management,
230
+ PS: ControlType.Operational,
231
+ PT: ControlType.Operational,
232
+ RA: ControlType.Management,
233
+ SA: ControlType.Management,
234
+ SC: ControlType.Technical,
235
+ SI: ControlType.Technical,
236
+ SR: ControlType.Management
237
+ };
238
+ /**
239
+ * Derive the HDF `controlType` for a single NIST 800-53 control identifier
240
+ * using a family-prefix heuristic. Returns undefined when the family is
241
+ * unrecognized or the tag is not a NIST control identifier.
242
+ *
243
+ * Heuristic, per NIST SP 800-53 Rev 5 Appendix C and SP 800-53A:
244
+ * - Management: PM, RA, CA, PL, SA, SR families
245
+ * - Operational: AT, AU, CM, CP, IR, MA, MP, PE, PS, PT families
246
+ * - Technical: AC, IA, SC, SI families
247
+ * - Policy: any "-1" sub-control (the per-family policy/procedure
248
+ * document, regardless of which family it belongs to). Enhancements of
249
+ * -1 controls (e.g., AC-1(1)) also resolve to policy.
250
+ *
251
+ * The "-1" rule takes precedence over the family rule because the per-family
252
+ * policy/procedure document is more usefully classified by its document
253
+ * nature than by the family it documents.
254
+ *
255
+ * @example
256
+ * deriveControlType("AC-3") // ControlType.Technical
257
+ * deriveControlType("AC-1") // ControlType.Policy (any *-1 is policy)
258
+ * deriveControlType("AC-3(1)") // ControlType.Technical (enhancement of AC-3)
259
+ * deriveControlType("PM-2") // ControlType.Management
260
+ * deriveControlType("SV-238196") // undefined (not a NIST tag)
261
+ */
262
+ function deriveControlType(nistTag) {
263
+ const match = NIST_TAG_PATTERN.exec(nistTag.trim().toUpperCase());
264
+ if (!match || match[1] === void 0 || match[2] === void 0) return void 0;
265
+ const family = match[1];
266
+ const subControl = match[2];
267
+ const familyClass = NIST_FAMILY_CONTROL_TYPE[family];
268
+ if (familyClass === void 0) return void 0;
269
+ if (subControl === "1") return ControlType.Policy;
270
+ return familyClass;
271
+ }
272
+ /**
273
+ * NIST tag sets this package uses as per-converter static fallbacks when no
274
+ * real per-finding mapping is available. When deriveControlTypeFromTags sees
275
+ * an input that exactly matches one of these bundles, it returns undefined —
276
+ * the input carries no real per-finding signal, and stamping every
277
+ * requirement with the same derived controlType is misleading.
278
+ *
279
+ * Keep in sync with DEFAULT_STATIC_ANALYSIS_NIST_TAGS, DEFAULT_REMEDIATION_NIST_TAGS.
280
+ */
281
+ const NIST_FALLBACK_BUNDLES = [
282
+ ["RA-5", "SA-11"],
283
+ ["RA-5", "SI-2"],
284
+ ["CM-8"]
285
+ ];
286
+ function tagsMatchFallback(tags) {
287
+ if (tags.length === 0) return false;
288
+ const sorted = [...new Set(tags)].sort();
289
+ return NIST_FALLBACK_BUNDLES.some((bundle) => bundle.length === sorted.length && bundle.every((b, i) => b === sorted[i]));
290
+ }
291
+ /**
292
+ * Derive the HDF `controlType` for a slice of NIST tags. Resolves each tag
293
+ * via {@link deriveControlType}, then picks the most-specific class by
294
+ * precedence: technical > operational > management > policy > procedure.
295
+ * The rationale is that a control enforced via configuration (technical)
296
+ * is more actionable than the same control's management/policy framing.
297
+ *
298
+ * Returns undefined when no tag resolves to a known classification, OR when
299
+ * the input exactly matches a converter-level static-fallback bundle (e.g.
300
+ * the DEFAULT_STATIC_ANALYSIS_NIST_TAGS set). The fallback gate prevents
301
+ * converters that have no per-finding NIST signal from stamping every
302
+ * requirement with the same misleading controlType.
303
+ */
304
+ function deriveControlTypeFromTags(tags) {
305
+ if (tagsMatchFallback(tags)) return void 0;
306
+ const rank = {
307
+ [ControlType.Technical]: 0,
308
+ [ControlType.Operational]: 1,
309
+ [ControlType.Management]: 2,
310
+ [ControlType.Policy]: 3,
311
+ [ControlType.Procedure]: 4
312
+ };
313
+ let best;
314
+ let bestRank = Number.POSITIVE_INFINITY;
315
+ for (const tag of tags) {
316
+ const ct = deriveControlType(tag);
317
+ if (ct === void 0) continue;
318
+ const r = rank[ct];
319
+ if (r < bestRank) {
320
+ bestRank = r;
321
+ best = ct;
322
+ }
323
+ }
324
+ return best;
325
+ }
326
+ /**
327
+ * Derive the HDF `verificationMethod` for a requirement based on whether
328
+ * check code is present. Returns `automated` when code is non-empty (a check
329
+ * exists and runs without operator action), and undefined otherwise — the
330
+ * converter is responsible for distinguishing manual-by-design (statement-form,
331
+ * e.g. FedRAMP 20x KSI) from manual-pending-automation (a check that could
332
+ * be automated but isn't yet) when it has the source-format context to do so.
333
+ */
334
+ function deriveVerificationMethod(code) {
335
+ if (code === void 0 || code === null || code === "") return void 0;
336
+ return VerificationMethodEnum$1.Automated;
337
+ }
205
338
  //#endregion
206
339
  //#region converters/legacyhdf-to-hdf/typescript/converter.ts
207
340
  /**
@@ -341,6 +474,11 @@ function convertControl(v1Control) {
341
474
  if (v1Control.results && Array.isArray(v1Control.results)) v2Req.results = v1Control.results.map(convertResult);
342
475
  if (!v2Req.effectiveStatus) v2Req.effectiveStatus = computeEffectiveStatus(v1Control.impact, v2Req.results ?? []);
343
476
  v2Req.severity = tagSeverityToSeverity(v1Control.tags?.severity) ?? impactToSeverity$2(v1Control.impact);
477
+ const rawNist = v1Control.tags?.nist;
478
+ if (Array.isArray(rawNist)) {
479
+ const controlType = deriveControlTypeFromTags(rawNist.filter((v) => typeof v === "string"));
480
+ if (controlType !== void 0) v2Req.controlType = controlType;
481
+ }
344
482
  const knownFields = new Set([
345
483
  "id",
346
484
  "title",
@@ -605,7 +743,11 @@ function convertResultGroup(ruleId, rule, sarifResults) {
605
743
  const descriptions = buildDescriptions$1(description, rule, firstResult);
606
744
  const options = { tags: buildTags$3(firstResult, rule, ruleLevel, cweIds, nistControls, cciControls) };
607
745
  if (sourceLocation) options.sourceLocation = sourceLocation;
608
- return createRequirement(ruleId, title, descriptions, impact, results, options);
746
+ const req = createRequirement(ruleId, title, descriptions, impact, results, options);
747
+ const controlType = deriveControlTypeFromTags(nistControls);
748
+ if (controlType !== void 0) req.controlType = controlType;
749
+ req.verificationMethod = VerificationMethodEnum.Automated;
750
+ return req;
609
751
  }
610
752
  function resolveRuleLevel(rule, results) {
611
753
  if (rule?.defaultConfiguration?.level) return rule.defaultConfiguration.level;
@@ -810,8 +952,8 @@ function createHDFResult(location, status, backtrace, suppressionMessage) {
810
952
  //#endregion
811
953
  //#region converters/junit-to-hdf/typescript/converter.ts
812
954
  const DEFAULT_NIST = ["SA-11"];
813
- const CONVERTER_VERSION$1 = "1.0.0";
814
- const ARRAY_TAGS$1 = ["testsuite", "testcase"];
955
+ const CONVERTER_VERSION$2 = "1.0.0";
956
+ const ARRAY_TAGS$2 = ["testsuite", "testcase"];
815
957
  /**
816
958
  * Converts JUnit XML test results to HDF format.
817
959
  */
@@ -821,7 +963,7 @@ async function convertJunitToHdf(input) {
821
963
  const { suites, name } = parseJUnitXML(input);
822
964
  return buildHdfResults({
823
965
  generatorName: "hdf-converters",
824
- converterVersion: CONVERTER_VERSION$1,
966
+ converterVersion: CONVERTER_VERSION$2,
825
967
  toolName: "JUnit XML",
826
968
  toolFormat: "XML",
827
969
  baselines: [createMinimalBaseline(name, buildRequirements(suites), { resultsChecksum: await inputChecksum(input) })],
@@ -833,7 +975,7 @@ async function convertJunitToHdf(input) {
833
975
  });
834
976
  }
835
977
  function parseJUnitXML(input) {
836
- const parsed = parseXmlWithArrays(input, ARRAY_TAGS$1);
978
+ const parsed = parseXmlWithArrays(input, ARRAY_TAGS$2);
837
979
  if (parsed.testsuites) return {
838
980
  suites: parsed.testsuites.testsuite ?? [],
839
981
  name: parsed.testsuites.name || "JUnit Test Results"
@@ -876,7 +1018,11 @@ function testCaseToRequirement(tc, suiteTimestamp) {
876
1018
  label: "default",
877
1019
  data: `JUnit test: ${tc.name} in ${tc.classname || "unknown"}`
878
1020
  }];
879
- return createRequirement(id, tc.name, descriptions, .5, [result], { tags: { nist: DEFAULT_NIST } });
1021
+ const req = createRequirement(id, tc.name, descriptions, .5, [result], { tags: { nist: DEFAULT_NIST } });
1022
+ const controlType = deriveControlTypeFromTags(DEFAULT_NIST);
1023
+ if (controlType !== void 0) req.controlType = controlType;
1024
+ req.verificationMethod = VerificationMethodEnum.Automated;
1025
+ return req;
880
1026
  }
881
1027
  function buildID(tc) {
882
1028
  if (tc.classname) return `${tc.classname}.${tc.name}`;
@@ -923,10 +1069,10 @@ function buildCodeDesc$9(tc) {
923
1069
  }
924
1070
  //#endregion
925
1071
  //#region converters/xccdf-results-to-hdf/typescript/converter.ts
926
- const CONVERTER_VERSION = "1.0.0";
1072
+ const CONVERTER_VERSION$1 = "1.0.0";
927
1073
  const CCI_SYSTEM = "http://cyber.mil/cci";
928
1074
  /** Tags that must always be parsed as arrays even if only one element exists. */
929
- const ARRAY_TAGS = [
1075
+ const ARRAY_TAGS$1 = [
930
1076
  "Group",
931
1077
  "Rule",
932
1078
  "Profile",
@@ -969,7 +1115,7 @@ const STATUS_MAP = {
969
1115
  async function convertXccdfResultsToHdf(input) {
970
1116
  if (!input || !input.trim()) throw new Error("Empty input");
971
1117
  validateInputSize(input, "xccdf-results");
972
- const parsed = parseXmlWithArrays(input, ARRAY_TAGS);
1118
+ const parsed = parseXmlWithArrays(input, ARRAY_TAGS$1);
973
1119
  const arfParsed = parsed;
974
1120
  if (arfParsed["asset-report-collection"]) return convertArfCollection(arfParsed["asset-report-collection"], input);
975
1121
  const benchmark = parsed.Benchmark;
@@ -999,7 +1145,7 @@ async function convertBenchmarkResultsToHdf(benchmark, rawInput) {
999
1145
  baselines: [baseline],
1000
1146
  generator: {
1001
1147
  name: "hdf-converters",
1002
- version: CONVERTER_VERSION
1148
+ version: CONVERTER_VERSION$1
1003
1149
  },
1004
1150
  tool: {
1005
1151
  name: "XCCDF Results",
@@ -1058,7 +1204,7 @@ async function convertArfCollection(arc, rawInput) {
1058
1204
  baselines,
1059
1205
  generator: {
1060
1206
  name: "hdf-converters",
1061
- version: CONVERTER_VERSION
1207
+ version: CONVERTER_VERSION$1
1062
1208
  },
1063
1209
  tool: {
1064
1210
  name: "ARF",
@@ -1144,13 +1290,17 @@ function ruleResultToRequirement(rr, ruleIndex) {
1144
1290
  });
1145
1291
  const result = createResult(STATUS_MAP[(rr.result ?? "").toLowerCase()] ?? ResultStatus.NotReviewed, "", { codeDesc: `XCCDF rule ${id}` });
1146
1292
  const tags = {};
1293
+ let nistTags = [];
1147
1294
  const cciIds = extractCCIs(rr.ident ?? ruleDef?.ident ?? []);
1148
1295
  if (cciIds.length > 0) {
1149
1296
  tags["cci"] = cciIds;
1150
- const nistTags = cciIds.flatMap((cci) => getCCINistMappings(cci) ?? []);
1151
- if (nistTags.length > 0) tags["nist"] = [...new Set(nistTags)];
1297
+ nistTags = [...new Set(cciIds.flatMap((cci) => getCCINistMappings(cci) ?? []))];
1298
+ if (nistTags.length > 0) tags["nist"] = nistTags;
1152
1299
  }
1153
- return createRequirement(id, title, descriptions, impact, [result], { tags });
1300
+ const req = createRequirement(id, title, descriptions, impact, [result], { tags });
1301
+ const controlType = deriveControlTypeFromTags(nistTags);
1302
+ if (controlType !== void 0) req.controlType = controlType;
1303
+ return req;
1154
1304
  }
1155
1305
  /**
1156
1306
  * Build Component array from TestResult metadata.
@@ -1210,6 +1360,713 @@ function extractCCIs(idents) {
1210
1360
  return idents.filter((i) => i.system === CCI_SYSTEM).map((i) => i["#text"] ?? "").filter((v) => v.length > 0);
1211
1361
  }
1212
1362
  //#endregion
1363
+ //#region shared/typescript/checklist/status.ts
1364
+ function normalizeKey(s) {
1365
+ return s.toLowerCase().trim().split("_").join("").split(" ").join("");
1366
+ }
1367
+ const STATUS_BY_KEY = {
1368
+ open: "Open",
1369
+ notafinding: "NotAFinding",
1370
+ notreviewed: "Not_Reviewed",
1371
+ notapplicable: "Not_Applicable"
1372
+ };
1373
+ /** Map any CKL/CKLB status spelling to the canonical CheckStatus. */
1374
+ function parseStatus(s) {
1375
+ return STATUS_BY_KEY[normalizeKey(s ?? "")] ?? "Not_Reviewed";
1376
+ }
1377
+ /** CKL (XML) spelling. */
1378
+ function statusToCkl(s) {
1379
+ return s || "Not_Reviewed";
1380
+ }
1381
+ /** CKLB (JSON) snake_case spelling. */
1382
+ function statusToCklb(s) {
1383
+ switch (s) {
1384
+ case "Open": return "open";
1385
+ case "NotAFinding": return "not_a_finding";
1386
+ case "Not_Applicable": return "not_applicable";
1387
+ default: return "not_reviewed";
1388
+ }
1389
+ }
1390
+ /** Canonical status -> HDF Result_Status. */
1391
+ function statusToHdf(s) {
1392
+ switch (s) {
1393
+ case "Open": return ResultStatus.Failed;
1394
+ case "NotAFinding": return ResultStatus.Passed;
1395
+ case "Not_Applicable": return ResultStatus.NotApplicable;
1396
+ default: return ResultStatus.NotReviewed;
1397
+ }
1398
+ }
1399
+ /** HDF Result_Status -> canonical status (error -> Open). */
1400
+ function statusFromHdf(s) {
1401
+ switch (s) {
1402
+ case ResultStatus.Passed: return "NotAFinding";
1403
+ case ResultStatus.Failed:
1404
+ case ResultStatus.Error: return "Open";
1405
+ case ResultStatus.NotApplicable: return "Not_Applicable";
1406
+ default: return "Not_Reviewed";
1407
+ }
1408
+ }
1409
+ //#endregion
1410
+ //#region shared/typescript/checklist/ckl.ts
1411
+ const ARRAY_TAGS = [
1412
+ "iSTIG",
1413
+ "VULN",
1414
+ "STIG_DATA",
1415
+ "SI_DATA"
1416
+ ];
1417
+ const BUILD_OPTIONS$1 = {
1418
+ attributeNamePrefix: "@_",
1419
+ textNodeName: "#text",
1420
+ ignoreAttributes: false,
1421
+ format: true,
1422
+ indentBy: " ",
1423
+ suppressEmptyNode: false
1424
+ };
1425
+ function str(v) {
1426
+ return v === void 0 || v === null ? "" : String(v);
1427
+ }
1428
+ const VULN_ATTR_ORDER = [
1429
+ "Vuln_Num",
1430
+ "Severity",
1431
+ "Group_Title",
1432
+ "Rule_ID",
1433
+ "Rule_Ver",
1434
+ "Rule_Title",
1435
+ "Vuln_Discuss",
1436
+ "IA_Controls",
1437
+ "Check_Content",
1438
+ "Fix_Text",
1439
+ "False_Positives",
1440
+ "False_Negatives",
1441
+ "Documentable",
1442
+ "Mitigations",
1443
+ "Potential_Impact",
1444
+ "Third_Party_Tools",
1445
+ "Mitigation_Control",
1446
+ "Responsibility",
1447
+ "Security_Override_Guidance",
1448
+ "Check_Content_Ref",
1449
+ "Weight",
1450
+ "Class",
1451
+ "STIG_UUID"
1452
+ ];
1453
+ const CORE_VULN_ATTR = new Set([
1454
+ "Vuln_Num",
1455
+ "Severity",
1456
+ "Group_Title",
1457
+ "Rule_ID",
1458
+ "Rule_Ver",
1459
+ "Rule_Title",
1460
+ "Vuln_Discuss",
1461
+ "Check_Content",
1462
+ "Fix_Text",
1463
+ "Weight",
1464
+ "Class"
1465
+ ]);
1466
+ /** Parse CKL XML into the format-neutral Checklist model. */
1467
+ function parseCkl(input) {
1468
+ const checklist = parseXmlWithArrays(input, ARRAY_TAGS, { processEntities: true }).CHECKLIST;
1469
+ const istigs = checklist?.STIGS?.iSTIG;
1470
+ if (!checklist || !istigs || istigs.length === 0) throw new Error("parse ckl: no <iSTIG> blocks found (not a CKL document?)");
1471
+ const a = checklist.ASSET ?? {};
1472
+ return {
1473
+ format: "ckl",
1474
+ asset: {
1475
+ role: str(a["ROLE"]),
1476
+ assetType: str(a["ASSET_TYPE"]),
1477
+ marking: str(a["MARKING"]),
1478
+ hostName: str(a["HOST_NAME"]),
1479
+ hostIP: str(a["HOST_IP"]),
1480
+ hostMAC: str(a["HOST_MAC"]),
1481
+ hostFQDN: str(a["HOST_FQDN"]),
1482
+ targetComment: str(a["TARGET_COMMENT"]),
1483
+ techArea: str(a["TECH_AREA"]),
1484
+ targetKey: str(a["TARGET_KEY"]),
1485
+ webOrDatabase: str(a["WEB_OR_DATABASE"]) === "true",
1486
+ webDBSite: str(a["WEB_DB_SITE"]),
1487
+ webDBInstance: str(a["WEB_DB_INSTANCE"])
1488
+ },
1489
+ stigs: istigs.map((is) => {
1490
+ const si = is.STIG_INFO?.SI_DATA ?? [];
1491
+ const siVal = (name) => str(si.find((d) => d.SID_NAME === name)?.SID_DATA);
1492
+ return {
1493
+ stigID: siVal("stigid"),
1494
+ title: siVal("title"),
1495
+ version: siVal("version"),
1496
+ releaseInfo: siVal("releaseinfo"),
1497
+ uuid: siVal("uuid"),
1498
+ classification: siVal("classification"),
1499
+ vulns: (is.VULN ?? []).map(cklVulnToModel)
1500
+ };
1501
+ })
1502
+ };
1503
+ }
1504
+ function cklVulnToModel(v) {
1505
+ const data = v.STIG_DATA ?? [];
1506
+ const attr = (name) => str(data.find((sd) => sd.VULN_ATTRIBUTE === name)?.ATTRIBUTE_DATA);
1507
+ const ccis = [];
1508
+ const extra = {};
1509
+ const promoted = new Set([
1510
+ "CCI_REF",
1511
+ "Vuln_Num",
1512
+ "Severity",
1513
+ "Group_Title",
1514
+ "Rule_ID",
1515
+ "Rule_Ver",
1516
+ "Rule_Title",
1517
+ "Vuln_Discuss",
1518
+ "Check_Content",
1519
+ "Fix_Text",
1520
+ "Weight",
1521
+ "Class"
1522
+ ]);
1523
+ for (const sd of data) {
1524
+ const name = sd.VULN_ATTRIBUTE ?? "";
1525
+ const val = str(sd.ATTRIBUTE_DATA);
1526
+ if (name === "CCI_REF") {
1527
+ if (val) ccis.push(val);
1528
+ } else if (!promoted.has(name) && val) extra[name] = val;
1529
+ }
1530
+ return {
1531
+ vulnNum: attr("Vuln_Num"),
1532
+ ruleID: attr("Rule_ID"),
1533
+ ruleVer: attr("Rule_Ver"),
1534
+ groupTitle: attr("Group_Title"),
1535
+ severity: attr("Severity"),
1536
+ ruleTitle: attr("Rule_Title"),
1537
+ vulnDiscuss: attr("Vuln_Discuss"),
1538
+ checkContent: attr("Check_Content"),
1539
+ fixText: attr("Fix_Text"),
1540
+ weight: attr("Weight"),
1541
+ classification: attr("Class"),
1542
+ ccis,
1543
+ status: parseStatus(v.STATUS),
1544
+ findingDetails: str(v.FINDING_DETAILS),
1545
+ comments: str(v.COMMENTS),
1546
+ extra
1547
+ };
1548
+ }
1549
+ /** Serialize the Checklist model to CKL XML (with declaration). */
1550
+ function serializeCkl(cl) {
1551
+ return `<?xml version="1.0" encoding="UTF-8"?>\n${buildXml({ CHECKLIST: {
1552
+ ASSET: {
1553
+ ROLE: cl.asset.role || "None",
1554
+ ASSET_TYPE: cl.asset.assetType || "Computing",
1555
+ HOST_NAME: cl.asset.hostName ?? "",
1556
+ HOST_IP: cl.asset.hostIP ?? "",
1557
+ HOST_MAC: cl.asset.hostMAC ?? "",
1558
+ HOST_FQDN: cl.asset.hostFQDN ?? "",
1559
+ TARGET_COMMENT: cl.asset.targetComment ?? "",
1560
+ TECH_AREA: cl.asset.techArea ?? "",
1561
+ TARGET_KEY: cl.asset.targetKey ?? "",
1562
+ WEB_OR_DATABASE: cl.asset.webOrDatabase ? "true" : "false",
1563
+ WEB_DB_SITE: cl.asset.webDBSite ?? "",
1564
+ WEB_DB_INSTANCE: cl.asset.webDBInstance ?? ""
1565
+ },
1566
+ STIGS: { iSTIG: cl.stigs.map((s) => ({
1567
+ STIG_INFO: { SI_DATA: stigInfoSiData(s) },
1568
+ VULN: s.vulns.map(modelVulnToCkl)
1569
+ })) }
1570
+ } }, BUILD_OPTIONS$1)}`;
1571
+ }
1572
+ function stigInfoSiData(s) {
1573
+ return [
1574
+ {
1575
+ name: "version",
1576
+ data: s.version
1577
+ },
1578
+ {
1579
+ name: "classification",
1580
+ data: s.classification
1581
+ },
1582
+ {
1583
+ name: "stigid",
1584
+ data: s.stigID
1585
+ },
1586
+ {
1587
+ name: "releaseinfo",
1588
+ data: s.releaseInfo
1589
+ },
1590
+ {
1591
+ name: "title",
1592
+ data: s.title
1593
+ },
1594
+ {
1595
+ name: "uuid",
1596
+ data: s.uuid
1597
+ }
1598
+ ].filter((p) => p.data).map((p) => ({
1599
+ SID_NAME: p.name,
1600
+ SID_DATA: p.data
1601
+ }));
1602
+ }
1603
+ function modelVulnToCkl(v) {
1604
+ const typed = {
1605
+ Vuln_Num: v.vulnNum,
1606
+ Severity: v.severity ?? "",
1607
+ Group_Title: v.groupTitle ?? "",
1608
+ Rule_ID: v.ruleID ?? "",
1609
+ Rule_Ver: v.ruleVer ?? "",
1610
+ Rule_Title: v.ruleTitle ?? "",
1611
+ Vuln_Discuss: v.vulnDiscuss ?? "",
1612
+ Check_Content: v.checkContent ?? "",
1613
+ Fix_Text: v.fixText ?? "",
1614
+ Weight: v.weight || "10.0",
1615
+ Class: v.classification || "Unclass"
1616
+ };
1617
+ const stigData = [];
1618
+ for (const name of VULN_ATTR_ORDER) {
1619
+ const val = typed[name] ?? v.extra?.[name] ?? "";
1620
+ if (!val && !CORE_VULN_ATTR.has(name)) continue;
1621
+ stigData.push({
1622
+ VULN_ATTRIBUTE: name,
1623
+ ATTRIBUTE_DATA: val
1624
+ });
1625
+ }
1626
+ for (const cci of v.ccis) stigData.push({
1627
+ VULN_ATTRIBUTE: "CCI_REF",
1628
+ ATTRIBUTE_DATA: cci
1629
+ });
1630
+ return {
1631
+ STIG_DATA: stigData,
1632
+ STATUS: statusToCkl(v.status),
1633
+ FINDING_DETAILS: v.findingDetails ?? "",
1634
+ COMMENTS: v.comments ?? ""
1635
+ };
1636
+ }
1637
+ //#endregion
1638
+ //#region shared/typescript/checklist/cklb.ts
1639
+ /** Parse CKLB JSON into the format-neutral Checklist model. */
1640
+ function parseCklb(input) {
1641
+ const doc = parseJSON(input);
1642
+ if (!doc || !Array.isArray(doc.stigs) || doc.stigs.length === 0) throw new Error("parse cklb: no stigs[] found (not a CKLB document?)");
1643
+ const t = doc.target_data ?? {};
1644
+ const asset = {
1645
+ role: nz(t.role),
1646
+ assetType: nz(t.target_type),
1647
+ hostName: nz(t.host_name),
1648
+ hostIP: nz(t.ip_address),
1649
+ hostMAC: nz(t.mac_address),
1650
+ hostFQDN: nz(t.fqdn),
1651
+ targetComment: nz(t.comments),
1652
+ webOrDatabase: t.is_web_database === true,
1653
+ webDBSite: nz(t.web_db_site),
1654
+ webDBInstance: nz(t.web_db_instance),
1655
+ techArea: nz(t.technology_area),
1656
+ classification: nz(t.classification)
1657
+ };
1658
+ const stigs = doc.stigs.map((s) => ({
1659
+ stigID: nz(s.stig_id),
1660
+ title: nz(s.stig_name) || nz(s.display_name),
1661
+ displayName: nz(s.display_name),
1662
+ version: nz(s.version),
1663
+ releaseInfo: nz(s.release_info),
1664
+ uuid: nz(s.uuid),
1665
+ referenceIdentifier: nz(s.reference_identifier),
1666
+ vulns: (s.rules ?? []).map(cklbRuleToModel)
1667
+ }));
1668
+ return {
1669
+ format: "cklb",
1670
+ cklbVersion: nz(doc.cklb_version),
1671
+ asset,
1672
+ stigs
1673
+ };
1674
+ }
1675
+ /** Coerce a possibly-null/non-string JSON value to string | undefined.
1676
+ * Real STIG Viewer CKLB output uses null for unset fields (e.g.
1677
+ * target_data.classification: null); the model expects string | undefined. */
1678
+ function nz(v) {
1679
+ return typeof v === "string" ? v : void 0;
1680
+ }
1681
+ function cklbRuleToModel(r) {
1682
+ const extra = {};
1683
+ if (r.third_party_tools) extra["Third_Party_Tools"] = r.third_party_tools;
1684
+ if (r.srg_id) extra["SRG_ID"] = r.srg_id;
1685
+ return {
1686
+ vulnNum: nz(r.group_id) ?? "",
1687
+ ruleID: nz(r.rule_id),
1688
+ ruleVer: nz(r.rule_version),
1689
+ groupID: nz(r.group_id),
1690
+ groupTitle: nz(r.group_title),
1691
+ severity: nz(r.severity),
1692
+ ruleTitle: nz(r.rule_title),
1693
+ vulnDiscuss: nz(r.discussion),
1694
+ checkContent: nz(r.check_content),
1695
+ fixText: nz(r.fix_text),
1696
+ weight: nz(r.weight),
1697
+ classification: nz(r.classification),
1698
+ ccis: Array.isArray(r.ccis) ? r.ccis.filter((c) => typeof c === "string") : [],
1699
+ legacyIDs: r.legacy_ids,
1700
+ status: parseStatus(r.status),
1701
+ findingDetails: nz(r.finding_details),
1702
+ comments: nz(r.comments),
1703
+ extra
1704
+ };
1705
+ }
1706
+ /** Serialize the Checklist model to CKLB JSON. */
1707
+ function serializeCklb(cl) {
1708
+ const doc = {
1709
+ title: cklbTitle(cl),
1710
+ cklb_version: cl.cklbVersion || "1.0",
1711
+ active: false,
1712
+ has_path: false,
1713
+ target_data: {
1714
+ target_type: cl.asset.assetType || "Computing",
1715
+ host_name: cl.asset.hostName ?? "",
1716
+ ip_address: cl.asset.hostIP ?? "",
1717
+ mac_address: cl.asset.hostMAC ?? "",
1718
+ fqdn: cl.asset.hostFQDN ?? "",
1719
+ comments: cl.asset.targetComment ?? "",
1720
+ role: cl.asset.role || "None",
1721
+ is_web_database: cl.asset.webOrDatabase ?? false,
1722
+ technology_area: cl.asset.techArea ?? "",
1723
+ web_db_site: cl.asset.webDBSite ?? "",
1724
+ web_db_instance: cl.asset.webDBInstance ?? "",
1725
+ ...cl.asset.classification ? { classification: cl.asset.classification } : {}
1726
+ },
1727
+ stigs: cl.stigs.map((s) => ({
1728
+ stig_name: s.title ?? "",
1729
+ display_name: s.displayName || s.title || "",
1730
+ stig_id: s.stigID ?? "",
1731
+ release_info: s.releaseInfo ?? "",
1732
+ version: s.version ?? "",
1733
+ uuid: s.uuid ?? "",
1734
+ ...s.referenceIdentifier ? { reference_identifier: s.referenceIdentifier } : {},
1735
+ rules: s.vulns.map((v) => ({
1736
+ group_id: v.groupID || v.vulnNum,
1737
+ group_title: v.groupTitle ?? "",
1738
+ rule_id: v.ruleID ?? "",
1739
+ rule_version: v.ruleVer ?? "",
1740
+ rule_title: v.ruleTitle ?? "",
1741
+ severity: v.severity ?? "",
1742
+ weight: v.weight || "10.0",
1743
+ check_content: v.checkContent ?? "",
1744
+ fix_text: v.fixText ?? "",
1745
+ discussion: v.vulnDiscuss ?? "",
1746
+ ccis: v.ccis,
1747
+ ...v.legacyIDs && v.legacyIDs.length ? { legacy_ids: v.legacyIDs } : {},
1748
+ status: statusToCklb(v.status),
1749
+ comments: v.comments ?? "",
1750
+ finding_details: v.findingDetails ?? "",
1751
+ ...v.extra?.["Third_Party_Tools"] ? { third_party_tools: v.extra["Third_Party_Tools"] } : {}
1752
+ }))
1753
+ }))
1754
+ };
1755
+ return JSON.stringify(doc, null, 2);
1756
+ }
1757
+ function cklbTitle(cl) {
1758
+ return cl.stigs[0]?.title || "STIG Checklist";
1759
+ }
1760
+ //#endregion
1761
+ //#region shared/typescript/checklist/to-hdf.ts
1762
+ const CONVERTER_VERSION = "1.0.0";
1763
+ /**
1764
+ * Map the format-neutral Checklist model to an HDF Results object.
1765
+ * controlType is derived per-Vuln from CCI->NIST; verificationMethod and
1766
+ * applicability are omitted (the checklist format cannot substantiate them).
1767
+ * Original-format metadata is stashed in extensions/tags for round-trip.
1768
+ */
1769
+ function checklistToHdf(cl, resultsChecksum) {
1770
+ const hdf = {
1771
+ baselines: cl.stigs.map((s) => stigToBaseline(s, resultsChecksum)),
1772
+ generator: {
1773
+ name: "hdf-converters",
1774
+ version: CONVERTER_VERSION
1775
+ },
1776
+ tool: {
1777
+ name: "DISA STIG Viewer",
1778
+ format: cl.format === "cklb" ? "CKLB" : "CKL"
1779
+ },
1780
+ timestamp: /* @__PURE__ */ new Date()
1781
+ };
1782
+ const component = assetToComponent(cl.asset);
1783
+ if (component) hdf.components = [component];
1784
+ const ext = rootExtensions(cl);
1785
+ if (Object.keys(ext).length > 0) hdf.extensions = ext;
1786
+ return hdf;
1787
+ }
1788
+ function stigToBaseline(s, resultsChecksum) {
1789
+ const baseline = createMinimalBaseline("STIG Checklist Scan", s.vulns.map(vulnToRequirement), { resultsChecksum });
1790
+ if (s.title) baseline.title = s.title;
1791
+ if (s.version) baseline.version = s.version;
1792
+ const ext = baselineExtensions(s);
1793
+ if (Object.keys(ext).length > 0) baseline.extensions = ext;
1794
+ return baseline;
1795
+ }
1796
+ function vulnToRequirement(v) {
1797
+ const severity = (v.severity ?? "").toLowerCase();
1798
+ const impact = severity ? severityToImpact(severity) : .5;
1799
+ const descriptions = [{
1800
+ label: "default",
1801
+ data: stripHTML(v.vulnDiscuss ?? "")
1802
+ }];
1803
+ if (v.checkContent) descriptions.push({
1804
+ label: "check",
1805
+ data: stripHTML(v.checkContent)
1806
+ });
1807
+ if (v.fixText) descriptions.push({
1808
+ label: "fix",
1809
+ data: stripHTML(v.fixText)
1810
+ });
1811
+ const message = [v.findingDetails, v.comments].map((s) => (s ?? "").trim()).filter(Boolean).join("\n\n");
1812
+ const result = createResult(statusToHdf(v.status), message, { codeDesc: `STIG rule ${v.ruleVer ?? ""}` });
1813
+ const tags = {};
1814
+ let nistTags = [];
1815
+ if (v.ccis.length > 0) {
1816
+ tags["cci"] = v.ccis;
1817
+ nistTags = [...new Set(v.ccis.flatMap((c) => getCCINistMappings(c) ?? []))].sort();
1818
+ tags["nist"] = nistTags;
1819
+ } else tags["nist"] = [];
1820
+ setIf(tags, "rid", v.ruleID);
1821
+ setIf(tags, "stig_id", v.ruleVer);
1822
+ setIf(tags, "gtitle", v.groupTitle);
1823
+ setIf(tags, "group_id", v.groupID);
1824
+ setIf(tags, "weight", v.weight);
1825
+ setIf(tags, "severity", severity);
1826
+ if (v.legacyIDs && v.legacyIDs.length) tags["legacy_ids"] = v.legacyIDs;
1827
+ if (v.extra && Object.keys(v.extra).length > 0) tags["cklMetadata"] = { ...v.extra };
1828
+ const req = createRequirement(v.vulnNum, v.ruleTitle ?? v.vulnNum, descriptions, impact, [result], { tags });
1829
+ if (severity) req.severity = severity;
1830
+ const controlType = deriveControlTypeFromTags(nistTags);
1831
+ if (controlType !== void 0) req.controlType = controlType;
1832
+ return req;
1833
+ }
1834
+ function assetToComponent(a) {
1835
+ if (!a.hostName && !a.hostIP && !a.hostFQDN) return void 0;
1836
+ const c = {
1837
+ name: a.hostName || a.hostFQDN || a.hostIP || "",
1838
+ type: Copyright.Host
1839
+ };
1840
+ if (a.hostIP) c.ipAddress = a.hostIP;
1841
+ if (a.hostFQDN) c.fqdn = a.hostFQDN;
1842
+ if (a.hostMAC) c.macAddress = a.hostMAC;
1843
+ return c;
1844
+ }
1845
+ function rootExtensions(cl) {
1846
+ const ext = { checklistFormat: cl.format || "ckl" };
1847
+ if (cl.cklbVersion) ext["cklbVersion"] = cl.cklbVersion;
1848
+ const ax = {};
1849
+ setIf(ax, "role", cl.asset.role);
1850
+ setIf(ax, "assetType", cl.asset.assetType);
1851
+ setIf(ax, "marking", cl.asset.marking);
1852
+ setIf(ax, "targetKey", cl.asset.targetKey);
1853
+ setIf(ax, "techArea", cl.asset.techArea);
1854
+ setIf(ax, "targetComment", cl.asset.targetComment);
1855
+ setIf(ax, "webDbSite", cl.asset.webDBSite);
1856
+ setIf(ax, "webDbInstance", cl.asset.webDBInstance);
1857
+ setIf(ax, "classification", cl.asset.classification);
1858
+ if (cl.asset.webOrDatabase) ax["webOrDatabase"] = true;
1859
+ if (Object.keys(ax).length > 0) ext["assetExtras"] = ax;
1860
+ return ext;
1861
+ }
1862
+ function baselineExtensions(s) {
1863
+ const ext = {};
1864
+ setIf(ext, "stigid", s.stigID);
1865
+ setIf(ext, "uuid", s.uuid);
1866
+ setIf(ext, "releaseInfo", s.releaseInfo);
1867
+ setIf(ext, "displayName", s.displayName);
1868
+ setIf(ext, "referenceIdentifier", s.referenceIdentifier);
1869
+ setIf(ext, "classification", s.classification);
1870
+ return ext;
1871
+ }
1872
+ function setIf(m, key, val) {
1873
+ if (val) m[key] = val;
1874
+ }
1875
+ //#endregion
1876
+ //#region shared/typescript/checklist/from-hdf.ts
1877
+ /**
1878
+ * Map HDF Results back to the format-neutral Checklist model. When the HDF
1879
+ * carries checklist passthrough (extensions/tags from checklistToHdf), the
1880
+ * original fields are reproduced losslessly; otherwise required checklist
1881
+ * fields are synthesized best-effort so any HDF yields a valid checklist.
1882
+ */
1883
+ function hdfToChecklist(input) {
1884
+ const hdf = parseJSON(input);
1885
+ if (!hdf || !Array.isArray(hdf.baselines) || hdf.baselines.length === 0) throw new Error("hdf to checklist: HDF has no baselines");
1886
+ const ext = hdf.extensions ?? {};
1887
+ const format = strVal(ext, "checklistFormat") || "ckl";
1888
+ const cklbVersion = strVal(ext, "cklbVersion");
1889
+ const asset = buildAsset(hdf, ext);
1890
+ const stigs = hdf.baselines.map(baselineToStig);
1891
+ return {
1892
+ format,
1893
+ cklbVersion: cklbVersion || void 0,
1894
+ asset,
1895
+ stigs
1896
+ };
1897
+ }
1898
+ function buildAsset(hdf, ext) {
1899
+ const asset = {};
1900
+ const comp = hdf.components?.[0];
1901
+ if (comp) {
1902
+ asset.hostName = comp.name;
1903
+ asset.hostIP = comp.ipAddress;
1904
+ asset.hostFQDN = comp.fqdn;
1905
+ asset.hostMAC = comp.macAddress;
1906
+ }
1907
+ const ax = ext["assetExtras"];
1908
+ if (ax && typeof ax === "object") {
1909
+ const a = ax;
1910
+ asset.role = strVal(a, "role");
1911
+ asset.assetType = strVal(a, "assetType");
1912
+ asset.marking = strVal(a, "marking");
1913
+ asset.targetKey = strVal(a, "targetKey");
1914
+ asset.techArea = strVal(a, "techArea");
1915
+ asset.targetComment = strVal(a, "targetComment");
1916
+ asset.webDBSite = strVal(a, "webDbSite");
1917
+ asset.webDBInstance = strVal(a, "webDbInstance");
1918
+ asset.classification = strVal(a, "classification");
1919
+ asset.webOrDatabase = a["webOrDatabase"] === true;
1920
+ }
1921
+ return asset;
1922
+ }
1923
+ function baselineToStig(bl) {
1924
+ const ext = bl.extensions ?? {};
1925
+ return {
1926
+ stigID: strVal(ext, "stigid") || bl.title || "",
1927
+ title: bl.title,
1928
+ version: bl.version,
1929
+ uuid: strVal(ext, "uuid"),
1930
+ releaseInfo: strVal(ext, "releaseInfo"),
1931
+ displayName: strVal(ext, "displayName"),
1932
+ referenceIdentifier: strVal(ext, "referenceIdentifier"),
1933
+ classification: strVal(ext, "classification"),
1934
+ vulns: bl.requirements.map(requirementToVuln)
1935
+ };
1936
+ }
1937
+ function requirementToVuln(req) {
1938
+ const tags = req.tags ?? {};
1939
+ const descs = req.descriptions ?? [];
1940
+ return {
1941
+ vulnNum: req.id,
1942
+ ruleID: strVal(tags, "rid"),
1943
+ ruleVer: strVal(tags, "stig_id"),
1944
+ groupID: strVal(tags, "group_id") || req.id,
1945
+ groupTitle: strVal(tags, "gtitle"),
1946
+ ruleTitle: req.title,
1947
+ weight: strVal(tags, "weight"),
1948
+ severity: resolveSeverity(req, tags),
1949
+ vulnDiscuss: descData(descs, "default"),
1950
+ checkContent: descData(descs, "check"),
1951
+ fixText: descData(descs, "fix"),
1952
+ ccis: resolveCcis(tags),
1953
+ legacyIDs: strSlice(tags, "legacy_ids"),
1954
+ status: statusFromHdf(req.results?.[0]?.status),
1955
+ findingDetails: req.results?.[0]?.message,
1956
+ extra: extractCklMetadata(tags)
1957
+ };
1958
+ }
1959
+ function resolveSeverity(req, tags) {
1960
+ const tagSev = strVal(tags, "severity");
1961
+ if (tagSev) return tagSev;
1962
+ if (req.severity) return String(req.severity).toLowerCase();
1963
+ const i = req.impact ?? 0;
1964
+ if (i >= .7) return "high";
1965
+ if (i >= .4) return "medium";
1966
+ if (i > 0) return "low";
1967
+ return "";
1968
+ }
1969
+ function resolveCcis(tags) {
1970
+ const direct = strSlice(tags, "cci");
1971
+ if (direct.length > 0) return direct;
1972
+ const nist = strSlice(tags, "nist");
1973
+ if (nist.length > 0) {
1974
+ const ccis = nistToCci(nist);
1975
+ if (ccis.length > 0) return ccis;
1976
+ }
1977
+ return [];
1978
+ }
1979
+ function extractCklMetadata(tags) {
1980
+ const meta = tags["cklMetadata"];
1981
+ if (!meta || typeof meta !== "object") return void 0;
1982
+ const out = {};
1983
+ for (const [k, v] of Object.entries(meta)) if (typeof v === "string") out[k] = v;
1984
+ return Object.keys(out).length > 0 ? out : void 0;
1985
+ }
1986
+ function descData(descs, label) {
1987
+ return descs.find((d) => d.label === label)?.data ?? "";
1988
+ }
1989
+ function strVal(m, key) {
1990
+ const v = m[key];
1991
+ return typeof v === "string" ? v : "";
1992
+ }
1993
+ function strSlice(m, key) {
1994
+ const v = m[key];
1995
+ if (Array.isArray(v)) return v.filter((e) => typeof e === "string");
1996
+ return [];
1997
+ }
1998
+ //#endregion
1999
+ //#region converters/ckl-to-hdf/typescript/converter.ts
2000
+ /**
2001
+ * Convert a DISA STIG Viewer .ckl document to HDF Results JSON.
2002
+ *
2003
+ * Parsing and the HDF mapping live in the shared checklist module. v3.2
2004
+ * classification: controlType is derived per-VULN from CCI->NIST;
2005
+ * verificationMethod and applicability are omitted (the checklist format
2006
+ * cannot substantiate them — see the Go package doc and build-converter
2007
+ * skill Step 4d).
2008
+ */
2009
+ async function convertCklToHdf(input) {
2010
+ validateInputSize(input, "ckl-to-hdf");
2011
+ const resultsChecksum = await inputChecksum(input);
2012
+ const checklist = parseCkl(input);
2013
+ return JSON.stringify(checklistToHdf(checklist, resultsChecksum), null, 2);
2014
+ }
2015
+ //#endregion
2016
+ //#region converters/cklb-to-hdf/typescript/converter.ts
2017
+ /**
2018
+ * Convert a DISA STIG Viewer 3.x .cklb document to HDF Results JSON.
2019
+ *
2020
+ * Parsing and the HDF mapping live in the shared checklist module. v3.2
2021
+ * classification: controlType is derived per-rule from CCI->NIST;
2022
+ * verificationMethod and applicability are omitted (the checklist format
2023
+ * cannot substantiate them — see the Go package doc and build-converter
2024
+ * skill Step 4d).
2025
+ */
2026
+ async function convertCklbToHdf(input) {
2027
+ validateInputSize(input, "cklb-to-hdf");
2028
+ const resultsChecksum = await inputChecksum(input);
2029
+ const checklist = parseCklb(input);
2030
+ return JSON.stringify(checklistToHdf(checklist, resultsChecksum), null, 2);
2031
+ }
2032
+ //#endregion
2033
+ //#region converters/hdf-to-ckl/typescript/converter.ts
2034
+ /**
2035
+ * Convert HDF Results JSON into a DISA STIG Viewer checklist (.ckl XML).
2036
+ *
2037
+ * This is a thin wrapper over the shared checklist module, mirroring the
2038
+ * hdf-to-csv reverse converter. It produces a STIG Viewer 2.x .ckl from ANY
2039
+ * HDF: when the HDF carries checklist passthrough (extensions/tags written by
2040
+ * a prior ckl/cklb-to-hdf conversion) the original fields are reproduced
2041
+ * losslessly; otherwise the required checklist fields are synthesized
2042
+ * best-effort (id->Vuln_Num, nist->CCI reverse, status reverse) with safe
2043
+ * defaults. Mirrors heimdall2 PR #4841.
2044
+ *
2045
+ * @param input HDF Results JSON string
2046
+ * @returns CKL XML string (with the `<?xml ...?>` header)
2047
+ */
2048
+ function convertHdfToCkl(input) {
2049
+ return serializeCkl(hdfToChecklist(input));
2050
+ }
2051
+ //#endregion
2052
+ //#region converters/hdf-to-cklb/typescript/converter.ts
2053
+ /**
2054
+ * Convert HDF Results JSON into a DISA STIG Viewer 3.x checklist (.cklb, JSON).
2055
+ *
2056
+ * The HDF->checklist mapping and CKLB serialization live in the shared
2057
+ * checklist module; this converter is a thin wrapper. Any HDF input produces a
2058
+ * valid CKLB: when the HDF carries checklist passthrough (it originated from a
2059
+ * CKL/CKLB via the reverse converters), the original fields are reproduced
2060
+ * losslessly; otherwise the required checklist fields are synthesized
2061
+ * best-effort from the HDF requirements, tags, and results.
2062
+ *
2063
+ * @param input HDF Results JSON string
2064
+ * @returns CKLB JSON string
2065
+ */
2066
+ function convertHdfToCklb(input) {
2067
+ return serializeCklb(hdfToChecklist(input));
2068
+ }
2069
+ //#endregion
1213
2070
  //#region converters/snyk-to-hdf/typescript/converter.ts
1214
2071
  /**
1215
2072
  * Formats the "from" array as a human-readable dependency path.
@@ -1221,7 +2078,7 @@ function formatDependencyPath(from) {
1221
2078
  /**
1222
2079
  * Builds a single EvaluatedRequirement from a group of vulnerabilities sharing an ID.
1223
2080
  */
1224
- function buildRequirement$15(vulnID, vulns) {
2081
+ function buildRequirement$16(vulnID, vulns) {
1225
2082
  const rep = vulns[0];
1226
2083
  const cweIDs = rep.identifiers.CWE ?? [];
1227
2084
  const nist = mapCWEToNIST(cweIDs, DEFAULT_STATIC_ANALYSIS_NIST_TAGS);
@@ -1237,7 +2094,11 @@ function buildRequirement$15(vulnID, vulns) {
1237
2094
  data: rep.description
1238
2095
  }];
1239
2096
  const results = vulns.map((vuln) => createResult(ResultStatus.Failed, void 0, { codeDesc: formatDependencyPath(vuln.from) }));
1240
- return createRequirement(vulnID, rep.title, descriptions, severityToImpact(rep.severity), results, { tags });
2097
+ const req = createRequirement(vulnID, rep.title, descriptions, severityToImpact(rep.severity), results, { tags });
2098
+ const controlType = deriveControlTypeFromTags(nist);
2099
+ if (controlType !== void 0) req.controlType = controlType;
2100
+ req.verificationMethod = VerificationMethodEnum.Automated;
2101
+ return req;
1241
2102
  }
1242
2103
  /**
1243
2104
  * Converts a single Snyk project report to an HDF baseline.
@@ -1253,7 +2114,7 @@ function convertSingleProject(report, resultsChecksum) {
1253
2114
  else groups.set(vuln.id, [vuln]);
1254
2115
  }
1255
2116
  const requirements = [];
1256
- for (const [vulnID, vulns] of groups) requirements.push(buildRequirement$15(vulnID, vulns));
2117
+ for (const [vulnID, vulns] of groups) requirements.push(buildRequirement$16(vulnID, vulns));
1257
2118
  return createMinimalBaseline("Snyk Scan", requirements, {
1258
2119
  resultsChecksum,
1259
2120
  title: `Snyk Project: ${report.projectName ?? ""} Snyk Path: ${report.path ?? ""}`,
@@ -1313,7 +2174,7 @@ const IMPACT_MAPPING$8 = new Map([
1313
2174
  ["negligible", 0],
1314
2175
  ["unknown", .5]
1315
2176
  ]);
1316
- function getImpact$8(severity) {
2177
+ function getImpact$9(severity) {
1317
2178
  if (!severity) return .5;
1318
2179
  return IMPACT_MAPPING$8.get(severity.toLowerCase()) ?? .5;
1319
2180
  }
@@ -1370,7 +2231,7 @@ function convertMatchToRequirement(match, isIgnored) {
1370
2231
  const vuln = match.vulnerability;
1371
2232
  const cveId = vuln.id;
1372
2233
  const severity = vuln.severity;
1373
- const impact = getImpact$8(severity);
2234
+ const impact = getImpact$9(severity);
1374
2235
  const description = getDescription(vuln, match.relatedVulnerabilities);
1375
2236
  const fixInfo = getFixInfo(vuln.fix);
1376
2237
  const cvssInfo = getCVSSInfo(vuln, match.relatedVulnerabilities);
@@ -1392,7 +2253,7 @@ function convertMatchToRequirement(match, isIgnored) {
1392
2253
  startTime: /* @__PURE__ */ new Date("0001-01-01T00:00:00Z")
1393
2254
  };
1394
2255
  const tags = buildNistCciTags(DEFAULT_STATIC_ANALYSIS_NIST_TAGS, nistToCci(DEFAULT_STATIC_ANALYSIS_NIST_TAGS));
1395
- return {
2256
+ const requirement = {
1396
2257
  id: isIgnored ? `Grype-Ignored-Match/${cveId}` : `Grype/${cveId}`,
1397
2258
  impact,
1398
2259
  results: [result],
@@ -1411,8 +2272,12 @@ function convertMatchToRequirement(match, isIgnored) {
1411
2272
  data: cvssInfo
1412
2273
  }
1413
2274
  ],
1414
- refs: refs.length > 0 ? refs.map((url) => ({ url })) : void 0
2275
+ refs: refs.length > 0 ? refs.map((url) => ({ url })) : void 0,
2276
+ verificationMethod: VerificationMethodEnum.Automated
1415
2277
  };
2278
+ const controlType = deriveControlTypeFromTags(DEFAULT_STATIC_ANALYSIS_NIST_TAGS);
2279
+ if (controlType !== void 0) requirement.controlType = controlType;
2280
+ return requirement;
1416
2281
  }
1417
2282
  async function convertGrypeToHdf(input) {
1418
2283
  validateInputSize(input, "grype");
@@ -1554,16 +2419,30 @@ function convertReportHostToBaseline(host, policyName, version, resultsChecksum)
1554
2419
  }
1555
2420
  function convertReportItemToRequirement(item, host) {
1556
2421
  const isCompliance = !!item["compliance-reference"];
1557
- return {
1558
- id: isCompliance ? parseComplianceRef(item["compliance-reference"], "Vuln-ID")[0] || item["pluginID"] : item["pluginID"],
1559
- title: isCompliance ? item["compliance-check-name"] || item["pluginName"] : item["pluginName"],
1560
- descriptions: buildDescriptions(item, isCompliance),
1561
- impact: calculateImpact(item, isCompliance),
1562
- tags: buildTags$2(item, isCompliance),
1563
- refs: buildRefs(item),
1564
- results: [buildResult$1(item, host, isCompliance)],
1565
- code: JSON.stringify(item, null, 2)
2422
+ const id = isCompliance ? parseComplianceRef(item["compliance-reference"], "Vuln-ID")[0] || item["pluginID"] : item["pluginID"];
2423
+ const title = isCompliance ? item["compliance-check-name"] || item["pluginName"] : item["pluginName"];
2424
+ const descriptions = buildDescriptions(item, isCompliance);
2425
+ const impact = calculateImpact(item, isCompliance);
2426
+ const tags = buildTags$2(item, isCompliance);
2427
+ const refs = buildRefs(item);
2428
+ const results = [buildResult$1(item, host, isCompliance)];
2429
+ const code = JSON.stringify(item, null, 2);
2430
+ const nistTags = tags["nist"];
2431
+ const controlType = deriveControlTypeFromTags(nistTags ?? []);
2432
+ const verificationMethod = deriveVerificationMethod(code);
2433
+ const req = {
2434
+ id,
2435
+ title,
2436
+ descriptions,
2437
+ impact,
2438
+ tags,
2439
+ refs,
2440
+ results,
2441
+ code
1566
2442
  };
2443
+ if (controlType !== void 0) req.controlType = controlType;
2444
+ if (verificationMethod !== void 0) req.verificationMethod = verificationMethod;
2445
+ return req;
1567
2446
  }
1568
2447
  function buildDescriptions(item, isCompliance) {
1569
2448
  const descriptions = [];
@@ -1786,7 +2665,11 @@ function convertRuleToRequirement(ruleKey, issues, componentMap, ruleMap) {
1786
2665
  ...allTags
1787
2666
  } };
1788
2667
  if (sourceLocation) options.sourceLocation = sourceLocation;
1789
- return createRequirement(ruleKey, title, [createDescription("default", description)], impact, results, options);
2668
+ const req = createRequirement(ruleKey, title, [createDescription("default", description)], impact, results, options);
2669
+ const controlType = deriveControlTypeFromTags(nistControls);
2670
+ if (controlType !== void 0) req.controlType = controlType;
2671
+ req.verificationMethod = VerificationMethodEnum.Automated;
2672
+ return req;
1790
2673
  }
1791
2674
  function extractDescription(rule) {
1792
2675
  if (!rule) return "";
@@ -1905,7 +2788,7 @@ function buildResult(r) {
1905
2788
  ...startTime ? { startTime } : {}
1906
2789
  });
1907
2790
  }
1908
- function buildRequirement$14(rule) {
2791
+ function buildRequirement$15(rule) {
1909
2792
  const nist = buildNistTags$3(rule.Source.SourceIdentifier, rule.ConfigRuleName);
1910
2793
  const tags = nist.length > 0 ? { nist } : {};
1911
2794
  const descriptions = [{
@@ -1917,13 +2800,17 @@ function buildRequirement$14(rule) {
1917
2800
  }];
1918
2801
  const title = `${getAccountId(rule.ConfigRuleArn)} - ${rule.ConfigRuleName}`;
1919
2802
  const results = rule.EvaluationResults.map(buildResult);
1920
- return createRequirement(rule.ConfigRuleId, title, descriptions, .5, results, {
2803
+ const req = createRequirement(rule.ConfigRuleId, title, descriptions, .5, results, {
1921
2804
  tags,
1922
2805
  sourceLocation: {
1923
2806
  ref: rule.ConfigRuleArn,
1924
2807
  line: 1
1925
2808
  }
1926
2809
  });
2810
+ const controlType = deriveControlTypeFromTags(nist);
2811
+ if (controlType !== void 0) req.controlType = controlType;
2812
+ req.verificationMethod = VerificationMethodEnum.Automated;
2813
+ return req;
1927
2814
  }
1928
2815
  /**
1929
2816
  * Converts an AWS Config static export (ConfigRulesFile JSON) to HDF format.
@@ -1942,7 +2829,7 @@ async function convertAwsConfigToHdf(input) {
1942
2829
  /* v8 ignore next -- truncation only triggers with >100K items */
1943
2830
  if (truncatedRules) console.warn(`WARNING: Input truncated at ${limitedRules.length} ConfigRule items (original: ${data.ConfigRules.length})`);
1944
2831
  const baseline = {
1945
- ...createMinimalBaseline("AWS Config", limitedRules.map(buildRequirement$14), { resultsChecksum }),
2832
+ ...createMinimalBaseline("AWS Config", limitedRules.map(buildRequirement$15), { resultsChecksum }),
1946
2833
  title: "AWS Config Compliance Results",
1947
2834
  version: "1.0.0",
1948
2835
  maintainer: "Amazon Web Services"
@@ -1968,6 +2855,116 @@ async function convertAwsConfigToHdf(input) {
1968
2855
  });
1969
2856
  }
1970
2857
  //#endregion
2858
+ //#region converters/checkov-to-hdf/typescript/converter.ts
2859
+ /**
2860
+ * Maps checkov result string to HDF ResultStatus.
2861
+ */
2862
+ function mapStatus$2(result) {
2863
+ switch (result.toUpperCase()) {
2864
+ case "PASSED": return ResultStatus.Passed;
2865
+ case "FAILED": return ResultStatus.Failed;
2866
+ case "SKIPPED": return ResultStatus.NotReviewed;
2867
+ default: return ResultStatus.NotReviewed;
2868
+ }
2869
+ }
2870
+ /**
2871
+ * Maps severity to impact, defaulting to 0.5 for null/unknown.
2872
+ */
2873
+ function getImpact$8(severity) {
2874
+ if (!severity) return .5;
2875
+ return severityToImpact(severity);
2876
+ }
2877
+ /**
2878
+ * Converts a single CheckovCheck to an HDF RequirementResult.
2879
+ */
2880
+ function checkToResult(check) {
2881
+ const status = mapStatus$2(check.check_result.result);
2882
+ const codeDesc = `Resource: ${check.resource}\nFile: ${check.file_path} (lines ${JSON.stringify(check.file_line_range)})`;
2883
+ let message;
2884
+ if (status === ResultStatus.NotReviewed && check.check_result.suppress_comment) message = check.check_result.suppress_comment;
2885
+ return createResult(status, message ?? "", { codeDesc });
2886
+ }
2887
+ /**
2888
+ * Converts a group of checks sharing a check_id into one EvaluatedRequirement.
2889
+ */
2890
+ function buildRequirement$14(checkId, checks) {
2891
+ const rep = checks[0];
2892
+ const impact = getImpact$8(rep.severity);
2893
+ const tags = { nist: [...DEFAULT_STATIC_ANALYSIS_NIST_TAGS] };
2894
+ const descriptions = [{
2895
+ label: "default",
2896
+ data: rep.check_name
2897
+ }];
2898
+ if (rep.guideline) descriptions.push({
2899
+ label: "check",
2900
+ data: rep.guideline
2901
+ });
2902
+ const results = checks.map(checkToResult);
2903
+ const req = createRequirement(checkId, rep.check_name, descriptions, impact, results, { tags });
2904
+ req.verificationMethod = VerificationMethodEnum.Automated;
2905
+ const controlType = deriveControlTypeFromTags([...DEFAULT_STATIC_ANALYSIS_NIST_TAGS]);
2906
+ if (controlType !== void 0) req.controlType = controlType;
2907
+ return req;
2908
+ }
2909
+ /**
2910
+ * Parses checkov input which can be a single object or array.
2911
+ */
2912
+ function parseInput(input) {
2913
+ const parsed = parseJSON(input);
2914
+ if (Array.isArray(parsed)) return parsed;
2915
+ if (!parsed || typeof parsed !== "object") throw new Error("Invalid checkov structure: not a valid JSON object");
2916
+ if (!parsed.results || typeof parsed.results !== "object") throw new Error("Invalid checkov structure: missing or invalid results field");
2917
+ return [parsed];
2918
+ }
2919
+ /**
2920
+ * Converts checkov output to HDF format.
2921
+ * Accepts native checkov JSON (single object or array) and SARIF format.
2922
+ * SARIF input is detected automatically and delegated to the shared SARIF converter.
2923
+ *
2924
+ * @param input - checkov JSON or SARIF string
2925
+ * @returns HDF JSON string
2926
+ */
2927
+ async function convertCheckovToHdf(input) {
2928
+ validateInputSize(input, "checkov");
2929
+ registerAllFingerprints();
2930
+ const detected = detectConverter(input);
2931
+ if (detected && detected.fingerprint.id === "sarif-to-hdf") return convertSarifToHdf(input);
2932
+ const resultsChecksum = await inputChecksum(input);
2933
+ const reports = parseInput(input);
2934
+ const allChecks = [];
2935
+ const checkTypes = [];
2936
+ let version;
2937
+ for (const report of reports) {
2938
+ checkTypes.push(report.check_type);
2939
+ if (!version && report.summary.checkov_version) version = report.summary.checkov_version;
2940
+ allChecks.push(...report.results.passed_checks);
2941
+ allChecks.push(...report.results.failed_checks);
2942
+ allChecks.push(...report.results.skipped_checks);
2943
+ }
2944
+ const { items: limitedChecks, truncated } = limitArray(allChecks);
2945
+ /* v8 ignore next -- truncation only triggers with >100K items */
2946
+ if (truncated) console.warn(`WARNING: Input truncated at ${limitedChecks.length} check items (original: ${allChecks.length})`);
2947
+ const groups = /* @__PURE__ */ new Map();
2948
+ for (const check of limitedChecks) {
2949
+ const existing = groups.get(check.check_id);
2950
+ if (existing) existing.push(check);
2951
+ else groups.set(check.check_id, [check]);
2952
+ }
2953
+ const requirements = [];
2954
+ for (const [checkId, checks] of groups) requirements.push(buildRequirement$14(checkId, checks));
2955
+ const baseline = createMinimalBaseline("Checkov Scan", requirements, { resultsChecksum });
2956
+ const format = checkTypes.join(", ");
2957
+ return buildHdfResults({
2958
+ generatorName: "checkov-to-hdf",
2959
+ converterVersion: "1.0.0",
2960
+ toolName: "Checkov",
2961
+ toolVersion: version,
2962
+ toolFormat: format,
2963
+ baselines: [baseline],
2964
+ timestamp: /* @__PURE__ */ new Date()
2965
+ });
2966
+ }
2967
+ //#endregion
1971
2968
  //#region converters/gosec-to-hdf/typescript/converter.ts
1972
2969
  /**
1973
2970
  * Severity to HDF impact mapping for gosec.
@@ -2010,8 +3007,9 @@ function issueToResult(issue) {
2010
3007
  function buildRequirement$13(ruleId, issues) {
2011
3008
  const rep = issues[0];
2012
3009
  const impact = IMPACT_MAPPING$6[rep.severity.toUpperCase()] ?? .5;
3010
+ const nist = mapCWEToNIST([rep.cwe.id], DEFAULT_REMEDIATION_NIST_TAGS$1);
2013
3011
  const tags = {
2014
- nist: mapCWEToNIST([rep.cwe.id], DEFAULT_REMEDIATION_NIST_TAGS$1),
3012
+ nist,
2015
3013
  cwe: {
2016
3014
  id: rep.cwe.id,
2017
3015
  url: rep.cwe.url
@@ -2025,7 +3023,11 @@ function buildRequirement$13(ruleId, issues) {
2025
3023
  label: "check",
2026
3024
  data: `CWE-${rep.cwe.id}: ${rep.cwe.url}`
2027
3025
  }];
2028
- return createRequirement(ruleId, rep.details, descriptions, impact, results, { tags });
3026
+ const req = createRequirement(ruleId, rep.details, descriptions, impact, results, { tags });
3027
+ req.verificationMethod = VerificationMethodEnum.Automated;
3028
+ const controlType = deriveControlTypeFromTags(nist);
3029
+ if (controlType !== void 0) req.controlType = controlType;
3030
+ return req;
2029
3031
  }
2030
3032
  /**
2031
3033
  * Converts gosec output to HDF format.
@@ -2089,7 +3091,7 @@ function convertVulnToRequirement(vuln) {
2089
3091
  const extras = {};
2090
3092
  if (vuln.OSVDB && vuln.OSVDB !== "0") extras.osvdb = vuln.OSVDB;
2091
3093
  const tags = buildNistCciTags(nistTags, cciTags, Object.keys(extras).length > 0 ? extras : void 0);
2092
- return {
3094
+ const req = {
2093
3095
  id: vuln.id,
2094
3096
  title: vuln.msg,
2095
3097
  impact: .5,
@@ -2100,6 +3102,10 @@ function convertVulnToRequirement(vuln) {
2100
3102
  data: vuln.msg
2101
3103
  }]
2102
3104
  };
3105
+ const controlType = deriveControlTypeFromTags(nistTags);
3106
+ if (controlType !== void 0) req.controlType = controlType;
3107
+ req.verificationMethod = VerificationMethodEnum.Automated;
3108
+ return req;
2103
3109
  }
2104
3110
  async function convertNiktoToHdf(input) {
2105
3111
  validateInputSize(input, "nikto");
@@ -2291,8 +3297,11 @@ async function convertZapToHdf(input) {
2291
3297
  impact,
2292
3298
  results,
2293
3299
  tags,
2294
- descriptions
3300
+ descriptions,
3301
+ verificationMethod: VerificationMethodEnum.Automated
2295
3302
  };
3303
+ const controlType = deriveControlTypeFromTags(nistTags);
3304
+ if (controlType !== void 0) req.controlType = controlType;
2296
3305
  requirements.push(req);
2297
3306
  }
2298
3307
  const targetName = site["@host"] ?? "Unknown Host";
@@ -2435,7 +3444,10 @@ async function convertCyclonedxToHdf(input) {
2435
3444
  const affects = vuln.affects ?? [];
2436
3445
  const results = affects.length > 0 ? affects.map((affect) => createResult(ResultStatus.Failed, void 0, { codeDesc: formatCodeDesc$4(componentLookup, affect.ref) })) : [createResult(ResultStatus.Failed, void 0, { codeDesc: `Vulnerability ${vuln.id}` })];
2437
3446
  const title = vuln.source?.name ? `${vuln.id} (${vuln.source.name})` : vuln.id;
2438
- requirements.push(createRequirement(vuln.id, title, descriptions, impact, results, { tags }));
3447
+ const req = createRequirement(vuln.id, title, descriptions, impact, results, { tags });
3448
+ const controlType = deriveControlTypeFromTags(nist);
3449
+ if (controlType !== void 0) req.controlType = controlType;
3450
+ requirements.push(req);
2439
3451
  }
2440
3452
  const baseline = createMinimalBaseline("CycloneDX Scan", requirements, { resultsChecksum });
2441
3453
  const targetName = bom.metadata?.component?.name ?? "";
@@ -2501,6 +3513,9 @@ function createRow(baseline, requirement, target) {
2501
3513
  "Status": String(status),
2502
3514
  "NIST Controls": nistControls,
2503
3515
  "CCI Controls": cciControls,
3516
+ "Control Type": requirement.controlType ?? "",
3517
+ "Verification Method": requirement.verificationMethod ?? "",
3518
+ "Applicability": requirement.applicability ?? "",
2504
3519
  "Result Message": message
2505
3520
  };
2506
3521
  }
@@ -2624,7 +3639,12 @@ async function convertSplunkToHdf(input) {
2624
3639
  })) : [];
2625
3640
  const options = { tags: control.tags ?? {} };
2626
3641
  if (control.source_location) options.sourceLocation = control.source_location;
2627
- return createRequirement(control.id, control.title, descriptions, control.impact, results, options);
3642
+ const req = createRequirement(control.id, control.title, descriptions, control.impact, results, options);
3643
+ const nistTagsRaw = control.tags?.["nist"];
3644
+ const controlType = deriveControlTypeFromTags(Array.isArray(nistTagsRaw) ? nistTagsRaw.filter((t) => typeof t === "string") : []);
3645
+ if (controlType !== void 0) req.controlType = controlType;
3646
+ req.verificationMethod = VerificationMethodEnum.Automated;
3647
+ return req;
2628
3648
  });
2629
3649
  const groups = convertGroups(profile.groups);
2630
3650
  const baselineOptions = { resultsChecksum };
@@ -2867,8 +3887,11 @@ async function convertGitlabToHdf(input) {
2867
3887
  impact,
2868
3888
  results: [result],
2869
3889
  tags,
2870
- descriptions
3890
+ descriptions,
3891
+ verificationMethod: VerificationMethodEnum.Automated
2871
3892
  };
3893
+ const controlType = deriveControlTypeFromTags(nistTags);
3894
+ if (controlType !== void 0) req.controlType = controlType;
2872
3895
  requirements.push(req);
2873
3896
  }
2874
3897
  const baseline = createMinimalBaseline("GitLab Security Scan", requirements, {
@@ -3004,13 +4027,17 @@ function buildRequirement$12(reqID, findings) {
3004
4027
  }));
3005
4028
  const sourceFile = getSourceFile(rep);
3006
4029
  const sourceLine = getSourceLine(rep);
3007
- return createRequirement(reqID, title, descriptions, .5, results, {
4030
+ const req = createRequirement(reqID, title, descriptions, .5, results, {
3008
4031
  tags,
3009
4032
  sourceLocation: sourceFile ? {
3010
4033
  ref: sourceFile,
3011
4034
  line: sourceLine
3012
4035
  } : void 0
3013
4036
  });
4037
+ const controlType = deriveControlTypeFromTags(TRUFFLEHOG_NIST);
4038
+ if (controlType !== void 0) req.controlType = controlType;
4039
+ req.verificationMethod = VerificationMethodEnum.Automated;
4040
+ return req;
3014
4041
  }
3015
4042
  /**
3016
4043
  * Converts TruffleHog output to HDF format.
@@ -3165,14 +4192,18 @@ function buildRequirement$11(issueType, issues) {
3165
4192
  };
3166
4193
  });
3167
4194
  const impact = getImpact$7(rep.severity ?? "information");
3168
- return {
4195
+ const req = {
3169
4196
  id: issueType,
3170
4197
  title: rep.name ?? void 0,
3171
4198
  impact,
3172
4199
  tags,
3173
4200
  descriptions,
3174
- results
4201
+ results,
4202
+ verificationMethod: VerificationMethodEnum.Automated
3175
4203
  };
4204
+ const controlType = deriveControlTypeFromTags(nist);
4205
+ if (controlType !== void 0) req.controlType = controlType;
4206
+ return req;
3176
4207
  }
3177
4208
  //#endregion
3178
4209
  //#region converters/dbprotect-to-hdf/typescript/converter.ts
@@ -3261,7 +4292,11 @@ function buildRequirement$10(checkID, findings, hasStatus) {
3261
4292
  startTime: parseDate(f["Date"] ?? "")
3262
4293
  });
3263
4294
  });
3264
- return createRequirement(checkID, rep["Check"] ?? "", descriptions, getImpact$6(rep["Risk DV"] ?? ""), results, { tags });
4295
+ const req = createRequirement(checkID, rep["Check"] ?? "", descriptions, getImpact$6(rep["Risk DV"] ?? ""), results, { tags });
4296
+ req.verificationMethod = VerificationMethodEnum.Automated;
4297
+ const controlType = deriveControlTypeFromTags([...nist]);
4298
+ if (controlType !== void 0) req.controlType = controlType;
4299
+ return req;
3265
4300
  }
3266
4301
  /**
3267
4302
  * Converts DBProtect Cognos XML output to HDF format.
@@ -3373,7 +4408,11 @@ function buildRequirement$9(vuln) {
3373
4408
  codeDesc: formatCodeDesc$2(vuln),
3374
4409
  startTime
3375
4410
  })];
3376
- return createRequirement(vuln.id, vuln.id, descriptions, twistlockSeverityToImpact(vuln.severity), results, { tags });
4411
+ const req = createRequirement(vuln.id, vuln.id, descriptions, twistlockSeverityToImpact(vuln.severity), results, { tags });
4412
+ const controlType = deriveControlTypeFromTags(nist);
4413
+ if (controlType !== void 0) req.controlType = controlType;
4414
+ req.verificationMethod = VerificationMethodEnum.Automated;
4415
+ return req;
3377
4416
  }
3378
4417
  /**
3379
4418
  * Converts a single TwistlockResult to an EvaluatedBaseline.
@@ -3486,7 +4525,11 @@ function buildRequirement$8(finding, timestamp) {
3486
4525
  codeDesc,
3487
4526
  startTime: timestamp ? new Date(timestamp) : void 0
3488
4527
  })];
3489
- return createRequirement(finding.matrix, getTitle$1(finding), descriptions, getImpact$5(finding.vulnerability.severity), results, { tags });
4528
+ const req = createRequirement(finding.matrix, getTitle$1(finding), descriptions, getImpact$5(finding.vulnerability.severity), results, { tags });
4529
+ req.verificationMethod = VerificationMethodEnum.Automated;
4530
+ const controlType = deriveControlTypeFromTags(nist);
4531
+ if (controlType !== void 0) req.controlType = controlType;
4532
+ return req;
3490
4533
  }
3491
4534
  /**
3492
4535
  * Converts Dependency-Track FPF JSON output to HDF format.
@@ -3589,7 +4632,11 @@ function buildRequirement$7(entryID, entries) {
3589
4632
  data: formatDescription(rep)
3590
4633
  }];
3591
4634
  const results = entries.map((entry) => createResult(ResultStatus.Failed, void 0, { codeDesc: formatCodeDesc$1(entry) }));
3592
- return createRequirement(entryID, rep.summary, descriptions, severityToImpact(rep.severity), results, { tags });
4635
+ const req = createRequirement(entryID, rep.summary, descriptions, severityToImpact(rep.severity), results, { tags });
4636
+ const controlType = deriveControlTypeFromTags(nist);
4637
+ if (controlType !== void 0) req.controlType = controlType;
4638
+ req.verificationMethod = VerificationMethodEnum.Automated;
4639
+ return req;
3593
4640
  }
3594
4641
  /**
3595
4642
  * Converts JFrog Xray JSON output to HDF format.
@@ -3687,7 +4734,11 @@ function buildRequirement$6(vuln) {
3687
4734
  data: vuln.description
3688
4735
  }];
3689
4736
  const results = [createResult(ResultStatus.Failed, vulnMessage(vuln), { codeDesc: "" })];
3690
- return createRequirement(vulnID(vuln), vulnTitle(vuln), descriptions, getImpact$4(vuln), results, { tags });
4737
+ const req = createRequirement(vulnID(vuln), vulnTitle(vuln), descriptions, getImpact$4(vuln), results, { tags });
4738
+ const controlType = deriveControlTypeFromTags(nist);
4739
+ if (controlType !== void 0) req.controlType = controlType;
4740
+ req.verificationMethod = VerificationMethodEnum.Automated;
4741
+ return req;
3691
4742
  }
3692
4743
  /**
3693
4744
  * Constructs the baseline title from the image metadata.
@@ -3826,14 +4877,18 @@ function buildRequirement$5(desc, vulns, snippetMap, startTimeStr) {
3826
4877
  codeDesc: buildCodeDesc$2(vuln, snippetMap),
3827
4878
  startTime: new Date(startTimeStr)
3828
4879
  }));
3829
- return {
4880
+ const req = {
3830
4881
  id: desc.classID ?? "unknown",
3831
4882
  title,
3832
4883
  impact,
3833
4884
  tags,
3834
4885
  descriptions,
3835
- results
4886
+ results,
4887
+ verificationMethod: VerificationMethodEnum.Automated
3836
4888
  };
4889
+ const controlType = deriveControlTypeFromTags(nistTags);
4890
+ if (controlType !== void 0) req.controlType = controlType;
4891
+ return req;
3837
4892
  }
3838
4893
  /**
3839
4894
  * Converts Fortify FVDL XML to HDF format.
@@ -3985,7 +5040,11 @@ function buildRequirement$4(rec) {
3985
5040
  data: rec.Description
3986
5041
  }];
3987
5042
  const results = [createResult(ResultStatus.Failed, message, { codeDesc })];
3988
- return createRequirement(id, title, descriptions, getImpact$3(rec.Severity), results, { tags });
5043
+ const req = createRequirement(id, title, descriptions, getImpact$3(rec.Severity), results, { tags });
5044
+ const controlType = deriveControlTypeFromTags(nist);
5045
+ if (controlType !== void 0) req.controlType = controlType;
5046
+ req.verificationMethod = VerificationMethodEnum.Automated;
5047
+ return req;
3989
5048
  }
3990
5049
  /**
3991
5050
  * Groups records by hostname, preserving insertion order.
@@ -4145,7 +5204,7 @@ function buildRequirement$3(vuln, initiated) {
4145
5204
  startTime
4146
5205
  }];
4147
5206
  const impact = getImpact$2(vuln.severity ?? "");
4148
- return {
5207
+ const req = {
4149
5208
  id: vuln.LookupId ?? "",
4150
5209
  title: vuln.name ?? void 0,
4151
5210
  impact,
@@ -4153,6 +5212,10 @@ function buildRequirement$3(vuln, initiated) {
4153
5212
  descriptions,
4154
5213
  results
4155
5214
  };
5215
+ const controlType = deriveControlTypeFromTags(nist);
5216
+ if (controlType !== void 0) req.controlType = controlType;
5217
+ req.verificationMethod = VerificationMethodEnum.Automated;
5218
+ return req;
4156
5219
  }
4157
5220
  /**
4158
5221
  * Converts Netsparker/Invicti XML scan results to HDF format.
@@ -4284,7 +5347,11 @@ function buildRequirement$2(ruleID, finding, startTime) {
4284
5347
  codeDesc: finding.description,
4285
5348
  startTime: startTime ? new Date(startTime) : void 0
4286
5349
  });
4287
- return createRequirement(ruleID, finding.description, descriptions, getImpact$1(finding.level), [resultObj], { tags });
5350
+ const req = createRequirement(ruleID, finding.description, descriptions, getImpact$1(finding.level), [resultObj], { tags });
5351
+ const controlType = deriveControlTypeFromTags(nist);
5352
+ if (controlType !== void 0) req.controlType = controlType;
5353
+ req.verificationMethod = VerificationMethodEnum.Automated;
5354
+ return req;
4288
5355
  }
4289
5356
  /**
4290
5357
  * Converts ScoutSuite output to HDF format.
@@ -4432,7 +5499,11 @@ function buildRequirementFromResult(result, filename) {
4432
5499
  codeDesc: `No sections reported by ${scannerName}`,
4433
5500
  startTime
4434
5501
  })];
4435
- return createRequirement(result.sha256, filename, descriptions, scoreToImpact(score), results, { tags });
5502
+ const req = createRequirement(result.sha256, filename, descriptions, scoreToImpact(score), results, { tags });
5503
+ req.verificationMethod = VerificationMethodEnum.Automated;
5504
+ const controlType = deriveControlTypeFromTags([...nist]);
5505
+ if (controlType !== void 0) req.controlType = controlType;
5506
+ return req;
4436
5507
  }
4437
5508
  /**
4438
5509
  * Builds an HDF baseline for a single scanner's results.
@@ -4660,7 +5731,11 @@ function buildCWERequirement(cat, impact, firstBuildDate) {
4660
5731
  startTime
4661
5732
  }));
4662
5733
  });
4663
- return createRequirement(attr(cat, "categoryid"), attr(cat, "categoryname"), descriptions, impact, results, { tags });
5734
+ const req = createRequirement(attr(cat, "categoryid"), attr(cat, "categoryname"), descriptions, impact, results, { tags });
5735
+ const controlType = deriveControlTypeFromTags(nist);
5736
+ if (controlType !== void 0) req.controlType = controlType;
5737
+ req.verificationMethod = VerificationMethodEnum.Automated;
5738
+ return req;
4664
5739
  }
4665
5740
  /** Build CVE-based requirements from SCA components. */
4666
5741
  function buildCVERequirements(sca, firstBuildDate) {
@@ -4712,10 +5787,14 @@ function buildCVERequirement(vuln, components, firstBuildDate) {
4712
5787
  }));
4713
5788
  const cveSummary = attr(vuln, "cve_summary");
4714
5789
  const cveId = attr(vuln, "cve_id");
4715
- return createRequirement(cveId, cveId, [{
5790
+ const req = createRequirement(cveId, cveId, [{
4716
5791
  label: "default",
4717
5792
  data: cveSummary || ""
4718
5793
  }], impact, results, { tags });
5794
+ const controlType = deriveControlTypeFromTags(nist);
5795
+ if (controlType !== void 0) req.controlType = controlType;
5796
+ req.verificationMethod = VerificationMethodEnum.Automated;
5797
+ return req;
4719
5798
  }
4720
5799
  /**
4721
5800
  * Convert Veracode DetailedReport XML to HDF JSON string.
@@ -4811,7 +5890,8 @@ function buildRequirement$1(cs, profiles, createdDateTime) {
4811
5890
  const title = getTitle(profiles, cs);
4812
5891
  const impact = getImpact(profiles, cs);
4813
5892
  const status = getStatus(profiles, cs);
4814
- const tags = buildNistCciTags([...DEFAULT_STATIC_ANALYSIS_NIST_TAGS], []);
5893
+ const nist = [...DEFAULT_STATIC_ANALYSIS_NIST_TAGS];
5894
+ const tags = buildNistCciTags(nist, []);
4815
5895
  const descriptions = [{
4816
5896
  label: "default",
4817
5897
  data: stripHTML(cs.description)
@@ -4831,10 +5911,14 @@ function buildRequirement$1(cs, profiles, createdDateTime) {
4831
5911
  }
4832
5912
  const codeDesc = cs.implementationStatus || "No implementation status provided";
4833
5913
  const startTime = createdDateTime ? new Date(createdDateTime) : void 0;
4834
- return createRequirement(id, title, descriptions, impact, [createResult(status, void 0, {
5914
+ const req = createRequirement(id, title, descriptions, impact, [createResult(status, void 0, {
4835
5915
  codeDesc,
4836
5916
  ...startTime ? { startTime } : {}
4837
5917
  })], { tags });
5918
+ const controlType = deriveControlTypeFromTags(nist);
5919
+ if (controlType !== void 0) req.controlType = controlType;
5920
+ req.verificationMethod = VerificationMethodEnum.Automated;
5921
+ return req;
4838
5922
  }
4839
5923
  /**
4840
5924
  * Converts Microsoft Secure Score combined JSON to HDF format.
@@ -5021,7 +6105,9 @@ function buildRequirement(assessmentID, assessments) {
5021
6105
  data: meta.remediationDescription
5022
6106
  });
5023
6107
  const results = assessments.map(buildResultFromAssessment);
5024
- return createRequirement(assessmentID, rep.properties.displayName, descriptions, impact, results, { tags });
6108
+ const req = createRequirement(assessmentID, rep.properties.displayName, descriptions, impact, results, { tags });
6109
+ req.verificationMethod = VerificationMethodEnum.Automated;
6110
+ return req;
5025
6111
  }
5026
6112
  /**
5027
6113
  * Converts a single assessment into an HDF RequirementResult.
@@ -5189,7 +6275,12 @@ function alertToRequirement(alert) {
5189
6275
  data: alert.recommendedActions
5190
6276
  });
5191
6277
  const tags = buildTags$1(alert);
5192
- return createRequirement(alert.id, alert.title, descriptions, impact, results, { tags });
6278
+ const req = createRequirement(alert.id, alert.title, descriptions, impact, results, { tags });
6279
+ const nistTags = tags.nist;
6280
+ const controlType = deriveControlTypeFromTags(nistTags);
6281
+ if (controlType !== void 0) req.controlType = controlType;
6282
+ req.verificationMethod = VerificationMethodEnum.Automated;
6283
+ return req;
5193
6284
  }
5194
6285
  /**
5195
6286
  * Converts Microsoft Defender for Endpoint alerts (Microsoft Graph Security API v2 format) to HDF.
@@ -5964,6 +7055,9 @@ async function convertIonchannelToHdf(input) {
5964
7055
  startTime: /* @__PURE__ */ new Date("0001-01-01T00:00:00Z")
5965
7056
  })], { tags });
5966
7057
  req.code = code;
7058
+ const controlType = deriveControlTypeFromTags(DEFAULT_COMPONENT_MANAGEMENT_NIST_TAGS);
7059
+ if (controlType !== void 0) req.controlType = controlType;
7060
+ req.verificationMethod = VerificationMethodEnum.Automated;
5967
7061
  return req;
5968
7062
  });
5969
7063
  const resultsChecksum = await inputChecksum(input);
@@ -6083,13 +7177,17 @@ function controlToBaselineRequirement(ctrl) {
6083
7177
  const nistTag = controlIdToNistTag(ctrl.id);
6084
7178
  const descriptions = buildCatalogDescriptions(ctrl);
6085
7179
  const tags = buildCatalogTags(ctrl);
6086
- return {
7180
+ const req = {
6087
7181
  id: nistTag,
6088
7182
  title: ctrl.title,
6089
7183
  impact: .5,
6090
7184
  descriptions,
6091
7185
  tags
6092
7186
  };
7187
+ const controlType = deriveControlTypeFromTags([nistTag]);
7188
+ if (controlType !== void 0) req.controlType = controlType;
7189
+ if (extractPropValue(ctrl.props, "CORE") === "true") req.applicability = Applicability.Required;
7190
+ return req;
6093
7191
  }
6094
7192
  /** Creates HDF Description entries from control parts. */
6095
7193
  function buildCatalogDescriptions(ctrl) {
@@ -6870,7 +7968,10 @@ function findingsToEvaluatedRequirement(controlId, findings, obsMap, riskMap, re
6870
7968
  const descriptions = sarBuildDescriptions(findings, obsMap);
6871
7969
  const results = [];
6872
7970
  for (const f of findings) results.push(findingToRequirementResult(f, obsMap, riskMap, result));
6873
- return createRequirement(nistTag, title, descriptions, impact, results, { tags: { nist: [nistTag] } });
7971
+ const req = createRequirement(nistTag, title, descriptions, impact, results, { tags: { nist: [nistTag] } });
7972
+ const controlType = deriveControlTypeFromTags([nistTag]);
7973
+ if (controlType !== void 0) req.controlType = controlType;
7974
+ return req;
6874
7975
  }
6875
7976
  function findingToRequirementResult(f, obsMap, riskMap, result) {
6876
7977
  const status = mapFindingStatus(f);
@@ -6983,6 +8084,6 @@ function sarBaselineName(result, sar) {
6983
8084
  return toKebabCase(result.title || sar.metadata.title, "oscal-assessment-results");
6984
8085
  }
6985
8086
  //#endregion
6986
- export { convertAwsConfigToHdf, convertBurpsuiteToHdf, convertConveyorToHdf, convertCyclonedxToHdf, convertDbprotectToHdf, convertDeptrackToHdf, convertFortifyToHdf, convertGitlabToHdf, convertGosecToHdf, convertGrypeToHdf, convertHdfToCsv, convertHdfToOscalPoam, convertHdfToOscalSar, convertHdfToXccdf, convertHdfToXml, convertIonchannelToHdf, convertJfrogXrayToHdf, convertJunitToHdf, convertMsftDefenderCloudToHdf, convertMsftDefenderDevopsToHdf, convertMsftDefenderEndpointToHdf, convertMsftSecureScoreToHdf, convertNessusToHdf, convertNetsparkerToHdf, convertNeuvectorToHdf, convertNiktoToHdf, convertOscalCatalogToHdf, convertOscalComponentToHdf, convertOscalPoamToHdf, convertOscalProfileToHdf, convertOscalSapToHdf, convertOscalSarToHdf, convertOscalSspToHdf, convertPrismaToHdf, convertSarifToHdf, convertScoutsuiteToHdf, convertSnykToHdf, convertSonarqubeToHdf, convertSplunkToHdf, convertTrufflehogToHdf, convertTwistlockToHdf, convertV1ToV2, convertVeracodeToHdf, convertXccdfResultsToHdf, convertZapToHdf, detectOscalDocumentType, isHDFV1 };
8087
+ export { convertAwsConfigToHdf, convertBurpsuiteToHdf, convertCheckovToHdf, convertCklToHdf, convertCklbToHdf, convertConveyorToHdf, convertCyclonedxToHdf, convertDbprotectToHdf, convertDeptrackToHdf, convertFortifyToHdf, convertGitlabToHdf, convertGosecToHdf, convertGrypeToHdf, convertHdfToCkl, convertHdfToCklb, convertHdfToCsv, convertHdfToOscalPoam, convertHdfToOscalSar, convertHdfToXccdf, convertHdfToXml, convertIonchannelToHdf, convertJfrogXrayToHdf, convertJunitToHdf, convertMsftDefenderCloudToHdf, convertMsftDefenderDevopsToHdf, convertMsftDefenderEndpointToHdf, convertMsftSecureScoreToHdf, convertNessusToHdf, convertNetsparkerToHdf, convertNeuvectorToHdf, convertNiktoToHdf, convertOscalCatalogToHdf, convertOscalComponentToHdf, convertOscalPoamToHdf, convertOscalProfileToHdf, convertOscalSapToHdf, convertOscalSarToHdf, convertOscalSspToHdf, convertPrismaToHdf, convertSarifToHdf, convertScoutsuiteToHdf, convertSnykToHdf, convertSonarqubeToHdf, convertSplunkToHdf, convertTrufflehogToHdf, convertTwistlockToHdf, convertV1ToV2, convertVeracodeToHdf, convertXccdfResultsToHdf, convertZapToHdf, detectOscalDocumentType, isHDFV1 };
6987
8088
 
6988
8089
  //# sourceMappingURL=index.js.map