@contrast/config 1.28.3 → 1.30.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/lib/index.d.ts +6 -3
- package/lib/index.test.js +557 -0
- package/lib/options.js +14 -1
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -17,10 +17,10 @@ import { ProtectRuleMode, Rule } from '@contrast/common';
|
|
|
17
17
|
import { LevelWithSilent } from 'pino';
|
|
18
18
|
export { ConfigSource } from './common.js';
|
|
19
19
|
|
|
20
|
-
export interface EffectiveEntry {
|
|
20
|
+
export interface EffectiveEntry<T> {
|
|
21
21
|
canonical_name: string;
|
|
22
22
|
name: string;
|
|
23
|
-
value:
|
|
23
|
+
value: T;
|
|
24
24
|
source: ConfigSource;
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -53,7 +53,7 @@ export interface ConfigOption<T> {
|
|
|
53
53
|
|
|
54
54
|
export interface Config {
|
|
55
55
|
_filepath: string;
|
|
56
|
-
_effectiveMap: Map<EffectiveEntry
|
|
56
|
+
_effectiveMap: Map<string, EffectiveEntry<any>>;
|
|
57
57
|
_errors: Error[];
|
|
58
58
|
_status: string,
|
|
59
59
|
|
|
@@ -213,6 +213,7 @@ export interface Config {
|
|
|
213
213
|
inventory: {
|
|
214
214
|
/** Default: `true` */
|
|
215
215
|
analyze_libraries: boolean;
|
|
216
|
+
gather_metadata_via: 'AWS' | 'Azure' | 'GCP' | undefined;
|
|
216
217
|
};
|
|
217
218
|
|
|
218
219
|
assess: {
|
|
@@ -292,6 +293,8 @@ export interface Config {
|
|
|
292
293
|
environment?: string;
|
|
293
294
|
tags?: string;
|
|
294
295
|
version?: string;
|
|
296
|
+
/** Default: `true` */
|
|
297
|
+
discover_cloud_resource: boolean;
|
|
295
298
|
};
|
|
296
299
|
getEffectiveSource(cannonicalName: string): any;
|
|
297
300
|
getEffectiveValue(cannonicalName: string): any;
|
|
@@ -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
|
@@ -495,6 +495,12 @@ Example - \`/opt/Contrast/contrast.log\` creates a log in the \`/opt/Contrast\`
|
|
|
495
495
|
fn: castBoolean,
|
|
496
496
|
desc: 'Set to `false` to disable library analysis.',
|
|
497
497
|
},
|
|
498
|
+
{
|
|
499
|
+
name: 'inventory.gather_metadata_via',
|
|
500
|
+
arg: '<provider>',
|
|
501
|
+
enum: ['AWS', 'Azure', 'GCP'],
|
|
502
|
+
desc: 'Specifies the cloud provider from which the agent should gather metadata (such as resource identifiers). Options are `AWS`, `Azure`, or `GCP`'
|
|
503
|
+
},
|
|
498
504
|
// assess
|
|
499
505
|
{
|
|
500
506
|
name: 'assess.enable',
|
|
@@ -613,7 +619,7 @@ Example - \`label1, label2, label3\``,
|
|
|
613
619
|
},
|
|
614
620
|
{
|
|
615
621
|
name: 'application.metadata',
|
|
616
|
-
|
|
622
|
+
arg: '<metadata>',
|
|
617
623
|
desc: 'comma-separated list of key=value pairs that are applied to each application reported by the agent.',
|
|
618
624
|
},
|
|
619
625
|
// server
|
|
@@ -649,6 +655,13 @@ Example - \`label1, label2, label3\``,
|
|
|
649
655
|
arg: '<version>',
|
|
650
656
|
desc: "override the reported server version (if different from 'version' field in the application's package.json)",
|
|
651
657
|
},
|
|
658
|
+
{
|
|
659
|
+
name: 'server.discover_cloud_resource',
|
|
660
|
+
arg: '[false]',
|
|
661
|
+
default: true,
|
|
662
|
+
fn: castBoolean,
|
|
663
|
+
desc: 'Set to `false` to disable detection of cloud provider metadata such as resource identifiers.'
|
|
664
|
+
},
|
|
652
665
|
].map((opt) => Object.assign(opt, {
|
|
653
666
|
env: `CONTRAST__${opt.name.toUpperCase().replaceAll('.', '__')
|
|
654
667
|
.replaceAll('-', '_')}`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/config",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.0",
|
|
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.
|
|
20
|
+
"@contrast/common": "1.23.0",
|
|
21
21
|
"yaml": "^2.2.2"
|
|
22
22
|
}
|
|
23
23
|
}
|