@mitre/hdf-converters 3.1.0-rc.1 → 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/README.md +5 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +1 -1
- package/dist/index.d.ts +69 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1167 -66
- package/dist/index.js.map +1 -1
- package/dist/{register-all-DaYHszLd.js → register-all-ik8sNfNf.js} +68 -7
- package/dist/register-all-ik8sNfNf.js.map +1 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js.map +1 -1
- package/package.json +7 -7
- package/dist/register-all-DaYHszLd.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as detectConverter, t as registerAllFingerprints } from "./register-all-
|
|
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
|
-
|
|
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$
|
|
814
|
-
const ARRAY_TAGS$
|
|
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$
|
|
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$
|
|
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
|
-
|
|
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
|
-
|
|
1151
|
-
if (nistTags.length > 0) tags["nist"] =
|
|
1297
|
+
nistTags = [...new Set(cciIds.flatMap((cci) => getCCINistMappings(cci) ?? []))];
|
|
1298
|
+
if (nistTags.length > 0) tags["nist"] = nistTags;
|
|
1152
1299
|
}
|
|
1153
|
-
|
|
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$
|
|
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
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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
|
-
|
|
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
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
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
|
-
|
|
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$
|
|
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
|
-
|
|
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$
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|