Skip to content

Commit 26b0d33

Browse files
authored
Adding /firestore:generate_rules and /storage:generate_rules MCP prompts. (#9733)
* Adding `/firestore:generate_rules` and `/storage:generate_rules` MCP prompts. * Pr fixes
1 parent e7eed6f commit 26b0d33

6 files changed

Lines changed: 679 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
- Removed MCP tools and prompts that required Gemini in Firebase terms of service.
33
- Fixes an issue where the `--only` flag was not always respected for `firebase mcp`
44
- Removed timeout when connecting to Cloud SQL. Hopefully, should mitigate issue #9314. (#9725)
5+
- Added `/firestore:generate_rules` and `/storage:generate_rules` MCP prompts.
Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
1+
import { prompt } from "../../prompt";
2+
3+
export const generateRules = prompt(
4+
"firestore",
5+
{
6+
name: "generate_rules",
7+
description:
8+
"Generate secure Firebase Firestore Security Rules and corresponding unit tests for your project.",
9+
arguments: [],
10+
},
11+
async () => {
12+
return [
13+
{
14+
role: "user" as const,
15+
content: {
16+
type: "text",
17+
text: `You are an expert Firebase Security Rules engineer with deep knowledge of Firestore security best practices. Your task is to generate comprehensive, secure Firebase Security rules with corresponding unit tests for the user's project.
18+
19+
## Pre-Flight Check: Client-Side Application Verification
20+
21+
**CRITICAL FIRST STEP:** Before proceeding with rule generation, you MUST determine if this is a client-side application.
22+
23+
### Client-Side Application Indicators:
24+
25+
- Direct Firestore SDK usage in frontend code (React, Vue, Angular, vanilla JS, Flutter, Swift, Kotlin)
26+
- Browser-based or mobile app that connects directly to Firestore
27+
- No backend server handling Firestore operations
28+
- Frontend code contains 'initializeApp()', 'getFirestore()' or similar direct Firestore initialization
29+
30+
### Server-Side Application Indicators:
31+
32+
- Backend framework (Express, Django, Spring Boot, etc) handles all Firestore operations
33+
- Use of Firebase Admin SDK on server
34+
- Client makes HTTP/REST requests to backend, which then queries Firestore
35+
- No direct Firebase SDK usage in client code
36+
37+
**IF THIS IS A SERVER-SIDE APPLICATION:**
38+
39+
Stop immediately and respond:
40+
41+
'''
42+
!!! Skipping rule generation as this repository appears to be a server-side application. !!!
43+
'''
44+
45+
**ONLY IF THIS IS A CLIENT-SIDE APPLICATION:** Proceed with the workflow below.
46+
47+
## Workflow
48+
49+
Follow this structured workflow strictly:
50+
51+
### Phase-1: Codebase Analysis
52+
53+
1. **Scan the entire codebase** to identify:
54+
- Programming language(s) used (for understanding context only)
55+
- All Firestore collection and document paths
56+
- Data models and schemas (interfaces, classes, types)
57+
- Data types for each field (strings, numbers, booleans, timestamps, URLs, emails, etc.)
58+
- Required vs. optional fields
59+
- Field constraints (min/max length, format patterns, allowed values)
60+
- CRUD operations (create, read, update, delete)
61+
- Authentication patterns (Firebase Auth, custom tokens, anonymous)
62+
- Access patterns and business logic rules
63+
64+
2. **Document your findings** in a structured format:
65+
66+
'''
67+
Language: [detected language - for context only]
68+
Collections: [list all collections with their document structures]
69+
Data Models:
70+
[collection_name]:
71+
- field1: type (required/optional, constraints)
72+
- field2: type (required/optional, constraints)
73+
- [include immutable fields like uid, createdAt, authorId, etc.]
74+
Access Patterns: [who can read/write what, under what conditions]
75+
Authentication: [auth methods used]
76+
'''
77+
78+
### Phase-2: Security Rules Generation
79+
80+
Generate Firebase Security Rules following these principles:
81+
82+
- **Default deny:** Start with denying all access, then explicitly allow only what's needed
83+
- **Least privilege:** Grant minimum permissions required
84+
- **Validate data:** Check data types, required fields, and constraints on both creates and updates
85+
- **Authentication checks:** Verify user identity before granting access
86+
- **Authorization logic:** Implement role-based or ownership-based access control
87+
- **UID Protection:** Prevent users from changing ownership of data
88+
89+
**Structure Requirements:**
90+
91+
1. **Document assumed data models at the beginning of the rules file:**
92+
93+
'''javascript
94+
// ===============================================================
95+
// Assumed Data Model
96+
// ===============================================================
97+
//
98+
// This security rules file assumes the following data structures:
99+
//
100+
// Collection: [name]
101+
// Document ID: [pattern]
102+
// Fields:
103+
// - field1: type (required/optional, constraints) - description
104+
// - field2: type (required/optional, constraints) - description
105+
// [List all fields with types, constraints, and whether immutable]
106+
//
107+
// [Repeat for all collections]
108+
//
109+
// ===============================================================
110+
'''
111+
112+
2. **Include comprehensive helper functions to avoid repetition:**
113+
114+
'''javascript
115+
// ===============================================================
116+
// Helper Functions
117+
// ===============================================================
118+
//
119+
// Check if the user is authenticated
120+
function isAuthenticated() {
121+
return request.auth != null;
122+
}
123+
//
124+
// Check if user owns the resource (for user-owned documents)
125+
function isOwner(userId) {
126+
return isAuthenticated() && request.auth.uid == userId;
127+
}
128+
//
129+
// Check if user is owner based on document's uid field
130+
function isDocOwner() {
131+
return isAuthenticated() && request.auth.uid == resource.data.uid;
132+
}
133+
//
134+
// Verify UID hasn't been tampered with on create
135+
function uidUnchanged() {
136+
return !('uid' in request.resource.data) ||
137+
request.resource.data.uid == request.auth.uid;
138+
}
139+
//
140+
// Ensure uid field is not modified on update
141+
function uidNotModified() {
142+
return !('uid' in request.resource.data) ||
143+
request.resource.data.uid == resource.data.uid;
144+
}
145+
//
146+
// Validate required fields exist
147+
function hasRequiredFields(fields) {
148+
return request.resource.data.keys().hasAll(fields);
149+
}
150+
//
151+
// Validate string length
152+
function validStringLength(field, minLen, maxLen) {
153+
return request.resource.data[field] is string &&
154+
request.resource.data[field].size() >= minLen &&
155+
request.resource.data[field].size() <= maxLen;
156+
}
157+
//
158+
// Validate URL format (must start with https:// or http://)
159+
function isValidUrl(url) {
160+
return url is string &&
161+
(url.matches("^https://.*") || url.matches("^http://.*"));
162+
}
163+
//
164+
// Validate email format
165+
function isValidEmail(email) {
166+
return email is string &&
167+
email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
168+
}
169+
//
170+
// [Add more helper functions as needed for the data validation]
171+
//
172+
// ===============================================================
173+
'''
174+
175+
3. **For each collection, implement explicit data validation:**
176+
177+
- Type Checking: 'field is string', 'field is number', 'field is bool', 'field is timestamp'
178+
- Required fields validation using 'hasRequiredFields()'
179+
- String length constraints using 'validStringLength()'
180+
- URL validation using 'isValidUrl()' for URL fields
181+
- Email validation using 'isValidEmail()' for email fields
182+
- UID protection using 'uidUnchanged()' on creates and 'uidNotModified()' on updates
183+
- Immutable field protection (authorId, createdAt, etc. should not change on update)
184+
185+
Structure your rules clearly with comments explaining each rule's purpose.
186+
187+
### Phase-3: Devil's Advocate Attack
188+
189+
**Critical step:** Attempt to break your own rules by:
190+
191+
1. Trying to read data you shouldn't access
192+
2. Attempting unauthorized writes
193+
3. Attempting to create documents with someone else's UID
194+
4. Attempting to change UID on update (stealing ownership)
195+
5. Sending invalid data types
196+
6. Omitting required fields
197+
7. Sending invalid URLs (not starting with https:// or http://)
198+
8. Sending invalid email formats
199+
9. Exceeding string length limits
200+
10. Modifying immutable fields like createdAt, authorId
201+
11. Testing edge cases (null values, missing auth, malformed data)
202+
12. Checking for injection vulnerabilities
203+
13. Testing cascade delete scenarios
204+
14. Verifying field-level security
205+
206+
Document each attack attempt and whether it succeeded. If ANY attack succeeds:
207+
208+
- Fix the security hole
209+
- Regenerate the rules
210+
- **Repeat Phase-3** until no attacks succeed
211+
212+
### Phase-4: Syntactic Validation
213+
214+
Once devil's advocate testing passes:
215+
216+
1. Use the Firebase MCP 'firebase_validate_security_rules' tool to check syntax
217+
2. If validation fails:
218+
- Fix syntax errors
219+
- **Return to Phase-3** (devil's advocate must re-approve)
220+
3. Repeat until rules pass validation
221+
222+
### Phase-5: Test Suite Generation
223+
224+
Generate a comprehensive **JavaScript / TypeScript** test suite using '@firebase/rules-unit-testing'.
225+
226+
**Test coverage must include:**
227+
228+
- Authorized operations (should succeed)
229+
- Unauthorized operations (should fail)
230+
- UID tampering tests (cannot create with another user's UID)
231+
- UID modification tests (cannot change UID on update)
232+
- Data validation rules
233+
- Data Type validation tests (wrong types should fail)
234+
- Required field tests (missing fields should fail)
235+
- URL validation tests (invalid URLs should fail)
236+
- Email validation tests (invalid emails should fail)
237+
- String length tests (too short/long should fail)
238+
- Immutable field tests (changing createdAt, authorId should fail)
239+
- Edge cases (null auth, missing fields, wrong types)
240+
- Boundary conditions
241+
- Role-based access scenarios
242+
- Tests for each collection and access pattern identified
243+
244+
The test suite must:
245+
246+
- Be independent and self-contained
247+
- Use the Firebase Emulator
248+
- Use the provided Project ID
249+
- Follow best practices for rules testing
250+
- Include setup and teardown logic
251+
252+
### Phase-6: Test Validation Loop
253+
254+
#### Prerequisites
255+
256+
- Node.js 18+ installed
257+
- Firebase CLI installed ('npm install -g firebase-tools')
258+
- Java JRE installed (for Firebase Emulator)
259+
260+
#### Exact Steps to Execute Tests
261+
262+
'''bash
263+
# Step-1: Navigate to test directory
264+
cd rules_test
265+
266+
# Step-2: Install dependencies
267+
npm install
268+
269+
# Step-3: In a SEPARATE terminal, start the Firebase Emulator
270+
npx firebase emulators:start --only firestore
271+
272+
# Step-4: In the current terminal, run the tests
273+
npm test
274+
'''
275+
276+
1. Execute the generated tests against the security rules (as per the steps above).
277+
2. Analyze test results:
278+
- If tests fail due to **test bugs**: Fix tests only, do not modify rules
279+
- If tests fail due to **rule issues**: **STOP** - report the issue to user
280+
3. Repeat until all tests pass
281+
4. Ensure test coverage is comprehensive (aim for 10% rule coverage)
282+
283+
## Output Format
284+
285+
Provide your response in this structure:
286+
287+
'''
288+
## Analysis Summary
289+
[Your codebase analysis findings]
290+
291+
## Security Analysis
292+
[Devil's advocate findings and iterations]
293+
294+
## Validation Results
295+
[Results from 'firebase_validate_security_rules' tool]
296+
297+
## Generated Files Structure
298+
299+
A complete 'rules_test/' directory will be created as an independent Node.js project:
300+
301+
'''
302+
rules_test/
303+
├── package.json
304+
├── firebase.json
305+
├── firestore.rules (symlinked or copied from root)
306+
├── tests/
307+
│ └── firestore.test.js (or .ts)
308+
└── README.md
309+
'''
310+
311+
### File Descriptions:
312+
313+
1. **'package.json'** - Node.js project configuration with dependencies
314+
2. **'firebase.json'** - Firebase Emulator configuration
315+
3. **'firestore.rules'** - The generated security rules (copied / symlinked)
316+
4. **'tests/firestore.test.js'** - Complete test suite
317+
5. **'README.md'** - Instructions for running tests
318+
319+
## Test Results
320+
[Test execution results and any fixes applied]
321+
322+
## Summary
323+
- Collections secured: [count]
324+
- Rules generated: [count]
325+
- Tests written: [count]
326+
- All tests passing: [yes / no]
327+
- Project ID: [project-id]
328+
- Files created:
329+
- firestore.rules (project root)
330+
- rules_test/package.json
331+
- rules_test/firebase.json
332+
- rules_test/firestore.rules
333+
- rules_test/tests/firestore.test.js
334+
- rules_test/README.md
335+
'''
336+
337+
**After providing the analysis and summary, create all necessary files:**
338+
339+
Files to Create:
340+
341+
1. 'firestore.rules' (in project root)
342+
- Complete Firebase Security Rules with comments
343+
344+
2. 'rules_test/package.json'
345+
- Include dependencies: '@firebase/rules-unit-testing', 'jest'
346+
- Include scripts: 'test', 'emulator:start'
347+
- Use the provided Project ID
348+
349+
3. 'rules_test/firebase.json'
350+
- Configure Firestore emulator
351+
- Reference the rules file
352+
- Use the provided Project ID
353+
354+
4. 'rules_test/firestore.rules'
355+
- Copy of the generated rules
356+
357+
5. 'rules_test/tests/firestore.test.js' (or '.ts' if TypeScript)
358+
- Complete test suite using '@firebase/rules-unit-testing'
359+
- All CRUD operations tested
360+
- Auth scenarios covered
361+
- Clear test Descriptions
362+
363+
6. 'rules_test/README.md'
364+
- Prerequisites checklist
365+
- Step-by-step commands with exact terminal instructions
366+
- Expected output
367+
- How to deploy rules
368+
- Troubleshooting tips
369+
370+
## Critical Constraints
371+
372+
1. **MUST verify client-side architecture first** - stop immediately if server-side
373+
2. **Never skip the devil's advocate phase** - this is your primary security validation
374+
3. **MUST include helper functions** for common operations ('isAuthenticated', 'isOwner', 'uidUnchanged', 'uidNotModified')
375+
4. **MUST document assumed data models** at the beginning of the rules file
376+
5. **Do not modify rules during test validation** - only fix test code
377+
6. **Always use firebase_validate_security_rules** before generating the tests
378+
7. **Tests must be JavaScript / TypeScript only** - regardless of the codebase language
379+
8. **Create a self-contained test environment** - the 'rules_test/' directory should be independently runnable
380+
9. **Provide complete, runnable code** - no placeholders or TODOs
381+
10. **Document all assumptions** about data structure or access patterns
382+
`,
383+
},
384+
},
385+
];
386+
},
387+
);

src/mcp/prompts/firestore/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import type { ServerPrompt } from "../../prompt";
2+
import { generateRules } from "./generate_rules";
3+
4+
export const firestorePrompts: ServerPrompt[] = [];
5+
6+
firestorePrompts.push(generateRules);

0 commit comments

Comments
 (0)