@mitre/inspec-objects 1.0.0 → 2.0.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/.github/dependabot.yml +11 -0
- package/.github/workflows/auto-approve-and-merge.yml +22 -0
- package/.github/workflows/e2e-test.yml +1 -1
- package/.github/workflows/linter.yml +1 -2
- package/README.md +45 -4
- package/lib/index.d.ts +4 -2
- package/lib/index.js +5 -2
- package/lib/objects/control.d.ts +78 -0
- package/lib/objects/control.js +111 -19
- package/lib/objects/profile.d.ts +58 -0
- package/lib/objects/profile.js +60 -1
- package/lib/parsers/json.d.ts +32 -0
- package/lib/parsers/json.js +36 -5
- package/lib/parsers/oval.d.ts +28 -0
- package/lib/parsers/oval.js +45 -5
- package/lib/parsers/xccdf.d.ts +32 -1
- package/lib/parsers/xccdf.js +84 -38
- package/lib/utilities/diff.d.ts +42 -0
- package/lib/utilities/diff.js +51 -12
- package/lib/utilities/diffMarkdown.d.ts +13 -0
- package/lib/utilities/diffMarkdown.js +24 -12
- package/lib/utilities/global.d.ts +53 -0
- package/lib/utilities/global.js +92 -13
- package/lib/utilities/logging.d.ts +1 -1
- package/lib/utilities/logging.js +8 -5
- package/lib/utilities/update.d.ts +60 -1
- package/lib/utilities/update.js +132 -42
- package/lib/utilities/xccdf.d.ts +82 -1
- package/lib/utilities/xccdf.js +113 -22
- package/package.json +17 -17
package/lib/parsers/json.js
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.processEvaluation = processEvaluation;
|
|
4
|
+
exports.processProfileJSON = processProfileJSON;
|
|
5
|
+
exports.processExecJSON = processExecJSON;
|
|
6
|
+
exports.processInSpecProfile = processInSpecProfile;
|
|
4
7
|
const tslib_1 = require("tslib");
|
|
5
8
|
const inspecjs_1 = require("inspecjs");
|
|
6
9
|
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
7
10
|
const control_1 = tslib_1.__importStar(require("../objects/control"));
|
|
8
11
|
const profile_1 = tslib_1.__importDefault(require("../objects/profile"));
|
|
9
12
|
const update_1 = require("../utilities/update");
|
|
13
|
+
/**
|
|
14
|
+
* Processes a contextualized evaluation input and converts it into a Profile object.
|
|
15
|
+
*
|
|
16
|
+
* @param evaluationInput - The contextualized evaluation input containing profile and control data.
|
|
17
|
+
* @returns A Profile object populated with the data from the evaluation input.
|
|
18
|
+
*/
|
|
10
19
|
function processEvaluation(evaluationInput) {
|
|
11
20
|
const topLevelProfile = evaluationInput.contains[0];
|
|
12
21
|
const profile = new profile_1.default({
|
|
@@ -32,7 +41,12 @@ function processEvaluation(evaluationInput) {
|
|
|
32
41
|
});
|
|
33
42
|
return profile;
|
|
34
43
|
}
|
|
35
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Processes a contextualized profile JSON object and converts it into a Profile instance.
|
|
46
|
+
*
|
|
47
|
+
* @param profileInput - The contextualized profile input containing profile data and controls.
|
|
48
|
+
* @returns A Profile instance populated with the data from the input.
|
|
49
|
+
*/
|
|
36
50
|
function processProfileJSON(profileInput) {
|
|
37
51
|
const profile = new profile_1.default({
|
|
38
52
|
name: profileInput.data.name,
|
|
@@ -71,11 +85,29 @@ function processProfileJSON(profileInput) {
|
|
|
71
85
|
});
|
|
72
86
|
return profile;
|
|
73
87
|
}
|
|
74
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Processes the given ExecJSON execution object and returns a Profile.
|
|
90
|
+
*
|
|
91
|
+
* This function takes an ExecJSON execution object, contextualizes the evaluation,
|
|
92
|
+
* and then processes the evaluation to produce a Profile.
|
|
93
|
+
*
|
|
94
|
+
* @param execJSON - The ExecJSON execution object to be processed.
|
|
95
|
+
* @returns The processed Profile.
|
|
96
|
+
*/
|
|
75
97
|
function processExecJSON(execJSON) {
|
|
76
98
|
return processEvaluation((0, inspecjs_1.contextualizeEvaluation)(execJSON));
|
|
77
99
|
}
|
|
78
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Processes an InSpec profile from a JSON string.
|
|
102
|
+
*
|
|
103
|
+
* This function takes a JSON string representing an InSpec profile, converts it,
|
|
104
|
+
* and processes it to return a `Profile` object. It handles different versions
|
|
105
|
+
* of the InSpec JSON format and sorts the controls by their ID.
|
|
106
|
+
*
|
|
107
|
+
* @param json - The JSON string representing the InSpec profile.
|
|
108
|
+
* @returns A `Profile` object containing the processed profile data.
|
|
109
|
+
* @throws Will throw an error if the JSON string does not match known InSpec formats.
|
|
110
|
+
*/
|
|
79
111
|
function processInSpecProfile(json) {
|
|
80
112
|
const convertedFile = (0, inspecjs_1.convertFile)(json, true);
|
|
81
113
|
let profile = new profile_1.default();
|
|
@@ -91,4 +123,3 @@ function processInSpecProfile(json) {
|
|
|
91
123
|
profile.controls = lodash_1.default.sortBy(profile.controls, 'id');
|
|
92
124
|
return profile;
|
|
93
125
|
}
|
|
94
|
-
exports.processInSpecProfile = processInSpecProfile;
|
package/lib/parsers/oval.d.ts
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
1
|
import { OvalDefinitionValue, DefinitionCriterion } from '../types/oval';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts all test references from a list of initial criteria.
|
|
4
|
+
*
|
|
5
|
+
* This function recursively traverses the provided criteria and extracts
|
|
6
|
+
* all test references (`@_test_ref`) from each criterion. It returns an
|
|
7
|
+
* array of all found test references.
|
|
8
|
+
*
|
|
9
|
+
* @param initialCriteria - An array of `DefinitionCriterion` objects to extract test references from.
|
|
10
|
+
* @returns An array of strings containing all extracted test references.
|
|
11
|
+
*/
|
|
2
12
|
export declare function extractAllCriteriaRefs(initialCriteria: DefinitionCriterion[]): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Processes an OVAL (Open Vulnerability and Assessment Language) XML string and converts it into a JSON object.
|
|
15
|
+
* Extracts definitions and their associated criteria references and resolved values.
|
|
16
|
+
* The function performs the following steps:
|
|
17
|
+
* 1. Converts the OVAL XML string into a JSON object.
|
|
18
|
+
* 2. Iterates through the OVAL definitions and extracts each definition.
|
|
19
|
+
* 3. For each definition, extracts criteria references and resolves the associated objects and states.
|
|
20
|
+
* 4. Logs warnings if any objects or states cannot be found.
|
|
21
|
+
*
|
|
22
|
+
* The returned record contains:
|
|
23
|
+
* - The original definition.
|
|
24
|
+
* - An array of criteria references.
|
|
25
|
+
* - An array of resolved values, each containing the original criteria, resolved objects, and resolved states.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} [oval] - The OVAL XML string to be processed. If not provided, the function returns `undefined`.
|
|
28
|
+
* @returns {Record<string, OvalDefinitionValue> | undefined} - A record of extracted definitions with their
|
|
29
|
+
* criteria references and resolved values, or `undefined` if no OVAL string is provided.
|
|
30
|
+
*/
|
|
3
31
|
export declare function processOVAL(oval?: string): Record<string, OvalDefinitionValue> | undefined;
|
package/lib/parsers/oval.js
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.extractAllCriteriaRefs = extractAllCriteriaRefs;
|
|
4
|
+
exports.processOVAL = processOVAL;
|
|
4
5
|
const xccdf_1 = require("../utilities/xccdf");
|
|
5
6
|
const logging_1 = require("../utilities/logging");
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Search through all arrays of the tree to find a value from a property
|
|
9
|
+
* Code provided by:
|
|
10
|
+
* https://stackoverflow.com/questions/9133500/how-to-find-a-node-in-a-tree-with-javascript
|
|
11
|
+
*
|
|
12
|
+
* @param aTree : The tree array
|
|
13
|
+
* @param fCompair : This function will receive each node. Define based on caller for specific
|
|
14
|
+
condition necessary for the match. It must return true if the condition
|
|
15
|
+
is matched. Example:
|
|
16
|
+
function(oNode){ if(oNode["Name"] === "AA") return true; }
|
|
17
|
+
* @param bGreedy? : Set to `true` to search all node and not stopping after the first match, default is false
|
|
18
|
+
* @return An array with references to the nodes for which fCompair was true. In case no node was found an empty array
|
|
19
|
+
* will be returned
|
|
20
|
+
*/
|
|
7
21
|
function searchTree(aTree, fCompair, bGreedy) {
|
|
8
22
|
let oNode; // always the current node
|
|
9
23
|
const aInnerTree = []; // will contain the inner children
|
|
@@ -36,6 +50,16 @@ function searchTree(aTree, fCompair, bGreedy) {
|
|
|
36
50
|
}
|
|
37
51
|
return aReturnNodes;
|
|
38
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Extracts all test references from a list of initial criteria.
|
|
55
|
+
*
|
|
56
|
+
* This function recursively traverses the provided criteria and extracts
|
|
57
|
+
* all test references (`@_test_ref`) from each criterion. It returns an
|
|
58
|
+
* array of all found test references.
|
|
59
|
+
*
|
|
60
|
+
* @param initialCriteria - An array of `DefinitionCriterion` objects to extract test references from.
|
|
61
|
+
* @returns An array of strings containing all extracted test references.
|
|
62
|
+
*/
|
|
39
63
|
function extractAllCriteriaRefs(initialCriteria) {
|
|
40
64
|
const criteriaRefs = [];
|
|
41
65
|
initialCriteria.forEach(criteria => {
|
|
@@ -51,10 +75,27 @@ function extractAllCriteriaRefs(initialCriteria) {
|
|
|
51
75
|
});
|
|
52
76
|
return criteriaRefs;
|
|
53
77
|
}
|
|
54
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Processes an OVAL (Open Vulnerability and Assessment Language) XML string and converts it into a JSON object.
|
|
80
|
+
* Extracts definitions and their associated criteria references and resolved values.
|
|
81
|
+
* The function performs the following steps:
|
|
82
|
+
* 1. Converts the OVAL XML string into a JSON object.
|
|
83
|
+
* 2. Iterates through the OVAL definitions and extracts each definition.
|
|
84
|
+
* 3. For each definition, extracts criteria references and resolves the associated objects and states.
|
|
85
|
+
* 4. Logs warnings if any objects or states cannot be found.
|
|
86
|
+
*
|
|
87
|
+
* The returned record contains:
|
|
88
|
+
* - The original definition.
|
|
89
|
+
* - An array of criteria references.
|
|
90
|
+
* - An array of resolved values, each containing the original criteria, resolved objects, and resolved states.
|
|
91
|
+
*
|
|
92
|
+
* @param {string} [oval] - The OVAL XML string to be processed. If not provided, the function returns `undefined`.
|
|
93
|
+
* @returns {Record<string, OvalDefinitionValue> | undefined} - A record of extracted definitions with their
|
|
94
|
+
* criteria references and resolved values, or `undefined` if no OVAL string is provided.
|
|
95
|
+
*/
|
|
55
96
|
function processOVAL(oval) {
|
|
56
97
|
var _a;
|
|
57
|
-
const logger = (0, logging_1.createWinstonLogger)();
|
|
98
|
+
const logger = (0, logging_1.createWinstonLogger)('ts-inspec-objects');
|
|
58
99
|
if (!oval) {
|
|
59
100
|
return undefined;
|
|
60
101
|
}
|
|
@@ -114,4 +155,3 @@ function processOVAL(oval) {
|
|
|
114
155
|
}
|
|
115
156
|
return extractedDefinitions;
|
|
116
157
|
}
|
|
117
|
-
exports.processOVAL = processOVAL;
|
package/lib/parsers/xccdf.d.ts
CHANGED
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
import Profile from '../objects/profile';
|
|
2
2
|
import { BenchmarkGroup, BenchmarkRule, RuleComplexCheck } from '../types/xccdf';
|
|
3
3
|
import { OvalDefinitionValue } from '../types/oval';
|
|
4
|
-
export
|
|
4
|
+
export type GroupContextualizedRule = BenchmarkRule & {
|
|
5
5
|
group: Omit<BenchmarkGroup, 'Rule' | 'Group'>;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Extracts all rules from the given benchmark groups, including nested groups.
|
|
9
|
+
*
|
|
10
|
+
* @param groups - An array of benchmark groups to extract rules from.
|
|
11
|
+
* @returns An array of contextualized rules, each rule includes its parent group context.
|
|
12
|
+
*/
|
|
7
13
|
export declare function extractAllRules(groups: BenchmarkGroup[]): GroupContextualizedRule[];
|
|
14
|
+
/**
|
|
15
|
+
* Extracts all nested complex checks from a given `RuleComplexCheck` object.
|
|
16
|
+
*
|
|
17
|
+
* This function recursively traverses the `complex-check` property of the input
|
|
18
|
+
* `RuleComplexCheck` object and collects all nested complex checks into a flat array.
|
|
19
|
+
* Each complex check in the resulting array will have its own `complex-check` property omitted.
|
|
20
|
+
*
|
|
21
|
+
* @param complexCheck - The `RuleComplexCheck` object to extract complex checks from.
|
|
22
|
+
* @returns An array of `RuleComplexCheck` objects with the `complex-check` property omitted.
|
|
23
|
+
*/
|
|
8
24
|
export declare function extractAllComplexChecks(complexCheck: RuleComplexCheck): Omit<RuleComplexCheck, 'complex-check'>[];
|
|
25
|
+
export type InputTextLang = {
|
|
26
|
+
'#text': string;
|
|
27
|
+
'@_lang': string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Processes an XCCDF XML string and converts it into a Profile object.
|
|
31
|
+
* Note: Moved the newline removal to diff library rather than here.
|
|
32
|
+
*
|
|
33
|
+
* @param xml - The XCCDF XML string to process.
|
|
34
|
+
* @param removeNewlines - A flag indicating whether to remove newlines from the processed data.
|
|
35
|
+
* @param useRuleId - Specifies the rule ID format to use. Can be 'group', 'rule', 'version', or 'cis'.
|
|
36
|
+
* @param ovalDefinitions - Optional OVAL definitions to use for resolving values.
|
|
37
|
+
* @returns A Profile object representing the processed XCCDF data.
|
|
38
|
+
* @throws Will throw an error if the XCCDF file is not properly formatted or if required data is missing.
|
|
39
|
+
*/
|
|
9
40
|
export declare function processXCCDF(xml: string, removeNewlines: false, useRuleId: 'group' | 'rule' | 'version' | 'cis', ovalDefinitions?: Record<string, OvalDefinitionValue & {
|
|
10
41
|
criteriaRefs?: string[];
|
|
11
42
|
resolvedValues?: any;
|
package/lib/parsers/xccdf.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.extractAllRules = extractAllRules;
|
|
4
|
+
exports.extractAllComplexChecks = extractAllComplexChecks;
|
|
5
|
+
exports.processXCCDF = processXCCDF;
|
|
4
6
|
const tslib_1 = require("tslib");
|
|
5
7
|
const profile_1 = tslib_1.__importDefault(require("../objects/profile"));
|
|
6
8
|
const xccdf_1 = require("../utilities/xccdf");
|
|
@@ -9,6 +11,12 @@ const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
|
9
11
|
const CciNistMappingData_1 = require("../mappings/CciNistMappingData");
|
|
10
12
|
const pretty_1 = tslib_1.__importDefault(require("pretty"));
|
|
11
13
|
const logging_1 = require("../utilities/logging");
|
|
14
|
+
/**
|
|
15
|
+
* Extracts all rules from the given benchmark groups, including nested groups.
|
|
16
|
+
*
|
|
17
|
+
* @param groups - An array of benchmark groups to extract rules from.
|
|
18
|
+
* @returns An array of contextualized rules, each rule includes its parent group context.
|
|
19
|
+
*/
|
|
12
20
|
function extractAllRules(groups) {
|
|
13
21
|
const rules = [];
|
|
14
22
|
groups.forEach((group) => {
|
|
@@ -26,7 +34,16 @@ function extractAllRules(groups) {
|
|
|
26
34
|
});
|
|
27
35
|
return rules;
|
|
28
36
|
}
|
|
29
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Extracts all nested complex checks from a given `RuleComplexCheck` object.
|
|
39
|
+
*
|
|
40
|
+
* This function recursively traverses the `complex-check` property of the input
|
|
41
|
+
* `RuleComplexCheck` object and collects all nested complex checks into a flat array.
|
|
42
|
+
* Each complex check in the resulting array will have its own `complex-check` property omitted.
|
|
43
|
+
*
|
|
44
|
+
* @param complexCheck - The `RuleComplexCheck` object to extract complex checks from.
|
|
45
|
+
* @returns An array of `RuleComplexCheck` objects with the `complex-check` property omitted.
|
|
46
|
+
*/
|
|
30
47
|
function extractAllComplexChecks(complexCheck) {
|
|
31
48
|
const complexChecks = [lodash_1.default.omit(complexCheck, 'complex-check')];
|
|
32
49
|
if (complexCheck['complex-check']) {
|
|
@@ -37,13 +54,32 @@ function extractAllComplexChecks(complexCheck) {
|
|
|
37
54
|
}
|
|
38
55
|
return complexChecks;
|
|
39
56
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Ensures that the input is decoded as an XML string value.
|
|
59
|
+
*
|
|
60
|
+
* @param input - The input value which can be either a string or an array of
|
|
61
|
+
* InputTextLang objects.
|
|
62
|
+
* @param defaultValue - The default string value to return if the input is
|
|
63
|
+
* not a string.
|
|
64
|
+
* @returns The decoded XML string value if the input is a string, otherwise the
|
|
65
|
+
* value from the first element of the input array or the default value.
|
|
66
|
+
*/
|
|
67
|
+
function ensureDecodedXMLStringValue(input, defaultValue) {
|
|
68
|
+
return lodash_1.default.isString(input) ? input : lodash_1.default.get(input, '[0].#text', defaultValue);
|
|
43
69
|
}
|
|
44
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Processes an XCCDF XML string and converts it into a Profile object.
|
|
72
|
+
* Note: Moved the newline removal to diff library rather than here.
|
|
73
|
+
*
|
|
74
|
+
* @param xml - The XCCDF XML string to process.
|
|
75
|
+
* @param removeNewlines - A flag indicating whether to remove newlines from the processed data.
|
|
76
|
+
* @param useRuleId - Specifies the rule ID format to use. Can be 'group', 'rule', 'version', or 'cis'.
|
|
77
|
+
* @param ovalDefinitions - Optional OVAL definitions to use for resolving values.
|
|
78
|
+
* @returns A Profile object representing the processed XCCDF data.
|
|
79
|
+
* @throws Will throw an error if the XCCDF file is not properly formatted or if required data is missing.
|
|
80
|
+
*/
|
|
45
81
|
function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
46
|
-
const logger = (0, logging_1.createWinstonLogger)();
|
|
82
|
+
const logger = (0, logging_1.createWinstonLogger)('ts-inspec-objects');
|
|
47
83
|
const parsedXML = (0, xccdf_1.convertEncodedXmlIntoJson)(xml);
|
|
48
84
|
if (parsedXML.Benchmark === undefined) {
|
|
49
85
|
throw new Error('Could not process the XCCDF file, check the input to make sure this is a properly formatted XCCDF file.');
|
|
@@ -85,11 +121,11 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
85
121
|
control.id = rule.group['@_id'];
|
|
86
122
|
break;
|
|
87
123
|
case 'rule':
|
|
88
|
-
if (rule['@_id'].toLowerCase().startsWith('sv')) {
|
|
89
|
-
control.id = rule['@_id'].split('r')[0];
|
|
124
|
+
if (rule['@_id'][0].toLowerCase().startsWith('sv')) {
|
|
125
|
+
control.id = rule['@_id'][0].split('r')[0];
|
|
90
126
|
}
|
|
91
127
|
else {
|
|
92
|
-
control.id = rule['@_id'];
|
|
128
|
+
control.id = rule['@_id'][0];
|
|
93
129
|
}
|
|
94
130
|
break;
|
|
95
131
|
case 'version':
|
|
@@ -110,7 +146,10 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
110
146
|
default:
|
|
111
147
|
throw new Error('useRuleId must be one of "group", "rule", or "version"');
|
|
112
148
|
}
|
|
113
|
-
|
|
149
|
+
if (!(lodash_1.default.isArray(rule.title) && rule.title.length === 1)) {
|
|
150
|
+
throw new Error('Rule title is not an array of length 1. Investigate if the file is in the proper format.');
|
|
151
|
+
}
|
|
152
|
+
control.title = (0, xccdf_1.removeXMLSpecialCharacters)(rule['@_severity'] ? ensureDecodedXMLStringValue(rule.title[0], 'undefined title') : `[[[MISSING SEVERITY FROM BENCHMARK]]] ${ensureDecodedXMLStringValue(rule.title[0], 'undefined title')}`);
|
|
114
153
|
if (typeof extractedDescription === 'object' && !Array.isArray(extractedDescription)) {
|
|
115
154
|
control.desc = ((_a = extractedDescription.VulnDiscussion) === null || _a === void 0 ? void 0 : _a.split('Satisfies: ')[0]) || '';
|
|
116
155
|
}
|
|
@@ -123,13 +162,13 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
123
162
|
else {
|
|
124
163
|
logger.warn(`Invalid value for extracted description: ${extractedDescription}`);
|
|
125
164
|
}
|
|
126
|
-
control.impact = (0, xccdf_1.severityStringToImpact)(rule['@_severity'] || 'medium'
|
|
165
|
+
control.impact = (0, xccdf_1.severityStringToImpact)(rule['@_severity'] || 'medium');
|
|
127
166
|
if (!control.descs || Array.isArray(control.descs)) {
|
|
128
167
|
control.descs = {};
|
|
129
168
|
}
|
|
130
169
|
if (rule.check) {
|
|
131
170
|
if (rule.check.some((ruleValue) => 'check-content' in ruleValue)) {
|
|
132
|
-
control.descs.check = (0, xccdf_1.removeXMLSpecialCharacters)(rule.check ? rule.check[0]['check-content'] : 'Missing description');
|
|
171
|
+
control.descs.check = (0, xccdf_1.removeXMLSpecialCharacters)(rule.check ? rule.check[0]['check-content'][0] : 'Missing description');
|
|
133
172
|
control.tags.check_id = rule.check[0]['@_system'];
|
|
134
173
|
}
|
|
135
174
|
else if (rule.check.some((ruleValue) => 'check-content-ref' in ruleValue) && ovalDefinitions) {
|
|
@@ -145,7 +184,8 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
145
184
|
}
|
|
146
185
|
}
|
|
147
186
|
if (referenceID && referenceID in ovalDefinitions) {
|
|
148
|
-
|
|
187
|
+
// May need to further check if ovalDefinitions[referenceID].metadata[0].title[0] are not populated?
|
|
188
|
+
control.descs.check = (0, xccdf_1.removeXMLSpecialCharacters)(ovalDefinitions[referenceID].metadata[0].title[0]);
|
|
149
189
|
}
|
|
150
190
|
else if (referenceID) {
|
|
151
191
|
logger.warn(`Could not find OVAL definition for ${referenceID}`);
|
|
@@ -164,7 +204,7 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
164
204
|
if (complexCheck.check) {
|
|
165
205
|
complexCheck.check.forEach((check) => {
|
|
166
206
|
var _a;
|
|
167
|
-
if ((_a = check['@_system']) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes('oval')) {
|
|
207
|
+
if ((_a = check['@_system']) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase().includes('oval')) {
|
|
168
208
|
const ovalReference = check['check-content-ref'][0]['@_name'];
|
|
169
209
|
if (!ovalDefinitions) {
|
|
170
210
|
logger.warn(`Missing OVAL definitions! Unable to process OVAL reference: ${ovalReference}`);
|
|
@@ -203,12 +243,17 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
203
243
|
if (lodash_1.default.get(rule.fixtext, '[0]["#text"]')) {
|
|
204
244
|
control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)(rule.fixtext[0]['#text']);
|
|
205
245
|
}
|
|
206
|
-
else if (typeof rule.fixtext === '
|
|
207
|
-
|
|
246
|
+
else if (typeof rule.fixtext === 'undefined') {
|
|
247
|
+
if (rule.fix && rule.fix[0]) {
|
|
248
|
+
control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)(rule.fix[0]['#text'] || 'Missing fix text');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else if (typeof rule.fixtext[0] === 'string') {
|
|
252
|
+
control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)(rule.fixtext[0]);
|
|
208
253
|
}
|
|
209
|
-
else if (typeof rule.fixtext === 'object') {
|
|
210
|
-
if (Array.isArray(rule.fixtext)) {
|
|
211
|
-
control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)((0, pretty_1.default)((0, xccdf_1.convertJsonIntoXML)(rule.fixtext.map((fixtext) => {
|
|
254
|
+
else if (typeof rule.fixtext[0] === 'object') {
|
|
255
|
+
if (Array.isArray(rule.fixtext[0])) {
|
|
256
|
+
control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)((0, pretty_1.default)((0, xccdf_1.convertJsonIntoXML)(rule.fixtext[0].map((fixtext) => {
|
|
212
257
|
if (fixtext.div) {
|
|
213
258
|
return fixtext.div;
|
|
214
259
|
}
|
|
@@ -221,23 +266,18 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
221
266
|
control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)((0, pretty_1.default)((0, xccdf_1.convertJsonIntoXML)(rule.fixtext)));
|
|
222
267
|
}
|
|
223
268
|
}
|
|
224
|
-
else if (typeof rule.fixtext === 'undefined') {
|
|
225
|
-
if (rule.fix && rule.fix[0]) {
|
|
226
|
-
control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)(rule.fix[0]['#text'] || 'Missing fix text');
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
269
|
else {
|
|
230
270
|
control.descs.fix = 'Missing fix text';
|
|
231
271
|
}
|
|
232
|
-
control.tags.severity = (0, xccdf_1.impactNumberToSeverityString)((0, xccdf_1.severityStringToImpact)(rule['@_severity'] || 'medium'
|
|
272
|
+
control.tags.severity = (0, xccdf_1.impactNumberToSeverityString)((0, xccdf_1.severityStringToImpact)(rule['@_severity'] || 'medium'));
|
|
233
273
|
control.tags.gid = rule.group['@_id'],
|
|
234
274
|
control.tags.rid = rule['@_id'];
|
|
235
275
|
control.tags.stig_id = rule['version'];
|
|
236
|
-
if (typeof rule.group.title === 'string') {
|
|
237
|
-
control.tags.gtitle = (0, xccdf_1.removeXMLSpecialCharacters)(rule.group.title);
|
|
276
|
+
if (typeof rule.group.title[0] === 'string') {
|
|
277
|
+
control.tags.gtitle = (0, xccdf_1.removeXMLSpecialCharacters)(rule.group.title[0]);
|
|
238
278
|
}
|
|
239
279
|
else {
|
|
240
|
-
control.tags.gtitle = (0, xccdf_1.removeXMLSpecialCharacters)(lodash_1.default.get(rule.group, 'title[0].#text'));
|
|
280
|
+
control.tags.gtitle = (0, xccdf_1.removeXMLSpecialCharacters)(lodash_1.default.get(rule.group, 'title[0].#text', 'undefined title'));
|
|
241
281
|
}
|
|
242
282
|
if (rule['fix'] && rule['fix'].length > 0) {
|
|
243
283
|
control.tags.fix_id = rule['fix'][0]['@_id'];
|
|
@@ -260,7 +300,15 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
260
300
|
control.tags.ia_controls = extractedDescription.IAControls || undefined;
|
|
261
301
|
}
|
|
262
302
|
control.tags = lodash_1.default.mapValues(lodash_1.default.omitBy(control.tags, (value) => value === undefined), (value) => {
|
|
263
|
-
if (
|
|
303
|
+
if (value && Array.isArray(value)) {
|
|
304
|
+
if (Array.isArray(value[0])) {
|
|
305
|
+
return (0, xccdf_1.removeXMLSpecialCharacters)(value[0][0]);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
return (0, xccdf_1.removeXMLSpecialCharacters)(value[0]);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
else if (typeof value === 'string') {
|
|
264
312
|
return (0, xccdf_1.removeXMLSpecialCharacters)(value);
|
|
265
313
|
}
|
|
266
314
|
else {
|
|
@@ -272,21 +320,21 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
272
320
|
rule.ident.forEach((identifier) => {
|
|
273
321
|
var _a, _b, _c;
|
|
274
322
|
// Get CCIs
|
|
275
|
-
if (identifier['@_system'].toLowerCase().includes('cci')) {
|
|
323
|
+
if (identifier['@_system'][0].toLowerCase().includes('cci')) {
|
|
276
324
|
if (!('cci' in control.tags)) {
|
|
277
325
|
control.tags.cci = [];
|
|
278
326
|
}
|
|
279
327
|
(_a = control.tags.cci) === null || _a === void 0 ? void 0 : _a.push(identifier['#text']);
|
|
280
328
|
}
|
|
281
329
|
// Get legacy identifiers
|
|
282
|
-
else if (identifier['@_system'].toLowerCase().includes('legacy')) {
|
|
330
|
+
else if (identifier['@_system'][0].toLowerCase().includes('legacy')) {
|
|
283
331
|
if (!('legacy' in control.tags)) {
|
|
284
332
|
control.tags.legacy = [];
|
|
285
333
|
}
|
|
286
334
|
(_b = control.tags.legacy) === null || _b === void 0 ? void 0 : _b.push(identifier['#text']);
|
|
287
335
|
}
|
|
288
336
|
// Get NIST identifiers
|
|
289
|
-
else if (identifier['@_system'].toLowerCase().includes('nist')) {
|
|
337
|
+
else if (identifier['@_system'].toString().toLowerCase().includes('nist')) {
|
|
290
338
|
if (!('nist' in control.tags)) {
|
|
291
339
|
control.tags.nist = [];
|
|
292
340
|
}
|
|
@@ -297,14 +345,14 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
297
345
|
(_c = rule.reference) === null || _c === void 0 ? void 0 : _c.forEach((reference) => {
|
|
298
346
|
var _a, _b, _c, _d;
|
|
299
347
|
if (lodash_1.default.get(reference, '@_href') === '') {
|
|
300
|
-
(_a = control.refs) === null || _a === void 0 ? void 0 : _a.push(lodash_1.default.get(reference, '#text'));
|
|
348
|
+
(_a = control.refs) === null || _a === void 0 ? void 0 : _a.push(lodash_1.default.get(reference, '#text', 'undefined href'));
|
|
301
349
|
}
|
|
302
350
|
else {
|
|
303
351
|
try {
|
|
304
352
|
const referenceText = lodash_1.default.get(reference, '#text') || '';
|
|
305
353
|
const referenceURL = lodash_1.default.get(reference, '@_href') || '';
|
|
306
354
|
if (referenceURL) {
|
|
307
|
-
const parsedURL = new URL(lodash_1.default.get(reference, '@_href'));
|
|
355
|
+
const parsedURL = new URL(lodash_1.default.get(reference, '@_href', 'undefined href'));
|
|
308
356
|
if (parsedURL.protocol.toLowerCase().includes('http') || parsedURL.protocol.toLowerCase().includes('https')) {
|
|
309
357
|
(_b = control.refs) === null || _b === void 0 ? void 0 : _b.push({
|
|
310
358
|
ref: referenceText,
|
|
@@ -341,8 +389,7 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
341
389
|
}
|
|
342
390
|
}
|
|
343
391
|
else {
|
|
344
|
-
logger.warn('Reference parts of invalid length:');
|
|
345
|
-
logger.info(referenceParts);
|
|
392
|
+
logger.warn('Reference parts of invalid length: ', referenceParts);
|
|
346
393
|
}
|
|
347
394
|
}
|
|
348
395
|
}
|
|
@@ -370,4 +417,3 @@ function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
|
370
417
|
profile.controls = lodash_1.default.sortBy(profile.controls, 'id');
|
|
371
418
|
return profile.toUnformattedObject();
|
|
372
419
|
}
|
|
373
|
-
exports.processXCCDF = processXCCDF;
|
package/lib/utilities/diff.d.ts
CHANGED
|
@@ -1,8 +1,50 @@
|
|
|
1
1
|
import Profile from '../objects/profile';
|
|
2
2
|
import { ProfileDiff } from '../types/diff';
|
|
3
3
|
import winston from 'winston';
|
|
4
|
+
/**
|
|
5
|
+
* Removes newlines from all string values within a nested object.
|
|
6
|
+
*
|
|
7
|
+
* This function recursively traverses the provided object and replaces
|
|
8
|
+
* newline characters (`\n`) in string values with the placeholder `{{{{newlineHERE}}}}`.
|
|
9
|
+
* It also trims any leading or trailing whitespace from the string values.
|
|
10
|
+
*
|
|
11
|
+
* @param control - The object from which to remove newlines. If not provided,
|
|
12
|
+
* an empty object is returned.
|
|
13
|
+
* @returns A new object with newlines removed from all string values.
|
|
14
|
+
*/
|
|
4
15
|
export declare function removeNewlines(control?: Record<string, unknown>): Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* Processes a diff object to ignore formatting differences such as whitespace.
|
|
18
|
+
* Goal is to use a linter for the formatting and compare characters without
|
|
19
|
+
* whitespaces here.
|
|
20
|
+
*
|
|
21
|
+
* The function performs the following:
|
|
22
|
+
* - If the diff value has a `__new` property, it compares the `__new` and
|
|
23
|
+
* `__old` values after removing whitespace. If they are different, it sets
|
|
24
|
+
* the result to the `__new` value.
|
|
25
|
+
* - If the diff value is an array, it maps and filters the array to include
|
|
26
|
+
* only the new values.
|
|
27
|
+
* - If the diff value is an object, it recursively processes the object.
|
|
28
|
+
* - If the key ends with `__deleted`, it ignores the value.
|
|
29
|
+
* - Otherwise, it sets the result to the diff value.
|
|
30
|
+
*
|
|
31
|
+
* @param diffData - The diff object containing differences to process.
|
|
32
|
+
* @returns A new object with formatting differences ignored.
|
|
33
|
+
*
|
|
34
|
+
|
|
35
|
+
*/
|
|
5
36
|
export declare function ignoreFormattingDiff(diffData: Record<string, unknown>): Record<string, unknown>;
|
|
37
|
+
/**
|
|
38
|
+
* Computes the differences between two profiles and logs the process.
|
|
39
|
+
*
|
|
40
|
+
* @param fromProfile - The original profile to compare from.
|
|
41
|
+
* @param toProfile - The target profile to compare to.
|
|
42
|
+
* @param logger - The logger instance to use for logging information.
|
|
43
|
+
*
|
|
44
|
+
* @returns An object containing two properties:
|
|
45
|
+
* - `ignoreFormattingDiff`: The profile differences ignoring formatting changes.
|
|
46
|
+
* - `rawDiff`: The raw profile differences.
|
|
47
|
+
*/
|
|
6
48
|
export declare function diffProfile(fromProfile: Profile, toProfile: Profile, logger: winston.Logger): {
|
|
7
49
|
ignoreFormattingDiff: ProfileDiff;
|
|
8
50
|
rawDiff: Record<string, unknown>;
|