@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.
package/server.cjs CHANGED
@@ -59,8 +59,11 @@ const body_parser_1 = __importDefault(require("body-parser"));
59
59
  const ws_1 = require("ws");
60
60
  const ws_2 = require("graphql-ws/lib/use/ws");
61
61
  const auth_1 = require("./middleware/auth.cjs");
62
+ const rate_limiter_1 = require("./middleware/rate-limiter.cjs");
62
63
  const audit_logger_1 = require("./middleware/audit-logger.cjs");
63
64
  const tenancy_scoping_1 = require("./middleware/tenancy-scoping.cjs");
65
+ const cortex_auth_checker_1 = require("./auth/cortex-auth-checker.cjs");
66
+ const authorization_map_1 = require("./auth/authorization-map.cjs");
64
67
  const http_status_mapper_1 = require("./plugins/http-status-mapper.cjs");
65
68
  const graphql_validation_plugin_1 = require("./middleware/graphql-validation-plugin.cjs");
66
69
  const query_complexity_1 = require("./middleware/query-complexity.cjs");
@@ -100,7 +103,15 @@ function principalToUser(principal) {
100
103
  };
101
104
  }
102
105
  }
106
+ /**
107
+ * Default number of proxy hops trusted for X-Forwarded-For resolution when
108
+ * `TRUST_PROXY` is unset. One hop matches a single fronting LB/ingress proxy;
109
+ * operators must set `TRUST_PROXY` to the exact hop count of their deployment
110
+ * (audit B01-backend-legacy-02 / -12).
111
+ */
112
+ const DEFAULT_TRUST_PROXY_HOPS = 1;
103
113
  const startServer = async () => {
114
+ var _a;
104
115
  // Boot-time invariant: in production, `GOOGLE_OAUTH_CLIENT_IDS` must be set.
105
116
  // Without it, no Google ID token can be safely verified — and the verifier
106
117
  // would surface a per-request `misconfigured` error indefinitely. Refuse to
@@ -110,6 +121,21 @@ const startServer = async () => {
110
121
  // is on (defaults on in production/staging). Registers default Node.js metrics
111
122
  // and starts the uptime gauge ticker. See: src/config/metrics.ts.
112
123
  (0, metrics_1.initMetrics)();
124
+ // CORTEX-P0-001 phase 2 (audit B01-backend-legacy-03): decorate generated
125
+ // CRUD resolvers with @Authorized() — full coverage on the 5 investor-relations
126
+ // models, delete mutations elsewhere — so the authChecker below actually
127
+ // executes. Must run BEFORE buildSchema (decorators land in TypeGraphQL's
128
+ // metadata storage). The checker stays SHADOW-FIRST: would-denies are logged
129
+ // + counted but ALLOWED until CORTEX_AUTHCHECKER_ENFORCE is flipped on.
130
+ // The boot log satisfies audit B01-backend-legacy-07: a zero decorated-action
131
+ // count means the checker is unreachable and its metrics are meaningless.
132
+ const authzSummary = (0, authorization_map_1.applyCortexAuthorizationMap)();
133
+ logger_1.logger.info('[cortex-authz] applied @Authorized coverage (authChecker in shadow unless CORTEX_AUTHCHECKER_ENFORCE)', {
134
+ fullCoverageModels: authzSummary.fullCoverageModels,
135
+ deleteCoverageModels: authzSummary.deleteCoverageModels,
136
+ decoratedActions: authzSummary.decoratedActions,
137
+ skippedActions: authzSummary.skippedActions.length,
138
+ });
113
139
  const schema = await (0, type_graphql_1.buildSchema)({
114
140
  resolvers: [...typegraphql_prisma_1.resolvers, custom_1.OptionsGreeksHistoryCustomResolver],
115
141
  validate: false,
@@ -118,12 +144,42 @@ const startServer = async () => {
118
144
  // and unauthenticated callers are bypassed in every mode. Gated by
119
145
  // `TENANCY_SCOPING_MODE` (default `shadow`).
120
146
  globalMiddlewares: [(0, tenancy_scoping_1.createTenancyScopingMiddleware)()],
147
+ // Resolver-level authorization (CORTEX-P0-001). Invoked for the
148
+ // `@Authorized()`-decorated fields applied by applyCortexAuthorizationMap
149
+ // above. SHADOW-FIRST: while `CORTEX_AUTHCHECKER_ENFORCE` is OFF (default),
150
+ // it observes + counts would-deny operations but always allows —
151
+ // byte-identical live behaviour until enforcement is flipped on.
152
+ authChecker: cortex_auth_checker_1.cortexAuthChecker,
121
153
  });
122
154
  const app = (0, express_1.default)();
123
155
  const httpServer = (0, http_1.createServer)(app);
156
+ // Trust the load-balancer proxy chain so `req.ip` resolves the CLIENT address
157
+ // from X-Forwarded-For instead of the proxy hop (audit B01-backend-legacy-02).
158
+ // Without this, every external caller shares one rate-limit bucket per tier,
159
+ // invalidating the shadow signal and making any future enforce flip an outage
160
+ // switch for the whole /graphql surface. `TRUST_PROXY` accepts a hop count
161
+ // (recommended: the EXACT number of proxy hops, so a spoofed X-Forwarded-For
162
+ // cannot mint arbitrary identifiers — audit B01-backend-legacy-12) or an
163
+ // Express trust-proxy string (CIDR / preset). Defaults to 1 hop.
164
+ const rawTrustProxy = ((_a = process.env.TRUST_PROXY) !== null && _a !== void 0 ? _a : '').trim();
165
+ const trustProxy = rawTrustProxy === ''
166
+ ? DEFAULT_TRUST_PROXY_HOPS
167
+ : /^\d+$/.test(rawTrustProxy)
168
+ ? parseInt(rawTrustProxy, 10)
169
+ : rawTrustProxy;
170
+ app.set('trust proxy', trustProxy);
124
171
  // HTTP request metrics — must be mounted early to capture every request.
125
172
  // The middleware is a no-op when metrics are disabled.
126
173
  app.use(metrics_1.metricsMiddleware);
174
+ // Rate limiting (CORTEX-P0-001). SHADOW-FIRST: while `CORTEX_RATE_LIMIT_ENFORCE`
175
+ // is OFF (default), the limiters observe + count requests that WOULD be blocked
176
+ // but never touch the response, so live behaviour is byte-identical. The
177
+ // GraphQL limiter is mounted INSIDE the /graphql chain after cors() (see below)
178
+ // so an enforce-mode 429 carries CORS headers and browser clients can read the
179
+ // Retry-After instead of seeing an opaque CORS failure
180
+ // (audit B01-backend-legacy-11). Mounted before `/api` auth so limiting
181
+ // precedes the (more expensive) auth work.
182
+ app.use('/api', rate_limiter_1.authRateLimiter);
127
183
  app.use('/api', (req, res, next) => (0, auth_1.authMiddleware)(req, res, next));
128
184
  // APQ cache: in-memory LRU, gated by `APQ_ENABLED` (default on). The
129
185
  // Apollo Server option only accepts a value when a cache is provided;
@@ -242,7 +298,11 @@ const startServer = async () => {
242
298
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID'],
243
299
  maxAge: 86400, // 24h preflight cache
244
300
  };
245
- app.use('/graphql', (0, cors_1.default)(corsOptions), body_parser_1.default.json(), (0, express4_1.expressMiddleware)(server, {
301
+ app.use('/graphql', (0, cors_1.default)(corsOptions),
302
+ // After cors() so enforce-mode 429s carry CORS headers; before body parsing
303
+ // so limiting stays cheap. OPTIONS preflights are skipped inside the
304
+ // limiter (audit B01-backend-legacy-11).
305
+ rate_limiter_1.graphqlRateLimiter, body_parser_1.default.json(), (0, express4_1.expressMiddleware)(server, {
246
306
  context: async ({ req }) => {
247
307
  // Ensure we're using the global prisma instance and never disconnecting it between requests
248
308
  if (!global.prisma) {