brakit 0.7.5 → 0.7.6
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/README.md +78 -50
- package/dist/api.js +54 -76
- package/dist/bin/brakit.js +28 -23
- package/dist/runtime/index.js +33 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Every request, query, and security issue — before you ship.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
<h1 align="center"><img src="docs/images/icon.png" height="24" alt="" /> Brakit</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<b>See what your app is actually doing.</b> <br />
|
|
5
|
+
Every request, query, and security issue — before you ship. <br />
|
|
6
|
+
<b>Open source · Local only · Zero config · 2 dependencies</b>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<h3 align="center">
|
|
10
|
+
<a href="docs/design/architecture.md">Architecture</a> •
|
|
11
|
+
<a href="https://brakit.ai">Website</a> •
|
|
12
|
+
<a href="CONTRIBUTING.md">Contributing</a>
|
|
13
|
+
</h3>
|
|
14
|
+
|
|
15
|
+
<h4 align="center">
|
|
16
|
+
<a href="LICENSE">
|
|
17
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License" />
|
|
18
|
+
</a>
|
|
19
|
+
<a href="https://nodejs.org">
|
|
20
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg" alt="Node >= 18" />
|
|
21
|
+
</a>
|
|
22
|
+
<a href="https://typescriptlang.org">
|
|
23
|
+
<img src="https://img.shields.io/badge/built%20with-TypeScript-3178c6.svg" alt="TypeScript" />
|
|
24
|
+
</a>
|
|
25
|
+
<a href="CONTRIBUTING.md">
|
|
26
|
+
<img src="https://img.shields.io/badge/PRs-Welcome-brightgreen" alt="PRs welcome!" />
|
|
27
|
+
</a>
|
|
28
|
+
</h4>
|
|
12
29
|
|
|
13
30
|
---
|
|
14
31
|
|
|
32
|
+
<p align="center">
|
|
33
|
+
<img width="700" src="docs/images/dashboard.png" alt="Brakit Dashboard" />
|
|
34
|
+
</p>
|
|
35
|
+
|
|
15
36
|
## Quick Start
|
|
16
37
|
|
|
17
38
|
```bash
|
|
@@ -28,18 +49,19 @@ Dashboard at `http://localhost:<port>/__brakit`. Insights in the terminal.
|
|
|
28
49
|
|
|
29
50
|
> **Requirements:** Node.js >= 18 and a project with `package.json`.
|
|
30
51
|
|
|
31
|
-
[Documentation](https://brakit.ai/docs) · [Website](https://brakit.ai)
|
|
32
|
-
|
|
33
52
|
---
|
|
34
53
|
|
|
35
54
|
## What You Get
|
|
36
55
|
|
|
37
|
-
- **
|
|
56
|
+
- **Live dashboard** at `/__brakit` — performance overview, request history, scatter charts, real-time via SSE
|
|
57
|
+
- **8 security rules** scanned against live traffic — leaked secrets, PII in responses, missing auth flags
|
|
58
|
+
- **Time breakdown** — every endpoint shows where time goes: DB, Fetch, or App code
|
|
59
|
+
- **N+1 query detection** — same query pattern repeated 5+ times in a single request
|
|
60
|
+
- **Regression detection** — p95 latency or query count increased vs. previous session
|
|
38
61
|
- **Action-level visibility** — see "Sign Up" and "Load Dashboard", not 47 raw HTTP requests
|
|
39
62
|
- **Duplicate detection** — same API called twice? Flagged with redundancy percentage
|
|
40
|
-
- **N+1 query detection** — same query pattern repeated 5+ times in a single request? That's an N+1
|
|
41
63
|
- **Full server tracing** — fetch calls, DB queries, console logs, errors — zero code changes
|
|
42
|
-
- **
|
|
64
|
+
- **Response overfetch** — large JSON responses with many fields your client doesn't use
|
|
43
65
|
- **Performance tracking** — health grades and p95 trends across dev sessions
|
|
44
66
|
|
|
45
67
|
---
|
|
@@ -56,16 +78,16 @@ Brakit watches every action your app takes — not raw HTTP noise, but what actu
|
|
|
56
78
|
|
|
57
79
|
8 high-confidence rules that scan your live traffic and flag real issues — not theoretical ones:
|
|
58
80
|
|
|
59
|
-
| | Rule
|
|
60
|
-
| ------------ |
|
|
61
|
-
| **Critical** | Exposed Secret
|
|
62
|
-
| **Critical** | Token in URL
|
|
63
|
-
| **Critical** | Stack Trace Leak
|
|
64
|
-
| **Critical** | Error Info Leak
|
|
65
|
-
| Warning | PII in Response
|
|
66
|
-
| Warning | Insecure Cookie
|
|
67
|
-
| Warning | Sensitive Logs
|
|
68
|
-
| Warning | CORS + Credentials | `credentials: true` with wildcard origin
|
|
81
|
+
| | Rule | What it catches |
|
|
82
|
+
| ------------ | ------------------ | -------------------------------------------------------------------------------- |
|
|
83
|
+
| **Critical** | Exposed Secret | Response contains `password`, `api_key`, `client_secret` fields with real values |
|
|
84
|
+
| **Critical** | Token in URL | Auth tokens in query parameters instead of headers |
|
|
85
|
+
| **Critical** | Stack Trace Leak | Internal stack traces sent to the client |
|
|
86
|
+
| **Critical** | Error Info Leak | DB connection strings, SQL queries, or secret values in error responses |
|
|
87
|
+
| Warning | PII in Response | API echoes back emails, returns full user records with internal IDs |
|
|
88
|
+
| Warning | Insecure Cookie | Missing `HttpOnly` or `SameSite` flags |
|
|
89
|
+
| Warning | Sensitive Logs | Passwords, secrets, or token values in console output |
|
|
90
|
+
| Warning | CORS + Credentials | `credentials: true` with wildcard origin |
|
|
69
91
|
|
|
70
92
|
---
|
|
71
93
|
|
|
@@ -93,27 +115,27 @@ Instrumentation hooks capture fetch calls, DB queries, console output, and error
|
|
|
93
115
|
|
|
94
116
|
Brakit never runs in production. 7 independent layers ensure it:
|
|
95
117
|
|
|
96
|
-
| #
|
|
97
|
-
|
|
98
|
-
| 1
|
|
99
|
-
| 2
|
|
100
|
-
| 3
|
|
101
|
-
| 4
|
|
102
|
-
| 5
|
|
103
|
-
| 6
|
|
104
|
-
| 7
|
|
118
|
+
| # | Layer | How it blocks |
|
|
119
|
+
| --- | ---------------------------- | ----------------------------------------- |
|
|
120
|
+
| 1 | `shouldActivate()` | Checks `NODE_ENV` + 15 cloud/CI env vars |
|
|
121
|
+
| 2 | `instrumentation.ts` guard | Its own `NODE_ENV !== 'production'` check |
|
|
122
|
+
| 3 | devDependency | Pruned in production builds |
|
|
123
|
+
| 4 | `try/catch` on import | Missing module = silent no-op |
|
|
124
|
+
| 5 | Localhost-only dashboard | Non-local IPs get 404 on `/__brakit` |
|
|
125
|
+
| 6 | `safeWrap` + circuit breaker | 10 errors = brakit self-disables |
|
|
126
|
+
| 7 | `BRAKIT_DISABLE=true` | Manual kill switch |
|
|
105
127
|
|
|
106
128
|
### Supported Frameworks
|
|
107
129
|
|
|
108
|
-
| Framework
|
|
109
|
-
|
|
|
110
|
-
| Next.js
|
|
111
|
-
| Remix
|
|
112
|
-
| Nuxt
|
|
113
|
-
| Vite
|
|
114
|
-
| Astro
|
|
115
|
-
| Express
|
|
116
|
-
| Fastify
|
|
130
|
+
| Framework | Status |
|
|
131
|
+
| --------- | -------------------------- |
|
|
132
|
+
| Next.js | Full support (auto-detect) |
|
|
133
|
+
| Remix | Auto-detect |
|
|
134
|
+
| Nuxt | Auto-detect |
|
|
135
|
+
| Vite | Auto-detect |
|
|
136
|
+
| Astro | Auto-detect |
|
|
137
|
+
| Express | Auto-detect |
|
|
138
|
+
| Fastify | Auto-detect |
|
|
117
139
|
|
|
118
140
|
### Supported Databases
|
|
119
141
|
|
|
@@ -157,34 +179,40 @@ Only 2 production dependencies: `citty` (CLI) and `picocolors` (terminal colors)
|
|
|
157
179
|
|
|
158
180
|
```
|
|
159
181
|
src/
|
|
160
|
-
runtime/ In-process entry point,
|
|
161
|
-
analysis/
|
|
182
|
+
runtime/ In-process entry point, interceptor, capture, safety
|
|
183
|
+
analysis/ Insights engine and security scanner
|
|
184
|
+
insights/ InsightRule implementations (one file per rule)
|
|
162
185
|
rules/ SecurityRule implementations (one file per rule)
|
|
163
186
|
cli/ CLI commands (install, uninstall)
|
|
187
|
+
constants/ Shared thresholds, route paths, limits
|
|
164
188
|
dashboard/
|
|
165
189
|
api/ REST handlers — requests, flows, telemetry, metrics
|
|
166
190
|
client/ Browser JS generated as template strings
|
|
167
191
|
views/ Tab renderers (overview, flows, graph, etc.)
|
|
168
192
|
styles/ CSS modules
|
|
169
193
|
detect/ Framework auto-detection
|
|
170
|
-
instrument/
|
|
194
|
+
instrument/ Database adapters and instrumentation hooks
|
|
171
195
|
adapters/ BrakitAdapter implementations (one file per library)
|
|
172
196
|
hooks/ Core hooks (fetch, console, errors, context)
|
|
197
|
+
output/ Terminal insight listener
|
|
173
198
|
store/ In-memory telemetry stores + persistent metrics
|
|
174
199
|
types/ TypeScript definitions by domain
|
|
200
|
+
utils/ Shared utilities (collections, format, math, endpoint)
|
|
175
201
|
```
|
|
176
202
|
|
|
177
203
|
---
|
|
178
204
|
|
|
179
205
|
## Contributing
|
|
180
206
|
|
|
181
|
-
Brakit is early and moving fast. The most common contributions — adding a
|
|
182
|
-
database adapter
|
|
183
|
-
interface. See [CONTRIBUTING.md](CONTRIBUTING.md) for
|
|
207
|
+
Brakit is early and moving fast. The most common contributions — adding a
|
|
208
|
+
database adapter, a security rule, or an insight rule — each require exactly
|
|
209
|
+
one file and one interface. See [CONTRIBUTING.md](CONTRIBUTING.md) for
|
|
210
|
+
step-by-step guides.
|
|
184
211
|
|
|
185
212
|
Some areas where help would be great:
|
|
186
213
|
|
|
187
214
|
- **Database adapters** — Drizzle, Mongoose, SQLite, MongoDB
|
|
215
|
+
- **Insight rules** — New performance patterns, custom thresholds
|
|
188
216
|
- **Security rules** — More patterns, configurable severity
|
|
189
217
|
- **Dashboard** — Request diff, timeline view, HAR export
|
|
190
218
|
|
package/dist/api.js
CHANGED
|
@@ -409,6 +409,58 @@ var corsCredentialsRule = {
|
|
|
409
409
|
}
|
|
410
410
|
};
|
|
411
411
|
|
|
412
|
+
// src/constants/thresholds.ts
|
|
413
|
+
var FLOW_GAP_MS = 5e3;
|
|
414
|
+
var SLOW_REQUEST_THRESHOLD_MS = 2e3;
|
|
415
|
+
var MIN_POLLING_SEQUENCE = 3;
|
|
416
|
+
var ENDPOINT_TRUNCATE_LENGTH = 12;
|
|
417
|
+
var N1_QUERY_THRESHOLD = 5;
|
|
418
|
+
var ERROR_RATE_THRESHOLD_PCT = 20;
|
|
419
|
+
var SLOW_ENDPOINT_THRESHOLD_MS = 1e3;
|
|
420
|
+
var MIN_REQUESTS_FOR_INSIGHT = 2;
|
|
421
|
+
var HIGH_QUERY_COUNT_PER_REQ = 5;
|
|
422
|
+
var CROSS_ENDPOINT_MIN_ENDPOINTS = 3;
|
|
423
|
+
var CROSS_ENDPOINT_PCT = 50;
|
|
424
|
+
var CROSS_ENDPOINT_MIN_OCCURRENCES = 5;
|
|
425
|
+
var REDUNDANT_QUERY_MIN_COUNT = 2;
|
|
426
|
+
var LARGE_RESPONSE_BYTES = 51200;
|
|
427
|
+
var HIGH_ROW_COUNT = 100;
|
|
428
|
+
var OVERFETCH_MIN_REQUESTS = 2;
|
|
429
|
+
var OVERFETCH_MIN_FIELDS = 8;
|
|
430
|
+
var OVERFETCH_MIN_INTERNAL_IDS = 2;
|
|
431
|
+
var OVERFETCH_NULL_RATIO = 0.3;
|
|
432
|
+
var REGRESSION_PCT_THRESHOLD = 50;
|
|
433
|
+
var REGRESSION_MIN_INCREASE_MS = 200;
|
|
434
|
+
var REGRESSION_MIN_REQUESTS = 5;
|
|
435
|
+
var QUERY_COUNT_REGRESSION_RATIO = 1.5;
|
|
436
|
+
var OVERFETCH_MANY_FIELDS = 12;
|
|
437
|
+
var OVERFETCH_UNWRAP_MIN_SIZE = 3;
|
|
438
|
+
var MAX_DUPLICATE_INSIGHTS = 3;
|
|
439
|
+
|
|
440
|
+
// src/utils/response.ts
|
|
441
|
+
function unwrapResponse(parsed) {
|
|
442
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
443
|
+
const obj = parsed;
|
|
444
|
+
const keys = Object.keys(obj);
|
|
445
|
+
if (keys.length > 3) return parsed;
|
|
446
|
+
let best = null;
|
|
447
|
+
let bestSize = 0;
|
|
448
|
+
for (const key of keys) {
|
|
449
|
+
const val = obj[key];
|
|
450
|
+
if (Array.isArray(val) && val.length > bestSize) {
|
|
451
|
+
best = val;
|
|
452
|
+
bestSize = val.length;
|
|
453
|
+
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
454
|
+
const size = Object.keys(val).length;
|
|
455
|
+
if (size > bestSize) {
|
|
456
|
+
best = val;
|
|
457
|
+
bestSize = size;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return best && bestSize >= OVERFETCH_UNWRAP_MIN_SIZE ? best : parsed;
|
|
462
|
+
}
|
|
463
|
+
|
|
412
464
|
// src/analysis/rules/response-pii-leak.ts
|
|
413
465
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
|
|
414
466
|
var FULL_RECORD_MIN_FIELDS = 5;
|
|
@@ -453,28 +505,6 @@ function hasInternalIds(obj) {
|
|
|
453
505
|
}
|
|
454
506
|
return false;
|
|
455
507
|
}
|
|
456
|
-
function unwrapResponse(parsed) {
|
|
457
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
458
|
-
const obj = parsed;
|
|
459
|
-
const keys = Object.keys(obj);
|
|
460
|
-
if (keys.length > 3) return parsed;
|
|
461
|
-
let best = null;
|
|
462
|
-
let bestSize = 0;
|
|
463
|
-
for (const key of keys) {
|
|
464
|
-
const val = obj[key];
|
|
465
|
-
if (Array.isArray(val) && val.length > bestSize) {
|
|
466
|
-
best = val;
|
|
467
|
-
bestSize = val.length;
|
|
468
|
-
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
469
|
-
const size = Object.keys(val).length;
|
|
470
|
-
if (size > bestSize) {
|
|
471
|
-
best = val;
|
|
472
|
-
bestSize = size;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
return best && bestSize >= 3 ? best : parsed;
|
|
477
|
-
}
|
|
478
508
|
function detectPII(method, reqBody, resBody) {
|
|
479
509
|
const target = unwrapResponse(resBody);
|
|
480
510
|
if (WRITE_METHODS.has(method) && reqBody && typeof reqBody === "object") {
|
|
@@ -600,34 +630,6 @@ var DASHBOARD_PREFIX = "/__brakit";
|
|
|
600
630
|
var MAX_REQUEST_ENTRIES = 1e3;
|
|
601
631
|
var MAX_TELEMETRY_ENTRIES = 1e3;
|
|
602
632
|
|
|
603
|
-
// src/constants/thresholds.ts
|
|
604
|
-
var FLOW_GAP_MS = 5e3;
|
|
605
|
-
var SLOW_REQUEST_THRESHOLD_MS = 2e3;
|
|
606
|
-
var MIN_POLLING_SEQUENCE = 3;
|
|
607
|
-
var ENDPOINT_TRUNCATE_LENGTH = 12;
|
|
608
|
-
var N1_QUERY_THRESHOLD = 5;
|
|
609
|
-
var ERROR_RATE_THRESHOLD_PCT = 20;
|
|
610
|
-
var SLOW_ENDPOINT_THRESHOLD_MS = 1e3;
|
|
611
|
-
var MIN_REQUESTS_FOR_INSIGHT = 2;
|
|
612
|
-
var HIGH_QUERY_COUNT_PER_REQ = 5;
|
|
613
|
-
var CROSS_ENDPOINT_MIN_ENDPOINTS = 3;
|
|
614
|
-
var CROSS_ENDPOINT_PCT = 50;
|
|
615
|
-
var CROSS_ENDPOINT_MIN_OCCURRENCES = 5;
|
|
616
|
-
var REDUNDANT_QUERY_MIN_COUNT = 2;
|
|
617
|
-
var LARGE_RESPONSE_BYTES = 51200;
|
|
618
|
-
var HIGH_ROW_COUNT = 100;
|
|
619
|
-
var OVERFETCH_MIN_REQUESTS = 2;
|
|
620
|
-
var OVERFETCH_MIN_FIELDS = 8;
|
|
621
|
-
var OVERFETCH_MIN_INTERNAL_IDS = 2;
|
|
622
|
-
var OVERFETCH_NULL_RATIO = 0.3;
|
|
623
|
-
var REGRESSION_PCT_THRESHOLD = 50;
|
|
624
|
-
var REGRESSION_MIN_INCREASE_MS = 200;
|
|
625
|
-
var REGRESSION_MIN_REQUESTS = 5;
|
|
626
|
-
var QUERY_COUNT_REGRESSION_RATIO = 1.5;
|
|
627
|
-
var OVERFETCH_MANY_FIELDS = 12;
|
|
628
|
-
var OVERFETCH_UNWRAP_MIN_SIZE = 3;
|
|
629
|
-
var MAX_DUPLICATE_INSIGHTS = 3;
|
|
630
|
-
|
|
631
633
|
// src/utils/static-patterns.ts
|
|
632
634
|
var STATIC_PATTERNS = [
|
|
633
635
|
/^\/_next\//,
|
|
@@ -1642,30 +1644,6 @@ var highRowsRule = {
|
|
|
1642
1644
|
}
|
|
1643
1645
|
};
|
|
1644
1646
|
|
|
1645
|
-
// src/utils/response.ts
|
|
1646
|
-
function unwrapResponse2(parsed) {
|
|
1647
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
1648
|
-
const obj = parsed;
|
|
1649
|
-
const keys = Object.keys(obj);
|
|
1650
|
-
if (keys.length > 3) return parsed;
|
|
1651
|
-
let best = null;
|
|
1652
|
-
let bestSize = 0;
|
|
1653
|
-
for (const key of keys) {
|
|
1654
|
-
const val = obj[key];
|
|
1655
|
-
if (Array.isArray(val) && val.length > bestSize) {
|
|
1656
|
-
best = val;
|
|
1657
|
-
bestSize = val.length;
|
|
1658
|
-
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
1659
|
-
const size = Object.keys(val).length;
|
|
1660
|
-
if (size > bestSize) {
|
|
1661
|
-
best = val;
|
|
1662
|
-
bestSize = size;
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
return best && bestSize >= OVERFETCH_UNWRAP_MIN_SIZE ? best : parsed;
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
1647
|
// src/analysis/insights/rules/response-overfetch.ts
|
|
1670
1648
|
var responseOverfetchRule = {
|
|
1671
1649
|
id: "response-overfetch",
|
|
@@ -1682,7 +1660,7 @@ var responseOverfetchRule = {
|
|
|
1682
1660
|
} catch {
|
|
1683
1661
|
continue;
|
|
1684
1662
|
}
|
|
1685
|
-
const target =
|
|
1663
|
+
const target = unwrapResponse(parsed);
|
|
1686
1664
|
const inspectObj = Array.isArray(target) && target.length > 0 ? target[0] : target;
|
|
1687
1665
|
if (!inspectObj || typeof inspectObj !== "object" || Array.isArray(inspectObj)) continue;
|
|
1688
1666
|
const fields = Object.keys(inspectObj);
|
|
@@ -1900,7 +1878,7 @@ var AnalysisEngine = class {
|
|
|
1900
1878
|
};
|
|
1901
1879
|
|
|
1902
1880
|
// src/index.ts
|
|
1903
|
-
var VERSION = "0.7.
|
|
1881
|
+
var VERSION = "0.7.6";
|
|
1904
1882
|
export {
|
|
1905
1883
|
AdapterRegistry,
|
|
1906
1884
|
AnalysisEngine,
|
package/dist/bin/brakit.js
CHANGED
|
@@ -386,6 +386,33 @@ var corsCredentialsRule = {
|
|
|
386
386
|
}
|
|
387
387
|
};
|
|
388
388
|
|
|
389
|
+
// src/constants/thresholds.ts
|
|
390
|
+
var OVERFETCH_UNWRAP_MIN_SIZE = 3;
|
|
391
|
+
|
|
392
|
+
// src/utils/response.ts
|
|
393
|
+
function unwrapResponse(parsed) {
|
|
394
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
395
|
+
const obj = parsed;
|
|
396
|
+
const keys = Object.keys(obj);
|
|
397
|
+
if (keys.length > 3) return parsed;
|
|
398
|
+
let best = null;
|
|
399
|
+
let bestSize = 0;
|
|
400
|
+
for (const key of keys) {
|
|
401
|
+
const val = obj[key];
|
|
402
|
+
if (Array.isArray(val) && val.length > bestSize) {
|
|
403
|
+
best = val;
|
|
404
|
+
bestSize = val.length;
|
|
405
|
+
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
406
|
+
const size = Object.keys(val).length;
|
|
407
|
+
if (size > bestSize) {
|
|
408
|
+
best = val;
|
|
409
|
+
bestSize = size;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return best && bestSize >= OVERFETCH_UNWRAP_MIN_SIZE ? best : parsed;
|
|
414
|
+
}
|
|
415
|
+
|
|
389
416
|
// src/analysis/rules/response-pii-leak.ts
|
|
390
417
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
|
|
391
418
|
var FULL_RECORD_MIN_FIELDS = 5;
|
|
@@ -430,28 +457,6 @@ function hasInternalIds(obj) {
|
|
|
430
457
|
}
|
|
431
458
|
return false;
|
|
432
459
|
}
|
|
433
|
-
function unwrapResponse(parsed) {
|
|
434
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
435
|
-
const obj = parsed;
|
|
436
|
-
const keys = Object.keys(obj);
|
|
437
|
-
if (keys.length > 3) return parsed;
|
|
438
|
-
let best = null;
|
|
439
|
-
let bestSize = 0;
|
|
440
|
-
for (const key of keys) {
|
|
441
|
-
const val = obj[key];
|
|
442
|
-
if (Array.isArray(val) && val.length > bestSize) {
|
|
443
|
-
best = val;
|
|
444
|
-
bestSize = val.length;
|
|
445
|
-
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
446
|
-
const size = Object.keys(val).length;
|
|
447
|
-
if (size > bestSize) {
|
|
448
|
-
best = val;
|
|
449
|
-
bestSize = size;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
return best && bestSize >= 3 ? best : parsed;
|
|
454
|
-
}
|
|
455
460
|
function detectPII(method, reqBody, resBody) {
|
|
456
461
|
const target = unwrapResponse(resBody);
|
|
457
462
|
if (WRITE_METHODS.has(method) && reqBody && typeof reqBody === "object") {
|
|
@@ -695,7 +700,7 @@ import { resolve as resolve2 } from "path";
|
|
|
695
700
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
696
701
|
|
|
697
702
|
// src/index.ts
|
|
698
|
-
var VERSION = "0.7.
|
|
703
|
+
var VERSION = "0.7.6";
|
|
699
704
|
|
|
700
705
|
// src/cli/commands/install.ts
|
|
701
706
|
var IMPORT_LINE = `import "brakit";`;
|
package/dist/runtime/index.js
CHANGED
|
@@ -3076,6 +3076,36 @@ var init_cors_credentials = __esm({
|
|
|
3076
3076
|
}
|
|
3077
3077
|
});
|
|
3078
3078
|
|
|
3079
|
+
// src/utils/response.ts
|
|
3080
|
+
function unwrapResponse(parsed) {
|
|
3081
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
3082
|
+
const obj = parsed;
|
|
3083
|
+
const keys = Object.keys(obj);
|
|
3084
|
+
if (keys.length > 3) return parsed;
|
|
3085
|
+
let best = null;
|
|
3086
|
+
let bestSize = 0;
|
|
3087
|
+
for (const key of keys) {
|
|
3088
|
+
const val = obj[key];
|
|
3089
|
+
if (Array.isArray(val) && val.length > bestSize) {
|
|
3090
|
+
best = val;
|
|
3091
|
+
bestSize = val.length;
|
|
3092
|
+
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
3093
|
+
const size = Object.keys(val).length;
|
|
3094
|
+
if (size > bestSize) {
|
|
3095
|
+
best = val;
|
|
3096
|
+
bestSize = size;
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
return best && bestSize >= OVERFETCH_UNWRAP_MIN_SIZE ? best : parsed;
|
|
3101
|
+
}
|
|
3102
|
+
var init_response = __esm({
|
|
3103
|
+
"src/utils/response.ts"() {
|
|
3104
|
+
"use strict";
|
|
3105
|
+
init_thresholds();
|
|
3106
|
+
}
|
|
3107
|
+
});
|
|
3108
|
+
|
|
3079
3109
|
// src/analysis/rules/response-pii-leak.ts
|
|
3080
3110
|
function tryParseJson2(body) {
|
|
3081
3111
|
if (!body) return null;
|
|
@@ -3117,28 +3147,6 @@ function hasInternalIds(obj) {
|
|
|
3117
3147
|
}
|
|
3118
3148
|
return false;
|
|
3119
3149
|
}
|
|
3120
|
-
function unwrapResponse(parsed) {
|
|
3121
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
3122
|
-
const obj = parsed;
|
|
3123
|
-
const keys = Object.keys(obj);
|
|
3124
|
-
if (keys.length > 3) return parsed;
|
|
3125
|
-
let best = null;
|
|
3126
|
-
let bestSize = 0;
|
|
3127
|
-
for (const key of keys) {
|
|
3128
|
-
const val = obj[key];
|
|
3129
|
-
if (Array.isArray(val) && val.length > bestSize) {
|
|
3130
|
-
best = val;
|
|
3131
|
-
bestSize = val.length;
|
|
3132
|
-
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
3133
|
-
const size = Object.keys(val).length;
|
|
3134
|
-
if (size > bestSize) {
|
|
3135
|
-
best = val;
|
|
3136
|
-
bestSize = size;
|
|
3137
|
-
}
|
|
3138
|
-
}
|
|
3139
|
-
}
|
|
3140
|
-
return best && bestSize >= 3 ? best : parsed;
|
|
3141
|
-
}
|
|
3142
3150
|
function detectPII(method, reqBody, resBody) {
|
|
3143
3151
|
const target = unwrapResponse(resBody);
|
|
3144
3152
|
if (WRITE_METHODS.has(method) && reqBody && typeof reqBody === "object") {
|
|
@@ -3186,6 +3194,7 @@ var init_response_pii_leak = __esm({
|
|
|
3186
3194
|
"src/analysis/rules/response-pii-leak.ts"() {
|
|
3187
3195
|
"use strict";
|
|
3188
3196
|
init_patterns();
|
|
3197
|
+
init_response();
|
|
3189
3198
|
WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
|
|
3190
3199
|
FULL_RECORD_MIN_FIELDS = 5;
|
|
3191
3200
|
LIST_PII_MIN_ITEMS = 2;
|
|
@@ -3879,36 +3888,6 @@ var init_high_rows = __esm({
|
|
|
3879
3888
|
}
|
|
3880
3889
|
});
|
|
3881
3890
|
|
|
3882
|
-
// src/utils/response.ts
|
|
3883
|
-
function unwrapResponse2(parsed) {
|
|
3884
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
3885
|
-
const obj = parsed;
|
|
3886
|
-
const keys = Object.keys(obj);
|
|
3887
|
-
if (keys.length > 3) return parsed;
|
|
3888
|
-
let best = null;
|
|
3889
|
-
let bestSize = 0;
|
|
3890
|
-
for (const key of keys) {
|
|
3891
|
-
const val = obj[key];
|
|
3892
|
-
if (Array.isArray(val) && val.length > bestSize) {
|
|
3893
|
-
best = val;
|
|
3894
|
-
bestSize = val.length;
|
|
3895
|
-
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
3896
|
-
const size = Object.keys(val).length;
|
|
3897
|
-
if (size > bestSize) {
|
|
3898
|
-
best = val;
|
|
3899
|
-
bestSize = size;
|
|
3900
|
-
}
|
|
3901
|
-
}
|
|
3902
|
-
}
|
|
3903
|
-
return best && bestSize >= OVERFETCH_UNWRAP_MIN_SIZE ? best : parsed;
|
|
3904
|
-
}
|
|
3905
|
-
var init_response = __esm({
|
|
3906
|
-
"src/utils/response.ts"() {
|
|
3907
|
-
"use strict";
|
|
3908
|
-
init_thresholds();
|
|
3909
|
-
}
|
|
3910
|
-
});
|
|
3911
|
-
|
|
3912
3891
|
// src/analysis/insights/rules/response-overfetch.ts
|
|
3913
3892
|
var responseOverfetchRule;
|
|
3914
3893
|
var init_response_overfetch = __esm({
|
|
@@ -3933,7 +3912,7 @@ var init_response_overfetch = __esm({
|
|
|
3933
3912
|
} catch {
|
|
3934
3913
|
continue;
|
|
3935
3914
|
}
|
|
3936
|
-
const target =
|
|
3915
|
+
const target = unwrapResponse(parsed);
|
|
3937
3916
|
const inspectObj = Array.isArray(target) && target.length > 0 ? target[0] : target;
|
|
3938
3917
|
if (!inspectObj || typeof inspectObj !== "object" || Array.isArray(inspectObj)) continue;
|
|
3939
3918
|
const fields = Object.keys(inspectObj);
|
|
@@ -4226,7 +4205,7 @@ var init_src = __esm({
|
|
|
4226
4205
|
init_engine();
|
|
4227
4206
|
init_insights3();
|
|
4228
4207
|
init_insights2();
|
|
4229
|
-
VERSION = "0.7.
|
|
4208
|
+
VERSION = "0.7.6";
|
|
4230
4209
|
}
|
|
4231
4210
|
});
|
|
4232
4211
|
|
package/package.json
CHANGED