@contrast/agentify 1.13.1 → 1.15.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.
@@ -0,0 +1,63 @@
1
+ /*
2
+ * Copyright: 2023 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 fs = require('fs');
19
+ const path = require('path');
20
+ const v8 = require('v8');
21
+
22
+ module.exports = function init(core) {
23
+ const {
24
+ config: {
25
+ agent: { heap_dump },
26
+ },
27
+ logger
28
+ } = core;
29
+
30
+ const dir = path.join(process.cwd(), heap_dump.path);
31
+ const ext = '.heapsnapshot';
32
+
33
+ const heapSnapshots = {
34
+ writeHeapSnapshot() {
35
+ const filename = path.format({ name: `${Date.now()}-contrast`, dir, ext });
36
+ logger.info('Writing heap snapshot at %s', filename);
37
+ v8.writeHeapSnapshot(filename);
38
+ },
39
+ async install() {
40
+ if (!heap_dump.enable) return;
41
+
42
+ try {
43
+ await fs.promises.mkdir(dir, { recursive: true });
44
+ } catch (err) {
45
+ logger.error({ err }, 'Unable to create snapshot directory. No heap snapshots will be taken.');
46
+ return;
47
+ }
48
+
49
+ setTimeout(() => {
50
+ let count = 0;
51
+ const interval = setInterval(async () => {
52
+ await heapSnapshots.writeHeapSnapshot();
53
+ count++;
54
+ if (count === heap_dump.count) {
55
+ clearInterval(interval);
56
+ }
57
+ }, heap_dump.window_ms).unref();
58
+ }, heap_dump.delay_ms).unref();
59
+ },
60
+ };
61
+
62
+ return core.heapSnapshots = heapSnapshots;
63
+ };
package/lib/index.d.ts CHANGED
@@ -13,8 +13,27 @@
13
13
  * way not consistent with the End User License Agreement.
14
14
  */
15
15
 
16
- import RequireHook from '@contrast/require-hook';
16
+ import { Config } from '@contrast/config';
17
17
  import { Logger } from '@contrast/logger';
18
+ import RequireHook from '@contrast/require-hook';
19
+ import { Rewriter } from '@contrast/rewriter';
20
+
21
+ declare module 'module' {
22
+ class Module {
23
+ /**
24
+ * @see https://github.com/nodejs/node/blob/main/lib/internal/modules/cjs/loader.js
25
+ * @param content The source code of the module
26
+ * @param filename The file path of the module
27
+ */
28
+ _compile(content: string, filename: string);
29
+ }
30
+ export = Module;
31
+ }
32
+
33
+ declare module 'node:module' {
34
+ import Module = require('module');
35
+ export = Module;
36
+ }
18
37
 
19
38
  interface AgentifyOptions {
20
39
  install: boolean;
@@ -41,9 +60,11 @@ export interface Agentify<T> {
41
60
  (preRunMain: PreRunMain<T>, opts?: AgentifyOptions): Agent<T>;
42
61
  }
43
62
 
44
- interface Core<T> {
63
+ export interface Core<T> {
64
+ readonly config: Config;
45
65
  readonly depHooks: RequireHook;
46
66
  readonly logger: Logger;
67
+ readonly rewriter: Rewriter;
47
68
  agentify: Agentify<T>;
48
69
  }
49
70
 
package/lib/index.js CHANGED
@@ -20,8 +20,7 @@ const path = require('path');
20
20
  const Module = require('module');
21
21
 
22
22
  const defaultOpts = {
23
- install: true,
24
- svcList: [
23
+ installOrder: [
25
24
  'reporter',
26
25
  'contrastMethods',
27
26
  'deadzones',
@@ -33,6 +32,7 @@ const defaultOpts = {
33
32
  'depHooks',
34
33
  'routeCoverage',
35
34
  'libraryAnalysis',
35
+ 'heapSnapshots',
36
36
  'rewriteHooks',
37
37
  'functionHooks'
38
38
  ]
@@ -40,10 +40,12 @@ const defaultOpts = {
40
40
 
41
41
  module.exports = function (core) {
42
42
  // compose add'l local services
43
+ require('./heap-snapshots')(core);
43
44
  require('./sources')(core);
44
45
  require('./function-hooks')(core);
45
46
  require('./rewrite-hooks')(core);
46
47
 
48
+
47
49
  /**
48
50
  * The interface is a function, which when called, will hook runMain
49
51
  * @param {function} preRunMain
@@ -95,11 +97,11 @@ class Agent {
95
97
  }
96
98
 
97
99
  logger.info('Starting the Contrast agent');
98
- logger.debug({ config }, 'Agent configuration');
100
+ logger.info({ config }, 'Agent configuration');
99
101
 
100
102
  const plugin = await opts.preRunMain(core);
101
103
 
102
- if (opts.install) {
104
+ if (opts.installOrder?.length) {
103
105
  await self.install();
104
106
  }
105
107
 
@@ -130,7 +132,7 @@ class Agent {
130
132
  }
131
133
 
132
134
  async install() {
133
- for (const svcName of this.opts.svcList) {
135
+ for (const svcName of this.opts.installOrder) {
134
136
  const svc = this.core[svcName];
135
137
  if (svc?.install) {
136
138
  this.core.logger.trace('installing service: %s', svcName);
@@ -12,22 +12,33 @@
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
+ // @ts-check
15
16
 
16
17
  'use strict';
17
18
 
18
19
  const Module = require('module');
19
20
 
20
- module.exports = function(deps) {
21
- const origCompile = Module.prototype._compile;
22
-
23
- deps.rewriteHooks = {
21
+ /**
22
+ * @param {import('.').Core & {
23
+ * rewriteHooks?: import('@contrast/common').Installable;
24
+ * }} core;
25
+ * @returns {import('@contrast/common').Installable}
26
+ */
27
+ module.exports = function init(core) {
28
+ const { _compile } = Module.prototype;
24
29
 
30
+ core.rewriteHooks = {
25
31
  install() {
26
- if (!deps.config.agent.node.enable_rewrite) return;
32
+ if (!core.config.agent.node.enable_rewrite) return;
27
33
 
28
- Module.prototype._compile = function(content, filename) {
29
- let compiled;
30
- const { code } = deps.rewriter.rewrite(content, {
34
+ /**
35
+ * @see https://github.com/nodejs/node/blob/main/lib/internal/modules/cjs/loader.js
36
+ * @param {string} content The source code of the module
37
+ * @param {string} filename The file path of the module
38
+ */
39
+ Module.prototype._compile = function (content, filename) {
40
+ let result;
41
+ const { code } = core.rewriter.rewrite(content, {
31
42
  filename,
32
43
  isModule: false,
33
44
  inject: true,
@@ -35,25 +46,24 @@ module.exports = function(deps) {
35
46
  });
36
47
 
37
48
  try {
38
- compiled = origCompile.call(this, code, filename);
49
+ result = _compile.call(this, code, filename);
39
50
  } catch (err) {
40
- deps.logger.error(
51
+ core.logger.warn(
41
52
  { err },
42
- 'Failed to compile rewritten code for %s, rewritten code %s, compiling original code.',
53
+ 'Failed to compile rewritten code for %s, compiling original code.',
43
54
  filename,
44
- code
45
55
  );
46
- compiled = origCompile.call(this, content, filename);
56
+ result = _compile.call(this, content, filename);
47
57
  }
48
58
 
49
- return compiled;
59
+ return result;
50
60
  };
51
61
  },
52
62
 
53
- restore() {
54
- Module.prototype._compile = origCompile;
63
+ uninstall() {
64
+ Module.prototype._compile = _compile;
55
65
  }
56
66
  };
57
67
 
58
- return deps.rewriteHooks;
68
+ return core.rewriteHooks;
59
69
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/agentify",
3
- "version": "1.13.1",
3
+ "version": "1.15.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)",
@@ -17,6 +17,8 @@
17
17
  "test": "../scripts/test.sh"
18
18
  },
19
19
  "dependencies": {
20
- "@contrast/common": "1.15.1"
20
+ "@contrast/common": "1.15.1",
21
+ "@contrast/config": "1.20.0",
22
+ "@contrast/logger": "1.6.0"
21
23
  }
22
24
  }