brakit 0.7.5 → 0.8.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.
- package/README.md +87 -52
- package/dist/api.d.ts +47 -2
- package/dist/api.js +275 -94
- package/dist/bin/brakit.js +1143 -48
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.js +737 -0
- package/dist/runtime/index.js +302 -66
- package/package.json +5 -1
package/dist/api.js
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
// src/store/finding-store.ts
|
|
2
|
+
import {
|
|
3
|
+
readFileSync as readFileSync2,
|
|
4
|
+
writeFileSync as writeFileSync2,
|
|
5
|
+
existsSync as existsSync2,
|
|
6
|
+
mkdirSync as mkdirSync2,
|
|
7
|
+
renameSync
|
|
8
|
+
} from "fs";
|
|
9
|
+
import { writeFile as writeFile2, mkdir, rename } from "fs/promises";
|
|
10
|
+
import { resolve as resolve2 } from "path";
|
|
11
|
+
|
|
12
|
+
// src/constants/routes.ts
|
|
13
|
+
var DASHBOARD_PREFIX = "/__brakit";
|
|
14
|
+
|
|
15
|
+
// src/constants/limits.ts
|
|
16
|
+
var MAX_REQUEST_ENTRIES = 1e3;
|
|
17
|
+
var MAX_TELEMETRY_ENTRIES = 1e3;
|
|
18
|
+
|
|
19
|
+
// src/constants/thresholds.ts
|
|
20
|
+
var FLOW_GAP_MS = 5e3;
|
|
21
|
+
var SLOW_REQUEST_THRESHOLD_MS = 2e3;
|
|
22
|
+
var MIN_POLLING_SEQUENCE = 3;
|
|
23
|
+
var ENDPOINT_TRUNCATE_LENGTH = 12;
|
|
24
|
+
var N1_QUERY_THRESHOLD = 5;
|
|
25
|
+
var ERROR_RATE_THRESHOLD_PCT = 20;
|
|
26
|
+
var SLOW_ENDPOINT_THRESHOLD_MS = 1e3;
|
|
27
|
+
var MIN_REQUESTS_FOR_INSIGHT = 2;
|
|
28
|
+
var HIGH_QUERY_COUNT_PER_REQ = 5;
|
|
29
|
+
var CROSS_ENDPOINT_MIN_ENDPOINTS = 3;
|
|
30
|
+
var CROSS_ENDPOINT_PCT = 50;
|
|
31
|
+
var CROSS_ENDPOINT_MIN_OCCURRENCES = 5;
|
|
32
|
+
var REDUNDANT_QUERY_MIN_COUNT = 2;
|
|
33
|
+
var LARGE_RESPONSE_BYTES = 51200;
|
|
34
|
+
var HIGH_ROW_COUNT = 100;
|
|
35
|
+
var OVERFETCH_MIN_REQUESTS = 2;
|
|
36
|
+
var OVERFETCH_MIN_FIELDS = 8;
|
|
37
|
+
var OVERFETCH_MIN_INTERNAL_IDS = 2;
|
|
38
|
+
var OVERFETCH_NULL_RATIO = 0.3;
|
|
39
|
+
var REGRESSION_PCT_THRESHOLD = 50;
|
|
40
|
+
var REGRESSION_MIN_INCREASE_MS = 200;
|
|
41
|
+
var REGRESSION_MIN_REQUESTS = 5;
|
|
42
|
+
var QUERY_COUNT_REGRESSION_RATIO = 1.5;
|
|
43
|
+
var OVERFETCH_MANY_FIELDS = 12;
|
|
44
|
+
var OVERFETCH_UNWRAP_MIN_SIZE = 3;
|
|
45
|
+
var MAX_DUPLICATE_INSIGHTS = 3;
|
|
46
|
+
|
|
47
|
+
// src/constants/metrics.ts
|
|
48
|
+
var METRICS_DIR = ".brakit";
|
|
49
|
+
var FINDINGS_FILE = ".brakit/findings.json";
|
|
50
|
+
var FINDINGS_FLUSH_INTERVAL_MS = 1e4;
|
|
4
51
|
|
|
5
52
|
// src/utils/fs.ts
|
|
6
53
|
import { access } from "fs/promises";
|
|
@@ -14,8 +61,191 @@ async function fileExists(path) {
|
|
|
14
61
|
return false;
|
|
15
62
|
}
|
|
16
63
|
}
|
|
64
|
+
function ensureGitignore(dir, entry) {
|
|
65
|
+
try {
|
|
66
|
+
const gitignorePath = resolve(dir, "../.gitignore");
|
|
67
|
+
if (existsSync(gitignorePath)) {
|
|
68
|
+
const content = readFileSync(gitignorePath, "utf-8");
|
|
69
|
+
if (content.split("\n").some((l) => l.trim() === entry)) return;
|
|
70
|
+
writeFileSync(gitignorePath, content.trimEnd() + "\n" + entry + "\n");
|
|
71
|
+
} else {
|
|
72
|
+
writeFileSync(gitignorePath, entry + "\n");
|
|
73
|
+
}
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/store/finding-id.ts
|
|
79
|
+
import { createHash } from "crypto";
|
|
80
|
+
function computeFindingId(finding) {
|
|
81
|
+
const key = `${finding.rule}:${finding.endpoint}:${finding.desc}`;
|
|
82
|
+
return createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/store/finding-store.ts
|
|
86
|
+
var FindingStore = class {
|
|
87
|
+
constructor(rootDir) {
|
|
88
|
+
this.rootDir = rootDir;
|
|
89
|
+
this.metricsDir = resolve2(rootDir, METRICS_DIR);
|
|
90
|
+
this.findingsPath = resolve2(rootDir, FINDINGS_FILE);
|
|
91
|
+
this.tmpPath = this.findingsPath + ".tmp";
|
|
92
|
+
this.load();
|
|
93
|
+
}
|
|
94
|
+
findings = /* @__PURE__ */ new Map();
|
|
95
|
+
flushTimer = null;
|
|
96
|
+
dirty = false;
|
|
97
|
+
writing = false;
|
|
98
|
+
findingsPath;
|
|
99
|
+
tmpPath;
|
|
100
|
+
metricsDir;
|
|
101
|
+
start() {
|
|
102
|
+
this.flushTimer = setInterval(
|
|
103
|
+
() => this.flush(),
|
|
104
|
+
FINDINGS_FLUSH_INTERVAL_MS
|
|
105
|
+
);
|
|
106
|
+
this.flushTimer.unref();
|
|
107
|
+
}
|
|
108
|
+
stop() {
|
|
109
|
+
if (this.flushTimer) {
|
|
110
|
+
clearInterval(this.flushTimer);
|
|
111
|
+
this.flushTimer = null;
|
|
112
|
+
}
|
|
113
|
+
this.flushSync();
|
|
114
|
+
}
|
|
115
|
+
upsert(finding, source) {
|
|
116
|
+
const id = computeFindingId(finding);
|
|
117
|
+
const existing = this.findings.get(id);
|
|
118
|
+
const now = Date.now();
|
|
119
|
+
if (existing) {
|
|
120
|
+
existing.lastSeenAt = now;
|
|
121
|
+
existing.occurrences++;
|
|
122
|
+
existing.finding = finding;
|
|
123
|
+
if (existing.state === "resolved") {
|
|
124
|
+
existing.state = "open";
|
|
125
|
+
existing.resolvedAt = null;
|
|
126
|
+
}
|
|
127
|
+
this.dirty = true;
|
|
128
|
+
return existing;
|
|
129
|
+
}
|
|
130
|
+
const stateful = {
|
|
131
|
+
findingId: id,
|
|
132
|
+
state: "open",
|
|
133
|
+
source,
|
|
134
|
+
finding,
|
|
135
|
+
firstSeenAt: now,
|
|
136
|
+
lastSeenAt: now,
|
|
137
|
+
resolvedAt: null,
|
|
138
|
+
occurrences: 1
|
|
139
|
+
};
|
|
140
|
+
this.findings.set(id, stateful);
|
|
141
|
+
this.dirty = true;
|
|
142
|
+
return stateful;
|
|
143
|
+
}
|
|
144
|
+
transition(findingId, state) {
|
|
145
|
+
const finding = this.findings.get(findingId);
|
|
146
|
+
if (!finding) return false;
|
|
147
|
+
finding.state = state;
|
|
148
|
+
if (state === "resolved") {
|
|
149
|
+
finding.resolvedAt = Date.now();
|
|
150
|
+
}
|
|
151
|
+
this.dirty = true;
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
reconcilePassive(currentFindings) {
|
|
155
|
+
const currentIds = new Set(currentFindings.map(computeFindingId));
|
|
156
|
+
for (const [id, stateful] of this.findings) {
|
|
157
|
+
if (stateful.source === "passive" && stateful.state === "open" && !currentIds.has(id)) {
|
|
158
|
+
stateful.state = "resolved";
|
|
159
|
+
stateful.resolvedAt = Date.now();
|
|
160
|
+
this.dirty = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
getAll() {
|
|
165
|
+
return [...this.findings.values()];
|
|
166
|
+
}
|
|
167
|
+
getByState(state) {
|
|
168
|
+
return [...this.findings.values()].filter((f) => f.state === state);
|
|
169
|
+
}
|
|
170
|
+
get(findingId) {
|
|
171
|
+
return this.findings.get(findingId);
|
|
172
|
+
}
|
|
173
|
+
clear() {
|
|
174
|
+
this.findings.clear();
|
|
175
|
+
this.dirty = true;
|
|
176
|
+
}
|
|
177
|
+
load() {
|
|
178
|
+
try {
|
|
179
|
+
if (existsSync2(this.findingsPath)) {
|
|
180
|
+
const raw = readFileSync2(this.findingsPath, "utf-8");
|
|
181
|
+
const parsed = JSON.parse(raw);
|
|
182
|
+
if (parsed?.version === 1 && Array.isArray(parsed.findings)) {
|
|
183
|
+
for (const f of parsed.findings) {
|
|
184
|
+
this.findings.set(f.findingId, f);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
flush() {
|
|
192
|
+
if (!this.dirty) return;
|
|
193
|
+
this.writeAsync();
|
|
194
|
+
}
|
|
195
|
+
flushSync() {
|
|
196
|
+
if (!this.dirty) return;
|
|
197
|
+
try {
|
|
198
|
+
this.ensureDir();
|
|
199
|
+
const data = {
|
|
200
|
+
version: 1,
|
|
201
|
+
findings: [...this.findings.values()]
|
|
202
|
+
};
|
|
203
|
+
writeFileSync2(this.tmpPath, JSON.stringify(data));
|
|
204
|
+
renameSync(this.tmpPath, this.findingsPath);
|
|
205
|
+
this.dirty = false;
|
|
206
|
+
} catch (err) {
|
|
207
|
+
process.stderr.write(
|
|
208
|
+
`[brakit] failed to save findings: ${err.message}
|
|
209
|
+
`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async writeAsync() {
|
|
214
|
+
if (this.writing) return;
|
|
215
|
+
this.writing = true;
|
|
216
|
+
try {
|
|
217
|
+
if (!existsSync2(this.metricsDir)) {
|
|
218
|
+
await mkdir(this.metricsDir, { recursive: true });
|
|
219
|
+
ensureGitignore(this.metricsDir, METRICS_DIR);
|
|
220
|
+
}
|
|
221
|
+
const data = {
|
|
222
|
+
version: 1,
|
|
223
|
+
findings: [...this.findings.values()]
|
|
224
|
+
};
|
|
225
|
+
await writeFile2(this.tmpPath, JSON.stringify(data));
|
|
226
|
+
await rename(this.tmpPath, this.findingsPath);
|
|
227
|
+
this.dirty = false;
|
|
228
|
+
} catch (err) {
|
|
229
|
+
process.stderr.write(
|
|
230
|
+
`[brakit] failed to save findings: ${err.message}
|
|
231
|
+
`
|
|
232
|
+
);
|
|
233
|
+
} finally {
|
|
234
|
+
this.writing = false;
|
|
235
|
+
if (this.dirty) this.writeAsync();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
ensureDir() {
|
|
239
|
+
if (!existsSync2(this.metricsDir)) {
|
|
240
|
+
mkdirSync2(this.metricsDir, { recursive: true });
|
|
241
|
+
ensureGitignore(this.metricsDir, METRICS_DIR);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
};
|
|
17
245
|
|
|
18
246
|
// src/detect/project.ts
|
|
247
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
248
|
+
import { join } from "path";
|
|
19
249
|
var FRAMEWORKS = [
|
|
20
250
|
{ name: "nextjs", dep: "next", devCmd: "next dev", bin: "next", defaultPort: 3e3, devArgs: ["dev", "--port"] },
|
|
21
251
|
{ name: "remix", dep: "@remix-run/dev", devCmd: "remix dev", bin: "remix", defaultPort: 3e3, devArgs: ["dev"] },
|
|
@@ -409,6 +639,30 @@ var corsCredentialsRule = {
|
|
|
409
639
|
}
|
|
410
640
|
};
|
|
411
641
|
|
|
642
|
+
// src/utils/response.ts
|
|
643
|
+
function unwrapResponse(parsed) {
|
|
644
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return parsed;
|
|
645
|
+
const obj = parsed;
|
|
646
|
+
const keys = Object.keys(obj);
|
|
647
|
+
if (keys.length > 3) return parsed;
|
|
648
|
+
let best = null;
|
|
649
|
+
let bestSize = 0;
|
|
650
|
+
for (const key of keys) {
|
|
651
|
+
const val = obj[key];
|
|
652
|
+
if (Array.isArray(val) && val.length > bestSize) {
|
|
653
|
+
best = val;
|
|
654
|
+
bestSize = val.length;
|
|
655
|
+
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
656
|
+
const size = Object.keys(val).length;
|
|
657
|
+
if (size > bestSize) {
|
|
658
|
+
best = val;
|
|
659
|
+
bestSize = size;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return best && bestSize >= OVERFETCH_UNWRAP_MIN_SIZE ? best : parsed;
|
|
664
|
+
}
|
|
665
|
+
|
|
412
666
|
// src/analysis/rules/response-pii-leak.ts
|
|
413
667
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
|
|
414
668
|
var FULL_RECORD_MIN_FIELDS = 5;
|
|
@@ -453,28 +707,6 @@ function hasInternalIds(obj) {
|
|
|
453
707
|
}
|
|
454
708
|
return false;
|
|
455
709
|
}
|
|
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
710
|
function detectPII(method, reqBody, resBody) {
|
|
479
711
|
const target = unwrapResponse(resBody);
|
|
480
712
|
if (WRITE_METHODS.has(method) && reqBody && typeof reqBody === "object") {
|
|
@@ -593,41 +825,6 @@ function createDefaultScanner() {
|
|
|
593
825
|
return scanner;
|
|
594
826
|
}
|
|
595
827
|
|
|
596
|
-
// src/constants/routes.ts
|
|
597
|
-
var DASHBOARD_PREFIX = "/__brakit";
|
|
598
|
-
|
|
599
|
-
// src/constants/limits.ts
|
|
600
|
-
var MAX_REQUEST_ENTRIES = 1e3;
|
|
601
|
-
var MAX_TELEMETRY_ENTRIES = 1e3;
|
|
602
|
-
|
|
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
828
|
// src/utils/static-patterns.ts
|
|
632
829
|
var STATIC_PATTERNS = [
|
|
633
830
|
/^\/_next\//,
|
|
@@ -776,15 +973,15 @@ function getEndpointKey(method, path) {
|
|
|
776
973
|
|
|
777
974
|
// src/store/metrics/persistence.ts
|
|
778
975
|
import {
|
|
779
|
-
readFileSync as
|
|
780
|
-
writeFileSync as
|
|
781
|
-
mkdirSync as
|
|
782
|
-
existsSync as
|
|
976
|
+
readFileSync as readFileSync3,
|
|
977
|
+
writeFileSync as writeFileSync3,
|
|
978
|
+
mkdirSync as mkdirSync3,
|
|
979
|
+
existsSync as existsSync3,
|
|
783
980
|
unlinkSync,
|
|
784
|
-
renameSync
|
|
981
|
+
renameSync as renameSync2
|
|
785
982
|
} from "fs";
|
|
786
|
-
import { writeFile as
|
|
787
|
-
import { resolve as
|
|
983
|
+
import { writeFile as writeFile3, mkdir as mkdir2, rename as rename2 } from "fs/promises";
|
|
984
|
+
import { resolve as resolve3 } from "path";
|
|
788
985
|
|
|
789
986
|
// src/analysis/group.ts
|
|
790
987
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
@@ -1642,30 +1839,6 @@ var highRowsRule = {
|
|
|
1642
1839
|
}
|
|
1643
1840
|
};
|
|
1644
1841
|
|
|
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
1842
|
// src/analysis/insights/rules/response-overfetch.ts
|
|
1670
1843
|
var responseOverfetchRule = {
|
|
1671
1844
|
id: "response-overfetch",
|
|
@@ -1682,7 +1855,7 @@ var responseOverfetchRule = {
|
|
|
1682
1855
|
} catch {
|
|
1683
1856
|
continue;
|
|
1684
1857
|
}
|
|
1685
|
-
const target =
|
|
1858
|
+
const target = unwrapResponse(parsed);
|
|
1686
1859
|
const inspectObj = Array.isArray(target) && target.length > 0 ? target[0] : target;
|
|
1687
1860
|
if (!inspectObj || typeof inspectObj !== "object" || Array.isArray(inspectObj)) continue;
|
|
1688
1861
|
const fields = Object.keys(inspectObj);
|
|
@@ -1819,8 +1992,9 @@ function computeInsights(ctx) {
|
|
|
1819
1992
|
|
|
1820
1993
|
// src/analysis/engine.ts
|
|
1821
1994
|
var AnalysisEngine = class {
|
|
1822
|
-
constructor(metricsStore, debounceMs = 300) {
|
|
1995
|
+
constructor(metricsStore, findingStore, debounceMs = 300) {
|
|
1823
1996
|
this.metricsStore = metricsStore;
|
|
1997
|
+
this.findingStore = findingStore;
|
|
1824
1998
|
this.debounceMs = debounceMs;
|
|
1825
1999
|
this.scanner = createDefaultScanner();
|
|
1826
2000
|
this.boundRequestListener = () => this.scheduleRecompute();
|
|
@@ -1881,6 +2055,12 @@ var AnalysisEngine = class {
|
|
|
1881
2055
|
const fetches = defaultFetchStore.getAll();
|
|
1882
2056
|
const flows = groupRequestsIntoFlows(requests);
|
|
1883
2057
|
this.cachedFindings = this.scanner.scan({ requests, logs });
|
|
2058
|
+
if (this.findingStore) {
|
|
2059
|
+
for (const finding of this.cachedFindings) {
|
|
2060
|
+
this.findingStore.upsert(finding, "passive");
|
|
2061
|
+
}
|
|
2062
|
+
this.findingStore.reconcilePassive(this.cachedFindings);
|
|
2063
|
+
}
|
|
1884
2064
|
this.cachedInsights = computeInsights({
|
|
1885
2065
|
requests,
|
|
1886
2066
|
queries,
|
|
@@ -1900,10 +2080,11 @@ var AnalysisEngine = class {
|
|
|
1900
2080
|
};
|
|
1901
2081
|
|
|
1902
2082
|
// src/index.ts
|
|
1903
|
-
var VERSION = "0.
|
|
2083
|
+
var VERSION = "0.8.0";
|
|
1904
2084
|
export {
|
|
1905
2085
|
AdapterRegistry,
|
|
1906
2086
|
AnalysisEngine,
|
|
2087
|
+
FindingStore,
|
|
1907
2088
|
InsightRunner,
|
|
1908
2089
|
SecurityScanner,
|
|
1909
2090
|
VERSION,
|