@mitre/inspec-objects 0.0.13 → 0.0.14

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.
@@ -8,6 +8,7 @@ export default class Control {
8
8
  id?: string | null;
9
9
  title?: string | null;
10
10
  code?: string | null;
11
+ describe?: string | null;
11
12
  desc?: string | null;
12
13
  descs?: {
13
14
  [key: string]: string | undefined;
@@ -31,7 +31,7 @@ class Control {
31
31
  const flattened = (0, flat_1.flatten)(this);
32
32
  Object.entries(flattened).forEach(([key, value]) => {
33
33
  if (typeof value === 'string') {
34
- lodash_1.default.set(flattened, key, (0, global_1.unformatText)(value));
34
+ lodash_1.default.set(flattened, key, value);
35
35
  }
36
36
  });
37
37
  return new Control((0, flat_1.unflatten)(flattened));
@@ -40,13 +40,13 @@ class Control {
40
40
  let result = "# encoding: UTF-8\n\n";
41
41
  result += `control "${this.id}" do\n`;
42
42
  if (this.title) {
43
- result += ` title "${(0, global_1.wrapAndEscapeQuotes)((0, global_1.removeNewlinePlaceholders)(this.title), lineLength)}"\n`;
43
+ result += ` title "${(0, global_1.escapeDoubleQuotes)((0, global_1.removeNewlinePlaceholders)(this.title))}"\n`;
44
44
  }
45
45
  else {
46
46
  console.error(`${this.id} does not have a title`);
47
47
  }
48
48
  if (this.desc) {
49
- result += ` desc "${(0, global_1.wrapAndEscapeQuotes)((0, global_1.removeNewlinePlaceholders)(this.desc), lineLength)}"\n`;
49
+ result += ` desc "${(0, global_1.escapeDoubleQuotes)((0, global_1.removeNewlinePlaceholders)(this.desc))}"\n`;
50
50
  }
51
51
  else {
52
52
  console.error(`${this.id} does not have a desc`);
@@ -54,7 +54,7 @@ class Control {
54
54
  if (this.descs) {
55
55
  Object.entries(this.descs).forEach(([key, desc]) => {
56
56
  if (desc) {
57
- result += ` desc "${key}", "${(0, global_1.wrapAndEscapeQuotes)((0, global_1.removeNewlinePlaceholders)(desc), lineLength)}"\n`;
57
+ result += ` desc "${key}", "${(0, global_1.escapeDoubleQuotes)((0, global_1.removeNewlinePlaceholders)(desc))}"\n`;
58
58
  }
59
59
  else {
60
60
  console.error(`${this.id} does not have a desc for the value ${key}`);
@@ -96,10 +96,14 @@ class Control {
96
96
  }
97
97
  }
98
98
  else if (typeof value === "string") {
99
- result += ` tag ${tag}: "${(0, global_1.wrapAndEscapeQuotes)((0, global_1.removeNewlinePlaceholders)(value), lineLength)}"\n`;
99
+ result += ` tag ${tag}: "${(0, global_1.escapeDoubleQuotes)((0, global_1.removeNewlinePlaceholders)(value))}"\n`;
100
100
  }
101
101
  }
102
102
  });
103
+ if (this.describe) {
104
+ result += '\n';
105
+ result += this.describe;
106
+ }
103
107
  result += "end";
104
108
  return result;
105
109
  }
@@ -37,7 +37,7 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
37
37
  summary: parsedXML.Benchmark[0].description[0]['#text']
38
38
  });
39
39
  rules.forEach(rule => {
40
- var _a, _b, _c, _d;
40
+ var _a, _b, _c;
41
41
  let extractedDescription;
42
42
  if (Array.isArray(rule.description)) {
43
43
  extractedDescription = rule.description[0]['#text'];
@@ -68,29 +68,15 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
68
68
  default:
69
69
  throw new Error('useRuleId must be one of "group", "rule", or "version"');
70
70
  }
71
- if (removeNewlines) {
72
- const title = (0, xccdf_1.removeXMLSpecialCharacters)(rule['@_severity'] ? ensureDecodedXMLStringValue(rule.title) : `[[[MISSING SEVERITY FROM STIG]]] ${ensureDecodedXMLStringValue(rule.title)}`);
73
- control.title = title.replace(/\n/g, '{{{{newlineHERE}}}}');
74
- const desc = (0, xccdf_1.removeXMLSpecialCharacters)(typeof extractedDescription === 'string' ? extractedDescription : ((_a = extractedDescription.VulnDiscussion) === null || _a === void 0 ? void 0 : _a.split('Satisfies: ')[0]) || 'Missing Description');
75
- control.desc = desc === null || desc === void 0 ? void 0 : desc.trim().replace(/\n/g, '{{{{newlineHERE}}}}');
76
- }
77
- else {
78
- control.title = (0, xccdf_1.removeXMLSpecialCharacters)(rule['@_severity'] ? ensureDecodedXMLStringValue(rule.title) : `[[[MISSING SEVERITY FROM STIG]]] ${ensureDecodedXMLStringValue(rule.title)}`);
79
- control.desc = (0, xccdf_1.removeXMLSpecialCharacters)(typeof extractedDescription === 'string' ? extractedDescription : ((_b = extractedDescription.VulnDiscussion) === null || _b === void 0 ? void 0 : _b.split('Satisfies: ')[0]) || 'Missing Description');
80
- }
81
- control.impact = (0, xccdf_1.severityStringToImpact)(rule['@_severity'] || 'critical', rule.group['@_id']);
71
+ control.title = (0, xccdf_1.removeXMLSpecialCharacters)(rule['@_severity'] ? ensureDecodedXMLStringValue(rule.title) : `[[[MISSING SEVERITY FROM STIG]]] ${ensureDecodedXMLStringValue(rule.title)}`);
72
+ control.desc = (0, xccdf_1.removeXMLSpecialCharacters)(typeof extractedDescription === 'string' ? extractedDescription : ((_a = extractedDescription.VulnDiscussion) === null || _a === void 0 ? void 0 : _a.split('Satisfies: ')[0]) || 'Missing Description');
73
+ control.impact = (0, xccdf_1.severityStringToImpact)(rule['@_severity'] || 'medium', rule.group['@_id']);
82
74
  if (!control.descs || Array.isArray(control.descs)) {
83
75
  control.descs = {};
84
76
  }
85
77
  if (rule.check) {
86
78
  if (rule.check.some((ruleValue) => 'check-content' in ruleValue)) {
87
- if (removeNewlines) {
88
- const check = (0, xccdf_1.removeXMLSpecialCharacters)(rule.check ? rule.check[0]['check-content'] : 'Missing description');
89
- control.descs.check = check.replace(/\n/g, '{{{{newlineHERE}}}}');
90
- }
91
- else {
92
- control.descs.check = (0, xccdf_1.removeXMLSpecialCharacters)(rule.check ? rule.check[0]['check-content'] : 'Missing description');
93
- }
79
+ control.descs.check = (0, xccdf_1.removeXMLSpecialCharacters)(rule.check ? rule.check[0]['check-content'] : 'Missing description');
94
80
  }
95
81
  else if (rule.check.some((ruleValue) => 'check-content-ref' in ruleValue) && ovalDefinitions) {
96
82
  let referenceID = null;
@@ -104,26 +90,14 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
104
90
  }
105
91
  }
106
92
  if (referenceID && referenceID in ovalDefinitions) {
107
- if (removeNewlines) {
108
- const check = (0, xccdf_1.removeXMLSpecialCharacters)(ovalDefinitions[referenceID].metadata[0].title);
109
- control.descs.check = check.replace(/\n/g, '{{{{newlineHERE}}}}');
110
- }
111
- else {
112
- control.descs.check = (0, xccdf_1.removeXMLSpecialCharacters)(ovalDefinitions[referenceID].metadata[0].title);
113
- }
93
+ control.descs.check = (0, xccdf_1.removeXMLSpecialCharacters)(ovalDefinitions[referenceID].metadata[0].title);
114
94
  }
115
95
  else if (referenceID) {
116
96
  console.warn(`Could not find OVAL definition for ${referenceID}`);
117
97
  }
118
98
  }
119
99
  }
120
- if (removeNewlines) {
121
- const fix = (0, xccdf_1.removeXMLSpecialCharacters)(rule.fixtext ? rule.fixtext[0]['#text'] : (rule.fix ? rule.fix[0]['#text'] || 'Missing fix text' : 'Missing fix text'));
122
- control.descs.fix = fix.replace(/\n/g, '{{{{newlineHERE}}}}');
123
- }
124
- else {
125
- control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)(rule.fixtext ? rule.fixtext[0]['#text'] : (rule.fix ? rule.fix[0]['#text'] || 'Missing fix text' : 'Missing fix text'));
126
- }
100
+ control.descs.fix = (0, xccdf_1.removeXMLSpecialCharacters)(rule.fixtext ? rule.fixtext[0]['#text'] : (rule.fix ? rule.fix[0]['#text'] || 'Missing fix text' : 'Missing fix text'));
127
101
  control.tags.severity = (0, xccdf_1.impactNumberToSeverityString)((0, xccdf_1.severityStringToImpact)(rule['@_severity'] || 'critical', control.id || 'Unknown'));
128
102
  control.tags.gid = rule.group['@_id'],
129
103
  control.tags.rid = rule['@_id'];
@@ -141,7 +115,7 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
141
115
  control.tags.rationale = rule['rationale'][0]['#text'];
142
116
  }
143
117
  if (typeof extractedDescription === 'object') {
144
- control.tags.satisfies = ((_c = extractedDescription.VulnDiscussion) === null || _c === void 0 ? void 0 : _c.includes('Satisfies: ')) && extractedDescription.VulnDiscussion.split('Satisfies: ').length >= 1 ? extractedDescription.VulnDiscussion.split('Satisfies: ')[1].split(',').map(satisfaction => satisfaction.trim()) : undefined;
118
+ control.tags.satisfies = ((_b = extractedDescription.VulnDiscussion) === null || _b === void 0 ? void 0 : _b.includes('Satisfies: ')) && extractedDescription.VulnDiscussion.split('Satisfies: ').length >= 1 ? extractedDescription.VulnDiscussion.split('Satisfies: ')[1].split(',').map(satisfaction => satisfaction.trim()) : undefined;
145
119
  control.tags.false_negatives = extractedDescription.FalseNegatives || undefined;
146
120
  control.tags.false_positives = extractedDescription.FalsePositives || undefined;
147
121
  control.tags.documentable = typeof extractedDescription.Documentable === 'boolean' ? extractedDescription.Documentable : undefined;
@@ -194,7 +168,7 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
194
168
  }
195
169
  });
196
170
  }
197
- (_d = rule.reference) === null || _d === void 0 ? void 0 : _d.forEach((reference) => {
171
+ (_c = rule.reference) === null || _c === void 0 ? void 0 : _c.forEach((reference) => {
198
172
  var _a, _b, _c, _d;
199
173
  if (lodash_1.default.get(reference, '@_href') === '') {
200
174
  (_a = control.refs) === null || _a === void 0 ? void 0 : _a.push(lodash_1.default.get(reference, '#text'));
@@ -1,2 +1,2 @@
1
1
  import winston from "winston";
2
- export declare function createWinstonLogger(mapperName: string, level?: string): winston.Logger;
2
+ export declare function createWinstonLogger(level?: string): winston.Logger;
@@ -3,13 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createWinstonLogger = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const winston_1 = tslib_1.__importDefault(require("winston"));
6
- function createWinstonLogger(mapperName, level = 'debug') {
6
+ function createWinstonLogger(level = 'debug') {
7
7
  return winston_1.default.createLogger({
8
8
  transports: [new winston_1.default.transports.Console()],
9
9
  level: level,
10
10
  format: winston_1.default.format.combine(winston_1.default.format.timestamp({
11
11
  format: 'MMM-DD-YYYY HH:mm:ss Z',
12
- }), winston_1.default.format.printf(info => `[${[info.timestamp]}] ${mapperName} ${info.message}`)),
12
+ }), winston_1.default.format.printf(info => `[${[info.timestamp]}] ${info.message}`)),
13
13
  });
14
14
  }
15
15
  exports.createWinstonLogger = createWinstonLogger;
@@ -9,6 +9,7 @@ const profile_1 = tslib_1.__importDefault(require("../objects/profile"));
9
9
  const xccdf_1 = require("../parsers/xccdf");
10
10
  const diff_1 = require("./diff");
11
11
  const diffMarkdown_1 = require("./diffMarkdown");
12
+ const knownInSpecKeywords = ['title', 'desc', 'impact', 'ref', 'tag', "\""];
12
13
  function projectValuesOntoExistingObj(dst, src, currentPath = '') {
13
14
  for (const updatedValue in src) {
14
15
  const existingValue = lodash_1.default.get(dst, updatedValue);
@@ -31,8 +32,44 @@ function projectValuesOntoExistingObj(dst, src, currentPath = '') {
31
32
  }
32
33
  return dst;
33
34
  }
35
+ // This is the most likely thing to break if you are getting code formatting issues.
36
+ // Extract the existing describe blocks (what is actually run by inspec for validation)
37
+ function getExistingDescribeFromControl(control) {
38
+ if (control.code) {
39
+ let existingDescribeBlock = '';
40
+ let inQuoteBlock = false;
41
+ control.code.split('\n').forEach((line) => {
42
+ const wordSplit = line.trim().split(' ');
43
+ wordSplit.forEach((word, index) => {
44
+ const charSplit = word.split('');
45
+ charSplit.forEach((char, index) => {
46
+ if (char === '"' && charSplit[index - 1] !== '\\') {
47
+ inQuoteBlock = !inQuoteBlock;
48
+ }
49
+ });
50
+ });
51
+ if (!inQuoteBlock) {
52
+ // Get the number of spaces at the beggining of the current line
53
+ const spaces = line.substring(0, line.indexOf(wordSplit[0])).length;
54
+ if (spaces >= 2) {
55
+ const firstWord = wordSplit[0];
56
+ if (knownInSpecKeywords.indexOf(firstWord.toLowerCase()) === -1 || (knownInSpecKeywords.indexOf(firstWord.toLowerCase()) !== -1 && spaces > 2)) {
57
+ existingDescribeBlock += line + '\n';
58
+ }
59
+ }
60
+ }
61
+ });
62
+ return existingDescribeBlock;
63
+ }
64
+ else {
65
+ return '';
66
+ }
67
+ }
34
68
  function updateControl(from, update) {
35
- return projectValuesOntoExistingObj(from, update);
69
+ const existingDescribeBlock = getExistingDescribeFromControl(from);
70
+ const projectedControl = projectValuesOntoExistingObj(from, update);
71
+ projectedControl.describe = existingDescribeBlock;
72
+ return projectedControl;
36
73
  }
37
74
  exports.updateControl = updateControl;
38
75
  function updateProfile(from, using) {
@@ -73,7 +110,6 @@ function updateProfile(from, using) {
73
110
  }
74
111
  exports.updateProfile = updateProfile;
75
112
  function updateProfileUsingXCCDF(from, using, id, logger, ovalDefinitions) {
76
- console.log(from.controls[0].desc);
77
113
  // Parse the XCCDF benchmark and convert it into a Profile
78
114
  logger.debug('Loading XCCDF File');
79
115
  const xccdfProfile = (0, xccdf_1.processXCCDF)(using, false, id);
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@mitre/inspec-objects",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@mitre/inspec-objects",
9
- "version": "0.0.13",
9
+ "version": "0.0.14",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@types/flat": "^5.0.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mitre/inspec-objects",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Typescript objects for normalizing between InSpec profiles and XCCDF benchmarks",
5
5
  "main": "lib/index.js",
6
6
  "publishConfig": {