prr-kit 1.1.3 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +260 -235
- package/docs/assets/banner.svg +30 -248
- package/docs/assets/how-it-works.svg +87 -0
- package/package.json +60 -60
- package/src/core/agents/prr-master.agent.yaml +18 -7
- package/src/core/tasks/clear.md +140 -0
- package/src/core/tasks/help.md +15 -13
- package/src/core/workflows/clear/workflow.md +6 -0
- package/src/core/workflows/help/workflow.md +6 -0
- package/src/core/workflows/party-mode/steps/step-01-load-reviewers.md +35 -24
- package/src/core/workflows/party-mode/steps/step-02-discussion.md +45 -25
- package/src/core/workflows/party-mode/workflow.md +2 -2
- package/src/prr/agents/architecture-reviewer.agent.yaml +65 -45
- package/src/prr/agents/business-reviewer.agent.yaml +66 -0
- package/src/prr/agents/general-reviewer.agent.yaml +64 -48
- package/src/prr/agents/performance-reviewer.agent.yaml +65 -45
- package/src/prr/agents/security-reviewer.agent.yaml +67 -43
- package/src/prr/config-template.yaml +97 -0
- package/src/prr/data/stacks/actix.md +55 -0
- package/src/prr/data/stacks/alpine.md +47 -0
- package/src/prr/data/stacks/android.md +53 -0
- package/src/prr/data/stacks/angular.md +96 -0
- package/src/prr/data/stacks/ansible.md +55 -0
- package/src/prr/data/stacks/apollo.md +54 -0
- package/src/prr/data/stacks/astro.md +48 -0
- package/src/prr/data/stacks/aws-cdk.md +55 -0
- package/src/prr/data/stacks/axum.md +56 -0
- package/src/prr/data/stacks/babylonjs.md +55 -0
- package/src/prr/data/stacks/bash.md +53 -0
- package/src/prr/data/stacks/bevy.md +53 -0
- package/src/prr/data/stacks/bootstrap.md +52 -0
- package/src/prr/data/stacks/bun.md +55 -0
- package/src/prr/data/stacks/cpp.md +57 -0
- package/src/prr/data/stacks/csharp.md +95 -0
- package/src/prr/data/stacks/css.md +55 -0
- package/src/prr/data/stacks/cypress.md +53 -0
- package/src/prr/data/stacks/d3.md +53 -0
- package/src/prr/data/stacks/deno.md +49 -0
- package/src/prr/data/stacks/django.md +92 -0
- package/src/prr/data/stacks/docker.md +79 -0
- package/src/prr/data/stacks/drizzle.md +54 -0
- package/src/prr/data/stacks/dynamodb.md +55 -0
- package/src/prr/data/stacks/electron.md +44 -0
- package/src/prr/data/stacks/elixir.md +53 -0
- package/src/prr/data/stacks/expo.md +53 -0
- package/src/prr/data/stacks/expressjs.md +82 -0
- package/src/prr/data/stacks/fastapi.md +88 -0
- package/src/prr/data/stacks/fastify.md +60 -0
- package/src/prr/data/stacks/fiber.md +55 -0
- package/src/prr/data/stacks/firebase.md +43 -0
- package/src/prr/data/stacks/flask.md +46 -0
- package/src/prr/data/stacks/flutter.md +75 -0
- package/src/prr/data/stacks/gin.md +57 -0
- package/src/prr/data/stacks/github-actions.md +71 -0
- package/src/prr/data/stacks/go.md +88 -0
- package/src/prr/data/stacks/godot.md +56 -0
- package/src/prr/data/stacks/graphql.md +76 -0
- package/src/prr/data/stacks/grpc.md +56 -0
- package/src/prr/data/stacks/haskell.md +48 -0
- package/src/prr/data/stacks/helm.md +54 -0
- package/src/prr/data/stacks/hono.md +54 -0
- package/src/prr/data/stacks/htmx.md +38 -0
- package/src/prr/data/stacks/java.md +87 -0
- package/src/prr/data/stacks/jest-vitest.md +87 -0
- package/src/prr/data/stacks/jquery.md +50 -0
- package/src/prr/data/stacks/junit.md +53 -0
- package/src/prr/data/stacks/kotlin.md +89 -0
- package/src/prr/data/stacks/kubernetes.md +148 -0
- package/src/prr/data/stacks/langchain.md +56 -0
- package/src/prr/data/stacks/laravel.md +56 -0
- package/src/prr/data/stacks/libgdx.md +46 -0
- package/src/prr/data/stacks/lit.md +49 -0
- package/src/prr/data/stacks/love2d.md +51 -0
- package/src/prr/data/stacks/lua.md +51 -0
- package/src/prr/data/stacks/mobx.md +54 -0
- package/src/prr/data/stacks/mongodb.md +85 -0
- package/src/prr/data/stacks/monogame.md +51 -0
- package/src/prr/data/stacks/mysql.md +57 -0
- package/src/prr/data/stacks/nestjs.md +95 -0
- package/src/prr/data/stacks/nextjs.md +88 -0
- package/src/prr/data/stacks/nginx.md +55 -0
- package/src/prr/data/stacks/node.md +56 -0
- package/src/prr/data/stacks/nuxtjs.md +91 -0
- package/src/prr/data/stacks/openai-api.md +54 -0
- package/src/prr/data/stacks/opengl.md +54 -0
- package/src/prr/data/stacks/phaser.md +54 -0
- package/src/prr/data/stacks/phoenix.md +55 -0
- package/src/prr/data/stacks/php.md +56 -0
- package/src/prr/data/stacks/playwright.md +86 -0
- package/src/prr/data/stacks/postgresql.md +60 -0
- package/src/prr/data/stacks/prisma.md +81 -0
- package/src/prr/data/stacks/pygame.md +52 -0
- package/src/prr/data/stacks/pytest.md +53 -0
- package/src/prr/data/stacks/python.md +94 -0
- package/src/prr/data/stacks/pytorch.md +54 -0
- package/src/prr/data/stacks/qwik.md +50 -0
- package/src/prr/data/stacks/rails.md +48 -0
- package/src/prr/data/stacks/react-native.md +77 -0
- package/src/prr/data/stacks/react.md +104 -0
- package/src/prr/data/stacks/redis.md +76 -0
- package/src/prr/data/stacks/redux.md +107 -0
- package/src/prr/data/stacks/remix.md +51 -0
- package/src/prr/data/stacks/rust.md +88 -0
- package/src/prr/data/stacks/sass.md +51 -0
- package/src/prr/data/stacks/scala.md +50 -0
- package/src/prr/data/stacks/scikit-learn.md +53 -0
- package/src/prr/data/stacks/sequelize.md +54 -0
- package/src/prr/data/stacks/socket-io.md +54 -0
- package/src/prr/data/stacks/solidity.md +53 -0
- package/src/prr/data/stacks/solidjs.md +45 -0
- package/src/prr/data/stacks/spring-boot.md +92 -0
- package/src/prr/data/stacks/sql.md +85 -0
- package/src/prr/data/stacks/sqlite.md +55 -0
- package/src/prr/data/stacks/styled-components.md +51 -0
- package/src/prr/data/stacks/supabase.md +57 -0
- package/src/prr/data/stacks/svelte.md +77 -0
- package/src/prr/data/stacks/sveltekit.md +54 -0
- package/src/prr/data/stacks/swift.md +61 -0
- package/src/prr/data/stacks/tailwindcss.md +10 -0
- package/src/prr/data/stacks/tanstack-query.md +48 -0
- package/src/prr/data/stacks/tauri.md +52 -0
- package/src/prr/data/stacks/terraform.md +53 -0
- package/src/prr/data/stacks/three.md +53 -0
- package/src/prr/data/stacks/trpc.md +49 -0
- package/src/prr/data/stacks/typeorm.md +40 -0
- package/src/prr/data/stacks/typescript.md +83 -0
- package/src/prr/data/stacks/unity.md +61 -0
- package/src/prr/data/stacks/unreal.md +58 -0
- package/src/prr/data/stacks/vite.md +48 -0
- package/src/prr/data/stacks/vue3.md +95 -0
- package/src/prr/data/stacks/vulkan.md +53 -0
- package/src/prr/data/stacks/wasm.md +49 -0
- package/src/prr/data/stacks/webpack.md +48 -0
- package/src/prr/data/stacks/zig.md +51 -0
- package/src/prr/data/stacks/zustand.md +56 -0
- package/src/prr/workflows/1-discover/select-pr/steps/step-05-confirm.md +1 -0
- package/src/prr/workflows/1-discover/select-pr/workflow.md +1 -1
- package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-01-analyze-files.md +334 -0
- package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-02-collect-sources.md +451 -0
- package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-03-build-knowledge-base.md +337 -0
- package/src/prr/workflows/2-analyze/collect-pr-context/workflow.md +123 -0
- package/src/prr/workflows/2-analyze/describe-pr/steps/step-02-classify.md +12 -6
- package/src/prr/workflows/2-analyze/describe-pr/steps/step-03-walkthrough.md +59 -1
- package/src/prr/workflows/3-review/architecture-review/checklist.md +4 -0
- package/src/prr/workflows/3-review/architecture-review/instructions.xml +32 -4
- package/src/prr/workflows/3-review/architecture-review/workflow.yaml +17 -18
- package/src/prr/workflows/3-review/business-review/checklist.md +27 -0
- package/src/prr/workflows/3-review/business-review/instructions.xml +153 -0
- package/src/prr/workflows/3-review/business-review/workflow.yaml +17 -0
- package/src/prr/workflows/3-review/general-review/checklist.md +5 -1
- package/src/prr/workflows/3-review/general-review/instructions.xml +39 -8
- package/src/prr/workflows/3-review/general-review/workflow.yaml +17 -18
- package/src/prr/workflows/3-review/performance-review/checklist.md +3 -1
- package/src/prr/workflows/3-review/performance-review/instructions.xml +10 -3
- package/src/prr/workflows/3-review/performance-review/workflow.yaml +17 -18
- package/src/prr/workflows/3-review/security-review/checklist.md +2 -1
- package/src/prr/workflows/3-review/security-review/instructions.xml +8 -3
- package/src/prr/workflows/3-review/security-review/workflow.yaml +18 -19
- package/src/prr/workflows/4-improve/improve-code/workflow.yaml +17 -18
- package/src/prr/workflows/6-report/generate-report/steps/step-01-collect.md +9 -2
- package/src/prr/workflows/6-report/generate-report/steps/step-02-organize.md +28 -7
- package/src/prr/workflows/6-report/generate-report/steps/step-03-write.md +6 -4
- package/src/prr/workflows/6-report/generate-report/templates/review-report.template.md +124 -78
- package/src/prr/workflows/6-report/post-comments/steps/step-01-format.md +104 -13
- package/src/prr/workflows/6-report/post-comments/steps/step-02-post.md +92 -21
- package/src/prr/workflows/6-report/post-comments/workflow.md +6 -0
- package/src/prr/workflows/quick/workflow.md +138 -32
- package/src/prr/workflows/0-setup/collect-project-context/steps/step-01-scan-configs.md +0 -106
- package/src/prr/workflows/0-setup/collect-project-context/steps/step-02-extract-rules.md +0 -131
- package/src/prr/workflows/0-setup/collect-project-context/steps/step-03-ask-context.md +0 -194
- package/src/prr/workflows/0-setup/collect-project-context/steps/step-04-save-context.md +0 -161
- package/src/prr/workflows/0-setup/collect-project-context/workflow.md +0 -58
|
@@ -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.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Flutter / Dart — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `*.dart` files · `pubspec.yaml` with `flutter:` · `import 'package:flutter/` · `Widget` · `StatefulWidget` · `BuildContext` · `Riverpod`/`Bloc`/`Provider`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
|
|
10
|
+
- **[HIGH]** Sensitive data (tokens, passwords, PINs) in `SharedPreferences` → not encrypted. Use `flutter_secure_storage` (Keychain on iOS, Keystore on Android).
|
|
11
|
+
- **[HIGH]** `WebView` with `javaScriptMode: JavascriptMode.unrestricted` loading untrusted URLs → XSS, platform channel access.
|
|
12
|
+
- **[HIGH]** API keys hardcoded in Dart source → extracted from APK/IPA via reverse engineering. Use `--dart-define` or backend proxy.
|
|
13
|
+
- **[HIGH]** `dart:mirrors` used for dynamic invocation of user-controlled method names → code injection.
|
|
14
|
+
- **[MEDIUM]** Certificate validation disabled (custom `HttpClient.badCertificateCallback`) → MITM.
|
|
15
|
+
- **[MEDIUM]** `Platform.environment` in Flutter → may expose environment variables. Use `--dart-define` for build-time constants.
|
|
16
|
+
- **[MEDIUM]** Deep link params not validated → malicious intent triggers action with crafted data.
|
|
17
|
+
- **[LOW]** Debug flag (`kDebugMode`) not checked before logging sensitive data.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Performance
|
|
22
|
+
|
|
23
|
+
- **[HIGH]** `setState()` on high-level ancestor for leaf change → rebuilds entire subtree. Use `Provider`/`Riverpod`/`ValueNotifier` to scope rebuilds.
|
|
24
|
+
- **[HIGH]** Heavy objects created inside `build()` → recreated on every rebuild. Move to `initState()` or `didChangeDependencies()`.
|
|
25
|
+
- **[HIGH]** `ListView` (non-builder) for dynamic/long lists → all items rendered. Use `ListView.builder()`.
|
|
26
|
+
- **[HIGH]** `FutureBuilder` without stable `future` reference → parent rebuild creates new Future, re-fetches every time. Store Future in `initState`.
|
|
27
|
+
- **[HIGH]** `const` constructor missing on stateless widgets → prevents subtree optimization.
|
|
28
|
+
- **[HIGH]** `build()` method doing I/O or heavy computation → blocks UI thread. Use `compute()` or `Isolate`.
|
|
29
|
+
- **[MEDIUM]** `Image.network` without `cacheWidth`/`cacheHeight` → full resolution decoded for small display.
|
|
30
|
+
- **[MEDIUM]** `AnimationController` not disposed → memory leak and assertion errors.
|
|
31
|
+
- **[MEDIUM]** `StreamBuilder` subscribing to broadcast stream that never closes → subscription held forever.
|
|
32
|
+
- **[LOW]** Not using `RepaintBoundary` to isolate frequently repainting widgets → whole tree repainted.
|
|
33
|
+
- **[LOW]** `Opacity` widget used for animations instead of `AnimatedOpacity` or `FadeTransition`.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
- **[HIGH]** Business logic inside `Widget.build()` → hard to test. Use BLoC, Provider, Riverpod, or GetX.
|
|
40
|
+
- **[HIGH]** `BuildContext` used across `async` gap without `mounted` check → crash after navigation.
|
|
41
|
+
- **[HIGH]** `Navigator.pop()` called without checking navigator stack → `FlutterError` on first route.
|
|
42
|
+
- **[HIGH]** `StatefulWidget` used for everything → use `StatelessWidget` + state management for separation.
|
|
43
|
+
- **[MEDIUM]** `GetX` controller not bound to widget lifecycle → controller persists after widget destroyed.
|
|
44
|
+
- **[MEDIUM]** Not using `GoRouter` or `auto_route` for deep link + navigation → manual route management breaks.
|
|
45
|
+
- **[MEDIUM]** Platform channel not handling errors → unhandled exception on plugin failure.
|
|
46
|
+
- **[LOW]** Widget `build()` >100 lines → extract named sub-widgets or methods.
|
|
47
|
+
- **[LOW]** Not organizing code by feature → flat `lib/` directory with hundreds of files.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Code Quality
|
|
52
|
+
|
|
53
|
+
- **[HIGH]** `dynamic` type used broadly → defeats Dart sound null safety. Use specific types or generics.
|
|
54
|
+
- **[HIGH]** `TextEditingController`/`FocusNode`/`ScrollController` not disposed → memory leak + debug assertion.
|
|
55
|
+
- **[HIGH]** `mounted` check missing after every `await` in `StatefulWidget` method.
|
|
56
|
+
- **[MEDIUM]** `print()` in production → use `debugPrint()` (no-op in release) or structured logging.
|
|
57
|
+
- **[MEDIUM]** Missing `Key` on list items → Flutter can't reconcile tree on reorder.
|
|
58
|
+
- **[MEDIUM]** `late` variables accessed before initialization → `LateInitializationError` at runtime.
|
|
59
|
+
- **[MEDIUM]** Nullable variable accessed with `!` without check → `Null check operator used on null value`.
|
|
60
|
+
- **[LOW]** Not running `flutter analyze` in CI → lint issues uncaught.
|
|
61
|
+
- **[LOW]** `pubspec.yaml` dependencies not version-pinned → unexpected breaking changes.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Common Bugs & Pitfalls
|
|
66
|
+
|
|
67
|
+
- **[HIGH]** `async` `onPressed` without `mounted` check → `setState()` on unmounted widget.
|
|
68
|
+
- **[HIGH]** `Column` with `Expanded` inside `ListView` → layout exception (unbounded height). Use `shrinkWrap` or restructure.
|
|
69
|
+
- **[HIGH]** `StreamController` not closed → memory leak and lint warning.
|
|
70
|
+
- **[MEDIUM]** `Image.network` without `errorBuilder` → broken image shown silently.
|
|
71
|
+
- **[MEDIUM]** `FocusNode.dispose()` not called → memory leak.
|
|
72
|
+
- **[MEDIUM]** `Riverpod` provider accessed after widget disposed → `ProviderScope` not found error.
|
|
73
|
+
- **[MEDIUM]** `WillPopScope` deprecated (Flutter 3.12+) → use `PopScope` with `canPop` instead.
|
|
74
|
+
- **[LOW]** `ThemeData` not using `ColorScheme.fromSeed` (Material 3) → inconsistent colors.
|
|
75
|
+
- **[LOW]** Not testing on both iOS and Android → platform-specific bugs missed.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Gin — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: "github.com/gin-gonic/gin", gin.Default(), gin.New(), c.JSON(, c.ShouldBindJSON, r.GET(, r.POST(
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
- **[CRITICAL]** `c.ShouldBind` used without validation struct tags → unvalidated user input reaches business logic. Always define and enforce validation tags (`binding:"required"`, `validate:"email"`, etc.) on all bound structs.
|
|
10
|
+
- **[CRITICAL]** SQL injection via `fmt.Sprintf` in database queries → attacker-controlled input alters query structure. Always use parameterized queries or an ORM with prepared statements.
|
|
11
|
+
- **[HIGH]** Missing CORS configuration or wildcard CORS (`"*"`) in production → cross-origin requests accepted from any domain. Configure explicit allowed origins via gin-cors middleware.
|
|
12
|
+
- **[HIGH]** No rate limiting middleware → DoS attacks succeed without throttling. Integrate a rate limiter such as `golang.org/x/time/rate` or a middleware library.
|
|
13
|
+
- **[HIGH]** Server binding to `0.0.0.0` in production without TLS → traffic transmitted in plaintext over network. Terminate TLS at the load balancer or configure `tls.ListenAndServeTLS`.
|
|
14
|
+
- **[HIGH]** SSRF via user-controlled URL in proxy or fetch handlers → attacker triggers requests to internal services. Validate and whitelist allowed URL schemes and hosts before making server-side requests.
|
|
15
|
+
- **[MEDIUM]** Sensitive data (tokens, passwords) logged in debug mode → secrets appear in log files accessible to operators. Use structured logging with field redaction and disable debug logs in production.
|
|
16
|
+
- **[MEDIUM]** Missing input length limits on string fields → oversized payloads cause excessive memory allocation or ReDoS in regex validators. Enforce maximum lengths in validation tags or middleware.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Performance
|
|
21
|
+
- **[HIGH]** Debug mode (`gin.Default()`) used in production → verbose logging and color output add unnecessary overhead. Use `gin.New()` with explicit middleware and set `GIN_MODE=release`.
|
|
22
|
+
- **[MEDIUM]** No response caching for static or slow-changing data → repeated expensive queries for identical data on every request. Add cache-control headers or an in-memory cache layer.
|
|
23
|
+
- **[MEDIUM]** Synchronous database calls in handlers without goroutines for independent queries → sequential round-trips increase total response latency. Use goroutines with `errgroup` for parallel independent DB calls.
|
|
24
|
+
- **[MEDIUM]** Large JSON marshaling of full structs without streaming → entire response built in memory before sending. For very large datasets, use streaming encoders or pagination.
|
|
25
|
+
- **[LOW]** Missing gzip middleware for large responses → uncompressed payloads increase bandwidth and client latency. Add `github.com/gin-contrib/gzip` to the middleware stack.
|
|
26
|
+
- **[MEDIUM]** Allocating large slices with fixed capacity inside handlers → GC pressure accumulates under load. Pre-allocate with realistic capacity estimates or use sync.Pool for reusable buffers.
|
|
27
|
+
- **[MEDIUM]** Not using Gin route groups for common middleware (e.g., auth, logging) → middleware applied redundantly or inconsistently across routes. Use `r.Group()` with shared middleware.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Architecture
|
|
32
|
+
- **[HIGH]** Business logic implemented in handler functions instead of a service layer → handlers become large, untestable, and tightly coupled to HTTP. Extract logic into service structs with well-defined interfaces.
|
|
33
|
+
- **[HIGH]** Not using dependency injection → hardcoded global DB connections and singletons make testing impossible and hide coupling. Pass dependencies (DB, logger, services) through handler structs or closures.
|
|
34
|
+
- **[MEDIUM]** Route groups not organized by domain or API version → route file becomes a flat, unnavigable list as the app grows. Group related routes with `r.Group("/api/v1/")` and domain prefixes.
|
|
35
|
+
- **[MEDIUM]** Middleware not scoped appropriately to route groups → auth or logging middleware applied globally when only needed for specific paths. Attach middleware at the group level, not globally.
|
|
36
|
+
- **[MEDIUM]** No graceful shutdown handling → in-flight requests dropped when the process receives SIGTERM. Implement `srv.Shutdown(ctx)` on SIGTERM/SIGINT signals.
|
|
37
|
+
- **[LOW]** Single router file containing all route definitions → file grows unwieldy in large applications. Split route registration into per-domain files and register them in the main router setup.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Code Quality
|
|
42
|
+
- **[HIGH]** Missing `binding:"required"` tags on struct fields → optional fields treated as present when absent, leading to zero-value data passing validation silently. Tag all required fields explicitly.
|
|
43
|
+
- **[MEDIUM]** Not using `c.Error()` for error accumulation during request processing → multiple errors not collected, only the last one surfaced. Use `c.Error(err)` and a centralized error handler middleware.
|
|
44
|
+
- **[MEDIUM]** Handler returning `nil` error for all code paths → callers cannot differentiate success from business-logic errors. Return meaningful typed errors and let the error handler map them to HTTP status codes.
|
|
45
|
+
- **[HIGH]** `c.Abort()` not called after `c.JSON()` in error path → handler chain continues executing after error response is sent. Always call `c.Abort()` when sending an early response in middleware.
|
|
46
|
+
- **[MEDIUM]** Missing API versioning strategy → breaking changes break existing clients without warning. Use route groups with version prefixes (`/api/v1`) and document deprecation timelines.
|
|
47
|
+
- **[LOW]** Not using Gin's custom validator tags via `validator.RegisterValidation` → complex validation rules duplicated across handlers. Register custom validators once and reference them via struct tags.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Common Bugs & Pitfalls
|
|
52
|
+
- **[MEDIUM]** Confusing `c.ShouldBindJSON` with `c.BindJSON` → `c.BindJSON` writes a 400 response automatically on error, preventing custom error handling. Prefer `c.ShouldBindJSON` and handle errors explicitly.
|
|
53
|
+
- **[CRITICAL]** Handler goroutine using `c *gin.Context` after the request ends → Gin reuses context objects, causing data races and panics. Copy needed values before launching goroutines; never pass `c` directly.
|
|
54
|
+
- **[MEDIUM]** `gin.Recovery()` swallowing panics silently in production without custom handler → panics logged at error level but client gets a generic 500 with no alerting. Replace with a custom recovery middleware that triggers alerting.
|
|
55
|
+
- **[LOW]** Route params and paths being case-sensitive with trailing slash issues → clients get unexpected 404s due to URL casing or missing slash. Configure `RedirectTrailingSlash` and document case sensitivity.
|
|
56
|
+
- **[HIGH]** Not validating `Content-Type` header before binding → unexpected content type causes a 400 error that is hard to debug. Check content-type early and return a clear error message.
|
|
57
|
+
- **[MEDIUM]** Ignoring errors from `c.JSON()` or `c.String()` → write failures go undetected. Log write errors or use a response wrapper that captures write errors.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# GitHub Actions Stack Rules
|
|
2
|
+
|
|
3
|
+
Detection signals: `.github/workflows/*.yml`, `.github/workflows/*.yaml`, `on:` trigger, `jobs:`, `steps:`, `uses:`, `runs-on:`, `actions/checkout`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Security
|
|
8
|
+
|
|
9
|
+
- **[CRITICAL]** User-controlled data interpolated directly in a `run:` step via expressions like `github.event.issue.title` passed as shell arguments → script injection allows an attacker to execute arbitrary commands with the runner's permissions. Always pass untrusted input via an env var and reference as `$VAR` in shell, never inline the expression.
|
|
10
|
+
- **[CRITICAL]** `pull_request_target` trigger checking out and running code from the PR branch → this event runs with write permissions and access to secrets; a malicious PR can exfiltrate the `GITHUB_TOKEN` or deploy credentials. Never checkout the PR ref in `pull_request_target` without strict branch restrictions and required approvals.
|
|
11
|
+
- **[CRITICAL]** Secrets echoed or logged in run steps → GitHub masks known secret values but transformed or encoded forms may still leak. Never echo, log, or interpolate secrets into shell output; pass them only as environment variables to commands that need them.
|
|
12
|
+
- **[HIGH]** Actions pinned by mutable tag (e.g. `uses: actions/checkout@v4`) rather than a full commit SHA → the tag can be moved or deleted, enabling a supply-chain attack that substitutes malicious code. Pin to full SHA with a tag comment: `uses: actions/checkout@11bd71901... # v4`.
|
|
13
|
+
- **[HIGH]** `permissions: write-all` or omitting the `permissions` key entirely (defaults to write on some repos) → the `GITHUB_TOKEN` is over-privileged, increasing the blast radius of any compromised step. Always declare minimal permissions per job.
|
|
14
|
+
- **[HIGH]** Self-hosted runner on shared infrastructure with no job isolation between runs → one workflow can read another job's secrets, artifacts, or working directory state. Use ephemeral self-hosted runners or GitHub-hosted runners for sensitive jobs.
|
|
15
|
+
- **[HIGH]** Workflow triggered on `pull_request` with write permissions and no approval requirement for fork PRs → fork PR can trigger a privileged workflow and leak secrets. Use environment protection rules with required reviewers for any job that accesses secrets.
|
|
16
|
+
- **[MEDIUM]** Third-party action from an unverified publisher without SHA pinning → the action could be compromised at any future point without warning. Fork the action into your own org, or pin to a specific commit SHA and audit the source.
|
|
17
|
+
- **[MEDIUM]** Secrets stored in repo-level env blocks visible in verbose runner logs → even masked secrets may appear in transformed form. Use step-level env blocks and minimize secret scope to the step that needs it.
|
|
18
|
+
- **[MEDIUM]** `GITHUB_TOKEN` used beyond its intended repository scope without explicit permission grant → scoping errors cause unexpected access or unexpected failures. Declare permissions explicitly; use fine-grained PATs for cross-repository operations.
|
|
19
|
+
- **[LOW]** Workflow files in public repositories not reviewed by a security-aware maintainer → any maintainer can introduce a step that exfiltrates secrets. Require CODEOWNERS review for all changes to `.github/workflows/`.
|
|
20
|
+
- **[LOW]** `continue-on-error: true` on security-sensitive steps such as secret rotation or audit submission → failure is silently ignored, leaving the system in an insecure state. Only use this on genuinely optional steps.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Performance
|
|
25
|
+
|
|
26
|
+
- **[CRITICAL]** No dependency caching (`actions/cache` or setup action built-in cache) for package managers → npm/pip/maven/gradle install runs from scratch on every job, wasting 1-5 minutes. Cache with a key based on the lockfile hash using hashFiles.
|
|
27
|
+
- **[HIGH]** All steps in a single monolithic job with no parallelism → serial bottleneck; the job is as slow as the sum of all steps. Split into parallel jobs using the `needs:` dependency graph to run independent work concurrently.
|
|
28
|
+
- **[HIGH]** Uploading and downloading artifacts in every job when only specific jobs need them → unnecessary I/O and artifact storage costs. Upload once in the producing job; download only in jobs that explicitly need it.
|
|
29
|
+
- **[HIGH]** Matrix strategy not used for multi-platform or multi-version testing → sequential test runs instead of parallel. Use `strategy: matrix: { os: [...], node: [...] }` to test all combinations concurrently.
|
|
30
|
+
- **[MEDIUM]** Uploading large unused artifacts (full build directories, node_modules) → wastes storage quota and slows down the workflow summary. Filter artifacts to only the files needed by downstream jobs or for debugging.
|
|
31
|
+
- **[MEDIUM]** Missing `timeout-minutes` on jobs → a hung job (deadlocked process, waiting for user input) runs until the 6-hour GitHub default limit, burning paid minutes. Set an explicit timeout appropriate for each job.
|
|
32
|
+
- **[MEDIUM]** No concurrency cancellation for PR branch workflows → every push to a PR branch queues a new run while old runs are still active, wasting minutes. Add a concurrency group with cancel-in-progress: true for pull_request triggers.
|
|
33
|
+
- **[MEDIUM]** Running the full test suite on every push to every branch without path filtering → a docs-only change triggers a full 10-minute test run. Use `on: push: paths:` or `paths-ignore:` filters to skip irrelevant runs.
|
|
34
|
+
- **[LOW]** Tool installation repeated in every job because the runner environment is not cached → installing Node.js, Python, or other runtimes adds 30-60 seconds per job. Use setup actions (`actions/setup-node`) with their built-in caching options.
|
|
35
|
+
- **[LOW]** Not using composite actions or reusable workflows for repeated step sequences → the same 5-step build setup copy-pasted across 8 workflows drifts over time. Extract to a composite action or reusable workflow called via `uses:`.
|
|
36
|
+
- **[LOW]** Not gating expensive steps on PR draft status or fork conditions → expensive deployments and integration tests run on every commit including work-in-progress. Check `github.event.pull_request.draft` before expensive steps.
|
|
37
|
+
- **[LOW]** Not using `fetch-depth: 1` for jobs that do not need git history → full clone adds seconds on large repos. Add `fetch-depth: 1` to the checkout step for pure build/test jobs.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Architecture
|
|
42
|
+
|
|
43
|
+
- **[HIGH]** All deployment and CI logic in a single monolithic workflow file → no reusability; every project duplicates the same steps. Extract shared logic to reusable workflows (`workflow_call`) or composite actions and call them from individual workflow files.
|
|
44
|
+
- **[HIGH]** Workflow triggered on push to main with no branch protection rules → direct pushes bypass PR review and immediately trigger production deployment. Enforce branch protection: require PR, status checks, and at least one review before merge.
|
|
45
|
+
- **[HIGH]** No environment protection rules on production deployment jobs → any branch or actor can trigger a production deploy. Use GitHub Environments with required reviewers and deployment wait timers for production.
|
|
46
|
+
- **[HIGH]** Repository-level secrets used across all workflows regardless of need → any workflow can read any repo secret, increasing blast radius of a compromised workflow. Use environment-scoped secrets that are only available to jobs targeting that environment.
|
|
47
|
+
- **[MEDIUM]** Environment URLs, account IDs, or regions hardcoded in workflow YAML → changing environments requires searching and editing all workflow files. Use GitHub Environments, the `vars` context, or repository variables for environment-specific values.
|
|
48
|
+
- **[MEDIUM]** No concurrency group on deployment workflows → parallel deployments to the same environment create race conditions and partial rollouts. Add a concurrency group per environment and cancel-in-progress or queue-based strategy.
|
|
49
|
+
- **[MEDIUM]** Reusable workflow not versioned with a release tag → callers get breaking changes automatically when the reusable workflow is updated. Tag reusable workflows with semver releases and have callers pin to a tag.
|
|
50
|
+
- **[MEDIUM]** Complex job dependency graph (needs:) not documented → multi-job DAGs are impossible to understand without a visual aid. Add a Mermaid diagram or ASCII art of the workflow DAG to the README or workflow file header.
|
|
51
|
+
- **[LOW]** No branch naming convention enforced on wildcard triggers → wildcard branch patterns in triggers match unintended branches. Document and enforce a branch naming convention (`feature/*`, `fix/*`) and use it in trigger patterns.
|
|
52
|
+
- **[LOW]** `workflow_dispatch` inputs not validated before use → integer or enum inputs arrive as strings; invalid values cause obscure errors in later steps. Validate all inputs in the first step and fail fast with a clear error message.
|
|
53
|
+
- **[LOW]** No staging environment between CI and production → code goes directly from CI green to production without a pre-production validation step. Add a staging environment job with a smoke test gate before the production deployment job.
|
|
54
|
+
- **[LOW]** Secrets shared between staging and production environments → a staging breach exposes production credentials. Use separate secret sets per environment; rotate independently.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Code Quality
|
|
59
|
+
|
|
60
|
+
- **[HIGH]** Deprecated `set-output` command: `echo "::set-output name=foo::bar"` → command was removed; workflows using it silently fail or produce warnings. Replace with the environment file approach: `echo "foo=bar" >> 'GITHUB_OUTPUT var'`.
|
|
61
|
+
- **[HIGH]** Deprecated `set-env` command: `echo "::set-env name=VAR::val"` → command was disabled due to security vulnerabilities. Replace with: `echo "VAR=val" >> 'GITHUB_ENV var'`.
|
|
62
|
+
- **[HIGH]** Deprecated `add-path` command: `echo "::add-path::..."` → command was disabled. Replace with: `echo "/my/path" >> 'GITHUB_PATH var'`.
|
|
63
|
+
- **[HIGH]** `continue-on-error: true` on critical steps (build, test, security scan, deploy) → the job shows green even when a critical step fails, hiding real failures. Only use `continue-on-error` for genuinely optional steps; always check step outcome.
|
|
64
|
+
- **[MEDIUM]** Long inline shell scripts in `run:` blocks → inline scripts are untestable, unlintable, and hard to review. Extract scripts to files in the repository (`.github/scripts/`), test them locally, and call them from the workflow.
|
|
65
|
+
- **[MEDIUM]** Missing `defaults.run.shell` at workflow or job level → shell behavior differs across ubuntu, windows, and macos runners. Be explicit: set `defaults: run: shell: bash` to ensure consistent behavior.
|
|
66
|
+
- **[MEDIUM]** Hardcoded runner labels using specific OS versions (`ubuntu-20.04`) → end-of-life runners cause silent workflow failures when GitHub removes them. Use `ubuntu-latest` or document the pinned version and set a calendar reminder to update.
|
|
67
|
+
- **[MEDIUM]** Not using `fromJSON()` for complex expressions involving JSON manipulation → string operations on JSON in expression context are fragile and hard to debug. Use `fromJSON(steps.id.outputs.value)` to parse JSON outputs properly.
|
|
68
|
+
- **[MEDIUM]** YAML anchors not used for repeated step configurations (env vars, options) → the same environment variable block copy-pasted across 12 steps drifts when values change. Use YAML anchors and aliases to define once and reference many times.
|
|
69
|
+
- **[LOW]** Missing `if: always()` on cleanup or notification steps → these steps are skipped when a previous step fails, leaving cleanup undone and stakeholders uninformed. Add `if: always()` to steps that must run regardless of prior step outcome.
|
|
70
|
+
- **[LOW]** Workflow files not linted with `actionlint` or a similar tool → YAML syntax errors, unknown context references, and deprecated commands are only caught at runtime. Add `rhysd/actionlint` to a pre-commit hook or a dedicated lint workflow.
|
|
71
|
+
- **[LOW]** No comments explaining non-obvious workflow logic or permission grants → future maintainers cannot understand why a permission is needed or why a step exists. Add inline comments for all non-obvious decisions.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Go — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `*.go` files, `go.mod`, `package main`, `func main()`, `goroutine`, `chan`, `go vet`, `golangci-lint`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
|
|
10
|
+
- **[CRITICAL]** SQL query with `fmt.Sprintf` / string concatenation of user input → SQL injection. Use `db.Query("SELECT ... WHERE id = ?", userInput)`.
|
|
11
|
+
- **[CRITICAL]** `os/exec.Command` with user input as string to shell → command injection. Use argument list form.
|
|
12
|
+
- **[HIGH]** `html/template` replaced with `text/template` for HTML rendering → XSS, `text/template` doesn't escape.
|
|
13
|
+
- **[HIGH]** Sensitive data in error messages returned to client → info disclosure.
|
|
14
|
+
- **[HIGH]** `math/rand` for security-sensitive values (tokens, IDs) → predictable. Use `crypto/rand`.
|
|
15
|
+
- **[HIGH]** `filepath.Join` not used for user-controlled paths → path traversal via `../`.
|
|
16
|
+
- **[HIGH]** `http.ListenAndServe` without TLS in production → plaintext traffic.
|
|
17
|
+
- **[HIGH]** Goroutine spawned to handle request without context cancellation → goroutine leak on client disconnect.
|
|
18
|
+
- **[HIGH]** CORS wildcard with credentials in HTTP handler → credential leakage to any origin.
|
|
19
|
+
- **[MEDIUM]** Secrets loaded with `os.Getenv()` without validation for empty string → app runs with empty secret.
|
|
20
|
+
- **[MEDIUM]** Race condition on shared map without `sync.Mutex` or `sync.RWMutex`.
|
|
21
|
+
- **[LOW]** `regexp.MustCompile` with user input at runtime → panic on invalid regex.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Performance
|
|
26
|
+
|
|
27
|
+
- **[HIGH]** Goroutine leak — goroutine started but never signaled to stop (no `ctx.Done()`, no WaitGroup) → memory grows indefinitely.
|
|
28
|
+
- **[HIGH]** Mutex held during I/O → blocks all goroutines waiting for lock.
|
|
29
|
+
- **[HIGH]** Unbuffered channel for high-frequency events → sender blocks on every send.
|
|
30
|
+
- **[HIGH]** `append` in tight loop without pre-allocated capacity → many reallocations. Use `make([]T, 0, knownSize)`.
|
|
31
|
+
- **[HIGH]** `fmt.Sprintf` in hot path for string building → use `strings.Builder`.
|
|
32
|
+
- **[HIGH]** Missing context timeout/deadline on HTTP client calls → requests hang indefinitely.
|
|
33
|
+
- **[HIGH]** `sync.Mutex` protecting large struct when `sync.RWMutex` allows parallel reads.
|
|
34
|
+
- **[MEDIUM]** Pointer to small struct unnecessarily → passing small structs by value is cheaper.
|
|
35
|
+
- **[MEDIUM]** `defer` inside loop → defers execute at function end, not loop end → resource exhaustion.
|
|
36
|
+
- **[MEDIUM]** Goroutine per request without worker pool → goroutine explosion under load.
|
|
37
|
+
- **[MEDIUM]** JSON marshaling/unmarshaling in hot path without pooling encoder/decoder.
|
|
38
|
+
- **[LOW]** `interface{}` / `any` in hot path → boxing/unboxing overhead.
|
|
39
|
+
- **[LOW]** Not using `sync.Pool` for frequently allocated/freed objects.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Architecture
|
|
44
|
+
|
|
45
|
+
- **[HIGH]** Error ignored with `_` on operations that can fail → silent failures.
|
|
46
|
+
- **[HIGH]** Panic used for expected error conditions → use error returns. Panic only for programmer errors.
|
|
47
|
+
- **[HIGH]** Global mutable state (`var globalDB *sql.DB` mutated after init) → race conditions.
|
|
48
|
+
- **[HIGH]** `init()` functions doing side effects (DB init, file I/O) → hard to test, unpredictable order.
|
|
49
|
+
- **[HIGH]** Context not propagated through function call chain → cancellation doesn't work.
|
|
50
|
+
- **[MEDIUM]** Interface defined by implementer instead of consumer → breaks dependency inversion.
|
|
51
|
+
- **[MEDIUM]** Package names too generic (`util`, `common`, `helper`) → hard to discover.
|
|
52
|
+
- **[MEDIUM]** Struct embedding for code reuse when composition/interfaces cleaner → hidden method promotion.
|
|
53
|
+
- **[MEDIUM]** Not using `errors.Is()` / `errors.As()` for error inspection → string comparison brittle.
|
|
54
|
+
- **[MEDIUM]** Not using sentinel errors or custom error types → callers can't distinguish error categories.
|
|
55
|
+
- **[LOW]** Exported type without methods returning interface → unnecessary coupling.
|
|
56
|
+
- **[LOW]** Not using `go generate` for repetitive boilerplate.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Code Quality
|
|
61
|
+
|
|
62
|
+
- **[HIGH]** Error not checked: `result, _ := someFunc()` when error indicates real failure.
|
|
63
|
+
- **[HIGH]** `defer file.Close()` after error check omitted → resource leak if `Open()` fails.
|
|
64
|
+
- **[HIGH]** Goroutine closure capturing loop variable → all goroutines use last value. Shadow: `v := v`.
|
|
65
|
+
- **[MEDIUM]** Named return values with naked `return` in long functions → confusing.
|
|
66
|
+
- **[MEDIUM]** Returning concrete type instead of interface from constructor → couples callers to implementation.
|
|
67
|
+
- **[MEDIUM]** Not using `golangci-lint` / `staticcheck` → issues not caught.
|
|
68
|
+
- **[MEDIUM]** `go vet` not run in CI → common mistakes missed.
|
|
69
|
+
- **[MEDIUM]** Test files not using `_test` package for black-box testing → testing internal state.
|
|
70
|
+
- **[LOW]** Missing `golint` compliance (exported types without comments).
|
|
71
|
+
- **[LOW]** Not using table-driven tests → duplicated test setup.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Common Bugs & Pitfalls
|
|
76
|
+
|
|
77
|
+
- **[HIGH]** Loop variable captured by goroutine: `go func() { use(v) }()` in range → all use last value (fixed in Go 1.22).
|
|
78
|
+
- **[HIGH]** Map/slice concurrent read+write without mutex → data race, undefined behavior.
|
|
79
|
+
- **[HIGH]** `time.Sleep` for synchronization → use channels or `sync.WaitGroup`.
|
|
80
|
+
- **[HIGH]** `nil` interface vs nil concrete pointer — `interface{}` wrapping nil pointer is not `== nil`.
|
|
81
|
+
- **[HIGH]** `http.Response.Body` not closed after reading → connection leak.
|
|
82
|
+
- **[HIGH]** Goroutine panics not recovered → crashes entire program.
|
|
83
|
+
- **[MEDIUM]** `json.Unmarshal` ignoring error → silently retains zero values on malformed JSON.
|
|
84
|
+
- **[MEDIUM]** Integer conversion between `int32` and `int64` losing data on 32-bit platforms.
|
|
85
|
+
- **[MEDIUM]** `select` with default case in timing-sensitive code → busy loop.
|
|
86
|
+
- **[MEDIUM]** `context.WithCancel` defer cancel not called → context leak.
|
|
87
|
+
- **[LOW]** `make(chan T)` vs `make(chan T, 1)` — unbuffered vs buffered behavior difference not understood.
|
|
88
|
+
- **[LOW]** `strings.Contains` used where `strings.HasPrefix`/`HasSuffix` is more appropriate.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Godot — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `*.gd` GDScript files, `*.tscn` scenes, `extends Node`, `func _ready()`, `func _process()`, `export var`, `@export`, `Godot`, `project.godot`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
- **[HIGH]** `OS.execute()` or `OS.shell_open()` called with user-controlled arguments → command injection on the host OS; never pass untrusted input to OS execution APIs.
|
|
10
|
+
- **[HIGH]** HTTP requests made to user-provided URLs without validation → SSRF and malicious content fetching; validate URLs against an allowlist before any network request.
|
|
11
|
+
- **[HIGH]** Save game files loaded with `JSON.parse()` or `ResourceLoader.load()` without schema validation → crashes or exploits from malformed data; validate all fields and types after deserialization.
|
|
12
|
+
- **[MEDIUM]** `get_node()` called with a `NodePath` derived from user input → accessing arbitrary nodes in the scene tree; never construct node paths from untrusted data.
|
|
13
|
+
- **[MEDIUM]** Autoload singletons storing authentication tokens or private game state accessible from any script → overly broad attack surface; restrict sensitive data access to dedicated, narrowly scoped systems.
|
|
14
|
+
- **[LOW]** GDScript source files not encrypted in exported project (`Export > Resources > Script export mode`) → readable with PCK extraction tools; use bytecode-only export and PCK encryption for commercial titles.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Performance
|
|
19
|
+
- **[HIGH]** Heavy computation (pathfinding, collision queries, string building) in `_process(delta)` → called every frame at full refresh rate; move to `_physics_process`, signals, timers, or background threads via `Thread`.
|
|
20
|
+
- **[HIGH]** `get_node()` or `$NodePath` shorthand called every frame instead of cached in `_ready()` → repeated scene-tree traversal; cache all node references as member variables in `_ready()`.
|
|
21
|
+
- **[HIGH]** Nodes instantiated and freed every frame (bullets, particles, effects) without pooling → GC pressure and frame spikes; implement a node pool using `queue_free()` + `visible = false` recycling.
|
|
22
|
+
- **[HIGH]** Large images imported without enabling appropriate compression (VRAM-compressed formats like S3TC, ETC2, BPTC) → excessive VRAM usage; configure import settings per texture type.
|
|
23
|
+
- **[MEDIUM]** `await get_tree().process_frame` used in tight loops without frame budget awareness → logic spread across many deferred frames; batch work with explicit budgeting.
|
|
24
|
+
- **[MEDIUM]** Signals not disconnected when nodes are freed → potential callbacks on freed objects; always disconnect signals in `_exit_tree()` or use `connect(..., CONNECT_ONE_SHOT)`.
|
|
25
|
+
- **[LOW]** `VisibleOnScreenNotifier2D`/`VisibleOnScreenNotifier3D` not used for off-screen objects that run `_process` → wasted CPU on invisible nodes; disable processing when off-screen.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Architecture
|
|
30
|
+
- **[HIGH]** Scene tree traversal using `get_parent().get_parent().get_child(2)` chains → brittle structural coupling; use signals, groups, or exported node references for cross-node communication.
|
|
31
|
+
- **[HIGH]** Autoloads used as a dumping ground for all shared state and logic → implicit global coupling that makes scenes non-portable; limit autoloads to truly global services and use scene-local composition otherwise.
|
|
32
|
+
- **[MEDIUM]** Node-to-node communication done by calling methods directly on sibling or parent nodes instead of emitting signals → tight coupling; emit signals upward and call methods downward.
|
|
33
|
+
- **[MEDIUM]** Game logic embedded in UI nodes (`Button`, `Label` subclasses with game rules) → untestable in isolation; separate game logic into non-UI Node or RefCounted classes.
|
|
34
|
+
- **[MEDIUM]** Data not modeled as `Resource` subclasses → ad-hoc dictionaries passed everywhere; use typed `Resource` subclasses with `@export` fields for all structured data.
|
|
35
|
+
- **[LOW]** Scenes not decomposed into reusable sub-scenes → monolithic tscn files that are hard to maintain; extract repeating structures into their own scenes.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Code Quality
|
|
40
|
+
- **[HIGH]** `@export` variables declared without type hints (`@export var speed` instead of `@export var speed: float`) → no editor type validation or static analysis; always type all exported variables.
|
|
41
|
+
- **[HIGH]** Return value of `get_node()` used without null check on nodes that may be absent → "Invalid get index" runtime error; null-check or use `has_node()` before access.
|
|
42
|
+
- **[MEDIUM]** GDScript functions and variables declared without type hints → static analyzer and Godot's type checker cannot catch errors; add type annotations to all declarations.
|
|
43
|
+
- **[MEDIUM]** `match` statement without a default `_:` branch for enum-like values → unhandled states silently fall through; always include a default branch that asserts or logs.
|
|
44
|
+
- **[MEDIUM]** Signals defined but never emitted, or emitted but never connected → dead code or broken communication channels; audit all signal definitions for use.
|
|
45
|
+
- **[LOW]** Node names containing spaces (e.g., `"My Node"`) → `$My Node` shorthand breaks; use PascalCase or snake_case node names consistently.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Common Bugs & Pitfalls
|
|
50
|
+
- **[HIGH]** Holding a reference to a node after `queue_free()` and accessing it on the next frame → "Object was deleted" crash; use `is_instance_valid(node)` before accessing any potentially freed node.
|
|
51
|
+
- **[HIGH]** Signal connected multiple times (e.g., inside `_process` or on scene re-entry) without checking for existing connections → callback invoked multiple times per event; use `is_connected()` guard or `CONNECT_ONE_SHOT`.
|
|
52
|
+
- **[HIGH]** `_ready()` called before parent node's `_ready()` has completed in child-first order → child accesses parent state that is not yet initialized; use `call_deferred()` or `await owner.ready` for deferred initialization.
|
|
53
|
+
- **[MEDIUM]** `CharacterBody2D`/`CharacterBody3D` velocity not reset to zero before applying new movement each frame → accumulated velocity causing unintended drift; reset or reassign `velocity` explicitly each physics frame.
|
|
54
|
+
- **[MEDIUM]** `@export` variable default value changed in script after the scene has been saved → saved scene retains old serialized value, script default ignored; reset the property in the scene inspector after changing script defaults.
|
|
55
|
+
- **[MEDIUM]** `Timer` node not stopped and freed when the owning node is removed → timer fires callback on a freed object; always call `timer.stop()` in `_exit_tree()`.
|
|
56
|
+
- **[LOW]** Integer division used unintentionally in GDScript 4 (`5 / 2 == 2`) → use `float(5) / 2` or `5.0 / 2.0` for fractional results.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# GraphQL — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `*.graphql` / `*.gql` files, `gql\`\``, `GraphQLSchema`, `typeDefs`, `resolvers`, `ApolloServer`, `graphql-yoga`, `pothos`, `nexus`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
|
|
10
|
+
- **[CRITICAL]** Missing field-level authorization in resolver → any authenticated user queries any field/mutation. Check permissions per-resolver, not just at route level.
|
|
11
|
+
- **[CRITICAL]** Introspection enabled in production → full schema exposed to attackers. Set `introspection: false` in production.
|
|
12
|
+
- **[HIGH]** Missing query depth limit → nested queries cause exponential DB calls (DoS). Use `graphql-depth-limit` (max 7-10 levels).
|
|
13
|
+
- **[HIGH]** Missing query complexity limit → single query requesting thousands of nodes. Use `graphql-query-complexity`.
|
|
14
|
+
- **[HIGH]** User-controlled field names in dynamic resolver → injection or over-fetching of sensitive fields.
|
|
15
|
+
- **[HIGH]** Batch query abuse — 1000 aliases in single query bypassing per-query rate limit. Limit max aliases.
|
|
16
|
+
- **[HIGH]** Missing rate limiting at GraphQL endpoint → high-complexity queries bypass REST-level limits.
|
|
17
|
+
- **[HIGH]** GraphQL errors leaking stack traces → configure custom error formatter to strip internal details.
|
|
18
|
+
- **[MEDIUM]** IDOR in resolver — fetching resource by ID in args without ownership check.
|
|
19
|
+
- **[MEDIUM]** Subscription not authenticated → real-time events delivered to unauthenticated WebSocket.
|
|
20
|
+
- **[LOW]** `directives` not documented or enforced on sensitive fields → ad-hoc security.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Performance
|
|
25
|
+
|
|
26
|
+
- **[CRITICAL]** N+1 in resolver — DB query per parent node's children. Use `DataLoader` for batching + per-request caching.
|
|
27
|
+
- **[HIGH]** Resolver fetching all related data regardless of selection set → over-fetching. Use projection based on `info.fieldNodes`.
|
|
28
|
+
- **[HIGH]** No persisted queries → clients send full query string each request, larger payload, no CDN caching.
|
|
29
|
+
- **[HIGH]** `DataLoader` not scoped per-request → stale data served from previous request's loader cache.
|
|
30
|
+
- **[HIGH]** Subscription sending full object on every update when client only needs changed fields.
|
|
31
|
+
- **[MEDIUM]** Missing `@cacheControl` directives → CDN cannot cache GraphQL responses.
|
|
32
|
+
- **[MEDIUM]** Over-fetching in resolvers — entire DB record loaded for 2-field selection.
|
|
33
|
+
- **[MEDIUM]** `context.dataloaders` not used → DataLoader instances not shared across resolvers in request.
|
|
34
|
+
- **[MEDIUM]** Deeply nested fragment spread causing resolver chain traversal on every request.
|
|
35
|
+
- **[LOW]** Not using `graphql-jit` for hot query compilation.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Architecture
|
|
40
|
+
|
|
41
|
+
- **[HIGH]** Business logic in resolver functions → move to service/domain layer; resolvers orchestrate only.
|
|
42
|
+
- **[HIGH]** Schema-first vs code-first inconsistency in same project → pick one, enforce via lint.
|
|
43
|
+
- **[HIGH]** Mutations not returning affected type → client must do extra query to refresh; return mutated entity.
|
|
44
|
+
- **[HIGH]** Missing input validation on mutation args → invalid data reaches business logic.
|
|
45
|
+
- **[MEDIUM]** Overloaded `Query` type with dozens of top-level fields → use namespaced query types.
|
|
46
|
+
- **[MEDIUM]** Not using schema federation for microservices → monolithic schema becomes bottleneck.
|
|
47
|
+
- **[MEDIUM]** Context not used for shared services (DB, auth, DataLoader) → instantiating per-resolver.
|
|
48
|
+
- **[MEDIUM]** Union/interface types not used for polymorphic data → overloaded nullable fields.
|
|
49
|
+
- **[LOW]** Missing `description` on types/fields → poor schema documentation, bad DX.
|
|
50
|
+
- **[LOW]** Not using code-generation (`graphql-codegen`) for TypeScript types → resolvers typed as `any`.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Code Quality
|
|
55
|
+
|
|
56
|
+
- **[HIGH]** `any` type on resolver `context` or `parent` → no type safety.
|
|
57
|
+
- **[HIGH]** Missing `__resolveType` on union/interface → Apollo can't distinguish members.
|
|
58
|
+
- **[MEDIUM]** Resolver returning `undefined` for nullable field → client gets `null` unexpectedly.
|
|
59
|
+
- **[MEDIUM]** `async` resolver not returning Promise → Apollo silently resolves, async work never awaited.
|
|
60
|
+
- **[MEDIUM]** Mutations not following `input` type convention → inline args instead of typed `input` object.
|
|
61
|
+
- **[MEDIUM]** Error handling inconsistent — some resolvers throw, others return `null` → client can't distinguish.
|
|
62
|
+
- **[LOW]** Not using `graphql-scalars` for common scalars (DateTime, URL, Email) → custom validator reinvented.
|
|
63
|
+
- **[LOW]** Schema not validated with `graphql-inspector` → breaking changes undetected.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Common Bugs & Pitfalls
|
|
68
|
+
|
|
69
|
+
- **[HIGH]** `DataLoader` key type mismatch (string vs number) → batching function receives mixed types, wrong results.
|
|
70
|
+
- **[HIGH]** Subscription not cleaned up on client disconnect → resource leak (DB connection, event listener).
|
|
71
|
+
- **[HIGH]** Resolver error not wrapped in `GraphQLError` → error format inconsistent, stack trace leaked.
|
|
72
|
+
- **[MEDIUM]** `context` mutated inside resolver → shared between parallel field resolvers, race condition.
|
|
73
|
+
- **[MEDIUM]** DataLoader `batchLoadFn` not returning results in same order as keys → wrong data mapped to wrong parents.
|
|
74
|
+
- **[MEDIUM]** `@deprecated` directive added but not enforced in CI → clients continue using deprecated fields.
|
|
75
|
+
- **[LOW]** Union type `__resolveType` missing → Apollo returns null for union field.
|
|
76
|
+
- **[LOW]** `null` vs empty array not distinguished in list fields → client gets wrong "no results" state.
|