@contrast/assess 1.37.0 → 1.38.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 (90) hide show
  1. package/lib/crypto-analysis/install/crypto.js +1 -1
  2. package/lib/dataflow/propagation/install/JSON/parse.js +1 -0
  3. package/lib/dataflow/propagation/install/JSON/stringify.js +1 -0
  4. package/lib/dataflow/propagation/install/array-prototype-join.js +1 -0
  5. package/lib/dataflow/propagation/install/buffer.js +1 -0
  6. package/lib/dataflow/propagation/install/contrast-methods/number.js +1 -0
  7. package/lib/dataflow/propagation/install/contrast-methods/string.js +1 -0
  8. package/lib/dataflow/propagation/install/contrast-methods/tag.js +1 -0
  9. package/lib/dataflow/propagation/install/decode-uri-component.js +1 -0
  10. package/lib/dataflow/propagation/install/ejs/escape-xml.js +1 -0
  11. package/lib/dataflow/propagation/install/ejs/template.js +1 -0
  12. package/lib/dataflow/propagation/install/encode-uri.js +1 -0
  13. package/lib/dataflow/propagation/install/escape-html.js +1 -0
  14. package/lib/dataflow/propagation/install/escape.js +1 -0
  15. package/lib/dataflow/propagation/install/fastify-send.js +1 -0
  16. package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.js +1 -0
  17. package/lib/dataflow/propagation/install/isnumeric-0.js +1 -0
  18. package/lib/dataflow/propagation/install/joi/boolean.js +2 -1
  19. package/lib/dataflow/propagation/install/joi/expression.js +2 -1
  20. package/lib/dataflow/propagation/install/joi/index.js +3 -1
  21. package/lib/dataflow/propagation/install/joi/keys.js +1 -0
  22. package/lib/dataflow/propagation/install/joi/number.js +2 -1
  23. package/lib/dataflow/propagation/install/joi/string-schema.js +3 -1
  24. package/lib/dataflow/propagation/install/joi/values.js +2 -1
  25. package/lib/dataflow/propagation/install/mongoose/schema-map.js +2 -0
  26. package/lib/dataflow/propagation/install/mongoose/schema-mixed.js +2 -0
  27. package/lib/dataflow/propagation/install/mongoose/schema-string.js +5 -0
  28. package/lib/dataflow/propagation/install/mustache-escape.js +1 -0
  29. package/lib/dataflow/propagation/install/mysql-connection-escape.js +3 -0
  30. package/lib/dataflow/propagation/install/parse-int.js +1 -0
  31. package/lib/dataflow/propagation/install/path/basename.js +1 -0
  32. package/lib/dataflow/propagation/install/path/dirname.js +1 -0
  33. package/lib/dataflow/propagation/install/path/extname.js +1 -0
  34. package/lib/dataflow/propagation/install/path/format.js +1 -0
  35. package/lib/dataflow/propagation/install/path/join-and-resolve.js +1 -0
  36. package/lib/dataflow/propagation/install/path/normalize.js +1 -0
  37. package/lib/dataflow/propagation/install/path/parse.js +2 -1
  38. package/lib/dataflow/propagation/install/path/relative.js +1 -0
  39. package/lib/dataflow/propagation/install/path/toNamespacedPath.js +1 -0
  40. package/lib/dataflow/propagation/install/pug/index.js +1 -0
  41. package/lib/dataflow/propagation/install/pug-runtime-escape.js +1 -0
  42. package/lib/dataflow/propagation/install/querystring/escape.js +2 -1
  43. package/lib/dataflow/propagation/install/querystring/parse.js +1 -0
  44. package/lib/dataflow/propagation/install/querystring/stringify.js +2 -1
  45. package/lib/dataflow/propagation/install/reg-exp-prototype-exec.js +1 -0
  46. package/lib/dataflow/propagation/install/send.js +1 -0
  47. package/lib/dataflow/propagation/install/sequelize/query-generator.js +1 -0
  48. package/lib/dataflow/propagation/install/sequelize/sql-string.js +1 -0
  49. package/lib/dataflow/propagation/install/sql-template-strings.js +1 -0
  50. package/lib/dataflow/propagation/install/string/concat.js +1 -1
  51. package/lib/dataflow/propagation/install/string/format-methods.js +1 -1
  52. package/lib/dataflow/propagation/install/string/html-methods.js +1 -1
  53. package/lib/dataflow/propagation/install/string/index.js +1 -1
  54. package/lib/dataflow/propagation/install/string/match-all.js +1 -1
  55. package/lib/dataflow/propagation/install/string/match.js +1 -1
  56. package/lib/dataflow/propagation/install/string/replace.js +1 -1
  57. package/lib/dataflow/propagation/install/string/slice.js +1 -1
  58. package/lib/dataflow/propagation/install/string/split.js +1 -1
  59. package/lib/dataflow/propagation/install/string/substring.js +1 -1
  60. package/lib/dataflow/propagation/install/string/trim.js +3 -3
  61. package/lib/dataflow/propagation/install/unescape.js +1 -0
  62. package/lib/dataflow/propagation/install/url/domain-parsers.js +1 -0
  63. package/lib/dataflow/propagation/install/url/parse.js +2 -1
  64. package/lib/dataflow/propagation/install/url/searchParams.js +3 -1
  65. package/lib/dataflow/propagation/install/url/url.js +2 -1
  66. package/lib/dataflow/propagation/install/util-format.js +1 -0
  67. package/lib/dataflow/propagation/install/validator/hooks.js +2 -0
  68. package/lib/dataflow/sinks/install/child-process.js +1 -1
  69. package/lib/dataflow/sinks/install/express/unvalidated-redirect.js +1 -1
  70. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +1 -1
  71. package/lib/dataflow/sinks/install/fs-original.js +170 -0
  72. package/lib/dataflow/sinks/install/fs.js +1 -1
  73. package/lib/dataflow/sinks/install/function.js +1 -1
  74. package/lib/dataflow/sinks/install/hapi/unvalidated-redirect.js +1 -1
  75. package/lib/dataflow/sinks/install/http/request.js +1 -1
  76. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +1 -1
  77. package/lib/dataflow/sinks/install/libxmljs.js +1 -1
  78. package/lib/dataflow/sinks/install/marsdb.js +1 -1
  79. package/lib/dataflow/sinks/install/mongodb.js +1 -1
  80. package/lib/dataflow/sinks/install/mysql.js +1 -1
  81. package/lib/dataflow/sinks/install/postgres.js +1 -1
  82. package/lib/dataflow/sinks/install/sequelize.js +1 -1
  83. package/lib/dataflow/sinks/install/vm.js +1 -1
  84. package/lib/sampler.js +1 -1
  85. package/lib/sampler.test.js +10 -5
  86. package/lib/session-configuration/install/express-session.js +1 -1
  87. package/lib/session-configuration/install/fastify-cookie.js +1 -1
  88. package/lib/session-configuration/install/hapi.js +1 -1
  89. package/lib/session-configuration/install/koa.js +1 -1
  90. package/package.json +9 -9
@@ -75,7 +75,7 @@ module.exports = function(core) {
75
75
  patcher.patch(String.prototype, 'matchAll', {
76
76
  name,
77
77
  patchType,
78
- usePerf: true,
78
+ usePerf: 'sync',
79
79
  around(origFn, data) {
80
80
  const { args, obj, hooked, orig } = data;
81
81
 
@@ -79,7 +79,7 @@ module.exports = function(core) {
79
79
  patcher.patch(String.prototype, 'match', {
80
80
  name,
81
81
  patchType,
82
- usePerf: true,
82
+ usePerf: 'sync',
83
83
  around(origFn, data) {
84
84
  const { args, obj } = data;
85
85
  if (
@@ -150,7 +150,7 @@ module.exports = function(core) {
150
150
  patcher.patch(String.prototype, 'replace', {
151
151
  name,
152
152
  patchType,
153
- usePerf: true,
153
+ usePerf: 'sync',
154
154
  pre(data) {
155
155
  if (!getSourceContext(PROPAGATOR)) return;
156
156
 
@@ -54,7 +54,7 @@ module.exports = function(core) {
54
54
  patcher.patch(String.prototype, 'slice', {
55
55
  name,
56
56
  patchType,
57
- usePerf: true,
57
+ usePerf: 'sync',
58
58
  post(data) {
59
59
  const { name, args: origArgs, obj, result, hooked, orig } = data;
60
60
  if (!result || !getSourceContext(PROPAGATOR)) return;
@@ -37,7 +37,7 @@ module.exports = function(core) {
37
37
  patcher.patch(String.prototype, 'split', {
38
38
  name,
39
39
  patchType,
40
- usePerf: true,
40
+ usePerf: 'sync',
41
41
  post(data) {
42
42
  const { name, args: origArgs, obj, result, hooked, orig } = data;
43
43
  if (
@@ -62,7 +62,7 @@ module.exports = function(core) {
62
62
  patcher.patch(String.prototype, method, {
63
63
  name: `String.prototype.${method}`,
64
64
  patchType,
65
- usePerf: true,
65
+ usePerf: 'sync',
66
66
  post(data) {
67
67
  const { obj, args: origArgs, result, name, hooked, orig } = data;
68
68
  if (!result || !getSourceContext(PROPAGATOR)) return;
@@ -92,21 +92,21 @@ module.exports = function(core) {
92
92
  name: 'String.prototype.trim',
93
93
  patchType,
94
94
  post: createPostHook('trim'),
95
- usePerf: true,
95
+ usePerf: 'sync',
96
96
  });
97
97
 
98
98
  patcher.patch(String.prototype, 'trimStart', {
99
99
  name: 'String.prototype.trimStart',
100
100
  patchType,
101
101
  post: createPostHook('trimStart'),
102
- usePerf: true,
102
+ usePerf: 'sync',
103
103
  });
104
104
 
105
105
  patcher.patch(String.prototype, 'trimEnd', {
106
106
  name: 'String.prototype.trimEnd',
107
107
  patchType,
108
108
  post: createPostHook('trimEnd', 0),
109
- usePerf: true,
109
+ usePerf: 'sync',
110
110
  });
111
111
  },
112
112
  uninstall() {
@@ -37,6 +37,7 @@ module.exports = function(core) {
37
37
  patcher.patch(global, 'unescape', {
38
38
  name,
39
39
  patchType,
40
+ usePerf: 'sync',
40
41
  post(data) {
41
42
  const { args, result, hooked, orig } = data;
42
43
  if (!result || !args[0] || !getSourceContext(PROPAGATOR)) return;
@@ -39,6 +39,7 @@ module.exports = function(core) {
39
39
  patcher.patch(url, method, {
40
40
  name,
41
41
  patchType,
42
+ usePerf: 'sync',
42
43
  post(data) {
43
44
  const { args, result, hooked, orig } = data;
44
45
  if (!result || !args[0] || !getSourceContext(PROPAGATOR)) return;
@@ -24,7 +24,7 @@ module.exports = function(core) {
24
24
  depHooks,
25
25
  assess: {
26
26
  getSourceContext,
27
- inspect, // todo: remove
27
+ inspect, // TODO NODE-3455: remove
28
28
  eventFactory: { createPropagationEvent },
29
29
  dataflow: { tracker }
30
30
  }
@@ -87,6 +87,7 @@ module.exports = function(core) {
87
87
  patcher.patch(url, 'parse', {
88
88
  name,
89
89
  patchType,
90
+ usePerf: 'sync',
90
91
  post(data) {
91
92
  const { args, result, hooked, orig } = data;
92
93
  if (!result || !args[0] || !getSourceContext(PROPAGATOR)) return;
@@ -25,7 +25,7 @@ module.exports = function(core) {
25
25
  patcher,
26
26
  depHooks,
27
27
  assess: {
28
- inspect, // todo: remove
28
+ inspect, // TODO NODE-3455: remove
29
29
  getSourceContext,
30
30
  eventFactory: { createPropagationEvent },
31
31
  dataflow: { tracker }
@@ -66,6 +66,7 @@ module.exports = function(core) {
66
66
  patcher.patch(url, 'URLSearchParams', {
67
67
  name,
68
68
  patchType,
69
+ usePerf: 'sync',
69
70
  post(data) {
70
71
  const { args, obj, result } = data;
71
72
  if (!result || !args[0] || !getSourceContext(PROPAGATOR)) return;
@@ -120,6 +121,7 @@ module.exports = function(core) {
120
121
  patcher.patch(obj.prototype, 'toString', {
121
122
  name: 'url.URLSearchParams.toString',
122
123
  patchType,
124
+ usePerf: 'sync',
123
125
  post(data) {
124
126
  const { obj: params } = data;
125
127
 
@@ -26,7 +26,7 @@ module.exports = function(core) {
26
26
  depHooks,
27
27
  assess: {
28
28
  getSourceContext,
29
- inspect, // todo: remove
29
+ inspect, // TODO NODE-3455: remove
30
30
  eventFactory: { createPropagationEvent },
31
31
  dataflow: { tracker }
32
32
  }
@@ -92,6 +92,7 @@ module.exports = function(core) {
92
92
  patcher.patch(url, 'URL', {
93
93
  name,
94
94
  patchType,
95
+ usePerf: 'sync',
95
96
  post(data) {
96
97
  const { args, result } = data;
97
98
  if (!result || !args[0] || !getSourceContext(PROPAGATOR)) return;
@@ -39,6 +39,7 @@ module.exports = function(core) {
39
39
  return patcher.patch(util, 'format', {
40
40
  name,
41
41
  patchType,
42
+ usePerf: 'sync',
42
43
  post(data) {
43
44
  const { args, result, hooked, orig } = data;
44
45
  if (!result || !args[0] || !isString(args[0]) || !getSourceContext(PROPAGATOR)) return;
@@ -70,6 +70,7 @@ module.exports = function (core) {
70
70
  return patcher.patch(...getPatcherArgs(index), {
71
71
  name,
72
72
  patchType,
73
+ usePerf: 'sync',
73
74
  post(data) {
74
75
  const matches = validator === 'matches';
75
76
  if (
@@ -105,6 +106,7 @@ module.exports = function (core) {
105
106
  (index) => patcher.patch(...getPatcherArgs(index), {
106
107
  name: `validator.${untracker}`,
107
108
  patchType,
109
+ usePerf: 'sync',
108
110
  post(data) {
109
111
  if (data.result && getSourceContext()) {
110
112
  const trackingData = tracker.getData(data.args[0]);
@@ -34,7 +34,7 @@ module.exports = function(core) {
34
34
  depHooks,
35
35
  patcher,
36
36
  assess: {
37
- inspect, // todo: remove
37
+ inspect, // TODO NODE-3455: remove
38
38
  getSourceContext,
39
39
  eventFactory: { createSinkEvent },
40
40
  dataflow: {
@@ -45,7 +45,7 @@ module.exports = function(core) {
45
45
  patcher,
46
46
  config,
47
47
  assess: {
48
- inspect, // todo: remove
48
+ inspect, // TODO NODE-3455: remove
49
49
  getSourceContext,
50
50
  eventFactory: { createSinkEvent },
51
51
  dataflow: {
@@ -64,7 +64,7 @@ module.exports = function(core) {
64
64
  depHooks,
65
65
  patcher,
66
66
  assess: {
67
- inspect, // todo: remove
67
+ inspect, // TODO NODE-3455: remove
68
68
  getSourceContext,
69
69
  eventFactory: { createSinkEvent },
70
70
  dataflow: {
@@ -0,0 +1,170 @@
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
+ 'use strict';
16
+ const { patchType } = require('../common');
17
+
18
+ const {
19
+ DataflowTag: {
20
+ URL_ENCODED,
21
+ LIMITED_CHARS,
22
+ ALPHANUM_SPACE_HYPHEN,
23
+ SAFE_PATH,
24
+ UNTRUSTED,
25
+ },
26
+ FS_METHODS,
27
+ Rule: { PATH_TRAVERSAL: ruleId },
28
+ isString,
29
+ ArrayPrototypeJoin,
30
+ } = require('@contrast/common');
31
+ const { InstrumentationType: { RULE } } = require('../../../constants');
32
+
33
+ module.exports = function(core) {
34
+ const {
35
+ depHooks,
36
+ patcher,
37
+ assess: {
38
+ inspect, // TODO NODE-3455: remove
39
+ getSourceContext,
40
+ eventFactory: { createSinkEvent },
41
+ dataflow: {
42
+ tracker,
43
+ sinks: { isVulnerable, reportFindings },
44
+ },
45
+ },
46
+ } = core;
47
+
48
+ const safeTags = [
49
+ `excluded:${ruleId}`,
50
+ URL_ENCODED,
51
+ LIMITED_CHARS,
52
+ ALPHANUM_SPACE_HYPHEN,
53
+ SAFE_PATH,
54
+ ];
55
+
56
+ function getValues(indices, args) {
57
+ return indices.reduce((acc, idx) => {
58
+ const value = args[idx];
59
+ if (value && isString(value)) acc.push(value);
60
+ return acc;
61
+ }, []);
62
+ }
63
+
64
+ const pre = (name, method, moduleName = 'fs', fullMethodName = '') => (data) => {
65
+ const { name: methodName, indices } = method;
66
+ if (!getSourceContext(RULE, ruleId)) return;
67
+
68
+ const values = getValues(indices, data.args);
69
+ if (!values.length) return;
70
+
71
+ const args = values.map((v) => {
72
+ const strInfo = tracker.getData(v);
73
+ return {
74
+ value: strInfo ? strInfo.value : v,
75
+ tracked: !!strInfo,
76
+ strInfo
77
+ };
78
+ });
79
+ for (let i = 0; i < values.length; i++) {
80
+ const { strInfo } = args[i];
81
+
82
+ if (!strInfo || !isVulnerable(UNTRUSTED, safeTags, strInfo.tags)) {
83
+ continue;
84
+ }
85
+
86
+ const event = createSinkEvent({
87
+ name,
88
+ moduleName,
89
+ methodName: fullMethodName || methodName,
90
+ context: `${name}(${ArrayPrototypeJoin.call(
91
+ args.map((a) => inspect(a.value)),
92
+ ', '
93
+ )})`,
94
+ history: [strInfo],
95
+ object: {
96
+ value: 'fs',
97
+ tracked: false,
98
+ },
99
+ args: args.map(({ value, tracked }) => ({ value, tracked })),
100
+ tags: strInfo.tags,
101
+ source: `P${i}`,
102
+ stacktraceOpts: {
103
+ contructorOpt: data.hooked,
104
+ prependFrames: [data.orig],
105
+ },
106
+ });
107
+
108
+ if (event) {
109
+ reportFindings({
110
+ ruleId,
111
+ sinkEvent: event,
112
+ });
113
+ }
114
+ }
115
+ };
116
+
117
+ core.assess.dataflow.sinks.pathTraversal = {
118
+ install() {
119
+ depHooks.resolve({ name: 'fs' }, (fs) => {
120
+ for (const method of FS_METHODS) {
121
+ // not all methods are available on every OS or Node version.
122
+ if (fs[method.name]) {
123
+ const name = `fs.${method.name}`;
124
+ patcher.patch(fs, method.name, {
125
+ name,
126
+ patchType,
127
+ pre: pre(name, method),
128
+ });
129
+ }
130
+
131
+ if (method.sync) {
132
+ const syncName = `${method.name}Sync`;
133
+ if (fs[syncName]) {
134
+ const name = `fs.${syncName}`;
135
+ patcher.patch(fs, syncName, {
136
+ name,
137
+ patchType,
138
+ pre: pre(name, method, 'fs', syncName),
139
+ });
140
+ }
141
+ }
142
+
143
+ if (method.promises && fs.promises && fs.promises[method.name]) {
144
+ const name = `fs.promises.${method.name}`;
145
+ patcher.patch(fs.promises, method.name, {
146
+ name,
147
+ patchType,
148
+ pre: pre(name, method, 'fs.promises'),
149
+ });
150
+ }
151
+ }
152
+ });
153
+
154
+ depHooks.resolve({ name: 'fs/promises' }, (fsPromises) => {
155
+ for (const method of FS_METHODS) {
156
+ if (method.promises && fsPromises[method.name]) {
157
+ const name = `fsPromises.${method.name}`;
158
+ patcher.patch(fsPromises, method.name, {
159
+ name,
160
+ patchType,
161
+ pre: pre(name, method, 'fsPromises'),
162
+ });
163
+ }
164
+ }
165
+ });
166
+ },
167
+ };
168
+
169
+ return core.assess.dataflow.sinks.pathTraversal;
170
+ };
@@ -35,7 +35,7 @@ module.exports = function(core) {
35
35
  depHooks,
36
36
  patcher,
37
37
  assess: {
38
- inspect, // todo: remove
38
+ inspect, // TODO NODE-3455: remove
39
39
  getSourceContext,
40
40
  eventFactory: { createSinkEvent },
41
41
  dataflow: {
@@ -46,7 +46,7 @@ module.exports = function (core) {
46
46
  logger,
47
47
  patcher,
48
48
  assess: {
49
- inspect, // todo: remove
49
+ inspect, // TODO NODE-3455: remove
50
50
  getSourceContext,
51
51
  eventFactory: { createSinkEvent },
52
52
  dataflow: {
@@ -45,7 +45,7 @@ module.exports = function(core) {
45
45
  patcher,
46
46
  config,
47
47
  assess: {
48
- inspect, // todo: remove
48
+ inspect, // TODO NODE-3455: remove
49
49
  getSourceContext,
50
50
  eventFactory: { createSinkEvent },
51
51
  dataflow: {
@@ -46,7 +46,7 @@ module.exports = function(core) {
46
46
  depHooks,
47
47
  patcher,
48
48
  assess: {
49
- inspect, // todo: remove
49
+ inspect, // TODO NODE-3455: remove
50
50
  getSourceContext,
51
51
  eventFactory: { createSinkEvent },
52
52
  dataflow: {
@@ -46,7 +46,7 @@ module.exports = function(core) {
46
46
  patcher,
47
47
  config,
48
48
  assess: {
49
- inspect, // todo: remove
49
+ inspect, // TODO NODE-3455: remove
50
50
  getSourceContext,
51
51
  eventFactory: { createSinkEvent },
52
52
  dataflow: {
@@ -47,7 +47,7 @@ module.exports = function(core) {
47
47
  depHooks,
48
48
  patcher,
49
49
  assess: {
50
- inspect, // todo: remove
50
+ inspect, // TODO NODE-3455: remove
51
51
  getSourceContext,
52
52
  eventFactory: { createSinkEvent },
53
53
  dataflow: {
@@ -50,7 +50,7 @@ module.exports = function (core) {
50
50
  logger,
51
51
  patcher,
52
52
  assess: {
53
- inspect, // todo: remove
53
+ inspect, // TODO NODE-3455: remove
54
54
  getSourceContext,
55
55
  eventFactory: { createSinkEvent },
56
56
  dataflow: {
@@ -82,7 +82,7 @@ module.exports = function (core) {
82
82
  logger,
83
83
  patcher,
84
84
  assess: {
85
- inspect, // todo: remove
85
+ inspect, // TODO NODE-3455: remove
86
86
  getSourceContext,
87
87
  eventFactory: { createSinkEvent },
88
88
  dataflow: {
@@ -53,7 +53,7 @@ module.exports = function(core) {
53
53
  depHooks,
54
54
  patcher,
55
55
  assess: {
56
- inspect, // todo: remove
56
+ inspect, // TODO NODE-3455: remove
57
57
  getSourceContext,
58
58
  eventFactory: { createSinkEvent },
59
59
  dataflow: {
@@ -42,7 +42,7 @@ module.exports = function(core) {
42
42
  depHooks,
43
43
  patcher,
44
44
  assess: {
45
- inspect, // todo: remove
45
+ inspect, // TODO NODE-3455: remove
46
46
  getSourceContext,
47
47
  eventFactory: { createSinkEvent },
48
48
  dataflow: {
@@ -41,7 +41,7 @@ module.exports = function (core) {
41
41
  patcher,
42
42
  config,
43
43
  assess: {
44
- inspect, // todo: remove
44
+ inspect, // TODO NODE-3455: remove
45
45
  getSourceContext,
46
46
  eventFactory: { createSinkEvent },
47
47
  dataflow: {
@@ -57,7 +57,7 @@ module.exports = function (core) {
57
57
  depHooks,
58
58
  patcher,
59
59
  assess: {
60
- inspect, // todo: remove
60
+ inspect, // TODO NODE-3455: remove
61
61
  getSourceContext,
62
62
  eventFactory: { createSinkEvent },
63
63
  dataflow: {
package/lib/sampler.js CHANGED
@@ -71,9 +71,9 @@ module.exports = function assess(core) {
71
71
  assess.sampler = SamplerFactory[strategy](opts);
72
72
  }
73
73
  } else {
74
+ if (assess.sampler) logger.info('assess sampling disabled');
74
75
  // disable sampling by setting sampler to null
75
76
  assess.sampler = null;
76
- logger.info('assess sampling disabled');
77
77
  }
78
78
  }
79
79
 
@@ -4,6 +4,7 @@ const { EventEmitter } = require('events');
4
4
  const { expect } = require('chai');
5
5
  const { Event } = require('@contrast/common');
6
6
  const mocks = require('@contrast/test/mocks');
7
+ const { devNull } = require('node:os');
7
8
 
8
9
  const TRIALS = 1000;
9
10
  const ZSCORE = 3.891; // 99.99% confidence
@@ -135,7 +136,11 @@ describe('assess sampler', function() {
135
136
 
136
137
  it('sampler behavior adjusts to series of TS updates', function() {
137
138
  // setup
139
+ const cfgPath = process.env.CONTRAST_CONFIG_PATH;
140
+ process.env.CONTRAST_CONFIG_PATH = devNull;
138
141
  const core = initMockCore();
142
+ process.env.CONTRAST_CONFIG_PATH = cfgPath;
143
+
139
144
  core.config.setValue('assess.enable', true, 'CONTRAST_UI');
140
145
  core.config.setValue('assess.probabilistic_sampling.enable', false, 'DEFAULT_VALUE');
141
146
  core.config.setValue('assess.probabilistic_sampling.base_probability', 0.50, 'CONTRAST_UI');
@@ -193,8 +198,6 @@ describe('assess sampler', function() {
193
198
 
194
199
  // test logging throughout init/updates
195
200
  expect(core.logger.info.getCalls().map(c => c.args)).to.deep.equal([
196
- // when initialized
197
- ['assess sampling disabled'],
198
201
  // update 1: env=PRODUCTION enables sampling
199
202
  [
200
203
  { strategy: 'probabilistic', opts: { base_probability: 0.5 } },
@@ -218,11 +221,11 @@ describe('assess sampler', function() {
218
221
 
219
222
  function initMockCore() {
220
223
  const { CONTRAST_CONFIG_PATH } = process.env;
224
+ process.env.CONTRAST_CONFIG_PATH = devNull;
225
+
221
226
  let core;
222
227
 
223
228
  try {
224
- // ensure default config if devs use this
225
- process.env.CONTRAST_CONFIG_PATH = '';
226
229
  core = {
227
230
  // sampler needs this namespace to exist
228
231
  assess: {},
@@ -235,12 +238,14 @@ function initMockCore() {
235
238
  require('@contrast/config')(core);
236
239
  core.config.setValue('assess.enable', true, 'CONTRAST_UI');
237
240
  } catch (err) {
241
+ process.env.CONTRAST_CONFIG_PATH = CONTRAST_CONFIG_PATH;
242
+
238
243
  console.dir(err);
239
244
  throw err;
240
245
  }
241
246
 
242
247
  // reset to orig value
243
- if (CONTRAST_CONFIG_PATH) process.env.CONTRAST_CONFIG_PATH = CONTRAST_CONFIG_PATH;
248
+ process.env.CONTRAST_CONFIG_PATH = CONTRAST_CONFIG_PATH;
244
249
 
245
250
  return core;
246
251
  }
@@ -26,7 +26,7 @@ const { patchType } = require('../common');
26
26
  module.exports = function (core) {
27
27
  const {
28
28
  assess: {
29
- inspect, // todo: remove
29
+ inspect, // TODO NODE-3455: remove
30
30
  getSourceContext,
31
31
  eventFactory: { createSessionEvent },
32
32
  sessionConfiguration: {
@@ -26,7 +26,7 @@ const { patchType } = require('../common');
26
26
  module.exports = function (core) {
27
27
  const {
28
28
  assess: {
29
- inspect, // todo: remove
29
+ inspect, // TODO NODE-3455: remove
30
30
  getSourceContext,
31
31
  eventFactory: { createSessionEvent },
32
32
  sessionConfiguration: {
@@ -19,7 +19,7 @@ const { patchType } = require('../common');
19
19
  module.exports = function (core) {
20
20
  const {
21
21
  assess: {
22
- inspect, // todo: remove
22
+ inspect, // TODO NODE-3455: remove
23
23
  eventFactory: { createSessionEvent },
24
24
  sessionConfiguration: {
25
25
  handleHttpOnly,
@@ -25,7 +25,7 @@ const { patchType } = require('../common');
25
25
  module.exports = function (core) {
26
26
  const {
27
27
  assess: {
28
- inspect, // todo: remove
28
+ inspect, // TODO NODE-3455: remove
29
29
  getSourceContext,
30
30
  eventFactory: { createSessionEvent },
31
31
  sessionConfiguration: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/assess",
3
- "version": "1.37.0",
3
+ "version": "1.38.0",
4
4
  "description": "Contrast service providing framework-agnostic Assess support",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -18,15 +18,15 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@contrast/common": "1.26.0",
21
- "@contrast/config": "1.34.0",
22
- "@contrast/core": "1.39.0",
23
- "@contrast/dep-hooks": "1.7.0",
21
+ "@contrast/config": "1.35.0",
22
+ "@contrast/core": "1.40.0",
23
+ "@contrast/dep-hooks": "1.8.0",
24
24
  "@contrast/distringuish": "^5.1.0",
25
- "@contrast/instrumentation": "1.17.0",
26
- "@contrast/logger": "1.12.0",
27
- "@contrast/patcher": "1.11.0",
28
- "@contrast/rewriter": "1.15.0",
29
- "@contrast/scopes": "1.8.0",
25
+ "@contrast/instrumentation": "1.18.0",
26
+ "@contrast/logger": "1.13.0",
27
+ "@contrast/patcher": "1.12.0",
28
+ "@contrast/rewriter": "1.16.0",
29
+ "@contrast/scopes": "1.9.0",
30
30
  "semver": "^7.6.0"
31
31
  }
32
32
  }