@justmpm/firebase-audit 0.5.7 → 0.5.8
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-FECVBQUO.js → chunk-7J3ADEBW.js} +8 -4
- package/dist/{chunk-BHRZOZYA.js → chunk-D75SRJ7P.js} +6 -5
- package/dist/{chunk-LJW7QXIJ.js → chunk-NZT4NIVA.js} +29 -19
- package/dist/cli.js +6 -3
- package/dist/index.d.ts +8 -1
- package/dist/index.js +5 -3
- package/dist/mcp-cli.js +3 -3
- package/dist/mcp.js +3 -3
- package/dist/{rules-W4VUUQM4.js → rules-HCXATUST.js} +1 -1
- package/dist/scan-RTIMO3I2.js +7 -0
- package/package.json +1 -1
- package/skill/SKILL.md +1 -1
- package/dist/scan-A34FDN66.js +0 -7
|
@@ -42,11 +42,12 @@ function stripRuleComments(content) {
|
|
|
42
42
|
}
|
|
43
43
|
function opsFrom(target) {
|
|
44
44
|
const t = target.trim().toLowerCase();
|
|
45
|
-
if (t === "read") return { ops: ["read", "get", "list"], known: true };
|
|
46
|
-
if (t === "write") return { ops: ["write", "create", "update", "delete"], known: true };
|
|
45
|
+
if (t === "read") return { ops: ["read", "get", "list"], known: true, unknown: [] };
|
|
46
|
+
if (t === "write") return { ops: ["write", "create", "update", "delete"], known: true, unknown: [] };
|
|
47
47
|
const parts = t.split(",").map((s) => s.trim()).filter(Boolean);
|
|
48
48
|
const valid = ["read", "get", "list", "create", "update", "delete", "write"];
|
|
49
49
|
const out = [];
|
|
50
|
+
const unknown = [];
|
|
50
51
|
let known = false;
|
|
51
52
|
for (const p of parts) {
|
|
52
53
|
if (valid.includes(p)) {
|
|
@@ -62,9 +63,11 @@ function opsFrom(target) {
|
|
|
62
63
|
if (!out.includes(extra)) out.push(extra);
|
|
63
64
|
}
|
|
64
65
|
}
|
|
66
|
+
} else {
|
|
67
|
+
unknown.push(p);
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
|
-
return { ops: out, known: out.length > 0 && known };
|
|
70
|
+
return { ops: out, known: out.length > 0 && known, unknown };
|
|
68
71
|
}
|
|
69
72
|
function findBlockEnd(content, openBraceIndex) {
|
|
70
73
|
let depth = 0;
|
|
@@ -247,13 +250,14 @@ function extractRulesContent(rawContent, relFile) {
|
|
|
247
250
|
const requestResourceReferences = [
|
|
248
251
|
...big.matchAll(/request\.resource\.data\.([A-Za-z0-9_]+)/g)
|
|
249
252
|
].map((x) => x[1]);
|
|
250
|
-
const { ops, known } = opsFrom(target);
|
|
253
|
+
const { ops, known, unknown } = opsFrom(target);
|
|
251
254
|
const isHelperCall = !unconditional && rawCondition !== resolved;
|
|
252
255
|
const hasAuth = authSource.includes("request.auth");
|
|
253
256
|
rules.push({
|
|
254
257
|
id: `rule-${idx++}`,
|
|
255
258
|
path: fullPath,
|
|
256
259
|
operations: ops,
|
|
260
|
+
unknownOperations: unknown.length > 0 ? unknown : void 0,
|
|
257
261
|
conditionPresent: !unconditional && condition.length > 0,
|
|
258
262
|
condition: unconditional ? void 0 : condition,
|
|
259
263
|
authReferences,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
scan
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NZT4NIVA.js";
|
|
4
4
|
import {
|
|
5
5
|
verify
|
|
6
6
|
} from "./chunk-CSMT4PIP.js";
|
|
@@ -142,17 +142,18 @@ function createMcpServer() {
|
|
|
142
142
|
"verify",
|
|
143
143
|
{
|
|
144
144
|
title: "Firebase Audit Verify (Emulator)",
|
|
145
|
-
description: "Gera matriz papel\xD7opera\xE7\xE3o\xD7path e avalia cobertura do ruleCoverage. Requer Emulator. Sem contrato usa pap\xE9is reduzidos (anonymous/user/admin). Nunca afirma cobertura sem teste real.",
|
|
145
|
+
description: "Gera matriz papel\xD7opera\xE7\xE3o\xD7path e avalia cobertura do ruleCoverage. Requer Emulator. Sem contrato usa pap\xE9is reduzidos (anonymous/user/admin). Nunca afirma cobertura sem teste real. N\xE3o substitui scan/check.",
|
|
146
146
|
inputSchema: {
|
|
147
147
|
cwd: z.string().min(1).describe("Diret\xF3rio raiz do projeto"),
|
|
148
|
-
coverage: z.string().optional().describe("Path do coverage.json do ruleCoverage (relativo ao cwd)")
|
|
148
|
+
coverage: z.string().optional().describe("Path do coverage.json do ruleCoverage (relativo ao cwd)"),
|
|
149
|
+
adapter: z.string().optional().describe("Fun\xE7\xE3o de permiss\xE3o no c\xF3digo que recebe o nome como texto (ex: rbac.can). Default: do contrato.")
|
|
149
150
|
}
|
|
150
151
|
},
|
|
151
|
-
async ({ cwd, coverage }) => {
|
|
152
|
+
async ({ cwd, coverage, adapter }) => {
|
|
152
153
|
try {
|
|
153
154
|
assertCwd(cwd);
|
|
154
155
|
const { resolve } = await import("path");
|
|
155
|
-
const { summary: scanSummary, model } = await scan(cwd);
|
|
156
|
+
const { summary: scanSummary, model } = await scan(cwd, { adapterFn: adapter });
|
|
156
157
|
const res = verify(model, { coverageFile: coverage ? resolve(cwd, coverage) : void 0 });
|
|
157
158
|
const roles = model.authorization.roles.length > 0 ? model.authorization.roles.map((r) => r.name) : ["anonymous", "user", "admin"];
|
|
158
159
|
const truncated = res.cases.length > 50;
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
resolveHelperConditionDetailed,
|
|
10
10
|
stripOuterParens,
|
|
11
11
|
stripRuleComments
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7J3ADEBW.js";
|
|
13
13
|
|
|
14
14
|
// src/scan.ts
|
|
15
15
|
import { readFileSync as readFileSync3, existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
@@ -107,6 +107,10 @@ var SERVER_HINTS_SEGMENTS = [
|
|
|
107
107
|
"backend",
|
|
108
108
|
"scripts"
|
|
109
109
|
];
|
|
110
|
+
function isTestPath(file) {
|
|
111
|
+
const n = file.replace(/\\/g, "/");
|
|
112
|
+
return /\.test\.[tj]sx?$/.test(n) || /\.spec\.[tj]sx?$/.test(n) || /(^|\/)__tests__\//.test(n) || /(^|\/)(test|tests|testing)\//.test(n);
|
|
113
|
+
}
|
|
110
114
|
function classifyOrigin(file, content) {
|
|
111
115
|
const rel = file.replace(/\\/g, "/");
|
|
112
116
|
const segs = rel.split("/");
|
|
@@ -189,7 +193,7 @@ import { join as join2 } from "path";
|
|
|
189
193
|
import { executeFind } from "@justmpm/supergrep";
|
|
190
194
|
function isBuildOutput(file) {
|
|
191
195
|
const n = file.replace(/\\/g, "/");
|
|
192
|
-
return /(^|\/)(node_modules|dist|build|\.next|coverage|out)\//.test(n);
|
|
196
|
+
return /(^|\/)(node_modules|dist|build|\.next|coverage|out)\//.test(n) || /\/functions\/lib\//.test(n);
|
|
193
197
|
}
|
|
194
198
|
var IMPLEMENTED_CHECKS = ["FBA001", "FBA002", "FBA003", "FBA004", "FBA009", "FBA010", "FBA011", "FBA012", "FBA013"];
|
|
195
199
|
function createEvidence() {
|
|
@@ -276,14 +280,16 @@ async function runChecks(model, rootDir, opts = {}) {
|
|
|
276
280
|
}
|
|
277
281
|
}
|
|
278
282
|
for (const rule of model.rules) {
|
|
279
|
-
|
|
283
|
+
const unknown2 = rule.unknownOperations ?? [];
|
|
284
|
+
if (rule.operations.length === 0 || unknown2.length > 0) {
|
|
285
|
+
const detail = unknown2.length > 0 ? ` (trecho desconhecido: ${unknown2.join(", ")})` : "";
|
|
280
286
|
findings.push(
|
|
281
287
|
make(
|
|
282
288
|
"RULES_UNKNOWN_OP",
|
|
283
289
|
"WARNING",
|
|
284
290
|
"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}`,
|
|
291
|
+
`Opera\xE7\xE3o desconhecida em ${rule.path}${detail} (${rule.location.file}:${rule.location.start.line}). Typo em allow? Deploy rejeita.`,
|
|
292
|
+
`RULES_UNKNOWN_OP:${rule.path}:${rule.location.start.line}:${[...rule.operations].sort().join(",")}`,
|
|
287
293
|
{
|
|
288
294
|
file: rule.location.file,
|
|
289
295
|
line: rule.location.start.line,
|
|
@@ -530,10 +536,6 @@ async function runChecks(model, rootDir, opts = {}) {
|
|
|
530
536
|
}
|
|
531
537
|
}
|
|
532
538
|
const adminHits = await collectAdminImports(rootDir);
|
|
533
|
-
const isTestPath = (f) => {
|
|
534
|
-
const n = f.replace(/\\/g, "/");
|
|
535
|
-
return /\.test\.[tj]sx?$/.test(n) || /\.spec\.[tj]sx?$/.test(n) || /(^|\/)__tests__\//.test(n) || /(^|\/)(test|tests|testing)\//.test(n);
|
|
536
|
-
};
|
|
537
539
|
for (const hit of adminHits) {
|
|
538
540
|
let origin = "UNKNOWN";
|
|
539
541
|
try {
|
|
@@ -593,7 +595,7 @@ async function collectPermissionCalls(rootDir, adapterFn) {
|
|
|
593
595
|
}
|
|
594
596
|
const seen = /* @__PURE__ */ new Set();
|
|
595
597
|
const pushLiteral = (file, line, permission) => {
|
|
596
|
-
if (isBuildOutput(file)) return;
|
|
598
|
+
if (isBuildOutput(file) || isTestPath(file)) return;
|
|
597
599
|
const k = `${file}:${line}:${permission}`;
|
|
598
600
|
if (seen.has(k)) return;
|
|
599
601
|
seen.add(k);
|
|
@@ -606,7 +608,7 @@ async function collectPermissionCalls(rootDir, adapterFn) {
|
|
|
606
608
|
const raw = (m.metaVariables["PERM"] ?? "").trim();
|
|
607
609
|
const line = m.line + 1;
|
|
608
610
|
if (raw.includes("${")) {
|
|
609
|
-
if (!isBuildOutput(m.file)) {
|
|
611
|
+
if (!isBuildOutput(m.file) && !isTestPath(m.file)) {
|
|
610
612
|
const k = `${m.file}:${line}:${raw}`;
|
|
611
613
|
if (!seen.has(k)) {
|
|
612
614
|
seen.add(k);
|
|
@@ -620,7 +622,7 @@ async function collectPermissionCalls(rootDir, adapterFn) {
|
|
|
620
622
|
const perm = raw.replace(/^['"`]|['"`]$/g, "").trim();
|
|
621
623
|
if (/^[a-z][a-z0-9_-]*(\.[a-z][a-z0-9_-]*)*$/.test(perm)) pushLiteral(m.file, line, perm);
|
|
622
624
|
else {
|
|
623
|
-
if (!isBuildOutput(m.file)) {
|
|
625
|
+
if (!isBuildOutput(m.file) && !isTestPath(m.file)) {
|
|
624
626
|
const k = `${m.file}:${line}:${raw}:invalid`;
|
|
625
627
|
if (!seen.has(k)) {
|
|
626
628
|
seen.add(k);
|
|
@@ -629,7 +631,7 @@ async function collectPermissionCalls(rootDir, adapterFn) {
|
|
|
629
631
|
}
|
|
630
632
|
}
|
|
631
633
|
} else if (raw.length > 0) {
|
|
632
|
-
if (!isBuildOutput(m.file)) {
|
|
634
|
+
if (!isBuildOutput(m.file) && !isTestPath(m.file)) {
|
|
633
635
|
const k = `${m.file}:${line}:${raw}`;
|
|
634
636
|
if (!seen.has(k)) {
|
|
635
637
|
seen.add(k);
|
|
@@ -772,6 +774,8 @@ var RuleSchema = z.strictObject({
|
|
|
772
774
|
id: z.string().min(1),
|
|
773
775
|
path: z.string().min(1),
|
|
774
776
|
operations: z.array(OperationSchema),
|
|
777
|
+
/** Partes de `allow` não reconhecidas (typo parcial: `get, gett`). */
|
|
778
|
+
unknownOperations: z.array(z.string()).optional(),
|
|
775
779
|
conditionPresent: z.boolean(),
|
|
776
780
|
condition: z.string().optional(),
|
|
777
781
|
authReferences: z.array(z.string()),
|
|
@@ -908,6 +912,14 @@ function validateClaimSamples(samples) {
|
|
|
908
912
|
|
|
909
913
|
// src/scan.ts
|
|
910
914
|
async function scan(rootDir, opts = {}) {
|
|
915
|
+
const { statSync: statRoot } = await import("fs");
|
|
916
|
+
let rootOk = false;
|
|
917
|
+
try {
|
|
918
|
+
rootOk = statRoot(rootDir).isDirectory();
|
|
919
|
+
} catch {
|
|
920
|
+
rootOk = false;
|
|
921
|
+
}
|
|
922
|
+
if (!rootOk) throw new Error(`Diret\xF3rio n\xE3o existe: ${rootDir}`);
|
|
911
923
|
const d = discover(rootDir);
|
|
912
924
|
if (opts.graph === true) {
|
|
913
925
|
try {
|
|
@@ -1421,7 +1433,7 @@ async function countAppCheckEnforced(rootDir, functionsDir) {
|
|
|
1421
1433
|
try {
|
|
1422
1434
|
const { readdirSync, readFileSync: readSync, statSync: stat } = await import("fs");
|
|
1423
1435
|
const { join: joinP } = await import("path");
|
|
1424
|
-
const { stripRuleComments: strip } = await import("./rules-
|
|
1436
|
+
const { stripRuleComments: strip } = await import("./rules-HCXATUST.js");
|
|
1425
1437
|
const roots = [functionsDir ?? joinP(rootDir, "functions")];
|
|
1426
1438
|
let occurrences = 0;
|
|
1427
1439
|
const files = /* @__PURE__ */ new Set();
|
|
@@ -1430,10 +1442,7 @@ async function countAppCheckEnforced(rootDir, functionsDir) {
|
|
|
1430
1442
|
let limitHit = false;
|
|
1431
1443
|
const stack = [...roots];
|
|
1432
1444
|
let guard = 0;
|
|
1433
|
-
const isTestFile =
|
|
1434
|
-
const n = p.replace(/\\/g, "/");
|
|
1435
|
-
return /\.test\.[tj]sx?$/.test(n) || /\.spec\.[tj]sx?$/.test(n) || /(^|\/)__tests__\//.test(n) || /(^|\/)(test|tests|testing)\//.test(n);
|
|
1436
|
-
};
|
|
1445
|
+
const isTestFile = isTestPath;
|
|
1437
1446
|
while (stack.length > 0 && guard < 200) {
|
|
1438
1447
|
guard += 1;
|
|
1439
1448
|
const cur = stack.pop();
|
|
@@ -1482,7 +1491,7 @@ async function countAppCheckEnforced(rootDir, functionsDir) {
|
|
|
1482
1491
|
files.add(abs);
|
|
1483
1492
|
}
|
|
1484
1493
|
}
|
|
1485
|
-
const manualHits = text.match(/verifyToken\s*\(|verify_token\s*\(|consumeAppCheckToken|getLimitedUseToken
|
|
1494
|
+
const manualHits = text.match(/verifyToken\s*\(|verify_token\s*\(|consumeAppCheckToken|getLimitedUseToken/g);
|
|
1486
1495
|
if (manualHits) manual += manualHits.length;
|
|
1487
1496
|
} catch {
|
|
1488
1497
|
}
|
|
@@ -1588,6 +1597,7 @@ function expandStorageOps(target) {
|
|
|
1588
1597
|
export {
|
|
1589
1598
|
discover,
|
|
1590
1599
|
SERVER_HINTS_SEGMENTS,
|
|
1600
|
+
isTestPath,
|
|
1591
1601
|
classifyOrigin,
|
|
1592
1602
|
emptyModel,
|
|
1593
1603
|
enrichWithGraph,
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
scan
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-NZT4NIVA.js";
|
|
5
|
+
import "./chunk-7J3ADEBW.js";
|
|
6
6
|
|
|
7
7
|
// src/cli.ts
|
|
8
8
|
import { createRequire } from "module";
|
|
@@ -46,6 +46,9 @@ Uso: firebase-audit scan [--json] [--strict] [--adapter=fn] [--cwd=path]`);
|
|
|
46
46
|
console.error(`Valor inv\xE1lido para --strict: ${strictArg} (use --strict, --strict=true ou --strict=false)`);
|
|
47
47
|
process.exit(1);
|
|
48
48
|
}
|
|
49
|
+
if (cmd === "check" && strictArg === "false") {
|
|
50
|
+
console.error("Aviso: 'check' \xE9 sempre strict por defini\xE7\xE3o \u2014 --strict=false ignorado.");
|
|
51
|
+
}
|
|
49
52
|
const asJsonArg = getArg("json");
|
|
50
53
|
const asJson = (args.includes("--json") || asJsonArg === "true") && asJsonArg !== "false";
|
|
51
54
|
if (asJsonArg !== void 0 && asJsonArg !== "true" && asJsonArg !== "false") {
|
|
@@ -81,7 +84,7 @@ Uso: firebase-audit scan|check|verify|drift [--json] ...`);
|
|
|
81
84
|
const { resolve: resolveRoot } = await import("path");
|
|
82
85
|
const rootDir = cwdArg ? resolveRoot(process.cwd(), cwdArg) : process.cwd();
|
|
83
86
|
if (cmd === "verify") {
|
|
84
|
-
const { scan: scanForVerify } = await import("./scan-
|
|
87
|
+
const { scan: scanForVerify } = await import("./scan-RTIMO3I2.js");
|
|
85
88
|
const { verify } = await import("./verify-GQSR4FQL.js");
|
|
86
89
|
const { resolve: resolveVerify } = await import("path");
|
|
87
90
|
const coverageArg = getArg("coverage");
|
package/dist/index.d.ts
CHANGED
|
@@ -217,6 +217,7 @@ declare const RuleSchema: z.ZodObject<{
|
|
|
217
217
|
delete: "delete";
|
|
218
218
|
write: "write";
|
|
219
219
|
}>>;
|
|
220
|
+
unknownOperations: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
220
221
|
conditionPresent: z.ZodBoolean;
|
|
221
222
|
condition: z.ZodOptional<z.ZodString>;
|
|
222
223
|
authReferences: z.ZodArray<z.ZodString>;
|
|
@@ -419,6 +420,7 @@ declare const ProjectModelSchema: z.ZodObject<{
|
|
|
419
420
|
delete: "delete";
|
|
420
421
|
write: "write";
|
|
421
422
|
}>>;
|
|
423
|
+
unknownOperations: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
422
424
|
conditionPresent: z.ZodBoolean;
|
|
423
425
|
condition: z.ZodOptional<z.ZodString>;
|
|
424
426
|
authReferences: z.ZodArray<z.ZodString>;
|
|
@@ -639,6 +641,8 @@ interface DiscoveryResult {
|
|
|
639
641
|
declare function discover(rootDir: string): DiscoveryResult;
|
|
640
642
|
/** Segmentos de servidor (fail-closed: `api` genérico NÃO é server, ver classifyOrigin). */
|
|
641
643
|
declare const SERVER_HINTS_SEGMENTS: string[];
|
|
644
|
+
/** Arquivo de teste/setup de Emulator (com Admin legitimamente): nunca reprova CI. */
|
|
645
|
+
declare function isTestPath(file: string): boolean;
|
|
642
646
|
/** Heurística CLIENT vs SERVER: caminho manda primeiro (grafo ai-tool preenche listas na Fase 3).
|
|
643
647
|
* Segmentos ancorados — nunca substring solta (`myapp/` não é `app/`). */
|
|
644
648
|
declare function classifyOrigin(file: string, content: string): "CLIENT" | "SERVER" | "UNKNOWN";
|
|
@@ -665,6 +669,7 @@ declare function stripRuleComments(content: string): string;
|
|
|
665
669
|
declare function opsFrom(target: string): {
|
|
666
670
|
ops: Rule["operations"];
|
|
667
671
|
known: boolean;
|
|
672
|
+
unknown: string[];
|
|
668
673
|
};
|
|
669
674
|
/** Normaliza target de allow para fingerprint estável (case/espaço/ordem). */
|
|
670
675
|
declare function normalizeTarget(target: string): string;
|
|
@@ -763,7 +768,9 @@ interface ScanSummary {
|
|
|
763
768
|
errors: number;
|
|
764
769
|
warnings: number;
|
|
765
770
|
infos: number;
|
|
771
|
+
/** Checks FBA que passaram (só FBA; infra nomeada vai em `infra`). */
|
|
766
772
|
passedChecks: number;
|
|
773
|
+
/** Total de checks FBA implementados. */
|
|
767
774
|
totalChecks: number;
|
|
768
775
|
/** Infra nomeada (fora dos checks FBA): cada item diz qual e por quê. */
|
|
769
776
|
infra: {
|
|
@@ -845,4 +852,4 @@ declare function drift(localFile: string | null, remoteFile: string | null): Dri
|
|
|
845
852
|
|
|
846
853
|
declare const VERSION: string;
|
|
847
854
|
|
|
848
|
-
export { AccessOriginSchema, type AuditYaml, AuditYamlSchema, ConfidenceSchema, type DiscoveryResult, type DriftEntry, type DriftResult, type DriftStatus, DynamicValueSchema, type Evidence, EvidenceSchema, type Finding, FindingSchema, FirestoreIndexSchema, GraphEdgeSchema, IMPLEMENTED_CHECKS, IndexFieldSchema, LocationSchema, OperationSchema, PermissionSchema, PositionSchema, type ProjectModel, ProjectModelSchema, QueryFilterSchema, QueryOrderSchema, type QueryShape, QueryShapeSchema, RESERVED_CLAIM_KEYS, RoleSchema, RuleSchema, SERVER_HINTS_SEGMENTS, type ScanOptions, type ScanResult, type ScanSummary, SeveritySchema, VERSION, type VerifyCase, type VerifyOptions, type VerifyResult, buildFullPath, classifyOrigin, conditionKeyForFingerprint, discover, drift, emptyModel, enrichWithGraph, extractRules, extractRulesContent, findPublicAllows, findPublicAllowsContent, hashShort, helperBodyToCondition, inlineHelperArgs, inlineHelpersInCondition, isPublicCondition, normalizeTarget, opsFrom, parseMatchBlocks, parseRuleFunctions, parseRuleFunctionsDetailed, planVerify, resolveHelperCondition, resolveHelperConditionDetailed, runChecks, scan, stripOuterParens, stripRuleComments, validateClaimSamples, verify };
|
|
855
|
+
export { AccessOriginSchema, type AuditYaml, AuditYamlSchema, ConfidenceSchema, type DiscoveryResult, type DriftEntry, type DriftResult, type DriftStatus, DynamicValueSchema, type Evidence, EvidenceSchema, type Finding, FindingSchema, FirestoreIndexSchema, GraphEdgeSchema, IMPLEMENTED_CHECKS, IndexFieldSchema, LocationSchema, OperationSchema, PermissionSchema, PositionSchema, type ProjectModel, ProjectModelSchema, QueryFilterSchema, QueryOrderSchema, type QueryShape, QueryShapeSchema, RESERVED_CLAIM_KEYS, RoleSchema, RuleSchema, SERVER_HINTS_SEGMENTS, type ScanOptions, type ScanResult, type ScanSummary, SeveritySchema, VERSION, type VerifyCase, type VerifyOptions, type VerifyResult, buildFullPath, classifyOrigin, conditionKeyForFingerprint, discover, drift, emptyModel, enrichWithGraph, extractRules, extractRulesContent, findPublicAllows, findPublicAllowsContent, hashShort, helperBodyToCondition, inlineHelperArgs, inlineHelpersInCondition, isPublicCondition, isTestPath, normalizeTarget, opsFrom, parseMatchBlocks, parseRuleFunctions, parseRuleFunctionsDetailed, planVerify, resolveHelperCondition, resolveHelperConditionDetailed, runChecks, scan, stripOuterParens, stripRuleComments, validateClaimSamples, verify };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMcpServer,
|
|
3
3
|
startMcpServer
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-D75SRJ7P.js";
|
|
5
5
|
import {
|
|
6
6
|
AccessOriginSchema,
|
|
7
7
|
AuditYamlSchema,
|
|
@@ -30,10 +30,11 @@ import {
|
|
|
30
30
|
discover,
|
|
31
31
|
emptyModel,
|
|
32
32
|
enrichWithGraph,
|
|
33
|
+
isTestPath,
|
|
33
34
|
runChecks,
|
|
34
35
|
scan,
|
|
35
36
|
validateClaimSamples
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-NZT4NIVA.js";
|
|
37
38
|
import {
|
|
38
39
|
buildFullPath,
|
|
39
40
|
conditionKeyForFingerprint,
|
|
@@ -55,7 +56,7 @@ import {
|
|
|
55
56
|
resolveHelperConditionDetailed,
|
|
56
57
|
stripOuterParens,
|
|
57
58
|
stripRuleComments
|
|
58
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-7J3ADEBW.js";
|
|
59
60
|
import {
|
|
60
61
|
planVerify,
|
|
61
62
|
verify
|
|
@@ -111,6 +112,7 @@ export {
|
|
|
111
112
|
inlineHelperArgs,
|
|
112
113
|
inlineHelpersInCondition,
|
|
113
114
|
isPublicCondition,
|
|
115
|
+
isTestPath,
|
|
114
116
|
normalizeTarget,
|
|
115
117
|
opsFrom,
|
|
116
118
|
parseMatchBlocks,
|
package/dist/mcp-cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
startMcpServer
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-D75SRJ7P.js";
|
|
5
|
+
import "./chunk-NZT4NIVA.js";
|
|
6
|
+
import "./chunk-7J3ADEBW.js";
|
|
7
7
|
import "./chunk-CSMT4PIP.js";
|
|
8
8
|
import "./chunk-LD3F73XI.js";
|
|
9
9
|
|
package/dist/mcp.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createMcpServer,
|
|
3
3
|
startMcpServer
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-D75SRJ7P.js";
|
|
5
|
+
import "./chunk-NZT4NIVA.js";
|
|
6
|
+
import "./chunk-7J3ADEBW.js";
|
|
7
7
|
import "./chunk-CSMT4PIP.js";
|
|
8
8
|
import "./chunk-LD3F73XI.js";
|
|
9
9
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justmpm/firebase-audit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.8",
|
|
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",
|
package/skill/SKILL.md
CHANGED
|
@@ -34,6 +34,6 @@ Use `drift` para comparar índices locais vs implantados (MATCHED/LOCAL_ONLY/REM
|
|
|
34
34
|
|
|
35
35
|
## Limites honestos
|
|
36
36
|
|
|
37
|
-
- AppCheck: varredura TS/Python por texto (`enforceAppCheck`, `verifyToken` e afins). Config via variável conta como não observada; `onRequest` exige revisão rota a rota.
|
|
37
|
+
- AppCheck: varredura TS/Python por texto (`enforceAppCheck`, `verifyToken` e afins). Config via variável ou objeto compartilhado conta como não observada; janela de trigger pode errar em arquivo multi-função — `onRequest` exige revisão rota a rota.
|
|
38
38
|
- Isolamento por tenant (ownerId/tenantId) e mismatch de papel não-admin: fora dos checks — revise manualmente ou no Emulator.
|
|
39
39
|
- `graph: true` é prévia opt-in da biblioteca (nenhum check consome ainda).
|