From baf0d3ef227a40d541219b8873c4ecf6e7c1bd83 Mon Sep 17 00:00:00 2001 From: Vasco-jofra <11303847+Vasco-jofra@users.noreply.github.com> Date: Sat, 14 Jun 2025 23:27:49 +0200 Subject: [PATCH 1/6] Model NestJS middlewares as sources --- .../lib/semmle/javascript/frameworks/Nest.qll | 55 +++++++++++++++++++ .../frameworks/Nest/local/middleware.ts | 12 ++++ .../frameworks/Nest/test.expected | 4 ++ 3 files changed, 71 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/Nest/local/middleware.ts diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll index d6bcb9ddd400..80f16e6c1cc5 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll @@ -447,6 +447,61 @@ module NestJS { } } + /** + * A NestJS Middleware Class + */ + private class NestMiddlewareClass extends DataFlow::ClassNode { + NestMiddlewareClass() { + exists(ClassDefinition cls | + this = cls.flow() and + cls.getASuperInterface().hasUnderlyingType("@nestjs/common", "NestMiddleware") + ) + } + + DataFlow::FunctionNode getUseFunction() { result = this.getInstanceMethod("use") } + } + + /** + * A NestJS Middleware Class route handler (the `use` method) + */ + private class MiddlewareRouteHandler extends Http::RouteHandler, DataFlow::FunctionNode { + MiddlewareRouteHandler() { this = any(NestMiddlewareClass m).getUseFunction() } + + override Http::HeaderDefinition getAResponseHeader(string name) { none() } + + /** + * Gets the request object used by this route + */ + DataFlow::ParameterNode getRequest() { result = this.getParameter(0) } + + /** + * Gets the response object used by this route + */ + DataFlow::ParameterNode getResponse() { result = this.getParameter(1) } + } + + /** + * A source of `express` request objects for NestJS middlewares + */ + private class MiddlewareRequestSource extends Express::RequestSource { + MiddlewareRouteHandler middlewareRouteHandler; + + MiddlewareRequestSource() { this = middlewareRouteHandler.getRequest() } + + override Http::RouteHandler getRouteHandler() { result = middlewareRouteHandler } + } + + /** + * A source of `express` response objects for NestJS middlewares + */ + private class MiddlewareResponseSource extends Express::ResponseSource { + MiddlewareRouteHandler middlewareRouteHandler; + + MiddlewareResponseSource() { this = middlewareRouteHandler.getResponse() } + + override Http::RouteHandler getRouteHandler() { result = middlewareRouteHandler } + } + /** * A value passed in the `providers` array in: * ```js diff --git a/javascript/ql/test/library-tests/frameworks/Nest/local/middleware.ts b/javascript/ql/test/library-tests/frameworks/Nest/local/middleware.ts new file mode 100644 index 000000000000..f7f7104c68cc --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Nest/local/middleware.ts @@ -0,0 +1,12 @@ +import { Injectable, NestMiddleware } from '@nestjs/common'; +import { Response, NextFunction } from 'express'; +import { CustomRequest } from '@randomPackage/request'; + +@Injectable() +export class LoggerMiddleware implements NestMiddleware { + // The request can be a custom type that extends the express Request + use(req: CustomRequest, res: Response, next: NextFunction) { + console.log(req.query.abc); + next(); + } +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Nest/test.expected b/javascript/ql/test/library-tests/frameworks/Nest/test.expected index db49fc95eba9..6a10a942e2db 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/test.expected +++ b/javascript/ql/test/library-tests/frameworks/Nest/test.expected @@ -10,6 +10,7 @@ routeHandler | local/customPipe.ts:36:5:38:5 | propaga ... K\\n } | | local/customPipe.ts:41:5:43:5 | propaga ... K\\n } | | local/customPipe.ts:47:5:49:5 | propaga ... K\\n } | +| local/middleware.ts:8:3:11:3 | use(req ... ();\\n } | | local/routes.ts:6:3:8:3 | getFoo( ... o';\\n } | | local/routes.ts:11:3:13:3 | postFoo ... o';\\n } | | local/routes.ts:16:3:18:3 | getRoot ... o';\\n } | @@ -29,9 +30,11 @@ routeHandler | local/validation.ts:42:3:45:3 | route6( ... OK\\n } | requestSource | local/customDecorator.ts:5:21:5:51 | ctx.swi ... quest() | +| local/middleware.ts:8:7:8:9 | req | | local/routes.ts:30:12:30:14 | req | | local/routes.ts:61:23:61:25 | req | responseSource +| local/middleware.ts:8:27:8:29 | res | | local/routes.ts:61:35:61:37 | res | | local/routes.ts:62:5:62:25 | res.sen ... uery.x) | requestInputAccess @@ -44,6 +47,7 @@ requestInputAccess | parameter | local/customDecorator.ts:6:12:6:41 | request ... ryParam | | parameter | local/customPipe.ts:5:15:5:19 | value | | parameter | local/customPipe.ts:13:15:13:19 | value | +| parameter | local/middleware.ts:9:17:9:29 | req.query.abc | | parameter | local/routes.ts:27:17:27:17 | x | | parameter | local/routes.ts:28:14:28:21 | queryObj | | parameter | local/routes.ts:29:20:29:23 | name | From 2b143c86acc60cf74dc78ea072aa07991cf4e0e1 Mon Sep 17 00:00:00 2001 From: Vasco-jofra <11303847+Vasco-jofra@users.noreply.github.com> Date: Sun, 15 Jun 2025 00:09:07 +0200 Subject: [PATCH 2/6] NestJS dependency Injection support useFactory provider --- .../lib/semmle/javascript/frameworks/Nest.qll | 10 +++++++++- .../frameworks/Nest/global/app.module.ts | 19 +++++++++++++------ .../frameworks/Nest/global/foo.impl.ts | 8 +++++++- .../frameworks/Nest/global/foo.interface.ts | 4 ++++ .../frameworks/Nest/global/validation.ts | 5 +++-- .../frameworks/Nest/test.expected | 2 +- 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll index 80f16e6c1cc5..35900ef765f8 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll @@ -519,12 +519,20 @@ module NestJS { .(DataFlow::ArrayCreationNode) .getAnElement() } + private DataFlow::Node getConcreteClassFromProviderTuple(DataFlow::SourceNode tuple) { + result = tuple.getAPropertyWrite("useClass").getRhs() + or + exists(DataFlow::FunctionNode f | + f = tuple.getAPropertyWrite("useFactory").getRhs().getALocalSource() and + result.getAstNode() = f.getFunction().getAReturnedExpr().getType().(ClassType).getClass() + ) + } private predicate providerPair(DataFlow::Node interface, DataFlow::Node concreteClass) { exists(DataFlow::SourceNode tuple | tuple = providerTuple().getALocalSource() and interface = tuple.getAPropertyWrite("provide").getRhs() and - concreteClass = tuple.getAPropertyWrite("useClass").getRhs() + concreteClass = getConcreteClassFromProviderTuple(tuple) ) } diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts index 2c230821a632..1523b3201364 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts @@ -1,12 +1,19 @@ import { Module } from '@nestjs/common'; import { Controller } from './validation'; -import { Foo } from './foo.interface'; -import { FooImpl } from './foo.impl'; +import { Foo, Foo2 } from './foo.interface'; +import { FooImpl, Foo2Impl } from './foo.impl'; @Module({ - controllers: [Controller], - providers: [{ - provide: Foo, useClass: FooImpl - }], + controllers: [Controller], + providers: [ + { + provide: Foo, + useClass: FooImpl + }, + { + provide: Foo2, + useFactory: () => new Foo2Impl() + } + ], }) export class AppModule { } diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts index 979389a3804c..f4f591d230d3 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts @@ -1,7 +1,13 @@ -import { Foo } from "./foo.interface"; +import { Foo , Foo2 } from "./foo.interface"; export class FooImpl extends Foo { fooMethod(x: string) { sink(x); // $ hasValueFlow=x } } + +export class Foo2Impl extends Foo2 { + fooMethod(x: string) { + sink(x); // $ hasValueFlow=x + } +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts index f22529c2d185..db4606426558 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts @@ -1,3 +1,7 @@ export abstract class Foo { abstract fooMethod(x: string): void; } + +export abstract class Foo2 { + abstract fooMethod(x: string): void; +} diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts index 1872b5a51b7d..b0470b70d1ee 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts @@ -1,10 +1,10 @@ import { Get, Query } from '@nestjs/common'; import { IsIn } from 'class-validator'; -import { Foo } from './foo.interface'; +import { Foo, Foo2 } from './foo.interface'; export class Controller { constructor( - private readonly foo: Foo + private readonly foo: Foo, private readonly foo2: Foo2 ) { } @Get() @@ -16,6 +16,7 @@ export class Controller { @Get() route2(@Query('x') x: string) { this.foo.fooMethod(x); + this.foo2.fooMethod(x); } } diff --git a/javascript/ql/test/library-tests/frameworks/Nest/test.expected b/javascript/ql/test/library-tests/frameworks/Nest/test.expected index 6a10a942e2db..53b34ecef942 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/test.expected +++ b/javascript/ql/test/library-tests/frameworks/Nest/test.expected @@ -1,7 +1,7 @@ testFailures routeHandler | global/validation.ts:11:3:14:3 | route1( ... OK\\n } | -| global/validation.ts:17:3:19:3 | route2( ... x);\\n } | +| global/validation.ts:17:3:20:3 | route2( ... x);\\n } | | local/customDecorator.ts:18:3:20:3 | sneaky( ... OK\\n } | | local/customDecorator.ts:23:3:25:3 | safe(@S ... OK\\n } | | local/customPipe.ts:20:5:22:5 | sanitiz ... K\\n } | From 477f32c7ff807bf1b01555d365d37069f7ae8cd4 Mon Sep 17 00:00:00 2001 From: Vasco-jofra <11303847+Vasco-jofra@users.noreply.github.com> Date: Sun, 15 Jun 2025 00:21:38 +0200 Subject: [PATCH 3/6] NestJS dependency injection support useValue provider --- .../ql/lib/semmle/javascript/frameworks/Nest.qll | 3 +++ .../library-tests/frameworks/Nest/global/app.module.ts | 10 ++++++++-- .../library-tests/frameworks/Nest/global/foo.impl.ts | 6 ++++++ .../frameworks/Nest/global/foo.interface.ts | 4 ++++ .../library-tests/frameworks/Nest/global/validation.ts | 5 +++-- .../test/library-tests/frameworks/Nest/test.expected | 2 +- 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll index 35900ef765f8..ff3c7920247d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll @@ -526,6 +526,9 @@ module NestJS { f = tuple.getAPropertyWrite("useFactory").getRhs().getALocalSource() and result.getAstNode() = f.getFunction().getAReturnedExpr().getType().(ClassType).getClass() ) + or + result.getAstNode() = + tuple.getAPropertyWrite("useValue").getRhs().asExpr().getType().(ClassType).getClass() } private predicate providerPair(DataFlow::Node interface, DataFlow::Node concreteClass) { diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts index 1523b3201364..39c17fcc1d2a 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts @@ -1,7 +1,9 @@ import { Module } from '@nestjs/common'; import { Controller } from './validation'; -import { Foo, Foo2 } from './foo.interface'; -import { FooImpl, Foo2Impl } from './foo.impl'; +import { Foo, Foo2, Foo3 } from './foo.interface'; +import { FooImpl, Foo2Impl, Foo3Impl } from './foo.impl'; + +const foo3 = new Foo3Impl() @Module({ controllers: [Controller], @@ -13,6 +15,10 @@ import { FooImpl, Foo2Impl } from './foo.impl'; { provide: Foo2, useFactory: () => new Foo2Impl() + }, + { + provide: Foo3, + useValue: foo3 } ], }) diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts index f4f591d230d3..ebc2fa360849 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts @@ -10,4 +10,10 @@ export class Foo2Impl extends Foo2 { fooMethod(x: string) { sink(x); // $ hasValueFlow=x } +} + +export class Foo3Impl extends Foo2 { + fooMethod(x: string) { + sink(x); // $ hasValueFlow=x + } } \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts index db4606426558..f2f48b60cd2f 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts @@ -5,3 +5,7 @@ export abstract class Foo { export abstract class Foo2 { abstract fooMethod(x: string): void; } + +export abstract class Foo3 { + abstract fooMethod(x: string): void; +} diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts index b0470b70d1ee..d9a85fdaa8cc 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts @@ -1,10 +1,10 @@ import { Get, Query } from '@nestjs/common'; import { IsIn } from 'class-validator'; -import { Foo, Foo2 } from './foo.interface'; +import { Foo, Foo2, Foo3 } from './foo.interface'; export class Controller { constructor( - private readonly foo: Foo, private readonly foo2: Foo2 + private readonly foo: Foo, private readonly foo2: Foo2, private readonly foo3: Foo3 ) { } @Get() @@ -17,6 +17,7 @@ export class Controller { route2(@Query('x') x: string) { this.foo.fooMethod(x); this.foo2.fooMethod(x); + this.foo3.fooMethod(x); } } diff --git a/javascript/ql/test/library-tests/frameworks/Nest/test.expected b/javascript/ql/test/library-tests/frameworks/Nest/test.expected index 53b34ecef942..c2e8455e03ce 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/test.expected +++ b/javascript/ql/test/library-tests/frameworks/Nest/test.expected @@ -1,7 +1,7 @@ testFailures routeHandler | global/validation.ts:11:3:14:3 | route1( ... OK\\n } | -| global/validation.ts:17:3:20:3 | route2( ... x);\\n } | +| global/validation.ts:17:3:21:3 | route2( ... x);\\n } | | local/customDecorator.ts:18:3:20:3 | sneaky( ... OK\\n } | | local/customDecorator.ts:23:3:25:3 | safe(@S ... OK\\n } | | local/customPipe.ts:20:5:22:5 | sanitiz ... K\\n } | From 9019879d9926dcfd4e241cced6cc667aad3cb2b4 Mon Sep 17 00:00:00 2001 From: Vasco-jofra <11303847+Vasco-jofra@users.noreply.github.com> Date: Sun, 15 Jun 2025 00:32:26 +0200 Subject: [PATCH 4/6] Improve useFactory inter file function detection --- javascript/ql/lib/semmle/javascript/frameworks/Nest.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll index ff3c7920247d..b6af7f37e643 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll @@ -523,10 +523,10 @@ module NestJS { result = tuple.getAPropertyWrite("useClass").getRhs() or exists(DataFlow::FunctionNode f | - f = tuple.getAPropertyWrite("useFactory").getRhs().getALocalSource() and + f = tuple.getAPropertyWrite("useFactory").getRhs().getAFunctionValue() and result.getAstNode() = f.getFunction().getAReturnedExpr().getType().(ClassType).getClass() ) - or + or result.getAstNode() = tuple.getAPropertyWrite("useValue").getRhs().asExpr().getType().(ClassType).getClass() } From 69204300734501a2566a608b2adb3f647e295c89 Mon Sep 17 00:00:00 2001 From: Vasco-jofra <11303847+Vasco-jofra@users.noreply.github.com> Date: Sun, 15 Jun 2025 00:47:34 +0200 Subject: [PATCH 5/6] Improve dependency injection through import function calls --- .../lib/semmle/javascript/frameworks/Nest.qll | 37 +++++++++++++++---- .../frameworks/Nest/global/app.module.ts | 2 + .../frameworks/Nest/global/foo.impl.ts | 10 ++++- .../frameworks/Nest/global/foo.interface.ts | 4 ++ .../frameworks/Nest/global/imports.ts | 16 ++++++++ .../frameworks/Nest/global/validation.ts | 5 ++- 6 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 javascript/ql/test/library-tests/frameworks/Nest/global/imports.ts diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll index b6af7f37e643..fcd8da5c8931 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll @@ -510,15 +510,36 @@ module NestJS { * ``` */ private DataFlow::Node providerTuple() { - result = - DataFlow::moduleImport("@nestjs/common") - .getAPropertyRead("Module") - .getACall() - .getOptionArgument(0, "providers") - .getALocalSource() - .(DataFlow::ArrayCreationNode) - .getAnElement() + exists(DataFlow::CallNode moduleCall | + moduleCall = DataFlow::moduleImport("@nestjs/common").getAPropertyRead("Module").getACall() and + result = providerTupleAux(moduleCall.getArgument(0).getALocalSource()) + ) + } + + private DataFlow::Node providerTupleAux(DataFlow::ObjectLiteralNode o) { + ( + result = + o.getAPropertyWrite("providers") + .getRhs() + .getALocalSource() + .(DataFlow::ArrayCreationNode) + .getAnElement() + or + result = + providerTupleAux(o.getAPropertyWrite("imports") + .getRhs() + .getALocalSource() + .(DataFlow::ArrayCreationNode) + .getAnElement() + .(DataFlow::CallNode) + .getCalleeNode() + .getAFunctionValue() + .getFunction() + .getAReturnedExpr() + .flow()) + ) } + private DataFlow::Node getConcreteClassFromProviderTuple(DataFlow::SourceNode tuple) { result = tuple.getAPropertyWrite("useClass").getRhs() or diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts index 39c17fcc1d2a..b8793dc57895 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/app.module.ts @@ -1,5 +1,6 @@ import { Module } from '@nestjs/common'; import { Controller } from './validation'; +import { Imports } from './imports'; import { Foo, Foo2, Foo3 } from './foo.interface'; import { FooImpl, Foo2Impl, Foo3Impl } from './foo.impl'; @@ -7,6 +8,7 @@ const foo3 = new Foo3Impl() @Module({ controllers: [Controller], + imports: [Imports.forRoot()], providers: [ { provide: Foo, diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts index ebc2fa360849..9e54bc4774e9 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.impl.ts @@ -1,4 +1,4 @@ -import { Foo , Foo2 } from "./foo.interface"; +import { Foo, Foo2, Foo3, Foo4 } from "./foo.interface"; export class FooImpl extends Foo { fooMethod(x: string) { @@ -12,7 +12,13 @@ export class Foo2Impl extends Foo2 { } } -export class Foo3Impl extends Foo2 { +export class Foo3Impl extends Foo3 { + fooMethod(x: string) { + sink(x); // $ hasValueFlow=x + } +} + +export class Foo4Impl extends Foo4 { fooMethod(x: string) { sink(x); // $ hasValueFlow=x } diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts index f2f48b60cd2f..b3d18f2749a3 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/foo.interface.ts @@ -9,3 +9,7 @@ export abstract class Foo2 { export abstract class Foo3 { abstract fooMethod(x: string): void; } + +export abstract class Foo4 { + abstract fooMethod(x: string): void; +} diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/imports.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/imports.ts new file mode 100644 index 000000000000..1df36111161c --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/imports.ts @@ -0,0 +1,16 @@ +import { DynamicModule } from '@nestjs/common'; +import { Foo4Impl } from './foo.impl'; +import { Foo4 } from './foo.interface'; + +export class Imports { + static forRoot(): DynamicModule { + return { + providers: [ + { + provide: Foo4, + useClass: Foo4Impl, + }, + ], + }; + } +} diff --git a/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts b/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts index d9a85fdaa8cc..f6046e4651a1 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts +++ b/javascript/ql/test/library-tests/frameworks/Nest/global/validation.ts @@ -1,10 +1,10 @@ import { Get, Query } from '@nestjs/common'; import { IsIn } from 'class-validator'; -import { Foo, Foo2, Foo3 } from './foo.interface'; +import { Foo, Foo2, Foo3, Foo4 } from './foo.interface'; export class Controller { constructor( - private readonly foo: Foo, private readonly foo2: Foo2, private readonly foo3: Foo3 + private readonly foo: Foo, private readonly foo2: Foo2, private readonly foo3: Foo3, private readonly foo4: Foo4 ) { } @Get() @@ -18,6 +18,7 @@ export class Controller { this.foo.fooMethod(x); this.foo2.fooMethod(x); this.foo3.fooMethod(x); + this.foo4.fooMethod(x); } } From e2eca5bbff46785737a8e1ee55c1c14d2c73c7a4 Mon Sep 17 00:00:00 2001 From: Vasco-jofra <11303847+Vasco-jofra@users.noreply.github.com> Date: Sun, 15 Jun 2025 12:12:12 +0200 Subject: [PATCH 6/6] Update test.expected --- javascript/ql/test/library-tests/frameworks/Nest/test.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/frameworks/Nest/test.expected b/javascript/ql/test/library-tests/frameworks/Nest/test.expected index c2e8455e03ce..ea74b306b366 100644 --- a/javascript/ql/test/library-tests/frameworks/Nest/test.expected +++ b/javascript/ql/test/library-tests/frameworks/Nest/test.expected @@ -1,7 +1,7 @@ testFailures routeHandler | global/validation.ts:11:3:14:3 | route1( ... OK\\n } | -| global/validation.ts:17:3:21:3 | route2( ... x);\\n } | +| global/validation.ts:17:3:22:3 | route2( ... x);\\n } | | local/customDecorator.ts:18:3:20:3 | sneaky( ... OK\\n } | | local/customDecorator.ts:23:3:25:3 | safe(@S ... OK\\n } | | local/customPipe.ts:20:5:22:5 | sanitiz ... K\\n } |