@contrast/config 1.29.0 → 1.30.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,557 @@
1
+ 'use strict';
2
+
3
+ const EventEmitter = require('events');
4
+ const path = require('path');
5
+ const proxyquire = require('proxyquire');
6
+ const sinon = require('sinon');
7
+ const { expect } = require('chai');
8
+ const { Event } = require('@contrast/common');
9
+ const options = require('./options');
10
+ const {
11
+ ConfigSource: { ENVIRONMENT_VARIABLE }
12
+ } = require('./common');
13
+ const {
14
+ getGoodConfig,
15
+ getBadConfig,
16
+ getAbsolutePath,
17
+ getDefaultConfig,
18
+ getProperties,
19
+ containsAllProps,
20
+ } = require('../test/helpers');
21
+
22
+ describe('config', function () {
23
+ let env, Config, config;
24
+
25
+ beforeEach(function () {
26
+ env = {
27
+ ProgramData: 'C:\\ProgramData',
28
+ CONTRAST_CONFIG_PATH: getGoodConfig(),
29
+ };
30
+ Config = proxyquire('./config', {
31
+ process: { env },
32
+ });
33
+ config = proxyquire('.', {
34
+ process: { env },
35
+ './config': Config,
36
+ });
37
+
38
+ sinon.stub(console, 'error');
39
+ });
40
+
41
+ describe('default config behavior', function () {
42
+ it('sets all default properties in the config', function () {
43
+ const defaultConfigProps = getProperties(getDefaultConfig());
44
+ const loadConfigProps = getProperties(config());
45
+ expect(containsAllProps(loadConfigProps, defaultConfigProps)).to.be.true;
46
+ });
47
+
48
+ it('logs an error a config file path is given and no config is found', function () {
49
+ env['CONTRAST_CONFIG_PATH'] = 'fake config';
50
+ const fn = () => config();
51
+ expect(fn).to.throw('1) Unable to read Contrast configuration file: \'fake config\'');
52
+ });
53
+
54
+ it('logs an error when the config cannot be parsed', function () {
55
+ env['CONTRAST_CONFIG_PATH'] = getBadConfig();
56
+ const fn = () => config();
57
+ expect(fn).to.throw(`Contrast configuration file is malformed: '${getBadConfig()}'`);
58
+ });
59
+
60
+ it('accepts overrides from env', function () {
61
+ env['CONTRAST__API__API_KEY'] = 'demo';
62
+ const cfg = config();
63
+ expect(cfg.api.api_key).to.equal('demo');
64
+ });
65
+
66
+ it('loads and sets properties from a valid config', function () {
67
+ env['CONTRAST_CONFIG_PATH'] = getGoodConfig();
68
+ const cfg = config();
69
+ expect(console.error).not.to.have.been.called;
70
+ expect(cfg.api.enable).to.be.true;
71
+ expect(cfg.api.url).to.equal('http://localhost:19080/Contrast');
72
+ expect(cfg.api.api_key).to.equal('demo');
73
+ expect(cfg.api.service_key).to.equal('demo');
74
+ expect(cfg.api.user_name).to.equal('contrast_admin');
75
+ });
76
+ });
77
+
78
+ describe('config file path precedence', function () {
79
+ it('should set config from environment variable even when default is present', function () {
80
+ sinon.stub(Config.prototype, '_configDirs').returns([
81
+ path.dirname(getGoodConfig())
82
+ ]);
83
+ env['CONTRAST_CONFIG_PATH'] = getGoodConfig('two');
84
+ const cfg = config();
85
+ expect(cfg).to.have.property('_filepath', getGoodConfig('two'));
86
+ expect(cfg.api.url).to.equal('https://localhost:9999/Contrast');
87
+ expect(cfg.api.api_key).to.equal('QWERTYUIOP');
88
+ expect(cfg.api.service_key).to.equal('ASDFGHJKL');
89
+ expect(cfg.api.user_name).to.equal('contrast_user');
90
+ });
91
+
92
+ it('should set config from default location when no env var is set', function () {
93
+ sinon.stub(Config.prototype, '_configDirs').returns([
94
+ path.dirname(getGoodConfig())
95
+ ]);
96
+ delete env['CONTRAST_CONFIG_PATH'];
97
+ const cfg = config();
98
+ expect(cfg).to.have.property('_filepath', getGoodConfig());
99
+ expect(cfg.api.url).to.equal('http://localhost:19080/Contrast');
100
+ expect(cfg.api.api_key).to.equal('demo');
101
+ expect(cfg.api.service_key).to.equal('demo');
102
+ expect(cfg.api.user_name).to.equal('contrast_admin');
103
+ });
104
+
105
+ it('should set config from top valid default location', function () {
106
+ sinon.stub(Config.prototype, '_configDirs').returns([
107
+ path.dirname(getGoodConfig('two')),
108
+ path.dirname(getGoodConfig()),
109
+ ]);
110
+ delete env['CONTRAST_CONFIG_PATH'];
111
+ const cfg = config();
112
+ expect(cfg).to.have.property('_filepath', getGoodConfig('two'));
113
+ expect(cfg.api.url).to.equal('https://localhost:9999/Contrast');
114
+ expect(cfg.api.api_key).to.equal('QWERTYUIOP');
115
+ expect(cfg.api.service_key).to.equal('ASDFGHJKL');
116
+ expect(cfg.api.user_name).to.equal('contrast_user');
117
+ });
118
+
119
+ it('should set from env variable even when present in multiple defaults', function () {
120
+ sinon.stub(Config.prototype, '_configDirs').returns([
121
+ path.dirname(getGoodConfig('two')),
122
+ path.dirname(getGoodConfig()),
123
+ ]);
124
+ env['CONTRAST_CONFIG_PATH'] = getGoodConfig('three');
125
+ const cfg = config();
126
+ expect(cfg).to.have.property('_filepath', getGoodConfig('three'));
127
+ expect(cfg.api.url).to.equal('https://localhost:8080/Contrast');
128
+ expect(cfg.api.api_key).to.equal('QAZWSX');
129
+ expect(cfg.api.service_key).to.equal('EDCRFV');
130
+ expect(cfg.api.user_name).to.equal('super_admin');
131
+ });
132
+ });
133
+
134
+ describe('config value precedence', function () {
135
+ let options;
136
+
137
+ beforeEach(function () {
138
+ options = getDefaultConfig();
139
+ });
140
+
141
+ it('should use env var before config file value', function () {
142
+ env['CONTRAST__API__API_KEY'] = 'NOPE';
143
+ const cfg = config(options);
144
+ expect(cfg.api.api_key).to.equal('NOPE');
145
+ });
146
+ });
147
+
148
+ describe('environment variables', function () {
149
+ it('should support CONTRAST__ options', function () {
150
+ const options = getDefaultConfig();
151
+ env['CONTRAST__AGENT__NODE__REWRITE__ENABLE'] = 'f';
152
+ const cfg = config(options);
153
+
154
+ expect(cfg.agent.node.rewrite.enable).to.be.false;
155
+ });
156
+
157
+ it('Should support CONTRAST__API__ options', function () {
158
+ const options = getDefaultConfig();
159
+ env['CONTRAST__API__API_KEY'] = 'abcdefg';
160
+ const cfg = config(options);
161
+
162
+ expect(cfg.api.api_key).to.equal('abcdefg');
163
+ });
164
+
165
+ it('should merge pm2 env variables', function () {
166
+ const options = getDefaultConfig();
167
+ const variables = {
168
+ CONTRAST_CONFIG_PATH: '/path/to/config',
169
+ CONTRAST__API__API_KEY: 'abcdefg',
170
+ env: {
171
+ CONTRAST_CONFIG_PATH: '/other/path/to/config'
172
+ }
173
+ };
174
+ delete env['CONTRAST_CONFIG_PATH'];
175
+ env['pm2_env'] = JSON.stringify(variables);
176
+
177
+ const fn = () => config(options);
178
+ expect(fn).throws('1) Unable to read Contrast configuration file: \'/other/path/to/config\'');
179
+ });
180
+
181
+ it('should throw an error if pm2_env is invalid', function () {
182
+ env['pm2_env'] = '{CONTRAST_';
183
+
184
+ const fn = () => config(options);
185
+ expect(fn).to.throw('1) Unable to parse pm2 environment variable: \'{CONTRAST_\'');
186
+ });
187
+ });
188
+
189
+ describe('multiple errors can be thrown in an exception', function() {
190
+ it('should report multiple errors', function() {
191
+ const options = getDefaultConfig();
192
+ env['pm2_env'] = '{CONTRAST_';
193
+ env['CONTRAST__APPLICATION__SESSION_ID'] = 'abcd-1234';
194
+ env['CONTRAST__APPLICATION__SESSION_METADATA'] = 'a=1,b=2';
195
+ env['CONTRAST_CONFIG_PATH'] = getGoodConfig('three');
196
+
197
+ const fn = () => config(options);
198
+ expect(fn).throws(/1\) Unable to parse pm2 .+ 2\) Cannot set both/);
199
+ });
200
+ });
201
+
202
+ describe('config options functions', function () {
203
+ describe('clearBaseCase', function () {
204
+ it('should return string if defined', function () {
205
+ const string = 'asdf';
206
+ expect(options.clearBaseCase(string)).to.equal(string);
207
+ });
208
+
209
+ it('should return undefined if string is empty', function () {
210
+ const string = '';
211
+ expect(options.clearBaseCase(string)).to.be.undefined;
212
+ });
213
+
214
+ it('should return int if and number and defined', function () {
215
+ const num = 1;
216
+ expect(options.clearBaseCase(num)).to.equal(num);
217
+ });
218
+
219
+ it('should return undefined if value is NaN', function () {
220
+ const num = NaN;
221
+ expect(options.clearBaseCase(num)).to.be.undefined;
222
+ });
223
+ });
224
+
225
+ describe('castBoolean', function () {
226
+ [true, 'true', 'TRUE', 't', 'T'].forEach(val => {
227
+ it(`should return true if string value is ${val}`, function () {
228
+ expect(options.castBoolean(val)).to.be.true;
229
+ });
230
+ });
231
+
232
+ [false, 'false', 'FALSE', 'f', 'F'].forEach(val => {
233
+ it(`should return false if string value is ${val}`, function () {
234
+ expect(options.castBoolean(val)).to.be.false;
235
+ });
236
+ });
237
+
238
+ ['rando', [1, 2, 3], {}, 100, null, undefined].forEach(val => {
239
+ it(`should return undefined if ${val} not a boolean or string or not true/t/false/f`, function () {
240
+ expect(options.castBoolean(val)).to.be.undefined;
241
+ });
242
+ });
243
+ });
244
+ });
245
+
246
+ describe('enum', function () {
247
+ it('should use value from enum if there is a match', function () {
248
+ env['CONTRAST__AGENT__LOGGER__LEVEL'] = 'INFO';
249
+ const cfg = config();
250
+ expect(cfg.agent.logger.level).to.equal('info');
251
+ });
252
+
253
+ it('should fall back to the default when provided option value is invalid', function () {
254
+ env['CONTRAST__AGENT__LOGGER__LEVEL'] = 'doggo';
255
+ const cfg = config();
256
+ expect(cfg.agent.logger.level).to.equal('info');
257
+ });
258
+ });
259
+
260
+ describe('uppercase, lowercase, parsenum transformations', function () {
261
+ it('should uppercase server.environment', function () {
262
+ env['CONTRAST__SERVER__ENVIRONMENT'] = 'qa';
263
+ const cfg = config();
264
+ expect(cfg.server.environment).to.equal('QA');
265
+ });
266
+
267
+ it('should lowercase logger level', function () {
268
+ env['CONTRAST__AGENT__LOGGER__LEVEL'] = 'DEBUG';
269
+ const cfg = config();
270
+ expect(cfg.agent.logger.level).to.equal('debug');
271
+ });
272
+
273
+ it('should parse stack_trace_limit into a number', function () {
274
+ env['CONTRAST__AGENT__STACK_TRACE_LIMIT'] = '25';
275
+ const cfg = config();
276
+ expect(cfg.agent.stack_trace_limit).to.equal(25);
277
+ });
278
+
279
+ it('agent.stack_trace_limit (Infinity string --> number)', function () {
280
+ env['CONTRAST__AGENT__STACK_TRACE_LIMIT'] = 'Infinity';
281
+ const cfg = config();
282
+ expect(cfg.agent.stack_trace_limit).to.equal(Infinity);
283
+ });
284
+ });
285
+
286
+ describe('application', function () {
287
+ describe('validation', function () {
288
+ afterEach(function () {
289
+ });
290
+ it('allows one to be set without error', function () {
291
+ env['CONTRAST__APPLICATION__SESSION_ID'] = 'abcd-1234';
292
+ expect(() => {
293
+ config();
294
+ }).not.to.throw(/Configuration Error:/);
295
+ });
296
+ it('session options are mutually exclusive', function () {
297
+ env['CONTRAST__APPLICATION__SESSION_ID'] = 'abcd-1234';
298
+ env['CONTRAST__APPLICATION__SESSION_METADATA'] = 'a=1,b=2';
299
+ const fn = () => config();
300
+ expect(fn).throws('1) Cannot set both `application.session_id` and `application.session_metadata`');
301
+ });
302
+ });
303
+ });
304
+
305
+ describe('mapping', function () {
306
+ describe('logger', function () {
307
+ it('casts logger path to absolute path', function () {
308
+ env['CONTRAST__AGENT__LOGGER__PATH'] = 'loggy.log';
309
+ const cfg = config();
310
+ expect(cfg.agent.logger.path).to.equal(getAbsolutePath('loggy.log'));
311
+ });
312
+
313
+ it('--debug does not overwrite explicitly set log level', function () {
314
+ env['DEBUG'] = 'true';
315
+ env['CONTRAST__AGENT__LOGGER__LEVEL'] = 'info';
316
+ const cfg = config();
317
+ expect(cfg.agent.logger.level).to.equal('info');
318
+ });
319
+ });
320
+ });
321
+
322
+ describe('effective configuration', function () {
323
+ let core;
324
+ let config;
325
+
326
+ beforeEach(function () {
327
+ core = { messages: new EventEmitter() };
328
+ // there needs to be a valid config file or env var set so config doesn't throw
329
+ // an error.
330
+ process.env.CONTRAST_CONFIG_PATH = path.resolve(__dirname, '../../test/fixtures/protect_contrast_security.yaml');
331
+ config = require('.')(core);
332
+
333
+ config.setValue('contrast_config_path', path.resolve(__dirname, '../../test/fixtures/protect_contrast_security.yaml'), ENVIRONMENT_VARIABLE);
334
+ config.setValue('contrast__agent__stack_trace_limit', 20, ENVIRONMENT_VARIABLE);
335
+ config.setValue('contrast.protect.rules.disabled_rules', ['cmd-injection', 'sql-injection'], ENVIRONMENT_VARIABLE);
336
+ config.setValue('api.enable', true, ENVIRONMENT_VARIABLE);
337
+ config.setValue('api.api_key', 'ABCDEFGHIJ', ENVIRONMENT_VARIABLE);
338
+ config.setValue('api.service_key', 'KLMNOPQRST', ENVIRONMENT_VARIABLE);
339
+
340
+ core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {
341
+ logger: {
342
+ // this will not take effect b/c value is set in config file
343
+ level: 'ERROR'
344
+ },
345
+ security_logger: {
346
+ syslog: {
347
+ enable: true,
348
+ ip: '127.0.0.1'
349
+ }
350
+ }
351
+ });
352
+ });
353
+
354
+ describe('.getEffectiveValue()', function () {
355
+ it('returns the resolved value based on precedence: env > file > UI > default', function () {
356
+ expect(config.getEffectiveValue('agent.security_logger.syslog.enable')).to.equal(true);
357
+ });
358
+ });
359
+
360
+ describe('.getReport', function () {
361
+ it('merges all the settings correctly and returns properly formatted config object', function () {
362
+
363
+ const result = config.getReport({ redact: false });
364
+ const {
365
+ config: {
366
+ effective_config,
367
+ }
368
+ } = result;
369
+
370
+ expect(result.config).to.have.property('status', 'Success');
371
+ expect(effective_config).to.deep.include(
372
+ {
373
+ canonical_name: 'api.enable',
374
+ name: 'api.enable',
375
+ source: 'ENVIRONMENT_VARIABLE',
376
+ value: 'true',
377
+ },
378
+ {
379
+ canonical_name: 'api.api_key',
380
+ name: 'api.api_key',
381
+ source: 'ENVIRONMENT_VARIABLE',
382
+ value: 'contrast-redacted-api.api_key',
383
+ },
384
+ {
385
+ canonical_name: 'api.service_key',
386
+ name: 'api.service_key',
387
+ source: 'ENVIRONMENT_VARIABLE',
388
+ value: 'contrast-redacted-api.service_key',
389
+ },
390
+ {
391
+ canonical_name: 'api.proxy.enable',
392
+ name: 'api.proxy.enable',
393
+ source: 'USER_CONFIGURATION_FILE',
394
+ value: 'false',
395
+ },
396
+ {
397
+ canonical_name: 'agent.diagnostics.enable',
398
+ name: 'agent.diagnostics.enable',
399
+ source: 'USER_CONFIGURATION_FILE',
400
+ value: 'false',
401
+ },
402
+ {
403
+ canonical_name: 'protect.enable',
404
+ name: 'protect.enable',
405
+ value: 'true',
406
+ source: 'USER_CONFIGURATION_FILE'
407
+ },
408
+ {
409
+ canonical_name: 'assess.enable',
410
+ name: 'assess.enable',
411
+ value: 'false',
412
+ source: 'USER_CONFIGURATION_FILE'
413
+ },
414
+ {
415
+ canonical_name: 'agent.security_logger.syslog.enable',
416
+ name: 'agent.security_logger.syslog.enable',
417
+ value: 'true',
418
+ source: 'CONTRAST_UI'
419
+ },
420
+ {
421
+ canonical_name: 'agent.polling.app_activity_ms',
422
+ name: 'agent.polling.app_activity_ms',
423
+ value: '30000',
424
+ source: 'DEFAULT_VALUE'
425
+ },
426
+ {
427
+ canonical_name: 'protect.rules.disabled_rules',
428
+ name: 'protect.rules.disabled_rules',
429
+ value: 'cmd-injection,sql-injection',
430
+ source: 'ENVIRONMENT_VARIABLE',
431
+ },
432
+ {
433
+ canonical_name: 'protect.probe_analysis.enable',
434
+ name: 'protect.probe_analysis.enable',
435
+ value: 'true',
436
+ source: 'DEFAULT_VALUE'
437
+ },
438
+ {
439
+ canonical_name: 'assess.trust_custom_validators',
440
+ name: 'assess.trust_custom_validators',
441
+ value: 'false',
442
+ source: 'DEFAULT_VALUE'
443
+ },
444
+ {
445
+ canonical_name: 'assess.max_propagation_events',
446
+ name: 'assess.max_propagation_events',
447
+ value: '500',
448
+ source: 'DEFAULT_VALUE'
449
+ },
450
+ {
451
+ canonical_name: 'assess.max_context_source_events',
452
+ name: 'assess.max_context_source_events',
453
+ value: '150',
454
+ source: 'DEFAULT_VALUE'
455
+ }
456
+ );
457
+ });
458
+
459
+ it('stringifies values and redacts api keys when `redact` is set to true', function () {
460
+ const result = config.getReport({ redact: true });
461
+ const {
462
+ config: {
463
+ effective_config,
464
+ }
465
+ } = result;
466
+
467
+ expect(result.config).to.have.property('status', 'Success');
468
+ expect(effective_config).to.deep.include(
469
+ {
470
+ canonical_name: 'api.enable',
471
+ name: 'api.enable',
472
+ source: 'ENVIRONMENT_VARIABLE',
473
+ value: 'true',
474
+ },
475
+ {
476
+ canonical_name: 'api.api_key',
477
+ name: 'api.api_key',
478
+ source: 'ENVIRONMENT_VARIABLE',
479
+ value: 'contrast-redacted-api.api_key',
480
+ },
481
+ {
482
+ canonical_name: 'api.service_key',
483
+ name: 'api.service_key',
484
+ source: 'ENVIRONMENT_VARIABLE',
485
+ value: 'contrast-redacted-api.service_key',
486
+ },
487
+ {
488
+ canonical_name: 'api.proxy.enable',
489
+ name: 'api.proxy.enable',
490
+ source: 'USER_CONFIGURATION_FILE',
491
+ value: 'false',
492
+ },
493
+ {
494
+ canonical_name: 'agent.diagnostics.enable',
495
+ name: 'agent.diagnostics.enable',
496
+ source: 'USER_CONFIGURATION_FILE',
497
+ value: 'false',
498
+ },
499
+ {
500
+ canonical_name: 'protect.enable',
501
+ name: 'protect.enable',
502
+ value: 'true',
503
+ source: 'USER_CONFIGURATION_FILE'
504
+ },
505
+ {
506
+ canonical_name: 'assess.enable',
507
+ name: 'assess.enable',
508
+ value: 'false',
509
+ source: 'USER_CONFIGURATION_FILE'
510
+ },
511
+ {
512
+ canonical_name: 'agent.security_logger.syslog.enable',
513
+ name: 'agent.security_logger.syslog.enable',
514
+ value: 'true',
515
+ source: 'CONTRAST_UI'
516
+ },
517
+ {
518
+ canonical_name: 'agent.polling.app_activity_ms',
519
+ name: 'agent.polling.app_activity_ms',
520
+ value: '30000',
521
+ source: 'DEFAULT_VALUE'
522
+ },
523
+ {
524
+ canonical_name: 'protect.rules.disabled_rules',
525
+ name: 'protect.rules.disabled_rules',
526
+ value: 'cmd-injection,sql-injection',
527
+ source: 'ENVIRONMENT_VARIABLE',
528
+ },
529
+ {
530
+ canonical_name: 'protect.probe_analysis.enable',
531
+ name: 'protect.probe_analysis.enable',
532
+ value: 'true',
533
+ source: 'DEFAULT_VALUE'
534
+ },
535
+ {
536
+ canonical_name: 'assess.trust_custom_validators',
537
+ name: 'assess.trust_custom_validators',
538
+ value: 'false',
539
+ source: 'DEFAULT_VALUE'
540
+ },
541
+ {
542
+ canonical_name: 'assess.max_propagation_events',
543
+ name: 'assess.max_propagation_events',
544
+ value: '500',
545
+ source: 'DEFAULT_VALUE'
546
+ },
547
+ {
548
+ canonical_name: 'assess.max_context_source_events',
549
+ name: 'assess.max_context_source_events',
550
+ value: '150',
551
+ source: 'DEFAULT_VALUE'
552
+ }
553
+ );
554
+ });
555
+ });
556
+ });
557
+ });
package/lib/options.js CHANGED
@@ -176,12 +176,11 @@ const options = [
176
176
  desc: 'Set to limit the length of Error stack traces to a specified number. Larger limits will improve accuracy but increase memory usage.',
177
177
  },
178
178
  {
179
- // NOTE: not in common config.
180
179
  name: 'agent.stack_trace_filters',
181
180
  arg: '<list,of,filters>',
182
181
  default: 'agent-,@contrast,node-agent',
183
182
  fn: split,
184
- desc: 'comma-separated list of patterns to ignore within stack traces',
183
+ desc: 'Comma-separated list of patterns to ignore within stack traces.',
185
184
  },
186
185
  // agent.diagnostics
187
186
  {
@@ -420,7 +419,6 @@ Example - \`/opt/Contrast/contrast.log\` creates a log in the \`/opt/Contrast\`
420
419
  desc: 'an entrypoint for an application that, when specified, will prevent the agent instrumenting on anything else'
421
420
  },
422
421
  {
423
- // NOTE: not in common config.
424
422
  name: 'agent.node.rewrite.enable',
425
423
  arg: '[false]',
426
424
  default: true,
@@ -428,7 +426,6 @@ Example - \`/opt/Contrast/contrast.log\` creates a log in the \`/opt/Contrast\`
428
426
  desc: 'Set to `false` to disable source code rewriting. Not recommended.',
429
427
  },
430
428
  {
431
- // NOTE: not in common config.
432
429
  name: 'agent.node.rewrite.cache.enable',
433
430
  arg: '[false]',
434
431
  default: true,
@@ -436,7 +433,6 @@ Example - \`/opt/Contrast/contrast.log\` creates a log in the \`/opt/Contrast\`
436
433
  desc: 'Set to `false` to disable caching rewritten source code files.',
437
434
  },
438
435
  {
439
- // NOTE: not in common config.
440
436
  name: 'agent.node.rewrite.cache.path',
441
437
  arg: '<path>',
442
438
  default: '.contrast',
@@ -444,13 +440,11 @@ Example - \`/opt/Contrast/contrast.log\` creates a log in the \`/opt/Contrast\`
444
440
  desc: "Set the directory in which to cache rewritten source code files. Defaults to `.contrast/` in the application's current working directory.",
445
441
  },
446
442
  {
447
- // NOTE: not in common config.
448
443
  name: 'agent.node.source_maps.enable',
449
444
  arg: '[false]',
450
445
  default: true,
451
446
  fn: castBoolean,
452
- // TODO: update description once we support handling and chaining source maps.
453
- desc: 'Set to `false` to disable source map generation.',
447
+ desc: 'Set to `false` to disable source map generation when rewriting.',
454
448
  },
455
449
  // agent.node.library_usage.reporting
456
450
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/config",
3
- "version": "1.29.0",
3
+ "version": "1.30.1",
4
4
  "description": "An API for discovering Contrast agent configuration data",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -17,7 +17,7 @@
17
17
  "test": "../scripts/test.sh"
18
18
  },
19
19
  "dependencies": {
20
- "@contrast/common": "1.22.0",
20
+ "@contrast/common": "1.23.0",
21
21
  "yaml": "^2.2.2"
22
22
  }
23
23
  }