checkmyvibe 1.1.0 → 1.2.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # checkmyvibe
2
2
 
3
- A structured, zero-dependency, local production readiness and code quality workflow packaged as an Agent Skill for AI coding assistants (such as Claude Code, Cursor, Codex, and Gemini CLI).
3
+ A structured, zero-dependency, local production readiness and code quality workflow packaged as an Agent Skill for AI coding assistants. Built for Claude Code today; the skill and command files can be adapted to other agents' rule/command formats.
4
4
 
5
5
  AI-generated ("vibe-coded") applications built on modern AI tools frequently ship with serious, well-documented configuration and quality issues—such as exposed API keys, fake authentication stubs, permissive default database rules, and client-side pricing logic. **checkmyvibe** solves this by packaging readiness and verification checks directly into an Agent Skill. When you ask your coding agent to "run checkmyvibe" or "perform a readiness check", the agent uses checkmyvibe's local helper scripts and its own reasoning capabilities to analyze your codebase, producing a prioritized report detailing what configuration issues or gaps exist, why they matter, and how to fix them.
6
6
 
@@ -13,7 +13,7 @@ AI-generated ("vibe-coded") applications built on modern AI tools frequently shi
13
13
  * **Fake & Stubbed Authentication:** Greps for common mock authentication markers (such as functions named `mockAuth`, `fakeLogin`, `tempAuth`, or logic that returns `true` unconditionally to bypass authentication checks).
14
14
  * **Database Misconfigurations:** Identifies permissive default rules (such as `allow read, write: if true;` in Firebase/Firestore configs) and checks if Row-Level Security (RLS) is enabled on Supabase database schemas.
15
15
  * **Broken Object-Level Authorization (BOLA/IDOR):** Analyzes API routes to check if endpoints fetch resources by ID without validating that the authenticated user owns or has permission to access that resource.
16
- * **Client-Side Payment & Pricing Logic:** Scans checkout routes and payment integrations to check if prices or transaction values are calculated or accepted directly from client-side parameters rather than securely fetched on the server.
16
+ * **Client-Side Payment & Pricing Logic:** Scans checkout routes and payment integrations to check if prices or transaction values are calculated or accepted directly from client-side parameters rather than securely fetched on the server, and verifies that payment webhooks validate provider signatures before trusting event payloads.
17
17
 
18
18
  ---
19
19
 
@@ -59,12 +59,14 @@ When actively developing a specific feature, run focused scans for fast, targete
59
59
 
60
60
  | Slash Command | Scope / Keyword | Included Checks | Use Case |
61
61
  | :--- | :--- | :--- | :--- |
62
- | `/checkmyvibe-secrets` | `/checkmyvibe secrets` | Check 1 + Check 2 | Exposed API keys, hardcoded credentials, and `.gitignore` hygiene |
62
+ | `/checkmyvibe-secrets` | `/checkmyvibe secrets` | Checks 1a + 1b + 2 | Server-side and client-exposed API keys/credentials, plus `.gitignore` hygiene |
63
63
  | `/checkmyvibe-auth` | `/checkmyvibe auth` | Check 3 | Missing, mock, stubbed, or bypassed authentication guards |
64
64
  | `/checkmyvibe-db` | `/checkmyvibe db` | Check 4 | Database & BaaS rules, Supabase RLS policies, Firebase permissions |
65
- | `/checkmyvibe-backend` | `/checkmyvibe backend` | Checks 3, 4, 5, 6 (server), 7 | All server-side logic: auth, DB/RLS, IDOR/BOLA, SQLi/input validation, pricing |
66
- | `/checkmyvibe-frontend` | `/checkmyvibe frontend` | Checks 1 (client), 3 (client), 7 (client) | Client bundle key leaks, UI-only auth hiding, client-side pricing overrides |
67
- | `/checkmyvibe-payment` | `/checkmyvibe payment` | Check 7 | Client-side payment tampering, price overrides, and checkout integrity |
65
+ | `/checkmyvibe-backend` | `/checkmyvibe backend` | Checks 1a, 3, 4, 5, 6 (server), 7 (server) | All server-side logic: hardcoded server credentials, auth, DB/RLS, IDOR/BOLA, SQLi/input validation/mass assignment, payment & webhook processing |
66
+ | `/checkmyvibe-frontend` | `/checkmyvibe frontend` | Checks 1b, 3 (client), 7 (client) | Client bundle key leaks, UI-only auth hiding, client-side pricing overrides |
67
+ | `/checkmyvibe-payment` | `/checkmyvibe payment` | Check 7 | Client-side payment tampering, price overrides, unverified webhooks, checkout integrity |
68
+
69
+ Each scoped command file contains its complete operating instructions inline — it only falls back to `SKILL.md` for the report format and severity rubric — so scoped scans work reliably even when skill auto-discovery fails.
68
70
 
69
71
  The agent will walk through the scoped checks, execute relevant local helper scripts, and print a prioritized markdown report (Critical / Should Fix / Worth Reviewing) with concrete remediation steps.
70
72
 
package/SKILL.md CHANGED
@@ -40,13 +40,15 @@ checkmyvibe supports targeted/scoped scanning for rapid iteration during develop
40
40
 
41
41
  | Scope / Command Keyword | Included Checks | Description / Focus Area |
42
42
  | :--- | :--- | :--- |
43
- | **`secrets`** | **Check 1 + Check 2** | Exposed credentials, API keys, tokens, and `.gitignore` file protection |
43
+ | **`secrets`** | **Check 1a + Check 1b + Check 2** | Server-side and client-exposed credentials, API keys, tokens, and `.gitignore` file protection |
44
44
  | **`auth`** | **Check 3** | Missing, mock, stubbed, or bypassed authentication guards |
45
45
  | **`db`** | **Check 4** | Database & BaaS rules, Supabase RLS policies, Firebase/storage permissions |
46
- | **`backend`** | **Check 3 + Check 4 + Check 5 + Check 6 (server-side) + Check 7** | All server-side logic: auth guards, database configs, IDOR/BOLA, SQLi/input validation, and payment processing |
47
- | **`frontend`** | **Check 1 (client-exposed) + Check 3 (client-only auth) + Check 7 (client pricing)** | Client-side bundle leaks, UI-only auth hiding, and client-controlled payment/pricing logic |
48
- | **`payment`** | **Check 7** | Client-side payment amount tampering, price overrides, and checkout integrity |
49
- | *(no argument / `full`)* | **All Checks (1–7)** | Full production readiness and code quality audit |
46
+ | **`backend`** | **Check 1a + Check 3 + Check 4 + Check 5 + Check 6 (server-side) + Check 7 (server-side)** | All server-side logic: hardcoded server credentials, auth guards, database configs, IDOR/BOLA, SQLi/input validation, mass assignment, and payment/webhook processing |
47
+ | **`frontend`** | **Check 1b + Check 3 (client-side view) + Check 7 (client-side view)** | Client-side bundle leaks, UI-only auth hiding, and client-controlled payment/pricing logic |
48
+ | **`payment`** | **Check 7** | Client-side payment amount tampering, price overrides, unverified webhooks, and checkout integrity |
49
+ | *(no argument / `full`)* | **All Checks (1a–7)** | Full production readiness and code quality audit |
50
+
51
+ > **Canonical definitions note:** The check definitions in this file are canonical. The scoped command files (`commands/checkmyvibe-*.md`) contain mirrored copies of their relevant checks so they can run standalone. When you change what a check does, update it here AND in every command file that mirrors it.
50
52
 
51
53
  ### Rules for Scoped Runs:
52
54
  - **Execute only the selected checks:** Do not run unselected check scripts or inspect code outside the chosen scope.
@@ -88,7 +90,7 @@ Critical user exposure > auth bypass > IDOR > payment logic > config issues > hy
88
90
 
89
91
  The report should help the coding agent make the repo safer in the next commit, not just describe problems.
90
92
 
91
- ## Check 1: Exposed secrets and credentials
93
+ ## Check 1a: Server-side secrets and credentials
92
94
 
93
95
  **Run the script** `scripts/scan_secrets.py` (located relative to this `SKILL.md` file) against the project root. It flags known key
94
96
  prefixes (`sk_live`, `sk_test`, `AIza`, `AKIA`, `ghp_`, `xox[bp]`), high-entropy
@@ -97,14 +99,13 @@ strings, and variable assignments where a name like `key`, `secret`, `token`, or
97
99
 
98
100
  **What counts as a finding:**
99
101
 
100
- - A real credential committed directly in source, e.g.:
101
- `const stripeKey = "sk_live_51H8x..."` — Critical
102
- - A secret present only in `.env` but `.env` is not gitignored (see Check 2) —
103
- Critical, because it WILL leak on the next commit even if it hasn't yet
104
- - A secret exposed to the client bundle — e.g. a server-only key referenced in
105
- frontend code, or a Next.js env var missing the required server-only scoping
106
- (using a secret key where only `NEXT_PUBLIC_`-prefixed vars should appear) —
107
- Critical, this is directly shippable to every visitor's browser
102
+ - A real credential committed directly in server-side source, e.g.:
103
+ `const stripeKey = "sk_live_51H8x..."` — **Critical**
104
+ - A **live** Stripe secret key (`sk_live_...`) anywhere in source — **Critical**, charges real cards
105
+ - A **test** Stripe secret key (`sk_test_...`) committed in source — **Should Fix**, not production-critical but test keys still must not be committed; rotate if the repo has ever been shared
106
+ - A server-only credential referenced in frontend code, or a Next.js env var
107
+ missing the required server-only scoping (using a secret key where only
108
+ `NEXT_PUBLIC_`-prefixed vars should appear) — **Critical**, this is directly shippable to every visitor's browser
108
109
 
109
110
  **What is NOT a finding (avoid false positives):**
110
111
 
@@ -114,6 +115,20 @@ strings, and variable assignments where a name like `key`, `secret`, `token`, or
114
115
  configured. Note this distinction explicitly in the report so the user isn't
115
116
  confused about why one key is fine and another isn't.
116
117
  - Example/placeholder values clearly meant as documentation, e.g. `"your-api-key-here"`
118
+ - Fake credentials inside unit tests, fixtures, or mock files (the scripts already skip these directories; if you find one manually, do not report it)
119
+
120
+ ## Check 1b: Client-exposed secrets (frontend scope view)
121
+
122
+ This is the client-facing slice of Check 1a, used by the `frontend` scope. Focus on:
123
+
124
+ - Secrets reachable from the client bundle: any secret referenced in frontend
125
+ code, anything passed through `NEXT_PUBLIC_*` / `VITE_*` / `REACT_APP_*` env
126
+ vars that isn't genuinely public, and secrets inlined in client config files.
127
+ - Service-role keys (Supabase `service_role`, Firebase admin SDK private keys,
128
+ OpenAI/Stripe secret keys) appearing anywhere under `src/`, `app/`,
129
+ `components/`, `public/`, or client entry points — **Critical**.
130
+
131
+ The severity rules and false-positive guidance from Check 1a apply unchanged.
117
132
 
118
133
  ## Check 2: .gitignore hygiene
119
134
 
@@ -231,6 +246,14 @@ Spot-check forms and API endpoints for:
231
246
  - User input rendered into HTML without escaping (XSS risk), especially in
232
247
  frameworks that don't auto-escape by default
233
248
  - File uploads with no restriction on file type or size
249
+ - **Mass assignment:** request bodies spread directly into ORM create/update calls,
250
+ e.g. `await prisma.user.update({ where: { id }, data: req.body })` — lets a user
251
+ set fields they should never control (`role`, `plan`, `isAdmin`, `emailVerified`).
252
+ Flag when the body is not explicitly whitelisted to safe fields. — Critical if a
253
+ privileged field can be set, otherwise Should Fix
254
+ - **No rate limiting on auth endpoints:** login, signup, password reset, and OTP
255
+ endpoints with no throttle/attempt limit allow credential stuffing and SMS-cost
256
+ abuse — Worth Reviewing at minimum, Should Fix for payment-handling apps
234
257
 
235
258
  This check doesn't need to be exhaustive — flag the clearest, highest-impact
236
259
  examples rather than every single form field, and note in the summary that a
@@ -257,6 +280,30 @@ app.post('/api/checkout', async (req, res) => {
257
280
  });
258
281
  ```
259
282
 
283
+ Also check **payment webhook signature verification** — this is the sibling flaw to
284
+ client-side pricing and just as common:
285
+
286
+ - A webhook endpoint (Stripe, Firebase, PayPal, Razorpay) that reads the event body
287
+ and acts on it **without verifying the signature first**. Anyone who finds the URL
288
+ can POST `{ "type": "payment_intent.succeeded", ... }` and get their order marked paid.
289
+ - Correct pattern (Express + Stripe):
290
+ ```js
291
+ app.post('/api/webhooks/stripe',
292
+ express.raw({ type: 'application/json' }), // raw body required for signature check
293
+ (req, res) => {
294
+ const event = stripe.webhooks.constructEvent(
295
+ req.body, req.headers['stripe-signature'], process.env.STRIPE_WEBHOOK_SECRET
296
+ );
297
+ // only now is the event trustworthy
298
+ });
299
+ ```
300
+ - Equivalent checks: Firebase Cloud Functions `onRequest` deployed with secret
301
+ headers compared server-side, PayPal webhook `verify-webhook-signature` API,
302
+ Razorpay `verifyPaymentSignature`. If a webhook route exists and no signature
303
+ verification call exists anywhere in the flow — **Critical**.
304
+ - Discount/coupon values accepted from the client rather than looked up from a
305
+ trusted source server-side — same severity as price tampering.
306
+
260
307
  ---
261
308
 
262
309
  ## Severity rubric
@@ -303,6 +350,8 @@ Once the checks are complete, create a readiness review report. **The report mus
303
350
  - what still needs attention
304
351
  - the final readiness verdict
305
352
 
353
+ **Post-fix verification:** if you applied fixes during this session, re-run the scripts for every category you touched and confirm the finding is actually gone before marking it fixed in the report. Report before/after per check (e.g. "scan_secrets.py: 3 findings → 0 findings"). A fix that hasn't been re-scanned must be listed as "applied, not yet verified", never as resolved.
354
+
306
355
  If no issues are found, still produce a short report that says no blocking issues were found in this pass, which categories were checked, and what the remaining scope limits are.
307
356
 
308
357
  ## Example report style
@@ -1,3 +1,46 @@
1
- Read the checkmyvibe `SKILL.md`. Run only **Check 3 (missing or fake authentication)** from that skill.
1
+ # /checkmyvibe-auth — Missing or fake authentication
2
2
 
3
- Use the same report format, severity rubric, and final summary structure defined in `SKILL.md`, but scope the final summary to note that this was an authentication-only check (Checks 1, 2, 4, 5, 6, and 7 were skipped), not a full audit, and suggest running the full `/checkmyvibe` audit before launch.
3
+ First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
4
+
5
+ 1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
6
+ 2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
7
+ 3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
8
+
9
+ Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
10
+
11
+ **Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
12
+
13
+ ## Scope
14
+
15
+ This is an **authentication-only check** (Check 3). Checks 1a/1b, 2, 4, 5, 6, and 7 are skipped and must be listed as skipped in the final summary.
16
+
17
+ ## Step 1 — Run the first-pass script
18
+
19
+ ```bash
20
+ python <skill_dir>/scripts/check_auth_patterns.py <target>
21
+ ```
22
+
23
+ It flags stub names (`mockAuth`, `fakeLogin`, `tempAuth`, `bypassAuth`, ...) and always-true auth functions. If Python is unavailable or it fails, say so and do the equivalent greps manually. The script skips test directories — do not report mock auth inside unit tests even if you see it manually.
24
+
25
+ ## Step 2 — Manual reasoning pass (this is where the real findings are)
26
+
27
+ The script is a first pass only. Read the actual auth code: login handlers, middleware, route guards, session checks, and every route that returns or modifies user-specific data.
28
+
29
+ Findings to hunt for:
30
+
31
+ - **Always-true stubs:** `function isAuthenticated() { return true; }`, `const checkAdmin = () => true` — Critical.
32
+ - **Stub-named helpers still wired in:** `mockAuth`, `devAuth`, `bypassAuth` reachable in production paths — Critical. Properly guarded behind `NODE_ENV === 'development'` → Should Fix (env misconfig leaks these constantly); verify the guard actually covers every import/call site.
33
+ - **Protected routes with no auth check at all:** list every route returning user-specific data, then check each one calls the session/auth middleware. A `/api/orders/:id` with no guard is Critical regardless of what the UI does.
34
+ - **Client-side-only enforcement:** UI hides a button/route for logged-out users but the underlying API never verifies the session — Critical. Anyone calls the API directly. To confirm this you MUST read the corresponding server route; do not clear a finding from the frontend alone.
35
+ - **Commented-out auth checks** with an active bypass nearby.
36
+ - **JWT/session verification gaps:** tokens decoded but not verified (`jwt.decode` instead of `jwt.verify`, no algorithm pinning), sessions accepted from client-controlled storage without server validation — Critical.
37
+
38
+ ## Step 3 — Judgment rules
39
+
40
+ - Read the function body fully before flagging or clearing — never decide from the name alone.
41
+ - Prefer one precise finding over several weak ones; tag uncertain items `High confidence` / `Medium confidence` / `Needs manual review`.
42
+ - Identify the stack's intended auth mechanism (NextAuth, Clerk, Supabase Auth, custom JWT) first; "missing" means missing relative to how routes access user data, not absence of a specific library.
43
+
44
+ ## Report
45
+
46
+ Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder: "authentication-only check — secrets, .gitignore, database rules, IDOR, input validation, and payment checks were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch."
@@ -1,8 +1,62 @@
1
- Read the checkmyvibe `SKILL.md`. Run only the server-side / backend checks from that skill:
2
- - **Check 3 (missing or fake authentication)**
3
- - **Check 4 (database and backend-as-a-service misconfiguration)**
4
- - **Check 5 (broken object-level authorization / IDOR)**
5
- - **Check 6 (unvalidated inputs, server-side / query portion)**
6
- - **Check 7 (payment and pricing logic)**
7
-
8
- Use the same report format, severity rubric, and final summary structure defined in `SKILL.md`, but scope the final summary to note that this was a backend-only check (Check 1 client bundle secrets and Check 2 .gitignore hygiene were skipped), not a full audit, and suggest running the full `/checkmyvibe` audit before launch.
1
+ # /checkmyvibe-backend — Server-side audit
2
+
3
+ First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
4
+
5
+ 1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
6
+ 2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
7
+ 3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
8
+
9
+ Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
10
+
11
+ **Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
12
+
13
+ ## Scope
14
+
15
+ This is a **backend-only check**: Check 1a (server-side secrets) + Check 3 (auth) + Check 4 (db) + Check 5 (IDOR) + Check 6 server-side + Check 7 server-side. Skipped and to be listed as such in the summary: Check 1b (client-exposed secrets), Check 2 (.gitignore hygiene), and client-side views of checks 3/6/7.
16
+
17
+ ## Step 1 — Run all three scripts
18
+
19
+ ```bash
20
+ python <skill_dir>/scripts/scan_secrets.py <target>
21
+ python <skill_dir>/scripts/check_auth_patterns.py <target>
22
+ python <skill_dir>/scripts/check_db_config.py <target>
23
+ ```
24
+
25
+ Triage per the rules in `/checkmyvibe-secrets`, `/checkmyvibe-auth`, and `/checkmyvibe-db` respectively: live keys Critical / test keys Should Fix; mock-auth hits outside tests need manual reading; missing RLS and `USING (true)` policies are Critical on user-data tables. If Python is unavailable, do each check manually and say so in the report.
26
+
27
+ ## Step 2 — IDOR sweep (Check 5 — spend the most time here)
28
+
29
+ This is the single most common serious flaw in AI-generated apps. Enumerate every route that takes an ID (URL param, query string, or body field) and touches a database record:
30
+
31
+ ```js
32
+ // Finding example — Critical: any logged-in user reads ANY order
33
+ app.get('/api/orders/:id', requireAuth, async (req, res) => {
34
+ const order = await db.query('SELECT * FROM orders WHERE id = $1', [req.params.id]);
35
+ res.json(order);
36
+ });
37
+
38
+ // Correct fix pattern: scope by owner, return 404 when absent
39
+ const order = await db.query(
40
+ 'SELECT * FROM orders WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]);
41
+ if (!order) return res.status(404).json({ error: 'Not found' });
42
+ ```
43
+
44
+ Check GET (exposure), PUT/PATCH (unauthorized modification), and DELETE (often most damaging) for all of them. An auth guard alone is not enough — ownership must be enforced in the query or immediately after fetch.
45
+
46
+ ## Step 3 — Server-side input handling (Check 6)
47
+
48
+ - SQL built by string concatenation instead of parameterized queries/ORM → Critical.
49
+ - **Mass assignment:** `req.body` spread straight into ORM create/update (`prisma.user.update({ data: req.body })`, `User.findByIdAndUpdate(id, req.body)`) letting users set `role`, `plan`, `isAdmin`, `emailVerified` → Critical; non-privileged fields → Should Fix.
50
+ - Unescaped user input into HTML in non-auto-escaping frameworks → flag worst cases.
51
+ - Login/signup/password-reset/OTP endpoints with no rate limiting → Should Fix for payment-handling apps, Worth Reviewing otherwise.
52
+ - File uploads with no type/size restriction.
53
+
54
+ ## Step 4 — Payment processing & webhooks (Check 7, server side)
55
+
56
+ - Price/discount/total taken from request body, query param, or hidden field instead of looked up from the DB → Critical.
57
+ - **Webhook signature verification:** every payment webhook route (Stripe, PayPal, Razorpay, Firebase) must verify the signature before trusting the body — e.g. Stripe's `stripe.webhooks.constructEvent(rawBody, sigHeader, webhookSecret)` with the raw body. A webhook route with no signature verification anywhere in its flow → Critical: anyone can POST "payment succeeded" and get their order marked paid.
58
+ - Webhook handlers acting on unverified amounts read from the event body → same severity.
59
+
60
+ ## Report
61
+
62
+ Use the format, severity rubric, evidence/confidence rules, and post-fix verification step from SKILL.md. Fix priority when multiple issues exist: critical user exposure > auth bypass > IDOR > payment logic > config > hygiene. Scope reminder: "backend-only check — client-exposed secrets, .gitignore hygiene, and frontend-side views were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch."
@@ -1,3 +1,51 @@
1
- Read the checkmyvibe `SKILL.md`. Run only **Check 4 (database and backend-as-a-service misconfiguration)** from that skill.
1
+ # /checkmyvibe-db — Database & BaaS misconfiguration
2
2
 
3
- Use the same report format, severity rubric, and final summary structure defined there, but scope the final summary to note that this was a database-only check (Checks 1, 2, 3, 5, 6, and 7 were skipped), not a full audit, and suggest running the full `/checkmyvibe` audit before launch.
3
+ First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
4
+
5
+ 1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
6
+ 2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
7
+ 3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
8
+
9
+ Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
10
+
11
+ **Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
12
+
13
+ ## Scope
14
+
15
+ This is a **database-only check** (Check 4). Checks 1a/1b, 2, 3, 5, 6, and 7 are skipped and must be listed as skipped in the final summary.
16
+
17
+ ## Step 1 — Run the first-pass script
18
+
19
+ ```bash
20
+ python <skill_dir>/scripts/check_db_config.py <target>
21
+ ```
22
+
23
+ It scans SQL files for tables created without RLS and permissive policies (`USING (true)` / `WITH CHECK (true)`), Firestore/storage rules for `allow ...: if true`, and Realtime Database rules set to `"true"`. If Python is unavailable or it fails, do the equivalent checks by reading schema/rules files manually and say so in the report.
24
+
25
+ ## Step 2 — Supabase (if used)
26
+
27
+ - Every table holding user-specific data must have `ENABLE ROW LEVEL SECURITY`. A table without it → Critical.
28
+ - Policies granting broad access fail: `FOR SELECT USING (true)`, policies `TO public/anon` with unconditional USING/CHECK → Critical.
29
+ - Recommended fix pattern:
30
+ ```sql
31
+ CREATE POLICY "users see own orders" ON orders
32
+ FOR SELECT USING (auth.uid() = user_id);
33
+ ```
34
+ - Check migrations/schema files under `supabase/migrations/`, `db/`, or wherever `.sql` files live. Also confirm RLS wasn't enabled *after* data was already readable via the anon key in earlier deployments.
35
+
36
+ ## Step 3 — Firebase (if used)
37
+
38
+ - `firestore.rules`: any `allow read, write: if true;` on collections holding user data → Critical. Test-mode rules (`allow read, write: if <timestamp>`) pasted into prod-like configs → Should Fix minimum.
39
+ - `database.rules.json` (Realtime DB): `".read": "true"` / `".write": "true"` on user-data nodes → Critical.
40
+ - Rules files present but clearly unused/default → Worth Reviewing; verify which project they deploy to.
41
+
42
+ ## Step 4 — Storage buckets
43
+
44
+ Supabase Storage, Firebase Storage, S3:
45
+
46
+ - Public buckets holding private user content (documents, receipts, profile files) → Critical.
47
+ - Public buckets for genuinely public assets (avatars, static images) → not findings; note the distinction.
48
+
49
+ ## Report
50
+
51
+ Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder: "database-only check — secrets, .gitignore, authentication, IDOR, input validation, and payment checks were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch."
@@ -1,6 +1,48 @@
1
- Read the checkmyvibe `SKILL.md`. Run only the frontend / client-side checks from that skill:
2
- - **Check 1 (client-exposed secrets in frontend bundles and environment configurations)**
3
- - **Check 3 (client-side-only auth checks / UI hiding without server enforcement)**
4
- - **Check 7 (client-side payment or pricing logic)**
1
+ # /checkmyvibe-frontend — Client-side audit
5
2
 
6
- Use the same report format, severity rubric, and final summary structure defined in `SKILL.md`, but scope the final summary to note that this was a frontend-only check (Check 2 .gitignore hygiene, Check 4 database rules, Check 5 IDOR, Check 6 server input validation, and full server auth checks were skipped), not a full audit, and suggest running the full `/checkmyvibe` audit before launch.
3
+ First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
4
+
5
+ 1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
6
+ 2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
7
+ 3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
8
+
9
+ Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
10
+
11
+ **Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
12
+
13
+ ## Scope
14
+
15
+ This is a **frontend-only check**: Check 1b (client-exposed secrets) + Check 3 viewed from the client (UI-only enforcement) + Check 7 viewed from the client (client-controlled pricing). Skipped and to be listed as such in the summary: Check 1a standalone triage, Check 2 (.gitignore), Check 4 (db rules), Check 5 (IDOR sweep), and full server-side reviews of auth/input/payment.
16
+
17
+ ## Step 1 — Client-exposed secrets (run script, then manual pass)
18
+
19
+ ```bash
20
+ python <skill_dir>/scripts/scan_secrets.py <target>
21
+ ```
22
+
23
+ Then manually inspect everything reachable from the browser:
24
+
25
+ - Framework env prefixes bundle values INTO shipped JS: `NEXT_PUBLIC_*`, `VITE_*`, `REACT_APP_*`, `EXPO_PUBLIC_*`. Any secret behind one of these → Critical.
26
+ - Supabase `service_role` key, Firebase admin SDK JSON, OpenAI/Stripe secret keys anywhere under `src/`, `app/`, `components/`, `pages/`, `public/`, or client entry files → Critical.
27
+ - Publishable keys (`pk_`, Supabase anon key, Firebase web config `apiKey`) are public-by-design → NOT findings; say so explicitly so the report isn't confusing.
28
+ - Placeholders and test-fixture values → not findings.
29
+
30
+ ## Step 2 — UI-only auth enforcement (Check 3, client view)
31
+
32
+ Find every place the UI gates access: redirects on protected pages, hidden nav items, disabled buttons, client route guards:
33
+
34
+ - For each gated feature, open the corresponding API route/mutation and confirm it independently verifies the session server-side. If it does not → Critical ("hiding the button does nothing; anyone calls the API directly").
35
+ - Auth state trusted purely from client storage (localStorage JWT, global store) to protect data → Critical if no server verification exists.
36
+ - You must read the server routes to clear or confirm findings — a clean-looking frontend proves nothing on its own.
37
+
38
+ ## Step 3 — Client-controlled pricing (Check 7, client view)
39
+
40
+ Inspect checkout/cart/pricing flows:
41
+
42
+ - Prices, discounts, totals, or quantities computed client-side and sent as the chargeable value (hidden form fields, request bodies, query params) → Critical on the corresponding server endpoint.
43
+ - Coupon codes validated only in the UI → flag the endpoint that accepts them without server-side validation.
44
+ - Note exactly which server endpoint accepts the tainted value so the backend fix is obvious.
45
+
46
+ ## Report
47
+
48
+ Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder: "frontend-only check — server-side secret triage, .gitignore hygiene, database rules, IDOR, server input validation, and webhook verification were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch."
@@ -1,3 +1,52 @@
1
- Read the checkmyvibe `SKILL.md`. Run only **Check 7 (client-side payment or pricing logic)** from that skill.
1
+ # /checkmyvibe-payment — Payment & pricing integrity
2
2
 
3
- Use the same report format, severity rubric, and final summary structure defined in `SKILL.md`, but scope the final summary to note that this was a payment/pricing-only check (Checks 1, 2, 3, 4, 5, and 6 were skipped), not a full audit, and suggest running the full `/checkmyvibe` audit before launch.
3
+ First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
4
+
5
+ 1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
6
+ 2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
7
+ 3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
8
+
9
+ Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
10
+
11
+ **Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
12
+
13
+ ## Scope
14
+
15
+ This is a **payment/pricing-only check** (Check 7, both client and server views). Checks 1a/1b, 2, 3, 4, 5, and 6 are skipped and must be listed as skipped in the final summary. Note: if this app handles real payments, state in the report that a professional external review is strongly recommended regardless of findings.
16
+
17
+ ## Step 1 — Map the payment surface
18
+
19
+ Identify the provider (Stripe, PayPal, Razorpay, Firebase-based, custom) and locate: checkout endpoints, webhook routes, cart/price calculation code (client and server), subscription/plan management, and coupon/discount handling. If there is no payment code at all, report "No issues found — no payment flow exists" and stop.
20
+
21
+ ## Step 2 — Server-side price trust
22
+
23
+ For each chargeable action:
24
+
25
+ - Is the amount read from the request (body field, query param, hidden form field) or computed from client-supplied data? → Critical:
26
+ ```js
27
+ // Finding example — Critical
28
+ const { productId, price } = req.body;
29
+ await chargeCard(req.user.paymentMethod, price);
30
+
31
+ // Correct fix pattern — server looks up the price
32
+ const { productId } = req.body;
33
+ const product = await db.query('SELECT price FROM products WHERE id = $1', [productId]);
34
+ await chargeCard(req.user.paymentMethod, product.price);
35
+ ```
36
+ - Quantities, currency, plan tiers, or seat counts accepted from the client and multiplied into totals without server-side lookup → same severity.
37
+ - Coupons/discounts validated only on the client, or discount values sent by the client rather than looked up server-side → Critical.
38
+ - Free-trial/trial-flag booleans trusted from request bodies → Critical (anyone posts `trial: true` forever).
39
+
40
+ ## Step 3 — Webhook signature verification (most-missed check)
41
+
42
+ Every payment webhook route must verify authenticity BEFORE trusting or acting on its body:
43
+
44
+ - Stripe: `stripe.webhooks.constructEvent(rawBody, sigHeader, process.env.STRIPE_WEBHOOK_SECRET)` with `express.raw({ type: 'application/json' })` on the route. No signature verification anywhere in the handler chain → Critical: anyone who finds the URL can POST a fake `payment_intent.succeeded` and get orders marked paid for free.
45
+ - PayPal: `verify-webhook-signature` API call missing → Critical.
46
+ - Razorpay: missing `verifyPaymentSignature` / HMAC comparison → Critical.
47
+ - Firebase/custom webhooks: no shared-secret header compared server-side → Critical.
48
+ - Also flag webhook handlers that fulfill orders based on amounts read from the unverified event payload instead of re-fetching them server-side.
49
+
50
+ ## Report
51
+
52
+ Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder: "payment-only check — secrets, .gitignore, authentication, database rules, IDOR, and input validation were skipped. This does not mean the app is production-ready. Run a full `/checkmyvibe` audit before launch, and get a professional security review before handling real money."
@@ -1,3 +1,55 @@
1
- Read the checkmyvibe `SKILL.md`. Run only **Check 1 (exposed secrets and credentials)** and **Check 2 (.gitignore hygiene)** from that skill.
1
+ # /checkmyvibe-secrets — Exposed secrets & .gitignore hygiene
2
2
 
3
- Use the same report format, severity rubric, and final summary structure defined in `SKILL.md`, but scope the final summary to note that this was a secrets-only check (Checks 3, 4, 5, 6, and 7 were skipped), not a full audit, and suggest running the full `/checkmyvibe` audit before launch.
3
+ First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
4
+
5
+ 1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
6
+ 2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
7
+ 3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
8
+
9
+ Use SKILL.md **only** for the report format, severity rubric, and final-summary structure. The complete operating instructions for this scope are below — follow them even if SKILL.md cannot be found.
10
+
11
+ **Optional argument:** a target directory may be passed after the command. Default to the project root if not given. Scripts live in the `scripts/` folder next to SKILL.md.
12
+
13
+ ## Scope
14
+
15
+ This is a **secrets-only check**: Check 1a (server-side secrets) + Check 1b (client-exposed secrets) + Check 2 (.gitignore hygiene). Checks 3–7 are skipped and must be listed as skipped in the final summary.
16
+
17
+ ## Step 1 — Run both scripts
18
+
19
+ ```bash
20
+ python <skill_dir>/scripts/scan_secrets.py <target>
21
+ python <skill_dir>/scripts/check_gitignore.py <target>
22
+ ```
23
+
24
+ If Python is unavailable or a script fails, say so explicitly in the report ("automated secret scan could not run; manually reviewed instead") and do the equivalent manually: grep for key prefixes (`sk_live_`, `sk_test_`, `AIza`, `AKIA`, `ghp_`, `xox[bp]-`) and literal assignments to names containing `key`, `secret`, `token`, `password`.
25
+
26
+ ## Step 2 — Triage every script finding
27
+
28
+ The scripts over-match on purpose. For each hit, open the file and decide:
29
+
30
+ - **Live Stripe key (`sk_live_...`)** → Critical. Charges real cards. Recommend immediate rotation at dashboard.stripe.com, not just deletion.
31
+ - **Test Stripe key (`sk_test_...`) in source** → Should Fix. Not production-critical but must not be committed; rotate if the repo was ever shared/pushed publicly.
32
+ - **AWS `AKIA`, Google `AIza`, GitHub `ghp_`, Slack tokens in source** → Critical. Recommend revoking at the provider console.
33
+ - **Publishable keys (`pk_live`, `pk_test`, Supabase anon keys, Firebase apiKey config)** → NOT findings. These are public-by-design; say so in one line so the user isn't confused.
34
+ - **Placeholders** (`your-api-key-here`, `<secret>`, dummy values) → not findings.
35
+ - Anything inside test/fixture/mock directories → not findings (the scripts already skip these).
36
+
37
+ ## Step 3 — Client-exposure pass (Check 1b)
38
+
39
+ Manually verify secrets aren't reachable from the browser:
40
+
41
+ - Grep frontend code (`src/`, `app/`, `components/`, `pages/`, `public/`, client entry points) for references to secret env vars or service-role keys.
42
+ - In Next.js: any secret used outside a server-only context, or a secret var incorrectly prefixed with `NEXT_PUBLIC_`. In Vite/CRA: secrets behind `VITE_*` / `REACT_APP_*` get bundled into shipped JS — Critical.
43
+ - Supabase `service_role` key, Firebase admin SDK private key JSON, OpenAI/Stripe secret keys appearing anywhere client-reachable → Critical.
44
+
45
+ ## Step 4 — .gitignore hygiene (Check 2)
46
+
47
+ From `check_gitignore.py` output plus manual review:
48
+
49
+ - `.env` / `.env.local` present but not ignored → Critical regardless of contents.
50
+ - No `.gitignore` at all with secret files present → Critical.
51
+ - Run `git log --all --full-history -- .env` (if git available). If `.env` was ever committed → Critical, and state plainly: removing it now is not enough; every secret in git history must be rotated because history stays recoverable.
52
+
53
+ ## Report
54
+
55
+ Use the format, severity rubric, and final-summary structure from SKILL.md. Scope reminder for this run: "secrets-only check — Checks 3 (auth), 4 (db), 5 (IDOR), 6 (inputs), and 7 (payments) were skipped. This does not mean the app is secure. Run a full `/checkmyvibe` audit before launch."
@@ -1,3 +1,26 @@
1
- Read the checkmyvibe `SKILL.md`. Run a full production readiness and code quality audit across all checks (Checks 1 through 7: exposed secrets, .gitignore hygiene, missing/fake auth, database misconfigurations, IDOR/BOLA, unvalidated inputs, and client-side payment logic).
1
+ # /checkmyvibe — Full production readiness audit
2
2
 
3
- Use the report format, severity rubric, and final summary structure defined in `SKILL.md`.
3
+ First, locate the checkmyvibe skill file `SKILL.md`. Check these paths in order:
4
+
5
+ 1. `.claude/skills/checkmyvibe/SKILL.md` (project-level install)
6
+ 2. `~/.claude/skills/checkmyvibe/SKILL.md` (global install)
7
+ 3. If neither exists, search the working directory for a file named `SKILL.md` whose frontmatter contains `name: checkmyvibe`
8
+
9
+ If it still cannot be found, tell the user and stop — do not improvise an audit without the skill definitions.
10
+
11
+ **Optional argument:** a target directory may be passed after the command (e.g. `/checkmyvibe src/`). Default to the project root if not given.
12
+
13
+ Then read `SKILL.md` in full and run the **complete audit: Checks 1a, 1b, 2, 3, 4, 5, 6, and 7**:
14
+
15
+ - Check 1a — server-side secrets and credentials
16
+ - Check 1b — client-exposed secrets
17
+ - Check 2 — .gitignore hygiene (including git-history check for committed `.env`)
18
+ - Check 3 — missing or fake authentication
19
+ - Check 4 — database / BaaS misconfiguration (Supabase RLS, Firebase rules, storage)
20
+ - Check 5 — broken object-level authorization (IDOR/BOLA), route by route
21
+ - Check 6 — unvalidated inputs, SQLi/XSS risk, mass assignment, missing rate limiting on auth endpoints
22
+ - Check 7 — client-side payment/pricing logic AND webhook signature verification
23
+
24
+ Run every script in the skill's `scripts/` folder that maps to Checks 1–4 (`scan_secrets.py`, `check_gitignore.py`, `check_auth_patterns.py`, `check_db_config.py`) against the target directory before relying on your own reasoning. If Python is unavailable or a script fails, state that explicitly in the report and do the check manually instead of silently skipping it.
25
+
26
+ Use the report format, severity rubric, evidence/confidence rules, post-fix verification step, and full-audit final summary structure defined in `SKILL.md`.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "checkmyvibe",
4
- "version": "1.1.0",
4
+ "version": "1.2.0",
5
5
  "description": "A structured production readiness and code quality workflow Agent Skill for AI coding assistants to catch common vibe-coded configuration issues.",
6
6
  "main": "install.js",
7
7
  "bin": {
@@ -2,12 +2,22 @@
2
2
  import os
3
3
  import sys
4
4
  import re
5
+ import fnmatch
5
6
 
6
7
  SKIP_DIRS = {
7
8
  'node_modules', '.git', 'build', 'dist', '.next', '.svelte-kit',
8
- '__pycache__', 'venv', '.venv', 'env', 'coverage', 'out'
9
+ '__pycache__', 'venv', '.venv', 'env', 'coverage', 'out',
10
+ # Test/support directories: mock auth there is intentional, not a finding
11
+ '__tests__', '__mocks__', '__snapshots__', 'tests', 'test', 'spec',
12
+ 'fixtures', 'mocks', 'e2e', 'cypress', '.storybook'
9
13
  }
10
14
 
15
+ TEST_FILE_PATTERNS = ['*.test.*', '*.spec.*', '*.stories.*', '*.mock.*']
16
+
17
+ def is_test_file(filename):
18
+ """Skip unit-test/spec/story/mock files: stubbed auth there is expected."""
19
+ return any(fnmatch.fnmatch(filename, pat) for pat in TEST_FILE_PATTERNS)
20
+
11
21
  SKIP_EXTS = {
12
22
  '.png', '.jpg', '.jpeg', '.gif', '.ico', '.pdf', '.zip', '.tar',
13
23
  '.gz', '.mp3', '.mp4', '.mov', '.db', '.sqlite', '.exe', '.dll',
@@ -98,7 +108,7 @@ def main():
98
108
 
99
109
  for file in files:
100
110
  ext = os.path.splitext(file)[1].lower()
101
- if ext in SKIP_EXTS or file.startswith('.'):
111
+ if ext in SKIP_EXTS or is_test_file(file) or file.startswith('.'):
102
112
  continue
103
113
 
104
114
  file_path = os.path.join(root, file)
@@ -2,8 +2,18 @@
2
2
  import os
3
3
  import sys
4
4
  import re
5
+ import fnmatch
5
6
 
6
- SKIP_DIRS = {'node_modules', '.git', 'dist', 'build'}
7
+ SKIP_DIRS = {
8
+ 'node_modules', '.git', 'dist', 'build',
9
+ '__tests__', '__mocks__', 'tests', 'test', 'spec', 'fixtures',
10
+ 'mocks', 'e2e', 'cypress'
11
+ }
12
+
13
+ TEST_FILE_PATTERNS = ['*.test.*', '*.spec.*', '*.mock.*']
14
+
15
+ def is_test_file(filename):
16
+ return any(fnmatch.fnmatch(filename, pat) for pat in TEST_FILE_PATTERNS)
7
17
 
8
18
  # Permissive rules patterns for Firestore and Firebase Storage
9
19
  FIREBASE_PERMISSIVE = re.compile(r'allow\s+[\w\s,]+:\s*if\s+true\s*;')
@@ -108,6 +118,8 @@ def main():
108
118
  dirs[:] = [d for d in dirs if d not in SKIP_DIRS and not d.startswith('.')]
109
119
 
110
120
  for file in files:
121
+ if is_test_file(file):
122
+ continue
111
123
  file_path = os.path.join(root, file)
112
124
  rel_path = os.path.relpath(file_path, target_dir)
113
125
 
@@ -3,14 +3,24 @@ import os
3
3
  import sys
4
4
  import re
5
5
  import math
6
+ import fnmatch
6
7
 
7
8
  # Directories to skip during scanning
8
9
  SKIP_DIRS = {
9
10
  'node_modules', '.git', 'build', 'dist', '.next', '.svelte-kit',
10
11
  '__pycache__', 'venv', '.venv', 'env', 'coverage', 'out', '.expo',
11
- '.output', '.nuxt'
12
+ '.output', '.nuxt',
13
+ # Test/support directories: mocked credentials here are expected, not leaks
14
+ '__tests__', '__mocks__', '__snapshots__', 'tests', 'test', 'spec',
15
+ 'fixtures', 'mocks', 'e2e', 'cypress', '.storybook'
12
16
  }
13
17
 
18
+ TEST_FILE_PATTERNS = ['*.test.*', '*.spec.*', '*.stories.*', '*.mock.*']
19
+
20
+ def is_test_file(filename):
21
+ """Skip unit-test/spec/story/mock files: fake keys there are intentional."""
22
+ return any(fnmatch.fnmatch(filename, pat) for pat in TEST_FILE_PATTERNS)
23
+
14
24
  # File extensions to skip (binary/media/lockfiles/assets)
15
25
  SKIP_EXTS = {
16
26
  '.png', '.jpg', '.jpeg', '.gif', '.ico', '.pdf', '.zip', '.tar',
@@ -20,12 +30,13 @@ SKIP_EXTS = {
20
30
  '.svg', '.css', '.scss', '.less', '.html', '.xml'
21
31
  }
22
32
 
23
- # Regexes for known API key formats
33
+ # Regexes for known API key formats (live keys are Critical; test keys are Should Fix)
24
34
  API_KEY_PATTERNS = [
25
35
  (re.compile(r'AIza[0-9A-Za-z-_]{35}'), 'Google API Key'),
26
36
  (re.compile(r'AKIA[0-9A-Z]{16}'), 'AWS Access Key ID'),
27
37
  (re.compile(r'ghp_[a-zA-Z0-9]{36,40}'), 'GitHub Personal Access Token'),
28
- (re.compile(r'sk_(live|test)_[0-9a-zA-Z]{24,96}'), 'Stripe Secret Key'),
38
+ (re.compile(r'sk_live_[0-9a-zA-Z]{24,96}'), 'Stripe LIVE Secret Key (Critical: charges real cards)'),
39
+ (re.compile(r'sk_test_[0-9a-zA-Z]{24,96}'), 'Stripe TEST Secret Key (Should Fix: not production-critical but must not be committed)'),
29
40
  (re.compile(r'xox[bapr]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32}'), 'Slack Token'),
30
41
  ]
31
42
 
@@ -134,7 +145,9 @@ def main():
134
145
  for file in files:
135
146
  ext = os.path.splitext(file)[1].lower()
136
147
  # Skip hidden files unless they are .env configuration files
137
- if ext in SKIP_EXTS or (file.startswith('.') and not file.startswith('.env')):
148
+ if ext in SKIP_EXTS or is_test_file(file):
149
+ continue
150
+ if file.startswith('.') and not file.startswith('.env'):
138
151
  continue
139
152
 
140
153
  file_path = os.path.join(root, file)