@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.
@@ -1,12 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.processInSpecProfile = exports.processExecJSON = exports.processProfileJSON = exports.processEvaluation = void 0;
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
- exports.processEvaluation = processEvaluation;
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
- exports.processProfileJSON = processProfileJSON;
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
- exports.processExecJSON = processExecJSON;
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;
@@ -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;
@@ -1,9 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.processOVAL = exports.extractAllCriteriaRefs = void 0;
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
- // https://stackoverflow.com/questions/9133500/how-to-find-a-node-in-a-tree-with-javascript
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
- exports.extractAllCriteriaRefs = extractAllCriteriaRefs;
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;
@@ -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 declare type GroupContextualizedRule = BenchmarkRule & {
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;
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.processXCCDF = exports.extractAllComplexChecks = exports.extractAllRules = void 0;
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
- exports.extractAllRules = extractAllRules;
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
- exports.extractAllComplexChecks = extractAllComplexChecks;
41
- function ensureDecodedXMLStringValue(input) {
42
- return lodash_1.default.get(input, '[0].#text') ? lodash_1.default.get(input, '[0].#text') : input;
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
- // Moving the newline removal to diff library rather than processXCCDF level
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
- control.title = (0, xccdf_1.removeXMLSpecialCharacters)(rule['@_severity'] ? ensureDecodedXMLStringValue(rule.title) : `[[[MISSING SEVERITY FROM BENCHMARK]]] ${ensureDecodedXMLStringValue(rule.title)}`);
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', rule.group['@_id']);
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
- control.descs.check = (0, xccdf_1.removeXMLSpecialCharacters)(ovalDefinitions[referenceID].metadata[0].title);
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 === 'string') {
207
- control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)(rule.fixtext);
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', control.id || 'Unknown'));
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 (typeof value === 'string') {
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;
@@ -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>;