@justmpm/firebase-audit 0.4.0 → 0.4.1

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.
@@ -783,6 +783,10 @@ async function runChecks(model, rootDir, opts = {}) {
783
783
  }
784
784
  }
785
785
  const adminHits = await collectAdminImports(rootDir);
786
+ const isTestPath = (f) => {
787
+ const n = f.replace(/\\/g, "/");
788
+ return /\.test\.[tj]sx?$/.test(n) || /\.spec\.[tj]sx?$/.test(n) || /(^|\/)__tests__\//.test(n) || /(^|\/)(test|tests|testing)\//.test(n);
789
+ };
786
790
  for (const hit of adminHits) {
787
791
  let origin = "UNKNOWN";
788
792
  try {
@@ -791,7 +795,7 @@ async function runChecks(model, rootDir, opts = {}) {
791
795
  } catch {
792
796
  origin = "UNKNOWN";
793
797
  }
794
- if (origin === "CLIENT") {
798
+ if (origin === "CLIENT" && !isTestPath(hit.file)) {
795
799
  findings.push(
796
800
  make(
797
801
  "FBA003",
@@ -1329,16 +1333,17 @@ async function scan(rootDir, opts = {}) {
1329
1333
  });
1330
1334
  }
1331
1335
  } else {
1336
+ const details = validated.error.issues.slice(0, 5).map((i) => `${String(i.path.join(".")) || "(raiz)"}: ${i.message}`).join("; ");
1332
1337
  findings_pre.push({
1333
1338
  rule: "CONTRACT_INVALID",
1334
1339
  severity: "WARNING",
1335
1340
  confidence: "CONFIRMED",
1336
- message: `firebase-audit.yaml existe mas \xE9 inv\xE1lido: ${validated.error.issues[0]?.message ?? "schema"} \u2014 contrato ignorado neste scan.`,
1341
+ message: `firebase-audit.yaml inv\xE1lido (${validated.error.issues.length} problema(s): ${details}) \u2014 contrato ignorado neste scan.`,
1337
1342
  fingerprint: "CONTRACT_INVALID",
1338
1343
  evidence: [
1339
- { id: "ev-contract-invalid", kind: "contract-parse", summary: "YAML inv\xE1lido", confidence: "CONFIRMED" }
1344
+ { id: "ev-contract-invalid", kind: "contract-parse", summary: details.slice(0, 200), confidence: "CONFIRMED" }
1340
1345
  ],
1341
- fix: "Valide contra templates/firebase-audit.yaml."
1346
+ fix: "Valide contra templates/firebase-audit.yaml (min\xFAsculas, sem chaves extras)."
1342
1347
  });
1343
1348
  }
1344
1349
  } catch (err) {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  scan
3
- } from "./chunk-5PVQB3ZI.js";
3
+ } from "./chunk-3SEVYYCX.js";
4
4
  import {
5
5
  verify
6
- } from "./chunk-TVEZQU7C.js";
6
+ } from "./chunk-PSSMYRRU.js";
7
7
  import {
8
8
  drift
9
9
  } from "./chunk-NJBCSW7E.js";
@@ -120,8 +120,8 @@ function createMcpServer() {
120
120
  title: "Firebase Audit Drift (\xEDndices)",
121
121
  description: "Compara \xEDndices locais vs implantados. Retorna MATCHED/LOCAL_ONLY/REMOTE_ONLY. Nunca diz 'unused', apenas NOT_OBSERVED.",
122
122
  inputSchema: {
123
- local: z.string().nullable().describe("Path do firestore.indexes.json local (ou null). Relativo resolve contra cwd."),
124
- remote: z.string().nullable().describe("Path do JSON remoto (gcloud/REST) (ou null). Relativo resolve contra cwd."),
123
+ local: z.string().nullable().optional().describe("Path do firestore.indexes.json local (ou null). Relativo resolve contra cwd."),
124
+ remote: z.string().nullable().optional().describe("Path do JSON remoto (gcloud/REST) (ou null). Relativo resolve contra cwd."),
125
125
  cwd: z.string().optional().describe("Diret\xF3rio base para paths relativos (default: cwd do servidor).")
126
126
  }
127
127
  },
@@ -130,7 +130,7 @@ function createMcpServer() {
130
130
  const { resolve: resolveP, isAbsolute } = await import("path");
131
131
  const base = cwd && cwd.length > 0 ? cwd : process.cwd();
132
132
  const resPath = (p) => {
133
- if (p === null) return null;
133
+ if (p === null || p === void 0) return null;
134
134
  return isAbsolute(p) ? p : resolveP(base, p);
135
135
  };
136
136
  const res = drift(resPath(local), resPath(remote));
@@ -7,7 +7,7 @@ function collectVisitCounts(node, out) {
7
7
  return;
8
8
  }
9
9
  const rec = node;
10
- for (const k of ["visitCount", "visit_count", "count", "hits", "visits", "evaluations"]) {
10
+ for (const k of ["visitCount", "visit_count"]) {
11
11
  const v = rec[k];
12
12
  if (typeof v === "number" && Number.isFinite(v)) {
13
13
  out.push(v);
@@ -26,6 +26,7 @@ function planVerify(model) {
26
26
  };
27
27
  const cases = [];
28
28
  for (const rule of model.rules) {
29
+ if (rule.path === "/(unknown)") continue;
29
30
  for (const role of roles) {
30
31
  for (const op of rule.operations) {
31
32
  for (const mapped of expand(op)) {
@@ -105,6 +106,7 @@ function verify(model, opts = {}) {
105
106
  return { cases, uncovered: [], findings, coveragePct };
106
107
  }
107
108
  for (const rule of model.rules) {
109
+ if (rule.path === "/(unknown)") continue;
108
110
  uncovered.push(rule.path);
109
111
  }
110
112
  return { cases, uncovered, findings, coveragePct };
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  scan
4
- } from "./chunk-5PVQB3ZI.js";
4
+ } from "./chunk-3SEVYYCX.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { createRequire } from "module";
@@ -64,8 +64,8 @@ Uso: firebase-audit scan|check|verify|drift [--json] ...`);
64
64
  const { resolve: resolveRoot } = await import("path");
65
65
  const rootDir = cwdArg ? resolveRoot(process.cwd(), cwdArg) : process.cwd();
66
66
  if (cmd === "verify") {
67
- const { scan: scanForVerify } = await import("./scan-6FRUE5BE.js");
68
- const { verify } = await import("./verify-R6LI2KNZ.js");
67
+ const { scan: scanForVerify } = await import("./scan-VREY2FGO.js");
68
+ const { verify } = await import("./verify-O722ZZBV.js");
69
69
  const { resolve: resolveVerify } = await import("path");
70
70
  const coverageArg = getArg("coverage");
71
71
  const coveragePath = coverageArg ? resolveVerify(rootDir, coverageArg) : void 0;
@@ -107,6 +107,15 @@ ${icon} ${f.rule} [${f.confidence}]
107
107
  const remotePath = remoteArg ? resolveDrift(rootDir, remoteArg) : null;
108
108
  for (const [label, p] of [["--local", localPath], ["--remote", remotePath]]) {
109
109
  if (p && !existsDrift(p)) {
110
+ if (asJson) {
111
+ const { drift: driftMissing } = await import("./drift-KU7HWL7M.js");
112
+ const res2 = driftMissing(
113
+ localPath && existsDrift(localPath) ? localPath : null,
114
+ remotePath && existsDrift(remotePath) ? remotePath : null
115
+ );
116
+ console.log(JSON.stringify({ version: pkg.version, entries: res2.entries, findings: res2.findings }, null, 2));
117
+ process.exit(1);
118
+ }
110
119
  console.error(`Arquivo ${label} n\xE3o encontrado: ${p}`);
111
120
  process.exit(1);
112
121
  }
package/dist/index.d.ts CHANGED
@@ -643,6 +643,10 @@ declare function enrichWithGraph(rootDir: string, d: DiscoveryResult): Promise<v
643
643
  /**
644
644
  * Rules extractor — estrutura + referências + locations (sem avaliar).
645
645
  * Parser leve e intencionalmente incompleto: avaliação real é do Emulator (V3).
646
+ *
647
+ * Limitação conhecida: `ALLOW_RE` corta a condição no primeiro `;` mesmo dentro
648
+ * de string literal (ex: `x != "a;b"`). Raríssimo em Rules reais; documentado aqui
649
+ * em vez de silêncio — Emulator acusa a regra de verdade.
646
650
  */
647
651
 
648
652
  type Rule = z$1.infer<typeof RuleSchema>;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createMcpServer,
3
3
  startMcpServer
4
- } from "./chunk-YVV7YRF3.js";
4
+ } from "./chunk-GOLWQBD5.js";
5
5
  import {
6
6
  AccessOriginSchema,
7
7
  AuditYamlSchema,
@@ -53,11 +53,11 @@ import {
53
53
  stripOuterParens,
54
54
  stripRuleComments,
55
55
  validateClaimSamples
56
- } from "./chunk-5PVQB3ZI.js";
56
+ } from "./chunk-3SEVYYCX.js";
57
57
  import {
58
58
  planVerify,
59
59
  verify
60
- } from "./chunk-TVEZQU7C.js";
60
+ } from "./chunk-PSSMYRRU.js";
61
61
  import {
62
62
  drift
63
63
  } from "./chunk-NJBCSW7E.js";
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-YVV7YRF3.js";
5
- import "./chunk-5PVQB3ZI.js";
6
- import "./chunk-TVEZQU7C.js";
4
+ } from "./chunk-GOLWQBD5.js";
5
+ import "./chunk-3SEVYYCX.js";
6
+ import "./chunk-PSSMYRRU.js";
7
7
  import "./chunk-NJBCSW7E.js";
8
8
 
9
9
  // src/mcp-cli.ts
package/dist/mcp.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  createMcpServer,
3
3
  startMcpServer
4
- } from "./chunk-YVV7YRF3.js";
5
- import "./chunk-5PVQB3ZI.js";
6
- import "./chunk-TVEZQU7C.js";
4
+ } from "./chunk-GOLWQBD5.js";
5
+ import "./chunk-3SEVYYCX.js";
6
+ import "./chunk-PSSMYRRU.js";
7
7
  import "./chunk-NJBCSW7E.js";
8
8
  export {
9
9
  createMcpServer,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  scan
3
- } from "./chunk-5PVQB3ZI.js";
3
+ } from "./chunk-3SEVYYCX.js";
4
4
  export {
5
5
  scan
6
6
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  planVerify,
3
3
  verify
4
- } from "./chunk-TVEZQU7C.js";
4
+ } from "./chunk-PSSMYRRU.js";
5
5
  export {
6
6
  planVerify,
7
7
  verify
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justmpm/firebase-audit",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
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",