@contrast/agentify 1.25.1 → 1.27.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 +1 -1
- package/lib/index.js +73 -34
- package/lib/rewrite-hooks.js +1 -2
- package/lib/utils.js +2 -77
- package/lib/validators.js +62 -0
- package/package.json +14 -14
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -12,14 +12,13 @@
|
|
|
12
12
|
* engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
13
|
* way not consistent with the End User License Agreement.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
/*eslint node/no-unsupported-features/es-syntax: ["error", {version: >=10.0.0}]*/
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const Module = require('module');
|
|
19
19
|
const {
|
|
20
20
|
assertValidOpts,
|
|
21
21
|
preStartupValidation,
|
|
22
|
-
postConfigValidation,
|
|
23
22
|
} = require('./utils');
|
|
24
23
|
const { IntentionalError } = require('@contrast/common');
|
|
25
24
|
|
|
@@ -89,7 +88,8 @@ module.exports = function init(core = {}) {
|
|
|
89
88
|
return runMain.apply(this, args);
|
|
90
89
|
};
|
|
91
90
|
} else {
|
|
92
|
-
// for 'esm' we load esm-hooks support, which
|
|
91
|
+
// for 'esm' we load esm-hooks support, which installs last
|
|
92
|
+
// eslint-disable-next-line node/no-unsupported-features/es-syntax
|
|
93
93
|
const { default: esmHooks } = await import('@contrast/esm-hooks/lib/index.mjs');
|
|
94
94
|
esmHooks(core);
|
|
95
95
|
|
|
@@ -135,45 +135,84 @@ module.exports = function init(core = {}) {
|
|
|
135
135
|
// check supported Node version and correct preload usage before anything else
|
|
136
136
|
preStartupValidation(core);
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
const modules = [
|
|
139
|
+
{ name: 'messages', spec: '@contrast/core/lib/messages' },
|
|
140
|
+
{ name: 'config', spec: '@contrast/config' },
|
|
141
|
+
{ name: 'logger', spec: '@contrast/logger', default: true },
|
|
142
|
+
// call all configValidation functions here
|
|
143
|
+
{ name: 'agent-info', spec: '@contrast/core/lib/agent-info' },
|
|
144
|
+
{ name: 'system-info', spec: '@contrast/core/lib/system-info' },
|
|
145
|
+
{ name: 'app-info', spec: '@contrast/core/lib/app-info' },
|
|
146
|
+
// was check for appInfo errors length and throw if found
|
|
147
|
+
{ name: 'sensitive-data-masking', spec: '@contrast/core/lib/sensitive-data-masking' },
|
|
148
|
+
{ name: 'is-agent-path', spec: '@contrast/core/lib/is-agent-path' },
|
|
149
|
+
{ name: 'dep-hooks', spec: '@contrast/dep-hooks' },
|
|
150
|
+
{ name: 'patcher', spec: '@contrast/patcher' },
|
|
151
|
+
{ name: 'capture-stacktrace', spec: '@contrast/core/lib/capture-stacktrace' },
|
|
152
|
+
{ name: 'rewriter', spec: '@contrast/rewriter' },
|
|
153
|
+
{ name: 'contrast-methods', spec: '@contrast/core/lib/contrast-methods' },
|
|
154
|
+
{ name: 'scopes', spec: '@contrast/scopes' },
|
|
155
|
+
{ name: 'deadzones', spec: '@contrast/deadzones' },
|
|
156
|
+
{ name: 'reporter', spec: '@contrast/reporter', default: true },
|
|
157
|
+
{ name: 'instrumentation', spec: '@contrast/instrumentation' },
|
|
158
|
+
{ name: 'metrics', spec: '@contrast/metrics' },
|
|
159
|
+
|
|
160
|
+
// compose additional local services
|
|
161
|
+
{ name: 'heap-snapshots', spec: './heap-snapshots' },
|
|
162
|
+
{ name: 'sources', spec: './sources' },
|
|
163
|
+
{ name: 'function-hooks', spec: './function-hooks' },
|
|
164
|
+
{ name: 'log-diagnostic-files', spec: './log-diagnostic-files' },
|
|
165
|
+
{ name: 'rewrite-hooks', spec: './rewrite-hooks' },
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
// collect validators for each module that has them.
|
|
169
|
+
//
|
|
170
|
+
// the pattern for supplying a validator for a module is to put a validators.js file
|
|
171
|
+
// in the same directory as the module's index.js file. the validators.js file should
|
|
172
|
+
// export an object with a property for each validator it implements.
|
|
173
|
+
//
|
|
174
|
+
// the module-loading for-loop defines the implemented validators.
|
|
175
|
+
// start with agentify, which is a special case because it's not in the list
|
|
176
|
+
// modules to be loaded.
|
|
177
|
+
const validators = { agentify: require('./validators') };
|
|
178
|
+
for (const { name, spec } of modules) {
|
|
179
|
+
try {
|
|
180
|
+
// if any module has files in a directory other than /lib then...
|
|
181
|
+
const v = require(`${spec}/lib/validators.js`);
|
|
182
|
+
validators[name] = v;
|
|
183
|
+
} catch (e) {
|
|
184
|
+
// if e.code !== 'MODULE_NOT_FOUND' consider logging.
|
|
185
|
+
// no validators for this module.
|
|
186
|
+
}
|
|
187
|
+
}
|
|
145
188
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
189
|
+
// now load each module and, if a validator is available, run it.
|
|
190
|
+
for (const { name, spec, default: isDefault } of modules) {
|
|
191
|
+
// typescript inserts a default export for esm modules.
|
|
192
|
+
let mod = require(spec);
|
|
193
|
+
if (isDefault) {
|
|
194
|
+
mod = mod.default;
|
|
195
|
+
}
|
|
196
|
+
mod(core);
|
|
197
|
+
|
|
198
|
+
// perform any validations that can take place now that this module is loaded.
|
|
199
|
+
if (name === 'logger') {
|
|
200
|
+
// note that this runs the "config" validation. it does this so that
|
|
201
|
+
// the logger is available for any validation errors.
|
|
202
|
+
for (const v in validators) {
|
|
203
|
+
validators[v]?.config && validators[v].config(core);
|
|
204
|
+
}
|
|
205
|
+
} // else if (name === 'other-validation-name') {...}
|
|
151
206
|
}
|
|
152
|
-
|
|
153
|
-
require('@contrast/core/lib/is-agent-path')(core);
|
|
154
|
-
require('@contrast/dep-hooks')(core);
|
|
155
|
-
require('@contrast/patcher')(core);
|
|
156
|
-
require('@contrast/core/lib/capture-stacktrace')(core);
|
|
157
|
-
require('@contrast/rewriter')(core); // merge contrast-methods?
|
|
158
|
-
require('@contrast/core/lib/contrast-methods')(core); // can we remove dependency on patcher?
|
|
159
|
-
require('@contrast/scopes')(core);
|
|
160
|
-
require('@contrast/deadzones')(core);
|
|
161
|
-
require('@contrast/reporter').default(core);
|
|
162
|
-
require('@contrast/instrumentation')(core);
|
|
163
|
-
require('@contrast/metrics')(core);
|
|
164
|
-
|
|
165
|
-
// compose additional local services
|
|
166
|
-
require('./heap-snapshots')(core);
|
|
167
|
-
require('./sources')(core);
|
|
168
|
-
require('./function-hooks')(core);
|
|
169
|
-
require('./log-diagnostic-files')(core); // this doesn't really belong in agentify
|
|
170
|
-
require('./rewrite-hooks')(core);
|
|
207
|
+
|
|
171
208
|
} catch (err) {
|
|
172
209
|
// TODO: Consider proper UNINSTALLATION and normal startup w/o agent
|
|
173
210
|
core.agentify = function agentify() {
|
|
174
211
|
return core;
|
|
175
212
|
};
|
|
176
213
|
|
|
214
|
+
// IntentionalError is used when the agent is disabled by config. We want
|
|
215
|
+
// to abort the installation but not issue any messages.
|
|
177
216
|
if (!(err instanceof IntentionalError)) {
|
|
178
217
|
if (core.logger) {
|
|
179
218
|
core.logger.error({ err }, ERROR_MESSAGE);
|
package/lib/rewrite-hooks.js
CHANGED
|
@@ -45,7 +45,6 @@ module.exports = function init(core) {
|
|
|
45
45
|
isModule: false,
|
|
46
46
|
inject: true,
|
|
47
47
|
wrap: true,
|
|
48
|
-
trim: false,
|
|
49
48
|
};
|
|
50
49
|
|
|
51
50
|
if (rewriteIsDeadzoned(filename)) {
|
|
@@ -59,7 +58,7 @@ module.exports = function init(core) {
|
|
|
59
58
|
const compiled = Reflect.apply(_compile, this, [result.code, filename]);
|
|
60
59
|
|
|
61
60
|
if (core.config.agent.node.rewrite.cache.enable) {
|
|
62
|
-
core.rewriter.cache.
|
|
61
|
+
core.rewriter.cache.writeSync(filename, result);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
return compiled;
|
package/lib/utils.js
CHANGED
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const process = require('process');
|
|
20
20
|
const semver = require('semver');
|
|
21
|
-
|
|
22
|
-
const { findPackageJsonSync } = require('@contrast/find-package-json');
|
|
21
|
+
|
|
23
22
|
const {
|
|
24
23
|
engines: {
|
|
25
24
|
node: nodeEngines,
|
|
@@ -89,6 +88,7 @@ function assertSupportedPreloadUsage() {
|
|
|
89
88
|
// if absolute path is provided read the package name to check if it's our agent
|
|
90
89
|
if (path.isAbsolute(preloadTarget)) {
|
|
91
90
|
try {
|
|
91
|
+
const { findPackageJsonSync } = require('@contrast/find-package-json');
|
|
92
92
|
const { name } = require(findPackageJsonSync({ cwd: path.dirname(preloadTarget) }));
|
|
93
93
|
if (name !== '@contrast/agent') continue;
|
|
94
94
|
preloadTarget = name;
|
|
@@ -129,79 +129,6 @@ function isLoader(arg) {
|
|
|
129
129
|
return arg == '--import' || arg == '--loader' || arg == '--experimental-loader';
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
/**
|
|
133
|
-
* Check that the config contains the minimum required settings. Issue appropriate
|
|
134
|
-
* error messages.
|
|
135
|
-
* @throws IntentionalError
|
|
136
|
-
*/
|
|
137
|
-
function postConfigValidation(core) {
|
|
138
|
-
// find out if any required settings are missing.
|
|
139
|
-
const missingRequiredSettings = [];
|
|
140
|
-
// these are only required if the API is enabled. if api.enable is false, it
|
|
141
|
-
// had to be set by the user because it defaults to true.
|
|
142
|
-
if (core.config.getEffectiveValue('api.enable')) {
|
|
143
|
-
for (const setting of ['api.api_key', 'api.service_key', 'api.user_name']) {
|
|
144
|
-
if (!core.config.getEffectiveValue(setting)) {
|
|
145
|
-
missingRequiredSettings.push(setting);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// v4 accepted `-c` or `--configFile` option in argv, but v5 does not. so if
|
|
151
|
-
// something that looks like a config flag is present on the command line, we
|
|
152
|
-
// log it. the worst case is that it's a false positive; if that's a problem
|
|
153
|
-
// we can make it an info level, but the goal here is for the user to see it
|
|
154
|
-
// without having to contact customer support and rerun their test at a more
|
|
155
|
-
// verbose log level.
|
|
156
|
-
const configFlag = getConfigFlag(process.argv);
|
|
157
|
-
if (configFlag) {
|
|
158
|
-
const msg = `Command line config flag present: ${configFlag[0]} ${configFlag[1]}`;
|
|
159
|
-
|
|
160
|
-
if (core.logger) {
|
|
161
|
-
core.logger.warn(msg);
|
|
162
|
-
} else {
|
|
163
|
-
console.warn(msg);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (missingRequiredSettings.length) {
|
|
168
|
-
const reason = `Missing required settings: ${missingRequiredSettings.join(', ')}`;
|
|
169
|
-
const finalMsg = 'A configuration error prevents the Contrast agent from starting.';
|
|
170
|
-
if (core.logger) {
|
|
171
|
-
core.logger.error({ reason }, finalMsg);
|
|
172
|
-
} else {
|
|
173
|
-
console.error(reason, finalMsg);
|
|
174
|
-
}
|
|
175
|
-
throw new IntentionalError(finalMsg);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// now check for serious errors, like file not readable, file format is wrong, etc.
|
|
179
|
-
// that were captured when building the config.
|
|
180
|
-
if (core.config._errors?.length) {
|
|
181
|
-
throw core.config._errors[0];
|
|
182
|
-
}
|
|
183
|
-
// finally, was it disabled?
|
|
184
|
-
if (!core.config.enable) {
|
|
185
|
-
const errorMessage = 'Contrast agent disabled by configuration (enable: false)';
|
|
186
|
-
throw new IntentionalError(errorMessage);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function getConfigFlag(argv) {
|
|
191
|
-
for (let i = 0; i < argv.length - 1; i++) {
|
|
192
|
-
if (argv[i] === '-c' || argv[i] === '--configFile') {
|
|
193
|
-
// should this check to see if the name looks like a contrast config file?
|
|
194
|
-
// let's not because that seems false-negative prone.
|
|
195
|
-
|
|
196
|
-
// if the next arg is another flag, then this isn't a contrast config flag
|
|
197
|
-
if (!argv[i + 1].startsWith('-') && argv[i + 1].toLowerCase().includes('contrast')) {
|
|
198
|
-
return argv.slice(i, i + 2);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
return undefined;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
132
|
/**
|
|
206
133
|
* Validates custom `installOrder` options. We currently need the reporter component
|
|
207
134
|
* to install first in order to onboard and get effective settings and mode values.
|
|
@@ -224,6 +151,4 @@ module.exports = {
|
|
|
224
151
|
assertSupportedNodeVersion,
|
|
225
152
|
assertSupportedPreloadUsage,
|
|
226
153
|
preStartupValidation,
|
|
227
|
-
postConfigValidation,
|
|
228
|
-
getConfigFlag,
|
|
229
154
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright: 2024 Contrast Security, Inc
|
|
3
|
+
* Contact: support@contrastsecurity.com
|
|
4
|
+
* License: Commercial
|
|
5
|
+
|
|
6
|
+
* NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
* used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
* made available through public repositories, use of this Software is subject to
|
|
9
|
+
* the applicable End User Licensing Agreement found at
|
|
10
|
+
* https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
* between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
* engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
* way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const { IntentionalError } = require('@contrast/common');
|
|
19
|
+
|
|
20
|
+
// v4 accepted `-c` or `--configFile` option in argv, but v5 does not. so if
|
|
21
|
+
// something that looks like a config flag is present on the command line, we
|
|
22
|
+
// log it. the worst case is that it's a false positive; if that's a problem
|
|
23
|
+
// we can make it an info level, but the goal here is for the user to see it
|
|
24
|
+
// without having to contact customer support and rerun their test at a more
|
|
25
|
+
// verbose log level.
|
|
26
|
+
function config(core) {
|
|
27
|
+
const configFlag = getConfigFlag(process.argv);
|
|
28
|
+
if (configFlag) {
|
|
29
|
+
const msg = `Command line config flag is not supported: ${configFlag[0]} ${configFlag[1]}`;
|
|
30
|
+
|
|
31
|
+
if (core.logger) {
|
|
32
|
+
core.logger.warn(msg);
|
|
33
|
+
} else {
|
|
34
|
+
console.warn(msg);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// finally, was it disabled?
|
|
39
|
+
if (!core.config.enable) {
|
|
40
|
+
const errorMessage = 'Contrast agent disabled by configuration (enable: false)';
|
|
41
|
+
throw new IntentionalError(errorMessage);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getConfigFlag(argv) {
|
|
46
|
+
for (let i = 0; i < argv.length - 1; i++) {
|
|
47
|
+
if (argv[i] === '-c' || argv[i] === '--configFile') {
|
|
48
|
+
// should this check to see if the name looks like a contrast config file?
|
|
49
|
+
// let's not because that seems false-negative prone.
|
|
50
|
+
|
|
51
|
+
// if the next arg is another flag, then this isn't a contrast config flag
|
|
52
|
+
if (!argv[i + 1].startsWith('-') && argv[i + 1].toLowerCase().includes('contrast')) {
|
|
53
|
+
return argv.slice(i, i + 2);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
config,
|
|
62
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/agentify",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.0",
|
|
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)",
|
|
@@ -11,25 +11,25 @@
|
|
|
11
11
|
"types": "lib/index.d.ts",
|
|
12
12
|
"engines": {
|
|
13
13
|
"npm": ">=6.13.7 <7 || >= 8.3.1",
|
|
14
|
-
"node": ">=
|
|
14
|
+
"node": ">= 16.9.1"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"test": "../scripts/test.sh"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@contrast/common": "1.21.
|
|
21
|
-
"@contrast/config": "1.28.
|
|
22
|
-
"@contrast/core": "1.32.
|
|
23
|
-
"@contrast/deadzones": "1.2.
|
|
24
|
-
"@contrast/dep-hooks": "1.3.
|
|
25
|
-
"@contrast/esm-hooks": "2.6.
|
|
20
|
+
"@contrast/common": "1.21.2",
|
|
21
|
+
"@contrast/config": "1.28.2",
|
|
22
|
+
"@contrast/core": "1.32.2",
|
|
23
|
+
"@contrast/deadzones": "1.2.2",
|
|
24
|
+
"@contrast/dep-hooks": "1.3.3",
|
|
25
|
+
"@contrast/esm-hooks": "2.6.2",
|
|
26
26
|
"@contrast/find-package-json": "^1.1.0",
|
|
27
|
-
"@contrast/instrumentation": "1.
|
|
28
|
-
"@contrast/logger": "1.8.
|
|
29
|
-
"@contrast/metrics": "1.8.
|
|
30
|
-
"@contrast/patcher": "1.7.
|
|
31
|
-
"@contrast/reporter": "1.27.
|
|
32
|
-
"@contrast/rewriter": "1.8.
|
|
27
|
+
"@contrast/instrumentation": "1.10.0",
|
|
28
|
+
"@contrast/logger": "1.8.4",
|
|
29
|
+
"@contrast/metrics": "1.8.2",
|
|
30
|
+
"@contrast/patcher": "1.7.3",
|
|
31
|
+
"@contrast/reporter": "1.27.2",
|
|
32
|
+
"@contrast/rewriter": "1.8.2",
|
|
33
33
|
"@contrast/scopes": "1.4.1",
|
|
34
34
|
"semver": "^7.6.0"
|
|
35
35
|
}
|