@codacy/gate-cli 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,586 @@
1
+ # GATE.md — Patterns Reference
2
+ # Research-backed catalog used by /gate-setup to synthesize project Standards.
3
+ # This is NOT a Standard — it is the reference from which Standards are built.
4
+
5
+ # =============================================================================
6
+ # 1. Quality Dimensions (always 4)
7
+ # =============================================================================
8
+
9
+ quality_dimensions:
10
+ - id: comprehensibility
11
+ description: "Code readable in one context load"
12
+ signals:
13
+ - metric: file_length
14
+ threshold: 300
15
+ unit: lines
16
+ rationale: "AI context windows degrade on large files (>300 lines ~ 3,000 tokens)"
17
+ source: "Stanford 'Lost in the Middle' — >30% accuracy drop for mid-context info"
18
+ - metric: cyclomatic_complexity
19
+ threshold: 15
20
+ unit: per_function
21
+ rationale: "Complexity-aware feedback improves AI Pass@1 by 35.71%"
22
+ source: "Multiple studies on CCN and LLM performance"
23
+ - metric: function_length
24
+ threshold: 50
25
+ unit: lines
26
+ rationale: "Short functions are easier for agents to modify safely"
27
+ - metric: naming_quality
28
+ tool: ai
29
+ rationale: "Descriptive names: 34.2% AI match rate vs 16.6% obfuscated (r=0.945)"
30
+ source: "JetBrains AI-Friendly Code Report"
31
+
32
+ - id: modularity
33
+ description: "Modify one concern without touching 3+ files"
34
+ signals:
35
+ - metric: single_responsibility
36
+ tool: ai
37
+ rationale: "AI performance drops sharply at 3+ files requiring modification"
38
+ source: "CodeScene, JetBrains, Factory.ai, Marmelab consensus"
39
+ - metric: shallow_abstractions
40
+ tool: ai
41
+ rationale: "LLMs achieve only 38.81% accuracy on design pattern recognition"
42
+ source: "Deep inheritance vs shallow composition studies"
43
+
44
+ - id: type_safety
45
+ description: "Type system catches errors before runtime"
46
+ signals:
47
+ - metric: strict_types
48
+ languages: [typescript, python]
49
+ rationale: ">50% reduction in compilation errors with type constraints"
50
+ source: "ETH Zurich type annotation study"
51
+ rules_by_language:
52
+ typescript:
53
+ tool: eslint
54
+ rules:
55
+ - "@typescript-eslint/no-explicit-any"
56
+ - "@typescript-eslint/explicit-function-return-type"
57
+ python:
58
+ tool: ruff
59
+ rules:
60
+ - "ANN001" # missing type annotation for function argument
61
+ - "ANN201" # missing return type annotation
62
+
63
+ - id: test_adequacy
64
+ description: "Tests define expected behavior for agents"
65
+ signals:
66
+ - metric: test_coverage
67
+ threshold: 80
68
+ unit: percent
69
+ ai_threshold: 90
70
+ rationale: "SonarQube recommends 90% for AI-generated code (vs 80% human)"
71
+ source: "SonarQube AI code quality guidelines"
72
+ - metric: test_quality
73
+ tool: ai
74
+ rationale: "Tests are the primary safety net for AI agents"
75
+ source: "OpenObserve: AI test agents grew 380 to 700+ tests, 85% flaky reduction"
76
+
77
+ # =============================================================================
78
+ # 2. Security Patterns (always all 7)
79
+ # =============================================================================
80
+
81
+ security_patterns:
82
+ # --- Critical severity (tool-enforceable) ---
83
+
84
+ - id: no-hardcoded-secrets
85
+ description: "No secrets, API keys, passwords, or tokens in source code"
86
+ severity: critical
87
+ cwe: [CWE-798]
88
+ enforced_by:
89
+ - tool: Trivy
90
+ config:
91
+ scanners: [secret]
92
+ - tool: Semgrep
93
+ rules: [generic.secrets]
94
+ secrets_patterns:
95
+ - name: AWS Access Key
96
+ pattern: 'AKIA[0-9A-Z]{16}'
97
+ - name: AWS Secret Key
98
+ pattern: '(?i)aws_secret_access_key\s*[:=]\s*[A-Za-z0-9/+=]{40}'
99
+ - name: GitHub Token
100
+ pattern: '(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}'
101
+ - name: Generic API Key
102
+ pattern: '(?i)(api[_-]?key|apikey|api[_-]?secret)\s*[:=]\s*[''""][A-Za-z0-9+/=]{20,}[''""]'
103
+ - name: Database URL
104
+ pattern: '(postgres|mysql|mongodb|redis)://[^\s''"]{10,}'
105
+ - name: Private Key
106
+ pattern: '-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----'
107
+ - name: JWT Secret
108
+ pattern: '(?i)(jwt[_-]?secret|jwt[_-]?key)\s*[:=]\s*[''""][^''"]{8,}[''""]'
109
+ - name: Slack Token
110
+ pattern: 'xox[bpors]-[0-9]{10,}-[A-Za-z0-9-]+'
111
+ - name: Stripe Key
112
+ pattern: '(sk|pk)_(test|live)_[A-Za-z0-9]{24,}'
113
+
114
+ - id: input-sanitization
115
+ description: "All user input validated and sanitized before use"
116
+ severity: critical
117
+ cwe: [CWE-20, CWE-80, CWE-89, CWE-117]
118
+ enforced_by:
119
+ - tool: Semgrep
120
+ rules:
121
+ - typescript.express.security
122
+ - python.flask.security
123
+ - python.django.security
124
+
125
+ - id: parameterized-queries
126
+ description: "Database queries use parameters, never string concatenation"
127
+ severity: critical
128
+ cwe: [CWE-89]
129
+ enforced_by:
130
+ - tool: Semgrep
131
+ rules:
132
+ - javascript.lang.security.audit.sqli
133
+ - python.lang.security.audit.sqli
134
+
135
+ # --- High severity (mixed tool + AI) ---
136
+
137
+ - id: dependency-verification
138
+ description: "No known-vulnerable dependencies"
139
+ severity: high
140
+ cwe: [CWE-1395]
141
+ enforced_by:
142
+ - tool: Trivy
143
+ config:
144
+ scanners: [vuln]
145
+ severity: [HIGH, CRITICAL]
146
+
147
+ - id: no-unsafe-deserialization
148
+ description: "No unsafe deserialization of untrusted data"
149
+ severity: high
150
+ cwe: [CWE-502]
151
+ enforced_by:
152
+ - tool: Semgrep
153
+ rules:
154
+ - python.lang.security.deserialization
155
+ - java.lang.security.deserialization
156
+
157
+ - id: access-control-checks
158
+ description: "Authorization verified on all sensitive operations"
159
+ severity: high
160
+ cwe: [CWE-639]
161
+ enforced_by: [] # AI-only — requires business context
162
+
163
+ - id: config-file-integrity
164
+ description: "Configuration files not manipulable by untrusted input"
165
+ severity: high
166
+ cwe: [CWE-15]
167
+ enforced_by: [] # AI-only
168
+
169
+ # =============================================================================
170
+ # 3. Language-Specific Security Anti-Patterns
171
+ # =============================================================================
172
+
173
+ language_security_patterns:
174
+ typescript:
175
+ - pattern: "eval()"
176
+ risk: "Arbitrary code execution"
177
+ cwe: CWE-94
178
+ - pattern: "innerHTML ="
179
+ risk: "Cross-site scripting (XSS)"
180
+ cwe: CWE-79
181
+ - pattern: "child_process.exec()"
182
+ risk: "Command injection"
183
+ cwe: CWE-78
184
+ - pattern: "new Function()"
185
+ risk: "Dynamic code generation"
186
+ cwe: CWE-94
187
+ - pattern: "document.write()"
188
+ risk: "DOM-based XSS"
189
+ cwe: CWE-79
190
+ - pattern: "String concatenation in SQL"
191
+ risk: "SQL injection"
192
+ cwe: CWE-89
193
+
194
+ python:
195
+ - pattern: "exec() / eval()"
196
+ risk: "Arbitrary code execution"
197
+ cwe: CWE-94
198
+ - pattern: "pickle.loads()"
199
+ risk: "Unsafe deserialization"
200
+ cwe: CWE-502
201
+ - pattern: "subprocess(shell=True)"
202
+ risk: "Command injection"
203
+ cwe: CWE-78
204
+ - pattern: "yaml.load() without SafeLoader"
205
+ risk: "Unsafe YAML deserialization"
206
+ cwe: CWE-502
207
+ - pattern: "os.system()"
208
+ risk: "Command injection"
209
+ cwe: CWE-78
210
+ - pattern: "f-string in SQL"
211
+ risk: "SQL injection"
212
+ cwe: CWE-89
213
+
214
+ go:
215
+ - pattern: "fmt.Sprintf in SQL"
216
+ risk: "SQL injection"
217
+ cwe: CWE-89
218
+ - pattern: "exec.Command with user input"
219
+ risk: "Command injection"
220
+ cwe: CWE-78
221
+ - pattern: "template.HTML()"
222
+ risk: "XSS via unescaped HTML"
223
+ cwe: CWE-79
224
+ - pattern: "net/http without TLS"
225
+ risk: "Cleartext transmission"
226
+ cwe: CWE-319
227
+
228
+ java:
229
+ - pattern: "Runtime.exec()"
230
+ risk: "Command injection"
231
+ cwe: CWE-78
232
+ - pattern: "ObjectInputStream.readObject()"
233
+ risk: "Unsafe deserialization"
234
+ cwe: CWE-502
235
+ - pattern: "Statement.execute() with concatenation"
236
+ risk: "SQL injection"
237
+ cwe: CWE-89
238
+ - pattern: "XMLParser without disabling external entities"
239
+ risk: "XXE injection"
240
+ cwe: CWE-611
241
+
242
+ # =============================================================================
243
+ # 4. Critical File Patterns (paths deserving deeper review)
244
+ # =============================================================================
245
+
246
+ critical_file_patterns:
247
+ - "auth/**"
248
+ - "middleware/**"
249
+ - "config/**"
250
+ - ".env*"
251
+ - "Dockerfile*"
252
+ - "docker-compose*"
253
+ - "migrations/**"
254
+ - "api/**"
255
+ - "routes/**"
256
+ - "security/**"
257
+ - "crypto/**"
258
+ - "**/secrets*"
259
+ - "**/credentials*"
260
+ - "*.pem"
261
+ - "*.key"
262
+
263
+ # =============================================================================
264
+ # 5. OWASP Top 10 (2021) Mapping
265
+ # =============================================================================
266
+
267
+ owasp_mapping:
268
+ A01_Broken_Access_Control:
269
+ standard_patterns: [access-control-checks]
270
+ description: "Missing or improper authorization checks"
271
+
272
+ A02_Cryptographic_Failures:
273
+ standard_patterns: [no-hardcoded-secrets, config-file-integrity]
274
+ description: "Weak crypto, exposed secrets, insecure transmission"
275
+
276
+ A03_Injection:
277
+ standard_patterns: [parameterized-queries, input-sanitization]
278
+ description: "SQL, NoSQL, OS, LDAP injection"
279
+
280
+ A04_Insecure_Design:
281
+ standard_patterns: [access-control-checks]
282
+ description: "Missing security controls in design"
283
+
284
+ A05_Security_Misconfiguration:
285
+ standard_patterns: [config-file-integrity, dependency-verification]
286
+ description: "Default configs, unnecessary features, missing hardening"
287
+
288
+ A06_Vulnerable_Components:
289
+ standard_patterns: [dependency-verification]
290
+ description: "Known CVEs in dependencies"
291
+
292
+ A07_Auth_Failures:
293
+ standard_patterns: [access-control-checks, no-hardcoded-secrets]
294
+ description: "Broken authentication, weak credentials"
295
+
296
+ A08_Software_Integrity:
297
+ standard_patterns: [dependency-verification, no-unsafe-deserialization]
298
+ description: "Untrusted data deserialization, compromised dependencies"
299
+
300
+ A09_Logging_Failures:
301
+ standard_patterns: [input-sanitization]
302
+ description: "Insufficient logging, log injection"
303
+
304
+ A10_SSRF:
305
+ standard_patterns: [input-sanitization]
306
+ description: "Server-side request forgery"
307
+
308
+ # =============================================================================
309
+ # 6. Tool Recommendations by Language
310
+ # Adapter IDs match @codacy/analysis-cli (from CODACY-ANALYSIS-CLI.md)
311
+ # =============================================================================
312
+
313
+ tool_recommendations:
314
+ typescript:
315
+ lightweight: [Trivy]
316
+ balanced: [ESLint9, Semgrep, Trivy]
317
+ thorough: [ESLint9, Semgrep, Trivy, Lizard]
318
+
319
+ javascript:
320
+ lightweight: [Trivy]
321
+ balanced: [ESLint9, Semgrep, Trivy]
322
+ thorough: [ESLint9, Semgrep, Trivy, Lizard]
323
+
324
+ python:
325
+ lightweight: [Trivy]
326
+ balanced: [Ruff, Semgrep, Trivy]
327
+ thorough: [Ruff, Semgrep, Bandit, Trivy, Lizard]
328
+
329
+ go:
330
+ lightweight: [Trivy]
331
+ balanced: [Semgrep, Trivy]
332
+ thorough: [Semgrep, Trivy, Lizard]
333
+
334
+ java:
335
+ lightweight: [Trivy]
336
+ balanced: [PMD7, Semgrep, Trivy]
337
+ thorough: [PMD7, Checkstyle, Semgrep, Trivy, Lizard]
338
+
339
+ kotlin:
340
+ lightweight: [Trivy]
341
+ balanced: [detekt, Semgrep, Trivy]
342
+ thorough: [detekt, Semgrep, Trivy]
343
+
344
+ ruby:
345
+ lightweight: [Trivy]
346
+ balanced: [Semgrep, Trivy]
347
+ thorough: [Semgrep, Trivy, Lizard]
348
+
349
+ rust:
350
+ lightweight: [Trivy]
351
+ balanced: [Semgrep, Trivy]
352
+ thorough: [Semgrep, Trivy]
353
+
354
+ c:
355
+ lightweight: [Trivy]
356
+ balanced: [cppcheck, Semgrep, Trivy]
357
+ thorough: [cppcheck, flawfinder, Semgrep, Trivy, Lizard]
358
+
359
+ cpp:
360
+ lightweight: [Trivy]
361
+ balanced: [cppcheck, Semgrep, Trivy]
362
+ thorough: [cppcheck, flawfinder, Semgrep, Trivy, Lizard]
363
+
364
+ shell:
365
+ lightweight: []
366
+ balanced: [shellcheck]
367
+ thorough: [shellcheck]
368
+
369
+ dockerfile:
370
+ lightweight: [Trivy]
371
+ balanced: [Hadolint, Trivy]
372
+ thorough: [Hadolint, Trivy]
373
+
374
+ # =============================================================================
375
+ # 7. Analysis Modes
376
+ # =============================================================================
377
+
378
+ analysis_modes:
379
+ lightweight:
380
+ description: "Critical security only. Fastest (~3s)."
381
+ tools: "Trivy only"
382
+ patterns: "Critical security patterns"
383
+
384
+ balanced:
385
+ description: "Security + key quality. Good balance (~8s)."
386
+ tools: "Trivy + 1-2 language-specific tools"
387
+ patterns: "Curated high-signal patterns only (see curated_patterns below)"
388
+
389
+ thorough:
390
+ description: "All tools, all rules. Most comprehensive (~15s)."
391
+ tools: "All applicable tools"
392
+ patterns: "Curated patterns + tool defaults for secondary tools"
393
+
394
+ # =============================================================================
395
+ # 8. Curated Patterns Per Tool
396
+ # IMPORTANT: patterns: [] means ALL defaults (thousands of rules, massive
397
+ # token consumption and slow runs). Always use these curated lists instead.
398
+ # Pattern IDs match @codacy/analysis-cli patternId format.
399
+ # =============================================================================
400
+
401
+ curated_patterns:
402
+
403
+ # --- ESLint9 (2900+ available → ~25 high-signal) ---
404
+ ESLint9:
405
+ description: "Security + error-prone + TypeScript strictness. Skips style/formatting."
406
+ patterns:
407
+ # Security (MUST have)
408
+ - patternId: "no-eval"
409
+ - patternId: "no-implied-eval"
410
+ - patternId: "no-new-func"
411
+ - patternId: "no-script-url"
412
+ # Error-prone (high value)
413
+ - patternId: "no-unused-vars"
414
+ - patternId: "no-undef"
415
+ - patternId: "no-unreachable"
416
+ - patternId: "no-constant-condition"
417
+ - patternId: "no-dupe-keys"
418
+ - patternId: "no-duplicate-case"
419
+ - patternId: "no-fallthrough"
420
+ - patternId: "no-self-assign"
421
+ - patternId: "no-self-compare"
422
+ - patternId: "use-isnan"
423
+ - patternId: "valid-typeof"
424
+ - patternId: "no-loss-of-precision"
425
+ - patternId: "no-unsafe-optional-chaining"
426
+ # TypeScript (if applicable)
427
+ - patternId: "@typescript-eslint/no-explicit-any"
428
+ - patternId: "@typescript-eslint/no-unused-vars"
429
+ - patternId: "@typescript-eslint/no-unsafe-assignment"
430
+ - patternId: "@typescript-eslint/no-unsafe-call"
431
+ - patternId: "@typescript-eslint/no-unsafe-return"
432
+ # Best practice
433
+ - patternId: "eqeqeq"
434
+ - patternId: "no-var"
435
+ - patternId: "prefer-const"
436
+
437
+ # --- Semgrep / Opengrep (2517 available → security-focused subset) ---
438
+ # Semgrep patterns use registry rule IDs. These target OWASP Top 10.
439
+ Semgrep:
440
+ description: "Security-only: injection, XSS, secrets, auth. No style rules."
441
+ patterns:
442
+ # Injection (SQL, NoSQL, command)
443
+ - patternId: "javascript.lang.security.audit.sqli.node-sequelize-sqli"
444
+ - patternId: "javascript.lang.security.audit.sqli.node-knex-sqli"
445
+ - patternId: "typescript.lang.security.audit.sqli.node-sequelize-sqli"
446
+ - patternId: "python.lang.security.audit.sqli.raw-query"
447
+ - patternId: "python.django.security.injection.sql.sql-injection"
448
+ - patternId: "go.lang.security.audit.sqli.gosql-sqli"
449
+ - patternId: "java.lang.security.audit.sqli.jdbc-sqli"
450
+ # Command injection
451
+ - patternId: "javascript.lang.security.audit.command-injection"
452
+ - patternId: "python.lang.security.audit.dangerous-subprocess-use"
453
+ # XSS
454
+ - patternId: "javascript.browser.security.insufficient-postmessage-origin-validation"
455
+ - patternId: "javascript.lang.security.audit.unsafe-html"
456
+ # Secrets
457
+ - patternId: "generic.secrets.security.detected-generic-api-key"
458
+ - patternId: "generic.secrets.security.detected-aws-account-id"
459
+ # Deserialization
460
+ - patternId: "python.lang.security.deserialization.avoid-pickle"
461
+ - patternId: "python.lang.security.deserialization.avoid-yaml-load"
462
+ # Auth
463
+ - patternId: "javascript.express.security.audit.express-jwt-not-revoked"
464
+ - patternId: "javascript.jsonwebtoken.security.jwt-hardcode"
465
+
466
+ # --- Trivy (6 umbrella patterns → use all, already minimal) ---
467
+ Trivy:
468
+ description: "Vulnerability + secret scanning. Already minimal at 6 patterns."
469
+ patterns:
470
+ - patternId: "trivy_vuln"
471
+ - patternId: "trivy_secret"
472
+ - patternId: "trivy_config"
473
+ - patternId: "trivy_license"
474
+
475
+ # --- Ruff (773 available → ~20 high-signal) ---
476
+ Ruff:
477
+ description: "Python errors + security. Skips style/formatting (use formatter instead)."
478
+ patterns:
479
+ # Pyflakes — error-prone
480
+ - patternId: "F401" # unused import
481
+ - patternId: "F811" # redefined unused name
482
+ - patternId: "F841" # unused variable
483
+ - patternId: "F821" # undefined name
484
+ # Bugbear — likely bugs
485
+ - patternId: "B006" # mutable default argument
486
+ - patternId: "B007" # unused loop variable
487
+ - patternId: "B018" # useless expression
488
+ # Security
489
+ - patternId: "S101" # assert used (not for prod)
490
+ - patternId: "S102" # exec used
491
+ - patternId: "S103" # bad file permissions
492
+ - patternId: "S104" # hardcoded bind all interfaces
493
+ - patternId: "S105" # hardcoded password string
494
+ - patternId: "S106" # hardcoded password argument
495
+ - patternId: "S107" # hardcoded password default
496
+ - patternId: "S108" # hardcoded temp file
497
+ - patternId: "S110" # try-except-pass
498
+ - patternId: "S301" # pickle usage
499
+ - patternId: "S608" # SQL injection via string formatting
500
+ # Type annotations (if desired)
501
+ - patternId: "ANN001" # missing type annotation for function argument
502
+ - patternId: "ANN201" # missing return type annotation
503
+
504
+ # --- ShellCheck (491 available → ~15 high-signal) ---
505
+ shellcheck:
506
+ description: "Quoting, globbing, and error-prone shell patterns."
507
+ patterns:
508
+ - patternId: "shellcheck_SC2086" # double quote to prevent globbing/splitting
509
+ - patternId: "shellcheck_SC2046" # quote to prevent word splitting
510
+ - patternId: "shellcheck_SC2006" # use $() instead of backticks
511
+ - patternId: "shellcheck_SC2034" # variable unused
512
+ - patternId: "shellcheck_SC2064" # use single quotes for trap
513
+ - patternId: "shellcheck_SC2155" # declare and assign separately
514
+ - patternId: "shellcheck_SC2164" # use cd ... || exit
515
+ - patternId: "shellcheck_SC2181" # check exit code directly
516
+ - patternId: "shellcheck_SC2162" # read without -r
517
+ - patternId: "shellcheck_SC2002" # useless cat
518
+ - patternId: "shellcheck_SC2004" # unnecessary $ in arithmetic
519
+ - patternId: "shellcheck_SC2116" # useless echo
520
+ - patternId: "shellcheck_SC2148" # missing shebang
521
+ - patternId: "shellcheck_SC2229" # command not found (typo)
522
+
523
+ # --- Bandit (78 available → ~10 high-signal) ---
524
+ Bandit:
525
+ description: "Python security only."
526
+ patterns:
527
+ - patternId: "B101" # assert used
528
+ - patternId: "B102" # exec used
529
+ - patternId: "B103" # set_bad_file_permissions
530
+ - patternId: "B104" # hardcoded_bind_all_interfaces
531
+ - patternId: "B105" # hardcoded_password_string
532
+ - patternId: "B301" # pickle usage
533
+ - patternId: "B303" # insecure hash (md5/sha1)
534
+ - patternId: "B608" # SQL injection
535
+ - patternId: "B602" # subprocess with shell=True
536
+ - patternId: "B501" # request with verify=False
537
+
538
+ # --- PMD7 (424 available → ~12 high-signal) ---
539
+ PMD7:
540
+ description: "Java error-prone + security. No style rules."
541
+ patterns:
542
+ - patternId: "UnusedLocalVariable"
543
+ - patternId: "UnusedPrivateField"
544
+ - patternId: "UnusedPrivateMethod"
545
+ - patternId: "EmptyCatchBlock"
546
+ - patternId: "AvoidReassigningParameters"
547
+ - patternId: "CloseResource"
548
+ - patternId: "CompareObjectsWithEquals"
549
+ - patternId: "EqualsNull"
550
+ - patternId: "MissingBreakInSwitch"
551
+ - patternId: "NullAssignment"
552
+ - patternId: "ReturnEmptyCollectionRatherThanNull"
553
+ - patternId: "SimplifiedTernary"
554
+
555
+ # --- detekt (296 available → ~10 high-signal) ---
556
+ detekt:
557
+ description: "Kotlin error-prone + complexity."
558
+ patterns:
559
+ - patternId: "EmptyCatchBlock"
560
+ - patternId: "SwallowedException"
561
+ - patternId: "UnusedPrivateMember"
562
+ - patternId: "MagicNumber"
563
+ - patternId: "ComplexMethod"
564
+ - patternId: "LongMethod"
565
+ - patternId: "TooManyFunctions"
566
+ - patternId: "ReturnCount"
567
+ - patternId: "ThrowsCount"
568
+ - patternId: "MaxLineLength"
569
+
570
+ # --- Lizard (12 available → all, already minimal) ---
571
+ Lizard:
572
+ description: "Complexity metrics only. Already minimal."
573
+ patterns: [] # All 12 patterns — they are all complexity metrics
574
+
575
+ # --- Hadolint (99 available → ~8 high-signal) ---
576
+ Hadolint:
577
+ description: "Dockerfile best practices."
578
+ patterns:
579
+ - patternId: "DL3006" # always tag the version of an image
580
+ - patternId: "DL3007" # using latest is error-prone
581
+ - patternId: "DL3008" # pin versions in apt-get
582
+ - patternId: "DL3009" # delete apt-get lists
583
+ - patternId: "DL3018" # pin versions in apk add
584
+ - patternId: "DL3025" # use JSON for CMD
585
+ - patternId: "DL3028" # pin versions in gem install
586
+ - patternId: "DL4006" # set SHELL option -o pipefail