@contrast/agentify 1.28.0 → 1.29.1

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.
@@ -0,0 +1,174 @@
1
+ 'use strict';
2
+
3
+ const { expect } = require('chai');
4
+ const mocks = require('@contrast/test/mocks');
5
+ const functionHooks = require('./function-hooks');
6
+
7
+ describe('agentify function-hooks', function () {
8
+ let core;
9
+
10
+ beforeEach(function () {
11
+ core = mocks.core();
12
+ core.patcher = mocks.patcher();
13
+ core.logger = mocks.logger();
14
+ core.depHooks = mocks.depHooks();
15
+ core.scopes = mocks.scopes();
16
+ core.rewriter = mocks.rewriter();
17
+ });
18
+
19
+ it('should install function hooks', function () {
20
+ functionHooks(core);
21
+ core.functionHooks.install();
22
+ expect(core.functionHooks.installed).to.be.true;
23
+ });
24
+
25
+ it('should skip if it is already installed', function () {
26
+ functionHooks(core);
27
+ core.functionHooks.installed = true;
28
+ core.functionHooks.install();
29
+
30
+ expect(core.logger.debug).not.to.have.been.called;
31
+ });
32
+
33
+ it('should return cached value when the function is already called', function () {
34
+ const functionA = function sum(a, b) {
35
+ eval(global.ContrastMethods.eval('2 + 2'));
36
+ return a + b;
37
+ };
38
+
39
+ const cachedValue = 'cachedValue';
40
+
41
+ functionHooks(core);
42
+
43
+ core.functionHooks.cache.set(functionA, cachedValue);
44
+
45
+ const data = {
46
+ obj: functionA,
47
+ };
48
+
49
+ let result;
50
+ core.patcher.patch.callsFake((prototype, method, options) => {
51
+ result = options.around(() => ({}), data);
52
+ });
53
+
54
+ core.functionHooks.install();
55
+
56
+ expect(result).to.equal(cachedValue);
57
+ });
58
+
59
+ it('should call the function itself when the function is not hooked', function () {
60
+ const functionA = function sum(a, b) {
61
+ eval(global.ContrastMethods.eval('2 + 2'));
62
+ return a + b;
63
+ };
64
+
65
+ functionHooks(core);
66
+
67
+ const data = {
68
+ obj: functionA,
69
+ };
70
+
71
+ let result;
72
+ core.patcher.patch.callsFake((prototype, method, options) => {
73
+ result = options.around(functionA.toString.bind(functionA), data);
74
+ });
75
+
76
+ const unwriteResult = `function sum(a, b) {
77
+ eval(2 + 2);
78
+ return a + b;
79
+ }`;
80
+
81
+ core.rewriter.unwriteSync.callsFake((data) => unwriteResult);
82
+
83
+ core.functionHooks.install();
84
+
85
+ expect(result).to.equal(unwriteResult);
86
+ expect(core.functionHooks.cache.get(data.obj)).to.equal(unwriteResult);
87
+ });
88
+
89
+ it('should the call the original function of the hooked function', function () {
90
+ const functionA = function sum(a, b) {
91
+ eval(global.ContrastMethods.eval('2 + 2'));
92
+ return a + b;
93
+ };
94
+
95
+ const functionB = function sum(a, b) {
96
+ eval(global.ContrastMethods.eval('2 + 2'));
97
+ return a + b + 2;
98
+ };
99
+
100
+ functionHooks(core);
101
+
102
+ const weekMap = core.patcher.hookedFunctions;
103
+ weekMap.set(functionA, { fn: functionB });
104
+
105
+ const data = {
106
+ obj: functionA,
107
+ };
108
+
109
+ let result;
110
+ core.patcher.patch.callsFake((prototype, method, options) => {
111
+ result = options.around(functionA.toString.bind(functionA), data);
112
+ });
113
+
114
+ const unwriteResult = `function sum(a, b) {
115
+ eval(2 + 2);
116
+ return a + b + 2;
117
+ }`;
118
+
119
+ core.rewriter.unwriteSync.callsFake((data) => unwriteResult);
120
+
121
+
122
+ core.functionHooks.install();
123
+
124
+ expect(result).to.equal(unwriteResult);
125
+ expect(core.functionHooks.cache.get(data.obj)).to.equal(unwriteResult);
126
+ });
127
+
128
+ it('should log warning message when there is a problem unwriting the code', function () {
129
+ const err = new Error('Error');
130
+ const functionA = function sum(a, b) {
131
+ eval(global.ContrastMethods.eval('2 + 2'));
132
+ return a + b;
133
+ };
134
+
135
+ functionHooks(core);
136
+
137
+ const data = {
138
+ obj: functionA,
139
+ };
140
+
141
+ core.patcher.patch.callsFake((prototype, method, options) => {
142
+ options.around(functionA.toString.bind(functionA), data);
143
+ });
144
+
145
+ core.rewriter.unwriteSync.throws(err);
146
+
147
+ core.functionHooks.install();
148
+
149
+ expect(core.logger.warn).to.have.been.calledWith({ err, code: functionA.toString() }, 'Failed to unwrite function code');
150
+ });
151
+
152
+ it('should call the original toString if the function is not hooked', function () {
153
+ const functionA = () => 1;
154
+ functionHooks(core);
155
+ core.functionHooks.install();
156
+
157
+ const resultOfA = functionA.toString();
158
+
159
+ expect(resultOfA).to.equal('() => 1');
160
+ });
161
+
162
+ it('should uninstall the hooks', function () {
163
+ const { toString } = Function.prototype;
164
+ const functionA = () => 1;
165
+ functionHooks(core);
166
+ core.functionHooks.install();
167
+ core.functionHooks.uninstall();
168
+
169
+ const resultOfA = functionA.toString();
170
+
171
+ expect(resultOfA).to.equal('() => 1');
172
+ expect(Function.prototype.toString).to.equal(toString);
173
+ });
174
+ });
@@ -0,0 +1,92 @@
1
+ 'use strict';
2
+
3
+ const { expect } = require('chai');
4
+ const path = require('path');
5
+ const proxyquire = require('proxyquire');
6
+ const sinon = require('sinon');
7
+ const { ConfigSource: { ENVIRONMENT_VARIABLE } } = require('@contrast/config');
8
+ const mocks = require('@contrast/test/mocks');
9
+ const { delay } = require('@contrast/test/utils');
10
+
11
+
12
+ describe('heap dump', function () {
13
+ let core,
14
+ heapSnapshots,
15
+ fsMock,
16
+ v8Mock,
17
+ dirname,
18
+ delayMs,
19
+ windowMs,
20
+ snapshotPath;
21
+
22
+ beforeEach(function () {
23
+ fsMock = {
24
+ promises: {
25
+ mkdir: sinon.stub().resolves(''),
26
+ }
27
+ };
28
+ v8Mock = {
29
+ writeHeapSnapshot: sinon.stub(),
30
+ };
31
+ delayMs = windowMs = 100;
32
+ snapshotPath = 'contrast_heap_dumps';
33
+ dirname = path.join(process.cwd(), snapshotPath);
34
+
35
+ core = {};
36
+ core.config = mocks.config();
37
+ core.logger = mocks.logger();
38
+
39
+ core.config.setValue('agent.heap_dump.enable', true, ENVIRONMENT_VARIABLE);
40
+ core.config.setValue('agent.heap_dump.path', snapshotPath, ENVIRONMENT_VARIABLE);
41
+ core.config.setValue('agent.heap_dump.delay_ms', delayMs, ENVIRONMENT_VARIABLE);
42
+ core.config.setValue('agent.heap_dump.window_ms', windowMs, ENVIRONMENT_VARIABLE);
43
+ core.config.setValue('agent.heap_dump.count', 2, ENVIRONMENT_VARIABLE);
44
+
45
+ const init = proxyquire('./heap-snapshots', {
46
+ fs: fsMock,
47
+ v8: v8Mock,
48
+ });
49
+
50
+ heapSnapshots = init(core);
51
+ });
52
+
53
+ describe('.writeHeapSnapshot()', function () {
54
+ it('writes snapshots', function () {
55
+ heapSnapshots.writeHeapSnapshot();
56
+ expect(core.logger.info).to.have.been.calledWithMatch(
57
+ 'Writing heap snapshot at %s',
58
+ dirname,
59
+ );
60
+ expect(v8Mock.writeHeapSnapshot).to.have.been.calledWithMatch(dirname);
61
+ });
62
+ });
63
+
64
+ describe('.install()', function () {
65
+ it('logs when the directory cannot be created', async function () {
66
+ const err = new Error('ENOENT');
67
+ fsMock.promises.mkdir.rejects(err);
68
+ await heapSnapshots.install();
69
+ expect(core.logger.error).to.have.been.calledOnceWithExactly({
70
+ err,
71
+ }, 'Unable to create snapshot directory. No heap snapshots will be taken.');
72
+ expect(v8Mock.writeHeapSnapshot).not.to.have.been.called;
73
+ });
74
+
75
+
76
+ it('does not write snapshots if enable is false', function () {
77
+ core.config.setValue('agent.heap_dumps.enable', false, ENVIRONMENT_VARIABLE);
78
+ heapSnapshots.install();
79
+ expect(v8Mock.writeHeapSnapshot).not.to.have.been.called;
80
+ });
81
+
82
+ it('writes snapshots at the correct intervals', async function () {
83
+ heapSnapshots.install();
84
+ expect(v8Mock.writeHeapSnapshot).not.to.have.been.called;
85
+ const pad = 50;
86
+ await delay(delayMs + windowMs + pad);
87
+ expect(v8Mock.writeHeapSnapshot).to.have.callCount(1);
88
+ await delay(windowMs);
89
+ expect(v8Mock.writeHeapSnapshot).to.have.callCount(2);
90
+ });
91
+ });
92
+ });
@@ -0,0 +1,169 @@
1
+ 'use strict';
2
+
3
+ const { expect } = require('chai');
4
+ const proxyquire = require('proxyquire');
5
+ const sinon = require('sinon');
6
+ const mocks = require('@contrast/test/mocks');
7
+
8
+ describe('agentify', function () {
9
+ const Module = require('module');
10
+ let agentify, preRunMain, runMain;
11
+
12
+ beforeEach(function () {
13
+ // added because the config validation code verifies that the agent has
14
+ // the three required settings and throws if not.
15
+ process.env.CONTRAST__API__API_KEY = 'testing';
16
+ process.env.CONTRAST__API__SERVICE_KEY = 'testing';
17
+ process.env.CONTRAST__API__USER_NAME = 'testing';
18
+
19
+ agentify = proxyquire('.', {
20
+ '@contrast/logger': {
21
+ default(core) {
22
+ return core.logger = mocks.logger();
23
+ }
24
+ },
25
+ '@contrast/dep-hooks'(core) {
26
+ return core.depHooks = mocks.depHooks();
27
+ },
28
+ })();
29
+ preRunMain = sinon.stub();
30
+ runMain = sinon.stub(Module, 'runMain');
31
+ });
32
+
33
+ after(function() {
34
+ delete process.env.CONTRAST__API__API_KEY;
35
+ delete process.env.CONTRAST__API__SERVICE_KEY;
36
+ delete process.env.CONTRAST__API_USER_NAME;
37
+ });
38
+
39
+ it('invoking with callback will initialize and patch runMain', async function () {
40
+ const core = await agentify(preRunMain, {
41
+ noValidate: true,
42
+ installOrder: ['depHooks'],
43
+ });
44
+
45
+ await Module.runMain();
46
+
47
+ expect(preRunMain).to.have.been.calledWith(core);
48
+ expect(runMain).to.have.been.called;
49
+ expect(core.depHooks.install).to.have.been.called;
50
+ expect(core.logger.error).not.to.have.been.called;
51
+ });
52
+
53
+ it('will not run install methods when installOrder option is empty array', async function () {
54
+ const core = await agentify(preRunMain, { installOrder: [] });
55
+ await Module.runMain();
56
+
57
+ expect(core.depHooks.install).not.to.have.been.called;
58
+ expect(core.logger.error).not.to.have.been.called;
59
+ });
60
+
61
+
62
+ it('handles errors in plugin initialization functions with logger', async function () {
63
+ const err = new Error('oof');
64
+ const agentify = proxyquire('.', {
65
+ '@contrast/logger': {
66
+ default(core) {
67
+ return core.logger = mocks.logger();
68
+ }
69
+ },
70
+ '@contrast/dep-hooks'() {
71
+ throw err;
72
+ },
73
+ })();
74
+
75
+ const core = await agentify(preRunMain, {
76
+ noValidate: true,
77
+ installOrder: ['depHooks'],
78
+ });
79
+
80
+ await Module.runMain();
81
+
82
+ expect(core).not.to.have.property('depHooks');
83
+ expect(runMain).to.have.been.called;
84
+ expect(core.logger.error).to.have.been.calledWith({ err });
85
+ });
86
+
87
+
88
+ it('handles errors in plugin initialization functions without logger', async function () {
89
+ const consoleErrorStub = sinon.stub(console, 'error');
90
+ const err = new Error('boop');
91
+ const agentify = proxyquire('.', {
92
+ '@contrast/logger': {
93
+ default() {
94
+ throw err;
95
+ }
96
+ },
97
+ '@contrast/dep-hooks'(core) {
98
+ return core.depHooks = mocks.depHooks();
99
+ },
100
+ })();
101
+
102
+ const core = await agentify(preRunMain, {
103
+ noValidate: true,
104
+ installOrder: ['depHooks'],
105
+ });
106
+
107
+ await Module.runMain();
108
+
109
+ expect(core).not.to.have.property('depHooks');
110
+ expect(runMain).to.have.been.called;
111
+ expect(consoleErrorStub).to.have.been.called;
112
+ });
113
+
114
+ it('handles errors in the preRunMain hook', async function () {
115
+ const err = new Error('bonk');
116
+ preRunMain.throws(err);
117
+ const core = await agentify(preRunMain, {
118
+ noValidate: true,
119
+ installOrder: ['depHooks'],
120
+ });
121
+
122
+ await Module.runMain();
123
+
124
+ expect(core.depHooks.install).not.to.have.been.called;
125
+ expect(runMain).to.have.been.called;
126
+ expect(core.logger.error).to.have.been.calledWith({ err });
127
+ });
128
+
129
+ it('handles "unregistered" services', async function () {
130
+ const core = await agentify(preRunMain, {
131
+ noValidate: true,
132
+ installOrder: ['foo'],
133
+ });
134
+
135
+ // Having non-existent service in list is handled during initialization
136
+ await Module.runMain();
137
+
138
+ expect(core.logger.error).not.to.have.been.called;
139
+ });
140
+
141
+ it('handles the return value of preRunMain', async function () {
142
+ const install = sinon.stub();
143
+ preRunMain.returns({ install });
144
+ const core = await agentify(preRunMain, { installOrder: [] });
145
+
146
+ // Having non-existent service in list is handled during initialization
147
+ await Module.runMain();
148
+
149
+ expect(install).to.have.been.called;
150
+ expect(core.logger.error).not.to.have.been.called;
151
+ });
152
+
153
+ it('handles the return value of preRunMain when erroring', async function () {
154
+ const err = new Error('err in install');
155
+ const install = sinon.stub().throws(err);
156
+ preRunMain.returns({ install });
157
+ const core = await agentify(preRunMain, { installOrder: [] });
158
+
159
+ // Having non-existent service in list is handled during initialization
160
+ await Module.runMain();
161
+
162
+ expect(install).to.have.been.called;
163
+ expect(core.logger.error).to.have.been.calledWith({ err });
164
+ });
165
+
166
+ it('requires init function arg', async function () {
167
+ return expect(agentify('not a function')).to.be.rejectedWith('Invalid usage: first argument must be a function');
168
+ });
169
+ });
@@ -0,0 +1,139 @@
1
+ // @ts-check
2
+ 'use strict';
3
+
4
+ const { expect } = require('chai');
5
+ const { readFileSync } = require('fs');
6
+ const Module = require('module');
7
+ const sinon = require('sinon');
8
+ const mocks = require('@contrast/test/mocks');
9
+
10
+ const testFilePath = require.resolve('../test/resources/file');
11
+ const deadzonedFilePath = require.resolve('../test/node_modules/bcryptjs/dist/bcrypt.js');
12
+ const testFileContent = readFileSync(testFilePath).toString();
13
+
14
+ describe('agentify rewrite-hooks', function () {
15
+ let core, complileSpy, rewriteHooks;
16
+
17
+ beforeEach(function () {
18
+ core = mocks.core();
19
+ core.logger = mocks.logger();
20
+ core.config = mocks.config();
21
+ core.rewriter = mocks.rewriter();
22
+
23
+ complileSpy = sinon.spy(Module.prototype, '_compile');
24
+
25
+ rewriteHooks = require('./rewrite-hooks')(core);
26
+ });
27
+
28
+ afterEach(function () {
29
+ delete require.cache[testFilePath];
30
+ rewriteHooks.uninstall();
31
+ });
32
+
33
+ it('rewrites code when the cache returns no results expected', function () {
34
+ core.rewriter.cache.readSync.returns(undefined);
35
+ rewriteHooks.install();
36
+
37
+ require(testFilePath);
38
+ expect(core.rewriter.rewriteSync).to.have.been.calledWith(testFileContent, {
39
+ filename: testFilePath,
40
+ isModule: false,
41
+ inject: true,
42
+ wrap: true,
43
+ });
44
+ expect(core.logger.warn).not.to.have.been.called;
45
+ expect(complileSpy).to.have.been.calledWith(
46
+ core.rewriter.rewriteSync.getCall(0).returnValue.code,
47
+ testFilePath,
48
+ );
49
+ });
50
+
51
+ it('does not not rewrite code when rewrite.enable is false', function () {
52
+ core.config.agent.node.rewrite.enable = false;
53
+ rewriteHooks.install();
54
+
55
+ require(testFilePath);
56
+ expect(core.rewriter.rewriteSync).not.to.have.been.called;
57
+ });
58
+
59
+ it('does not not rewrite code when the cache returns results', function () {
60
+ rewriteHooks.install();
61
+
62
+ require(testFilePath);
63
+ expect(core.rewriter.rewriteSync).not.to.have.been.called;
64
+ expect(complileSpy).to.have.been.calledWith(
65
+ core.rewriter.cache.readSync.getCall(0).returnValue,
66
+ testFilePath,
67
+ );
68
+ });
69
+
70
+ it('logs a debug message when a file is rewrite-deadzoned', function() {
71
+ rewriteHooks.install();
72
+
73
+ require(deadzonedFilePath);
74
+
75
+ expect(core.logger.debug).calledWith(
76
+ 'Skipping rewrite-deadzoned file %s',
77
+ deadzonedFilePath
78
+ );
79
+ });
80
+
81
+ it('logs a warning if the rewritten module does not compile', function () {
82
+ core.rewriter.cache.readSync.returns(undefined);
83
+ core.rewriter.rewriteSync.callsFake((content) => ({
84
+ code: content.replace('const variable', 'const variable const a'),
85
+ }));
86
+
87
+ rewriteHooks.install();
88
+
89
+ require(testFilePath);
90
+ expect(core.rewriter.rewriteSync).to.have.been.calledWith(testFileContent, {
91
+ filename: testFilePath,
92
+ isModule: false,
93
+ inject: true,
94
+ wrap: true,
95
+ });
96
+ expect(core.logger.warn).to.have.been.calledWith(
97
+ {
98
+ err: sinon.match({
99
+ message: 'Missing initializer in const declaration',
100
+ }),
101
+ },
102
+ 'Failed to compile rewritten code for %s, compiling original code.',
103
+ testFilePath,
104
+ );
105
+ expect(complileSpy).to.have.been.calledWith(
106
+ testFileContent,
107
+ testFilePath,
108
+ );
109
+ });
110
+
111
+ it('throws an error if the original file fails to compile', function () {
112
+ core.rewriter.cache.readSync.returns(undefined);
113
+ const testFilePath = require.resolve('../test/resources/file-bad');
114
+ const testFileContent = readFileSync(testFilePath).toString();
115
+
116
+ rewriteHooks.install();
117
+
118
+ expect(() => require(testFilePath)).to.throw('Unexpected identifier');
119
+ expect(core.rewriter.rewriteSync).to.have.been.calledWith(testFileContent, {
120
+ filename: testFilePath,
121
+ isModule: false,
122
+ inject: true,
123
+ wrap: true,
124
+ });
125
+ expect(core.logger.warn).to.have.been.calledWith(
126
+ {
127
+ err: sinon.match({
128
+ message: sinon.match('Unexpected identifier'),
129
+ }),
130
+ },
131
+ 'Failed to compile rewritten code for %s, compiling original code.',
132
+ testFilePath,
133
+ );
134
+ expect(complileSpy).to.have.been.calledWith(
135
+ testFileContent,
136
+ testFilePath,
137
+ );
138
+ });
139
+ });
@@ -59,6 +59,7 @@ const DEADZONED_PATHS = [
59
59
  'moment-timezone',
60
60
  'node-forge',
61
61
  'node-webpack',
62
+ 'pem',
62
63
  'react',
63
64
  'react-dom',
64
65
  'react-dom/server',
@@ -0,0 +1,121 @@
1
+ 'use strict';
2
+
3
+ const EventEmitter = require('events');
4
+ const { expect } = require('chai');
5
+ const { initProtectFixture } = require('@contrast/test/fixtures');
6
+
7
+ describe('agentify sources', function () {
8
+ [
9
+ {
10
+ name: 'http',
11
+ expected: {
12
+ port: 8080,
13
+ protocol: 'http',
14
+ serverType: 'http',
15
+ },
16
+ },
17
+ {
18
+ name: 'https',
19
+ expected: {
20
+ port: 8080,
21
+ protocol: 'https',
22
+ serverType: 'https',
23
+ },
24
+ },
25
+ {
26
+ name: 'spdy',
27
+ expected: {
28
+ port: 8080,
29
+ protocol: 'https',
30
+ serverType: 'spdy',
31
+ },
32
+ },
33
+ {
34
+ name: 'http2',
35
+ method: 'createServer',
36
+ expected: {
37
+ port: 8080,
38
+ protocol: 'https',
39
+ serverType: 'spdy',
40
+ },
41
+ },
42
+ {
43
+ name: 'http2',
44
+ method: 'createSecureServer',
45
+ expected: {
46
+ port: 8080,
47
+ protocol: 'https',
48
+ serverType: 'spdy',
49
+ },
50
+ }
51
+ ].forEach(({ name, method, expected }) => {
52
+ describe(`${name} sources using ${method || 'Server'}()`, function () {
53
+ let core, api, ServerMock, reqMock, resMock;
54
+
55
+ beforeEach(function () {
56
+ ({ core } = initProtectFixture());
57
+ ServerMock = function ServerMock() {
58
+ this.e = new EventEmitter();
59
+ };
60
+ ServerMock.prototype.emit = function (...args) {
61
+ this.e.emit(...args);
62
+ };
63
+ ServerMock.prototype.on = function (...args) {
64
+ this.e.on(...args);
65
+ };
66
+ api = {
67
+ Server: ServerMock,
68
+ createServer() {
69
+ return new ServerMock();
70
+ },
71
+ createSecureServer() {
72
+ return new ServerMock();
73
+ }
74
+ };
75
+ reqMock = {
76
+ socket: {
77
+ address() {
78
+ return { port: 8080 };
79
+ }
80
+ },
81
+ method: 'GET',
82
+ url: 'http://localhost',
83
+ };
84
+ resMock = new EventEmitter();
85
+
86
+ core.depHooks.resolve.withArgs({ name: 'http' }).yields(api);
87
+ require('./sources')(core).install();
88
+ });
89
+
90
+ it('"request" events run in scope with correct sourceInfo', function () {
91
+ const server = method ? api[method]() : new ServerMock();
92
+ let store;
93
+
94
+ server.on('request', function () {
95
+ store = core.scopes.sources.getStore();
96
+ });
97
+
98
+ server.emit('request', reqMock, resMock);
99
+
100
+ expect(store.sourceInfo).to.deep.include({
101
+ port: 8080,
102
+ protocol: 'http',
103
+ serverType: 'http',
104
+ });
105
+ expect(resMock._events.finish).to.be.a('function');
106
+ });
107
+
108
+ it('non-"request" events do not run in scope', function () {
109
+ const server = method ? api[method]() : new ServerMock();
110
+ let store;
111
+
112
+ server.on('foo', function () {
113
+ store = core.scopes.sources.getStore();
114
+ });
115
+
116
+ server.emit('foo', reqMock, resMock);
117
+ expect(store).to.be.undefined;
118
+ });
119
+ });
120
+ });
121
+ });
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+
3
+ const assert = require('node:assert');
4
+ const sinon = require('sinon');
5
+ const mocks = require('@contrast/test/mocks');
6
+ const { IntentionalError } = require('@contrast/common');
7
+
8
+ const originalArgv = process.argv;
9
+ const originalConsoleWarn = console.warn;
10
+ const originalConsoleError = console.error;
11
+
12
+ describe('reporter validators: config', function() {
13
+ let getEffectiveValue;
14
+ let logger;
15
+ let tcore;
16
+ let validators;
17
+
18
+ beforeEach(function() {
19
+ // change this to test different scenarios
20
+ getEffectiveValue = function() {
21
+ return false;
22
+ };
23
+ logger = mocks.logger();
24
+ tcore = {
25
+ config: {
26
+ enable: true,
27
+ getEffectiveValue: (prop) => getEffectiveValue(prop)
28
+ },
29
+ logger,
30
+ };
31
+ validators = require('@contrast/agentify/lib/validators.js');
32
+
33
+ process.argv = originalArgv.slice();
34
+ console.warn = sinon.stub();
35
+ console.error = sinon.stub();
36
+ });
37
+
38
+ after(function() {
39
+ console.warn = originalConsoleWarn;
40
+ console.error = originalConsoleError;
41
+ });
42
+
43
+ it('throws IntentionalError (info) when config enable: false', async function() {
44
+ tcore.config.enable = false;
45
+
46
+ assert.throws(() => validators.config(tcore), (e) => {
47
+ assert(logger.warn.notCalled);
48
+ assert(e instanceof IntentionalError);
49
+ assert.match(e.message, /Contrast agent disabled by configuration/);
50
+ return true;
51
+ });
52
+ });
53
+
54
+ ['-c', '--configFile'].forEach(function(tflag) {
55
+ ['Contrast_Security.yml', 'contrast-security.yaml', 'app.cfg'].forEach(function(farg) {
56
+ const shouldWarn = farg !== 'app.cfg';
57
+ const msg = shouldWarn ? `logs ${tflag} ${farg}` : `does not log ${tflag} ${farg}`;
58
+
59
+ it(`${msg} before an Error is thrown`, async function() {
60
+ tcore.config.enable = false;
61
+ process.argv.push(tflag, farg);
62
+
63
+ assert.throws(() => validators.config(tcore), (e) => {
64
+ if (shouldWarn) {
65
+ assert(logger.warn.calledOnceWith(`Command line config flag is not supported: ${tflag} ${farg}`));
66
+ } else {
67
+ assert(logger.warn.notCalled);
68
+ }
69
+
70
+ assert(e instanceof Error);
71
+ assert.match(e.message, /Contrast agent disabled by configuration/);
72
+ return true;
73
+ });
74
+ });
75
+ });
76
+ });
77
+ });
78
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/agentify",
3
- "version": "1.28.0",
3
+ "version": "1.29.1",
4
4
  "description": "Configures Contrast agent services and instrumentation within an application",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -17,19 +17,19 @@
17
17
  "test": "../scripts/test.sh"
18
18
  },
19
19
  "dependencies": {
20
- "@contrast/common": "1.22.0",
21
- "@contrast/config": "1.29.0",
22
- "@contrast/core": "1.33.0",
23
- "@contrast/deadzones": "1.3.0",
20
+ "@contrast/common": "1.23.0",
21
+ "@contrast/config": "1.30.1",
22
+ "@contrast/core": "1.34.1",
23
+ "@contrast/deadzones": "1.4.0",
24
24
  "@contrast/dep-hooks": "1.3.3",
25
- "@contrast/esm-hooks": "2.7.0",
25
+ "@contrast/esm-hooks": "2.8.1",
26
26
  "@contrast/find-package-json": "^1.1.0",
27
- "@contrast/instrumentation": "1.11.0",
27
+ "@contrast/instrumentation": "1.12.0",
28
28
  "@contrast/logger": "1.8.4",
29
- "@contrast/metrics": "1.9.0",
29
+ "@contrast/metrics": "1.10.0",
30
30
  "@contrast/patcher": "1.7.4",
31
- "@contrast/reporter": "1.28.0",
32
- "@contrast/rewriter": "1.9.0",
31
+ "@contrast/reporter": "1.29.1",
32
+ "@contrast/rewriter": "1.10.1",
33
33
  "@contrast/scopes": "1.4.1",
34
34
  "semver": "^7.6.0"
35
35
  }