@produtype/core 0.89.0 → 0.90.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.
@@ -18,6 +18,8 @@ const ORIGIN_HANDLING = [/Access-Control-Allow-Origin/i, /ALLOWED_ORIGINS/, /all
18
18
  * `ALLOWED_ORIGINS = ["*"]` are the same decision written in two frameworks, and only
19
19
  * the first was being caught.
20
20
  */
21
+ /** `== StatusCode::TOO_MANY_REQUESTS` and its spellings: a status being read. */
22
+ const COMPARES_A_STATUS = /[=!]==?\s*(?:StatusCode::TOO_MANY_REQUESTS|http\.StatusTooManyRequests|HttpStatus\.TOO_MANY_REQUESTS|HttpStatusCode\.TooManyRequests|Status429TooManyRequests)|(?:StatusCode::TOO_MANY_REQUESTS|http\.StatusTooManyRequests|HttpStatus\.TOO_MANY_REQUESTS|HttpStatusCode\.TooManyRequests)\s*[=!]==?/;
21
23
  const WILDCARD_ORIGIN = /(Access-Control-Allow-Origin["'\s:,]+\*)|(["']\*["'])/i;
22
24
  /**
23
25
  * A line that names an origin somebody chose.
@@ -252,8 +254,36 @@ async function detectSecurity(ctx) {
252
254
  /HTTPException\(\s*429/,
253
255
  /['"`]Retry-After['"`]\s*[,:]/i,
254
256
  /setHeader\(\s*['"`]Retry-After/i,
257
+ /**
258
+ * The same refusal, spelled the way each platform spells it.
259
+ *
260
+ * Every shape above is JavaScript or Python, so a service that throttles in any
261
+ * other language had to declare a package to be seen at all. crates.io writes
262
+ * its own limiter — `src/rate_limiter.rs`, no crate — and refuses with
263
+ * `StatusCode::TOO_MANY_REQUESTS`; it was told at `high` that it does not
264
+ * throttle.
265
+ *
266
+ * These are constants the standard library or the framework defines for one
267
+ * number in RFC 6585. Nobody picks the name, and each of them is the server
268
+ * issuing the refusal rather than reading one: a constant is what you construct
269
+ * a response from, where receiving is a comparison against `.status`.
270
+ */
271
+ /StatusCode::TOO_MANY_REQUESTS/,
272
+ /http\.StatusTooManyRequests/,
273
+ /HttpStatus\.TOO_MANY_REQUESTS/,
274
+ /HttpStatusCode\.TooManyRequests/,
275
+ /Status429TooManyRequests/,
255
276
  ], 20);
256
- const rateLimit = rateLimitDep || rateLimitSignals.length > 0;
277
+ /**
278
+ * Still issuing, not receiving — the constants need the same test the numbers got.
279
+ *
280
+ * `res.status(429)` can only be a server refusing, but
281
+ * `if resp.status() == StatusCode::TOO_MANY_REQUESTS` is this project being
282
+ * refused by somebody else's, which is what nocodb's webhook invoker does. A
283
+ * comparison is the reading direction; an argument is the writing one.
284
+ */
285
+ const issuedRateLimits = rateLimitSignals.filter((hit) => !COMPARES_A_STATUS.test(hit.snippet));
286
+ const rateLimit = rateLimitDep || issuedRateLimits.length > 0;
257
287
  /**
258
288
  * Rate limiting where the brute force happens.
259
289
  *
@@ -297,14 +327,14 @@ async function detectSecurity(ctx) {
297
327
  const coversAnAuthMount = mountedPaths.some((prefix) => authMountPaths.some((mount) => mount === prefix || mount.startsWith(`${prefix}/`)));
298
328
  const rateLimitNearAuth = coversAnAuthMount
299
329
  || (boundLimiterUses ?? []).some((use) => authSurfaceFiles.has(use.file))
300
- || rateLimitSignals.some((match) => authSurfaceFiles.has(match.file));
330
+ || issuedRateLimits.some((match) => authSurfaceFiles.has(match.file));
301
331
  if (helmetDep)
302
332
  evidence.push({ type: 'dependency', value: 'helmet', claim: 'headers' });
303
333
  if (rateLimitDep)
304
334
  evidence.push({ type: 'dependency', value: 'rate limiting package', claim: 'rate-limit' });
305
335
  for (const m of headerSignals)
306
336
  evidence.push({ type: 'snippet', value: m.snippet, file: m.file, line: m.line, claim: 'headers' });
307
- for (const m of rateLimitSignals)
337
+ for (const m of issuedRateLimits)
308
338
  evidence.push({ type: 'snippet', value: m.snippet, file: m.file, line: m.line, claim: 'rate-limit' });
309
339
  /**
310
340
  * Every identifier the `cors` package reaches, per file.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@produtype/core",
3
- "version": "0.89.0",
3
+ "version": "0.90.0",
4
4
  "description": "Deterministic CLI and library that analyzes a web application repository and reports how far it is from production-ready for the kind of product it is meant to be.",
5
5
  "license": "MIT",
6
6
  "bin": {