@sun-asterisk/sunlint 1.3.47 → 1.3.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/config/rules/rules-registry-generated.json +1717 -282
  2. package/core/architecture-integration.js +57 -15
  3. package/core/cli-action-handler.js +51 -36
  4. package/core/config-manager.js +6 -0
  5. package/core/config-merger.js +33 -0
  6. package/core/config-validator.js +37 -2
  7. package/core/file-targeting-service.js +148 -15
  8. package/core/init-command.js +118 -70
  9. package/core/output-service.js +12 -3
  10. package/core/project-detector.js +517 -0
  11. package/core/scoring-service.js +12 -6
  12. package/core/summary-report-service.js +9 -4
  13. package/core/tui-select.js +245 -0
  14. package/engines/arch-detect/rules/layered/l001-presentation-layer.js +7 -15
  15. package/engines/arch-detect/rules/layered/l002-business-layer.js +7 -15
  16. package/engines/arch-detect/rules/layered/l003-data-layer.js +7 -15
  17. package/engines/arch-detect/rules/layered/l004-model-layer.js +7 -15
  18. package/engines/arch-detect/rules/layered/l005-layer-separation.js +22 -2
  19. package/engines/arch-detect/rules/layered/l006-dependency-direction.js +8 -5
  20. package/engines/arch-detect/rules/modular/m005-no-deep-imports.js +67 -29
  21. package/engines/arch-detect/rules/presentation/pr001-view-layer.js +16 -9
  22. package/engines/arch-detect/rules/presentation/pr006-router-layer.js +33 -8
  23. package/engines/arch-detect/rules/presentation/pr007-interactor-layer.js +35 -6
  24. package/engines/arch-detect/rules/project-scanner/ps003-framework-detection.js +56 -10
  25. package/engines/impact/cli.js +54 -39
  26. package/engines/impact/config/default-config.js +105 -5
  27. package/engines/impact/core/impact-analyzer.js +12 -15
  28. package/engines/impact/core/utils/gitignore-parser.js +123 -0
  29. package/engines/impact/core/utils/method-call-graph.js +272 -87
  30. package/origin-rules/dart-en.md +1 -1
  31. package/origin-rules/go-en.md +231 -0
  32. package/origin-rules/php-en.md +107 -0
  33. package/origin-rules/python-en.md +113 -0
  34. package/origin-rules/ruby-en.md +607 -0
  35. package/package.json +1 -1
  36. package/scripts/copy-arch-detect.js +5 -1
  37. package/scripts/copy-impact-analyzer.js +5 -1
  38. package/scripts/generate-rules-registry.js +30 -14
  39. package/skill-assets/sunlint-code-quality/SKILL.md +3 -2
  40. package/skill-assets/sunlint-code-quality/rules/dart/C006-verb-noun-functions.md +45 -0
  41. package/skill-assets/sunlint-code-quality/rules/dart/C013-no-dead-code.md +53 -0
  42. package/skill-assets/sunlint-code-quality/rules/dart/C014-dependency-injection.md +92 -0
  43. package/skill-assets/sunlint-code-quality/rules/dart/C017-no-constructor-logic.md +62 -0
  44. package/skill-assets/sunlint-code-quality/rules/dart/C018-generic-errors.md +57 -0
  45. package/skill-assets/sunlint-code-quality/rules/dart/C019-error-log-level.md +50 -0
  46. package/skill-assets/sunlint-code-quality/rules/dart/C020-no-unused-imports.md +46 -0
  47. package/skill-assets/sunlint-code-quality/rules/dart/C022-no-unused-variables.md +50 -0
  48. package/skill-assets/sunlint-code-quality/rules/dart/C023-no-duplicate-names.md +56 -0
  49. package/skill-assets/sunlint-code-quality/rules/dart/C024-centralize-constants.md +75 -0
  50. package/skill-assets/sunlint-code-quality/rules/dart/C029-catch-log-root-cause.md +53 -0
  51. package/skill-assets/sunlint-code-quality/rules/dart/C030-custom-error-classes.md +86 -0
  52. package/skill-assets/sunlint-code-quality/rules/dart/C033-separate-data-access.md +90 -0
  53. package/skill-assets/sunlint-code-quality/rules/dart/C035-error-context-logging.md +62 -0
  54. package/skill-assets/sunlint-code-quality/rules/dart/C041-no-hardcoded-secrets.md +75 -0
  55. package/skill-assets/sunlint-code-quality/rules/dart/C042-boolean-naming.md +73 -0
  56. package/skill-assets/sunlint-code-quality/rules/dart/C052-widget-parsing.md +84 -0
  57. package/skill-assets/sunlint-code-quality/rules/dart/C060-superclass-logic.md +91 -0
  58. package/skill-assets/sunlint-code-quality/rules/dart/C067-no-hardcoded-config.md +108 -0
  59. package/skill-assets/sunlint-code-quality/rules/go/G001-explicit-error-handling.md +53 -0
  60. package/skill-assets/sunlint-code-quality/rules/go/G002-context-first-argument.md +44 -0
  61. package/skill-assets/sunlint-code-quality/rules/go/G003-receiver-consistency.md +38 -0
  62. package/skill-assets/sunlint-code-quality/rules/go/G004-avoid-panic.md +49 -0
  63. package/skill-assets/sunlint-code-quality/rules/go/G005-goroutine-leak-prevention.md +49 -0
  64. package/skill-assets/sunlint-code-quality/rules/go/G006-interface-consumer-definition.md +45 -0
  65. package/skill-assets/sunlint-code-quality/rules/go/GN001-gin-binding-validation.md +57 -0
  66. package/skill-assets/sunlint-code-quality/rules/go/GN002-gin-error-response.md +48 -0
  67. package/skill-assets/sunlint-code-quality/rules/go/GN003-graceful-shutdown.md +57 -0
  68. package/skill-assets/sunlint-code-quality/rules/go/GN004-gin-route-logical-grouping.md +54 -0
  69. package/skill-assets/sunlint-code-quality/rules/go-gin/AGENTS.md +149 -0
  70. package/skill-assets/sunlint-code-quality/rules/go-gin/GN001-abort-after-response.md +75 -0
  71. package/skill-assets/sunlint-code-quality/rules/go-gin/GN002-request-context.md +64 -0
  72. package/skill-assets/sunlint-code-quality/rules/go-gin/GN003-bind-error-handling.md +70 -0
  73. package/skill-assets/sunlint-code-quality/rules/go-gin/GN004-dependency-injection.md +78 -0
  74. package/skill-assets/sunlint-code-quality/rules/go-gin/GN005-route-groups-middleware.md +71 -0
  75. package/skill-assets/sunlint-code-quality/rules/go-gin/GN006-http-status-codes.md +91 -0
  76. package/skill-assets/sunlint-code-quality/rules/go-gin/GN007-release-mode.md +64 -0
  77. package/skill-assets/sunlint-code-quality/rules/go-gin/GN008-struct-validation-tags.md +90 -0
  78. package/skill-assets/sunlint-code-quality/rules/go-gin/GN009-recovery-middleware.md +68 -0
  79. package/skill-assets/sunlint-code-quality/rules/go-gin/GN010-context-scope.md +68 -0
  80. package/skill-assets/sunlint-code-quality/rules/go-gin/GN011-middleware-concerns.md +92 -0
  81. package/skill-assets/sunlint-code-quality/rules/go-gin/GN012-no-log-sensitive.md +84 -0
  82. package/skill-assets/sunlint-code-quality/rules/java/J001-try-with-resources.md +86 -0
  83. package/skill-assets/sunlint-code-quality/rules/java/J002-equals-and-hashcode.md +88 -0
  84. package/skill-assets/sunlint-code-quality/rules/java/J003-string-comparison.md +72 -0
  85. package/skill-assets/sunlint-code-quality/rules/java/J004-use-java-time.md +91 -0
  86. package/skill-assets/sunlint-code-quality/rules/java/J005-no-print-stack-trace.md +80 -0
  87. package/skill-assets/sunlint-code-quality/rules/java/J006-no-system-println.md +89 -0
  88. package/skill-assets/sunlint-code-quality/rules/java/J007-proper-logger.md +91 -0
  89. package/skill-assets/sunlint-code-quality/rules/java/J008-thread-safe-singleton.md +119 -0
  90. package/skill-assets/sunlint-code-quality/rules/java/J009-utility-class-constructor.md +82 -0
  91. package/skill-assets/sunlint-code-quality/rules/java/J010-preserve-stack-trace.md +119 -0
  92. package/skill-assets/sunlint-code-quality/rules/java/J011-null-safe-compare.md +88 -0
  93. package/skill-assets/sunlint-code-quality/rules/java/J012-use-enum-collections.md +104 -0
  94. package/skill-assets/sunlint-code-quality/rules/java/J013-return-empty-not-null.md +102 -0
  95. package/skill-assets/sunlint-code-quality/rules/java/J014-hardcoded-crypto-key.md +108 -0
  96. package/skill-assets/sunlint-code-quality/rules/java/J015-optional-instead-of-null.md +109 -0
  97. package/skill-assets/sunlint-code-quality/rules/php-laravel/AGENTS.md +124 -0
  98. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV001-form-request-validation.md +64 -0
  99. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV002-eager-load-no-n-plus-1.md +58 -0
  100. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV003-config-not-env.md +54 -0
  101. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV004-fillable-mass-assignment.md +51 -0
  102. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV005-policies-gates-authorization.md +71 -0
  103. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV006-queue-heavy-tasks.md +68 -0
  104. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV007-hash-passwords.md +51 -0
  105. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV008-route-model-binding.md +67 -0
  106. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV009-api-resources.md +72 -0
  107. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV010-chunk-large-datasets.md +58 -0
  108. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV011-db-transactions.md +73 -0
  109. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV012-service-layer.md +78 -0
  110. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV013-testing-factories.md +75 -0
  111. package/skill-assets/sunlint-code-quality/rules/php-laravel/LV014-service-container.md +61 -0
  112. package/skill-assets/sunlint-code-quality/rules/python/P001-mutable-default-argument.md +55 -0
  113. package/skill-assets/sunlint-code-quality/rules/python/P002-specify-file-encoding.md +45 -0
  114. package/skill-assets/sunlint-code-quality/rules/python/P003-context-manager-for-resources.md +54 -0
  115. package/skill-assets/sunlint-code-quality/rules/python/P004-no-bare-except.md +65 -0
  116. package/skill-assets/sunlint-code-quality/rules/python/P005-use-isinstance.md +60 -0
  117. package/skill-assets/sunlint-code-quality/rules/python/P006-timezone-aware-datetime.md +58 -0
  118. package/skill-assets/sunlint-code-quality/rules/python/P007-use-pathlib.md +62 -0
  119. package/skill-assets/sunlint-code-quality/rules/python/P008-no-wildcard-import.md +52 -0
  120. package/skill-assets/sunlint-code-quality/rules/python/P009-logging-lazy-format.md +50 -0
  121. package/skill-assets/sunlint-code-quality/rules/python/P010-exception-chaining.md +57 -0
  122. package/skill-assets/sunlint-code-quality/rules/python/P011-subprocess-check.md +59 -0
  123. package/skill-assets/sunlint-code-quality/rules/python/P012-requests-timeout.md +70 -0
  124. package/skill-assets/sunlint-code-quality/rules/python/P013-no-global-statement.md +73 -0
  125. package/skill-assets/sunlint-code-quality/rules/python/P014-no-modify-collection-while-iterating.md +66 -0
  126. package/skill-assets/sunlint-code-quality/rules/python/P015-prefer-fstrings.md +61 -0
  127. package/skill-assets/sunlint-code-quality/rules/ruby-rails/AGENTS.md +121 -0
  128. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR001-strong-parameters.md +55 -0
  129. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR002-eager-load-includes.md +51 -0
  130. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR003-service-objects.md +99 -0
  131. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR004-active-job-background.md +67 -0
  132. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR005-pagination.md +53 -0
  133. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR006-find-each-batches.md +53 -0
  134. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR007-http-status-codes.md +76 -0
  135. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR008-before-action-auth.md +77 -0
  136. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR009-rails-credentials.md +61 -0
  137. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR010-scopes.md +57 -0
  138. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR011-counter-cache.md +59 -0
  139. package/skill-assets/sunlint-code-quality/rules/ruby-rails/RR012-render-json-status.md +42 -0
  140. package/skill-assets/sunlint-code-quality/rules/swift/C006-verb-noun-functions.md +37 -0
  141. package/skill-assets/sunlint-code-quality/rules/swift/C013-no-dead-code.md +55 -0
  142. package/skill-assets/sunlint-code-quality/rules/swift/C014-dependency-injection.md +69 -0
  143. package/skill-assets/sunlint-code-quality/rules/swift/C017-no-constructor-logic.md +66 -0
  144. package/skill-assets/sunlint-code-quality/rules/swift/C018-generic-errors.md +64 -0
  145. package/skill-assets/sunlint-code-quality/rules/swift/C019-error-log-level.md +64 -0
  146. package/skill-assets/sunlint-code-quality/rules/swift/C020-no-unused-imports.md +47 -0
  147. package/skill-assets/sunlint-code-quality/rules/swift/C022-no-unused-variables.md +46 -0
  148. package/skill-assets/sunlint-code-quality/rules/swift/C023-no-duplicate-names.md +55 -0
  149. package/skill-assets/sunlint-code-quality/rules/swift/C024-centralize-constants.md +68 -0
  150. package/skill-assets/sunlint-code-quality/rules/swift/C029-catch-log-root-cause.md +69 -0
  151. package/skill-assets/sunlint-code-quality/rules/swift/C030-custom-error-classes.md +77 -0
  152. package/skill-assets/sunlint-code-quality/rules/swift/C033-separate-data-access.md +89 -0
  153. package/skill-assets/sunlint-code-quality/rules/swift/C035-error-context-logging.md +66 -0
  154. package/skill-assets/sunlint-code-quality/rules/swift/C041-no-hardcoded-secrets.md +65 -0
  155. package/skill-assets/sunlint-code-quality/rules/swift/C042-boolean-naming.md +60 -0
  156. package/skill-assets/sunlint-code-quality/rules/swift/C052-controller-parsing.md +67 -0
  157. package/skill-assets/sunlint-code-quality/rules/swift/C060-superclass-logic.md +95 -0
  158. package/skill-assets/sunlint-code-quality/rules/swift/C067-no-hardcoded-config.md +80 -0
  159. package/skill-assets/sunlint-code-quality/rules/swift/S003-sql-injection.md +65 -0
  160. package/skill-assets/sunlint-code-quality/rules/swift/S004-no-log-credentials.md +67 -0
  161. package/skill-assets/sunlint-code-quality/rules/swift/S005-server-authorization.md +73 -0
  162. package/skill-assets/sunlint-code-quality/rules/swift/S006-default-credentials.md +76 -0
  163. package/skill-assets/sunlint-code-quality/rules/swift/S007-output-encoding.md +96 -0
  164. package/skill-assets/sunlint-code-quality/rules/swift/S009-approved-crypto.md +86 -0
  165. package/skill-assets/sunlint-code-quality/rules/swift/S010-csprng.md +71 -0
  166. package/skill-assets/sunlint-code-quality/rules/swift/S011-insecure-deserialization.md +74 -0
  167. package/skill-assets/sunlint-code-quality/rules/swift/S012-secrets-management.md +81 -0
  168. package/skill-assets/sunlint-code-quality/rules/swift/S013-tls-connections.md +67 -0
  169. package/skill-assets/sunlint-code-quality/rules/swift/S017-parameterized-queries.md +86 -0
  170. package/skill-assets/sunlint-code-quality/rules/swift/S019-session-management.md +131 -0
  171. package/skill-assets/sunlint-code-quality/rules/swift/S020-kvc-injection.md +91 -0
  172. package/skill-assets/sunlint-code-quality/rules/swift/S025-input-validation.md +125 -0
  173. package/skill-assets/sunlint-code-quality/rules/swift/S029-brute-force-protection.md +120 -0
  174. package/skill-assets/sunlint-code-quality/rules/swift/S036-path-traversal.md +102 -0
  175. package/skill-assets/sunlint-code-quality/rules/swift/S039-tls-certificate-validation.md +109 -0
  176. package/skill-assets/sunlint-code-quality/rules/swift/S041-logout-invalidation.md +103 -0
  177. package/skill-assets/sunlint-code-quality/rules/swift/S043-password-hashing.md +116 -0
  178. package/skill-assets/sunlint-code-quality/rules/swift/S044-critical-changes-reauth.md +145 -0
  179. package/skill-assets/sunlint-code-quality/rules/swift/S045-debug-info-exposure.md +116 -0
  180. package/skill-assets/sunlint-code-quality/rules/swift/S046-unvalidated-redirect.md +140 -0
  181. package/skill-assets/sunlint-code-quality/rules/swift/S051-token-expiry.md +134 -0
  182. package/skill-assets/sunlint-code-quality/rules/swift/S053-jwt-validation.md +139 -0
  183. package/skill-assets/sunlint-code-quality/rules/swift/S059-background-snapshot-protection.md +113 -0
  184. package/skill-assets/sunlint-code-quality/rules/swift/S060-data-protection-api.md +106 -0
  185. package/skill-assets/sunlint-code-quality/rules/swift/S061-jailbreak-detection.md +132 -0
@@ -0,0 +1,108 @@
1
+ ---
2
+ title: Do Not Hardcode Configuration
3
+ impact: HIGH
4
+ impactDescription: enables environment-specific deployments
5
+ tags: configuration, environment, deployment, quality
6
+ ---
7
+
8
+ ## Do Not Hardcode Configuration
9
+
10
+ Hardcoded config requires code changes to deploy to different environments.
11
+
12
+ **Incorrect (hardcoded config):**
13
+
14
+ ```dart
15
+ const apiUrl = 'https://api.production.example.com';
16
+ const timeout = 5000;
17
+ const maxFileSize = 10485760;
18
+ const enableAnalytics = true;
19
+ ```
20
+
21
+ **Correct (externalized config via dart-define):**
22
+
23
+ ```dart
24
+ // lib/config/app_config.dart
25
+ class AppConfig {
26
+ AppConfig._();
27
+
28
+ static const String apiUrl = String.fromEnvironment(
29
+ 'API_URL',
30
+ defaultValue: 'https://api.dev.example.com',
31
+ );
32
+
33
+ static const int timeoutMs = int.fromEnvironment(
34
+ 'TIMEOUT_MS',
35
+ defaultValue: 5000,
36
+ );
37
+
38
+ static const int maxFileSizeBytes = int.fromEnvironment(
39
+ 'MAX_FILE_SIZE',
40
+ defaultValue: 10 * 1024 * 1024, // 10MB
41
+ );
42
+
43
+ static const bool enableAnalytics = bool.fromEnvironment(
44
+ 'ENABLE_ANALYTICS',
45
+ defaultValue: false,
46
+ );
47
+ }
48
+
49
+ // Usage
50
+ final client = HttpClient(baseUrl: AppConfig.apiUrl, timeout: Duration(milliseconds: AppConfig.timeoutMs));
51
+ ```
52
+
53
+ **Build with environment config:**
54
+
55
+ ```bash
56
+ # Development
57
+ flutter run --dart-define=API_URL=https://api.dev.example.com --dart-define=ENABLE_ANALYTICS=false
58
+
59
+ # Production
60
+ flutter build apk --dart-define=API_URL=https://api.production.example.com --dart-define=ENABLE_ANALYTICS=true
61
+
62
+ # Using a JSON config file (flutter_launcher_icons approach)
63
+ flutter run --dart-define-from-file=config/dev.json
64
+ flutter build apk --dart-define-from-file=config/prod.json
65
+ ```
66
+
67
+ **Example config files:**
68
+
69
+ ```json
70
+ // config/dev.json
71
+ {
72
+ "API_URL": "https://api.dev.example.com",
73
+ "ENABLE_ANALYTICS": "false",
74
+ "TIMEOUT_MS": "10000"
75
+ }
76
+ ```
77
+
78
+ ```json
79
+ // config/prod.json
80
+ {
81
+ "API_URL": "https://api.production.example.com",
82
+ "ENABLE_ANALYTICS": "true",
83
+ "TIMEOUT_MS": "5000"
84
+ }
85
+ ```
86
+
87
+ **For flavor-based config:**
88
+
89
+ ```dart
90
+ // lib/config/flavors.dart
91
+ enum Flavor { dev, staging, production }
92
+
93
+ class FlavorConfig {
94
+ static Flavor? _flavor;
95
+
96
+ static void initialize(Flavor flavor) {
97
+ _flavor = flavor;
98
+ }
99
+
100
+ static String get apiUrl => switch (_flavor!) {
101
+ Flavor.dev => 'https://api.dev.example.com',
102
+ Flavor.staging => 'https://api.staging.example.com',
103
+ Flavor.production => 'https://api.example.com',
104
+ };
105
+ }
106
+ ```
107
+
108
+ **Tools:** dart-define, envied, flutter_flavor, Code Review
@@ -0,0 +1,53 @@
1
+ ---
2
+ title: Explicit Error Handling
3
+ impact: CRITICAL
4
+ impactDescription: prevents silent failures and ensures robust error recovery
5
+ tags: go, error-handling, quality
6
+ ---
7
+
8
+ ## Explicit Error Handling
9
+
10
+ In Go, errors are values and must be handled explicitly. Ignoring errors using `_` or failing to check them leads to unpredictable state and silent failures.
11
+
12
+ **Incorrect (ignoring errors):**
13
+
14
+ ```go
15
+ func processData(data string) {
16
+ file, _ := os.Open("config.json") // Error ignored
17
+ defer file.Close()
18
+
19
+ bytes, _ := io.ReadAll(file) // Error ignored
20
+ json.Unmarshal(bytes, &config) // Error ignored
21
+ }
22
+ ```
23
+
24
+ **Correct (explicit checking):**
25
+
26
+ ```go
27
+ func processData(data string) error {
28
+ file, err := os.Open("config.json")
29
+ if err != nil {
30
+ return fmt.Errorf("failed to open config: %w", err)
31
+ }
32
+ defer file.Close()
33
+
34
+ bytes, err := io.ReadAll(file)
35
+ if err != nil {
36
+ return fmt.Errorf("failed to read config: %w", err)
37
+ }
38
+
39
+ if err := json.Unmarshal(bytes, &config); err != nil {
40
+ return fmt.Errorf("failed to parse config: %w", err)
41
+ }
42
+
43
+ return nil
44
+ }
45
+ ```
46
+
47
+ **Benefits:**
48
+ - Prevents silent crashes and data corruption
49
+ - Provides clear trace of what went wrong
50
+ - Forces developers to think about failure paths
51
+ - Makes code easier to debug
52
+
53
+ **Tools:** errcheck, golangci-lint, staticcheck
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Context as First Argument
3
+ impact: MEDIUM
4
+ impactDescription: follows Go idiomatic patterns for cancellation and timeouts
5
+ tags: go, context, patterns, quality
6
+ ---
7
+
8
+ ## Context as First Argument
9
+
10
+ `context.Context` should always be the first parameter of a function, typically named `ctx`. This consistency makes it easy to propagate cancellation, deadlines, and markers across call stacks.
11
+
12
+ **Incorrect (wrong order or missing):**
13
+
14
+ ```go
15
+ func (s *Service) FetchUser(userID string, ctx context.Context) (*User, error) {
16
+ // ctx is second argument
17
+ return s.repo.Get(ctx, userID)
18
+ }
19
+
20
+ func ProcessTask(taskID string) {
21
+ // Missing context for potentially long-running operation
22
+ db.Exec("UPDATE tasks SET status = 'done' WHERE id = ?", taskID)
23
+ }
24
+ ```
25
+
26
+ **Correct (context first):**
27
+
28
+ ```go
29
+ func (s *Service) FetchUser(ctx context.Context, userID string) (*User, error) {
30
+ return s.repo.Get(ctx, userID)
31
+ }
32
+
33
+ func ProcessTask(ctx context.Context, taskID string) error {
34
+ return db.ExecContext(ctx, "UPDATE tasks SET status = 'done' WHERE id = ?", taskID)
35
+ }
36
+ ```
37
+
38
+ **Benefits:**
39
+ - Standardizes API signatures across the codebase
40
+ - Simplifies cancellation propagation
41
+ - Enables proper timeout handling for I/O and external calls
42
+ - Improves observability with trace IDs in context
43
+
44
+ **Tools:** golangci-lint, contextcheck
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Consistent Receiver Naming
3
+ impact: LOW
4
+ impactDescription: improves readability and consistency
5
+ tags: go, style, quality
6
+ ---
7
+
8
+ ## Consistent Receiver Naming
9
+
10
+ Receiver names should be short (1-2 letters) and consistent across all methods of a type. Do not use generic names like `this`, `self`, or `me`.
11
+
12
+ **Incorrect (inconsistent or verbose):**
13
+
14
+ ```go
15
+ func (this *UserRepository) Get(id string) (*User, error) { ... }
16
+
17
+ func (repo *UserRepository) List() ([]*User, error) { ... }
18
+
19
+ func (self *UserRepository) Update(u *User) error { ... }
20
+ ```
21
+
22
+ **Correct (short and consistent):**
23
+
24
+ ```go
25
+ // Use 'r' consistently for UserRepository
26
+ func (r *UserRepository) Get(id string) (*User, error) { ... }
27
+
28
+ func (r *UserRepository) List() ([]*User, error) { ... }
29
+
30
+ func (r *UserRepository) Update(u *User) error { ... }
31
+ ```
32
+
33
+ **Benefits:**
34
+ - Reduces visual noise in method definitions
35
+ - Follows Go community standards
36
+ - Makes it easier to search and scan methods of the same type
37
+
38
+ **Tools:** golangci-lint, stylecheck
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Avoid Panic in Production
3
+ impact: HIGH
4
+ impactDescription: prevents application crashes and enables graceful degradation
5
+ tags: go, error-handling, stability, quality
6
+ ---
7
+
8
+ ## Avoid Panic in Production
9
+
10
+ Panic should be reserved for truly unrecoverable programmer errors (e.g., initialization failure where the app cannot start). Business logic and normal I/O should always use `error` returns.
11
+
12
+ **Incorrect (panic for normal errors):**
13
+
14
+ ```go
15
+ func GetUser(id string) *User {
16
+ user, err := db.Find(id)
17
+ if err != nil {
18
+ panic(err) // Crash!
19
+ }
20
+ return user
21
+ }
22
+ ```
23
+
24
+ **Correct (return error):**
25
+
26
+ ```go
27
+ func GetUser(id string) (*User, error) {
28
+ user, err := db.Find(id)
29
+ if err != nil {
30
+ return nil, fmt.Errorf("failed to find user: %w", err)
31
+ }
32
+ return user, nil
33
+ }
34
+
35
+ // In main or init, panic is acceptable if the app MUST die
36
+ func main() {
37
+ config, err := LoadConfig()
38
+ if err != nil {
39
+ panic("critical config missing: " + err.Error())
40
+ }
41
+ }
42
+ ```
43
+
44
+ **Benefits:**
45
+ - Improves application uptime and reliability
46
+ - Allows handlers to recover and return HTTP 500 instead of crashing the process
47
+ - Makes the code more predictable and testable
48
+
49
+ **Tools:** golangci-lint, staticcheck
@@ -0,0 +1,49 @@
1
+ ---
2
+ title: Goroutine Leak Prevention
3
+ impact: HIGH
4
+ impactDescription: prevents memory exhaustion and zombie processes
5
+ tags: go, concurrency, stability, quality
6
+ ---
7
+
8
+ ## Goroutine Leak Prevention
9
+
10
+ Always ensure that a goroutine has a clear termination path, typically via a `context.Context` or a close channel. Goroutines that block indefinitely on channel operations or I/O without a timeout cause memory leaks.
11
+
12
+ **Incorrect (leaky goroutine):**
13
+
14
+ ```go
15
+ func StartWatcher(ch chan string) {
16
+ go func() {
17
+ for msg := range ch { // Blocks forever if ch is never closed
18
+ fmt.Println(msg)
19
+ }
20
+ }()
21
+ }
22
+ ```
23
+
24
+ **Correct (context-aware goroutine):**
25
+
26
+ ```go
27
+ func StartWatcher(ctx context.Context, ch chan string) {
28
+ go func() {
29
+ for {
30
+ select {
31
+ case <-ctx.Done():
32
+ return // Exit cleanly when context is cancelled
33
+ case msg, ok := <-ch:
34
+ if !ok {
35
+ return // Exit when channel is closed
36
+ }
37
+ fmt.Println(msg)
38
+ }
39
+ }
40
+ }()
41
+ }
42
+ ```
43
+
44
+ **Benefits:**
45
+ - Prevents memory leaks and resource exhaustion
46
+ - Ensures clean application shutdown
47
+ - Makes concurrent code more predictable and testable
48
+
49
+ **Tools:** goleak, golangci-lint
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: Define Interfaces at Consumer Side
3
+ impact: MEDIUM
4
+ impactDescription: promotes decoupling and simplifies testing
5
+ tags: go, architecture, interfaces, quality
6
+ ---
7
+
8
+ ## Define Interfaces at Consumer Side
9
+
10
+ In Go, interfaces are satisfied implicitly. Do not define interfaces in the same package where the implementation is defined (producer side). Instead, define the interface in the package that requires the dependency (consumer side).
11
+
12
+ **Incorrect (interface in producer package):**
13
+
14
+ ```go
15
+ // package auth
16
+ type Service interface {
17
+ Login(user, pass string) (string, error)
18
+ }
19
+
20
+ type serviceImpl struct { ... }
21
+ func (s *serviceImpl) Login(u, p string) (string, error) { ... }
22
+ ```
23
+
24
+ **Correct (interface in consumer package):**
25
+
26
+ ```go
27
+ // package auth (implementation only)
28
+ type Service struct { ... }
29
+ func (s *Service) Login(u, p string) (string, error) { ... }
30
+
31
+ // package handler (consumer)
32
+ type AuthProvider interface {
33
+ Login(user, pass string) (string, error)
34
+ }
35
+
36
+ func LoginHandler(auth AuthProvider) { ... }
37
+ ```
38
+
39
+ **Benefits:**
40
+ - Prevents package circular dependencies
41
+ - Allows packages to define exactly what they need from a dependency
42
+ - Makes it easier to mock dependencies for unit testing
43
+ - Keeps the system more loosely coupled
44
+
45
+ **Tools:** Code Review, Architecture rules
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: Use Gin Binding for Validation
3
+ impact: HIGH
4
+ impactDescription: simplifies input handling and ensures consistent validation
5
+ tags: gin, go, validation, quality
6
+ ---
7
+
8
+ ## Use Gin Binding for Validation
9
+
10
+ Leverage Gin's built-in binding mechanism (`ShouldBindJSON`, `ShouldBindQuery`, etc.) and the `validator` library tags. This centralizes validation logic and keeps handlers clean.
11
+
12
+ **Incorrect (manual parsing and validation):**
13
+
14
+ ```go
15
+ func CreateUser(c *gin.Context) {
16
+ var raw map[string]interface{}
17
+ if err := c.BindJSON(&raw); err != nil {
18
+ c.JSON(400, gin.H{"error": "invalid json"})
19
+ return
20
+ }
21
+
22
+ email, ok := raw["email"].(string)
23
+ if !ok || email == "" {
24
+ c.JSON(400, gin.H{"error": "email is required"})
25
+ return
26
+ }
27
+ // ... more manual checks
28
+ }
29
+ ```
30
+
31
+ **Correct (struct binding and tags):**
32
+
33
+ ```go
34
+ type CreateUserRequest struct {
35
+ Email string `json:"email" binding:"required,email"`
36
+ Password string `json:"password" binding:"required,min=8"`
37
+ Age int `json:"age" binding:"gte=18"`
38
+ }
39
+
40
+ func CreateUser(c *gin.Context) {
41
+ var req CreateUserRequest
42
+ if err := c.ShouldBindJSON(&req); err != nil {
43
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
44
+ return
45
+ }
46
+
47
+ // Process validated request
48
+ }
49
+ ```
50
+
51
+ **Benefits:**
52
+ - Reduces boilerplate code in handlers
53
+ - Declarative validation is easier to read and maintain
54
+ - Automatically handles type conversion (e.g., string to int)
55
+ - Provides standard error messages
56
+
57
+ **Tools:** Gin, go-playground/validator
@@ -0,0 +1,48 @@
1
+ ---
2
+ title: Abort with Status for Errors
3
+ impact: MEDIUM
4
+ impactDescription: ensures middleware chain is interrupted and consistent response is sent
5
+ tags: gin, go, error-handling, quality
6
+ ---
7
+
8
+ ## Abort with Status for Errors
9
+
10
+ When a fatal error occurs in a Gin handler or middleware (e.g., auth failure, validation error), use `c.AbortWithStatusJSON` or `c.Abort()` to stop the execution of subsequent handlers in the chain.
11
+
12
+ **Incorrect (not aborting or only partial return):**
13
+
14
+ ```go
15
+ func AuthMiddleware(c *gin.Context) {
16
+ token := c.GetHeader("Authorization")
17
+ if token == "" {
18
+ c.JSON(401, gin.H{"error": "unauthorized"})
19
+ // MISSING c.Abort()! Subsequent handlers WILL execute.
20
+ return
21
+ }
22
+ }
23
+ ```
24
+
25
+ **Correct (using AbortWithStatusJSON):**
26
+
27
+ ```go
28
+ func AuthMiddleware(c *gin.Context) {
29
+ if c.GetHeader("Authorization") == "" {
30
+ c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
31
+ return
32
+ }
33
+ }
34
+
35
+ func Handler(c *gin.Context) {
36
+ if err := someFunc(); err != nil {
37
+ c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "internal error"})
38
+ return
39
+ }
40
+ }
41
+ ```
42
+
43
+ **Benefits:**
44
+ - Prevents security bypasses in middleware
45
+ - Consistent error response pattern
46
+ - Guarantees that only one response is sent to the client
47
+
48
+ **Tools:** Gin
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: Implement Graceful Shutdown
3
+ impact: MEDIUM
4
+ impactDescription: prevents data loss and ensures clean connection handling
5
+ tags: gin, go, stability, quality
6
+ ---
7
+
8
+ ## Implement Graceful Shutdown
9
+
10
+ Web servers should handle termination signals (`SIGINT`, `SIGTERM`) to allow inflight requests to finish and to close database connections cleanly. Gin's `Run()` method blocks and doesn't support this out of the box; use `http.Server` instead.
11
+
12
+ **Incorrect (standard Run):**
13
+
14
+ ```go
15
+ func main() {
16
+ r := gin.Default()
17
+ r.GET("/", handler)
18
+ r.Run(":8080") // Blocks and dies immediately on CTRL+C
19
+ }
20
+ ```
21
+
22
+ **Correct (graceful shutdown):**
23
+
24
+ ```go
25
+ func main() {
26
+ router := gin.Default()
27
+ srv := &http.Server{
28
+ Addr: ":8080",
29
+ Handler: router,
30
+ }
31
+
32
+ go func() {
33
+ if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
34
+ log.Fatalf("listen: %s\n", err)
35
+ }
36
+ }()
37
+
38
+ // Wait for interrupt signal
39
+ quit := make(chan os.Signal, 1)
40
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
41
+ <-quit
42
+
43
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
44
+ defer cancel()
45
+
46
+ if err := srv.Shutdown(ctx); err != nil {
47
+ log.Fatal("Server Shutdown:", err)
48
+ }
49
+ }
50
+ ```
51
+
52
+ **Benefits:**
53
+ - Prevents dropping active user connections
54
+ - Allows finishing long-running database transactions
55
+ - Ensures monitoring tools report clean shutdown instead of "crash"
56
+
57
+ **Tools:** Go Standard Library, Gin
@@ -0,0 +1,54 @@
1
+ ---
2
+ title: Logical Route Grouping
3
+ impact: MEDIUM
4
+ impactDescription: improves code organization and shared middleware management
5
+ tags: gin, go, routing, quality
6
+ ---
7
+
8
+ ## Logical Route Grouping
9
+
10
+ Use `RouterGroup` to organize routes logically (e.g., by version, resource, or access level). This allows applying middleware (like auth or logging) to a specific group of routes without repetition.
11
+
12
+ **Incorrect (flat and repetitive):**
13
+
14
+ ```go
15
+ func RegisterRoutes(r *gin.Engine) {
16
+ r.GET("/api/v1/users", AuthMiddleware(), GetUsers)
17
+ r.POST("/api/v1/users", AuthMiddleware(), CreateUser)
18
+ r.GET("/api/v1/users/:id", AuthMiddleware(), GetUser)
19
+ r.GET("/health", HealthCheck)
20
+ }
21
+ ```
22
+
23
+ **Correct (logical grouping):**
24
+
25
+ ```go
26
+ func RegisterRoutes(r *gin.Engine) {
27
+ // Public routes
28
+ r.GET("/health", HealthCheck)
29
+
30
+ // API v1 group
31
+ v1 := r.Group("/api/v1")
32
+ {
33
+ // Auth required group
34
+ auth := v1.Group("/")
35
+ auth.Use(AuthMiddleware())
36
+ {
37
+ users := auth.Group("/users")
38
+ {
39
+ users.GET("/", GetUsers)
40
+ users.POST("/", CreateUser)
41
+ users.GET("/:id", GetUser)
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ **Benefits:**
49
+ - Reduces code duplication for middleware application
50
+ - Provides clear structure of the API URL space
51
+ - Simplifies refactoring and versioning (e.g., adding `/v2` group)
52
+ - Improves readability of the main routing configuration
53
+
54
+ **Tools:** Gin