@justmpm/firebase-audit 0.5.6 → 0.5.7
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/{chunk-SH6HFX5Y.js → chunk-BHRZOZYA.js} +3 -3
- package/dist/{chunk-DIO36A3I.js → chunk-CSMT4PIP.js} +13 -6
- package/dist/{chunk-XZ32YQQC.js → chunk-LD3F73XI.js} +13 -3
- package/dist/{chunk-BB6XXEIK.js → chunk-LJW7QXIJ.js} +50 -12
- package/dist/cli.js +5 -5
- package/dist/{drift-QXALNO2V.js → drift-C3JZI5ZA.js} +1 -1
- package/dist/index.js +4 -4
- package/dist/mcp-cli.js +4 -4
- package/dist/mcp.js +4 -4
- package/dist/{scan-SDJSDRDQ.js → scan-A34FDN66.js} +1 -1
- package/dist/{verify-DECP4IUW.js → verify-GQSR4FQL.js} +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
scan
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LJW7QXIJ.js";
|
|
4
4
|
import {
|
|
5
5
|
verify
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CSMT4PIP.js";
|
|
7
7
|
import {
|
|
8
8
|
drift
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LD3F73XI.js";
|
|
10
10
|
|
|
11
11
|
// src/mcp.ts
|
|
12
12
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/verify.ts
|
|
2
|
-
import { readFileSync, existsSync } from "fs";
|
|
3
|
-
function collectVisitCounts(node, out) {
|
|
4
|
-
if (typeof node !== "object" || node === null) return;
|
|
2
|
+
import { readFileSync, existsSync, statSync } from "fs";
|
|
3
|
+
function collectVisitCounts(node, out, depth = 0) {
|
|
4
|
+
if (typeof node !== "object" || node === null || depth > 100) return;
|
|
5
5
|
if (Array.isArray(node)) {
|
|
6
|
-
for (const v of node) collectVisitCounts(v, out);
|
|
6
|
+
for (const v of node) collectVisitCounts(v, out, depth + 1);
|
|
7
7
|
return;
|
|
8
8
|
}
|
|
9
9
|
const rec = node;
|
|
@@ -14,7 +14,7 @@ function collectVisitCounts(node, out) {
|
|
|
14
14
|
break;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
for (const v of Object.values(rec)) collectVisitCounts(v, out);
|
|
17
|
+
for (const v of Object.values(rec)) collectVisitCounts(v, out, depth + 1);
|
|
18
18
|
}
|
|
19
19
|
function planVerify(model) {
|
|
20
20
|
const roles = model.authorization.roles.length > 0 ? model.authorization.roles.map((r) => r.name) : ["anonymous", "user", "admin"];
|
|
@@ -63,6 +63,13 @@ function verify(model, opts = {}) {
|
|
|
63
63
|
});
|
|
64
64
|
} else {
|
|
65
65
|
try {
|
|
66
|
+
let tooBig = false;
|
|
67
|
+
try {
|
|
68
|
+
tooBig = statSync(opts.coverageFile).size > 5 * 1024 * 1024;
|
|
69
|
+
} catch {
|
|
70
|
+
tooBig = false;
|
|
71
|
+
}
|
|
72
|
+
if (tooBig) throw new Error("coverage acima de 5 MB");
|
|
66
73
|
const raw = JSON.parse(readFileSync(opts.coverageFile, "utf-8"));
|
|
67
74
|
const counts = [];
|
|
68
75
|
collectVisitCounts(raw, counts);
|
|
@@ -95,7 +102,7 @@ function verify(model, opts = {}) {
|
|
|
95
102
|
rule: "COVERAGE_INVALID",
|
|
96
103
|
severity: "WARNING",
|
|
97
104
|
confidence: "CONFIRMED",
|
|
98
|
-
message: "Arquivo de cobertura inv\xE1lido \u2014 Verifier sem cobertura neste run.",
|
|
105
|
+
message: "Arquivo de cobertura inv\xE1lido ou acima de 5 MB \u2014 Verifier sem cobertura neste run.",
|
|
99
106
|
fingerprint: "COVERAGE_INVALID",
|
|
100
107
|
evidence: [{ id: "ev-coverage", kind: "coverage-parse", summary: "JSON inv\xE1lido", confidence: "CONFIRMED" }]
|
|
101
108
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/drift.ts
|
|
2
|
-
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { readFileSync, existsSync, statSync } from "fs";
|
|
3
3
|
function normalizeMode(f) {
|
|
4
4
|
if (typeof f.fieldPath !== "string" || f.fieldPath.length === 0) return null;
|
|
5
5
|
if (f.vectorConfig !== void 0 && f.vectorConfig !== null) return { fieldPath: f.fieldPath, mode: "VECTOR" };
|
|
@@ -59,10 +59,19 @@ function drift(localFile, remoteFile) {
|
|
|
59
59
|
});
|
|
60
60
|
return { entries: [], findings };
|
|
61
61
|
}
|
|
62
|
+
const tooLarge = (f) => {
|
|
63
|
+
if (!f || !existsSync(f)) return false;
|
|
64
|
+
try {
|
|
65
|
+
return statSync(f).size > 5 * 1024 * 1024;
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
62
70
|
let local = [];
|
|
63
71
|
let remote = [];
|
|
64
72
|
if (localFile && existsSync(localFile)) {
|
|
65
73
|
try {
|
|
74
|
+
if (tooLarge(localFile)) throw new Error("local acima de 5 MB");
|
|
66
75
|
const raw = JSON.parse(readFileSync(localFile, "utf-8"));
|
|
67
76
|
const rawIndexes = normalizeList(raw);
|
|
68
77
|
const parsed = [];
|
|
@@ -88,7 +97,7 @@ function drift(localFile, remoteFile) {
|
|
|
88
97
|
rule: "DRIFT_LOCAL_INVALID",
|
|
89
98
|
severity: "WARNING",
|
|
90
99
|
confidence: "CONFIRMED",
|
|
91
|
-
message: "\xCDndices locais inv\xE1lidos \u2014 drift sem base local.",
|
|
100
|
+
message: "\xCDndices locais inv\xE1lidos ou acima de 5 MB \u2014 drift sem base local.",
|
|
92
101
|
fingerprint: "DRIFT_LOCAL_INVALID",
|
|
93
102
|
evidence: [{ id: "ev-drift-local", kind: "drift-parse", summary: "local inv\xE1lido", confidence: "CONFIRMED" }]
|
|
94
103
|
});
|
|
@@ -96,6 +105,7 @@ function drift(localFile, remoteFile) {
|
|
|
96
105
|
}
|
|
97
106
|
if (remoteFile && existsSync(remoteFile)) {
|
|
98
107
|
try {
|
|
108
|
+
if (tooLarge(remoteFile)) throw new Error("remoto acima de 5 MB");
|
|
99
109
|
const list = normalizeList(JSON.parse(readFileSync(remoteFile, "utf-8")));
|
|
100
110
|
const parsed = [];
|
|
101
111
|
let skipped = 0;
|
|
@@ -120,7 +130,7 @@ function drift(localFile, remoteFile) {
|
|
|
120
130
|
rule: "DRIFT_REMOTE_INVALID",
|
|
121
131
|
severity: "WARNING",
|
|
122
132
|
confidence: "CONFIRMED",
|
|
123
|
-
message: "\xCDndices remotos inv\xE1lidos \u2014 drift sem base remota.",
|
|
133
|
+
message: "\xCDndices remotos inv\xE1lidos ou acima de 5 MB \u2014 drift sem base remota.",
|
|
124
134
|
fingerprint: "DRIFT_REMOTE_INVALID",
|
|
125
135
|
evidence: [{ id: "ev-drift-remote", kind: "drift-parse", summary: "remoto inv\xE1lido", confidence: "CONFIRMED" }]
|
|
126
136
|
});
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-FECVBQUO.js";
|
|
13
13
|
|
|
14
14
|
// src/scan.ts
|
|
15
|
-
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
|
|
15
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
16
16
|
import { join as join3 } from "path";
|
|
17
17
|
import { parse as parseYaml } from "yaml";
|
|
18
18
|
|
|
@@ -123,6 +123,8 @@ function classifyOrigin(file, content) {
|
|
|
123
123
|
if (rel.includes("src/app/api/")) return "SERVER";
|
|
124
124
|
if (rel.includes("server/api/")) return "SERVER";
|
|
125
125
|
if (hasSeg(...SERVER_HINTS_SEGMENTS)) return "SERVER";
|
|
126
|
+
const base = segs[segs.length - 1] ?? "";
|
|
127
|
+
if (/^(server|middleware)[.\-]/i.test(base)) return "SERVER";
|
|
126
128
|
if (content.includes("firebase-admin") || content.includes("firebase-functions")) {
|
|
127
129
|
return "CLIENT";
|
|
128
130
|
}
|
|
@@ -161,14 +163,14 @@ async function enrichWithGraph(rootDir, d) {
|
|
|
161
163
|
const res = await ai.map({ cwd: rootDir, format: "json" });
|
|
162
164
|
const files = Array.isArray(res.files) ? res.files : [];
|
|
163
165
|
const code = files.map((f) => String(f.path).replace(/\\/g, "/")).filter((p) => /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(p)).filter((p) => !p.includes("node_modules/") && !/(^|\/)(dist|build|\.next|coverage|lib)\//.test(p)).slice(0, 500);
|
|
164
|
-
const { readFileSync: readSync, existsSync: existsSyncFn, statSync:
|
|
166
|
+
const { readFileSync: readSync, existsSync: existsSyncFn, statSync: statSync3 } = await import("fs");
|
|
165
167
|
const { join: joinP } = await import("path");
|
|
166
168
|
for (const rel of code) {
|
|
167
169
|
let content = "";
|
|
168
170
|
try {
|
|
169
171
|
const abs = joinP(rootDir, rel);
|
|
170
172
|
if (!existsSyncFn(abs)) continue;
|
|
171
|
-
if (
|
|
173
|
+
if (statSync3(abs).size > 100 * 1024) continue;
|
|
172
174
|
content = readSync(abs, "utf-8");
|
|
173
175
|
} catch {
|
|
174
176
|
content = "";
|
|
@@ -273,6 +275,26 @@ async function runChecks(model, rootDir, opts = {}) {
|
|
|
273
275
|
}
|
|
274
276
|
}
|
|
275
277
|
}
|
|
278
|
+
for (const rule of model.rules) {
|
|
279
|
+
if (rule.operations.length === 0) {
|
|
280
|
+
findings.push(
|
|
281
|
+
make(
|
|
282
|
+
"RULES_UNKNOWN_OP",
|
|
283
|
+
"WARNING",
|
|
284
|
+
"CONFIRMED",
|
|
285
|
+
`Opera\xE7\xE3o desconhecida em ${rule.path} (${rule.location.file}:${rule.location.start.line}). Typo em allow? Deploy rejeita.`,
|
|
286
|
+
`RULES_UNKNOWN_OP:${rule.path}:${rule.location.start.line}`,
|
|
287
|
+
{
|
|
288
|
+
file: rule.location.file,
|
|
289
|
+
line: rule.location.start.line,
|
|
290
|
+
resource: rule.path,
|
|
291
|
+
evidence: [ev("unknown-op", rule.condition ?? "allow sem opera\xE7\xE3o v\xE1lida", "CONFIRMED", rule.location.file, rule.location.start.line)],
|
|
292
|
+
fix: "Corrija para read/get/list/write/create/update/delete."
|
|
293
|
+
}
|
|
294
|
+
)
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
276
298
|
const adapterFn = opts.adapterFn ?? "rbac.can";
|
|
277
299
|
const permissionCalls = await collectPermissionCalls(rootDir, adapterFn);
|
|
278
300
|
const declared = new Set(model.authorization.permissions.map((p) => p.name));
|
|
@@ -976,13 +998,14 @@ async function scan(rootDir, opts = {}) {
|
|
|
976
998
|
if (d.firestoreRulesFile && existsSync3(d.firestoreRulesFile)) {
|
|
977
999
|
const rel = model.firebase.firestore.rulesFile ?? "firestore.rules";
|
|
978
1000
|
try {
|
|
1001
|
+
if (tooLarge(d.firestoreRulesFile, 1024 * 1024)) throw new Error("rules acima de 1 MB");
|
|
979
1002
|
model.rules = extractRules(d.firestoreRulesFile, rel);
|
|
980
1003
|
} catch {
|
|
981
1004
|
findings_pre.push({
|
|
982
1005
|
rule: "RULES_UNREADABLE",
|
|
983
1006
|
severity: "WARNING",
|
|
984
1007
|
confidence: "CONFIRMED",
|
|
985
|
-
message: "firestore.rules existe mas n\xE3o p\xF4de ser lido \u2014 FBA001/FBA002 sem cobertura.",
|
|
1008
|
+
message: "firestore.rules existe mas n\xE3o p\xF4de ser lido (ileg\xEDvel ou acima de 1 MB) \u2014 FBA001/FBA002 sem cobertura.",
|
|
986
1009
|
fingerprint: "RULES_UNREADABLE",
|
|
987
1010
|
evidence: [
|
|
988
1011
|
{ id: "ev-rules-unreadable", kind: "rules-read", summary: "leitura falhou", confidence: "CONFIRMED" }
|
|
@@ -992,6 +1015,7 @@ async function scan(rootDir, opts = {}) {
|
|
|
992
1015
|
}
|
|
993
1016
|
if (d.firestoreIndexesFile && existsSync3(d.firestoreIndexesFile)) {
|
|
994
1017
|
try {
|
|
1018
|
+
if (tooLarge(d.firestoreIndexesFile, 1024 * 1024)) throw new Error("indexes acima de 1 MB");
|
|
995
1019
|
const raw = JSON.parse(readFileSync3(d.firestoreIndexesFile, "utf-8"));
|
|
996
1020
|
if (Array.isArray(raw.fieldOverrides) && raw.fieldOverrides.length > 0) {
|
|
997
1021
|
findings_pre.push({
|
|
@@ -1062,7 +1086,7 @@ async function scan(rootDir, opts = {}) {
|
|
|
1062
1086
|
rule: "INDEXES_INVALID",
|
|
1063
1087
|
severity: "WARNING",
|
|
1064
1088
|
confidence: "CONFIRMED",
|
|
1065
|
-
message: "firestore.indexes.json inv\xE1lido \u2014 \xEDndices ignorados neste scan.",
|
|
1089
|
+
message: "firestore.indexes.json inv\xE1lido ou acima de 1 MB \u2014 \xEDndices ignorados neste scan.",
|
|
1066
1090
|
fingerprint: "INDEXES_INVALID",
|
|
1067
1091
|
evidence: [
|
|
1068
1092
|
{ id: "ev-indexes-invalid", kind: "indexes-parse", summary: "JSON inv\xE1lido", confidence: "CONFIRMED" }
|
|
@@ -1072,6 +1096,7 @@ async function scan(rootDir, opts = {}) {
|
|
|
1072
1096
|
}
|
|
1073
1097
|
if (d.auditYamlFile && existsSync3(d.auditYamlFile)) {
|
|
1074
1098
|
try {
|
|
1099
|
+
if (tooLarge(d.auditYamlFile, 256 * 1024)) throw new Error("yaml acima de 256 KB");
|
|
1075
1100
|
const text = readFileSync3(d.auditYamlFile, "utf-8");
|
|
1076
1101
|
const parsed = parseYaml(text);
|
|
1077
1102
|
const validated = AuditYamlSchema.safeParse(parsed);
|
|
@@ -1180,6 +1205,7 @@ async function scan(rootDir, opts = {}) {
|
|
|
1180
1205
|
if (d.storageRulesFile && existsSync3(d.storageRulesFile)) {
|
|
1181
1206
|
checked.push("storage.rules");
|
|
1182
1207
|
try {
|
|
1208
|
+
if (tooLarge(d.storageRulesFile, 1024 * 1024)) throw new Error("storage acima de 1 MB");
|
|
1183
1209
|
const raw = readFileSync3(d.storageRulesFile, "utf-8");
|
|
1184
1210
|
const relStorage = model.firebase.storage?.rulesFile ?? "storage.rules";
|
|
1185
1211
|
const clean = stripRuleComments(raw);
|
|
@@ -1288,13 +1314,13 @@ async function scan(rootDir, opts = {}) {
|
|
|
1288
1314
|
}
|
|
1289
1315
|
}
|
|
1290
1316
|
} catch {
|
|
1291
|
-
skipped.push("storage.rules ileg\xEDvel \u2014 Storage sem cobertura neste scan");
|
|
1317
|
+
skipped.push("storage.rules ileg\xEDvel ou acima de 1 MB \u2014 Storage sem cobertura neste scan");
|
|
1292
1318
|
}
|
|
1293
1319
|
} else {
|
|
1294
1320
|
skipped.push("storage.rules n\xE3o observado \u2014 Storage fora deste scan");
|
|
1295
1321
|
}
|
|
1296
1322
|
if (d.functionsDir) {
|
|
1297
|
-
const appcheck = await countAppCheckEnforced(rootDir);
|
|
1323
|
+
const appcheck = await countAppCheckEnforced(rootDir, d.functionsDir);
|
|
1298
1324
|
model.functions = { dir: model.functions?.dir, appCheckEnforced: appcheck.occurrences };
|
|
1299
1325
|
checked.push("functions-appcheck");
|
|
1300
1326
|
if (appcheck.manual > 0) {
|
|
@@ -1384,12 +1410,19 @@ async function scan(rootDir, opts = {}) {
|
|
|
1384
1410
|
}
|
|
1385
1411
|
};
|
|
1386
1412
|
}
|
|
1387
|
-
|
|
1413
|
+
function tooLarge(abs, maxBytes) {
|
|
1414
|
+
try {
|
|
1415
|
+
return statSync2(abs).size > maxBytes;
|
|
1416
|
+
} catch {
|
|
1417
|
+
return false;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
async function countAppCheckEnforced(rootDir, functionsDir) {
|
|
1388
1421
|
try {
|
|
1389
1422
|
const { readdirSync, readFileSync: readSync, statSync: stat } = await import("fs");
|
|
1390
1423
|
const { join: joinP } = await import("path");
|
|
1391
1424
|
const { stripRuleComments: strip } = await import("./rules-W4VUUQM4.js");
|
|
1392
|
-
const roots = [joinP(rootDir, "functions")];
|
|
1425
|
+
const roots = [functionsDir ?? joinP(rootDir, "functions")];
|
|
1393
1426
|
let occurrences = 0;
|
|
1394
1427
|
const files = /* @__PURE__ */ new Set();
|
|
1395
1428
|
let manual = 0;
|
|
@@ -1403,7 +1436,6 @@ async function countAppCheckEnforced(rootDir) {
|
|
|
1403
1436
|
};
|
|
1404
1437
|
while (stack.length > 0 && guard < 200) {
|
|
1405
1438
|
guard += 1;
|
|
1406
|
-
if (guard >= 200 && stack.length > 0) limitHit = true;
|
|
1407
1439
|
const cur = stack.pop();
|
|
1408
1440
|
let entries = [];
|
|
1409
1441
|
try {
|
|
@@ -1456,6 +1488,7 @@ async function countAppCheckEnforced(rootDir) {
|
|
|
1456
1488
|
}
|
|
1457
1489
|
}
|
|
1458
1490
|
}
|
|
1491
|
+
if (stack.length > 0) limitHit = true;
|
|
1459
1492
|
return { occurrences, files: files.size, manual, ignoredOnRequest, limitHit };
|
|
1460
1493
|
} catch {
|
|
1461
1494
|
return { occurrences: 0, files: 0, manual: 0, ignoredOnRequest: 0, limitHit: false };
|
|
@@ -1522,9 +1555,14 @@ function parseStorageAllows(clean) {
|
|
|
1522
1555
|
const re = /allow\s+([^;:]+?)(?::\s*if\s+([^;]+))?;/gi;
|
|
1523
1556
|
let m;
|
|
1524
1557
|
while ((m = re.exec(clean)) !== null) {
|
|
1525
|
-
const containing = matches.filter((b) => b.start <= m.index && m.index < b.end).sort((a, b) =>
|
|
1558
|
+
const containing = matches.filter((b) => b.start <= m.index && m.index < b.end).sort((a, b) => a.start - b.start);
|
|
1559
|
+
const parts = [];
|
|
1560
|
+
for (const b of containing) {
|
|
1561
|
+
const p = b.path.trim().replace(/^\/+|\/+$/g, "");
|
|
1562
|
+
if (p.length > 0) parts.push(p);
|
|
1563
|
+
}
|
|
1526
1564
|
const line = clean.slice(0, m.index).split("\n").length;
|
|
1527
|
-
out.push({ target: m[1].trim(), condition: m[2]?.trim(), matchPath:
|
|
1565
|
+
out.push({ target: m[1].trim(), condition: m[2]?.trim(), matchPath: parts.length > 0 ? `/${parts.join("/")}` : "/(unknown)", line });
|
|
1528
1566
|
}
|
|
1529
1567
|
return out;
|
|
1530
1568
|
}
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
scan
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LJW7QXIJ.js";
|
|
5
5
|
import "./chunk-FECVBQUO.js";
|
|
6
6
|
|
|
7
7
|
// src/cli.ts
|
|
@@ -81,8 +81,8 @@ Uso: firebase-audit scan|check|verify|drift [--json] ...`);
|
|
|
81
81
|
const { resolve: resolveRoot } = await import("path");
|
|
82
82
|
const rootDir = cwdArg ? resolveRoot(process.cwd(), cwdArg) : process.cwd();
|
|
83
83
|
if (cmd === "verify") {
|
|
84
|
-
const { scan: scanForVerify } = await import("./scan-
|
|
85
|
-
const { verify } = await import("./verify-
|
|
84
|
+
const { scan: scanForVerify } = await import("./scan-A34FDN66.js");
|
|
85
|
+
const { verify } = await import("./verify-GQSR4FQL.js");
|
|
86
86
|
const { resolve: resolveVerify } = await import("path");
|
|
87
87
|
const coverageArg = getArg("coverage");
|
|
88
88
|
const coveragePath = coverageArg ? resolveVerify(rootDir, coverageArg) : void 0;
|
|
@@ -116,7 +116,7 @@ ${icon} ${f.rule} [${f.confidence}]
|
|
|
116
116
|
return;
|
|
117
117
|
}
|
|
118
118
|
if (cmd === "drift") {
|
|
119
|
-
const { drift } = await import("./drift-
|
|
119
|
+
const { drift } = await import("./drift-C3JZI5ZA.js");
|
|
120
120
|
const { resolve: resolveDrift } = await import("path");
|
|
121
121
|
const { existsSync: existsDrift } = await import("fs");
|
|
122
122
|
const localArg = getArg("local");
|
|
@@ -130,7 +130,7 @@ ${icon} ${f.rule} [${f.confidence}]
|
|
|
130
130
|
for (const [label, p] of [["--local", localPath], ["--remote", remotePath]]) {
|
|
131
131
|
if (p && !existsDrift(p)) {
|
|
132
132
|
if (asJson) {
|
|
133
|
-
const { drift: driftMissing } = await import("./drift-
|
|
133
|
+
const { drift: driftMissing } = await import("./drift-C3JZI5ZA.js");
|
|
134
134
|
const res2 = driftMissing(
|
|
135
135
|
localPath && existsDrift(localPath) ? localPath : null,
|
|
136
136
|
remotePath && existsDrift(remotePath) ? remotePath : null
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMcpServer,
|
|
3
3
|
startMcpServer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BHRZOZYA.js";
|
|
5
5
|
import {
|
|
6
6
|
AccessOriginSchema,
|
|
7
7
|
AuditYamlSchema,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
runChecks,
|
|
34
34
|
scan,
|
|
35
35
|
validateClaimSamples
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-LJW7QXIJ.js";
|
|
37
37
|
import {
|
|
38
38
|
buildFullPath,
|
|
39
39
|
conditionKeyForFingerprint,
|
|
@@ -59,10 +59,10 @@ import {
|
|
|
59
59
|
import {
|
|
60
60
|
planVerify,
|
|
61
61
|
verify
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-CSMT4PIP.js";
|
|
63
63
|
import {
|
|
64
64
|
drift
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-LD3F73XI.js";
|
|
66
66
|
|
|
67
67
|
// src/index.ts
|
|
68
68
|
import { createRequire } from "module";
|
package/dist/mcp-cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startMcpServer
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-BHRZOZYA.js";
|
|
5
|
+
import "./chunk-LJW7QXIJ.js";
|
|
6
6
|
import "./chunk-FECVBQUO.js";
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-CSMT4PIP.js";
|
|
8
|
+
import "./chunk-LD3F73XI.js";
|
|
9
9
|
|
|
10
10
|
// src/mcp-cli.ts
|
|
11
11
|
startMcpServer().catch((err) => {
|
package/dist/mcp.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMcpServer,
|
|
3
3
|
startMcpServer
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-BHRZOZYA.js";
|
|
5
|
+
import "./chunk-LJW7QXIJ.js";
|
|
6
6
|
import "./chunk-FECVBQUO.js";
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-CSMT4PIP.js";
|
|
8
|
+
import "./chunk-LD3F73XI.js";
|
|
9
9
|
export {
|
|
10
10
|
createMcpServer,
|
|
11
11
|
startMcpServer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justmpm/firebase-audit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.7",
|
|
4
4
|
"description": "Auditor de consistência e segurança para projetos Firebase: código + Rules + índices + contrato vs comportamento. Static-first, nunca inventa certeza.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"firebase",
|