brakit 0.9.1 → 0.10.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/dist/api.d.ts +142 -0
- package/dist/api.js +212 -42
- package/dist/bin/brakit.js +138 -19
- package/dist/dashboard-client.global.js +587 -276
- package/dist/dashboard.html +691 -276
- package/dist/mcp/server.js +4 -2
- package/dist/runtime/index.js +1103 -74
- package/package.json +1 -1
package/dist/bin/brakit.js
CHANGED
|
@@ -73,7 +73,7 @@ var init_type_guards = __esm({
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
// src/constants/labels.ts
|
|
76
|
-
var DASHBOARD_PREFIX, DASHBOARD_API_REQUESTS, DASHBOARD_API_EVENTS, DASHBOARD_API_FLOWS, DASHBOARD_API_CLEAR, DASHBOARD_API_LOGS, DASHBOARD_API_FETCHES, DASHBOARD_API_ERRORS, DASHBOARD_API_QUERIES, DASHBOARD_API_INGEST, DASHBOARD_API_METRICS, DASHBOARD_API_ACTIVITY, DASHBOARD_API_METRICS_LIVE, DASHBOARD_API_INSIGHTS, DASHBOARD_API_SECURITY, DASHBOARD_API_TAB, DASHBOARD_API_FINDINGS, DASHBOARD_API_FINDINGS_REPORT, VALID_TABS_TUPLE, VALID_TABS, POSTHOG_HOST, POSTHOG_CAPTURE_PATH, POSTHOG_REQUEST_TIMEOUT_MS;
|
|
76
|
+
var DASHBOARD_PREFIX, DASHBOARD_API_REQUESTS, DASHBOARD_API_EVENTS, DASHBOARD_API_FLOWS, DASHBOARD_API_CLEAR, DASHBOARD_API_LOGS, DASHBOARD_API_FETCHES, DASHBOARD_API_ERRORS, DASHBOARD_API_QUERIES, DASHBOARD_API_INGEST, DASHBOARD_API_METRICS, DASHBOARD_API_ACTIVITY, DASHBOARD_API_METRICS_LIVE, DASHBOARD_API_INSIGHTS, DASHBOARD_API_SECURITY, DASHBOARD_API_TAB, DASHBOARD_API_FINDINGS, DASHBOARD_API_FINDINGS_REPORT, DASHBOARD_API_GRAPH, VALID_TABS_TUPLE, VALID_TABS, POSTHOG_HOST, POSTHOG_CAPTURE_PATH, POSTHOG_REQUEST_TIMEOUT_MS;
|
|
77
77
|
var init_labels = __esm({
|
|
78
78
|
"src/constants/labels.ts"() {
|
|
79
79
|
"use strict";
|
|
@@ -95,6 +95,7 @@ var init_labels = __esm({
|
|
|
95
95
|
DASHBOARD_API_TAB = `${DASHBOARD_PREFIX}/api/tab`;
|
|
96
96
|
DASHBOARD_API_FINDINGS = `${DASHBOARD_PREFIX}/api/findings`;
|
|
97
97
|
DASHBOARD_API_FINDINGS_REPORT = `${DASHBOARD_PREFIX}/api/findings/report`;
|
|
98
|
+
DASHBOARD_API_GRAPH = `${DASHBOARD_PREFIX}/api/graph`;
|
|
98
99
|
VALID_TABS_TUPLE = [
|
|
99
100
|
"overview",
|
|
100
101
|
"actions",
|
|
@@ -104,7 +105,8 @@ var init_labels = __esm({
|
|
|
104
105
|
"errors",
|
|
105
106
|
"logs",
|
|
106
107
|
"performance",
|
|
107
|
-
"security"
|
|
108
|
+
"security",
|
|
109
|
+
"graph"
|
|
108
110
|
];
|
|
109
111
|
VALID_TABS = new Set(VALID_TABS_TUPLE);
|
|
110
112
|
POSTHOG_HOST = "https://us.i.posthog.com";
|
|
@@ -138,7 +140,7 @@ var init_features = __esm({
|
|
|
138
140
|
MAX_TIMELINE_EVENTS = 20;
|
|
139
141
|
MAX_RESOLVED_DISPLAY = 5;
|
|
140
142
|
ENRICHMENT_SEVERITY_FILTER = ["critical", "warning"];
|
|
141
|
-
MCP_SERVER_VERSION = "0.
|
|
143
|
+
MCP_SERVER_VERSION = "0.10.0";
|
|
142
144
|
RECOVERY_WINDOW_MS = 5 * 60 * 1e3;
|
|
143
145
|
PORT_MIN = 1;
|
|
144
146
|
PORT_MAX = 65535;
|
|
@@ -1063,7 +1065,7 @@ import { defineCommand } from "citty";
|
|
|
1063
1065
|
import { resolve as resolve3, join as join3, dirname } from "path";
|
|
1064
1066
|
import { readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
|
|
1065
1067
|
import { execSync } from "child_process";
|
|
1066
|
-
import { existsSync as existsSync5 } from "fs";
|
|
1068
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
1067
1069
|
import pc from "picocolors";
|
|
1068
1070
|
|
|
1069
1071
|
// src/store/issue-store.ts
|
|
@@ -1207,7 +1209,8 @@ async function detectPythonFramework(rootDir, hasPyproject, hasRequirements) {
|
|
|
1207
1209
|
const content = await readFile3(join2(rootDir, "requirements.txt"), "utf-8");
|
|
1208
1210
|
const lines = content.toLowerCase().split("\n");
|
|
1209
1211
|
for (const [dep, fw] of Object.entries(PYTHON_FRAMEWORK_MAP)) {
|
|
1210
|
-
|
|
1212
|
+
const versionChars = /* @__PURE__ */ new Set(["=", "<", ">", "~", "!", "["]);
|
|
1213
|
+
if (lines.some((l) => l.startsWith(dep) && (l.length === dep.length || versionChars.has(l[dep.length])))) {
|
|
1211
1214
|
return fw;
|
|
1212
1215
|
}
|
|
1213
1216
|
}
|
|
@@ -1313,20 +1316,115 @@ init_log();
|
|
|
1313
1316
|
init_type_guards();
|
|
1314
1317
|
|
|
1315
1318
|
// src/analysis/rules/patterns.ts
|
|
1316
|
-
var
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
+
var SECRET_KEY_SET = /* @__PURE__ */ new Set([
|
|
1320
|
+
"password",
|
|
1321
|
+
"passwd",
|
|
1322
|
+
"secret",
|
|
1323
|
+
"api_key",
|
|
1324
|
+
"apiKey",
|
|
1325
|
+
"api_secret",
|
|
1326
|
+
"apiSecret",
|
|
1327
|
+
"private_key",
|
|
1328
|
+
"privateKey",
|
|
1329
|
+
"client_secret",
|
|
1330
|
+
"clientSecret"
|
|
1331
|
+
]);
|
|
1332
|
+
var SECRET_KEYS = { test: (s) => SECRET_KEY_SET.has(s) };
|
|
1333
|
+
var TOKEN_PARAM_SET = /* @__PURE__ */ new Set([
|
|
1334
|
+
"token",
|
|
1335
|
+
"api_key",
|
|
1336
|
+
"apiKey",
|
|
1337
|
+
"secret",
|
|
1338
|
+
"password",
|
|
1339
|
+
"access_token",
|
|
1340
|
+
"session_id",
|
|
1341
|
+
"sessionId"
|
|
1342
|
+
]);
|
|
1343
|
+
var TOKEN_PARAMS = { test: (s) => TOKEN_PARAM_SET.has(s) };
|
|
1344
|
+
var SAFE_PARAM_SET = /* @__PURE__ */ new Set([
|
|
1345
|
+
"_rsc",
|
|
1346
|
+
"__clerk_handshake",
|
|
1347
|
+
"__clerk_db_jwt",
|
|
1348
|
+
"callback",
|
|
1349
|
+
"code",
|
|
1350
|
+
"state",
|
|
1351
|
+
"nonce",
|
|
1352
|
+
"redirect_uri",
|
|
1353
|
+
"utm_",
|
|
1354
|
+
"fbclid",
|
|
1355
|
+
"gclid"
|
|
1356
|
+
]);
|
|
1357
|
+
var SAFE_PARAMS = { test: (s) => SAFE_PARAM_SET.has(s) };
|
|
1358
|
+
var INTERNAL_ID_KEY_SET = /* @__PURE__ */ new Set([
|
|
1359
|
+
"id",
|
|
1360
|
+
"_id",
|
|
1361
|
+
"userId",
|
|
1362
|
+
"user_id",
|
|
1363
|
+
"createdBy",
|
|
1364
|
+
"updatedBy",
|
|
1365
|
+
"organizationId",
|
|
1366
|
+
"org_id",
|
|
1367
|
+
"tenantId",
|
|
1368
|
+
"tenant_id"
|
|
1369
|
+
]);
|
|
1370
|
+
var INTERNAL_ID_KEYS = { test: (s) => INTERNAL_ID_KEY_SET.has(s) };
|
|
1371
|
+
var INTERNAL_ID_SUFFIX = {
|
|
1372
|
+
test: (s) => s.endsWith("Id") || s.endsWith("_id")
|
|
1373
|
+
};
|
|
1374
|
+
var SENSITIVE_FIELD_SET = /* @__PURE__ */ new Set([
|
|
1375
|
+
"phone",
|
|
1376
|
+
"phonenumber",
|
|
1377
|
+
"phone_number",
|
|
1378
|
+
"ssn",
|
|
1379
|
+
"socialsecuritynumber",
|
|
1380
|
+
"social_security_number",
|
|
1381
|
+
"dateofbirth",
|
|
1382
|
+
"date_of_birth",
|
|
1383
|
+
"dob",
|
|
1384
|
+
"address",
|
|
1385
|
+
"streetaddress",
|
|
1386
|
+
"street_address",
|
|
1387
|
+
"creditcard",
|
|
1388
|
+
"credit_card",
|
|
1389
|
+
"cardnumber",
|
|
1390
|
+
"card_number",
|
|
1391
|
+
"bankaccount",
|
|
1392
|
+
"bank_account",
|
|
1393
|
+
"passport",
|
|
1394
|
+
"passportnumber",
|
|
1395
|
+
"passport_number",
|
|
1396
|
+
"nationalid",
|
|
1397
|
+
"national_id"
|
|
1398
|
+
]);
|
|
1399
|
+
var SENSITIVE_FIELD_NAMES = {
|
|
1400
|
+
test: (s) => SENSITIVE_FIELD_SET.has(s.toLowerCase())
|
|
1401
|
+
};
|
|
1402
|
+
var SELF_SERVICE_SEGMENTS = /* @__PURE__ */ new Set(["me", "account", "profile", "settings", "self"]);
|
|
1403
|
+
var SELF_SERVICE_PATH = {
|
|
1404
|
+
test: (path) => {
|
|
1405
|
+
const segments = path.toLowerCase().split(/[/?#]/);
|
|
1406
|
+
return segments.some((seg) => SELF_SERVICE_SEGMENTS.has(seg));
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
var MASKED_LITERALS = ["[REDACTED]", "[FILTERED]", "CHANGE_ME"];
|
|
1410
|
+
var MASKED_RE = {
|
|
1411
|
+
test: (s) => {
|
|
1412
|
+
const upper = s.toUpperCase();
|
|
1413
|
+
if (MASKED_LITERALS.some((m) => upper.includes(m))) return true;
|
|
1414
|
+
if (s.length > 0 && s.split("").every((c) => c === "*")) return true;
|
|
1415
|
+
if (s.length >= 3 && s.split("").every((c) => c === "x" || c === "X")) return true;
|
|
1416
|
+
return false;
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
var DB_PROTOCOLS = ["postgres://", "mysql://", "mongodb://", "redis://"];
|
|
1420
|
+
var DB_CONN_RE = {
|
|
1421
|
+
test: (s) => DB_PROTOCOLS.some((p) => s.includes(p))
|
|
1422
|
+
};
|
|
1319
1423
|
var STACK_TRACE_RE = /at\s+.+\(.+:\d+:\d+\)|at\s+Module\._compile|at\s+Object\.<anonymous>|at\s+processTicksAndRejections|Traceback \(most recent call last\)|File ".+", line \d+/;
|
|
1320
|
-
var DB_CONN_RE = /(postgres|mysql|mongodb|redis):\/\//;
|
|
1321
1424
|
var SQL_FRAGMENT_RE = /\b(SELECT\s+[\w.*]+\s+FROM|INSERT\s+INTO|UPDATE\s+\w+\s+SET|DELETE\s+FROM)\b/i;
|
|
1322
1425
|
var SECRET_VAL_RE = /(api_key|apiKey|secret|token)\s*[:=]\s*["']?[A-Za-z0-9_\-.+/]{8,}/;
|
|
1323
1426
|
var LOG_SECRET_RE = /(password|secret|token|api_key|apiKey)\s*[:=]\s*["']?[A-Za-z0-9_\-.+/]{8,}/i;
|
|
1324
|
-
var MASKED_RE = /^\*+$|\[REDACTED\]|\[FILTERED\]|CHANGE_ME|^x{3,}$/i;
|
|
1325
1427
|
var EMAIL_RE = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
|
|
1326
|
-
var INTERNAL_ID_KEYS = /^(id|_id|userId|user_id|createdBy|updatedBy|organizationId|org_id|tenantId|tenant_id)$/;
|
|
1327
|
-
var INTERNAL_ID_SUFFIX = /Id$|_id$/;
|
|
1328
|
-
var SELF_SERVICE_PATH = /\/(?:me|account|profile|settings|self)(?=\/|\?|#|$)/i;
|
|
1329
|
-
var SENSITIVE_FIELD_NAMES = /^(phone|phoneNumber|phone_number|ssn|socialSecurityNumber|social_security_number|dateOfBirth|date_of_birth|dob|address|streetAddress|street_address|creditCard|credit_card|cardNumber|card_number|bankAccount|bank_account|passport|passportNumber|passport_number|nationalId|national_id)$/i;
|
|
1330
1428
|
var RULE_HINTS = {
|
|
1331
1429
|
"exposed-secret": "Never include secret fields in API responses. Strip sensitive fields before returning.",
|
|
1332
1430
|
"token-in-url": "Pass tokens in the Authorization header, not URL query parameters.",
|
|
@@ -1812,7 +1910,7 @@ init_constants();
|
|
|
1812
1910
|
init_endpoint();
|
|
1813
1911
|
|
|
1814
1912
|
// src/index.ts
|
|
1815
|
-
var VERSION = "0.
|
|
1913
|
+
var VERSION = "0.10.0";
|
|
1816
1914
|
|
|
1817
1915
|
// src/cli/commands/install.ts
|
|
1818
1916
|
init_constants();
|
|
@@ -1915,6 +2013,14 @@ var install_default = defineCommand({
|
|
|
1915
2013
|
}
|
|
1916
2014
|
process.exit(1);
|
|
1917
2015
|
}
|
|
2016
|
+
const firstNode = nodeProjects[0];
|
|
2017
|
+
if (isFrontendOnly(firstNode.dir)) {
|
|
2018
|
+
console.log(pc.yellow(" \u26A0 This looks like a frontend-only app (React, Vue, etc.)."));
|
|
2019
|
+
console.log(pc.dim(" Brakit instruments your backend server, not the browser."));
|
|
2020
|
+
console.log(pc.dim(" Install brakit in your backend project instead (Express, Fastify, Next.js, etc.)."));
|
|
2021
|
+
console.log();
|
|
2022
|
+
process.exit(1);
|
|
2023
|
+
}
|
|
1918
2024
|
for (const p of nodeProjects) {
|
|
1919
2025
|
const node = p.node;
|
|
1920
2026
|
const suffix = p.relDir === "." ? "" : ` in ${p.relDir}`;
|
|
@@ -1951,9 +2057,8 @@ var install_default = defineCommand({
|
|
|
1951
2057
|
}
|
|
1952
2058
|
}
|
|
1953
2059
|
console.log();
|
|
1954
|
-
const port = nodeProjects[0].node?.defaultPort ?? 3e3;
|
|
1955
2060
|
console.log(pc.dim(" Start your app and visit:"));
|
|
1956
|
-
console.log(pc.bold(
|
|
2061
|
+
console.log(pc.bold(" http://localhost:<your-port>/__brakit"));
|
|
1957
2062
|
if (pythonProjects.length > 0) {
|
|
1958
2063
|
const pyLabel = pythonProjects.map((p) => p.relDir).join(", ");
|
|
1959
2064
|
console.log();
|
|
@@ -2105,6 +2210,20 @@ function findGitRoot(startDir) {
|
|
|
2105
2210
|
dir = parent;
|
|
2106
2211
|
}
|
|
2107
2212
|
}
|
|
2213
|
+
var FRONTEND_ONLY_DEPS = ["react", "vue", "svelte", "@angular/core", "solid-js", "preact"];
|
|
2214
|
+
var SERVER_DEPS = ["express", "fastify", "hono", "koa", "nest", "next", "@remix-run/dev", "nuxt", "astro"];
|
|
2215
|
+
function isFrontendOnly(rootDir) {
|
|
2216
|
+
try {
|
|
2217
|
+
const raw = readFileSync3(join3(rootDir, "package.json"), "utf-8");
|
|
2218
|
+
const pkg = JSON.parse(raw);
|
|
2219
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2220
|
+
const hasFrontend = FRONTEND_ONLY_DEPS.some((d) => d in allDeps);
|
|
2221
|
+
const hasServer = SERVER_DEPS.some((d) => d in allDeps);
|
|
2222
|
+
return hasFrontend && !hasServer;
|
|
2223
|
+
} catch {
|
|
2224
|
+
return false;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2108
2227
|
function printManualInstructions(framework) {
|
|
2109
2228
|
console.log(pc.yellow(" \u26A0 Could not auto-detect entry file."));
|
|
2110
2229
|
console.log();
|
|
@@ -2140,7 +2259,7 @@ import { spawn } from "child_process";
|
|
|
2140
2259
|
init_features();
|
|
2141
2260
|
import { homedir as homedir2, platform } from "os";
|
|
2142
2261
|
import { join as join4 } from "path";
|
|
2143
|
-
import { existsSync as existsSync6, readFileSync as
|
|
2262
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
2144
2263
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2145
2264
|
var IS_WINDOWS = platform() === "win32";
|
|
2146
2265
|
var CONFIG_DIR = join4(homedir2(), ".brakit");
|
|
@@ -2148,7 +2267,7 @@ var CONFIG_PATH = join4(CONFIG_DIR, "config.json");
|
|
|
2148
2267
|
function readConfig() {
|
|
2149
2268
|
try {
|
|
2150
2269
|
if (!existsSync6(CONFIG_PATH)) return null;
|
|
2151
|
-
return JSON.parse(
|
|
2270
|
+
return JSON.parse(readFileSync4(CONFIG_PATH, "utf-8"));
|
|
2152
2271
|
} catch {
|
|
2153
2272
|
return null;
|
|
2154
2273
|
}
|