@contrast/core 1.45.1 → 1.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -6
- package/lib/app-info.test.js +0 -189
- package/lib/build-id.test.js +0 -39
- package/lib/capture-stacktrace.test.js +0 -55
- package/lib/contrast-methods.test.js +0 -299
- package/lib/sensitive-data-masking/index.test.js +0 -163
- package/lib/system-info/cloud-provider-metadata.test.js +0 -160
- package/lib/system-info/index.test.js +0 -34
- package/lib/system-info/linux-os-info.test.js +0 -121
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.46.0",
|
|
4
4
|
"description": "Preconfigured Contrast agent core services and models",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
|
|
7
7
|
"files": [
|
|
8
|
-
"lib/"
|
|
8
|
+
"lib/",
|
|
9
|
+
"!*.test.*",
|
|
10
|
+
"!tsconfig.*",
|
|
11
|
+
"!*.map"
|
|
9
12
|
],
|
|
10
13
|
"types": "lib/index.d.ts",
|
|
11
14
|
"engines": {
|
|
@@ -16,12 +19,12 @@
|
|
|
16
19
|
"test": "../scripts/test.sh"
|
|
17
20
|
},
|
|
18
21
|
"dependencies": {
|
|
19
|
-
"@contrast/common": "1.
|
|
20
|
-
"@contrast/config": "1.
|
|
22
|
+
"@contrast/common": "1.30.0",
|
|
23
|
+
"@contrast/config": "1.41.0",
|
|
21
24
|
"@contrast/find-package-json": "^1.1.0",
|
|
22
25
|
"@contrast/fn-inspect": "^4.3.0",
|
|
23
|
-
"@contrast/logger": "1.
|
|
24
|
-
"@contrast/patcher": "1.
|
|
26
|
+
"@contrast/logger": "1.19.0",
|
|
27
|
+
"@contrast/patcher": "1.18.0",
|
|
25
28
|
"@tsxper/crc32": "^2.1.3",
|
|
26
29
|
"axios": "^1.7.4",
|
|
27
30
|
"semver": "^7.6.0"
|
package/lib/app-info.test.js
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const proxyquire = require('proxyquire');
|
|
6
|
-
const mocks = require('@contrast/test/mocks');
|
|
7
|
-
|
|
8
|
-
describe('core app-info', function () {
|
|
9
|
-
let os, core, appInfo;
|
|
10
|
-
|
|
11
|
-
beforeEach(function () {
|
|
12
|
-
core = mocks.core();
|
|
13
|
-
core.config = mocks.config();
|
|
14
|
-
core.config.server.type = 'Node.js';
|
|
15
|
-
core.config.server.environment = 'PRODUCTION';
|
|
16
|
-
core.logger = mocks.logger();
|
|
17
|
-
core.config.server.name = 'zoing';
|
|
18
|
-
|
|
19
|
-
os = {
|
|
20
|
-
type: sinon.stub().returns('Linux'),
|
|
21
|
-
platform: sinon.stub().returns('linux'),
|
|
22
|
-
arch: sinon.stub().returns('x64'),
|
|
23
|
-
release: sinon.stub().returns('1.23.45'),
|
|
24
|
-
hostname: sinon.stub().returns('hostname'),
|
|
25
|
-
};
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('builds out app data from os and process information', function () {
|
|
29
|
-
appInfo = proxyquire(
|
|
30
|
-
'./app-info',
|
|
31
|
-
{
|
|
32
|
-
os,
|
|
33
|
-
process: {
|
|
34
|
-
...process,
|
|
35
|
-
argv: ['node', __filename],
|
|
36
|
-
version: 'v14.17.5'
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
)(core);
|
|
40
|
-
|
|
41
|
-
expect(appInfo).to.deep.include({
|
|
42
|
-
os: {
|
|
43
|
-
type: 'Linux',
|
|
44
|
-
platform: 'linux',
|
|
45
|
-
architecture: 'x64',
|
|
46
|
-
release: '1.23.45'
|
|
47
|
-
},
|
|
48
|
-
hostname: 'hostname',
|
|
49
|
-
indexFile: __filename,
|
|
50
|
-
serverVersion: undefined,
|
|
51
|
-
nodeVersion: 'v14.17.5',
|
|
52
|
-
appPath: '/',
|
|
53
|
-
serverName: 'zoing',
|
|
54
|
-
serverType: 'Node.js',
|
|
55
|
-
serverEnvironment: 'PRODUCTION',
|
|
56
|
-
group: undefined,
|
|
57
|
-
metadata: undefined
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("instantiates with _errors if package con't be found at provided app_root", function() {
|
|
62
|
-
const { npm_package_json } = process.env;
|
|
63
|
-
delete process.env.npm_package_json;
|
|
64
|
-
|
|
65
|
-
core.config.agent.node.app_root = '/no/package/at/this/path';
|
|
66
|
-
appInfo = proxyquire(
|
|
67
|
-
'./app-info',
|
|
68
|
-
{
|
|
69
|
-
os,
|
|
70
|
-
process: {
|
|
71
|
-
...process,
|
|
72
|
-
argv: ['node', ''],
|
|
73
|
-
version: 'v14.17.5'
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
);
|
|
77
|
-
const fn = () => appInfo(core);
|
|
78
|
-
expect(fn).throws('unable to locate application package.json');
|
|
79
|
-
|
|
80
|
-
process.env.npm_package_json = npm_package_json;
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
[
|
|
84
|
-
{ version: 'v20.12.0', range: '>=18.19.0', badFlag: '-r', goodFlag: ['--import'] },
|
|
85
|
-
{ version: 'v18.18.0', range: '>=16.17.0 <18.19.0', badFlag: '-r', goodFlag: ['--loader'] },
|
|
86
|
-
{ version: 'v16.16.0', range: '<16.17.0', badFlag: '--loader', goodFlag: ['-r', '--require'] }
|
|
87
|
-
].forEach(({ version, range, badFlag, goodFlag }) => {
|
|
88
|
-
|
|
89
|
-
it(`does not log a warning if '@contrast/agent' is not part of exec args (${version})`, function() {
|
|
90
|
-
appInfo = proxyquire(
|
|
91
|
-
'./app-info',
|
|
92
|
-
{
|
|
93
|
-
os,
|
|
94
|
-
process: {
|
|
95
|
-
...process,
|
|
96
|
-
argv: ['node', __filename],
|
|
97
|
-
version,
|
|
98
|
-
execArgv: [badFlag, 'some/file']
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
)(core);
|
|
102
|
-
expect(core.logger.warn).to.not.have.been.called;
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it(`logs a warning if non-recommended preload flag is used (${version})`, function() {
|
|
106
|
-
appInfo = proxyquire(
|
|
107
|
-
'./app-info',
|
|
108
|
-
{
|
|
109
|
-
os,
|
|
110
|
-
process: {
|
|
111
|
-
...process,
|
|
112
|
-
argv: ['node', __filename],
|
|
113
|
-
version,
|
|
114
|
-
execArgv: [badFlag, '@contrast/agent']
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
)(core);
|
|
118
|
-
expect(core.logger.warn).to.have.been.calledWith(
|
|
119
|
-
'For Node LTS %s, use %s command to run the agent. See: https://docs.contrastsecurity.com/en/install-node-js.html',
|
|
120
|
-
range,
|
|
121
|
-
goodFlag
|
|
122
|
-
);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it(`logs a warning if non-recommended preload flag is used in NODE_OPTIONS (${version})`, function() {
|
|
126
|
-
appInfo = proxyquire(
|
|
127
|
-
'./app-info',
|
|
128
|
-
{
|
|
129
|
-
os,
|
|
130
|
-
process: {
|
|
131
|
-
...process,
|
|
132
|
-
argv: ['node', __filename],
|
|
133
|
-
version,
|
|
134
|
-
execArgv: [],
|
|
135
|
-
env: {
|
|
136
|
-
NODE_OPTIONS: `${badFlag} @contrast/agent`
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
)(core);
|
|
141
|
-
expect(core.logger.warn).to.have.been.calledWith(
|
|
142
|
-
'For Node LTS %s, use %s command to run the agent. See: https://docs.contrastsecurity.com/en/install-node-js.html',
|
|
143
|
-
range,
|
|
144
|
-
goodFlag
|
|
145
|
-
);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
[
|
|
150
|
-
{ version: 'v20.12.0', goodFlag: '--import' },
|
|
151
|
-
{ version: 'v18.18.0', goodFlag: '--loader' },
|
|
152
|
-
{ version: 'v16.16.0', goodFlag: '--require' }
|
|
153
|
-
].forEach(({ version, goodFlag }) => {
|
|
154
|
-
it('does not log a warning if recommended preload flag is used', function() {
|
|
155
|
-
appInfo = proxyquire(
|
|
156
|
-
'./app-info',
|
|
157
|
-
{
|
|
158
|
-
os,
|
|
159
|
-
process: {
|
|
160
|
-
...process,
|
|
161
|
-
argv: ['node', __filename],
|
|
162
|
-
version,
|
|
163
|
-
execArgv: [goodFlag, '@contrast/agent']
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
)(core);
|
|
167
|
-
expect(core.logger.warn).not.to.have.been.called;
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('does not log a warning if recommended preload flag is used in NODE_OPTIONS', function() {
|
|
171
|
-
appInfo = proxyquire(
|
|
172
|
-
'./app-info',
|
|
173
|
-
{
|
|
174
|
-
os,
|
|
175
|
-
process: {
|
|
176
|
-
...process,
|
|
177
|
-
argv: ['node', __filename],
|
|
178
|
-
version,
|
|
179
|
-
execArgv: [],
|
|
180
|
-
env: {
|
|
181
|
-
NODE_OPTIONS: `${goodFlag} @contrast/agent`
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
)(core);
|
|
186
|
-
expect(core.logger.warn).not.to.have.been.called;
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
});
|
package/lib/build-id.test.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const proxyquire = require('proxyquire');
|
|
6
|
-
|
|
7
|
-
describe('core build-id', function () {
|
|
8
|
-
let fs, getBuildId;
|
|
9
|
-
|
|
10
|
-
beforeEach(function() {
|
|
11
|
-
fs = { readFile: sinon.stub().rejects() };
|
|
12
|
-
|
|
13
|
-
getBuildId = proxyquire('./build-id', { 'fs/promises': fs })({
|
|
14
|
-
appInfo: {
|
|
15
|
-
app_dir: '/app',
|
|
16
|
-
pkg: { 'name': 'test', 'main': 'index.js', 'dependencies': {} }
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('resolves a string when package-lock is found', async function () {
|
|
22
|
-
fs.readFile.onCall(0).resolves(
|
|
23
|
-
Buffer.from('{"name":"test","lockfileVersion":3,"requires":true,"packages":{}}')
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
expect(await getBuildId()).to.equal('c6378fdf');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('resolves a string when package-lock is not found first', async function () {
|
|
30
|
-
expect(await getBuildId()).to.equal('55d7b2de');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('memoizes the result', async function () {
|
|
34
|
-
expect(await getBuildId()).to.equal('55d7b2de');
|
|
35
|
-
expect(fs.readFile).to.have.callCount(1);
|
|
36
|
-
await getBuildId();
|
|
37
|
-
expect(fs.readFile).to.have.callCount(1);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { expect } = require('chai');
|
|
4
|
-
const mocks = require('@contrast/test/mocks');
|
|
5
|
-
|
|
6
|
-
describe('core capture-stacktrace', function g() {
|
|
7
|
-
let core;
|
|
8
|
-
|
|
9
|
-
beforeEach(function () {
|
|
10
|
-
core = mocks.core();
|
|
11
|
-
core.config = mocks.config();
|
|
12
|
-
require('./capture-stacktrace')(core);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('appends a stack getter property', function () {
|
|
16
|
-
const obj = { foo: 'bar' };
|
|
17
|
-
core.captureStacktrace(obj);
|
|
18
|
-
const desc = Object.getOwnPropertyDescriptor(obj, 'stack');
|
|
19
|
-
expect(typeof desc.get).to.equal('function');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('generates a stacktrace from given options', function () {
|
|
23
|
-
(function outer() {
|
|
24
|
-
(function inner() {
|
|
25
|
-
const obj = {};
|
|
26
|
-
core.captureStacktrace(obj, { constructorOpt: inner });
|
|
27
|
-
expect(obj.stack[0]).to.have.property('method', 'outer');
|
|
28
|
-
expect(obj.stack).to.have.lengthOf(10);
|
|
29
|
-
})();
|
|
30
|
-
})();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('createSnapshot', function () {
|
|
34
|
-
it('prepends desired frames', function() {
|
|
35
|
-
const frame = { foo: 'bar' };
|
|
36
|
-
const stub = function stub() { };
|
|
37
|
-
|
|
38
|
-
const snapshot = core.createSnapshot({ prependFrames: [frame, stub] });
|
|
39
|
-
const result = snapshot();
|
|
40
|
-
expect(result[0]).to.equal(frame);
|
|
41
|
-
expect(result[1]).to.have.property('method', 'stub');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('handles `eval`', function () {
|
|
45
|
-
const snapshot = eval('core.createSnapshot()');
|
|
46
|
-
const result = snapshot();
|
|
47
|
-
|
|
48
|
-
expect(result).to.have.length(10);
|
|
49
|
-
const evalFrame = result[3];
|
|
50
|
-
expect(evalFrame).to.have.property('eval').that.is.not.undefined;
|
|
51
|
-
expect(evalFrame).to.have.property('file').that.matches(/capture-stacktrace.test.js$/);
|
|
52
|
-
expect(evalFrame).to.have.property('method', 'eval');
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
});
|
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const mocks = require('@contrast/test/mocks');
|
|
6
|
-
const patcher = require('@contrast/patcher');
|
|
7
|
-
|
|
8
|
-
const { stringify } = JSON;
|
|
9
|
-
|
|
10
|
-
const title = (method, args, expected) =>
|
|
11
|
-
`${method}(${args.map(stringify).join(', ')}) = ${stringify(expected)}`;
|
|
12
|
-
|
|
13
|
-
describe('core contrast-methods', function () {
|
|
14
|
-
let core, contrastMethods, api;
|
|
15
|
-
|
|
16
|
-
beforeEach(function () {
|
|
17
|
-
core = mocks.core();
|
|
18
|
-
core.logger = mocks.logger();
|
|
19
|
-
core.patcher = patcher(core);
|
|
20
|
-
sinon.spy(core.patcher, 'patch');
|
|
21
|
-
contrastMethods = require('./contrast-methods')(core);
|
|
22
|
-
api = contrastMethods.api;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const GENERIC_TESTS = [{}, null, 1, 'two', undefined];
|
|
26
|
-
|
|
27
|
-
describe('.api', function () {
|
|
28
|
-
describe('.eval()', function () {
|
|
29
|
-
GENERIC_TESTS.forEach((arg) => {
|
|
30
|
-
it(title('eval', [arg], arg), function () {
|
|
31
|
-
expect(api.eval(arg)).to.equal(arg);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const ADD_TESTS = [
|
|
37
|
-
[[1, 2], 3],
|
|
38
|
-
[[1, '2'], '12'],
|
|
39
|
-
[['foo', 'bar'], 'foobar'],
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
describe('.addAssign()', function () {
|
|
43
|
-
ADD_TESTS.forEach(([args, expected]) => {
|
|
44
|
-
it(title('addAssign', args, expected), function () {
|
|
45
|
-
expect(api.addAssign(...args)).to.equal(expected);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe('.add()', function () {
|
|
51
|
-
ADD_TESTS.forEach(([args, expected], i) => {
|
|
52
|
-
it(title('add', args, expected), function () {
|
|
53
|
-
expect(api.add(...args)).to.equal(expected);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const obj1 = { foo: 'bar' };
|
|
59
|
-
const obj2 = { foo: 'bar' };
|
|
60
|
-
const EQ_TESTS = [
|
|
61
|
-
[['', ''], true, true],
|
|
62
|
-
[['foo', 'foo'], true, true],
|
|
63
|
-
[['foo', 'bar'], false, false],
|
|
64
|
-
[[1, 1], true, true],
|
|
65
|
-
[[1, 2], false, false],
|
|
66
|
-
[[1, '1'], true, false],
|
|
67
|
-
[[obj1, obj1], true, true],
|
|
68
|
-
[[obj1, obj2], false, false],
|
|
69
|
-
];
|
|
70
|
-
|
|
71
|
-
describe('.eqEq()', function () {
|
|
72
|
-
EQ_TESTS.forEach(([args, expected]) => {
|
|
73
|
-
it(title('eqEq', args, expected), function () {
|
|
74
|
-
expect(api.eqEq(...args)).to.equal(expected);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
describe('.eqEqEq()', function () {
|
|
80
|
-
EQ_TESTS.forEach(([args, _, expected]) => {
|
|
81
|
-
it(title('eqEqEq', args, expected), function () {
|
|
82
|
-
expect(api.eqEqEq(...args)).to.equal(expected);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('.notEq()', function () {
|
|
88
|
-
EQ_TESTS.forEach(([args, expected]) => {
|
|
89
|
-
it(title('notEq', args, !expected), function () {
|
|
90
|
-
expect(api.notEq(...args)).to.equal(!expected);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe('.notEqEq()', function () {
|
|
96
|
-
EQ_TESTS.forEach(([args, _, expected]) => {
|
|
97
|
-
it(title('notEqEq', args, !expected), function () {
|
|
98
|
-
expect(api.notEqEq(...args)).to.equal(!expected);
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('.forceCopy()', function () {
|
|
104
|
-
GENERIC_TESTS.forEach((arg) => {
|
|
105
|
-
it(title('forceCopy', [arg], arg), function () {
|
|
106
|
-
expect(api.forceCopy(arg)).to.equal(arg);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
describe('.cast()', function () {
|
|
112
|
-
GENERIC_TESTS.forEach((arg) => {
|
|
113
|
-
it(title('cast', [arg], arg), function () {
|
|
114
|
-
expect(api.cast(arg)).to.equal(arg);
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe('.tag()', function () {
|
|
120
|
-
const bar = 'bar';
|
|
121
|
-
const baz = 'baz';
|
|
122
|
-
|
|
123
|
-
[
|
|
124
|
-
[[['']], ``], // eslint-disable-line quotes
|
|
125
|
-
[[['foo']], `foo`], // eslint-disable-line quotes
|
|
126
|
-
[[['', ''], bar], `${bar}`],
|
|
127
|
-
[[['foo', ''], bar], `foo${bar}`],
|
|
128
|
-
[[['foo', 'boo'], bar], `foo${bar}boo`],
|
|
129
|
-
[[['foo', 'boo', ''], bar, baz], `foo${bar}boo${baz}`],
|
|
130
|
-
[[['foo', 'boo', '.'], bar, baz], `foo${bar}boo${baz}.`],
|
|
131
|
-
].forEach(([args, template]) => {
|
|
132
|
-
it(title('tag', args, template), function () {
|
|
133
|
-
expect(api.tag(...args)).to.equal(template);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
describe('.Function()', function () {
|
|
139
|
-
it('patches the Function global', function () {
|
|
140
|
-
expect(core.patcher.patch).to.have.been.calledWithExactly(Function, {
|
|
141
|
-
name: 'global.Function',
|
|
142
|
-
patchType: 'rewrite-injection',
|
|
143
|
-
funcKey: 'rewrite-injection:global.Function',
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('acts as a function constructor', function () {
|
|
148
|
-
const fn = api.Function('return "hello world"');
|
|
149
|
-
|
|
150
|
-
expect(fn()).to.equal('hello world');
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe('.Number()', function () {
|
|
155
|
-
it('patches the Number global', function () {
|
|
156
|
-
expect(core.patcher.patch).to.have.been.calledWithExactly(Number, {
|
|
157
|
-
name: 'global.Number',
|
|
158
|
-
patchType: 'rewrite-injection',
|
|
159
|
-
funcKey: 'rewrite-injection:global.Number',
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('Number(14)', function () {
|
|
164
|
-
const result = api.Number(14);
|
|
165
|
-
|
|
166
|
-
expect(typeof result).to.equal('number');
|
|
167
|
-
expect(result).to.equal(14);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it("Number('14')", function () {
|
|
171
|
-
const result = api.Number('14');
|
|
172
|
-
|
|
173
|
-
expect(typeof result).to.equal('number');
|
|
174
|
-
expect(result).to.equal(14);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it("Number('boo')", function () {
|
|
178
|
-
const result = api.Number('boo');
|
|
179
|
-
|
|
180
|
-
expect(typeof result).to.equal('number');
|
|
181
|
-
expect(result).to.be.NaN;
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
describe('.Object()', function () {
|
|
186
|
-
it('patches the Object global', function () {
|
|
187
|
-
expect(core.patcher.patch).to.have.been.calledWithExactly(Object, {
|
|
188
|
-
name: 'global.Object',
|
|
189
|
-
patchType: 'rewrite-injection',
|
|
190
|
-
funcKey: 'rewrite-injection:global.Object',
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('Object(null)', function () {
|
|
195
|
-
const result = api.Object(null);
|
|
196
|
-
|
|
197
|
-
expect(typeof result).to.equal('object');
|
|
198
|
-
expect(result).not.to.equal({});
|
|
199
|
-
expect(result).to.deep.equal({});
|
|
200
|
-
expect(result.toString()).to.equal('[object Object]');
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it("Object({ foo: 'bar' })", function () {
|
|
204
|
-
const obj = { foo: 'bar' };
|
|
205
|
-
const result = api.Object(obj);
|
|
206
|
-
|
|
207
|
-
expect(typeof result).to.equal('object');
|
|
208
|
-
expect(result).to.equal(obj);
|
|
209
|
-
expect(result.toString()).to.equal('[object Object]');
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it("Object('boo')", function () {
|
|
213
|
-
const str = 'boo';
|
|
214
|
-
const result = api.Object(str);
|
|
215
|
-
|
|
216
|
-
expect(typeof result).to.equal('object');
|
|
217
|
-
expect(result == str).to.be.true;
|
|
218
|
-
expect(result === str).to.be.false;
|
|
219
|
-
expect(result.toString()).to.equal(str);
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
describe('.String()', function () {
|
|
224
|
-
it('patches the String global', function () {
|
|
225
|
-
expect(core.patcher.patch).to.have.been.calledWithExactly(String, {
|
|
226
|
-
name: 'global.String',
|
|
227
|
-
patchType: 'rewrite-injection',
|
|
228
|
-
funcKey: 'rewrite-injection:global.String',
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("String('boo')", function () {
|
|
233
|
-
const str = 'boo';
|
|
234
|
-
const result = api.String(str);
|
|
235
|
-
|
|
236
|
-
expect(typeof result).to.equal('string');
|
|
237
|
-
expect(result).to.equal(str);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('String(14)', function () {
|
|
241
|
-
const result = api.String(14);
|
|
242
|
-
|
|
243
|
-
expect(typeof result).to.equal('string');
|
|
244
|
-
expect(result).to.equal('14');
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it("String({ foo: 'bar' })", function () {
|
|
248
|
-
const result = api.String({ foo: 'bar' });
|
|
249
|
-
|
|
250
|
-
expect(typeof result).to.equal('string');
|
|
251
|
-
expect(result).to.equal('[object Object]');
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
describe('.getGlobal()', function () {
|
|
257
|
-
it('returns global', function () {
|
|
258
|
-
expect(contrastMethods.getGlobal()).to.equal(global);
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
describe('.install()', function () {
|
|
263
|
-
let globalMock;
|
|
264
|
-
|
|
265
|
-
beforeEach(function () {
|
|
266
|
-
globalMock = {};
|
|
267
|
-
sinon.stub(contrastMethods, 'getGlobal').returns(globalMock);
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it('installs on global a single time', function () {
|
|
271
|
-
expect(globalMock).not.to.have.property('ContrastMethods');
|
|
272
|
-
|
|
273
|
-
contrastMethods.install();
|
|
274
|
-
expect(globalMock).to.have.property('ContrastMethods', api);
|
|
275
|
-
expect(contrastMethods.getGlobal).to.have.been.calledOnce;
|
|
276
|
-
|
|
277
|
-
expect(() => {
|
|
278
|
-
delete globalMock.ContrastMethods;
|
|
279
|
-
}).throw("Cannot delete property 'ContrastMethods'");
|
|
280
|
-
|
|
281
|
-
contrastMethods.install();
|
|
282
|
-
expect(globalMock).to.have.property('ContrastMethods', api);
|
|
283
|
-
expect(contrastMethods.getGlobal).to.have.been.calledOnce;
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
it('logs an error when global.ContrastMethods cannot be injected', function () {
|
|
287
|
-
Object.defineProperty(globalMock, 'ContrastMethods', {
|
|
288
|
-
configurable: false,
|
|
289
|
-
value: 'does not matter for test',
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
contrastMethods.install();
|
|
293
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
294
|
-
sinon.match(Error),
|
|
295
|
-
'Unable to define global.ContrastMethods',
|
|
296
|
-
);
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
});
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { describe } = require('mocha');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const dataMaskingFactory = require('../sensitive-data-masking');
|
|
6
|
-
const mocks = require('@contrast/test/mocks');
|
|
7
|
-
const { Event, Rule } = require('@contrast/common');
|
|
8
|
-
|
|
9
|
-
describe('core sensitive-data-masking', function () {
|
|
10
|
-
let core, sdMasking, reqData, parsedParams, parsedCookies, parsedQuery, parsedBody, protect, resultsMap, trackRequest;
|
|
11
|
-
|
|
12
|
-
const ssn = '123-12-1234';
|
|
13
|
-
const cvv = '123';
|
|
14
|
-
const routingNumber = '123123123';
|
|
15
|
-
const apiToken = '$123-abcd<456*def';
|
|
16
|
-
const policy = require('../../test/resources/sensitive-data-policy');
|
|
17
|
-
|
|
18
|
-
beforeEach(function () {
|
|
19
|
-
core = mocks.core();
|
|
20
|
-
core.config = mocks.config();
|
|
21
|
-
core.logger = mocks.logger();
|
|
22
|
-
core.protect = mocks.protect();
|
|
23
|
-
core.config.api.enable = false;
|
|
24
|
-
|
|
25
|
-
reqData = {
|
|
26
|
-
uriPath: `/test/${cvv}/stuff`,
|
|
27
|
-
queries: `apiToken=${apiToken}&foo=bar`,
|
|
28
|
-
headers: [
|
|
29
|
-
'routingAccNum',
|
|
30
|
-
routingNumber,
|
|
31
|
-
],
|
|
32
|
-
};
|
|
33
|
-
parsedQuery = { ssn };
|
|
34
|
-
parsedParams = { cvv };
|
|
35
|
-
parsedCookies = { ssn };
|
|
36
|
-
parsedBody = { ssn, input: '../../etc/passwd' };
|
|
37
|
-
|
|
38
|
-
trackRequest = true;
|
|
39
|
-
resultsMap = {
|
|
40
|
-
'sql-injection': [
|
|
41
|
-
{
|
|
42
|
-
value: apiToken,
|
|
43
|
-
score: 10,
|
|
44
|
-
ruleId: Rule.SQL_INJECTION,
|
|
45
|
-
path: [],
|
|
46
|
-
mappedId: 'sql-injection',
|
|
47
|
-
key: 'apiToken',
|
|
48
|
-
inputType: 'HeaderValue',
|
|
49
|
-
idsList: [
|
|
50
|
-
'worth-watching'
|
|
51
|
-
],
|
|
52
|
-
exploitMetadata: [],
|
|
53
|
-
blocked: false
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
value: ssn,
|
|
57
|
-
score: 10,
|
|
58
|
-
ruleId: Rule.SQL_INJECTION,
|
|
59
|
-
path: [],
|
|
60
|
-
mappedId: 'sql-injection',
|
|
61
|
-
key: 'ssn',
|
|
62
|
-
inputType: 'JsonValue',
|
|
63
|
-
idsList: [],
|
|
64
|
-
exploitMetadata: [],
|
|
65
|
-
blocked: false
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
protect = {
|
|
71
|
-
reqData,
|
|
72
|
-
parsedQuery,
|
|
73
|
-
parsedParams,
|
|
74
|
-
parsedCookies,
|
|
75
|
-
parsedBody,
|
|
76
|
-
resultsMap,
|
|
77
|
-
trackRequest
|
|
78
|
-
};
|
|
79
|
-
sdMasking = dataMaskingFactory(core);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('logs when no policy is in server-settings message', function () {
|
|
83
|
-
core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {});
|
|
84
|
-
expect(sdMasking.policy.keywordSets).to.be.empty;
|
|
85
|
-
expect(sdMasking.policy.idMap).to.be.empty;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('handler is noop if no settings have been published', function () {
|
|
89
|
-
const store = { protect };
|
|
90
|
-
|
|
91
|
-
core.messages.emit(Event.PROTECT, store);
|
|
92
|
-
|
|
93
|
-
expect(reqData.uriPath).to.contain(cvv);
|
|
94
|
-
expect(reqData.queries).to.contain(apiToken);
|
|
95
|
-
expect(reqData.headers[1]).to.equal(routingNumber);
|
|
96
|
-
expect(parsedCookies).to.have.property('ssn', ssn);
|
|
97
|
-
expect(parsedQuery).to.have.property('ssn', ssn);
|
|
98
|
-
expect(parsedParams).to.have.property('cvv', cvv);
|
|
99
|
-
expect(protect.parsedBody).to.have.property('ssn', ssn);
|
|
100
|
-
expect(
|
|
101
|
-
resultsMap['sql-injection'][0]
|
|
102
|
-
).to.have.property('value', apiToken);
|
|
103
|
-
expect(
|
|
104
|
-
store.protect.resultsMap['sql-injection'][1]
|
|
105
|
-
).to.have.property('value', ssn);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('handles protect message', function () {
|
|
109
|
-
const store = { protect };
|
|
110
|
-
|
|
111
|
-
core.messages.emit(Event.SERVER_SETTINGS_UPDATE, { sensitive_data_masking_policy: policy });
|
|
112
|
-
expect(core.logger.trace).to.have.been.calledWith('updating sensitive data masking policy');
|
|
113
|
-
expect(parsedCookies).to.have.property('ssn', ssn);
|
|
114
|
-
|
|
115
|
-
core.messages.emit(Event.PROTECT, store);
|
|
116
|
-
|
|
117
|
-
expect(reqData.uriPath).to.equal('/test/contrast-redacted-financial-info/stuff');
|
|
118
|
-
expect(reqData.queries).to.equal('apiToken=contrast-redacted-authentication-info&foo=bar');
|
|
119
|
-
expect(reqData.headers[1]).to.equal('contrast-redacted-financial-info');
|
|
120
|
-
expect(parsedCookies).to.have.property('ssn', 'contrast-redacted-government-id');
|
|
121
|
-
expect(parsedQuery).to.have.property('ssn', 'contrast-redacted-government-id');
|
|
122
|
-
expect(parsedParams).to.have.property('cvv', 'contrast-redacted-financial-info');
|
|
123
|
-
expect(protect.parsedBody).to.equal('contrast-redacted-body');
|
|
124
|
-
expect(
|
|
125
|
-
resultsMap['sql-injection'][0]
|
|
126
|
-
).to.have.property('value', 'contrast-redacted-authentication-info');
|
|
127
|
-
expect(
|
|
128
|
-
store.protect.resultsMap['sql-injection'][1]
|
|
129
|
-
).to.have.property('value', 'contrast-redacted-government-id');
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('policy controls masking of attack vectors and body', function () {
|
|
133
|
-
const store = { protect };
|
|
134
|
-
core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {
|
|
135
|
-
sensitive_data_masking_policy: {
|
|
136
|
-
...policy,
|
|
137
|
-
mask_http_body: false,
|
|
138
|
-
mask_attack_vector: false,
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
expect(core.logger.trace).to.have.been.calledWith('updating sensitive data masking policy');
|
|
142
|
-
expect(parsedCookies).to.have.property('ssn', ssn);
|
|
143
|
-
|
|
144
|
-
core.messages.emit(Event.PROTECT, store);
|
|
145
|
-
|
|
146
|
-
expect(reqData.uriPath).to.equal('/test/contrast-redacted-financial-info/stuff');
|
|
147
|
-
expect(reqData.queries).to.equal('apiToken=contrast-redacted-authentication-info&foo=bar');
|
|
148
|
-
expect(reqData.headers[1]).to.equal('contrast-redacted-financial-info');
|
|
149
|
-
expect(parsedCookies).to.have.property('ssn', 'contrast-redacted-government-id');
|
|
150
|
-
expect(parsedQuery).to.have.property('ssn', 'contrast-redacted-government-id');
|
|
151
|
-
expect(parsedParams).to.have.property('cvv', 'contrast-redacted-financial-info');
|
|
152
|
-
expect(protect.parsedBody).to.deep.equal({
|
|
153
|
-
ssn: 'contrast-redacted-government-id',
|
|
154
|
-
input: '../../etc/passwd'
|
|
155
|
-
});
|
|
156
|
-
expect(
|
|
157
|
-
resultsMap['sql-injection'][0]
|
|
158
|
-
).to.have.property('value', apiToken);
|
|
159
|
-
expect(
|
|
160
|
-
store.protect.resultsMap['sql-injection'][1]
|
|
161
|
-
).to.have.property('value', ssn);
|
|
162
|
-
});
|
|
163
|
-
});
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const sinon = require('sinon');
|
|
5
|
-
const { expect } = require('chai');
|
|
6
|
-
const proxyquire = require('proxyquire');
|
|
7
|
-
const { CanceledError } = require('axios');
|
|
8
|
-
|
|
9
|
-
describe('core system-result cloud-provider-metadata', function () {
|
|
10
|
-
/** @type {sinon.SinonStub} */
|
|
11
|
-
let axios;
|
|
12
|
-
/** @type {import('./cloud-provider-metadata').getCloudProviderMetadata} */
|
|
13
|
-
let getCloudProviderMetadata;
|
|
14
|
-
|
|
15
|
-
beforeEach(function () {
|
|
16
|
-
axios = sinon.stub().rejects();
|
|
17
|
-
|
|
18
|
-
getCloudProviderMetadata = proxyquire('./cloud-provider-metadata', {
|
|
19
|
-
axios: { default: axios }
|
|
20
|
-
}).getCloudProviderMetadata;
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
describe('AWS', function () {
|
|
24
|
-
it('handles aws', async function () {
|
|
25
|
-
axios.onCall(0).resolves({ data: 'foo' });
|
|
26
|
-
axios.onCall(1).resolves({ data: { region: 'us-east1', accountId: '123456789', instanceId: 'i-012345678' } });
|
|
27
|
-
|
|
28
|
-
const result = await getCloudProviderMetadata('AWS');
|
|
29
|
-
expect(axios).to.have.callCount(2);
|
|
30
|
-
expect(axios).to.have.been.calledWithMatch({
|
|
31
|
-
method: 'PUT',
|
|
32
|
-
url: 'http://169.254.169.254/latest/api/token',
|
|
33
|
-
headers: {
|
|
34
|
-
'X-aws-ec2-metadata-token-ttl-seconds': '300'
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
expect(axios).to.have.been.calledWithMatch({
|
|
38
|
-
method: 'GET',
|
|
39
|
-
url: 'http://169.254.169.254/latest/dynamic/instance-identity/document',
|
|
40
|
-
headers: {
|
|
41
|
-
'X-aws-ec2-metadata-token': 'foo'
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
expect(result).to.deep.equal({
|
|
45
|
-
provider: 'aws',
|
|
46
|
-
id: 'arn:aws:ec2:us-east1:123456789:instance/i-012345678',
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('handles errors', async function () {
|
|
51
|
-
axios.onCall(0).resolves({ data: 'foo' });
|
|
52
|
-
axios.onCall(1).rejects();
|
|
53
|
-
|
|
54
|
-
const result = await getCloudProviderMetadata('AWS');
|
|
55
|
-
expect(axios).to.have.callCount(2);
|
|
56
|
-
expect(axios).to.have.been.calledWithMatch({
|
|
57
|
-
method: 'PUT',
|
|
58
|
-
url: 'http://169.254.169.254/latest/api/token',
|
|
59
|
-
headers: {
|
|
60
|
-
'X-aws-ec2-metadata-token-ttl-seconds': '300'
|
|
61
|
-
},
|
|
62
|
-
proxy: false,
|
|
63
|
-
});
|
|
64
|
-
expect(axios).to.have.been.calledWithMatch({
|
|
65
|
-
method: 'GET',
|
|
66
|
-
url: 'http://169.254.169.254/latest/dynamic/instance-identity/document',
|
|
67
|
-
headers: {
|
|
68
|
-
'X-aws-ec2-metadata-token': 'foo'
|
|
69
|
-
},
|
|
70
|
-
proxy: false,
|
|
71
|
-
});
|
|
72
|
-
expect(result).to.be.null;
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
describe('Azure', function () {
|
|
77
|
-
it('handles azure', async function () {
|
|
78
|
-
// example from azure docs: https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service?tabs=linux#access-azure-instance-metadata-service
|
|
79
|
-
const id = '/subscriptions/xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx/resourceGroups/macikgo-test-may-23/providers/Microsoft.Compute/virtualMachines/examplevmname';
|
|
80
|
-
axios.resolves({ data: id });
|
|
81
|
-
|
|
82
|
-
const result = await getCloudProviderMetadata('Azure');
|
|
83
|
-
expect(axios).to.have.callCount(1);
|
|
84
|
-
expect(axios).to.have.been.calledWithMatch({
|
|
85
|
-
method: 'GET',
|
|
86
|
-
url: 'http://169.254.169.254/metadata/instance/compute/resourceId?api-version=2021-02-01&format=text',
|
|
87
|
-
headers: {
|
|
88
|
-
Metadata: 'true'
|
|
89
|
-
},
|
|
90
|
-
proxy: false,
|
|
91
|
-
});
|
|
92
|
-
expect(result).to.deep.equal({ provider: 'azure', id });
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('handles errors', async function () {
|
|
96
|
-
axios.rejects();
|
|
97
|
-
|
|
98
|
-
const result = await getCloudProviderMetadata('Azure');
|
|
99
|
-
expect(axios).to.have.callCount(1);
|
|
100
|
-
expect(result).to.be.null;
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe('GCP', function () {
|
|
105
|
-
it('handles gcp', async function () {
|
|
106
|
-
axios.resolves({ data: '954399829989587067' });
|
|
107
|
-
|
|
108
|
-
const result = await getCloudProviderMetadata('GCP');
|
|
109
|
-
expect(axios).to.have.callCount(1);
|
|
110
|
-
expect(axios).to.have.been.calledWithMatch({
|
|
111
|
-
method: 'GET',
|
|
112
|
-
url: 'http://169.254.169.254/computeMetadata/v1/instance/id?alt=text',
|
|
113
|
-
headers: {
|
|
114
|
-
'Metadata-Flavor': 'Google'
|
|
115
|
-
},
|
|
116
|
-
proxy: false,
|
|
117
|
-
});
|
|
118
|
-
expect(result).to.deep.equal({ provider: 'gcp', id: '954399829989587067' });
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('retries if a 503 is returned', async function () {
|
|
122
|
-
axios.onCall(0).rejects({ response: { status: 503 } });
|
|
123
|
-
axios.onCall(1).resolves({ data: '954399829989587067' });
|
|
124
|
-
|
|
125
|
-
const result = await getCloudProviderMetadata('GCP');
|
|
126
|
-
expect(axios).to.have.callCount(2);
|
|
127
|
-
expect(result).to.deep.equal({ provider: 'gcp', id: '954399829989587067' });
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('handles misc errors', async function () {
|
|
131
|
-
axios.rejects();
|
|
132
|
-
|
|
133
|
-
const result = await getCloudProviderMetadata('GCP');
|
|
134
|
-
expect(axios).to.have.callCount(1);
|
|
135
|
-
expect(result).to.be.null;
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
describe('auto-detection', function () {
|
|
140
|
-
this.beforeEach(function () {
|
|
141
|
-
axios.rejects(new CanceledError('canceled'));
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('returns null if all responses timeout', async function () {
|
|
145
|
-
const result = await getCloudProviderMetadata(undefined);
|
|
146
|
-
expect(axios).to.have.callCount(3); // 1 aws + 1 azure + 1 gcp
|
|
147
|
-
expect(result).to.be.null;
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('handles a single valid response', async function () {
|
|
151
|
-
axios.withArgs(sinon.match({
|
|
152
|
-
url: 'http://169.254.169.254/metadata/instance/compute/resourceId?api-version=2021-02-01&format=text',
|
|
153
|
-
})).resolves({ data: 'azure-resource-identifier' });
|
|
154
|
-
|
|
155
|
-
const result = await getCloudProviderMetadata(undefined);
|
|
156
|
-
expect(axios).to.have.callCount(3); // 1 aws + 1 azure + 1 gcp
|
|
157
|
-
expect(result).to.deep.equal({ provider: 'azure', id: 'azure-resource-identifier' });
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const proxyquire = require('proxyquire');
|
|
6
|
-
|
|
7
|
-
describe('core system-info', function () {
|
|
8
|
-
let core;
|
|
9
|
-
|
|
10
|
-
beforeEach(function () {
|
|
11
|
-
core = require('@contrast/test/mocks/core')();
|
|
12
|
-
core.config = require('@contrast/test/mocks/config')();
|
|
13
|
-
|
|
14
|
-
proxyquire('.', {
|
|
15
|
-
'./cloud-provider-metadata': {
|
|
16
|
-
getCloudProviderMetadata: sinon.stub().resolves(null)
|
|
17
|
-
}
|
|
18
|
-
})(core);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('returns a properly structured object', async function () {
|
|
22
|
-
const info = await core.getSystemInfo();
|
|
23
|
-
|
|
24
|
-
expect(info).to.not.be.undefined;
|
|
25
|
-
expect(info).to.haveOwnProperty('ReportDate');
|
|
26
|
-
expect(info).to.haveOwnProperty('MachineName');
|
|
27
|
-
expect(info).to.haveOwnProperty('Contrast');
|
|
28
|
-
expect(info).to.haveOwnProperty('Node');
|
|
29
|
-
expect(info).to.haveOwnProperty('OperatingSystem');
|
|
30
|
-
expect(info).to.haveOwnProperty('Host');
|
|
31
|
-
expect(info).to.haveOwnProperty('Application');
|
|
32
|
-
expect(info).to.haveOwnProperty('Cloud');
|
|
33
|
-
});
|
|
34
|
-
});
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fsp = require('node:fs/promises');
|
|
4
|
-
const os = require('node:os');
|
|
5
|
-
const { expect } = require('chai');
|
|
6
|
-
const sinon = require('sinon');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
# cat /etc/os-release
|
|
10
|
-
NAME="Alpine Linux"
|
|
11
|
-
ID=alpine
|
|
12
|
-
VERSION_ID=3.20.3
|
|
13
|
-
PRETTY_NAME="Alpine Linux v3.20"
|
|
14
|
-
HOME_URL="https://alpinelinux.org/"
|
|
15
|
-
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
|
|
16
|
-
# cat /etc/alpine-release
|
|
17
|
-
3.20.3
|
|
18
|
-
|
|
19
|
-
# cat /etc/os-release
|
|
20
|
-
PRETTY_NAME="Ubuntu 22.04.3 LTS"
|
|
21
|
-
NAME="Ubuntu"
|
|
22
|
-
VERSION_ID="22.04"
|
|
23
|
-
VERSION="22.04.3 LTS (Jammy Jellyfish)"
|
|
24
|
-
VERSION_CODENAME=jammy
|
|
25
|
-
ID=ubuntu
|
|
26
|
-
ID_LIKE=debian
|
|
27
|
-
HOME_URL="https://www.ubuntu.com/"
|
|
28
|
-
SUPPORT_URL="https://help.ubuntu.com/"
|
|
29
|
-
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
|
|
30
|
-
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
|
|
31
|
-
UBUNTU_CODENAME=jammy
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
const linuxOsInfo = require('./linux-os-info');
|
|
35
|
-
|
|
36
|
-
describe('linux-os-info', function() {
|
|
37
|
-
let fsStub;
|
|
38
|
-
let osStub;
|
|
39
|
-
|
|
40
|
-
beforeEach(function() {
|
|
41
|
-
fsStub = sinon.stub(fsp, 'readFile');
|
|
42
|
-
// fake up so test passes on windows.
|
|
43
|
-
osStub = sinon.stub(os, 'type').returns('Linux');
|
|
44
|
-
});
|
|
45
|
-
afterEach(function() {
|
|
46
|
-
fsStub.restore();
|
|
47
|
-
osStub.restore();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should return info for Ubuntu', async function() {
|
|
51
|
-
fsStub.withArgs('/etc/os-release').resolves('PRETTY_NAME="Ubuntu 22.04.3 LTS"\nNAME="Ubuntu"\nVERSION_ID="22.04"\nVERSION="22.04.3 LTS (Jammy Jellyfish)"\nVERSION_CODENAME=jammy\nID=ubuntu\nID_LIKE=debian\nHOME_URL="https://www.ubuntu.com/"\nSUPPORT_URL="https://help.ubuntu.com/"\nBUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"\nPRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"\nUBUNTU_CODENAME=jammy\n');
|
|
52
|
-
fsStub.withArgs('/etc/alpine-release').rejects(new Error('ENOENT'));
|
|
53
|
-
|
|
54
|
-
const result = await linuxOsInfo();
|
|
55
|
-
expect(result).to.deep.equal({
|
|
56
|
-
file: '/etc/os-release',
|
|
57
|
-
pretty_name: 'Ubuntu 22.04.3 LTS',
|
|
58
|
-
name: 'Ubuntu',
|
|
59
|
-
id: 'ubuntu',
|
|
60
|
-
version_id: '22.04',
|
|
61
|
-
version: '22.04.3 LTS (Jammy Jellyfish)',
|
|
62
|
-
version_codename: 'jammy',
|
|
63
|
-
id_like: 'debian',
|
|
64
|
-
home_url: 'https://www.ubuntu.com/',
|
|
65
|
-
support_url: 'https://help.ubuntu.com/',
|
|
66
|
-
bug_report_url: 'https://bugs.launchpad.net/ubuntu/',
|
|
67
|
-
privacy_policy_url: 'https://www.ubuntu.com/legal/terms-and-policies/privacy-policy',
|
|
68
|
-
ubuntu_codename: 'jammy',
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should return info for Alpine without an os-release file', async function() {
|
|
73
|
-
fsStub.withArgs('/etc/os-release').rejects(new Error('ENOENT'));
|
|
74
|
-
fsStub.withArgs('/usr/lib/os-release').rejects(new Error('ENOENT'));
|
|
75
|
-
fsStub.withArgs('/etc/alpine-release').resolves('3.20.3\n');
|
|
76
|
-
|
|
77
|
-
const result = await linuxOsInfo();
|
|
78
|
-
expect(result).to.deep.equal({
|
|
79
|
-
file: '/etc/alpine-release',
|
|
80
|
-
name: 'Alpine',
|
|
81
|
-
id: 'alpine',
|
|
82
|
-
version: '3.20.3',
|
|
83
|
-
version_id: '3.20.3',
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should return info for Alpine with an os-release file', async function() {
|
|
88
|
-
fsStub.withArgs('/etc/os-release').resolves('NAME="Alpine Linux"\nID=alpine\nVERSION_ID=3.20.3\nPRETTY_NAME="Alpine Linux v3.20"\nHOME_URL="https://alpinelinux.org/"\nBUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"\n');
|
|
89
|
-
fsStub.withArgs('/usr/lib/os-release').rejects(new Error('ENOENT'));
|
|
90
|
-
fsStub.withArgs('/etc/alpine-release').resolves('3.20.3\n');
|
|
91
|
-
|
|
92
|
-
const result = await linuxOsInfo();
|
|
93
|
-
expect(result).to.deep.equal({
|
|
94
|
-
file: '/etc/os-release',
|
|
95
|
-
name: 'Alpine Linux',
|
|
96
|
-
id: 'alpine',
|
|
97
|
-
version_id: '3.20.3',
|
|
98
|
-
pretty_name: 'Alpine Linux v3.20',
|
|
99
|
-
home_url: 'https://alpinelinux.org/',
|
|
100
|
-
bug_report_url: 'https://gitlab.alpinelinux.org/alpine/aports/-/issues',
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should return info when no os-release or alpine-release files are found', async function() {
|
|
105
|
-
fsStub.withArgs('/etc/os-release').rejects(new Error('ENOENT'));
|
|
106
|
-
fsStub.withArgs('/usr/lib/os-release').rejects(new Error('ENOENT'));
|
|
107
|
-
fsStub.withArgs('/etc/alpine-release').rejects(new Error('ENOENT'));
|
|
108
|
-
|
|
109
|
-
const result = await linuxOsInfo();
|
|
110
|
-
// no file found
|
|
111
|
-
expect(result).deep.equal({ file: undefined });
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('should return null for non-linux systems', async function() {
|
|
115
|
-
osStub.returns('Windows_NT');
|
|
116
|
-
|
|
117
|
-
const result = await linuxOsInfo();
|
|
118
|
-
|
|
119
|
-
expect(result).to.be.null;
|
|
120
|
-
});
|
|
121
|
-
});
|