@mitre/inspec-objects 0.0.31 → 0.0.32
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/.eslintignore +2 -0
- package/.eslintrc +41 -0
- package/.github/workflows/e2e-test.yml +6 -19
- package/.github/workflows/linter.yml +27 -0
- package/.github/workflows/push-to-gpr.yml +36 -0
- package/.github/workflows/push-to-npm.yml +7 -6
- package/README.md +48 -0
- package/images/Delta_Process.jpg +0 -0
- package/images/ts-inspec-objects.jpg +0 -0
- package/lib/index.d.ts +7 -7
- package/lib/objects/control.d.ts +2 -2
- package/lib/objects/control.js +40 -21
- package/lib/objects/profile.d.ts +6 -6
- package/lib/objects/profile.js +1 -1
- package/lib/parsers/json.d.ts +2 -2
- package/lib/parsers/json.js +15 -11
- package/lib/parsers/oval.js +20 -19
- package/lib/parsers/xccdf.d.ts +1 -1
- package/lib/parsers/xccdf.js +8 -5
- package/lib/utilities/diff.d.ts +3 -3
- package/lib/utilities/diff.js +20 -18
- package/lib/utilities/diffMarkdown.d.ts +1 -1
- package/lib/utilities/diffMarkdown.js +14 -18
- package/lib/utilities/global.d.ts +1 -4
- package/lib/utilities/global.js +25 -13
- package/lib/utilities/logging.d.ts +1 -1
- package/lib/utilities/update.d.ts +2 -1
- package/lib/utilities/update.js +55 -88
- package/lib/utilities/xccdf.js +0 -1
- package/package.json +7 -4
- package/tsconfig.json +20 -21
package/.eslintignore
ADDED
package/.eslintrc
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rules": {
|
|
3
|
+
"@typescript-eslint/no-unused-vars": "warn",
|
|
4
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
5
|
+
"unicorn/filename-case": "off",
|
|
6
|
+
"unicorn/prefer-node-protocol": "off",
|
|
7
|
+
"unicorn/numeric-separators-style": "off",
|
|
8
|
+
"unicorn/no-hex-escape": "off",
|
|
9
|
+
"unicorn/better-regex": "off",
|
|
10
|
+
"unicorn/no-zero-fractions": "off",
|
|
11
|
+
"unicorn/no-array-for-each": "off",
|
|
12
|
+
"unicorn/explicit-length-check": "off",
|
|
13
|
+
"unicorn/no-process-exit": "off",
|
|
14
|
+
"no-process-exit": "off",
|
|
15
|
+
"no-await-in-loop": "off",
|
|
16
|
+
"no-control-regex": "off",
|
|
17
|
+
"max-nested-callbacks": "off",
|
|
18
|
+
"unicorn/prefer-json-parse-buffer": "off",
|
|
19
|
+
"camelcase": "off", // Camel case fields are used in CKL
|
|
20
|
+
"no-console": "off",
|
|
21
|
+
"node/no-missing-import": "off",
|
|
22
|
+
"complexity": "off",
|
|
23
|
+
"no-constant-condition": "off",
|
|
24
|
+
"keyword-spacing": 2,
|
|
25
|
+
"space-before-blocks":"warn",
|
|
26
|
+
"space-in-parens": 2,
|
|
27
|
+
"indent": ["error", 2, { "SwitchCase": 1 }],
|
|
28
|
+
"quotes": [2, "single", { "avoidEscape": true }],
|
|
29
|
+
"object-curly-spacing": [2, "never"]
|
|
30
|
+
},
|
|
31
|
+
"root": true,
|
|
32
|
+
"parser": "@typescript-eslint/parser",
|
|
33
|
+
"plugins": [
|
|
34
|
+
"@typescript-eslint"
|
|
35
|
+
],
|
|
36
|
+
"extends": [
|
|
37
|
+
"eslint:recommended",
|
|
38
|
+
"plugin:@typescript-eslint/eslint-recommended",
|
|
39
|
+
"plugin:@typescript-eslint/recommended"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -4,35 +4,22 @@ on:
|
|
|
4
4
|
push:
|
|
5
5
|
branches: [ main ]
|
|
6
6
|
pull_request:
|
|
7
|
-
branches: [ main ]
|
|
8
7
|
|
|
9
8
|
jobs:
|
|
10
9
|
build:
|
|
11
10
|
runs-on: ubuntu-20.04
|
|
12
11
|
|
|
13
12
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
15
|
-
|
|
16
|
-
- name: Cache node modules
|
|
17
|
-
uses: actions/cache@v2
|
|
18
|
-
env:
|
|
19
|
-
cache-name: cache-node-modules
|
|
20
|
-
with:
|
|
21
|
-
# npm cache files are stored in `~/.npm` on Linux/macOS
|
|
22
|
-
path: ~/.npm
|
|
23
|
-
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
|
|
24
|
-
restore-keys: |
|
|
25
|
-
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
26
|
-
${{ runner.os }}-build-
|
|
27
|
-
${{ runner.os }}-
|
|
13
|
+
- uses: actions/checkout@v3
|
|
28
14
|
|
|
29
15
|
- name: Setup Node.js
|
|
30
|
-
uses: actions/setup-node@
|
|
16
|
+
uses: actions/setup-node@v3
|
|
31
17
|
with:
|
|
32
|
-
node-version:
|
|
18
|
+
node-version: 18
|
|
19
|
+
cache: 'npm'
|
|
33
20
|
|
|
34
21
|
- name: Install dependencies
|
|
35
|
-
run: npm
|
|
22
|
+
run: npm ci
|
|
36
23
|
|
|
37
24
|
- name: Run e2e tests
|
|
38
|
-
run:
|
|
25
|
+
run: npm test
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
name: Lint TS-InSpec-Objects
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [ main ]
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-20.04
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout code
|
|
15
|
+
uses: actions/checkout@v3
|
|
16
|
+
|
|
17
|
+
- name: Setup Node.js
|
|
18
|
+
uses: actions/setup-node@v3
|
|
19
|
+
with:
|
|
20
|
+
node-version: 18
|
|
21
|
+
cache: 'npm'
|
|
22
|
+
|
|
23
|
+
- name: Install project dependencies
|
|
24
|
+
run: npm ci
|
|
25
|
+
|
|
26
|
+
- name: Run lint
|
|
27
|
+
run: npm run lint:ci
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Build and Release NPM to GPR (GitHub Package Registry)
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build-deploy:
|
|
9
|
+
runs-on: ubuntu-20.04
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v3
|
|
12
|
+
|
|
13
|
+
- name: Setup node
|
|
14
|
+
uses: actions/setup-node@v3
|
|
15
|
+
with:
|
|
16
|
+
node-version: 18
|
|
17
|
+
registry-url: https://npm.pkg.github.com/
|
|
18
|
+
scope: '@mitre'
|
|
19
|
+
|
|
20
|
+
- name: Build the NPM Package
|
|
21
|
+
run: |
|
|
22
|
+
npm install
|
|
23
|
+
npm run build
|
|
24
|
+
- name: Pack all items that are published
|
|
25
|
+
run: npm pack
|
|
26
|
+
# Setup .npmrc file to publish to GitHub Package Registry
|
|
27
|
+
- uses: actions/setup-node@v1
|
|
28
|
+
with:
|
|
29
|
+
registry-url: 'https://npm.pkg.github.com'
|
|
30
|
+
scope: '@mitre'
|
|
31
|
+
|
|
32
|
+
# Publish inspec-objects to GitHub Package Registry
|
|
33
|
+
- name: Publish inspec-objects to GPR
|
|
34
|
+
run: npm publish mitre-inspec-objects-*.tgz
|
|
35
|
+
env:
|
|
36
|
+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -2,17 +2,18 @@ name: Push @mitre/inspec-objects to NPM
|
|
|
2
2
|
on:
|
|
3
3
|
release:
|
|
4
4
|
types: [published]
|
|
5
|
+
workflow_dispatch:
|
|
5
6
|
|
|
6
7
|
jobs:
|
|
7
8
|
build-deploy:
|
|
8
|
-
runs-on: ubuntu-
|
|
9
|
+
runs-on: ubuntu-20.04
|
|
9
10
|
steps:
|
|
10
|
-
- uses: actions/checkout@
|
|
11
|
+
- uses: actions/checkout@v3
|
|
11
12
|
|
|
12
13
|
- name: setup node
|
|
13
|
-
uses: actions/setup-node@
|
|
14
|
+
uses: actions/setup-node@v3
|
|
14
15
|
with:
|
|
15
|
-
node-version:
|
|
16
|
+
node-version: 18
|
|
16
17
|
registry-url: 'https://registry.npmjs.org'
|
|
17
18
|
|
|
18
19
|
- name: Install project dependencies
|
|
@@ -27,7 +28,7 @@ jobs:
|
|
|
27
28
|
- name: Pack all items that are published as packages
|
|
28
29
|
run: npm pack
|
|
29
30
|
|
|
30
|
-
- name: Publish
|
|
31
|
+
- name: Publish inspec-objects to NPM
|
|
31
32
|
run: npm publish --access public mitre-inspec-objects-*.tgz
|
|
32
33
|
env:
|
|
33
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
34
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
# ts-inspec-objects
|
|
2
2
|
Typescript objects for InSpec profiles
|
|
3
3
|
|
|
4
|
+
This repository contains the source code that facilitates the writing of InSpec profiles (for use in things like stub generation and delta comparisons) more consistent with `Chef Cookstyle` formatting for ease of use when comparing with new changes from delta and when generating InSpec stubs that match a standard format.
|
|
5
|
+
|
|
6
|
+
For more information about Chef Cookstyle see:
|
|
7
|
+
- [chef/cookstyle on GitHub](https://github.com/chef/cookstyle)
|
|
8
|
+
- [Chef Cookstyle on Chef documents page](https://docs.chef.io/workstation/cookstyle/)
|
|
9
|
+
|
|
10
|
+
## How to Use
|
|
11
|
+
The process code maintained in this repository generates a `npm` executable that is published to the `npm registry` as [mitre-inspec-objects](https://www.npmjs.com/package/@mitre/inspec-objects).
|
|
12
|
+
|
|
13
|
+
To use the `mitre-inspec-objects` npm package, simply add the package as a dependency to your project application using the npm install command:
|
|
14
|
+
```
|
|
15
|
+
npm install mitre-inspec-objects
|
|
16
|
+
```
|
|
17
|
+
The package is a CommonJS-based npm written in TypeScript
|
|
18
|
+
|
|
19
|
+
## Parsing Process
|
|
20
|
+
|
|
21
|
+
When using this library to parse `InSpec profiles` or `xccdf files` for the purposes of generating InSpec profiles, the general workflow is as follows:
|
|
22
|
+
```
|
|
23
|
+
- The input is processed, read into a typescript object
|
|
24
|
+
- Operated on with any required action / logic
|
|
25
|
+
- Then written into an InSpec profile as output.
|
|
26
|
+
```
|
|
27
|
+
This means that we can not simply write out in the same format we got in. Instead, we have to make choices about formatting for how to write out content.
|
|
28
|
+
|
|
29
|
+
Here are some formatting choices that are being made.
|
|
30
|
+
|
|
31
|
+
1. String quotation
|
|
32
|
+
|
|
33
|
+
| The string contains | Use |
|
|
34
|
+
|-------- |-------------------- |
|
|
35
|
+
| single (') and double (") quotes| percent string syntax - %q() |
|
|
36
|
+
| single (') quotes | double (") quotes |
|
|
37
|
+
| other | single (') quotes |
|
|
38
|
+
|
|
39
|
+
2. Tag keywords are not quoted (ex: tag severity: 'medium')
|
|
40
|
+
3. Each control file ends with a newline
|
|
41
|
+
|
|
42
|
+
### Workflow graphical representation
|
|
43
|
+
<div align="center">
|
|
44
|
+
<img src="images/ts-inspec-objects.jpg" alt="Typescript Objects Generation Process" title="Typescript Objects Generation Process">
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
### Delta and Stub Process
|
|
48
|
+
<div align="center">
|
|
49
|
+
<img src="images/Delta_Process.jpg" alt="Delta and Stub Generation Process" title="Delta and Stub Generation Process">
|
|
50
|
+
</div>
|
|
51
|
+
|
|
4
52
|
### NOTICE
|
|
5
53
|
|
|
6
54
|
© 2018-2022 The MITRE Corporation.
|
|
Binary file
|
|
Binary file
|
package/lib/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
1
|
+
export * from './objects/control';
|
|
2
|
+
export * from './objects/profile';
|
|
3
|
+
export * from './parsers/json';
|
|
4
|
+
export * from './parsers/oval';
|
|
5
|
+
export * from './parsers/xccdf';
|
|
6
|
+
export * from './utilities/diff';
|
|
7
|
+
export * from './utilities/update';
|
package/lib/objects/control.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExecJSON } from
|
|
1
|
+
import { ExecJSON } from 'inspecjs';
|
|
2
2
|
export declare function objectifyDescriptions(descs: ExecJSON.ControlDescription[] | {
|
|
3
3
|
[key: string]: string | undefined;
|
|
4
4
|
} | null | undefined): {
|
|
@@ -49,5 +49,5 @@ export default class Control {
|
|
|
49
49
|
};
|
|
50
50
|
constructor(data?: Partial<Control>);
|
|
51
51
|
toUnformattedObject(): Control;
|
|
52
|
-
toRuby(
|
|
52
|
+
toRuby(): string;
|
|
53
53
|
}
|
package/lib/objects/control.js
CHANGED
|
@@ -36,25 +36,36 @@ class Control {
|
|
|
36
36
|
});
|
|
37
37
|
return new Control((0, flat_1.unflatten)(flattened));
|
|
38
38
|
}
|
|
39
|
-
toRuby(
|
|
40
|
-
let result =
|
|
41
|
-
result += `control
|
|
39
|
+
toRuby() {
|
|
40
|
+
let result = '';
|
|
41
|
+
result += `control '${this.id}' do\n`;
|
|
42
42
|
if (this.title) {
|
|
43
|
-
result += ` title
|
|
43
|
+
result += ` title ${(0, global_1.escapeQuotes)(this.title)}\n`;
|
|
44
44
|
}
|
|
45
45
|
else {
|
|
46
46
|
console.error(`${this.id} does not have a title`);
|
|
47
47
|
}
|
|
48
|
+
// This is the known 'default' description - on previous version this content was repeated on descriptions processed by "descs"
|
|
48
49
|
if (this.desc) {
|
|
49
|
-
result += ` desc
|
|
50
|
+
result += ` desc ${(0, global_1.escapeQuotes)(this.desc)}\n`;
|
|
50
51
|
}
|
|
51
52
|
else {
|
|
52
53
|
console.error(`${this.id} does not have a desc`);
|
|
53
54
|
}
|
|
54
55
|
if (this.descs) {
|
|
55
|
-
Object.entries(this.descs).forEach(([key,
|
|
56
|
-
if (
|
|
57
|
-
|
|
56
|
+
Object.entries(this.descs).forEach(([key, subDesc]) => {
|
|
57
|
+
if (subDesc) {
|
|
58
|
+
if (key.match('default') && this.desc) {
|
|
59
|
+
if (subDesc != this.desc) {
|
|
60
|
+
// The "default" keyword may have the same content as the desc content for backward compatibility with different historical InSpec versions.
|
|
61
|
+
// In that case, we can ignore writing the "default" subdescription field.
|
|
62
|
+
// If they are different, however, someone may be trying to use the keyword "default" for a unique subdescription, which should not be done.
|
|
63
|
+
console.error(`${this.id} has a subdescription called "default" with contents that do not match the main description. "Default" should not be used as a keyword for unique sub-descriptions.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
result += ` desc '${key}', ${(0, global_1.escapeQuotes)(subDesc)}\n`;
|
|
68
|
+
}
|
|
58
69
|
}
|
|
59
70
|
else {
|
|
60
71
|
console.error(`${this.id} does not have a desc for the value ${key}`);
|
|
@@ -69,34 +80,39 @@ class Control {
|
|
|
69
80
|
}
|
|
70
81
|
if (this.refs) {
|
|
71
82
|
this.refs.forEach((ref) => {
|
|
83
|
+
var _a;
|
|
72
84
|
if (typeof ref === 'string') {
|
|
73
|
-
result += ` ref
|
|
85
|
+
result += ` ref ${(0, global_1.escapeQuotes)(ref)}\n`;
|
|
74
86
|
}
|
|
75
87
|
else {
|
|
76
|
-
result += ` ref
|
|
88
|
+
result += ` ref ${(0, global_1.escapeQuotes)(((_a = ref.ref) === null || _a === void 0 ? void 0 : _a.toString()) || '')}, url: ${(0, global_1.escapeQuotes)(ref.url || '')}`;
|
|
77
89
|
}
|
|
78
90
|
});
|
|
79
91
|
}
|
|
80
92
|
Object.entries(this.tags).forEach(([tag, value]) => {
|
|
81
93
|
if (value) {
|
|
82
|
-
if (typeof value ===
|
|
83
|
-
if (Array.isArray(value) && typeof value[0] ===
|
|
84
|
-
|
|
94
|
+
if (typeof value === 'object') {
|
|
95
|
+
if (Array.isArray(value) && typeof value[0] === 'string') {
|
|
96
|
+
// The goal is to keep the style similar to cookstyle formatting
|
|
97
|
+
result += ` tag ${tag}: ${JSON.stringify(value)
|
|
98
|
+
.replace(/"/g, "'") // replace the double quotes with single quotes, ex: ["V-72029","SV-86653"] -> ['V-72029','SV-86653']
|
|
99
|
+
.split("','") // split the items in the string
|
|
100
|
+
.join("', '")}\n`; // join them together using single quote and a space, ex: ['V-72029','SV-86653'] -> ['V-72029', 'SV-86653']
|
|
85
101
|
}
|
|
86
102
|
else {
|
|
87
103
|
// Convert JSON Object to Ruby Hash
|
|
88
104
|
const stringifiedObject = JSON.stringify(value, null, 2)
|
|
89
|
-
.replace(/\n/g,
|
|
90
|
-
.replace(/\{\n {6}/g,
|
|
91
|
-
.replace(/\[\n {8}/g,
|
|
92
|
-
.replace(/\n {6}\]/g,
|
|
93
|
-
.replace(/\n {4}\}/g,
|
|
105
|
+
.replace(/\n/g, '\n ')
|
|
106
|
+
.replace(/\{\n {6}/g, '{')
|
|
107
|
+
.replace(/\[\n {8}/g, '[')
|
|
108
|
+
.replace(/\n {6}\]/g, ']')
|
|
109
|
+
.replace(/\n {4}\}/g, '}')
|
|
94
110
|
.replace(/": \[/g, '" => [');
|
|
95
111
|
result += ` tag ${tag}: ${stringifiedObject}\n`;
|
|
96
112
|
}
|
|
97
113
|
}
|
|
98
|
-
else if (typeof value ===
|
|
99
|
-
result += ` tag ${tag}:
|
|
114
|
+
else if (typeof value === 'string') {
|
|
115
|
+
result += ` tag ${tag}: ${(0, global_1.escapeQuotes)(value)}\n`;
|
|
100
116
|
}
|
|
101
117
|
}
|
|
102
118
|
});
|
|
@@ -104,7 +120,10 @@ class Control {
|
|
|
104
120
|
result += '\n';
|
|
105
121
|
result += this.describe;
|
|
106
122
|
}
|
|
107
|
-
result
|
|
123
|
+
if (!result.slice(-1).match('\n')) {
|
|
124
|
+
result += '\n';
|
|
125
|
+
}
|
|
126
|
+
result += 'end\n';
|
|
108
127
|
return result;
|
|
109
128
|
}
|
|
110
129
|
}
|
package/lib/objects/profile.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Control from
|
|
1
|
+
import Control from './control';
|
|
2
2
|
export default class Profile {
|
|
3
3
|
name?: string | null;
|
|
4
4
|
title?: string | null;
|
|
@@ -11,10 +11,10 @@ export default class Profile {
|
|
|
11
11
|
version?: string | null;
|
|
12
12
|
inspec_version?: string | null;
|
|
13
13
|
supports: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
'platform-family'?: string;
|
|
15
|
+
'platform-name'?: string;
|
|
16
|
+
'os-name'?: string;
|
|
17
|
+
'os-family'?: string;
|
|
18
18
|
release?: string;
|
|
19
19
|
platform?: string;
|
|
20
20
|
}[];
|
|
@@ -44,7 +44,7 @@ export default class Profile {
|
|
|
44
44
|
readme?: string | null;
|
|
45
45
|
files: string[];
|
|
46
46
|
controls: Control[];
|
|
47
|
-
constructor(data?: Omit<Partial<Profile>,
|
|
47
|
+
constructor(data?: Omit<Partial<Profile>, 'controls'>);
|
|
48
48
|
createInspecYaml(): string;
|
|
49
49
|
toUnformattedObject(): Profile;
|
|
50
50
|
}
|
package/lib/objects/profile.js
CHANGED
|
@@ -37,7 +37,7 @@ class Profile {
|
|
|
37
37
|
toUnformattedObject() {
|
|
38
38
|
const unformattedProfile = new Profile(this);
|
|
39
39
|
Object.entries(this).forEach(([key, value]) => {
|
|
40
|
-
if (typeof value ===
|
|
40
|
+
if (typeof value === 'string') {
|
|
41
41
|
lodash_1.default.set(unformattedProfile, key, (0, global_1.unformatText)(value));
|
|
42
42
|
}
|
|
43
43
|
});
|
package/lib/parsers/json.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ContextualizedEvaluation, ContextualizedProfile, ExecJSON } from
|
|
2
|
-
import Profile from
|
|
1
|
+
import { ContextualizedEvaluation, ContextualizedProfile, ExecJSON } from 'inspecjs';
|
|
2
|
+
import Profile from '../objects/profile';
|
|
3
3
|
export declare function processEvaluation(evaluationInput: ContextualizedEvaluation): Profile;
|
|
4
4
|
export declare function processProfileJSON(profileInput: ContextualizedProfile): Profile;
|
|
5
5
|
export declare function processExecJSON(execJSON: ExecJSON.Execution): Profile;
|
package/lib/parsers/json.js
CHANGED
|
@@ -6,6 +6,7 @@ const inspecjs_1 = require("inspecjs");
|
|
|
6
6
|
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
7
7
|
const control_1 = tslib_1.__importStar(require("../objects/control"));
|
|
8
8
|
const profile_1 = tslib_1.__importDefault(require("../objects/profile"));
|
|
9
|
+
const update_1 = require("../utilities/update");
|
|
9
10
|
function processEvaluation(evaluationInput) {
|
|
10
11
|
const topLevelProfile = evaluationInput.contains[0];
|
|
11
12
|
const profile = new profile_1.default({
|
|
@@ -14,9 +15,9 @@ function processEvaluation(evaluationInput) {
|
|
|
14
15
|
maintainer: topLevelProfile.data.maintainer,
|
|
15
16
|
copyright: topLevelProfile.data.copyright,
|
|
16
17
|
copyright_email: topLevelProfile.data.copyright_email,
|
|
17
|
-
license: lodash_1.default.get(topLevelProfile.data,
|
|
18
|
-
summary: lodash_1.default.get(topLevelProfile.data,
|
|
19
|
-
description: lodash_1.default.get(topLevelProfile.data,
|
|
18
|
+
license: lodash_1.default.get(topLevelProfile.data, 'license'),
|
|
19
|
+
summary: lodash_1.default.get(topLevelProfile.data, 'summary'),
|
|
20
|
+
description: lodash_1.default.get(topLevelProfile.data, 'description'),
|
|
20
21
|
version: topLevelProfile.data.version,
|
|
21
22
|
});
|
|
22
23
|
topLevelProfile.contains.forEach((control) => {
|
|
@@ -39,9 +40,9 @@ function processProfileJSON(profileInput) {
|
|
|
39
40
|
maintainer: profileInput.data.maintainer,
|
|
40
41
|
copyright: profileInput.data.copyright,
|
|
41
42
|
copyright_email: profileInput.data.copyright_email,
|
|
42
|
-
license: lodash_1.default.get(profileInput.data,
|
|
43
|
-
summary: lodash_1.default.get(profileInput.data,
|
|
44
|
-
description: lodash_1.default.get(profileInput.data,
|
|
43
|
+
license: lodash_1.default.get(profileInput.data, 'license'),
|
|
44
|
+
summary: lodash_1.default.get(profileInput.data, 'summary'),
|
|
45
|
+
description: lodash_1.default.get(profileInput.data, 'description'),
|
|
45
46
|
version: profileInput.data.version,
|
|
46
47
|
});
|
|
47
48
|
profileInput.data.controls.forEach((control) => {
|
|
@@ -54,12 +55,15 @@ function processProfileJSON(profileInput) {
|
|
|
54
55
|
tags: control.tags,
|
|
55
56
|
descs: (0, control_1.objectifyDescriptions)(control.descriptions),
|
|
56
57
|
});
|
|
58
|
+
newControl.describe = (0, update_1.getExistingDescribeFromControl)(newControl);
|
|
57
59
|
// Migrate check and fix text from tags to descriptions
|
|
58
60
|
if (newControl.tags.check && !newControl.descs.check) {
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
59
62
|
lodash_1.default.set(newControl.descs, 'check', control.tags.check);
|
|
60
63
|
lodash_1.default.set(newControl.tags, 'check', undefined);
|
|
61
64
|
}
|
|
62
65
|
if (newControl.tags.fix && !newControl.descs.fix) {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
63
67
|
lodash_1.default.set(newControl.descs, 'fix', control.tags.fix);
|
|
64
68
|
lodash_1.default.set(newControl.tags, 'fix', undefined);
|
|
65
69
|
}
|
|
@@ -75,16 +79,16 @@ exports.processExecJSON = processExecJSON;
|
|
|
75
79
|
function processInSpecProfile(json) {
|
|
76
80
|
const convertedFile = (0, inspecjs_1.convertFile)(json, true);
|
|
77
81
|
let profile = new profile_1.default();
|
|
78
|
-
if (convertedFile[
|
|
79
|
-
profile = processEvaluation((0, inspecjs_1.contextualizeEvaluation)(convertedFile[
|
|
82
|
+
if (convertedFile['1_0_ExecJson']) {
|
|
83
|
+
profile = processEvaluation((0, inspecjs_1.contextualizeEvaluation)(convertedFile['1_0_ExecJson'])).toUnformattedObject();
|
|
80
84
|
}
|
|
81
|
-
else if (convertedFile[
|
|
85
|
+
else if (convertedFile['1_0_ProfileJson']) {
|
|
82
86
|
profile = processProfileJSON((0, inspecjs_1.contextualizeProfile)(JSON.parse(json))).toUnformattedObject();
|
|
83
87
|
}
|
|
84
88
|
else {
|
|
85
|
-
throw new Error(
|
|
89
|
+
throw new Error('Unknown file type passed');
|
|
86
90
|
}
|
|
87
|
-
profile.controls = lodash_1.default.sortBy(profile.controls,
|
|
91
|
+
profile.controls = lodash_1.default.sortBy(profile.controls, 'id');
|
|
88
92
|
return profile;
|
|
89
93
|
}
|
|
90
94
|
exports.processInSpecProfile = processInSpecProfile;
|
package/lib/parsers/oval.js
CHANGED
|
@@ -4,10 +4,10 @@ exports.processOVAL = exports.extractAllCriteriaRefs = void 0;
|
|
|
4
4
|
const xccdf_1 = require("../utilities/xccdf");
|
|
5
5
|
// https://stackoverflow.com/questions/9133500/how-to-find-a-node-in-a-tree-with-javascript
|
|
6
6
|
function searchTree(aTree, fCompair, bGreedy) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// 1. loop through all root nodes so we don't touch the tree structure
|
|
7
|
+
let oNode; // always the current node
|
|
8
|
+
const aInnerTree = []; // will contain the inner children
|
|
9
|
+
const aReturnNodes = []; // the nodes array which will returned
|
|
10
|
+
// 1. loop through all root nodes, store tree content locally so we don't touch the tree structure
|
|
11
11
|
for (const keysTree in aTree) {
|
|
12
12
|
aInnerTree.push(aTree[keysTree]);
|
|
13
13
|
}
|
|
@@ -26,7 +26,7 @@ function searchTree(aTree, fCompair, bGreedy) {
|
|
|
26
26
|
// true if the property is an array
|
|
27
27
|
if (oNode[keysNode] instanceof Array) {
|
|
28
28
|
// 2. push all array object to aInnerTree to search in those later
|
|
29
|
-
for (
|
|
29
|
+
for (let i = 0; i < oNode[keysNode].length; i++) {
|
|
30
30
|
aInnerTree.push(oNode[keysNode][i]);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -40,8 +40,8 @@ function extractAllCriteriaRefs(initialCriteria) {
|
|
|
40
40
|
initialCriteria.forEach(criteria => {
|
|
41
41
|
var _a;
|
|
42
42
|
(_a = criteria.criterion) === null || _a === void 0 ? void 0 : _a.forEach((criterion) => {
|
|
43
|
-
if (criterion[
|
|
44
|
-
criteriaRefs.push(criterion[
|
|
43
|
+
if (criterion['@_test_ref']) {
|
|
44
|
+
criteriaRefs.push(criterion['@_test_ref']);
|
|
45
45
|
}
|
|
46
46
|
});
|
|
47
47
|
if (criteria.criteria) {
|
|
@@ -61,22 +61,23 @@ function processOVAL(oval) {
|
|
|
61
61
|
for (const ovalDefinitions of parsed.oval_definitions) {
|
|
62
62
|
for (const definitionList of ovalDefinitions.definitions) {
|
|
63
63
|
for (const definition of definitionList.definition) {
|
|
64
|
-
extractedDefinitions[definition[
|
|
65
|
-
extractedDefinitions[definition[
|
|
66
|
-
extractedDefinitions[definition[
|
|
64
|
+
extractedDefinitions[definition['@_id']] = definition;
|
|
65
|
+
extractedDefinitions[definition['@_id']].criteriaRefs = extractAllCriteriaRefs(definition.criteria);
|
|
66
|
+
extractedDefinitions[definition['@_id']].resolvedValues = (_a = extractedDefinitions[definition['@_id']].criteriaRefs) === null || _a === void 0 ? void 0 : _a.map((criteriaRef) => {
|
|
67
67
|
// Extract the original criteria from the oval file
|
|
68
|
-
const foundCriteriaRefererence = searchTree(parsed.oval_definitions[0].tests, (oNode) => oNode[
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
const foundCriteriaRefererence = searchTree(parsed.oval_definitions[0].tests, (oNode) => oNode['@_id'] === criteriaRef, false)[0];
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
70
|
+
const foundObjects = [];
|
|
71
|
+
const foundStates = [];
|
|
71
72
|
if (foundCriteriaRefererence) {
|
|
72
73
|
if (foundCriteriaRefererence.object) {
|
|
73
74
|
foundCriteriaRefererence.object.forEach((object) => {
|
|
74
|
-
if (!object[
|
|
75
|
+
if (!object['@_object_ref']) {
|
|
75
76
|
console.warn(`Found object without object_ref in test ${criteriaRef}`);
|
|
76
77
|
}
|
|
77
78
|
else {
|
|
78
|
-
const objectRef = object[
|
|
79
|
-
const foundObjectReference = searchTree(parsed.oval_definitions[0].objects, (oNode) => oNode[
|
|
79
|
+
const objectRef = object['@_object_ref'];
|
|
80
|
+
const foundObjectReference = searchTree(parsed.oval_definitions[0].objects, (oNode) => oNode['@_id'] === objectRef, false)[0];
|
|
80
81
|
if (foundObjectReference) {
|
|
81
82
|
foundObjects.push(foundObjectReference);
|
|
82
83
|
}
|
|
@@ -88,12 +89,12 @@ function processOVAL(oval) {
|
|
|
88
89
|
}
|
|
89
90
|
if (foundCriteriaRefererence.state) {
|
|
90
91
|
foundCriteriaRefererence.state.forEach((state) => {
|
|
91
|
-
if (!state[
|
|
92
|
+
if (!state['@_state_ref']) {
|
|
92
93
|
console.warn(`Found state without state_ref in test ${criteriaRef}`);
|
|
93
94
|
}
|
|
94
95
|
else {
|
|
95
|
-
const stateRef = state[
|
|
96
|
-
const foundStateReference = searchTree(parsed.oval_definitions[0].states, (oNode) => oNode[
|
|
96
|
+
const stateRef = state['@_state_ref'];
|
|
97
|
+
const foundStateReference = searchTree(parsed.oval_definitions[0].states, (oNode) => oNode['@_id'] === stateRef, false)[0];
|
|
97
98
|
if (foundStateReference) {
|
|
98
99
|
foundStates.push(foundStateReference);
|
|
99
100
|
}
|
package/lib/parsers/xccdf.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare type GroupContextualizedRule = BenchmarkRule & {
|
|
|
6
6
|
};
|
|
7
7
|
export declare function extractAllRules(groups: BenchmarkGroup[]): GroupContextualizedRule[];
|
|
8
8
|
export declare function extractAllComplexChecks(complexCheck: RuleComplexCheck): Omit<RuleComplexCheck, 'complex-check'>[];
|
|
9
|
-
export declare function processXCCDF(xml: string, removeNewlines:
|
|
9
|
+
export declare function processXCCDF(xml: string, removeNewlines: false, useRuleId: 'group' | 'rule' | 'version' | 'cis', ovalDefinitions?: Record<string, OvalDefinitionValue & {
|
|
10
10
|
criteriaRefs?: string[];
|
|
11
11
|
resolvedValues?: any;
|
|
12
12
|
}>): Profile;
|
package/lib/parsers/xccdf.js
CHANGED
|
@@ -41,7 +41,7 @@ function ensureDecodedXMLStringValue(input) {
|
|
|
41
41
|
return lodash_1.default.get(input, '[0].#text') ? lodash_1.default.get(input, '[0].#text') : input;
|
|
42
42
|
}
|
|
43
43
|
// Moving the newline removal to diff library rather than processXCCDF level
|
|
44
|
-
function processXCCDF(xml, removeNewlines
|
|
44
|
+
function processXCCDF(xml, removeNewlines, useRuleId, ovalDefinitions) {
|
|
45
45
|
const parsedXML = (0, xccdf_1.convertEncodedXmlIntoJson)(xml);
|
|
46
46
|
const rules = extractAllRules(parsedXML.Benchmark[0].Group);
|
|
47
47
|
const profile = new profile_1.default({
|
|
@@ -91,13 +91,15 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
|
|
|
91
91
|
control.id = rule.version;
|
|
92
92
|
break;
|
|
93
93
|
case 'cis':
|
|
94
|
+
// eslint-disable-next-line no-case-declarations
|
|
94
95
|
const controlIdRegex = /\d(\d?)(\d?)(\d?)(.\d(\d?)(\d?)(\d?))?(.\d(\d?)(\d?)(\d?))?(.\d(\d?)(\d?)(\d?))?(.\d(\d?)(\d?)(\d?))?/g;
|
|
96
|
+
// eslint-disable-next-line no-case-declarations
|
|
95
97
|
const controlIdMatch = controlIdRegex.exec(rule['@_id']);
|
|
96
98
|
if (controlIdMatch) {
|
|
97
99
|
control.id = controlIdMatch[0];
|
|
98
100
|
}
|
|
99
101
|
else {
|
|
100
|
-
throw new Error(`Could not parse control ID from rule ID: ${rule['@_id']}. Expecting format: 'xccdf_org.cisecurity.benchmarks_rule_1.1.11_Rule_title_summary`);
|
|
102
|
+
throw new Error(`Could not parse control ID from rule ID: ${rule['@_id']}. Expecting something in this example format: 'xccdf_org.cisecurity.benchmarks_rule_1.1.11_Rule_title_summary`);
|
|
101
103
|
}
|
|
102
104
|
break;
|
|
103
105
|
default:
|
|
@@ -147,7 +149,7 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
|
|
|
147
149
|
}
|
|
148
150
|
// Very CIS specific
|
|
149
151
|
else if (rule['complex-check']) {
|
|
150
|
-
|
|
152
|
+
const checkTexts = [];
|
|
151
153
|
for (const complexChecks of rule['complex-check']) {
|
|
152
154
|
const allComplexChecks = extractAllComplexChecks(complexChecks);
|
|
153
155
|
if (control.id === '1.1.1.5') {
|
|
@@ -226,7 +228,7 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
|
|
|
226
228
|
control.tags.gid = rule.group['@_id'],
|
|
227
229
|
control.tags.rid = rule['@_id'];
|
|
228
230
|
control.tags.stig_id = rule['version'];
|
|
229
|
-
if (typeof rule.group.title ===
|
|
231
|
+
if (typeof rule.group.title === 'string') {
|
|
230
232
|
control.tags.gtitle = (0, xccdf_1.removeXMLSpecialCharacters)(rule.group.title);
|
|
231
233
|
}
|
|
232
234
|
else {
|
|
@@ -320,6 +322,7 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
|
|
|
320
322
|
if (typeof referenceText === 'string' && referenceText.indexOf('§') !== -1) {
|
|
321
323
|
const referenceParts = referenceText.split('§');
|
|
322
324
|
if (referenceParts.length == 2) {
|
|
325
|
+
// eslint-disable-next-line prefer-const
|
|
323
326
|
let [identifierType, identifier] = referenceText.split('§');
|
|
324
327
|
identifierType = identifierType.toLowerCase();
|
|
325
328
|
if (!(identifierType in control.tags)) {
|
|
@@ -333,7 +336,7 @@ function processXCCDF(xml, removeNewlines = false, useRuleId, ovalDefinitions) {
|
|
|
333
336
|
}
|
|
334
337
|
}
|
|
335
338
|
else {
|
|
336
|
-
console.warn(
|
|
339
|
+
console.warn('Reference parts of invalid length:');
|
|
337
340
|
console.log(referenceParts);
|
|
338
341
|
}
|
|
339
342
|
}
|
package/lib/utilities/diff.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import Profile from
|
|
2
|
-
import { ProfileDiff } from
|
|
3
|
-
import winston from
|
|
1
|
+
import Profile from '../objects/profile';
|
|
2
|
+
import { ProfileDiff } from '../types/diff';
|
|
3
|
+
import winston from 'winston';
|
|
4
4
|
export declare function removeNewlines(control?: Record<string, unknown>): Record<string, unknown>;
|
|
5
5
|
export declare function ignoreFormattingDiff(diffData: Record<string, unknown>): Record<string, unknown>;
|
|
6
6
|
export declare function diffProfile(fromProfile: Profile, toProfile: Profile, logger: winston.Logger): {
|
package/lib/utilities/diff.js
CHANGED
|
@@ -11,10 +11,10 @@ function removeNewlines(control) {
|
|
|
11
11
|
return {};
|
|
12
12
|
}
|
|
13
13
|
return lodash_1.default.mapValues(control, (value) => {
|
|
14
|
-
if (typeof value ===
|
|
15
|
-
return value.replace(/\n/g,
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
return value.replace(/\n/g, '{{{{newlineHERE}}}}').trim();
|
|
16
16
|
}
|
|
17
|
-
else if (typeof value ===
|
|
17
|
+
else if (typeof value === 'object' && value !== null) {
|
|
18
18
|
return removeNewlines(value);
|
|
19
19
|
}
|
|
20
20
|
return value;
|
|
@@ -24,28 +24,28 @@ exports.removeNewlines = removeNewlines;
|
|
|
24
24
|
// Goal is to use a linter for the formatting and compare characters without whitespaces here
|
|
25
25
|
function ignoreFormattingDiff(diffData) {
|
|
26
26
|
return lodash_1.default.transform(diffData, (result, diffValue, key) => {
|
|
27
|
-
if (lodash_1.default.has(diffValue,
|
|
27
|
+
if (lodash_1.default.has(diffValue, '__new')) {
|
|
28
28
|
// Remove any trailing space
|
|
29
|
-
if (typeof lodash_1.default.get(diffValue,
|
|
30
|
-
typeof lodash_1.default.get(diffValue,
|
|
31
|
-
if ((0, global_1.removeWhitespace)(lodash_1.default.get(diffValue,
|
|
32
|
-
(0, global_1.removeWhitespace)(lodash_1.default.get(diffValue,
|
|
33
|
-
lodash_1.default.set(result, key, lodash_1.default.get(diffValue,
|
|
29
|
+
if (typeof lodash_1.default.get(diffValue, '__new') === 'string' &&
|
|
30
|
+
typeof lodash_1.default.get(diffValue, '__old') === 'string') {
|
|
31
|
+
if ((0, global_1.removeWhitespace)(lodash_1.default.get(diffValue, '__new')) !==
|
|
32
|
+
(0, global_1.removeWhitespace)(lodash_1.default.get(diffValue, '__old'))) {
|
|
33
|
+
lodash_1.default.set(result, key, lodash_1.default.get(diffValue, '__new'));
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
result[key] = lodash_1.default.get(diffValue,
|
|
37
|
+
result[key] = lodash_1.default.get(diffValue, '__new');
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
else if (Array.isArray(diffValue)) {
|
|
41
41
|
result[key] = diffValue
|
|
42
|
-
.map((value) => value[0] ===
|
|
42
|
+
.map((value) => value[0] === '+' && value[1])
|
|
43
43
|
.filter((value) => value);
|
|
44
44
|
}
|
|
45
|
-
else if (typeof diffValue ===
|
|
45
|
+
else if (typeof diffValue === 'object') {
|
|
46
46
|
result[key] = ignoreFormattingDiff(diffValue);
|
|
47
47
|
}
|
|
48
|
-
else if (key.endsWith(
|
|
48
|
+
else if (key.endsWith('__deleted')) {
|
|
49
49
|
return undefined;
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
@@ -77,13 +77,13 @@ function diffProfile(fromProfile, toProfile, logger) {
|
|
|
77
77
|
.sort();
|
|
78
78
|
const toControlIDs = toProfile.controls.map((control) => control.id).sort();
|
|
79
79
|
// Find new controls
|
|
80
|
-
const controlIDDiff = (_a = (0, json_diff_1.diff)(fromControlIDs, toControlIDs)) === null || _a === void 0 ? void 0 : _a.filter((item) => !(item.length === 1 && item[0] ===
|
|
80
|
+
const controlIDDiff = (_a = (0, json_diff_1.diff)(fromControlIDs, toControlIDs)) === null || _a === void 0 ? void 0 : _a.filter((item) => !(item.length === 1 && item[0] === ' '));
|
|
81
81
|
// Contains the new IDs
|
|
82
82
|
const changedControlIds = [];
|
|
83
83
|
// a diffValue has an entry for both what was subtracted ("-")
|
|
84
84
|
// and what was added ("+") -- need to handle both
|
|
85
85
|
controlIDDiff === null || controlIDDiff === void 0 ? void 0 : controlIDDiff.forEach((diffValue) => {
|
|
86
|
-
if (diffValue[0] ===
|
|
86
|
+
if (diffValue[0] === '-') {
|
|
87
87
|
const existingControl = fromProfile.controls.find((control) => control.id === diffValue[1]);
|
|
88
88
|
// Check if the control has been given a new ID
|
|
89
89
|
if (existingControl) {
|
|
@@ -92,7 +92,7 @@ function diffProfile(fromProfile, toProfile, logger) {
|
|
|
92
92
|
profileDiff.renamedControlIDs[existingControl.id] = newControl.id;
|
|
93
93
|
originalDiff.renamedControlIDs[existingControl.id] = newControl.id;
|
|
94
94
|
changedControlIds.push(newControl.id.toLowerCase());
|
|
95
|
-
const controlDiff = lodash_1.default.omit((0, json_diff_1.diff)(existingControl, newControl),
|
|
95
|
+
const controlDiff = lodash_1.default.omit((0, json_diff_1.diff)(existingControl, newControl), 'code__deleted');
|
|
96
96
|
// logger.info("CONTROL DIFF:" + JSON.stringify(controlDiff, null, 2))
|
|
97
97
|
const renamedControlIgnoredFormatting = ignoreFormattingDiff(controlDiff);
|
|
98
98
|
logger.info(JSON.stringify(renamedControlIgnoredFormatting));
|
|
@@ -111,7 +111,7 @@ function diffProfile(fromProfile, toProfile, logger) {
|
|
|
111
111
|
logger.error(`Unable to find existing control ${diffValue[1]}`);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
else if (diffValue[0] ===
|
|
114
|
+
else if (diffValue[0] === '+' && !changedControlIds.includes(diffValue[1].toLowerCase()) && diffValue[1]) {
|
|
115
115
|
logger.info(JSON.stringify(diffValue));
|
|
116
116
|
logger.info(JSON.stringify(changedControlIds));
|
|
117
117
|
profileDiff.addedControlIDs.push(diffValue[1]);
|
|
@@ -134,10 +134,12 @@ function diffProfile(fromProfile, toProfile, logger) {
|
|
|
134
134
|
for (const fromControl of fromProfile.controls) {
|
|
135
135
|
const toControl = toProfile.controls.find((control) => control.id === fromControl.id);
|
|
136
136
|
if (toControl) {
|
|
137
|
-
const controlDiff = lodash_1.default.omit((0, json_diff_1.diff)(fromControl, toControl),
|
|
137
|
+
const controlDiff = lodash_1.default.omit((0, json_diff_1.diff)(fromControl, toControl), 'code__deleted');
|
|
138
138
|
if (controlDiff) {
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
139
140
|
profileDiff.changedControls[toControl.id] = ignoreFormattingDiff(controlDiff);
|
|
140
141
|
profileDiff.changedControlIDs.push(toControl.id);
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
141
143
|
originalDiff.changedControls[toControl.id] = controlDiff;
|
|
142
144
|
originalDiff.changedControlIDs.push(toControl.id);
|
|
143
145
|
}
|
|
@@ -5,10 +5,6 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const mustache_1 = tslib_1.__importDefault(require("mustache"));
|
|
6
6
|
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
7
7
|
const automatticUpdateTemplate_json_1 = tslib_1.__importDefault(require("../resources/automatticUpdateTemplate.json"));
|
|
8
|
-
function getUpdatedCheckForId(id, profile) {
|
|
9
|
-
const foundControl = profile.controls.find((control) => control.id === id);
|
|
10
|
-
return lodash_1.default.get(foundControl === null || foundControl === void 0 ? void 0 : foundControl.descs, "check") || "Missing check";
|
|
11
|
-
}
|
|
12
8
|
function createDiffMarkdown(diff) {
|
|
13
9
|
const renderableDiffData = {
|
|
14
10
|
addedControls: Object.values(diff.ignoreFormattingDiff.addedControls),
|
|
@@ -30,10 +26,10 @@ function createDiffMarkdown(diff) {
|
|
|
30
26
|
Object.entries(diff.rawDiff.changedControls).forEach(([id, controlDiff]) => {
|
|
31
27
|
var _a, _b;
|
|
32
28
|
if ((_a = controlDiff.descs) === null || _a === void 0 ? void 0 : _a.check) {
|
|
33
|
-
const oldCheck = lodash_1.default.get(controlDiff.descs.check,
|
|
34
|
-
const newCheck = lodash_1.default.get(controlDiff.descs.check,
|
|
35
|
-
if (oldCheck.replace(/\n/g,
|
|
36
|
-
newCheck.replace(/\n/g,
|
|
29
|
+
const oldCheck = lodash_1.default.get(controlDiff.descs.check, '__old');
|
|
30
|
+
const newCheck = lodash_1.default.get(controlDiff.descs.check, '__new');
|
|
31
|
+
if (oldCheck.replace(/\n/g, '').replace(/\W/g, '') !==
|
|
32
|
+
newCheck.replace(/\n/g, '').replace(/\W/g, '')) {
|
|
37
33
|
renderableDiffData.updatedChecks.push({
|
|
38
34
|
id: id,
|
|
39
35
|
old: oldCheck,
|
|
@@ -42,10 +38,10 @@ function createDiffMarkdown(diff) {
|
|
|
42
38
|
}
|
|
43
39
|
}
|
|
44
40
|
if ((_b = controlDiff.descs) === null || _b === void 0 ? void 0 : _b.fix) {
|
|
45
|
-
const oldFix = lodash_1.default.get(controlDiff.descs.fix,
|
|
46
|
-
const newFix = lodash_1.default.get(controlDiff.descs.fix,
|
|
47
|
-
if (oldFix.replace(/\n/g,
|
|
48
|
-
newFix.replace(/\n/g,
|
|
41
|
+
const oldFix = lodash_1.default.get(controlDiff.descs.fix, '__old');
|
|
42
|
+
const newFix = lodash_1.default.get(controlDiff.descs.fix, '__new');
|
|
43
|
+
if (oldFix.replace(/\n/g, '').replace(/\W/g, '') !==
|
|
44
|
+
newFix.replace(/\n/g, '').replace(/\W/g, '')) {
|
|
49
45
|
renderableDiffData.updatedFixes.push({
|
|
50
46
|
id: id,
|
|
51
47
|
old: oldFix,
|
|
@@ -54,8 +50,8 @@ function createDiffMarkdown(diff) {
|
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
52
|
if (controlDiff.impact) {
|
|
57
|
-
const oldImpact = lodash_1.default.get(controlDiff.impact,
|
|
58
|
-
const newImpact = lodash_1.default.get(controlDiff.impact,
|
|
53
|
+
const oldImpact = lodash_1.default.get(controlDiff.impact, '__old');
|
|
54
|
+
const newImpact = lodash_1.default.get(controlDiff.impact, '__new');
|
|
59
55
|
if (oldImpact !== newImpact) {
|
|
60
56
|
renderableDiffData.updatedImpacts.push({
|
|
61
57
|
id: id,
|
|
@@ -65,8 +61,8 @@ function createDiffMarkdown(diff) {
|
|
|
65
61
|
}
|
|
66
62
|
}
|
|
67
63
|
if (controlDiff.title) {
|
|
68
|
-
const oldTitle = lodash_1.default.get(controlDiff.title,
|
|
69
|
-
const newTitle = lodash_1.default.get(controlDiff.title,
|
|
64
|
+
const oldTitle = lodash_1.default.get(controlDiff.title, '__old');
|
|
65
|
+
const newTitle = lodash_1.default.get(controlDiff.title, '__new');
|
|
70
66
|
if (oldTitle !== newTitle) {
|
|
71
67
|
renderableDiffData.updatedTitles.push({
|
|
72
68
|
id: id,
|
|
@@ -76,8 +72,8 @@ function createDiffMarkdown(diff) {
|
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
if (controlDiff.desc) {
|
|
79
|
-
const oldDesc = lodash_1.default.get(controlDiff.desc,
|
|
80
|
-
const newDesc = lodash_1.default.get(controlDiff.desc,
|
|
75
|
+
const oldDesc = lodash_1.default.get(controlDiff.desc, '__old');
|
|
76
|
+
const newDesc = lodash_1.default.get(controlDiff.desc, '__new');
|
|
81
77
|
if (oldDesc !== newDesc) {
|
|
82
78
|
renderableDiffData.updatedDescriptions.push({
|
|
83
79
|
id: id,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
export declare function wrap(s: string, lineLength?: number): string;
|
|
2
2
|
export declare function unformatText(s: string): string;
|
|
3
3
|
export declare function removeWhitespace(input: string): string;
|
|
4
|
-
declare
|
|
5
|
-
declare const escapeDoubleQuotes: (s: string) => string;
|
|
6
|
-
declare const wrapAndEscapeQuotes: (s: string, lineLength?: number) => string;
|
|
7
|
-
export { escapeQuotes, escapeDoubleQuotes, wrapAndEscapeQuotes };
|
|
4
|
+
export declare function escapeQuotes(s: string): string;
|
|
8
5
|
export declare function removeNewlinePlaceholders(s: string): string;
|
|
9
6
|
export declare function getFirstPath(object: Record<string, unknown>, paths: string[]): string;
|
|
10
7
|
export declare function hasPath(file: Record<string, unknown>, path: string | string[]): boolean;
|
package/lib/utilities/global.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hasPath = exports.getFirstPath = exports.removeNewlinePlaceholders = exports.
|
|
3
|
+
exports.hasPath = exports.getFirstPath = exports.removeNewlinePlaceholders = exports.escapeQuotes = exports.removeWhitespace = exports.unformatText = exports.wrap = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
6
6
|
// Breaks lines down to lineLength number of characters
|
|
7
7
|
function wrap(s, lineLength = 80) {
|
|
8
|
-
let newString =
|
|
9
|
-
let currentLine = "";
|
|
8
|
+
let newString = '';
|
|
10
9
|
let currentLength = 0;
|
|
11
10
|
let shouldBreakLine = false;
|
|
12
|
-
for (
|
|
11
|
+
for (let i = 0; i < s.length; i++) {
|
|
13
12
|
if (shouldBreakLine) {
|
|
14
|
-
newString +=
|
|
13
|
+
newString += '\n';
|
|
15
14
|
currentLength = 0;
|
|
16
15
|
shouldBreakLine = false;
|
|
17
16
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (nextChar ===
|
|
17
|
+
const currentChar = s.charAt(i);
|
|
18
|
+
const nextChar = s.charAt(i + 1);
|
|
19
|
+
if (nextChar === ' ') {
|
|
21
20
|
if (currentLength >= lineLength) {
|
|
22
21
|
shouldBreakLine = true;
|
|
23
22
|
newString += currentChar;
|
|
@@ -36,6 +35,7 @@ function wrap(s, lineLength = 80) {
|
|
|
36
35
|
return newString;
|
|
37
36
|
}
|
|
38
37
|
exports.wrap = wrap;
|
|
38
|
+
// Remove new lines and tabs
|
|
39
39
|
function unformatText(s) {
|
|
40
40
|
return s.replace(/\n/g, ' ').replace(/\\n/g, ' ').replace(/( +|\t)/g, ' ');
|
|
41
41
|
}
|
|
@@ -44,12 +44,24 @@ function removeWhitespace(input) {
|
|
|
44
44
|
return input.replace(/\s/gi, '');
|
|
45
45
|
}
|
|
46
46
|
exports.removeWhitespace = removeWhitespace;
|
|
47
|
-
const
|
|
47
|
+
const escapeSingleQuotes = (s) => {
|
|
48
|
+
return s.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); // Escape backslashes and quotes
|
|
49
|
+
};
|
|
50
|
+
const escapeDoubleQuotes = (s) => {
|
|
51
|
+
return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); // Escape backslashes and double quotes
|
|
52
|
+
};
|
|
53
|
+
function escapeQuotes(s) {
|
|
54
|
+
if (s.includes("'") && s.includes('"')) {
|
|
55
|
+
return `%q(${removeNewlinePlaceholders(s)})`;
|
|
56
|
+
}
|
|
57
|
+
else if (s.includes("'")) {
|
|
58
|
+
return `"${escapeDoubleQuotes(removeNewlinePlaceholders(s))}"`;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return `'${escapeSingleQuotes(removeNewlinePlaceholders(s))}'`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
48
64
|
exports.escapeQuotes = escapeQuotes;
|
|
49
|
-
const escapeDoubleQuotes = (s) => s.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); // Escape backslashes and double quotes
|
|
50
|
-
exports.escapeDoubleQuotes = escapeDoubleQuotes;
|
|
51
|
-
const wrapAndEscapeQuotes = (s, lineLength) => escapeDoubleQuotes(wrap(s, lineLength)); // Escape backslashes and quotes, and wrap long lines
|
|
52
|
-
exports.wrapAndEscapeQuotes = wrapAndEscapeQuotes;
|
|
53
65
|
function removeNewlinePlaceholders(s) {
|
|
54
66
|
return s.replace(/\{\{\{\{newlineHERE\}\}\}\}/g, '\n');
|
|
55
67
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import winston from
|
|
1
|
+
import winston from 'winston';
|
|
2
2
|
export declare function createWinstonLogger(level?: string): winston.Logger;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import winston from
|
|
1
|
+
import winston from 'winston';
|
|
2
2
|
import Control from '../objects/control';
|
|
3
3
|
import Profile from '../objects/profile';
|
|
4
4
|
import { ProfileDiff } from '../types/diff';
|
|
@@ -11,6 +11,7 @@ export declare type UpdatedProfileReturn = {
|
|
|
11
11
|
};
|
|
12
12
|
markdown: string;
|
|
13
13
|
};
|
|
14
|
+
export declare function getExistingDescribeFromControl(control: Control): string;
|
|
14
15
|
export declare function findUpdatedControlByAllIdentifiers(existingControl: Control, updatedControls: Control[]): Control | undefined;
|
|
15
16
|
export declare function updateControl(from: Control, update: Partial<Control>, logger: winston.Logger): Control;
|
|
16
17
|
export declare function updateProfile(from: Profile, using: Profile, logger: winston.Logger): Omit<UpdatedProfileReturn, 'markdown'>;
|
package/lib/utilities/update.js
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
// Utilities to update a profile or control with new metadata
|
|
3
3
|
// The ultimate goal is to preserve all the metadata that is already there and only add what is new
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.updateProfileUsingXCCDF = exports.updateProfile = exports.updateControl = exports.findUpdatedControlByAllIdentifiers = void 0;
|
|
5
|
+
exports.updateProfileUsingXCCDF = exports.updateProfile = exports.updateControl = exports.findUpdatedControlByAllIdentifiers = exports.getExistingDescribeFromControl = void 0;
|
|
6
6
|
const tslib_1 = require("tslib");
|
|
7
7
|
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
8
8
|
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', "\""];
|
|
13
12
|
function projectValuesOntoExistingObj(dst, src, currentPath = '') {
|
|
14
13
|
for (const updatedValue in src) {
|
|
15
14
|
const existingValue = lodash_1.default.get(dst, updatedValue);
|
|
@@ -32,101 +31,69 @@ function projectValuesOntoExistingObj(dst, src, currentPath = '') {
|
|
|
32
31
|
}
|
|
33
32
|
return dst;
|
|
34
33
|
}
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
/*
|
|
35
|
+
Return first index found from given array that is not an empty entry (cell)
|
|
36
|
+
*/
|
|
37
|
+
function getIndexOfFirstLine(auditArray, index, action) {
|
|
38
|
+
let indexVal = index;
|
|
39
|
+
while (auditArray[indexVal] === '') {
|
|
40
|
+
switch (action) {
|
|
41
|
+
case '-':
|
|
42
|
+
indexVal--;
|
|
43
|
+
break;
|
|
44
|
+
case '+':
|
|
45
|
+
indexVal++;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return indexVal;
|
|
50
|
+
}
|
|
51
|
+
/*
|
|
52
|
+
This is the most likely thing to break if you are getting code formatting issues.
|
|
53
|
+
Extract the existing describe blocks (what is actually run by inspec for validation)
|
|
54
|
+
*/
|
|
37
55
|
function getExistingDescribeFromControl(control) {
|
|
56
|
+
// Algorithm:
|
|
57
|
+
// Locate the start and end of the control string
|
|
58
|
+
// Update the end of the control that contains information (if empty lines are at the end of the control)
|
|
59
|
+
// loop: until the start index is changed (loop is done from the bottom up)
|
|
60
|
+
// Clean testing array entry line (removes any non-print characters)
|
|
61
|
+
// if: line starts with meta-information 'tag' or 'ref'
|
|
62
|
+
// set start index to found location
|
|
63
|
+
// break out of the loop
|
|
64
|
+
// end
|
|
65
|
+
// end
|
|
66
|
+
// Remove any empty lines after the start index (in any)
|
|
67
|
+
// Extract the describe block from the audit control given the start and end indices
|
|
68
|
+
// Assumptions:
|
|
69
|
+
// 1 - The meta-information 'tag' or 'ref' precedes the describe block
|
|
70
|
+
// Pros: Solves the potential issue with option 1, as the lookup for the meta-information
|
|
71
|
+
// 'tag' or 'ref' is expected to the at the beginning of the line.
|
|
38
72
|
if (control.code) {
|
|
39
73
|
let existingDescribeBlock = '';
|
|
40
|
-
let
|
|
41
|
-
let
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const wordArray = line.trim().split(' ');
|
|
52
|
-
const spaces = line.substring(0, line.indexOf(wordArray[0])).length;
|
|
53
|
-
if (spaces - mostSpacesSeen > 10) {
|
|
54
|
-
indentedMetadataOverride = true;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
mostSpacesSeen = spaces;
|
|
58
|
-
indentedMetadataOverride = false;
|
|
59
|
-
}
|
|
60
|
-
if ((!inPercentBlock && !inQuoteBlock && !inMetadataValueOverride && !indentedMetadataOverride) || inDescribeBlock) {
|
|
61
|
-
if (inDescribeBlock && wordArray.length === 1 && wordArray.includes('')) {
|
|
62
|
-
existingDescribeBlock += '\n';
|
|
63
|
-
}
|
|
64
|
-
// Get the number of spaces at the beginning of the current line
|
|
65
|
-
else if (spaces >= 2) {
|
|
66
|
-
const firstWord = wordArray[0];
|
|
67
|
-
if (knownInSpecKeywords.indexOf(firstWord.toLowerCase()) === -1 || (knownInSpecKeywords.indexOf(firstWord.toLowerCase()) !== -1 && spaces > 2) || inDescribeBlock) {
|
|
68
|
-
inDescribeBlock = true;
|
|
69
|
-
existingDescribeBlock += line + '\n';
|
|
70
|
-
}
|
|
71
|
-
}
|
|
74
|
+
let indexStart = control.code.toLowerCase().indexOf('control');
|
|
75
|
+
let indexEnd = control.code.toLowerCase().trimEnd().lastIndexOf('end');
|
|
76
|
+
const auditControl = control.code.substring(indexStart, indexEnd).split('\n');
|
|
77
|
+
indexStart = 0;
|
|
78
|
+
indexEnd = auditControl.length - 1;
|
|
79
|
+
indexEnd = getIndexOfFirstLine(auditControl, indexEnd, '-');
|
|
80
|
+
let index = indexEnd;
|
|
81
|
+
while (indexStart === 0) {
|
|
82
|
+
const line = auditControl[index].toLowerCase().trim();
|
|
83
|
+
if (line.indexOf('ref') === 0 || line.indexOf('tag') === 0) {
|
|
84
|
+
indexStart = index + 1;
|
|
72
85
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
lDelimiter = percentBlockMatch.groups.lDelimiter || '(';
|
|
79
|
-
switch (lDelimiter) {
|
|
80
|
-
case '{': {
|
|
81
|
-
rDelimiter = '}';
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
case '[': {
|
|
85
|
-
rDelimiter = ']';
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
case '<': {
|
|
89
|
-
rDelimiter = '>';
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
default: {
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const charArray = word.split('');
|
|
98
|
-
charArray.forEach((char, index) => {
|
|
99
|
-
if (inPercentBlock) {
|
|
100
|
-
if (char === rDelimiter && charArray[index - 1] !== '\\' && !inQuoteBlock) {
|
|
101
|
-
inPercentBlock = false;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (char === '"' && charArray[index - 1] !== '\\') {
|
|
105
|
-
if (!currentQuoteEscape || !inQuoteBlock) {
|
|
106
|
-
currentQuoteEscape = '"';
|
|
107
|
-
}
|
|
108
|
-
if (currentQuoteEscape === '"') {
|
|
109
|
-
inQuoteBlock = !inQuoteBlock;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
else if (char === "'" && charArray[index - 1] !== '\\') {
|
|
113
|
-
if (!currentQuoteEscape || !inQuoteBlock) {
|
|
114
|
-
currentQuoteEscape = "'";
|
|
115
|
-
}
|
|
116
|
-
if (currentQuoteEscape === "'") {
|
|
117
|
-
inQuoteBlock = !inQuoteBlock;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
// Take off the extra newline at the end
|
|
124
|
-
return existingDescribeBlock.slice(0, -1);
|
|
86
|
+
index--;
|
|
87
|
+
}
|
|
88
|
+
indexStart = getIndexOfFirstLine(auditControl, indexStart, '+');
|
|
89
|
+
existingDescribeBlock = auditControl.slice(indexStart, indexEnd + 1).join('\n').toString();
|
|
90
|
+
return existingDescribeBlock;
|
|
125
91
|
}
|
|
126
92
|
else {
|
|
127
93
|
return '';
|
|
128
94
|
}
|
|
129
95
|
}
|
|
96
|
+
exports.getExistingDescribeFromControl = getExistingDescribeFromControl;
|
|
130
97
|
function findUpdatedControlByAllIdentifiers(existingControl, updatedControls) {
|
|
131
98
|
// Try to match based on IDs
|
|
132
99
|
let updatedControl = updatedControls.find((updatedControl) => {
|
package/lib/utilities/xccdf.js
CHANGED
|
@@ -25,7 +25,6 @@ function removeXMLSpecialCharacters(str) {
|
|
|
25
25
|
return he_1.default.decode(str);
|
|
26
26
|
}
|
|
27
27
|
exports.removeXMLSpecialCharacters = removeXMLSpecialCharacters;
|
|
28
|
-
;
|
|
29
28
|
function severityStringToImpact(string, id) {
|
|
30
29
|
var _a, _b, _c, _d, _e;
|
|
31
30
|
if ((_a = string.match(/none|na|n\/a|not[\s()*_|]?applicable/i)) === null || _a === void 0 ? void 0 : _a.length) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mitre/inspec-objects",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"description": "Typescript objects for normalizing between InSpec profiles and XCCDF benchmarks",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc -p ./tsconfig.build.json",
|
|
11
11
|
"dev": "npx -y ts-node test.ts",
|
|
12
|
-
"test": "jest"
|
|
12
|
+
"test": "jest",
|
|
13
|
+
"lint": "eslint \"**/*.ts\" --fix",
|
|
14
|
+
"lint:ci": "eslint \"**/*.ts\" --max-warnings 0"
|
|
13
15
|
},
|
|
14
16
|
"repository": {
|
|
15
17
|
"type": "git",
|
|
@@ -48,8 +50,9 @@
|
|
|
48
50
|
"devDependencies": {
|
|
49
51
|
"@types/jest": "^28.1.1",
|
|
50
52
|
"@types/node": "^17.0.18",
|
|
51
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
52
|
-
"eslint": "^
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
|
54
|
+
"@typescript-eslint/parser": "^5.47.0",
|
|
55
|
+
"eslint": "^8.30.0",
|
|
53
56
|
"tslib": "^2.4.0"
|
|
54
57
|
},
|
|
55
58
|
"jest": {
|
package/tsconfig.json
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"moduleResolution": "node",
|
|
5
|
+
"noImplicitAny": true,
|
|
6
|
+
"resolveJsonModule": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"importHelpers": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"outDir": "lib",
|
|
11
|
+
"rootDir": "src",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"target": "es2019",
|
|
14
|
+
"types": ["node", "jest"]
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"index.ts",
|
|
18
|
+
"src/**/*",
|
|
19
|
+
"types/*"
|
|
20
|
+
],
|
|
21
|
+
}
|