@adaptic/backend-legacy 0.0.996 → 0.0.998

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,77 @@
1
+ /**
2
+ * CORTEX-P0-001 phase 2 — `@Authorized()` coverage for generated CRUD resolvers
3
+ * (audit B01-backend-legacy-03).
4
+ *
5
+ * The `cortexAuthChecker` registered in `buildSchema` is only invoked by
6
+ * TypeGraphQL for fields carrying an `@Authorized()` decorator; the
7
+ * auto-generated typegraphql-prisma resolvers carry none, so the checker was
8
+ * registered-but-inert. This module applies decorators via
9
+ * `applyResolversEnhanceMap`, making the checker actually execute:
10
+ *
11
+ * - FULL coverage (`_all`) for the five investor-relations models —
12
+ * regulated PII (tax documents, KYC status, LP capital ledger) that must
13
+ * never sit on an unauthenticated CRUD surface.
14
+ * - DELETE mutations (`deleteOne*` / `deleteMany*`) for every other model —
15
+ * the most destructive operations on the trading system-of-record.
16
+ *
17
+ * CRITICAL SAFETY CONTRACT — the checker itself remains SHADOW-FIRST: while
18
+ * `CORTEX_AUTHCHECKER_ENFORCE` is OFF (default) a would-deny operation is
19
+ * logged + counted and then ALLOWED, so engine service traffic cannot break.
20
+ * This module only determines WHERE the checker runs, not what it does.
21
+ * Graduation rule (audit B01-backend-legacy-07): enforce only after
22
+ * `cortex_authchecker_evaluations_total` > 0 and the would-deny series has
23
+ * been observed over a full trading week.
24
+ *
25
+ * Must be applied BEFORE `buildSchema` — decorators land in TypeGraphQL's
26
+ * global metadata storage, which `buildSchema` reads.
27
+ */
28
+ import { type ResolversEnhanceMap } from '../generated/typegraphql-prisma';
29
+ /** Model names accepted by the generated {@link ResolversEnhanceMap}. */
30
+ type EnhanceModelName = keyof ResolversEnhanceMap;
31
+ /**
32
+ * The five investor-relations models receiving FULL (`_all`) coverage:
33
+ * every generated query and mutation on these models invokes the authChecker.
34
+ */
35
+ export declare const IR_MODELS: readonly EnhanceModelName[];
36
+ /** Summary of the coverage applied, for the boot log and tests. */
37
+ export interface AuthorizationMapSummary {
38
+ /** Models decorated with `_all` (full CRUD coverage). */
39
+ readonly fullCoverageModels: number;
40
+ /** Models whose delete mutations were decorated. */
41
+ readonly deleteCoverageModels: number;
42
+ /** Total decorated resolver actions (delete actions + `_all` markers). */
43
+ readonly decoratedActions: number;
44
+ /**
45
+ * Delete-action names skipped because the generated CRUD resolver does not
46
+ * expose them — non-empty output means the naming convention drifted and the
47
+ * map must be updated. Never silently ignored: logged at warn on apply.
48
+ */
49
+ readonly skippedActions: readonly string[];
50
+ }
51
+ /** Internal build output: the map plus its audit summary. */
52
+ interface BuiltAuthorizationMap {
53
+ readonly map: ResolversEnhanceMap;
54
+ readonly summary: AuthorizationMapSummary;
55
+ }
56
+ /**
57
+ * Builds the CORTEX authorization enhance-map. Pure (no metadata mutation) so
58
+ * tests can pin its contents without touching TypeGraphQL global state.
59
+ *
60
+ * @returns The enhance map and a summary of the coverage it encodes.
61
+ */
62
+ export declare function buildCortexAuthorizationMap(): BuiltAuthorizationMap;
63
+ /**
64
+ * Applies the CORTEX authorization map to the generated resolvers. Idempotent:
65
+ * decorators land in TypeGraphQL's global metadata storage, so applying twice
66
+ * would duplicate `Authorized` metadata — subsequent calls return the cached
67
+ * summary without re-applying.
68
+ *
69
+ * Call BEFORE `buildSchema`. The registered `cortexAuthChecker` stays
70
+ * SHADOW-FIRST (log + count + allow) until `CORTEX_AUTHCHECKER_ENFORCE` is
71
+ * explicitly flipped on.
72
+ *
73
+ * @returns The {@link AuthorizationMapSummary} for the boot log.
74
+ */
75
+ export declare function applyCortexAuthorizationMap(): AuthorizationMapSummary;
76
+ export {};
77
+ //# sourceMappingURL=authorization-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-map.d.ts","sourceRoot":"","sources":["../../../src/auth/authorization-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAIH,OAAO,EAEL,KAAK,mBAAmB,EACzB,MAAM,iCAAiC,CAAC;AAIzC,yEAAyE;AACzE,KAAK,gBAAgB,GAAG,MAAM,mBAAmB,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,SAAS,gBAAgB,EAMhD,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,uBAAuB;IACtC,yDAAyD;IACzD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,oDAAoD;IACpD,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,0EAA0E;IAC1E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAmBD,6DAA6D;AAC7D,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,qBAAqB,CA8CnE;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,IAAI,uBAAuB,CAcrE"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-map.js","sourceRoot":"","sources":["../../../src/auth/authorization-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * CORTEX-P0-001 phase 2 — `@Authorized()` coverage for generated CRUD resolvers
3
+ * (audit B01-backend-legacy-03).
4
+ *
5
+ * The `cortexAuthChecker` registered in `buildSchema` is only invoked by
6
+ * TypeGraphQL for fields carrying an `@Authorized()` decorator; the
7
+ * auto-generated typegraphql-prisma resolvers carry none, so the checker was
8
+ * registered-but-inert. This module applies decorators via
9
+ * `applyResolversEnhanceMap`, making the checker actually execute:
10
+ *
11
+ * - FULL coverage (`_all`) for the five investor-relations models —
12
+ * regulated PII (tax documents, KYC status, LP capital ledger) that must
13
+ * never sit on an unauthenticated CRUD surface.
14
+ * - DELETE mutations (`deleteOne*` / `deleteMany*`) for every other model —
15
+ * the most destructive operations on the trading system-of-record.
16
+ *
17
+ * CRITICAL SAFETY CONTRACT — the checker itself remains SHADOW-FIRST: while
18
+ * `CORTEX_AUTHCHECKER_ENFORCE` is OFF (default) a would-deny operation is
19
+ * logged + counted and then ALLOWED, so engine service traffic cannot break.
20
+ * This module only determines WHERE the checker runs, not what it does.
21
+ * Graduation rule (audit B01-backend-legacy-07): enforce only after
22
+ * `cortex_authchecker_evaluations_total` > 0 and the would-deny series has
23
+ * been observed over a full trading week.
24
+ *
25
+ * Must be applied BEFORE `buildSchema` — decorators land in TypeGraphQL's
26
+ * global metadata storage, which `buildSchema` reads.
27
+ */
28
+ import { Authorized } from 'type-graphql';
29
+ import { Prisma } from '@prisma/client';
30
+ import { applyResolversEnhanceMap, } from '../generated/typegraphql-prisma/index.mjs';
31
+ import * as generatedIndex from '../generated/typegraphql-prisma/index.mjs';
32
+ import { logger } from '../utils/logger.mjs';
33
+ /**
34
+ * The five investor-relations models receiving FULL (`_all`) coverage:
35
+ * every generated query and mutation on these models invokes the authChecker.
36
+ */
37
+ export const IR_MODELS = [
38
+ 'Investor',
39
+ 'Holding',
40
+ 'InvestorTransaction',
41
+ 'InvestorDocument',
42
+ 'TaxDocument',
43
+ ];
44
+ /**
45
+ * Looks up the generated `<Model>CrudResolver` class for a model, so delete
46
+ * action names can be validated against the real resolver surface instead of
47
+ * being assumed by convention.
48
+ */
49
+ function crudResolverPrototype(model) {
50
+ const resolverClass = generatedIndex[`${model}CrudResolver`];
51
+ if (typeof resolverClass !== 'function') {
52
+ return undefined;
53
+ }
54
+ return resolverClass.prototype;
55
+ }
56
+ /**
57
+ * Builds the CORTEX authorization enhance-map. Pure (no metadata mutation) so
58
+ * tests can pin its contents without touching TypeGraphQL global state.
59
+ *
60
+ * @returns The enhance map and a summary of the coverage it encodes.
61
+ */
62
+ export function buildCortexAuthorizationMap() {
63
+ const map = {};
64
+ const skippedActions = [];
65
+ let decoratedActions = 0;
66
+ let deleteCoverageModels = 0;
67
+ for (const model of IR_MODELS) {
68
+ map[model] = { _all: [Authorized()] };
69
+ decoratedActions += 1;
70
+ }
71
+ const irModelSet = new Set(IR_MODELS);
72
+ for (const model of Object.values(Prisma.ModelName)) {
73
+ // IR models already have full coverage; decorating deletes again would
74
+ // register duplicate Authorized metadata on the same fields.
75
+ if (irModelSet.has(model)) {
76
+ continue;
77
+ }
78
+ const prototype = crudResolverPrototype(model);
79
+ const actionsConfig = {};
80
+ let coveredForModel = 0;
81
+ for (const action of [`deleteOne${model}`, `deleteMany${model}`]) {
82
+ if (prototype && typeof prototype[action] === 'function') {
83
+ actionsConfig[action] = [Authorized()];
84
+ coveredForModel += 1;
85
+ }
86
+ else {
87
+ skippedActions.push(action);
88
+ }
89
+ }
90
+ if (coveredForModel > 0) {
91
+ map[model] =
92
+ actionsConfig;
93
+ decoratedActions += coveredForModel;
94
+ deleteCoverageModels += 1;
95
+ }
96
+ }
97
+ return {
98
+ map,
99
+ summary: {
100
+ fullCoverageModels: IR_MODELS.length,
101
+ deleteCoverageModels,
102
+ decoratedActions,
103
+ skippedActions,
104
+ },
105
+ };
106
+ }
107
+ let appliedSummary;
108
+ /**
109
+ * Applies the CORTEX authorization map to the generated resolvers. Idempotent:
110
+ * decorators land in TypeGraphQL's global metadata storage, so applying twice
111
+ * would duplicate `Authorized` metadata — subsequent calls return the cached
112
+ * summary without re-applying.
113
+ *
114
+ * Call BEFORE `buildSchema`. The registered `cortexAuthChecker` stays
115
+ * SHADOW-FIRST (log + count + allow) until `CORTEX_AUTHCHECKER_ENFORCE` is
116
+ * explicitly flipped on.
117
+ *
118
+ * @returns The {@link AuthorizationMapSummary} for the boot log.
119
+ */
120
+ export function applyCortexAuthorizationMap() {
121
+ if (appliedSummary) {
122
+ return appliedSummary;
123
+ }
124
+ const { map, summary } = buildCortexAuthorizationMap();
125
+ applyResolversEnhanceMap(map);
126
+ if (summary.skippedActions.length > 0) {
127
+ logger.warn('[cortex-authz] delete actions missing from generated resolvers — authorization map drifted from codegen', { skippedActions: summary.skippedActions });
128
+ }
129
+ appliedSummary = summary;
130
+ return summary;
131
+ }
132
+ //# sourceMappingURL=authorization-map.js.map
@@ -0,0 +1,114 @@
1
+ /**
2
+ * CORTEX-P0-001 — resolver-level authorization AuthChecker (SHADOW-FIRST).
3
+ *
4
+ * A TypeGraphQL {@link AuthChecker} that evaluates whether an operation WOULD be
5
+ * allowed under resolver-level authorization, closing the residual vector called
6
+ * out in the tenancy-scoping middleware docs: a governed model reached
7
+ * transitively through a non-governed root, and — more broadly — any
8
+ * `@Authorized()`-decorated field executed without a verified principal.
9
+ *
10
+ * CRITICAL SAFETY CONTRACT — this change is additive and default-OFF. When
11
+ * enforcement is OFF (the default), the checker NEVER denies: it returns `true`
12
+ * for every operation, emitting a structured warn log and incrementing a
13
+ * Prometheus counter for any operation that enforcement WOULD deny. Live
14
+ * behaviour is byte-identical to before this change until
15
+ * `CORTEX_AUTHCHECKER_ENFORCE` is flipped on. Additionally, TypeGraphQL only
16
+ * invokes an AuthChecker for fields decorated with `@Authorized()`; the
17
+ * auto-generated typegraphql-prisma resolvers carry no such decorator, so
18
+ * registering this checker via `buildSchema({ authChecker })` is inert at
19
+ * runtime until decorators are added in the separate enforcement phase.
20
+ *
21
+ * Decision model (mirrors the token-verifier principal kinds):
22
+ *
23
+ * - `server` — trusted server-to-server caller. ALWAYS allowed; the
24
+ * engine + utils call the CRUD resolvers with a server principal and must
25
+ * retain full access, bypassing any role gate.
26
+ * - `admin` / `user` — verified end-user. Allowed when the field requires no
27
+ * specific role, or when the principal carries one of the required roles;
28
+ * otherwise a would-deny with reason `insufficient_role`.
29
+ * - `null` (no verified principal) — a genuinely unauthenticated caller on a
30
+ * non-public (i.e. `@Authorized()`) operation. A would-deny with reason
31
+ * `unauthenticated`.
32
+ *
33
+ * @see src/auth/tenancy-scope.ts for the row-level (data-scope) counterpart.
34
+ * @see src/auth/token-verifier.ts for `BackendPrincipal`.
35
+ */
36
+ import { Counter } from 'prom-client';
37
+ import type { AuthChecker } from 'type-graphql';
38
+ import type { BackendPrincipal } from './token-verifier';
39
+ /**
40
+ * Environment variable gating enforcement. When set to `true`/`1`, the checker
41
+ * fails closed (returns `false`) for any would-deny operation. Unset or any
42
+ * other value keeps the checker in SHADOW mode (observe + count + allow).
43
+ */
44
+ export declare const CORTEX_AUTHCHECKER_ENFORCE_ENV = "CORTEX_AUTHCHECKER_ENFORCE";
45
+ /**
46
+ * Whether resolver-level authorization enforcement is ON. Read fresh on each
47
+ * call (a cheap env read) so the shadow→enforce graduation can be flipped
48
+ * operationally without a process restart — the same pattern the tenancy-scoping
49
+ * middleware uses. Defaults to OFF (shadow) for any unset/unrecognised value.
50
+ *
51
+ * @param env - Environment source (defaults to `process.env`); injectable for tests.
52
+ * @returns `true` only when the flag is explicitly `true`/`1`.
53
+ */
54
+ export declare function isAuthCheckerEnforced(env?: Record<string, string | undefined>): boolean;
55
+ /**
56
+ * Finite set of reasons enforcement WOULD deny an operation. Used as the sole
57
+ * label on {@link cortexAuthCheckerWouldDenyTotal}.
58
+ */
59
+ export type WouldDenyReason = 'unauthenticated' | 'insufficient_role';
60
+ /**
61
+ * Counts EVERY AuthChecker invocation, regardless of outcome (audit
62
+ * B01-backend-legacy-07). A flat-zero {@link cortexAuthCheckerWouldDenyTotal}
63
+ * is ambiguous on its own: it can mean "no traffic would be denied" OR "the
64
+ * checker never ran" (no `@Authorized()` field was ever executed) — exactly the
65
+ * false-confidence pattern that preceded the beta-net-cap fail-open. Graduation
66
+ * rule: enforce only when this counter is > 0 and the would-deny series has
67
+ * been observed over a full trading week.
68
+ */
69
+ export declare const cortexAuthCheckerEvaluationsTotal: Counter<string>;
70
+ /**
71
+ * Counts operations that resolver-level authorization WOULD deny. In shadow mode
72
+ * this is the primary signal proving whether flipping `CORTEX_AUTHCHECKER_ENFORCE`
73
+ * to `enforce` would reject any legitimate platform or engine traffic. Labelled
74
+ * by the discriminated {@link WouldDenyReason}.
75
+ */
76
+ export declare const cortexAuthCheckerWouldDenyTotal: Counter<"reason">;
77
+ /** The outcome of evaluating whether an operation would be allowed. */
78
+ interface AuthEvaluation {
79
+ readonly wouldAllow: boolean;
80
+ /** Populated only when `wouldAllow` is `false`. */
81
+ readonly reason?: WouldDenyReason;
82
+ }
83
+ /**
84
+ * Pure evaluation of whether a principal would satisfy the required roles for an
85
+ * operation. Performs no I/O and no logging.
86
+ *
87
+ * @param principal - The verified principal, or `null` for an unauthenticated caller.
88
+ * @param requiredRoles - Roles declared on the field's `@Authorized(...)` decorator
89
+ * (empty when the field only requires authentication).
90
+ * @returns The {@link AuthEvaluation}.
91
+ */
92
+ export declare function evaluateWouldAllow(principal: BackendPrincipal | null, requiredRoles: readonly string[]): AuthEvaluation;
93
+ /**
94
+ * GraphQL context shape this checker reads. `principal` is the verified
95
+ * `BackendPrincipal` attached to the context in `server.ts` (`null` for an
96
+ * unauthenticated caller).
97
+ */
98
+ export interface CortexAuthContext {
99
+ principal?: BackendPrincipal | null;
100
+ }
101
+ /**
102
+ * The CORTEX-P0-001 AuthChecker. Register via
103
+ * `buildSchema({ authChecker: cortexAuthChecker })`.
104
+ *
105
+ * SHADOW (default): a would-deny operation increments
106
+ * {@link cortexAuthCheckerWouldDenyTotal}, emits a warn log, and RETURNS TRUE —
107
+ * no behaviour change. ENFORCE (`CORTEX_AUTHCHECKER_ENFORCE=true`): a would-deny
108
+ * operation is logged, the counter is incremented, and the checker RETURNS FALSE
109
+ * (fail closed). Operations that would be allowed always return `true` with no
110
+ * metric or log emission.
111
+ */
112
+ export declare const cortexAuthChecker: AuthChecker<CortexAuthContext>;
113
+ export {};
114
+ //# sourceMappingURL=cortex-auth-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cortex-auth-checker.d.ts","sourceRoot":"","sources":["../../../src/auth/cortex-auth-checker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,cAAc,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAQzD;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,+BAA+B,CAAC;AAK3E;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,OAAO,CAGT;AAMD;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAEtE;;;;;;;;GAQG;AACH,eAAO,MAAM,iCAAiC,iBAI5C,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,mBAK1C,CAAC;AAEH,uEAAuE;AACvE,UAAU,cAAc;IACtB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,gBAAgB,GAAG,IAAI,EAClC,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,cAAc,CAyBhB;AAMD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACrC;AAcD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,iBAAiB,CAkC5D,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cortex-auth-checker.js","sourceRoot":"","sources":["../../../src/auth/cortex-auth-checker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * CORTEX-P0-001 — resolver-level authorization AuthChecker (SHADOW-FIRST).
3
+ *
4
+ * A TypeGraphQL {@link AuthChecker} that evaluates whether an operation WOULD be
5
+ * allowed under resolver-level authorization, closing the residual vector called
6
+ * out in the tenancy-scoping middleware docs: a governed model reached
7
+ * transitively through a non-governed root, and — more broadly — any
8
+ * `@Authorized()`-decorated field executed without a verified principal.
9
+ *
10
+ * CRITICAL SAFETY CONTRACT — this change is additive and default-OFF. When
11
+ * enforcement is OFF (the default), the checker NEVER denies: it returns `true`
12
+ * for every operation, emitting a structured warn log and incrementing a
13
+ * Prometheus counter for any operation that enforcement WOULD deny. Live
14
+ * behaviour is byte-identical to before this change until
15
+ * `CORTEX_AUTHCHECKER_ENFORCE` is flipped on. Additionally, TypeGraphQL only
16
+ * invokes an AuthChecker for fields decorated with `@Authorized()`; the
17
+ * auto-generated typegraphql-prisma resolvers carry no such decorator, so
18
+ * registering this checker via `buildSchema({ authChecker })` is inert at
19
+ * runtime until decorators are added in the separate enforcement phase.
20
+ *
21
+ * Decision model (mirrors the token-verifier principal kinds):
22
+ *
23
+ * - `server` — trusted server-to-server caller. ALWAYS allowed; the
24
+ * engine + utils call the CRUD resolvers with a server principal and must
25
+ * retain full access, bypassing any role gate.
26
+ * - `admin` / `user` — verified end-user. Allowed when the field requires no
27
+ * specific role, or when the principal carries one of the required roles;
28
+ * otherwise a would-deny with reason `insufficient_role`.
29
+ * - `null` (no verified principal) — a genuinely unauthenticated caller on a
30
+ * non-public (i.e. `@Authorized()`) operation. A would-deny with reason
31
+ * `unauthenticated`.
32
+ *
33
+ * @see src/auth/tenancy-scope.ts for the row-level (data-scope) counterpart.
34
+ * @see src/auth/token-verifier.ts for `BackendPrincipal`.
35
+ */
36
+ import { Counter } from 'prom-client';
37
+ import { metricsRegistry } from '../config/metrics.mjs';
38
+ import { logger } from '../utils/logger.mjs';
39
+ // -----------------------------------------------------------------------------
40
+ // Enforcement flag
41
+ // -----------------------------------------------------------------------------
42
+ /**
43
+ * Environment variable gating enforcement. When set to `true`/`1`, the checker
44
+ * fails closed (returns `false`) for any would-deny operation. Unset or any
45
+ * other value keeps the checker in SHADOW mode (observe + count + allow).
46
+ */
47
+ export const CORTEX_AUTHCHECKER_ENFORCE_ENV = 'CORTEX_AUTHCHECKER_ENFORCE';
48
+ /** The `admin` role string used to satisfy admin-gated `@Authorized()` fields. */
49
+ const ADMIN_ROLE = 'admin';
50
+ /**
51
+ * Whether resolver-level authorization enforcement is ON. Read fresh on each
52
+ * call (a cheap env read) so the shadow→enforce graduation can be flipped
53
+ * operationally without a process restart — the same pattern the tenancy-scoping
54
+ * middleware uses. Defaults to OFF (shadow) for any unset/unrecognised value.
55
+ *
56
+ * @param env - Environment source (defaults to `process.env`); injectable for tests.
57
+ * @returns `true` only when the flag is explicitly `true`/`1`.
58
+ */
59
+ export function isAuthCheckerEnforced(env = process.env) {
60
+ const raw = (env[CORTEX_AUTHCHECKER_ENFORCE_ENV] ?? '').trim().toLowerCase();
61
+ return raw === 'true' || raw === '1';
62
+ }
63
+ /**
64
+ * Counts EVERY AuthChecker invocation, regardless of outcome (audit
65
+ * B01-backend-legacy-07). A flat-zero {@link cortexAuthCheckerWouldDenyTotal}
66
+ * is ambiguous on its own: it can mean "no traffic would be denied" OR "the
67
+ * checker never ran" (no `@Authorized()` field was ever executed) — exactly the
68
+ * false-confidence pattern that preceded the beta-net-cap fail-open. Graduation
69
+ * rule: enforce only when this counter is > 0 and the would-deny series has
70
+ * been observed over a full trading week.
71
+ */
72
+ export const cortexAuthCheckerEvaluationsTotal = new Counter({
73
+ name: 'cortex_authchecker_evaluations_total',
74
+ help: 'Total AuthChecker invocations, any outcome (zero means no @Authorized field was executed — distinct from "no would-denies")',
75
+ registers: [metricsRegistry],
76
+ });
77
+ /**
78
+ * Counts operations that resolver-level authorization WOULD deny. In shadow mode
79
+ * this is the primary signal proving whether flipping `CORTEX_AUTHCHECKER_ENFORCE`
80
+ * to `enforce` would reject any legitimate platform or engine traffic. Labelled
81
+ * by the discriminated {@link WouldDenyReason}.
82
+ */
83
+ export const cortexAuthCheckerWouldDenyTotal = new Counter({
84
+ name: 'cortex_authchecker_would_deny_total',
85
+ help: 'Operations resolver-level authorization would deny, by reason (counted in shadow mode without denying)',
86
+ labelNames: ['reason'],
87
+ registers: [metricsRegistry],
88
+ });
89
+ /**
90
+ * Pure evaluation of whether a principal would satisfy the required roles for an
91
+ * operation. Performs no I/O and no logging.
92
+ *
93
+ * @param principal - The verified principal, or `null` for an unauthenticated caller.
94
+ * @param requiredRoles - Roles declared on the field's `@Authorized(...)` decorator
95
+ * (empty when the field only requires authentication).
96
+ * @returns The {@link AuthEvaluation}.
97
+ */
98
+ export function evaluateWouldAllow(principal, requiredRoles) {
99
+ if (!principal) {
100
+ return { wouldAllow: false, reason: 'unauthenticated' };
101
+ }
102
+ // Server-to-server callers are unconditionally allowed and bypass role gates.
103
+ if (principal.kind === 'server') {
104
+ return { wouldAllow: true };
105
+ }
106
+ // Authenticated user/admin with no specific role requirement -> allowed.
107
+ if (requiredRoles.length === 0) {
108
+ return { wouldAllow: true };
109
+ }
110
+ const principalRoles = principal.kind === 'admin'
111
+ ? [...principal.roles, ADMIN_ROLE]
112
+ : principal.roles;
113
+ const roleSet = new Set(principalRoles);
114
+ const hasRequiredRole = requiredRoles.some((role) => roleSet.has(role));
115
+ return hasRequiredRole
116
+ ? { wouldAllow: true }
117
+ : { wouldAllow: false, reason: 'insufficient_role' };
118
+ }
119
+ /** Describe an operation for structured logs, without leaking arguments. */
120
+ function describeOperation(resolverData) {
121
+ const { info } = resolverData;
122
+ return {
123
+ operationType: info.operation.operation,
124
+ operationName: info.operation.name?.value ?? info.fieldName,
125
+ field: info.fieldName,
126
+ };
127
+ }
128
+ /**
129
+ * The CORTEX-P0-001 AuthChecker. Register via
130
+ * `buildSchema({ authChecker: cortexAuthChecker })`.
131
+ *
132
+ * SHADOW (default): a would-deny operation increments
133
+ * {@link cortexAuthCheckerWouldDenyTotal}, emits a warn log, and RETURNS TRUE —
134
+ * no behaviour change. ENFORCE (`CORTEX_AUTHCHECKER_ENFORCE=true`): a would-deny
135
+ * operation is logged, the counter is incremented, and the checker RETURNS FALSE
136
+ * (fail closed). Operations that would be allowed always return `true` with no
137
+ * metric or log emission.
138
+ */
139
+ export const cortexAuthChecker = (resolverData, roles) => {
140
+ // Unconditional: proves the checker is actually reachable (see
141
+ // cortexAuthCheckerEvaluationsTotal TSDoc / audit B01-backend-legacy-07).
142
+ cortexAuthCheckerEvaluationsTotal.inc();
143
+ const principal = resolverData.context.principal ?? null;
144
+ const evaluation = evaluateWouldAllow(principal, roles);
145
+ if (evaluation.wouldAllow) {
146
+ return true;
147
+ }
148
+ const reason = evaluation.reason ?? 'unauthenticated';
149
+ const enforced = isAuthCheckerEnforced();
150
+ const operation = describeOperation(resolverData);
151
+ cortexAuthCheckerWouldDenyTotal.inc({ reason });
152
+ logger.warn(enforced
153
+ ? '[cortex-authchecker] denying operation (enforce)'
154
+ : '[cortex-authchecker] shadow would-deny (allowing)', {
155
+ ...operation,
156
+ reason,
157
+ enforced,
158
+ principalKind: principal?.kind ?? 'none',
159
+ requiredRoles: [...roles],
160
+ });
161
+ return !enforced;
162
+ };
163
+ //# sourceMappingURL=cortex-auth-checker.js.map
@@ -0,0 +1,60 @@
1
+ import { vi } from 'vitest';
2
+ import type { Counter } from 'prom-client';
3
+ import type { Request, Response } from 'express';
4
+ import type { RateLimitConfig } from '../rate-limiter';
5
+ /**
6
+ * Shared fixtures for the rate-limiter test files (audit
7
+ * B01-backend-legacy-08). Pure helpers only — each test file remains
8
+ * responsible for setting `process.env.JWT_SECRET` via `vi.hoisted` BEFORE its
9
+ * first import pulls in `config/jwtConfig` (which reads the env at load time).
10
+ */
11
+ /** Window used by every test config. */
12
+ export declare const WINDOW_MS = 60000;
13
+ /**
14
+ * Builds a small test limiter config.
15
+ *
16
+ * @param overrides - Field overrides applied over the defaults.
17
+ * @returns A complete {@link RateLimitConfig}.
18
+ */
19
+ export declare function makeConfig(overrides?: Partial<RateLimitConfig>): RateLimitConfig;
20
+ /** A mock Express response with observable spies. */
21
+ export interface MockResponse {
22
+ res: Response;
23
+ setHeader: ReturnType<typeof vi.fn>;
24
+ status: ReturnType<typeof vi.fn>;
25
+ json: ReturnType<typeof vi.fn>;
26
+ }
27
+ /**
28
+ * Creates a mock response whose header/status/json calls are observable —
29
+ * the shadow contract is proven by these spies staying untouched.
30
+ *
31
+ * @returns The {@link MockResponse}.
32
+ */
33
+ export declare function makeRes(): MockResponse;
34
+ /**
35
+ * Creates a mock request. Defaults to an anonymous POST from a fixed IP.
36
+ *
37
+ * @param overrides - Request field overrides (headers, ip, method, …).
38
+ * @returns A Request usable by the limiter middleware.
39
+ */
40
+ export declare function makeReq(overrides?: Record<string, unknown>): Request;
41
+ /**
42
+ * Reads the current value of a limiter counter for a label pair.
43
+ *
44
+ * @param counter - The prom-client counter to read.
45
+ * @param labels - The limiter/tier label pair identifying the series.
46
+ * @returns The current value (0 when the series does not exist yet).
47
+ */
48
+ export declare function counterValue(counter: Counter<'limiter' | 'tier'>, labels: {
49
+ limiter: string;
50
+ tier: string;
51
+ }): Promise<number>;
52
+ /**
53
+ * Signs a real HS256 user JWT with the ambient `JWT_SECRET` (the same secret
54
+ * `config/jwtConfig` resolved at load), so the tier resolver verifies it.
55
+ *
56
+ * @param sub - Subject claim for the token.
57
+ * @returns A signed JWT string.
58
+ */
59
+ export declare function signUserToken(sub: string): string;
60
+ //# sourceMappingURL=rate-limit-test-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-test-utils.d.ts","sourceRoot":"","sources":["../../../../src/middleware/__tests__/rate-limit-test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD;;;;;GAKG;AAEH,wCAAwC;AACxC,eAAO,MAAM,SAAS,QAAS,CAAC;AAEhC;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,SAAS,GAAE,OAAO,CAAC,eAAe,CAAM,GACvC,eAAe,CAUjB;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,QAAQ,CAAC;IACd,SAAS,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACjC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,YAAY,CAMtC;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAQxE;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,EACpC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASjD"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-test-utils.js","sourceRoot":"","sources":["../../../../src/middleware/__tests__/rate-limit-test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC5B,OAAO,GAAG,MAAM,cAAc,CAAC;AAK/B;;;;;GAKG;AAEH,wCAAwC;AACxC,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,YAAsC,EAAE;IAExC,OAAO;QACL,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,SAAS;QACnB,gBAAgB,EAAE,GAAG;QACrB,kBAAkB,EAAE,CAAC;QACrB,eAAe,EAAE,IAAI;QACrB,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,EAAE;QACvD,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAUD;;;;;GAKG;AACH,MAAM,UAAU,OAAO;IACrB,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAyB,CAAC;IAC/D,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,YAAqC,EAAE;IAC7D,OAAO;QACL,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE;QACX,EAAE,EAAE,cAAc;QAClB,MAAM,EAAE,EAAE,aAAa,EAAE,cAAc,EAAE;QACzC,GAAG,SAAS;KACS,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAoC,EACpC,MAAyC;IAEzC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAC5E,CAAC;IACF,OAAO,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACtC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE;QAChD,SAAS,EAAE,OAAO;QAClB,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;AACL,CAAC"}