@stratum-hq/nestjs 0.3.1 → 1.1.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.
@@ -6,7 +6,7 @@
6
6
  * ```ts
7
7
  * @Get('me')
8
8
  * @UseGuards(StratumGuard)
9
- * getProfile(@Tenant() tenant: TenantContextLegacy) {
9
+ * getProfile(@Tenant() tenant: ResolvedTenantContext) {
10
10
  * return tenant;
11
11
  * }
12
12
  * ```
@@ -7,7 +7,7 @@ import { createParamDecorator } from "@nestjs/common";
7
7
  * ```ts
8
8
  * @Get('me')
9
9
  * @UseGuards(StratumGuard)
10
- * getProfile(@Tenant() tenant: TenantContextLegacy) {
10
+ * getProfile(@Tenant() tenant: ResolvedTenantContext) {
11
11
  * return tenant;
12
12
  * }
13
13
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"stratum.guard.d.ts","sourceRoot":"","sources":["../src/stratum.guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEhE,qBACa,YAAa,YAAW,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADR,MAAM,EAAE,aAAa,EACpB,OAAO,EAAE,oBAAoB;IAGnE,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CAsF/D"}
1
+ {"version":3,"file":"stratum.guard.d.ts","sourceRoot":"","sources":["../src/stratum.guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEhE,qBACa,YAAa,YAAW,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADR,MAAM,EAAE,aAAa,EACpB,OAAO,EAAE,oBAAoB;IAKnE,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;CAyE/D"}
@@ -11,7 +11,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { Inject, Injectable, UnauthorizedException, ForbiddenException } from "@nestjs/common";
14
- import { resolveFromHeader, resolveFromJwt } from "@stratum-hq/sdk";
14
+ import { assertJwtSupport, resolveTenantId } from "@stratum-hq/sdk";
15
15
  import { TenantNotFoundError } from "@stratum-hq/core";
16
16
  import { STRATUM_CLIENT, STRATUM_OPTIONS } from "./constants.js";
17
17
  let StratumGuard = class StratumGuard {
@@ -20,33 +20,22 @@ let StratumGuard = class StratumGuard {
20
20
  constructor(client, options) {
21
21
  this.client = client;
22
22
  this.options = options;
23
+ assertJwtSupport(options);
23
24
  }
24
25
  async canActivate(context) {
25
26
  const req = context.switchToHttp().getRequest();
26
27
  // 1. Resolve tenant ID: JWT (verified) → header → custom resolvers.
27
- // The verified JWT is authoritative; the header is only a fallback when
28
- // no JWT tenant is present, so it can never override a verified identity.
28
+ // When JWT verification is configured, a token that fails verification
29
+ // is rejected, and the header is only read if trustTenantHeader is set.
29
30
  // Order mirrors express.ts.
30
- let tenantId = null;
31
- tenantId = resolveFromJwt(req, this.options.jwtClaimPath, {
32
- secret: this.options.jwtSecret,
33
- verify: this.options.jwtVerify,
34
- });
35
- if (!tenantId) {
36
- tenantId = resolveFromHeader(req);
31
+ const resolution = await resolveTenantId(req, this.options);
32
+ if (resolution.status === "invalid_token") {
33
+ throw new UnauthorizedException("Bearer token could not be verified");
37
34
  }
38
- if (!tenantId && this.options.resolvers) {
39
- for (const resolver of this.options.resolvers) {
40
- const result = await resolver.resolve(req);
41
- if (result) {
42
- tenantId = result;
43
- break;
44
- }
45
- }
46
- }
47
- if (!tenantId) {
35
+ if (resolution.status === "missing") {
48
36
  throw new UnauthorizedException("Tenant ID could not be resolved from request");
49
37
  }
38
+ const tenantId = resolution.tenantId;
50
39
  // 2. Resolve caller tenant context
51
40
  let callerContext;
52
41
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"stratum.guard.js","sourceRoot":"","sources":["../src/stratum.guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stratum.guard.js","sourceRoot":"","sources":["../src/stratum.guard.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { NestInterceptor, ExecutionContext, CallHandler } from "@nestjs/common";
2
2
  import { Observable } from "rxjs";
3
3
  export declare class StratumContextInterceptor implements NestInterceptor {
4
- intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
4
+ intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
5
5
  }
6
6
  //# sourceMappingURL=stratum.interceptor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stratum.interceptor.d.ts","sourceRoot":"","sources":["../src/stratum.interceptor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAGlC,qBACa,yBAA0B,YAAW,eAAe;IAC/D,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG,CAAC;CAUzE"}
1
+ {"version":3,"file":"stratum.interceptor.d.ts","sourceRoot":"","sources":["../src/stratum.interceptor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrF,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAGlC,qBACa,yBAA0B,YAAW,eAAe;IAC/D,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC;CAU7E"}
@@ -9,6 +9,14 @@ export interface StratumModuleOptions {
9
9
  jwtSecret?: string;
10
10
  /** Custom JWT verify function — takes priority over jwtSecret. */
11
11
  jwtVerify?: (token: string) => Record<string, unknown> | null;
12
+ /** Header to read the tenant ID from. When set, only this header is read (default: X-Tenant-ID). */
13
+ headerName?: string;
14
+ /**
15
+ * When jwtSecret or jwtVerify is configured, the tenant header is ignored
16
+ * unless this is true. A bearer token that fails verification is always
17
+ * rejected. Default: false.
18
+ */
19
+ trustTenantHeader?: boolean;
12
20
  /** Custom tenant resolvers evaluated after header and JWT resolution. */
13
21
  resolvers?: import("@stratum-hq/sdk").TenantResolver[];
14
22
  /** Enable tenant impersonation via X-Impersonate-Tenant header. */
@@ -1 +1 @@
1
- {"version":3,"file":"stratum.module.d.ts","sourceRoot":"","sources":["../src/stratum.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAOtE,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,uHAAuH;IACvH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC9D,yEAAyE;IACzE,SAAS,CAAC,EAAE,OAAO,iBAAiB,EAAE,cAAc,EAAE,CAAC;IACvD,mEAAmE;IACnE,aAAa,CAAC,EAAE;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QACxG,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;KACxF,CAAC;CACH;AAED,MAAM,WAAW,yBAA0B,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC;IAChF,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACzF,MAAM,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;CACpC;AAED,qBAEa,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa;IAqB5D;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,yBAAyB,GAAG,aAAa;CA0B5E"}
1
+ {"version":3,"file":"stratum.module.d.ts","sourceRoot":"","sources":["../src/stratum.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAOtE,MAAM,WAAW,oBAAoB;IACnC,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,uHAAuH;IACvH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC9D,oGAAoG;IACpG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,yEAAyE;IACzE,SAAS,CAAC,EAAE,OAAO,iBAAiB,EAAE,cAAc,EAAE,CAAC;IACvD,mEAAmE;IACnE,aAAa,CAAC,EAAE;QACd,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QACxG,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;KACxF,CAAC;CACH;AAED,MAAM,WAAW,yBAA0B,SAAQ,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC;IAChF,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACzF,MAAM,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC;CACpC;AAED,qBAEa,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa;IAqB5D;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,yBAAyB,GAAG,aAAa;CA0B5E"}
@@ -1 +1 @@
1
- {"version":3,"file":"stratum.module.js","sourceRoot":"","sources":["../src/stratum.module.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AA6B9D,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,OAA6B;QAC1C,MAAM,cAAc,GAAG;YACrB,OAAO,EAAE,cAAc;YACvB,QAAQ,EAAE,IAAI,aAAa,CAAC;gBAC1B,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC;SACH,CAAC;QAEF,MAAM,eAAe,GAAG;YACtB,OAAO,EAAE,eAAe;YACxB,QAAQ,EAAE,OAAO;SAClB,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE,CAAC,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,yBAAyB,EAAE,CAAC;YAC7H,OAAO,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;SACxC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,YAAuC;QACzD,MAAM,eAAe,GAAoB;YACvC,OAAO,EAAE,eAAe;YACxB,UAAU,EAAE,YAAY,CAAC,UAAU;YACnC,MAAM,EAAE,YAAY,CAAC,MAAM,IAAI,EAAE;SAClC,CAAC;QAEF,MAAM,cAAc,GAAoB;YACtC,OAAO,EAAE,cAAc;YACvB,UAAU,EAAE,KAAK,EAAE,GAAG,IAAe,EAAE,EAAE;gBACvC,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBACvD,OAAO,IAAI,aAAa,CAAC;oBACvB,eAAe,EAAE,OAAO,CAAC,eAAe;oBACxC,MAAM,EAAE,OAAO,CAAC,MAAM;iBACvB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,EAAE,YAAY,CAAC,MAAM,IAAI,EAAE;SAClC,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,OAAO,EAAE,YAAY,CAAC,OAAO,IAAI,EAAE;YACnC,SAAS,EAAE,CAAC,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,yBAAyB,EAAE,CAAC;YAC7H,OAAO,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;SACxC,CAAC;IACJ,CAAC;CACF,CAAA;AAvDY,aAAa;IAFzB,MAAM,EAAE;IACR,MAAM,CAAC,EAAE,CAAC;GACE,aAAa,CAuDzB"}
1
+ {"version":3,"file":"stratum.module.js","sourceRoot":"","sources":["../src/stratum.module.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAqC9D,IAAM,aAAa,qBAAnB,MAAM,aAAa;IACxB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,OAA6B;QAC1C,MAAM,cAAc,GAAG;YACrB,OAAO,EAAE,cAAc;YACvB,QAAQ,EAAE,IAAI,aAAa,CAAC;gBAC1B,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC;SACH,CAAC;QAEF,MAAM,eAAe,GAAG;YACtB,OAAO,EAAE,eAAe;YACxB,QAAQ,EAAE,OAAO;SAClB,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,SAAS,EAAE,CAAC,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,yBAAyB,EAAE,CAAC;YAC7H,OAAO,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;SACxC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,YAAuC;QACzD,MAAM,eAAe,GAAoB;YACvC,OAAO,EAAE,eAAe;YACxB,UAAU,EAAE,YAAY,CAAC,UAAU;YACnC,MAAM,EAAE,YAAY,CAAC,MAAM,IAAI,EAAE;SAClC,CAAC;QAEF,MAAM,cAAc,GAAoB;YACtC,OAAO,EAAE,cAAc;YACvB,UAAU,EAAE,KAAK,EAAE,GAAG,IAAe,EAAE,EAAE;gBACvC,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBACvD,OAAO,IAAI,aAAa,CAAC;oBACvB,eAAe,EAAE,OAAO,CAAC,eAAe;oBACxC,MAAM,EAAE,OAAO,CAAC,MAAM;iBACvB,CAAC,CAAC;YACL,CAAC;YACD,MAAM,EAAE,YAAY,CAAC,MAAM,IAAI,EAAE;SAClC,CAAC;QAEF,OAAO;YACL,MAAM,EAAE,eAAa;YACrB,OAAO,EAAE,YAAY,CAAC,OAAO,IAAI,EAAE;YACnC,SAAS,EAAE,CAAC,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,yBAAyB,EAAE,CAAC;YAC7H,OAAO,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;SACxC,CAAC;IACJ,CAAC;CACF,CAAA;AAvDY,aAAa;IAFzB,MAAM,EAAE;IACR,MAAM,CAAC,EAAE,CAAC;GACE,aAAa,CAuDzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratum-hq/nestjs",
3
- "version": "0.3.1",
3
+ "version": "1.1.0",
4
4
  "description": "Stratum NestJS integration — StratumGuard, @Tenant() decorator, and StratumModule",
5
5
  "keywords": [
6
6
  "multi-tenancy",
@@ -43,19 +43,26 @@
43
43
  "peerDependencies": {
44
44
  "@nestjs/common": ">=10.0.0",
45
45
  "@nestjs/core": ">=10.0.0",
46
- "@stratum-hq/core": ">=0.3.0",
47
- "@stratum-hq/sdk": ">=0.3.0",
46
+ "@stratum-hq/core": ">=1.0.0",
47
+ "@stratum-hq/sdk": ">=1.1.0",
48
48
  "reflect-metadata": ">=0.1.13"
49
49
  },
50
50
  "devDependencies": {
51
- "@nestjs/common": "^10.0.0",
52
- "@nestjs/core": "^10.0.0",
53
- "@nestjs/testing": "^10.0.0",
51
+ "@nestjs/common": "^12.1.2",
52
+ "@nestjs/core": "^12.1.2",
53
+ "@nestjs/testing": "^12.1.2",
54
54
  "@stratum-hq/core": "*",
55
55
  "@stratum-hq/sdk": "*",
56
- "reflect-metadata": "^0.1.13",
56
+ "reflect-metadata": "^0.2.2",
57
57
  "typescript": "^5.4.0",
58
- "vitest": "^1.6.0"
58
+ "vitest": "^4.1.11"
59
+ },
60
+ "license": "MIT",
61
+ "author": "Christian Crank",
62
+ "homepage": "https://github.com/stratum-hq/Stratum/tree/main/packages/nestjs#readme",
63
+ "bugs": "https://github.com/stratum-hq/Stratum/issues",
64
+ "engines": {
65
+ "node": ">=20.0.0"
59
66
  },
60
67
  "repository": {
61
68
  "type": "git",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=stratum.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stratum.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/stratum.test.ts"],"names":[],"mappings":""}
@@ -1,341 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
- import { resolveFromHeader, resolveFromJwt } from "@stratum-hq/sdk";
3
- import { StratumGuard } from "../stratum.guard.js";
4
- // ── Mock StratumClient ───────────────────────────────────────────────────────
5
- function makeMockClient(resolvedContext = null, shouldThrow) {
6
- return {
7
- resolveTenant: vi.fn(async (_tenantId) => {
8
- if (shouldThrow)
9
- throw shouldThrow;
10
- if (!resolvedContext)
11
- throw new Error("No context configured");
12
- return resolvedContext;
13
- }),
14
- };
15
- }
16
- // ── makeContext helper ───────────────────────────────────────────────────────
17
- function makeExecutionContext(req) {
18
- return {
19
- switchToHttp: () => ({
20
- getRequest: () => req,
21
- getResponse: () => ({}),
22
- getNext: () => ({}),
23
- }),
24
- };
25
- }
26
- // ── Stubs for NestJS exceptions ──────────────────────────────────────────────
27
- import { TenantNotFoundError } from "@stratum-hq/core";
28
- class UnauthorizedException extends Error {
29
- constructor(message) {
30
- super(message);
31
- this.name = "UnauthorizedException";
32
- }
33
- }
34
- class ForbiddenException extends Error {
35
- constructor(message) {
36
- super(message);
37
- this.name = "ForbiddenException";
38
- }
39
- }
40
- // ── Guard logic (mirrors stratum.guard.ts) ───────────────────────────────────
41
- async function canActivate(client, context, options = {}) {
42
- const req = context.switchToHttp().getRequest();
43
- // 1. Resolve tenant ID: JWT (verified) → header → custom resolvers
44
- let tenantId = null;
45
- tenantId = resolveFromJwt(req, options.jwtClaimPath, {
46
- secret: options.jwtSecret,
47
- verify: options.jwtVerify,
48
- });
49
- if (!tenantId) {
50
- tenantId = resolveFromHeader(req);
51
- }
52
- if (!tenantId && options.resolvers) {
53
- for (const resolver of options.resolvers) {
54
- const result = await resolver.resolve(req);
55
- if (result) {
56
- tenantId = result;
57
- break;
58
- }
59
- }
60
- }
61
- if (!tenantId) {
62
- throw new UnauthorizedException("Tenant ID could not be resolved from request");
63
- }
64
- // 2. Resolve caller tenant context
65
- let callerContext;
66
- try {
67
- callerContext = await client.resolveTenant(tenantId);
68
- }
69
- catch (err) {
70
- if (err instanceof TenantNotFoundError) {
71
- throw new UnauthorizedException(`Tenant not found: ${tenantId}`);
72
- }
73
- throw err;
74
- }
75
- req["tenant"] = callerContext;
76
- req["impersonating"] = false;
77
- // 3. Impersonation
78
- if (options.impersonation?.enabled) {
79
- const impersonateHeader = options.impersonation.headerName ?? "X-Impersonate-Tenant";
80
- const headers = req.headers;
81
- const rawVal = headers?.[impersonateHeader.toLowerCase()];
82
- const impersonateTenantId = Array.isArray(rawVal) ? rawVal[0] : rawVal;
83
- if (impersonateTenantId && impersonateTenantId !== tenantId) {
84
- const authorized = await options.impersonation.authorize(req, tenantId, impersonateTenantId);
85
- if (!authorized) {
86
- throw new ForbiddenException("Not authorized to impersonate this tenant");
87
- }
88
- let impersonatedContext;
89
- try {
90
- impersonatedContext = await client.resolveTenant(impersonateTenantId);
91
- }
92
- catch (err) {
93
- if (err instanceof TenantNotFoundError) {
94
- throw new UnauthorizedException(`Impersonated tenant not found: ${impersonateTenantId}`);
95
- }
96
- throw err;
97
- }
98
- req["tenant"] = impersonatedContext;
99
- req["impersonating"] = true;
100
- req["originalTenantId"] = tenantId;
101
- options.impersonation.onImpersonate?.(req, tenantId, impersonateTenantId);
102
- return true;
103
- }
104
- }
105
- return true;
106
- }
107
- // ── @Tenant() decorator extraction logic ─────────────────────────────────────
108
- function extractTenant(req) {
109
- return req["tenant"];
110
- }
111
- // ── Tests ─────────────────────────────────────────────────────────────────────
112
- const MOCK_CONTEXT = {
113
- id: "tenant-123",
114
- slug: "acme",
115
- name: "Acme Corp",
116
- };
117
- const MOCK_CONTEXT_B = {
118
- id: "tenant-456",
119
- slug: "other",
120
- name: "Other Corp",
121
- };
122
- describe("StratumGuard", () => {
123
- let client;
124
- beforeEach(() => {
125
- client = makeMockClient(MOCK_CONTEXT);
126
- });
127
- describe("canActivate — x-tenant-id header", () => {
128
- it("returns true and sets req.tenant when x-tenant-id header is present", async () => {
129
- const req = {
130
- headers: { "x-tenant-id": "tenant-123" },
131
- };
132
- const ctx = makeExecutionContext(req);
133
- const result = await canActivate(client, ctx);
134
- expect(result).toBe(true);
135
- expect(req["tenant"]).toEqual(MOCK_CONTEXT);
136
- expect(client.resolveTenant).toHaveBeenCalledWith("tenant-123");
137
- });
138
- });
139
- describe("canActivate — JWT (unverified tokens rejected)", () => {
140
- function makeJwt(payload) {
141
- const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
142
- const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
143
- return `${header}.${body}.fakesig`;
144
- }
145
- it("does NOT trust JWT claims when no jwtSecret or jwtVerify is configured", async () => {
146
- // Without a secret, the guard must not extract tenant from JWT
147
- const token = makeJwt({ tenant_id: "forged-tenant" });
148
- const req = {
149
- headers: { authorization: `Bearer ${token}` },
150
- };
151
- const ctx = makeExecutionContext(req);
152
- // No options — should reject because JWT is unverified
153
- await expect(canActivate(client, ctx, {})).rejects.toThrow(UnauthorizedException);
154
- await expect(canActivate(client, ctx, {})).rejects.toThrow("Tenant ID could not be resolved from request");
155
- expect(client.resolveTenant).not.toHaveBeenCalled();
156
- });
157
- it("resolves tenant from JWT when jwtVerify is provided", async () => {
158
- const token = makeJwt({ tenant_id: "tenant-from-jwt" });
159
- const req = {
160
- headers: { authorization: `Bearer ${token}` },
161
- };
162
- const ctx = makeExecutionContext(req);
163
- // Supply a verify function that trusts this token
164
- const jwtVerify = (_t) => ({ tenant_id: "tenant-from-jwt" });
165
- const result = await canActivate(client, ctx, { jwtVerify });
166
- expect(result).toBe(true);
167
- expect(client.resolveTenant).toHaveBeenCalledWith("tenant-from-jwt");
168
- });
169
- it("prefers the verified JWT claim over the x-tenant-id header", async () => {
170
- const token = makeJwt({ tenant_id: "jwt-tenant" });
171
- const req = {
172
- headers: {
173
- "x-tenant-id": "header-tenant",
174
- authorization: `Bearer ${token}`,
175
- },
176
- };
177
- const ctx = makeExecutionContext(req);
178
- await canActivate(client, ctx, { jwtVerify: () => ({ tenant_id: "jwt-tenant" }) });
179
- expect(client.resolveTenant).toHaveBeenCalledWith("jwt-tenant");
180
- });
181
- });
182
- describe("canActivate — missing tenant", () => {
183
- it("throws UnauthorizedException when no tenant identifier in request", async () => {
184
- const req = { headers: {} };
185
- const ctx = makeExecutionContext(req);
186
- await expect(canActivate(client, ctx)).rejects.toThrow(UnauthorizedException);
187
- await expect(canActivate(client, ctx)).rejects.toThrow("Tenant ID could not be resolved from request");
188
- });
189
- it("throws UnauthorizedException when tenant not found in control plane", async () => {
190
- const notFoundClient = makeMockClient(null, new TenantNotFoundError("tenant-missing"));
191
- const req = {
192
- headers: { "x-tenant-id": "tenant-missing" },
193
- };
194
- const ctx = makeExecutionContext(req);
195
- await expect(canActivate(notFoundClient, ctx)).rejects.toThrow(UnauthorizedException);
196
- await expect(canActivate(notFoundClient, ctx)).rejects.toThrow("Tenant not found: tenant-missing");
197
- });
198
- it("re-throws unexpected errors", async () => {
199
- const boom = new Error("Network failure");
200
- const errorClient = makeMockClient(null, boom);
201
- const req = {
202
- headers: { "x-tenant-id": "tenant-123" },
203
- };
204
- const ctx = makeExecutionContext(req);
205
- await expect(canActivate(errorClient, ctx)).rejects.toThrow("Network failure");
206
- });
207
- });
208
- describe("canActivate — custom resolvers", () => {
209
- it("uses custom resolver when header and JWT resolve nothing", async () => {
210
- const req = { headers: {} };
211
- const ctx = makeExecutionContext(req);
212
- const customResolver = { resolve: vi.fn(async () => "tenant-from-resolver") };
213
- const result = await canActivate(client, ctx, { resolvers: [customResolver] });
214
- expect(result).toBe(true);
215
- expect(customResolver.resolve).toHaveBeenCalledWith(req);
216
- expect(client.resolveTenant).toHaveBeenCalledWith("tenant-from-resolver");
217
- });
218
- it("stops at first resolver that returns a value", async () => {
219
- const req = { headers: {} };
220
- const ctx = makeExecutionContext(req);
221
- const r1 = { resolve: vi.fn(async () => "first-resolver-tenant") };
222
- const r2 = { resolve: vi.fn(async () => "second-resolver-tenant") };
223
- await canActivate(client, ctx, { resolvers: [r1, r2] });
224
- expect(r1.resolve).toHaveBeenCalled();
225
- expect(r2.resolve).not.toHaveBeenCalled();
226
- expect(client.resolveTenant).toHaveBeenCalledWith("first-resolver-tenant");
227
- });
228
- });
229
- describe("canActivate — impersonation", () => {
230
- it("impersonates target tenant when authorized", async () => {
231
- // client returns MOCK_CONTEXT for "tenant-123", MOCK_CONTEXT_B for "tenant-456"
232
- const impClient = {
233
- resolveTenant: vi.fn(async (id) => {
234
- if (id === "tenant-123")
235
- return MOCK_CONTEXT;
236
- if (id === "tenant-456")
237
- return MOCK_CONTEXT_B;
238
- throw new TenantNotFoundError(id);
239
- }),
240
- };
241
- const req = {
242
- headers: {
243
- "x-tenant-id": "tenant-123",
244
- "x-impersonate-tenant": "tenant-456",
245
- },
246
- };
247
- const ctx = makeExecutionContext(req);
248
- const onImpersonate = vi.fn();
249
- const result = await canActivate(impClient, ctx, {
250
- impersonation: {
251
- enabled: true,
252
- authorize: async () => true,
253
- onImpersonate,
254
- },
255
- });
256
- expect(result).toBe(true);
257
- expect(req["tenant"]).toEqual(MOCK_CONTEXT_B);
258
- expect(req["impersonating"]).toBe(true);
259
- expect(req["originalTenantId"]).toBe("tenant-123");
260
- expect(onImpersonate).toHaveBeenCalledWith(req, "tenant-123", "tenant-456");
261
- });
262
- it("throws ForbiddenException when impersonation is denied", async () => {
263
- const req = {
264
- headers: {
265
- "x-tenant-id": "tenant-123",
266
- "x-impersonate-tenant": "tenant-456",
267
- },
268
- };
269
- const ctx = makeExecutionContext(req);
270
- await expect(canActivate(client, ctx, {
271
- impersonation: {
272
- enabled: true,
273
- authorize: async () => false,
274
- },
275
- })).rejects.toThrow(ForbiddenException);
276
- });
277
- });
278
- });
279
- // ── Real StratumGuard: verified JWT must be authoritative ─────────────────────
280
- // Exercises the actual guard (not the mirror above) to lock in that an untrusted
281
- // X-Tenant-ID header cannot override the tenant proven by a verified JWT.
282
- describe("StratumGuard (real guard): tenant identity precedence", () => {
283
- function makeJwt(payload) {
284
- const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
285
- const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
286
- return `${header}.${body}.fakesig`;
287
- }
288
- it("uses the verified JWT tenant and ignores a conflicting X-Tenant-ID header", async () => {
289
- const token = makeJwt({ tenant_id: "tenant-a" });
290
- const req = {
291
- headers: {
292
- authorization: `Bearer ${token}`,
293
- "x-tenant-id": "tenant-b",
294
- },
295
- };
296
- const ctx = makeExecutionContext(req);
297
- const resolveTenant = vi.fn(async (id) => ({ id, slug: id, name: id }));
298
- const client = { resolveTenant };
299
- const options = { jwtVerify: () => ({ tenant_id: "tenant-a" }) };
300
- const guard = new StratumGuard(client, options);
301
- const result = await guard.canActivate(ctx);
302
- expect(result).toBe(true);
303
- // The verified JWT tenant is authoritative; the header must not be used.
304
- expect(resolveTenant).toHaveBeenCalledWith("tenant-a");
305
- expect(resolveTenant).not.toHaveBeenCalledWith("tenant-b");
306
- expect(req["tenant"].id).toBe("tenant-a");
307
- });
308
- it("falls back to the X-Tenant-ID header only when no verified JWT tenant is present", async () => {
309
- const req = {
310
- headers: { "x-tenant-id": "tenant-header" },
311
- };
312
- const ctx = makeExecutionContext(req);
313
- const resolveTenant = vi.fn(async (id) => ({ id, slug: id, name: id }));
314
- const client = { resolveTenant };
315
- const guard = new StratumGuard(client, {});
316
- const result = await guard.canActivate(ctx);
317
- expect(result).toBe(true);
318
- expect(resolveTenant).toHaveBeenCalledWith("tenant-header");
319
- });
320
- });
321
- describe("@Tenant() decorator", () => {
322
- it("extracts req.tenant from execution context", () => {
323
- const req = { tenant: MOCK_CONTEXT };
324
- const tenant = extractTenant(req);
325
- expect(tenant).toEqual(MOCK_CONTEXT);
326
- });
327
- it("returns undefined when tenant not yet set (guard not applied)", () => {
328
- const req = {};
329
- const tenant = extractTenant(req);
330
- expect(tenant).toBeUndefined();
331
- });
332
- });
333
- describe("STRATUM_CLIENT / STRATUM_OPTIONS constants", () => {
334
- it("exports distinct Symbol injection tokens", async () => {
335
- const { STRATUM_CLIENT, STRATUM_OPTIONS } = await import("../constants.js");
336
- expect(typeof STRATUM_CLIENT).toBe("symbol");
337
- expect(typeof STRATUM_OPTIONS).toBe("symbol");
338
- expect(STRATUM_CLIENT).not.toBe(STRATUM_OPTIONS);
339
- });
340
- });
341
- //# sourceMappingURL=stratum.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stratum.test.js","sourceRoot":"","sources":["../../src/__tests__/stratum.test.ts"],"names":[],"mappings":"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"}