@contrast/route-coverage 1.35.1 → 1.36.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/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "@contrast/route-coverage",
3
- "version": "1.35.1",
3
+ "version": "1.36.0",
4
4
  "description": "Handles route discovery and observation",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
7
7
  "files": [
8
- "lib/"
8
+ "lib/",
9
+ "!*.test.*",
10
+ "!tsconfig.*",
11
+ "!*.map"
9
12
  ],
10
13
  "main": "lib/index.js",
11
14
  "types": "lib/index.d.ts",
@@ -17,13 +20,13 @@
17
20
  "test": "../scripts/test.sh"
18
21
  },
19
22
  "dependencies": {
20
- "@contrast/common": "1.29.1",
21
- "@contrast/config": "1.40.1",
22
- "@contrast/dep-hooks": "1.14.1",
23
+ "@contrast/common": "1.30.0",
24
+ "@contrast/config": "1.41.0",
25
+ "@contrast/dep-hooks": "1.15.0",
23
26
  "@contrast/fn-inspect": "^4.3.0",
24
- "@contrast/logger": "1.18.1",
25
- "@contrast/patcher": "1.17.1",
26
- "@contrast/scopes": "1.15.1",
27
+ "@contrast/logger": "1.19.0",
28
+ "@contrast/patcher": "1.18.0",
29
+ "@contrast/scopes": "1.16.0",
27
30
  "semver": "^7.6.0",
28
31
  "path-to-regexp": "^8.2.0"
29
32
  }
package/lib/index.test.js DELETED
@@ -1,136 +0,0 @@
1
- 'use strict';
2
-
3
- const { expect } = require('chai');
4
- const sinon = require('sinon');
5
- const proxyquire = require('proxyquire');
6
- const { Event } = require('@contrast/common');
7
- const mocks = require('@contrast/test/mocks');
8
- const { initAssessFixture } = require('@contrast/test/fixtures');
9
- const { installsComponents } = require('@contrast/test/utils');
10
-
11
- const MODULES = ['express', 'fastify', 'hapi', 'koa'];
12
-
13
- describe('route coverage', function () {
14
- let core, simulateRequestScope, routeCoverage, clock;
15
-
16
- beforeEach(function () {
17
- ({ core, simulateRequestScope } = initAssessFixture());
18
-
19
- clock = sinon.useFakeTimers();
20
- sinon.spy(core.messages, 'emit');
21
-
22
- const moduleMock = (moduleName) => (deps) => {
23
- deps.routeCoverage[moduleName] = mocks.installable();
24
- };
25
-
26
- routeCoverage = proxyquire('.', {
27
- './install/express': moduleMock('express'),
28
- './install/fastify': moduleMock('fastify'),
29
- './install/hapi': moduleMock('hapi'),
30
- './install/koa': moduleMock('koa'),
31
- });
32
- });
33
-
34
- it('installs its components', function () {
35
- routeCoverage(core).install();
36
- installsComponents(core.routeCoverage, MODULES);
37
- });
38
-
39
- it('does not install when not enabled', function () {
40
- core.config.agent.route_coverage.enable = false;
41
- routeCoverage(core);
42
- expect(core).not.to.have.property('routeCoverage');
43
- });
44
-
45
- describe('.discoveryFinished()', function () {
46
- beforeEach(function () {
47
- routeCoverage(core).install();
48
- });
49
-
50
- it('emits an event when discovery is finished', function () {
51
- const eventA = { signature: 'url.get', url: 'url', method: 'get' };
52
- const eventB = { signature: 'url.post', url: 'url', method: 'post' };
53
- core.routeCoverage.discover(eventA);
54
- core.routeCoverage.discover(eventA); // check that we dedupe discovery.
55
- core.routeCoverage.discover(eventB);
56
- core.routeCoverage.discoveryFinished();
57
-
58
- expect(core.messages.emit).to.have.been.calledWith(
59
- Event.ROUTE_COVERAGE_DISCOVERY_FINISHED,
60
- [eventA, eventB],
61
- );
62
- });
63
-
64
- it('queues new events after initial discovery is finished', function () {
65
- const eventA = { signature: 'url.get', url: 'url', method: 'get' };
66
- core.routeCoverage.discover(eventA);
67
- core.routeCoverage.discoveryFinished();
68
- expect(core.messages.emit).to.have.been.calledWith(
69
- Event.ROUTE_COVERAGE_DISCOVERY_FINISHED,
70
- [eventA],
71
- );
72
-
73
- const eventB = { signature: 'url.post', url: 'url', method: 'post' };
74
- core.routeCoverage.discover(eventA); // check that we dedupe routes discoverd on startup
75
- core.routeCoverage.discover(eventB);
76
- core.routeCoverage.discover(eventB); // check that we dedupe routes defined lazily
77
- clock.tick(10000); //queuingFinished
78
-
79
- expect(core.messages.emit).to.have.been.calledWith(
80
- Event.ROUTE_COVERAGE_DISCOVERY_FINISHED,
81
- [eventB],
82
- );
83
- });
84
- });
85
-
86
- describe('.observe()', function () {
87
- beforeEach(function () {
88
- routeCoverage(core).install();
89
- });
90
-
91
- it('logs debug messages when a route is missing on observation', function () {
92
- const info = { url: 'url', method: 'get' };
93
- core.routeCoverage.observe(info);
94
- expect(core.logger.debug).to.have.been.calledOnceWithExactly(
95
- info,
96
- 'unable to observe undiscovered route',
97
- );
98
- });
99
-
100
- it('emits an event on route observation', function () {
101
- const event = {
102
- signature: 'hello',
103
- url: 'url',
104
- method: 'get',
105
- sourceInfo: undefined
106
- };
107
- core.routeCoverage.discover(event);
108
- core.routeCoverage.observe(event);
109
-
110
- expect(core.messages.emit).to.have.been.calledWith(
111
- Event.ROUTE_COVERAGE_OBSERVATION,
112
- event,
113
- );
114
- });
115
-
116
- it('emits an event on route observation and appends sourceInfo when in request scope', function () {
117
- const event = {
118
- signature: 'hello',
119
- url: 'url',
120
- method: 'get',
121
- };
122
- core.routeCoverage.discover(event);
123
-
124
- simulateRequestScope(() => {
125
- core.routeCoverage.observe(event);
126
- const { sourceInfo, route } = core.scopes.sources.getStore();
127
- expect(sourceInfo).to.be.ok;
128
- expect(route).to.eql({ method: 'get', signature: 'hello', url: 'url' });
129
- expect(core.messages.emit).to.have.been.calledWith(
130
- Event.ROUTE_COVERAGE_OBSERVATION,
131
- sinon.match({ ...event, sourceInfo })
132
- );
133
- });
134
- });
135
- });
136
- });
@@ -1,418 +0,0 @@
1
- 'use strict';
2
-
3
- const { expect } = require('chai');
4
- const sinon = require('sinon');
5
- const scopes = require('@contrast/scopes');
6
- const patcher = require('@contrast/patcher');
7
- const mocks = require('@contrast/test/mocks');
8
-
9
- const METHODS = [
10
- 'all',
11
- 'get',
12
- 'post',
13
- 'put',
14
- 'delete',
15
- 'patch',
16
- 'options',
17
- 'head',
18
- ];
19
-
20
- describe('route-coverage express', function () {
21
- let core, http, Server, application, Router, Layer, express, fn, framework;
22
-
23
- beforeEach(function () {
24
- core = mocks.core();
25
- core.logger = mocks.logger();
26
- core.routeCoverage = mocks.routeCoverage();
27
- core.scopes = scopes(core);
28
- core.depHooks = mocks.depHooks();
29
- core.patcher = patcher(core);
30
-
31
- application = () => application;
32
- Router = () => Router;
33
- Layer = () => Layer;
34
- Layer.handle = sinon.stub();
35
-
36
- express = () => application;
37
- framework = 'express';
38
-
39
- Router.stack = [];
40
- Router.handle = sinon.stub();
41
- Router.use = (prefix, router) => {
42
- Router.stack.push({ handle: router, name: 'router', regexp: { source: `\\${prefix}` } });
43
- };
44
-
45
- express.application = application;
46
- express.application.use = (prefix, router) => {
47
- if (router?.use) router.use(prefix, router);
48
- return { _router: Router };
49
- };
50
- express.application._router = Router;
51
- express.Router = Router;
52
-
53
- METHODS.forEach((method) => {
54
- application[method] = () => {
55
- Router.stack.push(Layer);
56
- return { _router: Router };
57
- };
58
- Router[method] = (path, fn) => {
59
- Layer.regexp = { source: `\\${path}` };
60
- Layer.route = {
61
- path,
62
- stack: [
63
- {
64
- method
65
- }
66
- ],
67
- methods: {
68
- _all: false
69
- }
70
- };
71
- if (fn) Router.stack.push(Layer);
72
- return Router;
73
- };
74
- });
75
- Server = function () { };
76
- Server.prototype.listen = sinon.stub();
77
- http = {
78
- Server,
79
- createServer() {
80
- return new Server();
81
- }
82
- };
83
-
84
- fn = sinon.stub();
85
-
86
- core.depHooks.resolve.withArgs({ name: 'express', version: '>=4 <5' }).yields(express);
87
- core.depHooks.resolve.withArgs({ name: 'http' }).yields(http);
88
-
89
- require('./express4')(core).install();
90
- });
91
-
92
- describe('app', function () {
93
- METHODS.forEach((method) => {
94
- describe(`${method}`, function () {
95
- it('does not report a non-existent route', function () {
96
- const app = express();
97
- app[method]();
98
- expect(core.routeCoverage.discover).not.to.have.been.called;
99
- });
100
-
101
- it('does not report an invalid route', function () {
102
- const app = express();
103
- app[method](42);
104
- expect(core.routeCoverage.discover).not.to.have.been.called;
105
- });
106
-
107
- it('does not report a route missing a method', function () {
108
- const app = express();
109
- app[method]('/test/route');
110
- expect(core.routeCoverage.discover).not.to.have.been.called;
111
- });
112
-
113
- it('discovers a route', function () {
114
- const app = express();
115
- app[method]('/test/route', fn);
116
-
117
- expect(core.routeCoverage.discover).to.have.been.calledWith({
118
- signature: `App.${method}('/test/route', [Function])`,
119
- url: '/test/route',
120
- normalizedUrl: '/test/route',
121
- method,
122
- framework
123
- });
124
- });
125
-
126
- it('discovers an array route', function () {
127
- const app = express();
128
- app[method](['/test/foo', '/test/bar'], fn);
129
-
130
- expect(core.routeCoverage.discover).to.have.been.calledWith({
131
- signature: `App.${method}('/[/test/foo,/test/bar]', [Function])`,
132
- url: '/[/test/foo,/test/bar]',
133
- normalizedUrl: '/[/test/foo,/test/bar]',
134
- method,
135
- framework
136
- });
137
- });
138
-
139
- it('discovers a regEx route', function () {
140
- const app = express();
141
- app[method](/f*o/, fn);
142
-
143
- expect(core.routeCoverage.discover).to.have.been.calledWith({
144
- signature: `App.${method}('/{f*o}', [Function])`,
145
- url: '/{f*o}',
146
- normalizedUrl: '/{f*o}',
147
- method,
148
- framework
149
- });
150
- });
151
- });
152
- });
153
-
154
- it('does not discover and App.use route with no path and no router', function () {
155
- const app = express();
156
- app.use(fn);
157
- expect(core.routeCoverage.discover).not.have.been.called;
158
- });
159
-
160
- it('discovers an App.use route', function () {
161
- const app = express();
162
- app.use('/foo', fn);
163
-
164
- expect(core.routeCoverage.discover).to.have.been.calledWith({
165
- signature: 'App.use(\'/foo\', [Function])',
166
- url: '/foo',
167
- normalizedUrl: '/foo',
168
- method: 'use',
169
- framework
170
- });
171
- });
172
-
173
- it('discovers an App.use route with a non-string url', function () {
174
- const app = express();
175
- app.use(['/foo'], fn);
176
-
177
- expect(core.routeCoverage.discover).to.have.been.calledWith({
178
- signature: 'App.use(\'/[/foo]\', [Function])',
179
- url: '/[/foo]',
180
- normalizedUrl: '/[/foo]',
181
- method: 'use',
182
- framework
183
- });
184
- });
185
-
186
- it('discovers a route with middleware defined in an array', function() {
187
- const app = express();
188
- app.use('/foo', [fn]);
189
-
190
- expect(core.routeCoverage.discover).to.have.been.calledWith({
191
- signature: 'App.use(\'/foo\', [Function])',
192
- url: '/foo',
193
- normalizedUrl: '/foo',
194
- method: 'use',
195
- framework
196
- });
197
- });
198
-
199
- it('does not observe a route with an undefined method', function () {
200
- const app = express();
201
- app.get('/path/to/foo', fn);
202
-
203
- express.Router.handle({
204
- originalUrl: '/path/to/foo',
205
- route: { path: '/path/to/foo' }
206
- });
207
- expect(core.routeCoverage.observe).to.not.have.been.called;
208
- });
209
-
210
- it('observes a route when a route handler is exercised', function () {
211
- const app = express();
212
- app.get('/path/to/foo', fn);
213
-
214
- express.Router.stack[0].handle({
215
- method: 'GET',
216
- originalUrl: '/path/to/foo',
217
- route: { path: '/path/to/foo' }
218
- });
219
- expect(core.routeCoverage.observe).to.have.been.calledWith({
220
- signature: "App.get('/path/to/foo', [Function])",
221
- url: '/path/to/foo',
222
- normalizedUrl: '/path/to/foo',
223
- method: 'get',
224
- framework
225
- });
226
- });
227
-
228
- it('observes a route with a regExp path', function () {
229
- const app = express();
230
- app.get(/.*/, fn);
231
-
232
- express.Router.stack[0].handle({
233
- method: 'GET',
234
- originalUrl: '/path',
235
- route: { path: /.*/ }
236
- });
237
- expect(core.routeCoverage.observe).to.have.been.calledWith({
238
- signature: "App.get('/{.*}', [Function])",
239
- url: '/path',
240
- normalizedUrl: '/{.*}',
241
- method: 'get',
242
- framework
243
- });
244
- });
245
-
246
- it('observes a route with an Array path', function () {
247
- const app = express();
248
- app.get(['/test/foo', '/test/bar'], fn);
249
-
250
- express.Router.stack[0].handle({
251
- method: 'GET',
252
- originalUrl: '/[/test/foo,/test/bar]',
253
- route: { path: ['/test/foo', '/test/bar'] }
254
- });
255
- expect(core.routeCoverage.observe).to.have.been.calledWith({
256
- signature: "App.get('/[/test/foo,/test/bar]', [Function])",
257
- url: '/[/test/foo,/test/bar]',
258
- normalizedUrl: '/[/test/foo,/test/bar]',
259
- method: 'get',
260
- framework
261
- });
262
- });
263
-
264
- it('updates route prefixes', function () {
265
- const app = express();
266
- const router = express.Router();
267
- router.get('/foo', fn);
268
- app.use('/prefix', router);
269
- expect(core.routeCoverage.discover).to.have.been.calledWith({
270
- signature: "Router.get('/prefix/foo', [Function])",
271
- url: '/prefix/foo',
272
- normalizedUrl: '/prefix/foo',
273
- method: 'get',
274
- framework
275
- });
276
- });
277
- });
278
-
279
- describe('router', function () {
280
- METHODS.forEach((method) => {
281
- describe(`${method}`, function () {
282
- it('does not report a non-existent route', function () {
283
- const app = express();
284
- const router = express.Router();
285
- router[method]();
286
- app.use(router);
287
- expect(core.routeCoverage.discover).not.to.have.been.called;
288
- });
289
-
290
- it('does not report an invalid route', function () {
291
- const app = express();
292
- const router = express.Router();
293
- router[method](42);
294
- app.use(router);
295
- expect(core.routeCoverage.discover).not.to.have.been.called;
296
- });
297
-
298
- it('does not report a route missing a handler', function () {
299
- const app = express();
300
- const router = express.Router();
301
- router[method]('/test/route');
302
- app.use(router);
303
- expect(core.routeCoverage.discover).not.to.have.been.called;
304
- });
305
-
306
- it('discovers a route', function () {
307
- const app = express();
308
- const router = express.Router();
309
- router[method]('/test/route', fn);
310
- app.use(router);
311
-
312
- expect(core.routeCoverage.discover).to.have.been.calledWith({
313
- signature: `Router.${method}('/test/route', [Function])`,
314
- url: '/test/route',
315
- normalizedUrl: '/test/route',
316
- method,
317
- framework
318
- });
319
- });
320
-
321
- it('discovers an array route', function () {
322
- const app = express();
323
- const router = express.Router();
324
- router[method](['/test/foo', '/test/bar'], fn);
325
- app.use(router);
326
-
327
- expect(core.routeCoverage.discover).to.have.been.calledWith({
328
- signature: `Router.${method}('/[/test/foo,/test/bar]', [Function])`,
329
- url: '/[/test/foo,/test/bar]',
330
- normalizedUrl: '/[/test/foo,/test/bar]',
331
- method,
332
- framework
333
- });
334
- });
335
-
336
- it('discovers a regEx route', function () {
337
- const app = express();
338
- const router = express.Router();
339
- router[method](/f*o/, fn);
340
- app.use(router);
341
-
342
- expect(core.routeCoverage.discover).to.have.been.calledWith({
343
- signature: `Router.${method}('/{f*o}', [Function])`,
344
- url: '/{f*o}',
345
- normalizedUrl: '/{f*o}',
346
- method,
347
- framework
348
- });
349
- });
350
- });
351
- });
352
-
353
- it('does not observe a route with an undefined method', function () {
354
- const app = express();
355
- const router = express.Router();
356
- router.get('/path/to/foo', fn);
357
- app.use(router);
358
-
359
- express.Router.handle({
360
- originalUrl: '/path/to/foo',
361
- route: { path: '/path/to/foo' }
362
- });
363
- expect(core.routeCoverage.observe).to.not.have.been.called;
364
- });
365
-
366
- it('observes a route when a route handler is exercised', function () {
367
- const app = express();
368
- const router = express.Router();
369
- router.get('/path/to/foo', fn);
370
- app.use(router);
371
-
372
- express.Router.stack[0].handle({
373
- method: 'GET',
374
- originalUrl: '/path/to/foo',
375
- route: { path: '/path/to/foo' }
376
- });
377
- expect(core.routeCoverage.observe).to.have.been.calledWith({
378
- signature: "Router.get('/path/to/foo', [Function])",
379
- url: '/path/to/foo',
380
- normalizedUrl: '/path/to/foo',
381
- method: 'get',
382
- framework
383
- });
384
- });
385
-
386
- it('updates route prefixes on nested router', function () {
387
- const app = express();
388
- const router = express.Router();
389
- router.get('/foo', fn);
390
- router.use('/prefix', router);
391
- app.use(router);
392
- expect(core.routeCoverage.discover).to.have.been.calledWith({
393
- signature: "Router.get('/prefix/foo', [Function])",
394
- url: '/prefix/foo',
395
- normalizedUrl: '/prefix/foo',
396
- method: 'get',
397
- framework
398
- });
399
- });
400
-
401
- it('updates route prefixes on a non-nested router', function () {
402
- const app = express();
403
- const router = express.Router();
404
- const router2 = express.Router();
405
- router.get('/foo', fn);
406
- router2.use('/prefix', router);
407
- app.use(router);
408
- expect(core.routeCoverage.discover).to.have.been.calledWith({
409
- signature: "Router.get('/prefix/foo', [Function])",
410
- url: '/prefix/foo',
411
- normalizedUrl: '/prefix/foo',
412
- method: 'get',
413
- framework
414
- });
415
- });
416
-
417
- });
418
- });