prr-kit 1.1.2 → 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.
Files changed (173) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +260 -235
  3. package/docs/assets/banner.svg +33 -165
  4. package/docs/assets/how-it-works.svg +87 -0
  5. package/package.json +60 -60
  6. package/src/core/agents/prr-master.agent.yaml +18 -7
  7. package/src/core/tasks/clear.md +140 -0
  8. package/src/core/tasks/help.md +15 -13
  9. package/src/core/workflows/clear/workflow.md +6 -0
  10. package/src/core/workflows/help/workflow.md +6 -0
  11. package/src/core/workflows/party-mode/steps/step-01-load-reviewers.md +35 -24
  12. package/src/core/workflows/party-mode/steps/step-02-discussion.md +45 -25
  13. package/src/core/workflows/party-mode/workflow.md +2 -2
  14. package/src/prr/agents/architecture-reviewer.agent.yaml +65 -45
  15. package/src/prr/agents/business-reviewer.agent.yaml +66 -0
  16. package/src/prr/agents/general-reviewer.agent.yaml +64 -48
  17. package/src/prr/agents/performance-reviewer.agent.yaml +65 -45
  18. package/src/prr/agents/security-reviewer.agent.yaml +67 -43
  19. package/src/prr/config-template.yaml +97 -0
  20. package/src/prr/data/stacks/actix.md +55 -0
  21. package/src/prr/data/stacks/alpine.md +47 -0
  22. package/src/prr/data/stacks/android.md +53 -0
  23. package/src/prr/data/stacks/angular.md +96 -0
  24. package/src/prr/data/stacks/ansible.md +55 -0
  25. package/src/prr/data/stacks/apollo.md +54 -0
  26. package/src/prr/data/stacks/astro.md +48 -0
  27. package/src/prr/data/stacks/aws-cdk.md +55 -0
  28. package/src/prr/data/stacks/axum.md +56 -0
  29. package/src/prr/data/stacks/babylonjs.md +55 -0
  30. package/src/prr/data/stacks/bash.md +53 -0
  31. package/src/prr/data/stacks/bevy.md +53 -0
  32. package/src/prr/data/stacks/bootstrap.md +52 -0
  33. package/src/prr/data/stacks/bun.md +55 -0
  34. package/src/prr/data/stacks/cpp.md +57 -0
  35. package/src/prr/data/stacks/csharp.md +95 -0
  36. package/src/prr/data/stacks/css.md +55 -0
  37. package/src/prr/data/stacks/cypress.md +53 -0
  38. package/src/prr/data/stacks/d3.md +53 -0
  39. package/src/prr/data/stacks/deno.md +49 -0
  40. package/src/prr/data/stacks/django.md +92 -0
  41. package/src/prr/data/stacks/docker.md +79 -0
  42. package/src/prr/data/stacks/drizzle.md +54 -0
  43. package/src/prr/data/stacks/dynamodb.md +55 -0
  44. package/src/prr/data/stacks/electron.md +44 -0
  45. package/src/prr/data/stacks/elixir.md +53 -0
  46. package/src/prr/data/stacks/expo.md +53 -0
  47. package/src/prr/data/stacks/expressjs.md +82 -0
  48. package/src/prr/data/stacks/fastapi.md +88 -0
  49. package/src/prr/data/stacks/fastify.md +60 -0
  50. package/src/prr/data/stacks/fiber.md +55 -0
  51. package/src/prr/data/stacks/firebase.md +43 -0
  52. package/src/prr/data/stacks/flask.md +46 -0
  53. package/src/prr/data/stacks/flutter.md +75 -0
  54. package/src/prr/data/stacks/gin.md +57 -0
  55. package/src/prr/data/stacks/github-actions.md +71 -0
  56. package/src/prr/data/stacks/go.md +88 -0
  57. package/src/prr/data/stacks/godot.md +56 -0
  58. package/src/prr/data/stacks/graphql.md +76 -0
  59. package/src/prr/data/stacks/grpc.md +56 -0
  60. package/src/prr/data/stacks/haskell.md +48 -0
  61. package/src/prr/data/stacks/helm.md +54 -0
  62. package/src/prr/data/stacks/hono.md +54 -0
  63. package/src/prr/data/stacks/htmx.md +38 -0
  64. package/src/prr/data/stacks/java.md +87 -0
  65. package/src/prr/data/stacks/jest-vitest.md +87 -0
  66. package/src/prr/data/stacks/jquery.md +50 -0
  67. package/src/prr/data/stacks/junit.md +53 -0
  68. package/src/prr/data/stacks/kotlin.md +89 -0
  69. package/src/prr/data/stacks/kubernetes.md +148 -0
  70. package/src/prr/data/stacks/langchain.md +56 -0
  71. package/src/prr/data/stacks/laravel.md +56 -0
  72. package/src/prr/data/stacks/libgdx.md +46 -0
  73. package/src/prr/data/stacks/lit.md +49 -0
  74. package/src/prr/data/stacks/love2d.md +51 -0
  75. package/src/prr/data/stacks/lua.md +51 -0
  76. package/src/prr/data/stacks/mobx.md +54 -0
  77. package/src/prr/data/stacks/mongodb.md +85 -0
  78. package/src/prr/data/stacks/monogame.md +51 -0
  79. package/src/prr/data/stacks/mysql.md +57 -0
  80. package/src/prr/data/stacks/nestjs.md +95 -0
  81. package/src/prr/data/stacks/nextjs.md +88 -0
  82. package/src/prr/data/stacks/nginx.md +55 -0
  83. package/src/prr/data/stacks/node.md +56 -0
  84. package/src/prr/data/stacks/nuxtjs.md +91 -0
  85. package/src/prr/data/stacks/openai-api.md +54 -0
  86. package/src/prr/data/stacks/opengl.md +54 -0
  87. package/src/prr/data/stacks/phaser.md +54 -0
  88. package/src/prr/data/stacks/phoenix.md +55 -0
  89. package/src/prr/data/stacks/php.md +56 -0
  90. package/src/prr/data/stacks/playwright.md +86 -0
  91. package/src/prr/data/stacks/postgresql.md +60 -0
  92. package/src/prr/data/stacks/prisma.md +81 -0
  93. package/src/prr/data/stacks/pygame.md +52 -0
  94. package/src/prr/data/stacks/pytest.md +53 -0
  95. package/src/prr/data/stacks/python.md +94 -0
  96. package/src/prr/data/stacks/pytorch.md +54 -0
  97. package/src/prr/data/stacks/qwik.md +50 -0
  98. package/src/prr/data/stacks/rails.md +48 -0
  99. package/src/prr/data/stacks/react-native.md +77 -0
  100. package/src/prr/data/stacks/react.md +104 -0
  101. package/src/prr/data/stacks/redis.md +76 -0
  102. package/src/prr/data/stacks/redux.md +107 -0
  103. package/src/prr/data/stacks/remix.md +51 -0
  104. package/src/prr/data/stacks/rust.md +88 -0
  105. package/src/prr/data/stacks/sass.md +51 -0
  106. package/src/prr/data/stacks/scala.md +50 -0
  107. package/src/prr/data/stacks/scikit-learn.md +53 -0
  108. package/src/prr/data/stacks/sequelize.md +54 -0
  109. package/src/prr/data/stacks/socket-io.md +54 -0
  110. package/src/prr/data/stacks/solidity.md +53 -0
  111. package/src/prr/data/stacks/solidjs.md +45 -0
  112. package/src/prr/data/stacks/spring-boot.md +92 -0
  113. package/src/prr/data/stacks/sql.md +85 -0
  114. package/src/prr/data/stacks/sqlite.md +55 -0
  115. package/src/prr/data/stacks/styled-components.md +51 -0
  116. package/src/prr/data/stacks/supabase.md +57 -0
  117. package/src/prr/data/stacks/svelte.md +77 -0
  118. package/src/prr/data/stacks/sveltekit.md +54 -0
  119. package/src/prr/data/stacks/swift.md +61 -0
  120. package/src/prr/data/stacks/tailwindcss.md +10 -0
  121. package/src/prr/data/stacks/tanstack-query.md +48 -0
  122. package/src/prr/data/stacks/tauri.md +52 -0
  123. package/src/prr/data/stacks/terraform.md +53 -0
  124. package/src/prr/data/stacks/three.md +53 -0
  125. package/src/prr/data/stacks/trpc.md +49 -0
  126. package/src/prr/data/stacks/typeorm.md +40 -0
  127. package/src/prr/data/stacks/typescript.md +83 -0
  128. package/src/prr/data/stacks/unity.md +61 -0
  129. package/src/prr/data/stacks/unreal.md +58 -0
  130. package/src/prr/data/stacks/vite.md +48 -0
  131. package/src/prr/data/stacks/vue3.md +95 -0
  132. package/src/prr/data/stacks/vulkan.md +53 -0
  133. package/src/prr/data/stacks/wasm.md +49 -0
  134. package/src/prr/data/stacks/webpack.md +48 -0
  135. package/src/prr/data/stacks/zig.md +51 -0
  136. package/src/prr/data/stacks/zustand.md +56 -0
  137. package/src/prr/workflows/1-discover/select-pr/steps/step-05-confirm.md +1 -0
  138. package/src/prr/workflows/1-discover/select-pr/workflow.md +1 -1
  139. package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-01-analyze-files.md +334 -0
  140. package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-02-collect-sources.md +451 -0
  141. package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-03-build-knowledge-base.md +337 -0
  142. package/src/prr/workflows/2-analyze/collect-pr-context/workflow.md +123 -0
  143. package/src/prr/workflows/2-analyze/describe-pr/steps/step-02-classify.md +12 -6
  144. package/src/prr/workflows/2-analyze/describe-pr/steps/step-03-walkthrough.md +59 -1
  145. package/src/prr/workflows/3-review/architecture-review/checklist.md +4 -0
  146. package/src/prr/workflows/3-review/architecture-review/instructions.xml +32 -4
  147. package/src/prr/workflows/3-review/architecture-review/workflow.yaml +17 -18
  148. package/src/prr/workflows/3-review/business-review/checklist.md +27 -0
  149. package/src/prr/workflows/3-review/business-review/instructions.xml +153 -0
  150. package/src/prr/workflows/3-review/business-review/workflow.yaml +17 -0
  151. package/src/prr/workflows/3-review/general-review/checklist.md +5 -1
  152. package/src/prr/workflows/3-review/general-review/instructions.xml +39 -8
  153. package/src/prr/workflows/3-review/general-review/workflow.yaml +17 -18
  154. package/src/prr/workflows/3-review/performance-review/checklist.md +3 -1
  155. package/src/prr/workflows/3-review/performance-review/instructions.xml +10 -3
  156. package/src/prr/workflows/3-review/performance-review/workflow.yaml +17 -18
  157. package/src/prr/workflows/3-review/security-review/checklist.md +2 -1
  158. package/src/prr/workflows/3-review/security-review/instructions.xml +8 -3
  159. package/src/prr/workflows/3-review/security-review/workflow.yaml +18 -19
  160. package/src/prr/workflows/4-improve/improve-code/workflow.yaml +17 -18
  161. package/src/prr/workflows/6-report/generate-report/steps/step-01-collect.md +9 -2
  162. package/src/prr/workflows/6-report/generate-report/steps/step-02-organize.md +28 -7
  163. package/src/prr/workflows/6-report/generate-report/steps/step-03-write.md +6 -4
  164. package/src/prr/workflows/6-report/generate-report/templates/review-report.template.md +124 -78
  165. package/src/prr/workflows/6-report/post-comments/steps/step-01-format.md +104 -13
  166. package/src/prr/workflows/6-report/post-comments/steps/step-02-post.md +92 -21
  167. package/src/prr/workflows/6-report/post-comments/workflow.md +6 -0
  168. package/src/prr/workflows/quick/workflow.md +138 -32
  169. package/src/prr/workflows/0-setup/collect-project-context/steps/step-01-scan-configs.md +0 -106
  170. package/src/prr/workflows/0-setup/collect-project-context/steps/step-02-extract-rules.md +0 -131
  171. package/src/prr/workflows/0-setup/collect-project-context/steps/step-03-ask-context.md +0 -194
  172. package/src/prr/workflows/0-setup/collect-project-context/steps/step-04-save-context.md +0 -161
  173. package/src/prr/workflows/0-setup/collect-project-context/workflow.md +0 -58
@@ -0,0 +1,55 @@
1
+ # DynamoDB — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `@aws-sdk/client-dynamodb`, `dynamoose`, `from 'dynamodb'`, `DynamoDB.DocumentClient`, `aws-sdk` with DynamoDB, `PK`/`SK` table design
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[CRITICAL]** IAM role or user has `dynamodb:*` on `*` (all tables) → compromise grants full read/write/delete access to every table. Scope IAM policies to specific table ARNs and only the required actions (e.g., `dynamodb:GetItem`, `dynamodb:PutItem`).
10
+ - **[HIGH]** User-controlled input in `FilterExpression` or `KeyConditionExpression` without validation → logical injection allows querying unintended data. Validate all filter values against an allowlist; use `ExpressionAttributeValues` for all values.
11
+ - **[HIGH]** DynamoDB table name constructed from user input → attacker can target arbitrary tables. Hardcode all table names; read them from environment variables set at deployment time.
12
+ - **[HIGH]** No VPC endpoint for DynamoDB → traffic traverses the public internet. Create a VPC gateway endpoint and restrict outbound security group rules accordingly.
13
+ - **[MEDIUM]** Sensitive attributes (PII, tokens) not encrypted at the attribute level → storage-layer encryption alone is insufficient. Use AWS Encryption SDK to encrypt sensitive values before writing to DynamoDB.
14
+ - **[MEDIUM]** CloudTrail not enabled or DynamoDB data events not logged → no audit trail of who read or wrote which items. Enable CloudTrail with DynamoDB data event logging for tables with sensitive data.
15
+
16
+ ---
17
+
18
+ ## Performance
19
+ - **[CRITICAL]** `Scan` used instead of `Query` for data retrieval → reads every item in the table, consuming full provisioned read capacity proportional to table size. Use `Query` with a partition key; reserve `Scan` for one-off administrative operations.
20
+ - **[HIGH]** Hot partition key routing all traffic to a single partition (e.g., current date, fixed status string, or single tenant ID) → partitions cap at 3,000 RCU / 1,000 WCU; throttling occurs. Add a random suffix or shard number to distribute load.
21
+ - **[HIGH]** Missing GSI for access patterns not served by the primary key → every such query falls back to a full `Scan`. Define GSIs for all known access patterns before table creation.
22
+ - **[HIGH]** `FilterExpression` applied to `Scan` or `Query` results → filter runs after reading; full RCU cost charged for all items scanned. Encode filter criteria into the partition or sort key design.
23
+ - **[MEDIUM]** Item size consistently above 10 KB → RCU/WCU rounds up per 4 KB read / 1 KB write. Store large payloads in S3; keep only a reference key in DynamoDB.
24
+ - **[MEDIUM]** `ProjectionExpression` not specified → `GetItem` and `Query` return all attributes, wasting bandwidth and read capacity. Specify only the attributes the application needs.
25
+ - **[LOW]** On-demand capacity used for predictable steady traffic → on-demand costs more per request than provisioned at stable load. Switch to provisioned capacity with auto-scaling.
26
+
27
+ ---
28
+
29
+ ## Architecture
30
+ - **[CRITICAL]** Table designed relationally with one table per entity type (Users, Orders, Products) → DynamoDB has no cross-table JOINs; relational queries require multiple round trips. Use single-table design with overloaded PK/SK values.
31
+ - **[HIGH]** Access patterns not defined before table schema is finalized → retrofitting requires expensive table rebuilds. Document all query patterns (PK=X, SK starts-with Y) before writing any table creation code.
32
+ - **[HIGH]** Single-table design not used when entity types share access patterns (e.g., fetch user plus orders in one request) → requires two separate calls. Collapse entities into one table; use `Query` with `PK=userId` to retrieve all related items.
33
+ - **[MEDIUM]** TTL attribute not set on ephemeral items (sessions, OTP tokens, locks) → items accumulate indefinitely, increasing storage cost and scan time. Define a Unix-epoch numeric TTL attribute and enable DynamoDB TTL.
34
+ - **[MEDIUM]** DynamoDB Streams not used for event-driven side effects (cache invalidation, notifications) → polling or synchronous calls used instead. Enable Streams and attach a Lambda trigger.
35
+ - **[LOW]** No CloudWatch capacity alarms configured → throttling goes undetected until user-visible errors occur. Set alarms at 80% of provisioned `ConsumedWriteCapacityUnits` / `ConsumedReadCapacityUnits`.
36
+
37
+ ---
38
+
39
+ ## Code Quality
40
+ - **[HIGH]** Table names hardcoded as string literals throughout the codebase → renaming requires a grep-and-replace across all files. Centralize in a constants module or read from `process.env.TABLE_NAME`.
41
+ - **[HIGH]** No error handling for `ProvisionedThroughputExceededException` → throttled requests fail permanently. Use the AWS SDK `maxAttempts` retry config and add exponential backoff for throttling errors.
42
+ - **[MEDIUM]** `TransactWriteItems` not used for multi-item atomic operations (e.g., decrement inventory and create order) → partial success possible if one write fails. Use `TransactWriteItems` (up to 100 items) for all-or-nothing mutations.
43
+ - **[MEDIUM]** Raw `DynamoDB.DocumentClient` used without an abstraction layer → marshall/unmarshall logic scattered throughout. Use DynamoDB Toolbox, Dynamoose, or a thin repository class.
44
+ - **[MEDIUM]** Attribute names conflicting with DynamoDB reserved words (`name`, `status`, `date`, `key`) → queries without `ExpressionAttributeNames` throw `ValidationException`. Map reserved-word attributes using ExpressionAttributeNames.
45
+ - **[LOW]** No integration tests against a local DynamoDB (DynamoDB Local or LocalStack) → key condition expression bugs only caught in production. Add DynamoDB Local to the test environment.
46
+
47
+ ---
48
+
49
+ ## Common Bugs & Pitfalls
50
+ - **[HIGH]** `BatchWriteItem` response not checked for `UnprocessedItems` → DynamoDB may partially fail a batch silently. Always check `response.UnprocessedItems` and retry unprocessed items with exponential backoff.
51
+ - **[HIGH]** Optimistic locking via `ConditionExpression` not used for concurrent updates → two concurrent requests read the same version, both write the incremented version, and one silently overwrites the other. Use `ConditionExpression: "version = :expected"` and increment version on every write.
52
+ - **[MEDIUM]** `ConsistentRead: true` not used when strong consistency is needed after a write → eventual consistency may return stale data within the roughly 1-second replication window. Set `ConsistentRead: true` for reads that must reflect a preceding write.
53
+ - **[MEDIUM]** Global table replication lag not accounted for in cross-region reads → a write in us-east-1 may not be visible in eu-west-1 for several seconds. Route post-write reads to the write region.
54
+ - **[MEDIUM]** `UpdateItem` with `SET attr = :val` replacing a list attribute instead of appending → entire list overwritten when intent is to add one element. Use `SET listAttr = list_append(listAttr, :newItems)` to append.
55
+ - **[LOW]** Sort key not planned at design time → adding a sort key later requires creating a new table and migrating all data. Decide on composite vs. simple key before the first deployment.
@@ -0,0 +1,44 @@
1
+ # Electron — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `electron` in `dependencies` · `BrowserWindow` · `ipcMain` · `ipcRenderer` · `app.whenReady()` · `main.js` / `main.ts` as Electron entry
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[CRITICAL]** `contextIsolation: false` in `webPreferences` → renderer process has direct access to Node.js APIs; XSS in renderer = full system compromise.
11
+ - **[CRITICAL]** `nodeIntegration: true` in `webPreferences` → full Node.js API surface exposed to renderer; one XSS = RCE.
12
+ - **[CRITICAL]** `webSecurity: false` → disables CORS, allows loading local files from remote pages, enables cross-origin attacks.
13
+ - **[HIGH]** IPC handler executing user-controlled commands: `ipcMain.on('run', (e, cmd) => exec(cmd))` → arbitrary command execution from renderer or compromised web content.
14
+ - **[HIGH]** Loading remote URLs in `BrowserWindow` without a strict Content Security Policy → XSS attack surface.
15
+ - **[HIGH]** `shell.openExternal(url)` with user-controlled URL → opens `file://`, `smb://`, or other dangerous protocol URIs. Validate scheme and host allowlist.
16
+ - **[MEDIUM]** Bundling application without code signing → OS security warnings, easier to tamper with by local attacker.
17
+
18
+ ---
19
+
20
+ ## Performance
21
+
22
+ - **[HIGH]** Synchronous IPC `ipcRenderer.sendSync()` → blocks renderer's UI thread until main process responds. Use async `ipcRenderer.invoke()` / `ipcMain.handle()`.
23
+ - **[HIGH]** Sending large data (images, buffers) over IPC as serialized JSON → full serialize/deserialize cost. Use `SharedArrayBuffer` or write to a temp file and pass the path.
24
+ - **[MEDIUM]** Invisible `BrowserWindow` kept alive indefinitely → each window has a full Chromium renderer process (~80-150 MB). Destroy when not needed.
25
+ - **[LOW]** Requiring all Node modules at startup in main process → slow cold start. Use lazy requires inside handlers.
26
+
27
+ ---
28
+
29
+ ## Architecture
30
+
31
+ - **[HIGH]** Business logic placed in renderer process → should live in main process or a dedicated Node service; renderer should be a thin UI layer communicating via IPC.
32
+ - **[HIGH]** `remote` module (deprecated in Electron 12, removed in 14) still in use → security risk, use `contextBridge` to expose specific APIs to renderer.
33
+ - **[MEDIUM]** Entire `ipcRenderer` object exposed via `contextBridge.exposeInMainWorld` → expose a minimal typed API, not the full IPC surface.
34
+ - **[MEDIUM]** No auto-update mechanism (e.g., `electron-updater`) → security patches can't reach users. Implement silent update with user notification.
35
+
36
+ ---
37
+
38
+ ## Common Bugs & Pitfalls
39
+
40
+ - **[HIGH]** `app.quit()` not called after all windows close on Windows/Linux → process keeps running in background (tray icon or just CPU/memory waste). Add `app.on('window-all-closed', () => app.quit())` for non-macOS.
41
+ - **[HIGH]** Accessing `document` / `window` in main process → these are browser globals, undefined in Node.js main process context.
42
+ - **[MEDIUM]** Async operation started from IPC handler completes after `BrowserWindow` is destroyed → callback or `event.reply()` on destroyed window throws error.
43
+ - **[MEDIUM]** Dev tools opened in production build → `webContents.openDevTools()` call not removed. Gate with `!app.isPackaged`.
44
+ - **[LOW]** `process.resourcesPath` used to locate app files → use `path.join(__dirname, ...)` or `app.getAppPath()` for reliable cross-platform paths.
@@ -0,0 +1,53 @@
1
+ # Elixir / Phoenix — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `*.ex` / `*.exs` files · `mix.exs` · `defmodule` · `use Phoenix.` · `Repo.` · `Ecto.` · `defp` · `%{}` struct patterns
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[HIGH]** Raw SQL in Ecto: `Repo.query("SELECT * FROM users WHERE id = #{id}")` → SQL injection. Use `Ecto.Query` DSL or parameterized queries: `from(u in User, where: u.id == ^id)`.
11
+ - **[HIGH]** `Phoenix.Token.verify` called without `max_age` option → tokens never expire. Always pass `max_age:` (e.g., 86400 seconds = 1 day).
12
+ - **[HIGH]** `String.to_atom(user_input)` → atoms are never garbage collected; exhausting the atom table crashes the BEAM VM (DoS). Use `String.to_existing_atom/1` or keep as a string.
13
+ - **[MEDIUM]** Missing CSRF protection on non-GET, non-API endpoints → Phoenix includes `Plug.CSRFProtection` by default; ensure it's not removed from the pipeline.
14
+ - **[MEDIUM]** Mass assignment: `User.changeset(user, params)` without a field allowlist in the changeset → any client-supplied field (e.g., `role`, `admin`) gets set. Always use `cast/3` with explicit allowed fields.
15
+
16
+ ---
17
+
18
+ ## Performance
19
+
20
+ - **[HIGH]** N+1 query in Ecto: loading associations inside an `Enum.map` loop → generates N additional queries. Use `Repo.preload/2` or add `:preload` to the initial query.
21
+ - **[HIGH]** `Enum` functions on a large `Stream` that could be composed → `Enum.filter |> Enum.map` creates an intermediate list. Chain `Stream.filter |> Stream.map |> Enum.to_list` for lazy evaluation.
22
+ - **[MEDIUM]** `GenServer` using synchronous `call` for all operations including fire-and-forget mutations → serializes all operations through one process. Use `cast` for operations that don't need a return value.
23
+ - **[MEDIUM]** `Repo.all` without pagination on a potentially large table → memory spike and slow response. Use `Repo.paginate` or `limit/offset` in the query.
24
+ - **[LOW]** Pattern matching on entire map `%{field: val} = large_map` when only one field is needed → still works but is misleading; be explicit about what you're matching.
25
+
26
+ ---
27
+
28
+ ## Architecture
29
+
30
+ - **[HIGH]** Business logic in Phoenix controller action → extract to a Context module (boundary pattern). Controllers should only translate HTTP ↔ context function calls.
31
+ - **[HIGH]** Process state stored in `Agent` or `GenServer` without a persistence strategy → state is lost on process crash or node restart. Persist critical state to the database.
32
+ - **[MEDIUM]** `Task.async` without a supervisor → unlinked task crash is not propagated to the caller; use `Task.Supervisor` for resilient async work.
33
+ - **[MEDIUM]** Long-lived `GenServer` that receives unbounded messages without backpressure → mailbox grows indefinitely under load. Use `GenStage` or rate limiting.
34
+ - **[LOW]** `use GenServer` for simple key-value storage → consider `ETS` (Erlang Term Storage) for concurrent read-heavy in-memory state.
35
+
36
+ ---
37
+
38
+ ## Code Quality
39
+
40
+ - **[HIGH]** `with` expression without an `else` clause → if any clause returns a non-`{:ok, _}` value, it falls through as the return value of the `with` block. Always add `else` to handle errors explicitly.
41
+ - **[MEDIUM]** Large `case` expression where pattern-matched function clauses would be idiomatic → Elixir's pattern matching on function heads is cleaner than `case` for multiple conditions.
42
+ - **[MEDIUM]** `IO.inspect` / `IO.puts` debug statements left in production code → remove before merge. Use `Logger` for structured logging.
43
+ - **[LOW]** Not using `@spec` on public functions → poor documentation, no Dialyzer type checking benefit.
44
+
45
+ ---
46
+
47
+ ## Common Bugs & Pitfalls
48
+
49
+ - **[HIGH]** `Repo` operations outside a transaction when multiple operations must be atomic → partial write on failure leaves data inconsistent. Use `Repo.transaction/1` or `Ecto.Multi`.
50
+ - **[HIGH]** Calling `Repo.update_all` / `Repo.delete_all` without a `where` clause → modifies or deletes all rows in the table. Always include a `where` condition.
51
+ - **[MEDIUM]** `Map.get(map, key)` returns `nil` for missing keys, not an error → if the key is required, use `Map.fetch!(map, key)` which raises `KeyError` on missing key.
52
+ - **[MEDIUM]** Atom comparison vs string comparison: `"active" == :active` is always `false` → be consistent with atom vs string types for status/enum fields. Ecto enums use atoms; JSON payloads use strings.
53
+ - **[LOW]** `Enum.first(list)` returning `nil` for empty list treated as a valid value → check for `nil` or use pattern matching on the result.
@@ -0,0 +1,53 @@
1
+ # Expo — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `expo`, `from 'expo'`, `app.json` with `expo`, `from 'expo-router'`, `eas.json`, `from 'expo-constants'`
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[CRITICAL]** API keys or secrets placed in `app.json`, `app.config.js`, or `Constants.expoConfig` → values are bundled into the app binary and extractable. Move secrets server-side; use `expo-constants` only for non-sensitive public config.
10
+ - **[HIGH]** Sensitive data (tokens, user credentials) stored in `AsyncStorage` → unencrypted storage accessible on rooted/jailbroken devices. Use `expo-secure-store` which calls the OS keychain/keystore.
11
+ - **[HIGH]** Deep link URI scheme not validated before acting on parameters → open redirect or parameter injection via crafted links. Validate the full URI and all parameters before using deep link data.
12
+ - **[HIGH]** `expo-file-system` used to read/write paths constructed from user input → path traversal outside the app sandbox. Sanitize paths and restrict operations to `FileSystem.documentDirectory` or `cacheDirectory`.
13
+ - **[MEDIUM]** EAS Update (OTA) not configured with code signing → unsigned JavaScript bundles can be injected by a network attacker. Enable `codeSigningCertificate` in `eas.json` for all update channels.
14
+ - **[MEDIUM]** `__DEV__` check absent on verbose logging or debug screens → internal data and stack traces exposed in production builds. Guard all debug output with `if (__DEV__)`.
15
+
16
+ ---
17
+
18
+ ## Performance
19
+ - **[HIGH]** Heavy computation (sorting, encryption, image processing) run on the JavaScript thread → UI freezes. Offload to `expo-task-manager` background tasks, `react-native-worklets-core`, or a native module.
20
+ - **[HIGH]** Large images embedded at source resolution without optimization → bloated bundle and slow render on low-end devices. Use `expo-image-manipulator` to resize/compress assets; provide `@2x`/`@3x` variants.
21
+ - **[HIGH]** React Native `Image` component used instead of `expo-image` → no built-in memory caching, blurhash placeholder support, or progressive loading. Replace with `expo-image` for all image rendering.
22
+ - **[MEDIUM]** Data fetched in `useEffect` on every component mount without caching → repeated network calls on navigation. Use a caching layer (React Query, SWR, or Expo's `useCachedPromise`).
23
+ - **[MEDIUM]** All screens eager-loaded at startup in navigator → slow time-to-interactive. Use `lazy` option in Expo Router or React Navigation to defer screen registration.
24
+ - **[LOW]** `useFonts` from `expo-font` not awaited before rendering text → layout shift or missing glyphs on first frame. Hide the splash screen until fonts are ready with `SplashScreen.preventAutoHideAsync`.
25
+
26
+ ---
27
+
28
+ ## Architecture
29
+ - **[HIGH]** Custom navigation logic reimplemented instead of using Expo Router's file-based routing → navigation state bugs and missed deep linking support. Migrate to the `app/` directory convention with Expo Router.
30
+ - **[HIGH]** Platform-specific logic mixed inline with `Platform.OS === 'ios'` checks throughout components → hard to maintain. Use `.ios.tsx` / `.android.tsx` / `.web.tsx` file extensions for platform-specific implementations.
31
+ - **[MEDIUM]** Production builds done locally with `expo build` (deprecated) instead of EAS Build → inconsistent build environment and toolchain. Switch to `eas build` with a defined build profile.
32
+ - **[MEDIUM]** Static `app.json` used instead of `app.config.ts` → cannot inject environment variables or dynamic values at build time. Migrate to `app.config.ts` and read from `process.env`.
33
+ - **[MEDIUM]** Expo managed workflow plugins not used for native module configuration → manual native code edits that break on `expo prebuild`. Use config plugins for all native configuration.
34
+ - **[LOW]** Single `eas.json` profile for all environments → development, staging, and production share the same build configuration. Define separate `development`, `preview`, and `production` profiles.
35
+
36
+ ---
37
+
38
+ ## Code Quality
39
+ - **[HIGH]** Expo SDK version not pinned or using a major version range → `expo upgrade` introduces breaking changes automatically. Pin to an exact Expo SDK version and upgrade intentionally.
40
+ - **[MEDIUM]** `expo-constants` used for environment switching in runtime code instead of EAS build profiles → environment logic scattered and hard to audit. Centralize environment config in a single `config.ts` module populated at build time.
41
+ - **[MEDIUM]** Permissions (camera, location, notifications) requested without a usage description or at startup → users deny preemptively. Request permissions at the point of use and provide a `PermissionsExplanation` component.
42
+ - **[MEDIUM]** `babel.config.js` not using `babel-preset-expo` → Expo-specific transforms (SVG imports, module resolution) do not work. Ensure `presets: ['babel-preset-expo']` is the base config.
43
+ - **[LOW]** TypeScript strict mode not enabled in `tsconfig.json` → type errors masked. Set `"strict": true` and extend from `expo/tsconfig.base`.
44
+
45
+ ---
46
+
47
+ ## Common Bugs & Pitfalls
48
+ - **[HIGH]** Stale Metro bundler cache producing builds with old code after dependency changes → old module versions used at runtime. Run `expo start --clear` or `npx expo start -c` to clear the cache.
49
+ - **[HIGH]** `expo-av` `Audio` or `Video` playback not stopped or unloaded on component unmount → audio continues playing in the background, leaking native resources. Call `sound.stopAsync()` and `sound.unloadAsync()` in the `useEffect` cleanup.
50
+ - **[MEDIUM]** `KeyboardAvoidingView` using the same `behavior` for iOS and Android → input fields obscured by keyboard on one platform. Use `behavior="padding"` for iOS and `behavior="height"` for Android.
51
+ - **[MEDIUM]** `StatusBar` style not set per screen → status bar text color wrong against the screen's background. Use `expo-status-bar` `StatusBar` component with `style` set in each screen.
52
+ - **[MEDIUM]** `useCallback` and `useMemo` not applied to callbacks passed to `FlatList` `renderItem` → entire list re-renders on parent state change. Memoize `renderItem` and `keyExtractor` callbacks.
53
+ - **[LOW]** `Platform.OS === 'web'` checks missing for Expo Web → components using native-only APIs crash in the browser. Add web guards or provide web-specific implementations for all native API usage.
@@ -0,0 +1,82 @@
1
+ # Express.js — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `express()`, `app.use(`, `router.get/post/put/delete`, `from 'express'`, `require('express')`, `middleware`, `req.body`, `res.json`
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[CRITICAL]** Missing authentication middleware on protected routes → unauthenticated access.
11
+ - **[CRITICAL]** SQL / NoSQL query built with `req.body`/`req.params` string interpolation → injection.
12
+ - **[CRITICAL]** `res.send(req.body.input)` without sanitization → reflected XSS.
13
+ - **[CRITICAL]** `eval(req.body.code)` or dynamic `require(req.body.module)` → arbitrary code execution.
14
+ - **[HIGH]** Missing `helmet` middleware → no security headers (CSP, X-Frame-Options, HSTS).
15
+ - **[HIGH]** `req.body` used without validation (express-validator, zod, joi) → arbitrary data reaches logic.
16
+ - **[HIGH]** Error handler exposing stack trace: `res.json({ error: err.stack })` → info disclosure.
17
+ - **[HIGH]** Missing rate limiting on auth/sensitive endpoints (`express-rate-limit`) → brute force.
18
+ - **[HIGH]** File upload without MIME type/size validation → arbitrary file stored/executed.
19
+ - **[HIGH]** `res.redirect(req.query.next)` without URL validation → open redirect.
20
+ - **[HIGH]** Prototype pollution via `req.body` merged into objects without `Object.freeze(Object.prototype)`.
21
+ - **[MEDIUM]** Session secret hardcoded or weak → session hijacking.
22
+ - **[MEDIUM]** CORS `origin: '*'` with credentials in production → credential leakage.
23
+ - **[MEDIUM]** JWT stored in localStorage instead of httpOnly cookie → XSS token theft.
24
+ - **[LOW]** `express.static` serving files from root directory → source code exposure.
25
+
26
+ ---
27
+
28
+ ## Performance
29
+
30
+ - **[HIGH]** Synchronous `fs.readFileSync` / `crypto.pbkdf2Sync` in route handler → blocks event loop.
31
+ - **[HIGH]** `async` route handler without try/catch or `express-async-errors` → unhandled rejection crashes process.
32
+ - **[HIGH]** N+1 DB queries per request — loading related data in loop inside route.
33
+ - **[HIGH]** Missing response compression (`compression` middleware) for large JSON responses.
34
+ - **[HIGH]** No connection pooling for DB → new connection per request → latency + exhaustion.
35
+ - **[MEDIUM]** No response caching for idempotent, rarely-changing endpoints.
36
+ - **[MEDIUM]** Missing `req.setTimeout()` → hanging requests hold server resources indefinitely.
37
+ - **[MEDIUM]** `morgan` verbose logging in production → I/O overhead.
38
+ - **[MEDIUM]** Middleware running on all routes including static assets → unnecessary overhead.
39
+ - **[LOW]** `res.json` on large objects without streaming → buffering entire payload in memory.
40
+
41
+ ---
42
+
43
+ ## Architecture
44
+
45
+ - **[HIGH]** Business logic inside route handler → extract to service/controller layer.
46
+ - **[HIGH]** No centralized error handling middleware (`app.use((err, req, res, next) => {...})`) → inconsistent errors.
47
+ - **[HIGH]** Middleware order wrong — auth middleware placed after route it should protect → never runs.
48
+ - **[HIGH]** `next()` called after `res.send()` / `res.json()` → "Cannot set headers after they are sent" error.
49
+ - **[HIGH]** Not using `express.Router` per domain → all routes in single file → unmaintainable.
50
+ - **[MEDIUM]** Missing `app.set('trust proxy', 1)` behind load balancer → wrong `req.ip`, rate limiting broken.
51
+ - **[MEDIUM]** `app.use(express.json())` with no size limit → large payload DoS. Set `{ limit: '1mb' }`.
52
+ - **[MEDIUM]** Global state (module-level variables) used for request-scoped data → not isolated per request.
53
+ - **[MEDIUM]** Not using `AsyncLocalStorage` for request context propagation → prop drilling `req` everywhere.
54
+ - **[LOW]** Missing `404` catch-all handler at end of middleware chain.
55
+
56
+ ---
57
+
58
+ ## Code Quality
59
+
60
+ - **[HIGH]** `next(err)` not called in catch block → error swallowed, request hangs.
61
+ - **[HIGH]** Route params used directly as DB keys without type validation → `req.params.id` is always a string.
62
+ - **[MEDIUM]** `res.status(200).json(...)` on errors → client can't distinguish success from failure.
63
+ - **[MEDIUM]** Inconsistent response shape across routes → no standard `{ data, error }` envelope.
64
+ - **[MEDIUM]** Missing `await` on async middleware → middleware completes without waiting for async work.
65
+ - **[MEDIUM]** Not using TypeScript with `@types/express` → `req.body` is `any`.
66
+ - **[LOW]** `res.send()` for JSON responses instead of `res.json()` → must manually set Content-Type.
67
+ - **[LOW]** Not using environment-specific config (`dotenv` without validation).
68
+
69
+ ---
70
+
71
+ ## Common Bugs & Pitfalls
72
+
73
+ - **[HIGH]** Async middleware not calling `next()` on error → request hangs indefinitely.
74
+ - **[HIGH]** Route defined after `app.use(errorHandler)` → error handler intercepts all subsequent routes.
75
+ - **[HIGH]** Error-handling middleware with only 3 params `(req, res, next)` → Express doesn't recognize as error handler (needs 4: `err, req, res, next`).
76
+ - **[HIGH]** `app.use(express.json())` placed after route definition → `req.body` undefined.
77
+ - **[MEDIUM]** Wildcard route `app.get('*', ...)` placed before specific routes → all specific routes shadowed.
78
+ - **[MEDIUM]** `router.param()` not used for common param validation → repeated `parseInt(req.params.id)`.
79
+ - **[MEDIUM]** Cookie options (`httpOnly`, `secure`, `sameSite`) not set → vulnerable session cookies.
80
+ - **[MEDIUM]** `res.end()` vs `res.send()` vs `res.json()` confusion → wrong Content-Type header.
81
+ - **[LOW]** `app.listen()` not storing returned server for graceful shutdown.
82
+ - **[LOW]** `express-validator` errors not checked with `validationResult(req)` → validation runs but not enforced.
@@ -0,0 +1,88 @@
1
+ # FastAPI — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `from fastapi`, `@app.get`, `@app.post`, `@router.`, `Depends(`, `BaseModel` (pydantic), `uvicorn`, `@asynccontextmanager`, `lifespan`
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[CRITICAL]** Route missing `Depends(get_current_user)` on protected endpoints → unauthenticated access.
11
+ - **[CRITICAL]** SQL built with f-string/`.format()` with user data → injection. Use parameterized queries.
12
+ - **[CRITICAL]** `eval()` / `exec()` with user-controlled input in any route or utility.
13
+ - **[HIGH]** ORM model returned directly instead of Pydantic response schema → exposes passwords, internal IDs.
14
+ - **[HIGH]** Missing `response_model` on endpoints → no output filtering, arbitrary data returned.
15
+ - **[HIGH]** `allow_origins=["*"]` in production CORS config → any website makes credentialed requests.
16
+ - **[HIGH]** Secrets loaded with `os.getenv("SECRET")` returning `None` silently → app runs without secrets.
17
+ - **[HIGH]** File upload missing MIME type + size validation → arbitrary file upload.
18
+ - **[HIGH]** Missing `HTTPSRedirectMiddleware` in production → tokens/cookies sent over HTTP.
19
+ - **[HIGH]** JWT token not validated for expiry/signature in `get_current_user` dependency.
20
+ - **[HIGH]** User-supplied `redirect_uri` in OAuth flow not validated → open redirect.
21
+ - **[MEDIUM]** Missing rate limiting on auth endpoints → brute force on login.
22
+ - **[MEDIUM]** `background_tasks.add_task()` running with request-scoped DB session that closes → session closed before task runs.
23
+ - **[LOW]** OpenAPI docs (`/docs`, `/redoc`) accessible in production without auth → schema exposed.
24
+
25
+ ---
26
+
27
+ ## Performance
28
+
29
+ - **[HIGH]** Synchronous I/O (`requests.get()`, blocking DB calls) inside `async def` route → blocks event loop. Use `httpx.AsyncClient`, async ORM.
30
+ - **[HIGH]** N+1 ORM queries — loading relationships in loop. Use `selectinload`/`joinedload` with SQLAlchemy async.
31
+ - **[HIGH]** Missing `async` on database session operations with async SQLAlchemy → sync in async context.
32
+ - **[HIGH]** `await` inside `for` loop → sequential DB calls; batch with `asyncio.gather()`.
33
+ - **[HIGH]** Missing pagination on list endpoints → unbounded query.
34
+ - **[HIGH]** Sync function passed to `run_in_executor` without proper thread pool → blocking thread pool worker.
35
+ - **[MEDIUM]** `background_tasks` used for critical path work → fires and forgets, no error handling.
36
+ - **[MEDIUM]** Pydantic v1 `orm_mode` / v2 `from_attributes` missing → ORM objects not serializable.
37
+ - **[MEDIUM]** DB connection not pooled → new connection per request.
38
+ - **[MEDIUM]** Not using `ORJSONResponse` for large JSON payloads → default `JSONResponse` slower.
39
+ - **[LOW]** Multiple middleware layers running on every request including static assets.
40
+ - **[LOW]** `@lru_cache` on dependency returning DB session → sessions shared across requests.
41
+
42
+ ---
43
+
44
+ ## Architecture
45
+
46
+ - **[HIGH]** Business logic inside route function → delegate to service/repository layer.
47
+ - **[HIGH]** DB session directly in route (`db: Session = Depends(get_db)`) without proper lifecycle.
48
+ - **[HIGH]** Not using `APIRouter` per domain → everything in `main.py` → unmaintainable.
49
+ - **[HIGH]** No dependency injection for services → hardcoded globals, not testable.
50
+ - **[MEDIUM]** Missing `lifespan` context manager → using deprecated `@app.on_event("startup")`.
51
+ - **[MEDIUM]** Pydantic validators with side effects (DB queries in validators) → validators should be pure.
52
+ - **[MEDIUM]** Not using `@asynccontextmanager` for resource management in dependencies.
53
+ - **[MEDIUM]** Error handling missing global `@app.exception_handler` → default 500 for all errors.
54
+ - **[MEDIUM]** Not using `HTTPException` with proper status codes → all errors return 200 or 500.
55
+ - **[LOW]** Missing `tags`, `summary`, `description` on routers → poor OpenAPI docs.
56
+ - **[LOW]** Schema inheritance >2 levels deep → confusing field origins.
57
+
58
+ ---
59
+
60
+ ## Code Quality
61
+
62
+ - **[HIGH]** Missing type annotations on route parameters → FastAPI cannot parse/validate.
63
+ - **[HIGH]** `except Exception` swallowing errors in route handlers.
64
+ - **[HIGH]** Pydantic `field_validator` (v2) not raising `ValueError` → validation silently ignored.
65
+ - **[MEDIUM]** `Optional[str]` vs `str | None` inconsistency (pick one per Python version).
66
+ - **[MEDIUM]** `Query(None)` for optional params not using `Annotated` style (modern FastAPI).
67
+ - **[MEDIUM]** Not using `Annotated[str, Query(min_length=1)]` for reusable param validation.
68
+ - **[MEDIUM]** Status codes not semantically correct (201 for create, 204 for delete, etc.).
69
+ - **[MEDIUM]** Missing `response_description` on endpoints → OpenAPI shows no response info.
70
+ - **[LOW]** `Path()` / `Query()` missing `description` → undocumented parameters.
71
+ - **[LOW]** Not using `model_config = ConfigDict(str_strip_whitespace=True)` on input models.
72
+
73
+ ---
74
+
75
+ ## Common Bugs & Pitfalls
76
+
77
+ - **[HIGH]** Mutable default in Pydantic model (`field: list = []`) → shared across all instances.
78
+ - **[HIGH]** Async generator dependency not properly closed on exception → DB session leak.
79
+ - **[HIGH]** `HTTPException` raised inside `background_tasks` → silently swallowed, client got 200 already.
80
+ - **[HIGH]** Route handler `async def` but calling sync-heavy function without `asyncio.to_thread()` → event loop blocked.
81
+ - **[HIGH]** Pydantic v1 and v2 mixed in same project → validation behavior differences cause bugs.
82
+ - **[MEDIUM]** `Form()` and `Body()` used together → FastAPI doesn't support mixing form + JSON.
83
+ - **[MEDIUM]** `status_code=200` on POST creating resource → should be 201.
84
+ - **[MEDIUM]** Dependency exception not propagating correctly when dependency raises inside generator after `yield`.
85
+ - **[MEDIUM]** `PATCH` handler using `PUT` semantics (replacing entire object instead of partial update).
86
+ - **[MEDIUM]** Not using `model.model_dump(exclude_unset=True)` for PATCH → overwriting unset fields with defaults.
87
+ - **[LOW]** Not pinning pydantic version → v1/v2 breaking changes.
88
+ - **[LOW]** `uvicorn --reload` used in production → file watcher overhead.
@@ -0,0 +1,60 @@
1
+ # Fastify — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: from 'fastify', Fastify(), fastify.register(), fastify.route(), schema: with JSON Schema, @fastify/
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[HIGH]** Missing `@fastify/helmet` plugin → security headers (CSP, HSTS, X-Frame-Options) absent. Register it as a global plugin before routes.
10
+ - **[HIGH]** No rate limiting via `@fastify/rate-limit` → brute-force and DoS succeed on public endpoints. Apply globally with per-route overrides.
11
+ - **[CRITICAL]** JSON schema validation disabled or bypassed (`schema` omitted, AJV strict mode off) → prototype pollution and arbitrary data accepted. Always define request schemas.
12
+ - **[HIGH]** Unvalidated file paths in `@fastify/multipart` → path traversal or overwrite attacks. Sanitize filenames and whitelist destination directories.
13
+ - **[HIGH]** CORS wildcard origin with `credentials: true` in `@fastify/cors` → cookies accepted from any domain. Set explicit origins or disable credentials when using wildcard.
14
+ - **[MEDIUM]** Response schema leaking internal fields (e.g., `password`, `internalId`) → sensitive data returned to clients. Define `schema.response` on every route.
15
+ - **[HIGH]** String fields not sanitized beyond JSON schema type checks → stored XSS or injection when data rendered. Add `format` or `pattern` constraints and sanitize.
16
+ - **[MEDIUM]** `fastify.register()` load order placing routes before auth plugin initialized → auth hooks absent. Register security plugins before route plugins.
17
+
18
+ ---
19
+
20
+ ## Performance
21
+ - **[HIGH]** No `schema.response` defined → Fastify falls back to slow `JSON.stringify` instead of fast-json-stringify, reducing throughput 2-5x. Define response schemas on every route.
22
+ - **[CRITICAL]** Missing `return` before `reply.send()` in async handlers → execution continues post-response, causing "Reply already sent" crashes. Always write `return reply.send(...)`.
23
+ - **[HIGH]** Async handler not returning a value or promise → request left unresolved, client hangs. Return the promise or call `reply.send()` in every code path.
24
+ - **[HIGH]** Synchronous CPU-heavy operations (crypto, regex, large JSON) inside handlers → event loop blocked, degrading concurrent requests. Offload to worker threads or async chunks.
25
+ - **[MEDIUM]** Shared services not wrapped with `fastify-plugin` → each plugin scope re-instantiates the service, wasting memory and DB connections. Use `fp()` to share decorators.
26
+ - **[MEDIUM]** Same plugin registered multiple times in nested scopes → duplicate middleware overhead per request. Use `fastify-plugin` where cross-scope sharing is intended.
27
+ - **[MEDIUM]** Pino at `trace` or `debug` level in production → excessive log I/O overhead. Set `logger: { level: 'info' }` and use async pino transport.
28
+ - **[LOW]** No content-type when sending pre-serialized JSON strings → Fastify may re-serialize. Use `reply.type('application/json').send(str)`.
29
+
30
+ ---
31
+
32
+ ## Architecture
33
+ - **[HIGH]** Business logic in route handler functions → untestable monoliths mixing HTTP and domain concerns. Extract into service modules and inject via `fastify.decorate()`.
34
+ - **[HIGH]** Shared services not registered via `fastify.decorate()` → services re-instantiated per module. Decorate the Fastify instance once at startup.
35
+ - **[MEDIUM]** Plugins lacking proper encapsulation → decorators and hooks leak across boundaries, causing ordering bugs. Use `fastify-plugin` only for deliberate cross-scope sharing.
36
+ - **[HIGH]** No `onRequest` or `preHandler` auth hooks on protected routes → routes accessible without a valid token. Scope an auth hook to protected route groups.
37
+ - **[MEDIUM]** All routes defined in one file → codebase grows unmanageable as app scales. Organize into domain-scoped plugins with `fastify.register()` and logical prefixes.
38
+ - **[MEDIUM]** No `fastify.addContentTypeParser()` for non-JSON request bodies → binary or form data silently rejected. Register parsers for all expected content types.
39
+ - **[LOW]** Routes not versioned (`/v1/`, `/v2/`) → breaking changes force simultaneous client updates. Establish prefix-based versioning from the outset.
40
+
41
+ ---
42
+
43
+ ## Code Quality
44
+ - **[MEDIUM]** No TypeScript type provider (`@fastify/type-provider-typebox` or `@fastify/type-provider-zod`) → handler params typed as `any`. Integrate a type provider and colocate schemas with routes.
45
+ - **[MEDIUM]** Route schemas duplicated inline across routes → schema drift and maintenance burden. Register shared schemas with `fastify.addSchema()` and reference via ``.
46
+ - **[HIGH]** No `fastify.setErrorHandler()` → inconsistent error shapes from per-handler try/catch. Define a global error handler normalizing errors to a standard envelope.
47
+ - **[MEDIUM]** No custom `fastify.setNotFoundHandler()` → default 404 format breaks client error parsing. Register a not-found handler returning the standard error shape.
48
+ - **[LOW]** Full request objects logged including auth headers → tokens appear in log aggregators. Configure pino `redact` paths to strip sensitive fields.
49
+ - **[MEDIUM]** Not using `fastify.inject()` in tests → tests need a live port, causing EADDRINUSE conflicts. Use `fastify.inject()` for in-process HTTP testing.
50
+
51
+ ---
52
+
53
+ ## Common Bugs & Pitfalls
54
+ - **[CRITICAL]** `reply.send()` without `return` in async callbacks → "Reply already sent" errors or double-send crashes. Always `return reply.send()`.
55
+ - **[HIGH]** Plugin not awaited at top level → plugin uninitialized when requests arrive, missing decorator errors. Always await `fastify.register()` or use a ready hook.
56
+ - **[HIGH]** Schema `` used before `fastify.addSchema()` → validation fails silently or throws at startup. Register all shared schemas before routes that reference them.
57
+ - **[MEDIUM]** `fastify.close()` not called in tests → port stays bound, EADDRINUSE on next run. Call `fastify.close()` in `afterAll` or `afterEach`.
58
+ - **[HIGH]** `fastify.listen()` without `host: '0.0.0.0'` in containers → server binds loopback only, unreachable externally. Set host based on deployment environment.
59
+ - **[MEDIUM]** No `onError` hook or uncaught exception handler → errors in lifecycle hooks crash the process without diagnostics. Attach an `onError` hook and process-level handler.
60
+ - **[MEDIUM]** Mixing async handlers with callback-style `reply.send()` → control-flow bugs where promise resolves before reply is sent. Pick one pattern and apply consistently.
@@ -0,0 +1,55 @@
1
+ # Fiber — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: "github.com/gofiber/fiber", fiber.New(), app.Get(, c.JSON(, c.BodyParser(, fiber.Config{
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[HIGH]** Missing `helmet` middleware (`github.com/gofiber/helmet`) → no security headers sent, leaving app vulnerable to clickjacking, MIME sniffing, and XSS. Register helmet middleware globally before route handlers.
10
+ - **[HIGH]** CSRF middleware not configured on state-mutating routes → cross-site form submissions processed without token validation. Enable CSRF protection for all POST/PUT/PATCH/DELETE routes.
11
+ - **[HIGH]** `c.BodyParser` used without a body size limit → large payloads exhaust memory. Configure `fiber.Config{ BodyLimit: 4 * 1024 * 1024 }` to enforce a maximum request body size.
12
+ - **[HIGH]** Wildcard CORS configured in production (origin: "*") → cross-origin requests accepted from any domain. Set explicit allowed origins in `cors.Config{ AllowOrigins: "https://yourdomain.com" }`.
13
+ - **[CRITICAL]** Path traversal via `c.Params()` values used in file operations → attacker crafts a path to read or overwrite arbitrary files. Sanitize and validate all path parameters before using them in file system calls.
14
+ - **[MEDIUM]** Missing authentication middleware on protected route groups → unauthenticated requests reach protected handlers. Use `app.Use()` on route groups to enforce auth before handler execution.
15
+ - **[MEDIUM]** Not validating struct fields after `c.BodyParser` → business logic receives zero-value or malformed data. Integrate a validation library (e.g., `go-playground/validator`) after parsing.
16
+ - **[MEDIUM]** Sensitive error details returned in HTTP responses → internal paths or DB errors exposed to clients. Return generic error messages and log detailed errors server-side only.
17
+
18
+ ---
19
+
20
+ ## Performance
21
+ - **[CRITICAL]** Fiber reuses `*fiber.Ctx` across requests → capturing ctx in a goroutine causes data races and use-after-free bugs. Never pass ctx to goroutines; extract all needed values before launching.
22
+ - **[MEDIUM]** Missing compress middleware for large responses → uncompressed JSON or HTML payloads increase bandwidth and client load time. Add `github.com/gofiber/fiber/middleware/compress`.
23
+ - **[MEDIUM]** `c.JSON()` marshaling large structs without streaming → entire response buffered in memory. For large datasets, use streaming responses or pagination.
24
+ - **[LOW]** `Prefork: true` not used on multi-core servers handling CPU-bound workloads → single process cannot fully utilize available CPU cores. Enable prefork in production environments and test for compatibility.
25
+ - **[HIGH]** Synchronous blocking calls (file I/O, external HTTP) inside handlers → Fiber's event loop stalls, degrading all concurrent requests. Use goroutines with proper synchronization for blocking operations.
26
+ - **[MEDIUM]** Not using `app.Static()` for serving static files → static assets served through application handlers with unnecessary overhead. Configure the built-in static file middleware for asset serving.
27
+
28
+ ---
29
+
30
+ ## Architecture
31
+ - **[MEDIUM]** Not using `app.Group()` for route organization → all routes defined at the top level, making the router file unmanageable as the app grows. Group related routes with common prefixes and middleware.
32
+ - **[HIGH]** Business logic implemented directly in handler functions → handlers become untestable and hard to maintain. Extract domain logic into service types with clear interfaces.
33
+ - **[MEDIUM]** Custom error handler not set via `app.Use(errorHandler)` → default Fiber error format inconsistent with the application API contract. Define a custom error handler returning the standard error shape.
34
+ - **[MEDIUM]** Database connections not managed via dependency injection → global DB instances make testing difficult and hide coupling. Pass DB and service dependencies through closure or a custom handler struct.
35
+ - **[LOW]** No middleware for request ID generation → distributed tracing and log correlation are difficult without request IDs. Add a request-ID middleware and propagate it through context and response headers.
36
+
37
+ ---
38
+
39
+ ## Code Quality
40
+ - **[HIGH]** Missing input validation after `c.BodyParser` → raw parsed data used without field-level validation, allowing missing or malformed data into business logic. Integrate `go-playground/validator` or equivalent after parsing.
41
+ - **[MEDIUM]** `c.Locals()` used as a typed store without type assertions → values retrieved as `interface{}` cause silent nil panics when the type is wrong. Define typed accessor helpers for context locals.
42
+ - **[HIGH]** Not handling `c.BodyParser` errors explicitly → parse failures pass a zero-value struct to the handler, corrupting business logic. Always check and return the error from BodyParser.
43
+ - **[MEDIUM]** No logging middleware configured → requests and errors go untracked, making production debugging difficult. Add the built-in logger middleware or a structured logging middleware.
44
+ - **[LOW]** Not using fiber's built-in timeout middleware → slow handlers hold connections indefinitely. Configure `middleware/timeout` to enforce handler deadlines.
45
+ - **[MEDIUM]** Using `fiber.Map` for all responses instead of typed structs → response shape is untyped and prone to field name typos. Define response structs to enforce a stable contract.
46
+
47
+ ---
48
+
49
+ ## Common Bugs & Pitfalls
50
+ - **[CRITICAL]** `*fiber.Ctx` captured in a goroutine without copying → ctx is recycled after handler returns, causing reads of garbage data or panics. Use `c.Context().Copy()` or extract needed values before the goroutine.
51
+ - **[MEDIUM]** `c.JSON()` called after `c.Next()` in middleware → response already committed by an inner handler, causing "response already sent" errors. Check if response is committed before writing in middleware.
52
+ - **[MEDIUM]** Path parameters overlapping between route definitions → ambiguous routes cause the wrong handler to be called. Order routes from most specific to most general and use explicit path segments.
53
+ - **[HIGH]** Not handling panics in goroutines spawned from handlers → goroutine panics crash the process and take down all active requests. Recover from panics in goroutines and log or report the error.
54
+ - **[MEDIUM]** `app.Listen()` without graceful shutdown → in-flight requests dropped when process exits. Implement signal handling and `app.Shutdown()` for graceful termination.
55
+ - **[HIGH]** Not setting `ReadTimeout` and `WriteTimeout` in `fiber.Config` → slow or malicious clients hold connections open indefinitely, exhausting connection slots. Set appropriate timeouts in the Fiber config.
@@ -0,0 +1,43 @@
1
+ # Firebase — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `firebase` in deps · `initializeApp(` · `getFirestore(` · `getAuth(` · `collection(` · `import 'firebase/` · `firebase.json` · `.firebaserc`
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[CRITICAL]** Firestore / Realtime Database security rules contain `allow read, write: if true` → anyone on the internet can read, write, or delete your entire database.
11
+ - **[CRITICAL]** Firebase Admin SDK service account JSON committed to version control → full administrative access to your Firebase project, bypasses all security rules.
12
+ - **[HIGH]** Firestore security rules not validating incoming data shape or field types → client can write documents with any structure, including oversized fields or unexpected types. Add `request.resource.data` validation.
13
+ - **[HIGH]** Authorization logic in client-side code only: `if (user.uid === doc.ownerId)` → client code can be bypassed. Enforce ownership and access control in Firestore security rules.
14
+ - **[MEDIUM]** Firebase API key visible in client-side code → expected (it's a public identifier), BUT ensure domain restrictions are configured in Firebase Console to prevent use from unauthorized domains.
15
+
16
+ ---
17
+
18
+ ## Performance
19
+
20
+ - **[HIGH]** `onSnapshot` listener not unsubscribed on component unmount → each mount adds a new listener; stale listeners fire callbacks on unmounted components, causing memory leaks and potential state updates after unmount.
21
+ - **[HIGH]** Fetching entire collection without a `where()` query → every read costs money; full collection scans on large datasets will exhaust quota and budget.
22
+ - **[MEDIUM]** Missing `limit()` on Firestore queries → unbounded reads; a growing collection causes increasing cost and latency over time.
23
+ - **[MEDIUM]** Real-time `onSnapshot` listener used where a one-time `getDoc()` / `getDocs()` suffices → continuous WebSocket connection maintained unnecessarily.
24
+ - **[LOW]** Not using `enableIndexedDbPersistence()` for offline support → queries fail when offline; consider offline capability for mobile-like use cases.
25
+
26
+ ---
27
+
28
+ ## Architecture
29
+
30
+ - **[HIGH]** Business logic placed in Firestore security rules (complex calculations, multi-step workflows) → rules are for access control only; complex logic belongs in Cloud Functions or the application layer.
31
+ - **[MEDIUM]** Deeply nested Firestore sub-collections more than 2 levels → Firestore cannot query across parent documents for sub-collections. Flatten the data model or use root-level collections with foreign key fields.
32
+ - **[MEDIUM]** `set()` used without `{ merge: true }` when partial update is intended → overwrites entire document, deletes unspecified fields. Use `update()` for partial updates.
33
+ - **[LOW]** Storing large blobs or images directly in Firestore documents → Firestore is optimized for structured data; store binaries in Firebase Storage and keep URLs/metadata in Firestore.
34
+
35
+ ---
36
+
37
+ ## Common Bugs & Pitfalls
38
+
39
+ - **[HIGH]** Direct array write instead of `arrayUnion` / `arrayRemove` for concurrent updates → two simultaneous writes both read the array, modify it, and write back; one write overwrites the other (last-write-wins). Use atomic array operations.
40
+ - **[HIGH]** `Timestamp.now()` used for ordering instead of `serverTimestamp()` → client clock may be wrong (wrong timezone, wrong time). Use `serverTimestamp()` for ordering and audit trails.
41
+ - **[MEDIUM]** Querying with `where('field', '!=', value)` without a composite index → Firestore throws an error at runtime pointing to the missing index. Check the Firebase Console for required indexes.
42
+ - **[MEDIUM]** `auth.currentUser` accessed synchronously on app load before auth state is initialized → may be `null` even if user is logged in. Always use `onAuthStateChanged` to react to auth state.
43
+ - **[LOW]** Firestore `where` inequality filter (`<`, `>`, `!=`) on a field combined with `orderBy` on a different field → requires a composite index and may throw a runtime error.
@@ -0,0 +1,46 @@
1
+ # Flask — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `from flask import`, `@app.route`, `Flask(__name__)`, `Blueprint`, `flask` in requirements.txt
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[CRITICAL]** `render_template_string()` with user-controlled input → Server-Side Template Injection (SSTI). Never use with user data.
11
+ - **[CRITICAL]** SQL query with f-string / `.format()` of user input → SQL injection. Use parameterized queries.
12
+ - **[HIGH]** Missing `@login_required` / auth check on protected routes.
13
+ - **[HIGH]** `SECRET_KEY` hardcoded in app code → session forgery. Load from environment.
14
+ - **[HIGH]** `Markup()` used to mark user content as safe → XSS. Jinja2 escapes by default; don't bypass it.
15
+ - **[HIGH]** Debug mode enabled in production (`app.run(debug=True)`) → interactive debugger accessible to users, RCE risk.
16
+ - **[MEDIUM]** `send_file()` / `send_from_directory()` with user-controlled path → path traversal. Validate and sanitize paths.
17
+ - **[MEDIUM]** Missing CSRF protection (Flask-WTF or manual token) on state-changing forms.
18
+ - **[MEDIUM]** Allowing all origins in CORS configuration for APIs with auth.
19
+
20
+ ---
21
+
22
+ ## Performance
23
+
24
+ - **[HIGH]** Synchronous DB calls blocking Flask worker — use async frameworks (Quart) or offload to Celery.
25
+ - **[HIGH]** N+1 ORM queries in view function — load relations eagerly.
26
+ - **[MEDIUM]** `session` object used to store large data → stored in cookie, 4KB limit, sent on every request.
27
+ - **[MEDIUM]** No pagination on list endpoints.
28
+ - **[LOW]** Flask development server (`app.run()`) used in production instead of Gunicorn/uWSGI → single-threaded.
29
+
30
+ ---
31
+
32
+ ## Architecture
33
+
34
+ - **[HIGH]** All routes in single `app.py` → use Blueprints to organize by domain.
35
+ - **[MEDIUM]** Application factory pattern (`create_app()`) not used → hard to test with different configs.
36
+ - **[MEDIUM]** Business logic directly in route function → move to service/model layer.
37
+ - **[LOW]** `current_app` accessed outside application context → `RuntimeError`.
38
+
39
+ ---
40
+
41
+ ## Common Bugs & Pitfalls
42
+
43
+ - **[HIGH]** Mutable default in route function or SQLAlchemy model → shared state across requests.
44
+ - **[HIGH]** `g` object used to store request-scoped data but not cleaned up → leaks between requests in some WSGI setups.
45
+ - **[MEDIUM]** `redirect(request.referrer)` without validation → open redirect.
46
+ - **[MEDIUM]** `jsonify()` not used for JSON responses → missing Content-Type header.