redlinegate 0.0.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 +21 -0
- package/README.md +188 -0
- package/commands/redline-init.md +54 -0
- package/commands/redline-verify.md +69 -0
- package/dist/bin/redline.js +605 -0
- package/dist/bin/redline.js.map +1 -0
- package/dist/commands/exempt.js +45 -0
- package/dist/commands/exempt.js.map +1 -0
- package/dist/commands/init.js +615 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/policy.js +25 -0
- package/dist/commands/policy.js.map +1 -0
- package/dist/commands/remove.js +427 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/review.js +72 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/sync.js +42 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/verify.js +478 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/config/redline-json.js +187 -0
- package/dist/config/redline-json.js.map +1 -0
- package/dist/core/errors.js +25 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/git.js +152 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/log.js +22 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/severity.js +16 -0
- package/dist/core/severity.js.map +1 -0
- package/dist/core/version.js +15 -0
- package/dist/core/version.js.map +1 -0
- package/dist/detect/scan.js +79 -0
- package/dist/detect/scan.js.map +1 -0
- package/dist/detect/stack.js +71 -0
- package/dist/detect/stack.js.map +1 -0
- package/dist/enforce/ladder.js +148 -0
- package/dist/enforce/ladder.js.map +1 -0
- package/dist/exempt/parse.js +86 -0
- package/dist/exempt/parse.js.map +1 -0
- package/dist/metrics/options.js +257 -0
- package/dist/metrics/options.js.map +1 -0
- package/dist/metrics/run.js +72 -0
- package/dist/metrics/run.js.map +1 -0
- package/dist/platforms/azure/client.js +53 -0
- package/dist/platforms/azure/client.js.map +1 -0
- package/dist/platforms/azure/index.js +69 -0
- package/dist/platforms/azure/index.js.map +1 -0
- package/dist/platforms/azure/install.js +917 -0
- package/dist/platforms/azure/install.js.map +1 -0
- package/dist/platforms/azure/policy-types.js +70 -0
- package/dist/platforms/azure/policy-types.js.map +1 -0
- package/dist/platforms/azure/verify.js +309 -0
- package/dist/platforms/azure/verify.js.map +1 -0
- package/dist/platforms/detect.js +40 -0
- package/dist/platforms/detect.js.map +1 -0
- package/dist/platforms/github/client.js +49 -0
- package/dist/platforms/github/client.js.map +1 -0
- package/dist/platforms/github/index.js +54 -0
- package/dist/platforms/github/index.js.map +1 -0
- package/dist/platforms/github/install.js +558 -0
- package/dist/platforms/github/install.js.map +1 -0
- package/dist/platforms/github/push.js +102 -0
- package/dist/platforms/github/push.js.map +1 -0
- package/dist/platforms/github/remote.js +36 -0
- package/dist/platforms/github/remote.js.map +1 -0
- package/dist/platforms/github/verify.js +366 -0
- package/dist/platforms/github/verify.js.map +1 -0
- package/dist/platforms/http.js +58 -0
- package/dist/platforms/http.js.map +1 -0
- package/dist/platforms/pull-request-templates.js +157 -0
- package/dist/platforms/pull-request-templates.js.map +1 -0
- package/dist/platforms/remote.js +21 -0
- package/dist/platforms/remote.js.map +1 -0
- package/dist/platforms/resolve.js +69 -0
- package/dist/platforms/resolve.js.map +1 -0
- package/dist/platforms/shape.js +19 -0
- package/dist/platforms/shape.js.map +1 -0
- package/dist/platforms/types.js +24 -0
- package/dist/platforms/types.js.map +1 -0
- package/dist/policy/checks.js +91 -0
- package/dist/policy/checks.js.map +1 -0
- package/dist/policy/diff.js +50 -0
- package/dist/policy/diff.js.map +1 -0
- package/dist/registry/discover.js +74 -0
- package/dist/registry/discover.js.map +1 -0
- package/dist/registry/serialize.js +41 -0
- package/dist/registry/serialize.js.map +1 -0
- package/dist/registry/types.js +2 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/remove/host.js +294 -0
- package/dist/remove/host.js.map +1 -0
- package/dist/render/commands.js +139 -0
- package/dist/render/commands.js.map +1 -0
- package/dist/render/manifest.js +82 -0
- package/dist/render/manifest.js.map +1 -0
- package/dist/render/markers.js +166 -0
- package/dist/render/markers.js.map +1 -0
- package/dist/render/profile.js +23 -0
- package/dist/render/profile.js.map +1 -0
- package/dist/render/standards.js +169 -0
- package/dist/render/standards.js.map +1 -0
- package/dist/render/vendors.js +199 -0
- package/dist/render/vendors.js.map +1 -0
- package/dist/review/engines/api.js +95 -0
- package/dist/review/engines/api.js.map +1 -0
- package/dist/review/engines/embedded.js +20 -0
- package/dist/review/engines/embedded.js.map +1 -0
- package/dist/review/engines/types.js +2 -0
- package/dist/review/engines/types.js.map +1 -0
- package/dist/review/glob.js +29 -0
- package/dist/review/glob.js.map +1 -0
- package/dist/review/prompt.js +45 -0
- package/dist/review/prompt.js.map +1 -0
- package/dist/review/rules.js +25 -0
- package/dist/review/rules.js.map +1 -0
- package/dist/review/schema.js +84 -0
- package/dist/review/schema.js.map +1 -0
- package/dist/review/scope.js +27 -0
- package/dist/review/scope.js.map +1 -0
- package/dist/sarif/map.js +58 -0
- package/dist/sarif/map.js.map +1 -0
- package/dist/sarif/parse.js +88 -0
- package/dist/sarif/parse.js.map +1 -0
- package/dist/sarif/types.js +2 -0
- package/dist/sarif/types.js.map +1 -0
- package/dist/sync/host.js +21 -0
- package/dist/sync/host.js.map +1 -0
- package/dist/sync/plan.js +47 -0
- package/dist/sync/plan.js.map +1 -0
- package/dist/sync/render.js +57 -0
- package/dist/sync/render.js.map +1 -0
- package/dist/sync/run.js +118 -0
- package/dist/sync/run.js.map +1 -0
- package/dist/verify/host.js +52 -0
- package/dist/verify/host.js.map +1 -0
- package/dist/verify/remote.js +146 -0
- package/dist/verify/remote.js.map +1 -0
- package/package.json +52 -0
- package/platforms/azure/gate-template.yml +105 -0
- package/rulesets/redline-org-ruleset.json +46 -0
- package/rulesets/redline-ruleset.json +49 -0
- package/scripts/assign-rule-ids.mjs +129 -0
- package/scripts/build-baseline.mjs +124 -0
- package/scripts/build-correlation.mjs +74 -0
- package/scripts/build-dashboard.mjs +584 -0
- package/scripts/build-digest.mjs +164 -0
- package/scripts/build-inbox.mjs +133 -0
- package/scripts/build-registry.mjs +42 -0
- package/scripts/build-roi.mjs +181 -0
- package/scripts/check-pins.mjs +88 -0
- package/scripts/collect-telemetry.mjs +300 -0
- package/scripts/lib/__tests__/baseline.test.mjs +132 -0
- package/scripts/lib/__tests__/correlate.test.mjs +131 -0
- package/scripts/lib/__tests__/dora.test.mjs +110 -0
- package/scripts/lib/__tests__/exemptions.test.mjs +85 -0
- package/scripts/lib/__tests__/metrics-scanner.test.mjs +65 -0
- package/scripts/lib/__tests__/sarif.test.mjs +125 -0
- package/scripts/lib/__tests__/spend.test.mjs +64 -0
- package/scripts/lib/baseline.mjs +156 -0
- package/scripts/lib/correlate.mjs +125 -0
- package/scripts/lib/dora.mjs +133 -0
- package/scripts/lib/exemptions.mjs +79 -0
- package/scripts/lib/metrics.mjs +172 -0
- package/scripts/lib/rules.mjs +107 -0
- package/scripts/lib/sarif.mjs +108 -0
- package/scripts/lib/spend.mjs +69 -0
- package/scripts/measure-context.mjs +101 -0
- package/scripts/render-self.mjs +18 -0
- package/scripts/score-seeds.mjs +294 -0
- package/scripts/validate.mjs +394 -0
- package/standards/core.md +124 -0
- package/standards/manifest.json +214 -0
- package/standards/stacks/csharp.md +29 -0
- package/standards/stacks/go.md +30 -0
- package/standards/stacks/java.md +30 -0
- package/standards/stacks/javascript.md +42 -0
- package/standards/stacks/kotlin.md +27 -0
- package/standards/stacks/microservices.md +37 -0
- package/standards/stacks/nodejs.md +34 -0
- package/standards/stacks/python.md +29 -0
- package/standards/stacks/react-native.md +29 -0
- package/standards/stacks/react.md +46 -0
- package/standards/stacks/swift.md +26 -0
- package/standards/stacks/terraform.md +27 -0
- package/templates/CODEOWNERS +29 -0
- package/templates/azure/pull_request_template.md +72 -0
- package/templates/github/pull_request_template.md +72 -0
- package/templates/redline.yml +35 -0
- package/templates/repo-context.md +64 -0
- package/workflows/dashboard.yml +119 -0
- package/workflows/inbox.yml +97 -0
- package/workflows/redline-collect.yml +61 -0
- package/workflows/redline-gate.yml +301 -0
- package/workflows/redline-sync.yml +79 -0
- package/workflows/seed-canary.yml +231 -0
- package/workflows/verify-onboarding.yml +115 -0
- package/workflows/weekly-digest.yml +78 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Single source of truth for Redline. scripts/render.mjs turns this into vendor-specific artifacts. Never hand-edit generated output.",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"core": {
|
|
5
|
+
"title": "Redline Core Engineering Standards",
|
|
6
|
+
"source": "standards/core.md"
|
|
7
|
+
},
|
|
8
|
+
"stacks": {
|
|
9
|
+
"javascript": {
|
|
10
|
+
"title": "JavaScript",
|
|
11
|
+
"source": "standards/stacks/javascript.md",
|
|
12
|
+
"globs": [
|
|
13
|
+
"**/*.js",
|
|
14
|
+
"**/*.jsx",
|
|
15
|
+
"**/*.mjs",
|
|
16
|
+
"**/*.cjs"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"react": {
|
|
20
|
+
"title": "React (web)",
|
|
21
|
+
"source": "standards/stacks/react.md",
|
|
22
|
+
"globs": [
|
|
23
|
+
"**/*.tsx",
|
|
24
|
+
"**/*.jsx",
|
|
25
|
+
"src/**/*.ts",
|
|
26
|
+
"app/**/*.ts",
|
|
27
|
+
"packages/**/src/**/*.ts",
|
|
28
|
+
"apps/**/src/**/*.ts"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"react-native": {
|
|
32
|
+
"title": "React Native",
|
|
33
|
+
"source": "standards/stacks/react-native.md",
|
|
34
|
+
"extends": [
|
|
35
|
+
"react"
|
|
36
|
+
],
|
|
37
|
+
"globs": [
|
|
38
|
+
"**/*.tsx",
|
|
39
|
+
"**/*.native.ts",
|
|
40
|
+
"app/**/*.ts",
|
|
41
|
+
"src/screens/**",
|
|
42
|
+
"src/components/**",
|
|
43
|
+
"packages/**/src/**/*.tsx",
|
|
44
|
+
"apps/**/src/**/*.tsx"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"nodejs": {
|
|
48
|
+
"title": "Node.js (NestJS)",
|
|
49
|
+
"source": "standards/stacks/nodejs.md",
|
|
50
|
+
"globs": [
|
|
51
|
+
"src/**/*.ts",
|
|
52
|
+
"apps/**/src/**/*.ts",
|
|
53
|
+
"libs/**/src/**/*.ts",
|
|
54
|
+
"packages/**/src/**/*.ts"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"microservices": {
|
|
58
|
+
"title": "Microservice cross-cutting",
|
|
59
|
+
"source": "standards/stacks/microservices.md",
|
|
60
|
+
"globs": [
|
|
61
|
+
"**/*.java",
|
|
62
|
+
"**/*.go",
|
|
63
|
+
"**/*.py",
|
|
64
|
+
"**/*.cs",
|
|
65
|
+
"src/**/*.ts",
|
|
66
|
+
"cmd/**",
|
|
67
|
+
"internal/**",
|
|
68
|
+
"services/**"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"java": {
|
|
72
|
+
"title": "Java (Spring Boot)",
|
|
73
|
+
"source": "standards/stacks/java.md",
|
|
74
|
+
"globs": [
|
|
75
|
+
"**/*.java"
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"go": {
|
|
79
|
+
"title": "Go",
|
|
80
|
+
"source": "standards/stacks/go.md",
|
|
81
|
+
"globs": [
|
|
82
|
+
"**/*.go"
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"python": {
|
|
86
|
+
"title": "Python",
|
|
87
|
+
"source": "standards/stacks/python.md",
|
|
88
|
+
"globs": [
|
|
89
|
+
"**/*.py"
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
"csharp": {
|
|
93
|
+
"title": "C# (.NET)",
|
|
94
|
+
"source": "standards/stacks/csharp.md",
|
|
95
|
+
"globs": [
|
|
96
|
+
"**/*.cs"
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
"kotlin": {
|
|
100
|
+
"title": "Kotlin",
|
|
101
|
+
"source": "standards/stacks/kotlin.md",
|
|
102
|
+
"globs": [
|
|
103
|
+
"**/*.kt",
|
|
104
|
+
"**/*.kts"
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"swift": {
|
|
108
|
+
"title": "Swift (iOS)",
|
|
109
|
+
"source": "standards/stacks/swift.md",
|
|
110
|
+
"globs": [
|
|
111
|
+
"**/*.swift"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"terraform": {
|
|
115
|
+
"title": "Terraform / HCL",
|
|
116
|
+
"source": "standards/stacks/terraform.md",
|
|
117
|
+
"globs": [
|
|
118
|
+
"**/*.tf",
|
|
119
|
+
"**/*.tfvars",
|
|
120
|
+
"**/*.hcl"
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"$profileComment": "A repo installs exactly one profile. Profiles are the disambiguation mechanism: glob negation is not portable across vendors, so we never install two rule sets that would contradict each other in the same repo.",
|
|
125
|
+
"profiles": {
|
|
126
|
+
"tooling": [
|
|
127
|
+
"javascript"
|
|
128
|
+
],
|
|
129
|
+
"web": [
|
|
130
|
+
"javascript",
|
|
131
|
+
"react"
|
|
132
|
+
],
|
|
133
|
+
"mobile-rn": [
|
|
134
|
+
"javascript",
|
|
135
|
+
"react",
|
|
136
|
+
"react-native"
|
|
137
|
+
],
|
|
138
|
+
"mobile-android": [
|
|
139
|
+
"kotlin"
|
|
140
|
+
],
|
|
141
|
+
"mobile-ios": [
|
|
142
|
+
"swift"
|
|
143
|
+
],
|
|
144
|
+
"service-java": [
|
|
145
|
+
"microservices",
|
|
146
|
+
"java"
|
|
147
|
+
],
|
|
148
|
+
"service-go": [
|
|
149
|
+
"microservices",
|
|
150
|
+
"go"
|
|
151
|
+
],
|
|
152
|
+
"service-node": [
|
|
153
|
+
"javascript",
|
|
154
|
+
"microservices",
|
|
155
|
+
"nodejs"
|
|
156
|
+
],
|
|
157
|
+
"service-python": [
|
|
158
|
+
"microservices",
|
|
159
|
+
"python"
|
|
160
|
+
],
|
|
161
|
+
"service-dotnet": [
|
|
162
|
+
"microservices",
|
|
163
|
+
"csharp"
|
|
164
|
+
],
|
|
165
|
+
"infra": [
|
|
166
|
+
"terraform"
|
|
167
|
+
],
|
|
168
|
+
"fullstack-node": [
|
|
169
|
+
"javascript",
|
|
170
|
+
"react",
|
|
171
|
+
"microservices",
|
|
172
|
+
"nodejs"
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
"$aliasComment": "Legacy profile names accepted by sync-targets.txt for backwards compatibility.",
|
|
176
|
+
"profileAliases": {
|
|
177
|
+
"mobile": "mobile-rn",
|
|
178
|
+
"java": "service-java",
|
|
179
|
+
"go": "service-go",
|
|
180
|
+
"node": "service-node",
|
|
181
|
+
"python": "service-python",
|
|
182
|
+
"dotnet": "service-dotnet"
|
|
183
|
+
},
|
|
184
|
+
"vendors": {
|
|
185
|
+
"copilot": {
|
|
186
|
+
"title": "GitHub Copilot code review",
|
|
187
|
+
"enabled": true
|
|
188
|
+
},
|
|
189
|
+
"agents": {
|
|
190
|
+
"title": "AGENTS.md (OpenAI Codex, Copilot coding agent, Jules, Cursor agent, Devin)",
|
|
191
|
+
"enabled": true
|
|
192
|
+
},
|
|
193
|
+
"claude": {
|
|
194
|
+
"title": "Claude Code / Claude in GitHub",
|
|
195
|
+
"enabled": true
|
|
196
|
+
},
|
|
197
|
+
"cursor": {
|
|
198
|
+
"title": "Cursor rules",
|
|
199
|
+
"enabled": false
|
|
200
|
+
},
|
|
201
|
+
"skills": {
|
|
202
|
+
"$comment": "Ships off. It renders the same rules as the claude vendor in a different shape, and a repository selecting both loads every stack twice. Select it INSTEAD of claude where per-stack loading is wanted: redline init --vendors skills,copilot,agents.",
|
|
203
|
+
"title": "Claude skills (per-stack, loaded on demand)",
|
|
204
|
+
"enabled": false
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"$deterministicComment": "Rules a checker decides without a model. The classification lives HERE and not in the markdown deliberately: standards/*.md is what a reviewer reads, and removing a rule from it because a checker also covers it would narrow what the model considers. Every rule is classified by construction \u2014 listed here means deterministic, absent means judgement. Ids are permanent and are never rewritten by this list. scripts/validate.mjs fails the build if an id here has no implementation in cli/policy/checks.ts, which is the failure mode where a rule is silently enforced by nobody.",
|
|
208
|
+
"deterministic": [
|
|
209
|
+
"core/untracked-todo",
|
|
210
|
+
"core/type-checker-suppression",
|
|
211
|
+
"javascript/var-in-new-code",
|
|
212
|
+
"javascript/unsafe-numeric-coercion"
|
|
213
|
+
]
|
|
214
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# C# (.NET) Review Rules
|
|
2
|
+
|
|
3
|
+
## BLOCKER — request changes
|
|
4
|
+
|
|
5
|
+
- `csharp/async-void` — **`async void`** anywhere except event handlers — exceptions escape the caller and crash the process; return `Task`.
|
|
6
|
+
- `csharp/sync-over-async` — **Sync-over-async**: `.Result`, `.Wait()`, `.GetAwaiter().GetResult()` on async calls — deadlock and thread-pool starvation; async all the way.
|
|
7
|
+
- `csharp/httpclient-per-request` — **`HttpClient` instantiated per request** — socket exhaustion; use `IHttpClientFactory`.
|
|
8
|
+
- `csharp/captive-dependencies` — **Captive dependencies**: scoped services (DbContext) injected into singletons — cross-request state bleed; inject `IServiceScopeFactory` or restructure.
|
|
9
|
+
- `csharp/sql-string-concatenation` — **String-concatenated SQL with external input** — parameterized queries / EF LINQ only.
|
|
10
|
+
- `csharp/swallowed-exceptions` — **Swallowed exceptions**: `catch { }` or catch-log-continue treating failure as success.
|
|
11
|
+
- `csharp/missing-cancellation-token` — **Missing `CancellationToken` propagation** on new async endpoints and outbound calls.
|
|
12
|
+
|
|
13
|
+
## HIGH
|
|
14
|
+
|
|
15
|
+
- `csharp/ef-n-plus-one` — EF Core N+1: navigation properties accessed in loops — `.Include`/projection; and unbounded queries without paging.
|
|
16
|
+
- `csharp/multiple-enumeration` — `IEnumerable` multiple enumeration of LINQ-to-entities queries — materialize once with `ToListAsync`.
|
|
17
|
+
- `csharp/datetime-now` — DateTime.Now in new code — `DateTimeOffset.UtcNow` / `TimeProvider`.
|
|
18
|
+
- `csharp/entity-in-controller-response` — Entities returned from controllers — DTOs/records only; entities leak lazy-nav and internal fields.
|
|
19
|
+
- `csharp/missing-model-validation` — Missing model validation at the boundary (`[ApiController]` + data annotations or FluentValidation).
|
|
20
|
+
- `csharp/lock-over-async` — `lock` over async operations (can't await inside lock) — `SemaphoreSlim`.
|
|
21
|
+
- `csharp/fire-and-forget-task-run` — Fire-and-forget `Task.Run` without exception observation — use hosted services / background queues.
|
|
22
|
+
- `csharp/exception-detail-in-response` — Exception details in API responses — ProblemDetails mapping.
|
|
23
|
+
|
|
24
|
+
## SUGGESTION
|
|
25
|
+
|
|
26
|
+
- `csharp/records-for-dtos` — Records for immutable DTOs; `required`/init-only properties over constructors with many args.
|
|
27
|
+
- `csharp/nullable-reference-types` — Nullable reference types enabled and respected in new projects — no `!` dammit-operator without comment.
|
|
28
|
+
- `csharp/structured-logging` — `ILogger<T>` structured logging with message templates, not string interpolation.
|
|
29
|
+
- `csharp/api-style-consistency` — Minimal APIs vs controllers — follow whichever the service already uses.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Go Review Rules
|
|
2
|
+
|
|
3
|
+
## BLOCKER — request changes
|
|
4
|
+
|
|
5
|
+
- `go/ignored-errors` — **Ignored errors.** `_ = err`, unchecked returns, or `err` shadowed and never handled. Every error is handled, returned wrapped (`fmt.Errorf("...: %w", err)`), or explicitly justified.
|
|
6
|
+
- `go/goroutine-leaks` — **Goroutine leaks.** Goroutine started without a way to stop: missing context cancellation, blocked forever on channel send/receive, no `WaitGroup`/errgroup ownership.
|
|
7
|
+
- `go/missing-ctx-propagation` — **Missing `ctx` propagation.** Outbound calls (HTTP, DB, gRPC) must take the request's `context.Context`; no `context.Background()` inside request handling.
|
|
8
|
+
- `go/data-races` — **Data races.** Shared map/slice/struct written from multiple goroutines without mutex or channel ownership; loop variable captured by reference in goroutine (pre-1.22 semantics or when version unknown).
|
|
9
|
+
- `go/writing-nil-map` — **Writing to a nil map.**
|
|
10
|
+
- `go/copying-sync-primitive` — **Copying a struct containing `sync.Mutex`/`sync.WaitGroup`** (passing by value, range over slice of them).
|
|
11
|
+
- `go/defer-in-loop` — **`defer` in a loop for per-iteration resources** (files, rows, locks) — defers pile up until function exit; extract loop body into a function.
|
|
12
|
+
- `go/panic-for-expected-failure` — **Panics for expected failures** — panic only for programmer errors; return errors otherwise.
|
|
13
|
+
|
|
14
|
+
## HIGH
|
|
15
|
+
|
|
16
|
+
- `go/missing-client-server-timeout` — `http.Client`/`http.Server` without timeouts (`Timeout`, `ReadTimeout`, `WriteTimeout`) — zero values mean infinite.
|
|
17
|
+
- `go/response-body-not-drained` — Response body not closed, or closed without being drained (breaks connection reuse).
|
|
18
|
+
- `go/errors-is-as` — `errors.Is`/`errors.As` not used where sentinel/typed errors are compared with `==` or type assertion.
|
|
19
|
+
- `go/interface-at-implementation` — Interfaces defined next to the implementation instead of the consumer; interfaces with one implementation and no test need.
|
|
20
|
+
- `go/waitgroup-add-inside-goroutine` — `sync.WaitGroup.Add` inside the goroutine instead of before starting it.
|
|
21
|
+
- `go/unbuffered-channel-blocks-producer` — Unbuffered channel used where the producer must never block, or buffer sizes chosen arbitrarily without comment.
|
|
22
|
+
- `go/time-after-in-loop` — `time.After` in a loop (leaks timers until fire) — use `time.NewTimer`/`Ticker` with Stop.
|
|
23
|
+
- `go/package-level-mutable-state` — Package-level mutable state in new code.
|
|
24
|
+
|
|
25
|
+
## SUGGESTION
|
|
26
|
+
|
|
27
|
+
- `go/naked-returns` — Naked returns in functions longer than a few lines.
|
|
28
|
+
- `go/any-over-concrete-type` — `interface{}`/`any` where a concrete type or generic works.
|
|
29
|
+
- `go/error-string-style` — Error strings capitalized or ending with punctuation (Go convention: lowercase, no period).
|
|
30
|
+
- `go/receiver-consistency` — Struct field alignment/pointer-vs-value receiver inconsistency within a type.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Java (Spring Boot) Review Rules
|
|
2
|
+
|
|
3
|
+
## BLOCKER — request changes
|
|
4
|
+
|
|
5
|
+
- `java/entity-in-controller-response` — **JPA entities returned from controllers.** Endpoints return DTOs; entities leak lazy-loading proxies, internal fields, and cause serialization surprises.
|
|
6
|
+
- `java/n-plus-one-queries` — **N+1 queries.** Lazy association accessed in a loop or during serialization — require fetch join, `@EntityGraph`, or a projection.
|
|
7
|
+
- `java/transactional-self-invocation` — **`@Transactional` on private/self-invoked methods** — proxy is bypassed, annotation silently does nothing.
|
|
8
|
+
- `java/broad-catch` — **Catching `Exception`/`Throwable` broadly and continuing** — catch specific types; rethrow or fail the operation.
|
|
9
|
+
- `java/field-injection` — **Field injection (`@Autowired` on fields)** in new code — constructor injection only; field injection breaks testability and hides dependencies.
|
|
10
|
+
- `java/mutable-singleton-state` — **Mutable shared state in singleton beans** without synchronization — services/components are singletons; instance fields must be immutable or thread-safe.
|
|
11
|
+
- `java/blocking-in-reactive` — **Blocking calls inside reactive pipelines** (WebFlux: `block()`, JDBC, `RestTemplate` inside `Mono`/`Flux` chains).
|
|
12
|
+
- `java/jpql-string-concatenation` — **String-concatenated JPQL/SQL with external input** — parameterized queries / criteria API only.
|
|
13
|
+
|
|
14
|
+
## HIGH
|
|
15
|
+
|
|
16
|
+
- `java/optional-misuse` — `Optional` misuse: `Optional.get()` without presence check, `Optional` as field or method parameter.
|
|
17
|
+
- `java/entity-equals-hashcode` — `equals`/`hashCode` on JPA entities using generated IDs incorrectly (breaks in sets before persist) — or missing entirely on value objects.
|
|
18
|
+
- `java/missing-bean-validation` — Missing `@Valid` + Bean Validation on request DTOs at controller boundary.
|
|
19
|
+
- `java/transaction-scope-too-wide` — Transaction scope too wide: external HTTP calls or message publishing inside `@Transactional` — holds connections, couples commit to remote latency.
|
|
20
|
+
- `java/async-without-executor` — `@Async`/`CompletableFuture` work without dedicated executor — default pool starvation.
|
|
21
|
+
- `java/exception-detail-in-response` — Exception details (stack traces, SQL) returned in API error responses — map to problem-detail responses.
|
|
22
|
+
- `java/legacy-date-api` — New Date/`Calendar`/`SimpleDateFormat` in new code — `java.time` only; `SimpleDateFormat` is not thread-safe.
|
|
23
|
+
- `java/stream-side-effects` — Streams with side effects (`forEach` mutating external collections) — collect instead.
|
|
24
|
+
|
|
25
|
+
## SUGGESTION
|
|
26
|
+
|
|
27
|
+
- `java/lombok-data-on-entity` — Lombok `@Data` on entities (equals/hashCode/toString pitfalls) — prefer `@Getter` + explicit methods, or records for DTOs.
|
|
28
|
+
- `java/records-for-dtos` — Records for immutable DTOs where Java version allows.
|
|
29
|
+
- `java/var-usage` — `var` for obviously-typed locals; explicit types where inference hurts readability.
|
|
30
|
+
- `java/magic-values` — Magic numbers/strings for business values — extract named constants.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# JavaScript Review Rules
|
|
2
|
+
|
|
3
|
+
Applies to untyped and loosely-typed JS (`.js`, `.jsx`, `.mjs`, `.cjs`), including build
|
|
4
|
+
scripts, config files, serverless handlers, and legacy app code. TypeScript rules in the
|
|
5
|
+
core standard apply wherever the file is typed.
|
|
6
|
+
|
|
7
|
+
## BLOCKER — request changes
|
|
8
|
+
|
|
9
|
+
- `javascript/prototype-pollution` — **Prototype pollution sinks.** Recursive merge/`Object.assign` over external input
|
|
10
|
+
without rejecting `__proto__`, `constructor`, `prototype` keys.
|
|
11
|
+
- `javascript/dynamic-code-execution` — **`eval`, `new Function`, `setTimeout("string")`** on anything derived from external input.
|
|
12
|
+
- `javascript/floating-promises` — **Floating promises.** Every promise is `await`ed, returned, or `.catch`-handled. An
|
|
13
|
+
unhandled rejection terminates the process on modern Node.
|
|
14
|
+
- `javascript/loose-equality-coercion` — **`==` against `null`/`undefined`/`0`/`''` where coercion changes the branch** — use
|
|
15
|
+
`===`, or `== null` only as a deliberate nullish check with a comment.
|
|
16
|
+
- `javascript/shared-module-state-mutation` — **Mutating a shared module-scope object/array** used across requests or components.
|
|
17
|
+
- `javascript/unvalidated-boundary-input` — **Missing input validation at the boundary** — `JSON.parse` of external payloads without
|
|
18
|
+
try/catch and a size limit; `req.body` fields consumed without a schema check.
|
|
19
|
+
- `javascript/scattered-env-access` — **Secrets read ad hoc from `process.env` scattered across modules** — one validated
|
|
20
|
+
config module, fail fast at startup.
|
|
21
|
+
- `javascript/shell-injection` — **`child_process.exec` with an interpolated string** — use `execFile`/`spawn` with argv.
|
|
22
|
+
|
|
23
|
+
## HIGH
|
|
24
|
+
|
|
25
|
+
- `javascript/var-in-new-code` — `var` in new code — `const` by default, `let` when reassigned.
|
|
26
|
+
- `javascript/for-in-over-arrays` — `for...in` over arrays, or without `hasOwnProperty` filtering over objects.
|
|
27
|
+
- `javascript/unchecked-index-access` — Array index access assumed defined (`arr[0].x`) without a length or nullish check.
|
|
28
|
+
- `javascript/unsafe-numeric-coercion` — `parseInt` without radix; `Number()`/`+` coercion of user input without `Number.isFinite`.
|
|
29
|
+
- `javascript/async-callback-ignored-promise` — `async` callbacks passed to APIs that ignore the returned promise (`array.forEach`,
|
|
30
|
+
most event emitters) — rejections vanish.
|
|
31
|
+
- `javascript/hand-rolled-deep-clone` — Deep-equality or deep-clone hand-rolled instead of `structuredClone`/a maintained util.
|
|
32
|
+
- `javascript/unsafe-date-arithmetic` — Date arithmetic on `Date` objects across DST boundaries or with implicit local timezone.
|
|
33
|
+
- `javascript/try-catch-whole-function` — `try`/`catch` around a whole function body instead of the failing boundary call.
|
|
34
|
+
- `javascript/redos` — Regexes built from external input (ReDoS), or catastrophic backtracking patterns
|
|
35
|
+
(nested quantifiers over user-controlled length).
|
|
36
|
+
|
|
37
|
+
## SUGGESTION
|
|
38
|
+
|
|
39
|
+
- `javascript/prefer-optional-chaining` — Optional chaining and nullish coalescing over `&&`/`||` ladders.
|
|
40
|
+
- `javascript/prefer-named-exports` — Named exports over default exports for tree-shaking and refactor safety.
|
|
41
|
+
- `javascript/jsdoc-on-exports` — JSDoc types on exported functions in files that will not be converted to TS soon.
|
|
42
|
+
- `javascript/array-at-negative-index` — `Array.prototype.at(-1)` over `arr[arr.length - 1]`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Kotlin Review Rules (Android + backend)
|
|
2
|
+
|
|
3
|
+
## BLOCKER — request changes
|
|
4
|
+
|
|
5
|
+
- `kotlin/force-unwrap` — **`!!` non-null assertions** in production paths — restructure with `?.`, `?:`, `requireNotNull` with a message, or fix the type.
|
|
6
|
+
- `kotlin/globalscope` — **`GlobalScope.launch`** — coroutines must live in a structured scope (`viewModelScope`, `lifecycleScope`, injected `CoroutineScope`); GlobalScope leaks work past the owner's lifetime.
|
|
7
|
+
- `kotlin/blocking-in-coroutine` — **Blocking inside coroutines**: `Thread.sleep`, blocking IO, or `runBlocking` on `Dispatchers.Main` / inside `suspend` functions — use `delay`, suspending clients, or `withContext(Dispatchers.IO)`.
|
|
8
|
+
- `kotlin/context-leak` — **Android `Context` held by singletons / companion objects** — activity context leaks the whole view tree; application context only, and only when unavoidable.
|
|
9
|
+
- `kotlin/broad-catch-cancellation` — **Catching `Exception`/`Throwable` broadly and continuing** — also swallows `CancellationException`, breaking coroutine cancellation; catch specific types and rethrow `CancellationException`.
|
|
10
|
+
- `kotlin/unconfined-shared-state` — **Mutable shared state across coroutines without confinement** — use `Mutex`, `StateFlow`, or single-thread confinement.
|
|
11
|
+
- `kotlin/lateinit-misuse` — **`lateinit` used to dodge nullability logic** — acceptable only for framework-injected fields (DI, Android lifecycle).
|
|
12
|
+
|
|
13
|
+
## HIGH
|
|
14
|
+
|
|
15
|
+
- `kotlin/public-mutable-state` — Public `MutableStateFlow` / `MutableLiveData` — expose read-only `StateFlow`/`LiveData`, mutate privately.
|
|
16
|
+
- `kotlin/lifecycle-unaware-collection` — Flow collection in UI without `repeatOnLifecycle` / `collectAsStateWithLifecycle` — collects while backgrounded.
|
|
17
|
+
- `kotlin/hardcoded-dispatcher` — Hardcoded `Dispatchers.*` in classes — inject dispatchers for testability.
|
|
18
|
+
- `kotlin/data-class-var` — `data class` with `var` properties — copy/equality semantics break; use `val` + `copy`.
|
|
19
|
+
- `kotlin/companion-mutable-state` — Companion-object mutable state (global by another name).
|
|
20
|
+
- `kotlin/runcatching-silent-default` — `runCatching` chains that map failure to a default silently.
|
|
21
|
+
- `kotlin/force-unwrap-in-tests` — `!!` in tests hiding what the test actually asserts — use `assertNotNull` semantics.
|
|
22
|
+
|
|
23
|
+
## SUGGESTION
|
|
24
|
+
|
|
25
|
+
- `kotlin/prefer-sealed-state` — Sealed interfaces/classes for UI and result states instead of nullable-field combinations.
|
|
26
|
+
- `kotlin/value-class-identifiers` — `value class` for domain identifiers (MSISDN, AccountId) instead of raw `String`.
|
|
27
|
+
- `kotlin/deep-scope-function-nesting` — Nested `let`/`apply`/`run` chains more than two deep — extract a function.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Microservice Cross-Cutting Review Rules
|
|
2
|
+
|
|
3
|
+
**Scope:** backend service code in any language. Applies in addition to the
|
|
4
|
+
language-specific rules, never instead of them.
|
|
5
|
+
|
|
6
|
+
Apply to all backend services regardless of language, in addition to the language-specific rules.
|
|
7
|
+
|
|
8
|
+
## BLOCKER — request changes
|
|
9
|
+
|
|
10
|
+
- `microservices/missing-timeout` — **Outbound calls without timeouts.** Every HTTP/gRPC/DB/queue call must have an explicit timeout; no infinite defaults.
|
|
11
|
+
- `microservices/unversioned-breaking-change` — **Breaking API changes without versioning.** Removing/renaming fields, changing types, or tightening validation on a published API contract requires a version bump or an approved deprecation path. Additive changes only on existing versions.
|
|
12
|
+
- `microservices/pii-in-telemetry` — **PII in logs, traces, or metrics labels** — MSISDN, email, account IDs, tokens. Log opaque IDs only.
|
|
13
|
+
- `microservices/secrets-in-config` — **Secrets in code, Dockerfiles, compose files, Helm values, or CI YAML** — vault/secret-manager references only.
|
|
14
|
+
- `microservices/non-idempotent-consumer` — **Non-idempotent consumers/handlers for at-least-once delivery** (Kafka, SQS, retries on POST). Duplicate delivery must not double-apply.
|
|
15
|
+
- `microservices/swallowed-errors` — **Swallowed errors** — catch-and-ignore, error logged then treated as success, or error branch returning 200.
|
|
16
|
+
|
|
17
|
+
## HIGH
|
|
18
|
+
|
|
19
|
+
- `microservices/retry-without-backoff` — Retries without backoff + jitter, or retrying non-idempotent operations.
|
|
20
|
+
- `microservices/missing-circuit-breaker` — Missing circuit breaker / bulkhead on dependencies known to degrade (peer services, third parties).
|
|
21
|
+
- `microservices/unauthenticated-endpoint` — New endpoint without authn/authz middleware — even "internal" services; do not trust the network.
|
|
22
|
+
- `microservices/dual-write-no-outbox` — DB work and message publish in one logical step without outbox or equivalent — dual-write inconsistency.
|
|
23
|
+
- `microservices/unbounded-work` — Unbounded work from external input: no pagination limits, unbounded batch sizes, unbounded payload accepted.
|
|
24
|
+
- `microservices/readiness-liveness-conflated` — Missing health/readiness distinction: readiness must fail when dependencies are down; liveness must not.
|
|
25
|
+
- `microservices/missing-trace-propagation` — New external call without propagating trace context / correlation ID.
|
|
26
|
+
- `microservices/incompatible-migration` — Migration not backward-compatible with the currently deployed version (rename/drop column while old pods still run).
|
|
27
|
+
|
|
28
|
+
## SUGGESTION
|
|
29
|
+
|
|
30
|
+
- `microservices/undocumented-config` — New config value without a sane default and documentation in the service README/values file.
|
|
31
|
+
- `microservices/missing-metrics` — Metrics for new critical paths (rate, errors, duration) missing.
|
|
32
|
+
- `microservices/missing-dlq-handling` — Consumer lag / DLQ handling absent on new consumers.
|
|
33
|
+
|
|
34
|
+
## What NOT to flag
|
|
35
|
+
|
|
36
|
+
- Existing contract shapes the PR does not modify.
|
|
37
|
+
- Infrastructure choices (broker, DB engine) already established in the service.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Node.js (NestJS) Service Review Rules
|
|
2
|
+
|
|
3
|
+
**Scope:** server-side TypeScript in a NestJS service. Do not apply these rules to
|
|
4
|
+
`.tsx` files, test specs, or front-end code; if you see React in the file, this rule
|
|
5
|
+
set does not apply.
|
|
6
|
+
|
|
7
|
+
## BLOCKER — request changes
|
|
8
|
+
|
|
9
|
+
- `nodejs/floating-promises` — **Floating promises.** Every promise is `await`ed, returned, or explicitly handled with `.catch` — an unhandled rejection crashes the process on modern Node.
|
|
10
|
+
- `nodejs/blocking-event-loop` — **Blocking the event loop.** Sync APIs in request paths (`fs.*Sync`, `child_process.execSync`, `crypto.pbkdf2Sync`), or CPU-heavy loops/JSON parsing of large payloads without worker threads.
|
|
11
|
+
- `nodejs/missing-dto-validation` — **Missing validation at the boundary.** Request DTOs must use `class-validator` decorators with a global `ValidationPipe` (`whitelist: true`); no raw `@Body() body: any`.
|
|
12
|
+
- `nodejs/request-state-on-singleton` — **Request-scoped data in singleton providers.** NestJS providers are singletons by default — storing per-request state on `this` bleeds data across users. Use `REQUEST` scope deliberately or AsyncLocalStorage.
|
|
13
|
+
- `nodejs/await-in-loop` — **`await` in a loop for independent operations** — require `Promise.all` / `Promise.allSettled` with a bounded batch size.
|
|
14
|
+
- `nodejs/config-outside-configservice` — **Secrets/config read via `process.env` scattered through code** — access only through the typed `ConfigService`/config module, validated at startup (fail fast on missing).
|
|
15
|
+
- `nodejs/error-detail-swallowed` — **Errors caught and converted to generic 500 with details swallowed** — use exception filters; preserve cause in logs (structured), never in the response body.
|
|
16
|
+
|
|
17
|
+
## HIGH
|
|
18
|
+
|
|
19
|
+
- `nodejs/logic-in-controller` — Business logic in controllers — controllers translate HTTP only; logic lives in providers/services.
|
|
20
|
+
- `nodejs/forwardref-circular-dependency` — Circular module dependencies "solved" with `forwardRef` where extraction of a shared module is possible.
|
|
21
|
+
- `nodejs/raw-http-client` — Raw `axios`/`fetch` calls without timeout, and without going through the service's shared HTTP client (interceptors carry auth, tracing, retries).
|
|
22
|
+
- `nodejs/missing-guard` — New endpoint missing guard coverage (authn/authz) — verify global guard applies or explicit guard present.
|
|
23
|
+
- `nodejs/orm-n-plus-one` — TypeORM/Prisma queries inside loops (N+1) — batch with `In()`/`findMany`.
|
|
24
|
+
- `nodejs/transaction-spans-remote-call` — Transactions spanning external HTTP calls or message publishes.
|
|
25
|
+
- `nodejs/json-parse-external-input` — `JSON.parse` on external input without size limits or try/catch at the boundary.
|
|
26
|
+
- `nodejs/missing-listener-teardown` — Event emitter / interval / stream listeners registered without teardown in `onModuleDestroy`.
|
|
27
|
+
- `nodejs/console-logging` — Logging via `console.*` instead of the injected structured logger.
|
|
28
|
+
|
|
29
|
+
## SUGGESTION
|
|
30
|
+
|
|
31
|
+
- `nodejs/dto-input-output-shared` — DTO classes reused for both input and output — split; output shape is a contract.
|
|
32
|
+
- `nodejs/lazy-import-heavy-modules` — Heavy modules imported at top level but used in one rarely-hit path — lazy import.
|
|
33
|
+
- `nodejs/magic-values` — Magic status codes/strings — use `HttpStatus` and shared enums.
|
|
34
|
+
- `nodejs/hot-loop-allocation` — Repeated `Date.now()` / `new Intl.*` in hot loops — hoist.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Python Review Rules
|
|
2
|
+
|
|
3
|
+
## BLOCKER — request changes
|
|
4
|
+
|
|
5
|
+
- `python/mutable-default-argument` — **Mutable default arguments** (`def f(items=[])`) — shared across calls; use `None` + assign inside.
|
|
6
|
+
- `python/bare-except` — **Bare `except:` or `except Exception: pass`** — catch specific exceptions; never silence. Bare `except` also eats `KeyboardInterrupt`/`SystemExit`.
|
|
7
|
+
- `python/sql-string-interpolation` — **SQL built with f-strings/`%`/`.format` from external input** — parameterized queries only.
|
|
8
|
+
- `python/subprocess-shell-injection` — **`subprocess` with `shell=True`** on anything derived from external input; prefer list-form argv always.
|
|
9
|
+
- `python/dynamic-code-execution` — **`eval`/`exec`/`pickle.loads` on external data.**
|
|
10
|
+
- `python/blocking-in-async` — **Blocking calls inside `async def`**: `requests`, `time.sleep`, sync DB drivers — use `httpx`/`aiohttp`, `asyncio.sleep`, async drivers, or `run_in_executor`.
|
|
11
|
+
- `python/secrets-not-centralised` — **Secrets hardcoded or read ad hoc** — central config module, validated at startup.
|
|
12
|
+
|
|
13
|
+
## HIGH
|
|
14
|
+
|
|
15
|
+
- `python/missing-type-hints` — Missing type hints on new public functions — new code is typed; assume mypy/pyright strict.
|
|
16
|
+
- `python/missing-context-manager` — Files/connections/locks without context managers (`with`) — leaks on exception paths.
|
|
17
|
+
- `python/module-level-mutable-state` — Module-level mutable state used as implicit singleton across requests (Lambda warm starts share it — intentional caching must be explicit and documented).
|
|
18
|
+
- `python/broad-except-in-loop` — Broad `except Exception` that logs and continues in loops — one poisoned item must not silently vanish; dead-letter or re-raise policy required.
|
|
19
|
+
- `python/naive-datetime` — Datetime handling: naive `datetime.now()` in new code — `datetime.now(timezone.utc)` and timezone-aware throughout.
|
|
20
|
+
- `python/assert-for-validation` — `assert` for runtime validation — stripped under `-O`; raise proper exceptions.
|
|
21
|
+
- `python/boto3-client-per-call` — Boto3 clients created per call inside handlers/loops — create at module scope (Lambda) or inject.
|
|
22
|
+
- `python/http-call-without-timeout` — Unbounded `requests`/`httpx` calls without timeout.
|
|
23
|
+
|
|
24
|
+
## SUGGESTION
|
|
25
|
+
|
|
26
|
+
- `python/prefer-typed-models` — Dataclasses/pydantic models over dict-shaped data crossing function boundaries.
|
|
27
|
+
- `python/prefer-pathlib` — `pathlib` over `os.path` string juggling in new code.
|
|
28
|
+
- `python/prefer-f-strings` — f-strings over `%`/`.format`.
|
|
29
|
+
- `python/prefer-comprehensions` — Comprehensions over `map`/`filter` with lambdas; but no nested comprehensions beyond two levels.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# React Native Review Rules
|
|
2
|
+
|
|
3
|
+
All React rules apply. Additionally:
|
|
4
|
+
|
|
5
|
+
## BLOCKER — request changes
|
|
6
|
+
|
|
7
|
+
- `react-native/unvirtualised-list` — **Large lists without virtualization.** `ScrollView` + `.map()` over dynamic data, or `FlatList` where FlashList is the project standard — require FlashList (or FlatList minimum) for lists that can exceed ~20 items.
|
|
8
|
+
- `react-native/unmemoised-list-item` — **Non-memoized list item components** — every list item must be `React.memo` with stable callback references (no inline arrow closures over changing values passed to items).
|
|
9
|
+
- `react-native/animating-layout-properties` — **Animating layout properties** (`width`, `height`, `top`, `left`, `margin`) — animations must use `transform` and `opacity` only; layout properties run on the JS thread and jank.
|
|
10
|
+
- `react-native/bare-strings-outside-text` — **Bare strings outside `<Text>`** — crashes on Android.
|
|
11
|
+
- `react-native/falsy-and-rendering` — **Falsy `&&` rendering** (`count && <X/>`) — renders `0`/`NaN` as text and crashes on Android; require ternary.
|
|
12
|
+
- `react-native/blocking-gesture-handler` — **Blocking the JS thread in gesture/scroll handlers** — heavy work in `onScroll` without Reanimated worklets or throttling.
|
|
13
|
+
|
|
14
|
+
## HIGH
|
|
15
|
+
|
|
16
|
+
- `react-native/inline-props-in-list-items` — Inline style objects / inline functions in list item props — hoist or memoize; breaks item memoization.
|
|
17
|
+
- `react-native/remote-image-component` — `Image` from react-native for remote images where `expo-image` is available — no caching, no placeholder handling.
|
|
18
|
+
- `react-native/prefer-pressable` — `TouchableOpacity` in new code — use `Pressable`.
|
|
19
|
+
- `react-native/js-navigator` — JS-based navigators where native stack (`@react-navigation/native-stack`) is available.
|
|
20
|
+
- `react-native/missing-safe-area` — Missing safe-area handling in full-screen ScrollViews.
|
|
21
|
+
- `react-native/measure-over-onlayout` — `measure()` calls where `onLayout` suffices.
|
|
22
|
+
- `react-native/native-dep-in-shared-package` — Native dependencies added to shared monorepo packages instead of the app package.
|
|
23
|
+
- `react-native/reanimated-shared-value-misuse` — Reanimated shared values read during render or mutated outside worklets/handlers.
|
|
24
|
+
|
|
25
|
+
## SUGGESTION
|
|
26
|
+
|
|
27
|
+
- `react-native/intl-in-render` — `Intl.NumberFormat` / `Intl.DateTimeFormat` created inside render or loops — hoist to module scope.
|
|
28
|
+
- `react-native/missing-getitemtype` — Heterogeneous lists without `getItemType` (FlashList).
|
|
29
|
+
- `react-native/derived-animation-in-render` — Derived animation values computed in render instead of `useDerivedValue`.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# React Review Rules
|
|
2
|
+
|
|
3
|
+
**Scope:** web React. Where a file is also matched by the React Native rules, the
|
|
4
|
+
React Native rules extend these — they do not replace them. Do not flag web-only
|
|
5
|
+
concerns (DOM, `next/dynamic`, bundle splitting) on React Native files.
|
|
6
|
+
|
|
7
|
+
## BLOCKER — request changes
|
|
8
|
+
|
|
9
|
+
- `react/effect-derived-state` — **`useEffect` for derived state.** State computable from existing props/state must be computed during render, never synced via effect.
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
// WRONG
|
|
13
|
+
useEffect(() => { setFullName(first + ' ' + last); }, [first, last]);
|
|
14
|
+
// RIGHT
|
|
15
|
+
const fullName = first + ' ' + last;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- `react/effect-for-event-logic` — **`useEffect` for event logic.** Notifications, analytics, navigation triggered by a user action belong in the event handler, not an effect watching state.
|
|
19
|
+
- `react/missing-effect-cleanup` — **Missing `useEffect` cleanup** for subscriptions, timers, listeners, and in-flight requests (AbortController).
|
|
20
|
+
- `react/direct-state-mutation` — **Direct state mutation** (`arr.push`, `obj.x =`, `.splice`) followed by `setState` — silent update failure.
|
|
21
|
+
- `react/conditional-hook-calls` — **Conditional hook calls** — hooks inside `if`, loops, or early returns.
|
|
22
|
+
- `react/key-is-index` — **`key={index}`** on lists that reorder, insert, or delete.
|
|
23
|
+
- `react/server-data-in-local-state` — **Server data copied into local state.** With TanStack Query / SWR, the query result IS the source of truth — never `useEffect(() => setLocal(data))`.
|
|
24
|
+
- `react/nested-component-definition` — **Component defined inside another component** — remounts every render, loses state.
|
|
25
|
+
- `react/useformstatus-placement` — **`useFormStatus` in the same component that renders the `<form>`** — always returns `pending: false`; must be in a child.
|
|
26
|
+
- `react/promise-in-render` — **Promise created during render passed to `use()`** — infinite loop; promise must come from props, state, or cache.
|
|
27
|
+
- `react/exhaustive-deps-disabled` — **`eslint-disable react-hooks/exhaustive-deps`** — hides stale-closure bugs; require refactor instead.
|
|
28
|
+
|
|
29
|
+
## HIGH
|
|
30
|
+
|
|
31
|
+
- `react/incomplete-dependency-array` — Incomplete dependency arrays (stale closures).
|
|
32
|
+
- `react/sequential-awaits` — Sequential `await`s for independent operations — require `Promise.all`.
|
|
33
|
+
- `react/barrel-file-imports` — Barrel-file imports (`import { X } from '@/components'`) — require direct imports; barrels bloat bundles and cause circular deps.
|
|
34
|
+
- `react/heavy-component-static-import` — Heavy components (charts, editors, modals) imported statically — require `next/dynamic` / `React.lazy`.
|
|
35
|
+
- `react/uncontrolled-to-controlled` — `useState(undefined)` for controlled inputs — uncontrolled→controlled warning; use `''`.
|
|
36
|
+
- `react/missing-error-boundary` — Missing Error Boundary around subtrees that fetch or can throw.
|
|
37
|
+
- `react/falsy-and-rendering` — `&&` conditional rendering with a possibly-falsy non-boolean left side (`count && <X/>` renders `0`) — require ternary or explicit boolean.
|
|
38
|
+
|
|
39
|
+
## SUGGESTION
|
|
40
|
+
|
|
41
|
+
- `react/trivial-memoisation` — `useMemo`/`useCallback` wrapping trivial primitives — remove.
|
|
42
|
+
- `react/missing-lazy-initialiser` — Expensive `useState` initializer without lazy init — pass a function.
|
|
43
|
+
- `react/starttransition-for-non-urgent` — `startTransition` for non-urgent updates driving expensive renders.
|
|
44
|
+
- `react/oversized-component` — Component over ~300 lines — suggest split.
|
|
45
|
+
- `react/prop-drilling` — Prop drilling beyond 2–3 levels — suggest composition or context.
|
|
46
|
+
- `react/prefer-ref-over-state` — Interaction state read only inside callbacks — use a ref, not state, to avoid re-renders.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Swift (iOS) Review Rules
|
|
2
|
+
|
|
3
|
+
## BLOCKER — request changes
|
|
4
|
+
|
|
5
|
+
- `swift/force-operations` — **Force operations in production paths**: `!` force-unwrap, `try!`, `as!` — restructure with `guard let`, `if let`, `try?` + handling, or fix the optionality.
|
|
6
|
+
- `swift/retain-cycle` — **Retain cycles**: `self` captured strongly in `@escaping` closures stored by the object (handlers, subscriptions, timers) — require `[weak self]` and early-return pattern.
|
|
7
|
+
- `swift/ui-off-main-actor` — **UI mutation off the main actor** — UIKit/SwiftUI state must be touched on `@MainActor` / main queue; no fire-and-forget background completion touching views.
|
|
8
|
+
- `swift/blocking-main-thread` — **Blocking the main thread**: synchronous network/disk on main, `DispatchQueue.main.sync` from the main queue (deadlock).
|
|
9
|
+
- `swift/uncancelled-task` — **Unstructured `Task {}` in views without cancellation** — tie to `.task {}` modifier or store and cancel; leaked tasks outlive the screen.
|
|
10
|
+
- `swift/sensitive-data-in-userdefaults` — **Sensitive data in `UserDefaults`** — tokens/credentials belong in Keychain.
|
|
11
|
+
|
|
12
|
+
## HIGH
|
|
13
|
+
|
|
14
|
+
- `swift/unconfined-singleton-state` — Singletons with mutable state and no actor/queue confinement — convert to `actor` or confine.
|
|
15
|
+
- `swift/completion-handler-in-new-code` — Completion-handler APIs in new code where async/await is available.
|
|
16
|
+
- `swift/missing-mainactor` — Missing `@MainActor` on ObservableObject/ViewModel classes driving UI.
|
|
17
|
+
- `swift/unremoved-observer` — `NotificationCenter` observers without removal (pre-iOS 9-style APIs) or Combine subscriptions without `cancellables` storage.
|
|
18
|
+
- `swift/oversized-view` — Massive view controllers / SwiftUI views over ~300 lines — extract subviews and view models.
|
|
19
|
+
- `swift/stringly-typed-identifiers` — Stringly-typed identifiers (segues, notification names, userInfo keys) — use enums/constants.
|
|
20
|
+
- `swift/swallowed-decode-failure` — `Codable` decode failures swallowed with `try?` where the failure matters.
|
|
21
|
+
|
|
22
|
+
## SUGGESTION
|
|
23
|
+
|
|
24
|
+
- `swift/prefer-value-types` — Prefer `struct` value types; classes only for identity or reference semantics.
|
|
25
|
+
- `swift/prefer-typed-throws` — `Result` grab-bags where typed `throws` is clearer.
|
|
26
|
+
- `swift/prefer-guard-early-exit` — Prefer `guard` early-exit over nested `if let` pyramids.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Terraform / HCL Review Rules
|
|
2
|
+
|
|
3
|
+
## BLOCKER — request changes
|
|
4
|
+
|
|
5
|
+
- `terraform/secrets-in-config` — **Secrets in `.tf`/`.tfvars`** — passwords, keys, tokens, connection strings. Reference Secrets Manager / SSM / vault data sources; mark variables `sensitive = true`.
|
|
6
|
+
- `terraform/public-exposure` — **Public exposure**: `0.0.0.0/0` ingress on non-public ports, public S3 bucket ACLs/policies, `publicly_accessible = true` on databases — without an explicit justification comment and approval.
|
|
7
|
+
- `terraform/missing-moved-block` — **Resource rename/move without `moved {}` block** — plan shows destroy+create; data loss on stateful resources.
|
|
8
|
+
- `terraform/overly-broad-iam` — **Overly broad IAM**: `Action: "*"`, `Resource: "*"`, or `iam:PassRole` unscoped — least privilege, scoped ARNs.
|
|
9
|
+
- `terraform/prevent-destroy-removed` — **`prevent_destroy` removed** or lifecycle guards deleted on stateful resources (DBs, buckets, tables) without stated intent.
|
|
10
|
+
- `terraform/unpinned-source` — **Provider or module source unpinned** — exact version or bounded constraint (`~>`), never floating latest.
|
|
11
|
+
|
|
12
|
+
## HIGH
|
|
13
|
+
|
|
14
|
+
- `terraform/count-vs-for-each` — `count` on identity-bearing resources where `for_each` is correct — index shifts destroy/recreate siblings.
|
|
15
|
+
- `terraform/hardcoded-env-values` — Cross-environment values hardcoded in modules (account IDs, ARNs, CIDRs) — pass as variables.
|
|
16
|
+
- `terraform/missing-required-tags` — Missing required tags on new resources (owner, cost-centre, environment — per org tagging policy).
|
|
17
|
+
- `terraform/wide-open-egress` — Wide-open egress added without comment.
|
|
18
|
+
- `terraform/ambiguous-data-source` — Data sources fetching by name/tag that may match multiple resources — brittle; use IDs where stable.
|
|
19
|
+
- `terraform/missing-backup-retention` — New stateful resource without backup/retention configuration (RDS retention, S3 versioning, DynamoDB PITR).
|
|
20
|
+
- `terraform/missing-encryption` — Encryption not explicit on new data stores (at-rest KMS, in-transit enforced).
|
|
21
|
+
|
|
22
|
+
## SUGGESTION
|
|
23
|
+
|
|
24
|
+
- `terraform/variable-metadata` — Variables missing `description` and `type`.
|
|
25
|
+
- `terraform/output-metadata` — Outputs missing `description`; sensitive outputs not marked `sensitive`.
|
|
26
|
+
- `terraform/prefer-jsonencode` — Inline JSON policies over `jsonencode()`/data-source policy documents.
|
|
27
|
+
- `terraform/repeated-literal` — Repeated literal in 3+ places — promote to local.
|