@contrast/config 1.40.1 → 1.40.2

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/lib/config.js CHANGED
@@ -41,6 +41,8 @@ const OS_CONFIG_DIR = os.platform() === 'win32'
41
41
  const REDACTED_KEYS = ['api.api_key', 'api.service_key', 'api.token'];
42
42
  const OVERRIDABLE_SOURCES = [DEFAULT_VALUE, CONTRAST_UI];
43
43
 
44
+ const isValid = (opt) => opt !== undefined && opt !== null && opt !== '';
45
+
44
46
  module.exports = class Config {
45
47
  constructor(core) {
46
48
  // internals
@@ -88,7 +90,7 @@ module.exports = class Config {
88
90
  for (const [name, mapper] of Object.entries(mappings)) {
89
91
  if (OVERRIDABLE_SOURCES.includes(this.getEffectiveSource(name))) {
90
92
  const remoteValue = mapper(msg);
91
- if (remoteValue != null) {
93
+ if (isValid(remoteValue)) {
92
94
  this._effectiveMap.set(name, {
93
95
  canonical_name: name,
94
96
  name,
@@ -202,10 +204,10 @@ module.exports = class Config {
202
204
  const fileValue = get(fileOptions, opt.name);
203
205
  let source, value;
204
206
 
205
- if (envValue != null) {
207
+ if (isValid(envValue)) {
206
208
  source = ENVIRONMENT_VARIABLE;
207
209
  value = envValue;
208
- } else if (fileValue != null) {
210
+ } else if (isValid(fileValue)) {
209
211
  source = USER_CONFIGURATION_FILE;
210
212
  value = fileValue;
211
213
  } else {
package/lib/index.d.ts CHANGED
@@ -43,7 +43,7 @@ export type SyslogLevel =
43
43
  export interface ConfigOption<T> {
44
44
  name: string;
45
45
  abbrev?: string;
46
- env?: string;
46
+ env: string;
47
47
  arg: string;
48
48
  enum?: T[];
49
49
  default?: T;
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@contrast/config",
3
- "version": "1.40.1",
3
+ "version": "1.40.2",
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)",
7
7
  "files": [
8
- "lib/"
8
+ "lib/",
9
+ "!*.test.*",
10
+ "!tsconfig.*",
11
+ "!*.map"
9
12
  ],
10
13
  "main": "lib/index.js",
11
14
  "types": "lib/index.d.ts",
@@ -1,183 +0,0 @@
1
- 'use strict';
2
-
3
- const { expect } = require('chai');
4
- const { ProtectRuleMode } = require('@contrast/common');
5
- const { mappings } = require('./common');
6
-
7
- describe('config effective value mappings', function () {
8
- describe('"simple" mappings', function() {
9
- const simplyMappedNames = [
10
- 'assess.enable',
11
- 'agent.logger.path',
12
- 'agent.security_logger.syslog.enable',
13
- 'agent.security_logger.syslog.ip',
14
- 'agent.security_logger.syslog.port',
15
- 'agent.security_logger.syslog.facility',
16
- 'server.environment',
17
- 'protect.enable',
18
- ];
19
-
20
- it('"simple" mappings will return any value for corresponding remote setting (todo: validation for each)', function () {
21
- ['', 'foo', null, 0.3, 3, {}, [], true, false].forEach((val) => {
22
- const remoteData = {
23
- // server
24
- assess: {
25
- enable: val,
26
- sampling: { enable: val }
27
- },
28
- logger: {
29
- path: val,
30
- },
31
- security_logger: {
32
- syslog: {
33
- enable: val,
34
- ip: val,
35
- port: val,
36
- facility: val,
37
- serverity_exploited: val,
38
- serverity_blocked: val,
39
- exploited_probed: val,
40
- }
41
- },
42
- environment: val,
43
- // app
44
- protect: {
45
- enable: val,
46
- },
47
- };
48
-
49
- for (const name of simplyMappedNames) {
50
- const result = mappings[name](remoteData);
51
- expect(result).to.equal(val);
52
- }
53
- });
54
- });
55
-
56
- it('"simple" mappings will return `undefined` if there is no corresponding remote setting', function () {
57
- for (const name of simplyMappedNames) {
58
- expect(mappings[name]({})).to.equal(undefined);
59
- }
60
- });
61
- });
62
-
63
- describe('maps \'assess.probabilistic_sampling.base_probability\'', function() {
64
- [
65
- {
66
- desc: 'sets value by inverting request_frequency',
67
- remoteData: {
68
- assess: { sampling: { request_frequency: 20 } }
69
- },
70
- expected: 1 / 20,
71
- },
72
- {
73
- desc: 'ignores and returns undefined if request_frequency is 0',
74
- remoteData: {
75
- assess: { sampling: { request_frequency: 0 } }
76
- },
77
- expected: undefined,
78
- },
79
- {
80
- desc: 'ignores and returns undefined if calculating probability gives NaN',
81
- remoteData: {
82
- assess: { sampling: { request_frequency: 'forty five' } }
83
- },
84
- expected: undefined,
85
- },
86
- {
87
- desc: 'ignores and returns undefined if value is negative',
88
- remoteData: {
89
- assess: { sampling: { request_frequency: -12 } }
90
- },
91
- expected: undefined,
92
- },
93
- ].forEach(({ desc, remoteData, expected }) => {
94
- it(desc, function() {
95
- expect(mappings['assess.probabilistic_sampling.base_probability'](remoteData)).to.equal(expected);
96
- });
97
- });
98
- });
99
-
100
- describe('maps Protect rule modes', function() {
101
- [
102
- {
103
- tsValue: 'OFF',
104
- expected: ProtectRuleMode.OFF,
105
- },
106
- {
107
- tsValue: 'MONITORING',
108
- expected: ProtectRuleMode.MONITOR,
109
- },
110
- {
111
- tsValue: 'BLOCKING',
112
- expected: ProtectRuleMode.BLOCK,
113
- },
114
- {
115
- tsValue: 'BLOCK_AT_PERIMETER',
116
- expected: ProtectRuleMode.BLOCK_AT_PERIMETER,
117
- },
118
- {
119
- tsValue: 'FOO',
120
- expected: undefined
121
- },
122
- ].forEach(({ desc, tsValue, expected }) => {
123
- [
124
- 'protect.rules.cmd-injection.mode',
125
- 'protect.rules.cmd-injection-command-backdoors.mode',
126
- 'protect.rules.cmd-injection-semantic-chained-commands.mode',
127
- 'protect.rules.cmd-injection-semantic-dangerous-paths.mode',
128
- 'protect.rules.method-tampering.mode',
129
- 'protect.rules.nosql-injection.mode',
130
- 'protect.rules.nosql-injection-mongo.mode',
131
- 'protect.rules.path-traversal.mode',
132
- 'protect.rules.path-traversal-semantic-file-security-bypass.mode',
133
- 'protect.rules.reflected-xss.mode',
134
- 'protect.rules.sql-injection.mode',
135
- 'protect.rules.ssjs-injection.mode',
136
- 'protect.rules.unsafe-file-upload.mode',
137
- 'protect.rules.untrusted-deserialization.mode',
138
- 'protect.rules.xxe.mode',
139
- ].forEach((fullName) => {
140
- const ruleName = /rules\.(.*)\.mode/.exec(fullName)[1];
141
- it(`sets ${ruleName} to ${expected} when value is ${tsValue}`, function() {
142
- expect(mappings[fullName]({
143
- protect: {
144
- rules: {
145
- [ruleName]: { mode: tsValue },
146
- }
147
- }
148
- })).to.equal(expected);
149
- });
150
- });
151
- });
152
- });
153
-
154
- describe('maps security logger severity levels (lowercase)', function() {
155
- [
156
- {
157
- tsValue: 'FOO',
158
- expected: 'foo',
159
- },
160
- {
161
- tsValue: '',
162
- expected: undefined,
163
- }
164
- ].forEach(({ tsValue, expected }) => {
165
- [
166
- 'agent.security_logger.syslog.severity_exploited',
167
- 'agent.security_logger.syslog.severity_blocked',
168
- 'agent.security_logger.syslog.severity_probed',
169
- ].forEach((fullName) => {
170
- const severity = fullName.substr(fullName.lastIndexOf('.') + 1);
171
- it(`maps to ${expected} when tsValue is ${tsValue}`, function() {
172
- expect(mappings[fullName]({
173
- security_logger: {
174
- syslog: {
175
- [severity]: tsValue,
176
- },
177
- }
178
- })).to.equal(expected);
179
- });
180
- });
181
- });
182
- });
183
- });
package/lib/index.test.js DELETED
@@ -1,664 +0,0 @@
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('api.token handling', function () {
190
- it('sets api config vars when they are not present', function () {
191
- env['CONTRAST_CONFIG_PATH'] = getGoodConfig('token');
192
- const cfg = config();
193
-
194
- expect(cfg.api).to.include({
195
- url: 'http://localhost:12345/Contrast',
196
- api_key: 'secret',
197
- service_key: 'secret',
198
- user_name: 'tokenuser'
199
- });
200
- });
201
-
202
- it('does not override api config vars when they are explicitly set in config', function () {
203
- // url: 'http://localhost:12345/Contrast',
204
- // api_key: 'secret',
205
- // service_key: 'secret',
206
- // user_name: 'tokenuser'
207
- env['CONTRAST__API__TOKEN'] = 'eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQ1L0NvbnRyYXN0IiwiYXBpX2tleSI6InNlY3JldCIsInNlcnZpY2Vfa2V5Ijoic2VjcmV0IiwidXNlcl9uYW1lIjoidG9rZW51c2VyIn0=';
208
- const cfg = config();
209
-
210
- expect(cfg.api).to.include({
211
- url: 'http://localhost:19080/Contrast',
212
- api_key: 'demo',
213
- service_key: 'demo',
214
- user_name: 'contrast_admin'
215
- });
216
- });
217
-
218
- it('observes the correct precedence', function () {
219
- env['CONTRAST_CONFIG_PATH'] = getGoodConfig('token');
220
- env['CONTRAST__API__API_KEY'] = 'something else';
221
- const cfg = config();
222
-
223
- expect(cfg.api).to.include({
224
- url: 'http://localhost:12345/Contrast',
225
- api_key: 'something else',
226
- service_key: 'secret',
227
- user_name: 'tokenuser'
228
- });
229
- });
230
- });
231
-
232
- describe('multiple errors can be thrown in an exception', function() {
233
- it('should report multiple errors', function() {
234
- const options = getDefaultConfig();
235
- env['pm2_env'] = '{CONTRAST_';
236
- env['CONTRAST__APPLICATION__SESSION_ID'] = 'abcd-1234';
237
- env['CONTRAST__APPLICATION__SESSION_METADATA'] = 'a=1,b=2';
238
- env['CONTRAST_CONFIG_PATH'] = getGoodConfig('three');
239
-
240
- const fn = () => config(options);
241
- expect(fn).throws(/1\) Unable to parse pm2 .+ 2\) Cannot set both/);
242
- });
243
- });
244
-
245
- describe('config options functions', function () {
246
- describe('clearBaseCase', function () {
247
- it('should return string if defined', function () {
248
- const string = 'asdf';
249
- expect(options.clearBaseCase(string)).to.equal(string);
250
- });
251
-
252
- it('should return undefined if string is empty', function () {
253
- const string = '';
254
- expect(options.clearBaseCase(string)).to.be.undefined;
255
- });
256
-
257
- it('should return int if and number and defined', function () {
258
- const num = 1;
259
- expect(options.clearBaseCase(num)).to.equal(num);
260
- });
261
-
262
- it('should return undefined if value is NaN', function () {
263
- const num = NaN;
264
- expect(options.clearBaseCase(num)).to.be.undefined;
265
- });
266
- });
267
-
268
- describe('castBoolean', function () {
269
- [true, 'true', 'TRUE', 't', 'T'].forEach(val => {
270
- it(`should return true if string value is ${val}`, function () {
271
- expect(options.castBoolean(val)).to.be.true;
272
- });
273
- });
274
-
275
- [false, 'false', 'FALSE', 'f', 'F'].forEach(val => {
276
- it(`should return false if string value is ${val}`, function () {
277
- expect(options.castBoolean(val)).to.be.false;
278
- });
279
- });
280
-
281
- ['rando', [1, 2, 3], {}, 100, null, undefined].forEach(val => {
282
- it(`should return undefined if ${val} not a boolean or string or not true/t/false/f`, function () {
283
- expect(options.castBoolean(val)).to.be.undefined;
284
- });
285
- });
286
- });
287
- });
288
-
289
- describe('enum', function () {
290
- it('should use value from enum if there is a match', function () {
291
- env['CONTRAST__AGENT__LOGGER__LEVEL'] = 'INFO';
292
- const cfg = config();
293
- expect(cfg.agent.logger.level).to.equal('info');
294
- });
295
-
296
- it('should fall back to the default when provided option value is invalid', function () {
297
- env['CONTRAST__AGENT__LOGGER__LEVEL'] = 'doggo';
298
- const cfg = config();
299
- expect(cfg.agent.logger.level).to.equal('info');
300
- });
301
- });
302
-
303
- describe('uppercase, lowercase, parsenum transformations', function () {
304
- it('should uppercase server.environment', function () {
305
- env['CONTRAST__SERVER__ENVIRONMENT'] = 'qa';
306
- const cfg = config();
307
- expect(cfg.server.environment).to.equal('QA');
308
- });
309
-
310
- it('should lowercase logger level', function () {
311
- env['CONTRAST__AGENT__LOGGER__LEVEL'] = 'DEBUG';
312
- const cfg = config();
313
- expect(cfg.agent.logger.level).to.equal('debug');
314
- });
315
-
316
- it('should parse stack_trace_limit into a number', function () {
317
- env['CONTRAST__AGENT__STACK_TRACE_LIMIT'] = '25';
318
- const cfg = config();
319
- expect(cfg.agent.stack_trace_limit).to.equal(25);
320
- });
321
-
322
- it('agent.stack_trace_limit (Infinity string --> number)', function () {
323
- env['CONTRAST__AGENT__STACK_TRACE_LIMIT'] = 'Infinity';
324
- const cfg = config();
325
- expect(cfg.agent.stack_trace_limit).to.equal(Infinity);
326
- });
327
- });
328
-
329
- describe('application', function () {
330
- describe('validation', function () {
331
- afterEach(function () {
332
- });
333
- it('allows one to be set without error', function () {
334
- env['CONTRAST__APPLICATION__SESSION_ID'] = 'abcd-1234';
335
- expect(() => {
336
- config();
337
- }).not.to.throw(/Configuration Error:/);
338
- });
339
- it('session options are mutually exclusive', function () {
340
- env['CONTRAST__APPLICATION__SESSION_ID'] = 'abcd-1234';
341
- env['CONTRAST__APPLICATION__SESSION_METADATA'] = 'a=1,b=2';
342
- const fn = () => config();
343
- expect(fn).throws('1) Cannot set both `application.session_id` and `application.session_metadata`');
344
- });
345
- });
346
- });
347
-
348
- describe('mapping', function () {
349
- describe('logger', function () {
350
- it('casts logger path to absolute path', function () {
351
- env['CONTRAST__AGENT__LOGGER__PATH'] = 'loggy.log';
352
- const cfg = config();
353
- expect(cfg.agent.logger.path).to.equal(getAbsolutePath('loggy.log'));
354
- });
355
-
356
- it('--debug does not overwrite explicitly set log level', function () {
357
- env['DEBUG'] = 'true';
358
- env['CONTRAST__AGENT__LOGGER__LEVEL'] = 'info';
359
- const cfg = config();
360
- expect(cfg.agent.logger.level).to.equal('info');
361
- });
362
- });
363
- });
364
-
365
- describe('effective configuration', function () {
366
- let core;
367
- let config;
368
-
369
- beforeEach(function () {
370
- core = { messages: new EventEmitter() };
371
- // there needs to be a valid config file or env var set so config doesn't throw
372
- // an error.
373
- process.env.CONTRAST_CONFIG_PATH = path.resolve(__dirname, '../../test/fixtures/protect_contrast_security.yaml');
374
- //process.env.CONTRAST__PROTECT__RULES__DISABLED_RULES = 'cmd-injection,sql-injection';
375
- config = require('.')(core);
376
-
377
- config.setValue('contrast_config_path', path.resolve(__dirname, '../../test/fixtures/protect_contrast_security.yaml'), ENVIRONMENT_VARIABLE);
378
- config.setValue('contrast__agent__stack_trace_limit', 20, ENVIRONMENT_VARIABLE);
379
- config.setValue('protect.rules.disabled_rules', ['cmd-injection', 'sql-injection'], ENVIRONMENT_VARIABLE);
380
- config.setValue('api.enable', true, ENVIRONMENT_VARIABLE);
381
- config.setValue('api.api_key', 'ABCDEFGHIJ', ENVIRONMENT_VARIABLE);
382
- config.setValue('api.service_key', 'KLMNOPQRST', ENVIRONMENT_VARIABLE);
383
-
384
- core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {
385
- logger: {
386
- // this will not take effect b/c value is set in config file
387
- level: 'ERROR'
388
- },
389
- security_logger: {
390
- syslog: {
391
- enable: true,
392
- ip: '127.0.0.1'
393
- }
394
- }
395
- });
396
- });
397
-
398
- describe('.getEffectiveValue()', function () {
399
- it('returns the resolved value based on precedence: env > file > UI > default', function () {
400
- expect(config.getEffectiveValue('agent.security_logger.syslog.enable')).to.equal(true);
401
- });
402
- });
403
-
404
- describe('.getReport', function () {
405
- it('merges all the settings correctly and returns properly formatted config object', function () {
406
-
407
- const result = config.getReport({ redact: false });
408
- const {
409
- config: {
410
- effective_config,
411
- environment_variable,
412
- }
413
- } = result;
414
-
415
- expect(result.config).to.have.property('status', 'Success');
416
- const expectedResults = [
417
- {
418
- canonical_name: 'api.enable',
419
- name: 'api.enable',
420
- source: 'ENVIRONMENT_VARIABLE',
421
- value: 'true',
422
- },
423
- {
424
- canonical_name: 'api.api_key',
425
- name: 'api.api_key',
426
- source: 'ENVIRONMENT_VARIABLE',
427
- value: 'ABCDEFGHIJ',
428
- },
429
- {
430
- canonical_name: 'api.service_key',
431
- name: 'api.service_key',
432
- source: 'ENVIRONMENT_VARIABLE',
433
- value: 'KLMNOPQRST',
434
- },
435
- {
436
- canonical_name: 'api.proxy.enable',
437
- name: 'api.proxy.enable',
438
- source: 'USER_CONFIGURATION_FILE',
439
- value: 'false',
440
- },
441
- {
442
- canonical_name: 'agent.diagnostics.enable',
443
- name: 'agent.diagnostics.enable',
444
- source: 'USER_CONFIGURATION_FILE',
445
- value: 'false',
446
- },
447
- {
448
- canonical_name: 'protect.enable',
449
- name: 'protect.enable',
450
- value: 'true',
451
- source: 'USER_CONFIGURATION_FILE'
452
- },
453
- {
454
- canonical_name: 'assess.enable',
455
- name: 'assess.enable',
456
- value: 'false',
457
- source: 'USER_CONFIGURATION_FILE'
458
- },
459
- {
460
- canonical_name: 'agent.security_logger.syslog.enable',
461
- name: 'agent.security_logger.syslog.enable',
462
- value: 'true',
463
- source: 'CONTRAST_UI'
464
- },
465
- {
466
- canonical_name: 'agent.polling.app_activity_ms',
467
- name: 'agent.polling.app_activity_ms',
468
- value: '5000',
469
- source: 'DEFAULT_VALUE'
470
- },
471
- {
472
- canonical_name: 'protect.rules.disabled_rules',
473
- name: 'protect.rules.disabled_rules',
474
- value: 'cmd-injection,sql-injection',
475
- source: 'ENVIRONMENT_VARIABLE',
476
- },
477
- {
478
- canonical_name: 'protect.probe_analysis.enable',
479
- name: 'protect.probe_analysis.enable',
480
- value: 'true',
481
- source: 'DEFAULT_VALUE'
482
- },
483
- {
484
- canonical_name: 'assess.trust_custom_validators',
485
- name: 'assess.trust_custom_validators',
486
- value: 'false',
487
- source: 'DEFAULT_VALUE'
488
- },
489
- {
490
- canonical_name: 'assess.max_propagation_events',
491
- name: 'assess.max_propagation_events',
492
- value: '500',
493
- source: 'DEFAULT_VALUE'
494
- },
495
- {
496
- canonical_name: 'assess.max_context_source_events',
497
- name: 'assess.max_context_source_events',
498
- value: '150',
499
- source: 'DEFAULT_VALUE'
500
- }
501
- ];
502
-
503
- const failures = [];
504
- let effective;
505
- let envs;
506
- const envFailures = [];
507
-
508
- for (const expected of expectedResults) {
509
- effective = effective_config.filter(i => i.canonical_name === expected.canonical_name);
510
- expect(effective).an('array').lengthOf(1); // eslint-disable-line
511
- effective = effective[0];
512
- try {
513
- expect(expected).to.deep.equal(effective);
514
- } catch (e) {
515
- failures.push({ expected, actual: effective });
516
- }
517
- if (expected.source !== 'ENVIRONMENT_VARIABLE') continue;
518
-
519
- envs = environment_variable.filter(i => i.canonical_name === expected.canonical_name);
520
- expect(envs).an('array')
521
- .lengthOf(1, `Expected to find ${expected.name} in environment_variable`);
522
- envs = envs[0];
523
- try {
524
- expect(expected).to.deep.equal(envs);
525
- } catch (e) {
526
- envFailures.push({ expected, actual: envs });
527
- }
528
- }
529
- // this provides a useful error message
530
- expect(failures).eql([]);
531
- expect(envFailures).eql([]);
532
- });
533
-
534
- it('stringifies values and redacts api keys when `redact` is set to true', function () {
535
- const result = config.getReport({ redact: true });
536
- const {
537
- config: {
538
- effective_config,
539
- environment_variable,
540
- }
541
- } = result;
542
-
543
- expect(result.config).to.have.property('status', 'Success');
544
-
545
- const expectedResults = [
546
- {
547
- canonical_name: 'api.enable',
548
- name: 'api.enable',
549
- source: 'ENVIRONMENT_VARIABLE',
550
- value: 'true',
551
- },
552
- {
553
- canonical_name: 'api.api_key',
554
- name: 'api.api_key',
555
- source: 'ENVIRONMENT_VARIABLE',
556
- value: 'contrast-redacted-api.api_key',
557
- },
558
- {
559
- canonical_name: 'api.service_key',
560
- name: 'api.service_key',
561
- source: 'ENVIRONMENT_VARIABLE',
562
- value: 'contrast-redacted-api.service_key',
563
- },
564
- {
565
- canonical_name: 'api.proxy.enable',
566
- name: 'api.proxy.enable',
567
- source: 'USER_CONFIGURATION_FILE',
568
- value: 'false',
569
- },
570
- {
571
- canonical_name: 'agent.diagnostics.enable',
572
- name: 'agent.diagnostics.enable',
573
- source: 'USER_CONFIGURATION_FILE',
574
- value: 'false',
575
- },
576
- {
577
- canonical_name: 'protect.enable',
578
- name: 'protect.enable',
579
- value: 'true',
580
- source: 'USER_CONFIGURATION_FILE'
581
- },
582
- {
583
- canonical_name: 'assess.enable',
584
- name: 'assess.enable',
585
- value: 'false',
586
- source: 'USER_CONFIGURATION_FILE'
587
- },
588
- {
589
- canonical_name: 'agent.security_logger.syslog.enable',
590
- name: 'agent.security_logger.syslog.enable',
591
- value: 'true',
592
- source: 'CONTRAST_UI'
593
- },
594
- {
595
- canonical_name: 'agent.polling.app_activity_ms',
596
- name: 'agent.polling.app_activity_ms',
597
- value: '5000',
598
- source: 'DEFAULT_VALUE'
599
- },
600
- {
601
- canonical_name: 'protect.rules.disabled_rules',
602
- name: 'protect.rules.disabled_rules',
603
- value: 'cmd-injection,sql-injection',
604
- source: 'ENVIRONMENT_VARIABLE',
605
- },
606
- {
607
- canonical_name: 'protect.probe_analysis.enable',
608
- name: 'protect.probe_analysis.enable',
609
- value: 'true',
610
- source: 'DEFAULT_VALUE'
611
- },
612
- {
613
- canonical_name: 'assess.trust_custom_validators',
614
- name: 'assess.trust_custom_validators',
615
- value: 'false',
616
- source: 'DEFAULT_VALUE'
617
- },
618
- {
619
- canonical_name: 'assess.max_propagation_events',
620
- name: 'assess.max_propagation_events',
621
- value: '500',
622
- source: 'DEFAULT_VALUE'
623
- },
624
- {
625
- canonical_name: 'assess.max_context_source_events',
626
- name: 'assess.max_context_source_events',
627
- value: '150',
628
- source: 'DEFAULT_VALUE'
629
- }
630
- ];
631
-
632
- const failures = [];
633
- let effective;
634
- let envs;
635
- const envFailures = [];
636
-
637
- for (const expected of expectedResults) {
638
- effective = effective_config.filter(i => i.canonical_name === expected.canonical_name);
639
- expect(effective).an('array').lengthOf(1); // eslint-disable-line
640
- effective = effective[0];
641
- try {
642
- expect(expected).to.deep.equal(effective);
643
- } catch (e) {
644
- failures.push({ expected, actual: effective });
645
- }
646
- if (expected.source !== 'ENVIRONMENT_VARIABLE') continue;
647
-
648
- envs = environment_variable.filter(i => i.canonical_name === expected.canonical_name);
649
- expect(envs).an('array')
650
- .lengthOf(1, `Expected to find ${expected.name} in environment_variable`);
651
- envs = envs[0];
652
- try {
653
- expect(expected).to.deep.equal(envs);
654
- } catch (e) {
655
- envFailures.push({ expected, actual: envs });
656
- }
657
- }
658
- // this provides a useful error message
659
- expect(failures).eql([]);
660
- expect(envFailures).eql([]);
661
- });
662
- });
663
- });
664
- });
@@ -1,42 +0,0 @@
1
- 'use strict';
2
-
3
- const { expect } = require('chai');
4
- const mocks = require('@contrast/test/mocks');
5
- const validators = require('./validators');
6
-
7
- describe('config validators', function () {
8
- let core;
9
-
10
- beforeEach(function () {
11
- core = { logger: mocks.logger() };
12
- });
13
-
14
- describe('config', function () {
15
- it('calls `logger` for each log message provided', function () {
16
- core.config = {
17
- _logs: [
18
- { level: 'info', msg: 'some info level message' },
19
- {
20
- level: 'debug',
21
- obj: { foo: 'bar' },
22
- msg: 'some debug level message with %d %s',
23
- args: [2, 'args'],
24
- },
25
- ],
26
- };
27
-
28
- validators.config(core);
29
-
30
- expect(core.logger.info).to.have.been.calledWith(
31
- undefined,
32
- 'some info level message'
33
- );
34
- expect(core.logger.debug).to.have.been.calledWith(
35
- { foo: 'bar' },
36
- 'some debug level message with %d %s',
37
- 2,
38
- 'args',
39
- );
40
- });
41
- });
42
- });