@contrast/agentify 1.13.1 → 1.14.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
@@ -33,6 +33,7 @@ const defaultOpts = {
33
33
  'depHooks',
34
34
  'routeCoverage',
35
35
  'libraryAnalysis',
36
+ 'heapSnapshots',
36
37
  'rewriteHooks',
37
38
  'functionHooks'
38
39
  ]
@@ -40,10 +41,12 @@ const defaultOpts = {
40
41
 
41
42
  module.exports = function (core) {
42
43
  // compose add'l local services
44
+ require('./heap-snapshots')(core);
43
45
  require('./sources')(core);
44
46
  require('./function-hooks')(core);
45
47
  require('./rewrite-hooks')(core);
46
48
 
49
+
47
50
  /**
48
51
  * The interface is a function, which when called, will hook runMain
49
52
  * @param {function} preRunMain
@@ -95,7 +98,7 @@ class Agent {
95
98
  }
96
99
 
97
100
  logger.info('Starting the Contrast agent');
98
- logger.debug({ config }, 'Agent configuration');
101
+ logger.info({ config }, 'Agent configuration');
99
102
 
100
103
  const plugin = await opts.preRunMain(core);
101
104
 
@@ -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.14.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.19.0",
22
+ "@contrast/logger": "1.6.0"
21
23
  }
22
24
  }