@contrast/agent-bundle 5.39.1 → 5.40.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.
Files changed (52) hide show
  1. package/node_modules/@contrast/agent/lib/start-agent.js +50 -40
  2. package/node_modules/@contrast/agent/package.json +10 -10
  3. package/node_modules/@contrast/agentify/lib/sources.js +1 -0
  4. package/node_modules/@contrast/agentify/package.json +14 -14
  5. package/node_modules/@contrast/architecture-components/package.json +5 -5
  6. package/node_modules/@contrast/assess/lib/dataflow/propagation/install/string/replace.js +6 -3
  7. package/node_modules/@contrast/assess/lib/dataflow/sources/index.js +1 -1
  8. package/node_modules/@contrast/assess/lib/dataflow/sources/install/{body-parser1.js → body-parser.js} +1 -1
  9. package/node_modules/@contrast/assess/package.json +11 -11
  10. package/node_modules/@contrast/common/lib/constants.d.ts +6 -0
  11. package/node_modules/@contrast/common/lib/constants.js +8 -1
  12. package/node_modules/@contrast/common/package.json +1 -1
  13. package/node_modules/@contrast/config/lib/index.d.ts +1 -0
  14. package/node_modules/@contrast/config/package.json +3 -3
  15. package/node_modules/@contrast/core/package.json +5 -5
  16. package/node_modules/@contrast/deadzones/package.json +5 -5
  17. package/node_modules/@contrast/dep-hooks/package.json +3 -3
  18. package/node_modules/@contrast/esm-hooks/package.json +6 -6
  19. package/node_modules/@contrast/instrumentation/package.json +5 -5
  20. package/node_modules/@contrast/library-analysis/lib/install/library-reporting/dep.json +143 -145
  21. package/node_modules/@contrast/library-analysis/lib/install/library-reporting/index.js +9 -2
  22. package/node_modules/@contrast/library-analysis/lib/install/library-reporting/utils.js +54 -43
  23. package/node_modules/@contrast/library-analysis/package.json +4 -4
  24. package/node_modules/@contrast/logger/package.json +3 -3
  25. package/node_modules/@contrast/metrics/package.json +6 -6
  26. package/node_modules/@contrast/patcher/package.json +2 -2
  27. package/node_modules/@contrast/protect/lib/input-analysis/index.js +1 -1
  28. package/node_modules/@contrast/protect/lib/input-analysis/install/{body-parser1.js → body-parser.js} +1 -1
  29. package/node_modules/@contrast/protect/package.json +11 -11
  30. package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/routes-observed.js +2 -1
  31. package/node_modules/@contrast/reporter/package.json +6 -6
  32. package/node_modules/@contrast/rewriter/package.json +5 -5
  33. package/node_modules/@contrast/route-coverage/lib/index.d.ts +2 -0
  34. package/node_modules/@contrast/route-coverage/lib/index.js +14 -8
  35. package/node_modules/@contrast/route-coverage/lib/install/express/express5.js +491 -202
  36. package/node_modules/@contrast/route-coverage/package.json +9 -9
  37. package/node_modules/@contrast/scopes/package.json +5 -5
  38. package/node_modules/@contrast/telemetry/package.json +5 -5
  39. package/node_modules/@types/node/README.md +1 -1
  40. package/node_modules/@types/node/buffer.d.ts +5 -0
  41. package/node_modules/@types/node/dns/promises.d.ts +11 -10
  42. package/node_modules/@types/node/dns.d.ts +18 -19
  43. package/node_modules/@types/node/package.json +2 -2
  44. package/node_modules/@types/node/stream/web.d.ts +4 -0
  45. package/package.json +5 -3
  46. package/node_modules/@contrast/route-coverage/lib/install/http.js +0 -44
  47. package/node_modules/path-to-regexp/LICENSE +0 -21
  48. package/node_modules/path-to-regexp/Readme.md +0 -216
  49. package/node_modules/path-to-regexp/dist/index.d.ts +0 -136
  50. package/node_modules/path-to-regexp/dist/index.js +0 -403
  51. package/node_modules/path-to-regexp/dist/index.js.map +0 -1
  52. package/node_modules/path-to-regexp/package.json +0 -62
@@ -73,7 +73,6 @@ module.exports = function init(core) {
73
73
  } = core;
74
74
 
75
75
  const libPathHashMap = new Map();
76
-
77
76
  /**
78
77
  * @returns {Promise<string | undefined>}
79
78
  */
@@ -100,6 +99,14 @@ module.exports = function init(core) {
100
99
 
101
100
  const libraryReporting = core.libraryAnalysis.libraryReporting = {
102
101
  async install() {
102
+ const topLevelPkgInfo = core.appInfo.pkg;
103
+ if (!topLevelPkgInfo) {
104
+ logger.warn('Unable to get top-level package.json; aborting library analysis. Ensure the `agent.node.app_root` configuration variable is set to the directory containing your `node_modules` folder.');
105
+ return;
106
+ }
107
+
108
+ const { dependencies: topLevelDependencies } = topLevelPkgInfo;
109
+
103
110
  const nodeModulesPath = await getNodeModulesPath();
104
111
  if (!nodeModulesPath) {
105
112
  logger.warn('Unable to determine the location of the `node_modules` directory; aborting library analysis. Ensure the `agent.node.app_root` configuration variable is set to the directory containing your `node_modules` folder.');
@@ -108,7 +115,7 @@ module.exports = function init(core) {
108
115
 
109
116
  try {
110
117
  const flatAgentDeps = flattenDeps(agentDeps);
111
- const npmData = listInstalled(nodeModulesPath, flatAgentDeps, logger);
118
+ const npmData = listInstalled(topLevelDependencies, nodeModulesPath, flatAgentDeps, logger);
112
119
  processDependencies(npmData, libPathHashMap, logger);
113
120
  } catch (err) {
114
121
  logger.warn({ err }, 'Unable to perform library analysis.');
@@ -19,6 +19,27 @@ const path = require('path');
19
19
 
20
20
  const { primordials: { JSONParse } } = require('@contrast/common');
21
21
 
22
+ function parsePackage(filePath, logger) {
23
+ const pkgPath = path.join(filePath, 'package.json');
24
+ if (!fs.existsSync(pkgPath)) return;
25
+
26
+ const pkg = fs.readFileSync(pkgPath, 'utf-8');
27
+ if (!pkg) {
28
+ logger.warn('Error reading package.json for %s', pkgPath);
29
+ return;
30
+ }
31
+
32
+ if (typeof pkg !== 'string') return;
33
+
34
+ let pkgInfo;
35
+ try {
36
+ pkgInfo = JSONParse(pkg);
37
+ } catch (err) {
38
+ logger.warn({ err }, 'Error parsing package.json for %s', pkgPath);
39
+ }
40
+ return pkgInfo;
41
+ }
42
+
22
43
  // Just used, for now, to flatten the agent dependencies stored in dep.json
23
44
  function flattenDeps(deps, flatDeps = {}) {
24
45
  Object.entries(deps.dependencies).forEach(([key, val]) => {
@@ -31,59 +52,48 @@ function flattenDeps(deps, flatDeps = {}) {
31
52
  return flatDeps;
32
53
  }
33
54
 
34
- function listInstalled(nodeModulesPath, agentDeps, logger, installed = new Map()) {
55
+ function listInstalled(topLevelDeps, nodeModulesPath, agentDeps, logger, installed = new Map()) {
35
56
 
36
57
  if (!fs.existsSync(nodeModulesPath)) return;
37
58
 
38
59
  function traversePackage(filePath, checkingAgentDeps = false) {
39
- const pkgPath = path.join(filePath, 'package.json');
40
- if (!fs.existsSync(pkgPath)) return;
41
-
42
- const pkg = fs.readFileSync(pkgPath, 'utf-8');
43
- try {
44
- if (typeof pkg === 'string') {
45
- const pkgInfo = JSONParse(pkg);
46
- pkgInfo.path = filePath;
47
-
48
- const { name } = pkgInfo;
49
- const pkgId = `${name}:${pkgInfo?.version}`;
50
- if (installed.has(pkgId)) return;
51
-
52
- // The library we are checking is a known agent dependency
53
- // store its path so if it turns out to also be an app
54
- // dependency we can go back and traverse it later
55
- if (!checkingAgentDeps && agentDeps[name]) {
56
- agentDeps[name] = { filePath };
57
- return;
58
- }
59
-
60
- installed.set(pkgId, pkgInfo);
61
-
62
- // Looks in a library's package.json for dependencies shared by the agent
63
- // if one is found, go back and traverse it
64
- ['dependencies', 'peerDependencies', 'optionalDependencies'].forEach((deps) => {
65
- if (pkgInfo?.[deps]) {
66
- Object.entries(pkgInfo[deps]).forEach(([key]) => {
67
- if (agentDeps[key]) {
68
- const { filePath } = agentDeps[key];
69
- agentDeps[key] = false;
70
- if (filePath) traversePackage(filePath, true);
71
- }
72
- });
60
+ const pkgInfo = parsePackage(filePath, logger);
61
+ if (!pkgInfo) return;
62
+
63
+ pkgInfo.path = filePath;
64
+
65
+ const { name } = pkgInfo;
66
+ const pkgId = `${name}:${pkgInfo?.version}`;
67
+ if (installed.has(pkgId)) return;
68
+
69
+ // The library we are checking is a known agent dependency
70
+ // store its path so if it turns out to also be an app
71
+ // dependency we can go back and traverse it later
72
+ if (!checkingAgentDeps && agentDeps[name] && !topLevelDeps[name]) {
73
+ agentDeps[name] = { filePath };
74
+ return;
75
+ }
76
+
77
+ installed.set(pkgId, pkgInfo);
78
+
79
+ // Looks in a library's package.json for dependencies shared by the agent
80
+ // if one is found, go back and traverse it
81
+ ['dependencies', 'peerDependencies', 'optionalDependencies'].forEach((deps) => {
82
+ if (pkgInfo?.[deps]) {
83
+ Object.entries(pkgInfo[deps]).forEach(([key]) => {
84
+ if (agentDeps[key]) {
85
+ const { filePath } = agentDeps[key];
86
+ agentDeps[key] = false;
87
+ if (filePath) traversePackage(filePath, true);
73
88
  }
74
89
  });
75
- } else {
76
- logger.warn('Error reading package.json for %s', pkgPath);
77
90
  }
78
- } catch (err) {
79
- logger.warn(err);
80
- logger.warn('Error parsing package.json for %s', pkgPath);
81
- }
91
+ });
82
92
 
83
93
  // If a library contains its own node_modules directory
84
94
  const filePathNodeModulesPath = path.join(filePath, 'node_modules');
85
95
  if (fs.existsSync(filePathNodeModulesPath)) {
86
- listInstalled(filePathNodeModulesPath, agentDeps, logger, installed);
96
+ listInstalled(topLevelDeps, filePathNodeModulesPath, agentDeps, logger, installed);
87
97
  }
88
98
  }
89
99
 
@@ -110,6 +120,7 @@ function listInstalled(nodeModulesPath, agentDeps, logger, installed = new Map()
110
120
  }
111
121
 
112
122
  module.exports = {
123
+ parsePackage,
113
124
  flattenDeps,
114
- listInstalled
125
+ listInstalled,
115
126
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/library-analysis",
3
- "version": "1.44.1",
3
+ "version": "1.44.2",
4
4
  "description": "Handles library reporting and library usage analysis",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -21,10 +21,10 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@contrast/code-events": "^3.1.0",
24
- "@contrast/common": "1.34.1",
25
- "@contrast/config": "1.49.1",
24
+ "@contrast/common": "1.34.2",
25
+ "@contrast/config": "1.49.2",
26
26
  "@contrast/find-package-json": "^1.1.0",
27
- "@contrast/logger": "1.27.1",
27
+ "@contrast/logger": "1.27.2",
28
28
  "semver": "^7.6.0"
29
29
  }
30
30
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/logger",
3
- "version": "1.27.1",
3
+ "version": "1.27.2",
4
4
  "description": "Centralized logging for Contrast agent services",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -21,8 +21,8 @@
21
21
  "test": "bash ../scripts/test.sh"
22
22
  },
23
23
  "dependencies": {
24
- "@contrast/common": "1.34.1",
25
- "@contrast/config": "1.49.1",
24
+ "@contrast/common": "1.34.2",
25
+ "@contrast/config": "1.49.2",
26
26
  "pino": "^8.15.0"
27
27
  }
28
28
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/metrics",
3
- "version": "1.31.1",
3
+ "version": "1.31.2",
4
4
  "description": "Records and logs route latency",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -21,10 +21,10 @@
21
21
  "test": "bash ../scripts/test.sh"
22
22
  },
23
23
  "dependencies": {
24
- "@contrast/common": "1.34.1",
25
- "@contrast/config": "1.49.1",
26
- "@contrast/dep-hooks": "1.23.1",
27
- "@contrast/logger": "1.27.1",
28
- "@contrast/patcher": "1.26.1"
24
+ "@contrast/common": "1.34.2",
25
+ "@contrast/config": "1.49.2",
26
+ "@contrast/dep-hooks": "1.23.2",
27
+ "@contrast/logger": "1.27.2",
28
+ "@contrast/patcher": "1.26.2"
29
29
  }
30
30
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/patcher",
3
- "version": "1.26.1",
3
+ "version": "1.26.2",
4
4
  "description": "Advanced monkey patching--registers hooks to run in and around functions",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -20,6 +20,6 @@
20
20
  "test": "bash ../scripts/test.sh"
21
21
  },
22
22
  "dependencies": {
23
- "@contrast/logger": "1.27.1"
23
+ "@contrast/logger": "1.27.2"
24
24
  }
25
25
  }
@@ -27,7 +27,7 @@ module.exports = function(core) {
27
27
  require('./install/http')(core);
28
28
 
29
29
  // common libraries instrumentation
30
- require('./install/body-parser1')(core);
30
+ require('./install/body-parser')(core);
31
31
  require('./install/cookie-parser1')(core);
32
32
  require('./install/formidable1')(core);
33
33
  require('./install/koa-body5')(core);
@@ -62,7 +62,7 @@ module.exports = (core) => {
62
62
 
63
63
  // Patch body parser - `body-parser` used by `express` framework
64
64
  function install() {
65
- depHooks.resolve({ name: 'body-parser', version: '<2' }, (bodyParser) => {
65
+ depHooks.resolve({ name: 'body-parser', version: '<3' }, (bodyParser) => {
66
66
  const origBodyParser = bodyParser;
67
67
 
68
68
  const { json: origJson, raw: origRaw, text: origText, urlencoded: origUrlencoded } = bodyParser;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/protect",
3
- "version": "1.64.1",
3
+ "version": "1.64.2",
4
4
  "description": "Contrast service providing framework-agnostic Protect support",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -21,16 +21,16 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@contrast/agent-lib": "^9.1.0",
24
- "@contrast/common": "1.34.1",
25
- "@contrast/config": "1.49.1",
26
- "@contrast/core": "1.54.1",
27
- "@contrast/dep-hooks": "1.23.1",
28
- "@contrast/esm-hooks": "2.28.1",
29
- "@contrast/instrumentation": "1.33.1",
30
- "@contrast/logger": "1.27.1",
31
- "@contrast/patcher": "1.26.1",
32
- "@contrast/rewriter": "1.30.1",
33
- "@contrast/scopes": "1.24.1",
24
+ "@contrast/common": "1.34.2",
25
+ "@contrast/config": "1.49.2",
26
+ "@contrast/core": "1.54.2",
27
+ "@contrast/dep-hooks": "1.23.2",
28
+ "@contrast/esm-hooks": "2.28.2",
29
+ "@contrast/instrumentation": "1.33.2",
30
+ "@contrast/logger": "1.27.2",
31
+ "@contrast/patcher": "1.26.2",
32
+ "@contrast/rewriter": "1.30.2",
33
+ "@contrast/scopes": "1.24.2",
34
34
  "async-hook-domain": "^4.0.1",
35
35
  "ipaddr.js": "^2.0.1",
36
36
  "on-finished": "^2.4.1",
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const v1_endpoint_1 = __importDefault(require("./v1-endpoint"));
7
+ const common_1 = require("@contrast/common");
7
8
  class RoutesObserved extends v1_endpoint_1.default {
8
9
  constructor(core, uiReporter) {
9
10
  super(core, {
@@ -13,7 +14,7 @@ class RoutesObserved extends v1_endpoint_1.default {
13
14
  }
14
15
  async post(route) {
15
16
  const { client, core: { config }, } = this;
16
- const PROD = config.getEffectiveSource('server.environment');
17
+ const PROD = config.getEffectiveSource('server.environment') == common_1.ServerEnvironment.PRODUCTION;
17
18
  const session_id = config.getEffectiveValue('application.session_id');
18
19
  await client.post(this.appUrl('/observed'), {
19
20
  /**
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/reporter",
3
- "version": "1.51.1",
3
+ "version": "1.51.2",
4
4
  "description": "Subscribes to agent messages and reports them",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -21,12 +21,12 @@
21
21
  "test": "bash ../scripts/test.sh"
22
22
  },
23
23
  "dependencies": {
24
- "@contrast/common": "1.34.1",
25
- "@contrast/config": "1.49.1",
26
- "@contrast/core": "1.54.1",
27
- "@contrast/logger": "1.27.1",
24
+ "@contrast/common": "1.34.2",
25
+ "@contrast/config": "1.49.2",
26
+ "@contrast/core": "1.54.2",
27
+ "@contrast/logger": "1.27.2",
28
28
  "@contrast/perf": "1.3.1",
29
- "@contrast/scopes": "1.24.1",
29
+ "@contrast/scopes": "1.24.2",
30
30
  "axios": "^1.7.4",
31
31
  "crc-32": "^1.2.2",
32
32
  "safe-stable-stringify": "^2.4.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/rewriter",
3
- "version": "1.30.1",
3
+ "version": "1.30.2",
4
4
  "description": "A transpilation tool mainly used for instrumentation",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -21,10 +21,10 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@contrast/agent-swc-plugin": "3.0.0",
24
- "@contrast/common": "1.34.1",
25
- "@contrast/config": "1.49.1",
26
- "@contrast/core": "1.54.1",
27
- "@contrast/logger": "1.27.1",
24
+ "@contrast/common": "1.34.2",
25
+ "@contrast/config": "1.49.2",
26
+ "@contrast/core": "1.54.2",
27
+ "@contrast/logger": "1.27.2",
28
28
  "@swc/core": "1.11.24"
29
29
  }
30
30
  }
@@ -23,11 +23,13 @@ import { Scopes } from '@contrast/scopes';
23
23
  export { RouteInfo };
24
24
 
25
25
  export interface RouteCoverage extends Installable {
26
+ _normalizedUrlMapper: any;
26
27
  discover(info: RouteInfo): void;
27
28
  discoveryFinished(): void;
28
29
  queue(info: RouteInfo): void;
29
30
  queuingFinished(): void;
30
31
  observe(info: RouteInfo): void;
32
+ uriPathToNormalizedUrl(uriPath: string): string;
31
33
  }
32
34
 
33
35
  export interface Core {
@@ -44,8 +44,11 @@ module.exports = function init(core) {
44
44
  },
45
45
 
46
46
  discover(info) {
47
+ const id = routeIdentifier(info.method, info.signature);
48
+ if (routeInfo.get(id)) return;
49
+
47
50
  logger.trace({ info }, 'Discovered new route:');
48
- routeInfo.set(routeIdentifier(info.method, info.signature), info);
51
+ routeInfo.set(id, info);
49
52
  this._normalizedUrlMapper.handleDiscover(info);
50
53
 
51
54
  },
@@ -67,7 +70,7 @@ module.exports = function init(core) {
67
70
  if (routeQueue.size === 1) {
68
71
  setTimeout(() => {
69
72
  this.discoveryFinished();
70
- }, 10000);
73
+ }, 10_000);
71
74
  }
72
75
  },
73
76
 
@@ -99,16 +102,12 @@ module.exports = function init(core) {
99
102
  route.method = info.method;
100
103
  route.url = info.url;
101
104
  const store = scopes.sources.getStore();
102
- if (store && !store.route) {
103
- store.route = route;
104
- }
105
105
 
106
+ if (store) store.route = route;
106
107
  if (recentlyObserved.has(route.signature)) return;
107
108
 
108
109
  recentlyObserved.add(route.signature);
109
-
110
110
  logger.trace({ info }, 'Observed route:');
111
-
112
111
  // these events need source correlation
113
112
  messages.emit(Event.ROUTE_COVERAGE_OBSERVATION, {
114
113
  ...route,
@@ -122,7 +121,6 @@ module.exports = function init(core) {
122
121
  },
123
122
  };
124
123
 
125
- require('./install/http')(core);
126
124
  require('./install/express')(core);
127
125
  require('./install/fastify')(core);
128
126
  require('./install/graphql')(core);
@@ -130,5 +128,13 @@ module.exports = function init(core) {
130
128
  require('./install/koa')(core);
131
129
  require('./install/restify')(core);
132
130
 
131
+ messages.on(Event.SERVER_LISTENING, () => {
132
+ // we wait to report in timers event loop phase, this way we can
133
+ // have components respond to this synchronously to finalize discovery
134
+ setImmediate(() => {
135
+ core.routeCoverage.discoveryFinished();
136
+ });
137
+ });
138
+
133
139
  return routeCoverage;
134
140
  };