activo 0.4.4 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +203 -1
  2. package/data/2026-03-04_20-54.json +181 -0
  3. package/data/2026-03-04_20-56.json +181 -0
  4. package/data/apex-rulesets/egov.yaml +469 -0
  5. package/data/apex-rulesets/modernize.yaml +687 -0
  6. package/data/apex-rulesets/quality.yaml +1677 -0
  7. package/data/apex-rulesets/rule-schema.yaml +587 -0
  8. package/data/apex-rulesets/secure.yaml +1688 -0
  9. package/data/apex-rulesets/spring.yaml +455 -0
  10. package/data/apex-rulesets/sql-format.yaml +99 -0
  11. package/data/apex-rulesets/sql-oracle.yaml +281 -0
  12. package/data/apex-rulesets/sql.yaml +1660 -0
  13. package/dist/cli/headless.d.ts.map +1 -1
  14. package/dist/cli/headless.js +32 -10
  15. package/dist/cli/headless.js.map +1 -1
  16. package/dist/cli/index.js +31 -3
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/core/agent.d.ts +3 -3
  19. package/dist/core/agent.d.ts.map +1 -1
  20. package/dist/core/agent.js +203 -384
  21. package/dist/core/agent.js.map +1 -1
  22. package/dist/core/commands.d.ts +2 -1
  23. package/dist/core/commands.d.ts.map +1 -1
  24. package/dist/core/commands.js +61 -9
  25. package/dist/core/commands.js.map +1 -1
  26. package/dist/core/config.d.ts +14 -0
  27. package/dist/core/config.d.ts.map +1 -1
  28. package/dist/core/config.js +41 -4
  29. package/dist/core/config.js.map +1 -1
  30. package/dist/core/conversation.d.ts +2 -2
  31. package/dist/core/conversation.d.ts.map +1 -1
  32. package/dist/core/conversation.js.map +1 -1
  33. package/dist/core/intentRouter.d.ts +43 -0
  34. package/dist/core/intentRouter.d.ts.map +1 -0
  35. package/dist/core/intentRouter.js +804 -0
  36. package/dist/core/intentRouter.js.map +1 -0
  37. package/dist/core/llm/anthropic.d.ts +24 -0
  38. package/dist/core/llm/anthropic.d.ts.map +1 -0
  39. package/dist/core/llm/anthropic.js +226 -0
  40. package/dist/core/llm/anthropic.js.map +1 -0
  41. package/dist/core/llm/ollama.d.ts +5 -14
  42. package/dist/core/llm/ollama.d.ts.map +1 -1
  43. package/dist/core/llm/ollama.js +3 -0
  44. package/dist/core/llm/ollama.js.map +1 -1
  45. package/dist/core/llm/types.d.ts +22 -0
  46. package/dist/core/llm/types.d.ts.map +1 -0
  47. package/dist/core/llm/types.js +2 -0
  48. package/dist/core/llm/types.js.map +1 -0
  49. package/dist/core/mcp/client.d.ts +6 -0
  50. package/dist/core/mcp/client.d.ts.map +1 -1
  51. package/dist/core/mcp/client.js +16 -0
  52. package/dist/core/mcp/client.js.map +1 -1
  53. package/dist/core/mcp/init.d.ts +12 -0
  54. package/dist/core/mcp/init.d.ts.map +1 -0
  55. package/dist/core/mcp/init.js +55 -0
  56. package/dist/core/mcp/init.js.map +1 -0
  57. package/dist/core/mcp/logger.d.ts +14 -0
  58. package/dist/core/mcp/logger.d.ts.map +1 -0
  59. package/dist/core/mcp/logger.js +50 -0
  60. package/dist/core/mcp/logger.js.map +1 -0
  61. package/dist/core/tools/analyzePatterns.d.ts +3 -0
  62. package/dist/core/tools/analyzePatterns.d.ts.map +1 -0
  63. package/dist/core/tools/analyzePatterns.js +293 -0
  64. package/dist/core/tools/analyzePatterns.js.map +1 -0
  65. package/dist/core/tools/apexPaths.d.ts +14 -0
  66. package/dist/core/tools/apexPaths.d.ts.map +1 -0
  67. package/dist/core/tools/apexPaths.js +54 -0
  68. package/dist/core/tools/apexPaths.js.map +1 -0
  69. package/dist/core/tools/apexUtils.d.ts +36 -0
  70. package/dist/core/tools/apexUtils.d.ts.map +1 -0
  71. package/dist/core/tools/apexUtils.js +83 -0
  72. package/dist/core/tools/apexUtils.js.map +1 -0
  73. package/dist/core/tools/explainIssue.d.ts +3 -0
  74. package/dist/core/tools/explainIssue.d.ts.map +1 -0
  75. package/dist/core/tools/explainIssue.js +181 -0
  76. package/dist/core/tools/explainIssue.js.map +1 -0
  77. package/dist/core/tools/fixGen.d.ts +3 -0
  78. package/dist/core/tools/fixGen.d.ts.map +1 -0
  79. package/dist/core/tools/fixGen.js +338 -0
  80. package/dist/core/tools/fixGen.js.map +1 -0
  81. package/dist/core/tools/generateImprovements.d.ts +21 -0
  82. package/dist/core/tools/generateImprovements.d.ts.map +1 -0
  83. package/dist/core/tools/generateImprovements.js +602 -0
  84. package/dist/core/tools/generateImprovements.js.map +1 -0
  85. package/dist/core/tools/generateReport.d.ts +3 -0
  86. package/dist/core/tools/generateReport.d.ts.map +1 -0
  87. package/dist/core/tools/generateReport.js +315 -0
  88. package/dist/core/tools/generateReport.js.map +1 -0
  89. package/dist/core/tools/index.d.ts +7 -0
  90. package/dist/core/tools/index.d.ts.map +1 -1
  91. package/dist/core/tools/index.js +62 -23
  92. package/dist/core/tools/index.js.map +1 -1
  93. package/dist/core/tools/recommendProfile.d.ts +3 -0
  94. package/dist/core/tools/recommendProfile.d.ts.map +1 -0
  95. package/dist/core/tools/recommendProfile.js +334 -0
  96. package/dist/core/tools/recommendProfile.js.map +1 -0
  97. package/dist/core/tools/ruleGen.d.ts +3 -0
  98. package/dist/core/tools/ruleGen.d.ts.map +1 -0
  99. package/dist/core/tools/ruleGen.js +1103 -0
  100. package/dist/core/tools/ruleGen.js.map +1 -0
  101. package/dist/core/tools/standards.d.ts.map +1 -1
  102. package/dist/core/tools/standards.js +7 -3
  103. package/dist/core/tools/standards.js.map +1 -1
  104. package/dist/ui/App.d.ts.map +1 -1
  105. package/dist/ui/App.js +86 -35
  106. package/dist/ui/App.js.map +1 -1
  107. package/dist/ui/components/InputBox.d.ts +1 -3
  108. package/dist/ui/components/InputBox.d.ts.map +1 -1
  109. package/dist/ui/components/InputBox.js +146 -5
  110. package/dist/ui/components/InputBox.js.map +1 -1
  111. package/dist/ui/components/MessageList.d.ts +3 -1
  112. package/dist/ui/components/MessageList.d.ts.map +1 -1
  113. package/dist/ui/components/MessageList.js +13 -7
  114. package/dist/ui/components/MessageList.js.map +1 -1
  115. package/dist/ui/components/StatusBar.d.ts +1 -1
  116. package/dist/ui/components/StatusBar.d.ts.map +1 -1
  117. package/dist/ui/components/StatusBar.js +3 -2
  118. package/dist/ui/components/StatusBar.js.map +1 -1
  119. package/dist/ui/components/ToolStatus.d.ts +3 -1
  120. package/dist/ui/components/ToolStatus.d.ts.map +1 -1
  121. package/dist/ui/components/ToolStatus.js +19 -4
  122. package/dist/ui/components/ToolStatus.js.map +1 -1
  123. package/package.json +7 -1
  124. package/demo.gif +0 -0
  125. package/demo.tape +0 -53
  126. package/screenshot.png +0 -0
  127. package/src/cli/banner.ts +0 -38
  128. package/src/cli/headless.ts +0 -63
  129. package/src/cli/index.ts +0 -57
  130. package/src/core/agent.ts +0 -711
  131. package/src/core/commands.ts +0 -118
  132. package/src/core/config.ts +0 -98
  133. package/src/core/conversation.ts +0 -235
  134. package/src/core/llm/ollama.ts +0 -351
  135. package/src/core/mcp/client.ts +0 -143
  136. package/src/core/tools/analyzeAll.ts +0 -482
  137. package/src/core/tools/ast.ts +0 -826
  138. package/src/core/tools/builtIn.ts +0 -221
  139. package/src/core/tools/cache.ts +0 -570
  140. package/src/core/tools/cssAnalysis.ts +0 -324
  141. package/src/core/tools/dependencyAnalysis.ts +0 -363
  142. package/src/core/tools/embeddings.ts +0 -746
  143. package/src/core/tools/frontendAst.ts +0 -802
  144. package/src/core/tools/htmlAnalysis.ts +0 -466
  145. package/src/core/tools/index.ts +0 -160
  146. package/src/core/tools/javaAst.ts +0 -1030
  147. package/src/core/tools/javaQuality.integration.test.ts +0 -537
  148. package/src/core/tools/memory.ts +0 -655
  149. package/src/core/tools/mybatisAnalysis.ts +0 -322
  150. package/src/core/tools/openapiAnalysis.ts +0 -431
  151. package/src/core/tools/pythonAnalysis.ts +0 -477
  152. package/src/core/tools/sqlAnalysis.ts +0 -298
  153. package/src/core/tools/standards.test.ts +0 -186
  154. package/src/core/tools/standards.ts +0 -889
  155. package/src/core/tools/types.ts +0 -38
  156. package/src/ui/App.tsx +0 -334
  157. package/src/ui/components/InputBox.tsx +0 -37
  158. package/src/ui/components/MessageList.tsx +0 -80
  159. package/src/ui/components/StatusBar.tsx +0 -36
  160. package/src/ui/components/ToolStatus.tsx +0 -38
  161. package/tsconfig.json +0 -21
@@ -0,0 +1,455 @@
1
+ # Spring Development Standards Ruleset
2
+ # Spring / Spring Boot 개발 표준 규칙
3
+ # - DI 패턴 (생성자 주입 권장)
4
+ # - @Transactional 올바른 사용
5
+ # - Controller 계층 규칙
6
+ # - REST API 패턴
7
+ # - Bean 설정 패턴
8
+ # - 예외 처리 표준
9
+ # - 테스트 패턴
10
+ version: "1.0"
11
+ profile: "spring"
12
+
13
+ languages:
14
+ - language: java
15
+ rules:
16
+ # ==================== 1. DI 패턴 ====================
17
+
18
+ - id: "spring-di-001"
19
+ name: "@Autowired 필드 주입"
20
+ severity: "medium"
21
+ category: "dependency-injection"
22
+ description: "@Autowired 필드 주입은 테스트가 어렵고 순환 의존성을 숨깁니다. 생성자 주입을 사용하세요."
23
+ enabled: true
24
+ pattern:
25
+ type: "regex"
26
+ regex: "@Autowired\\s*$"
27
+ custom:
28
+ rule_id: "SPRING-DI-001"
29
+ fix: "생성자 주입(Constructor Injection)을 사용하세요. @RequiredArgsConstructor(Lombok)도 권장합니다."
30
+ example: "private final UserService userService; // 생성자에서 주입"
31
+
32
+ - id: "spring-di-002"
33
+ name: "@Inject 사용 (@Autowired 권장)"
34
+ severity: "low"
35
+ category: "dependency-injection"
36
+ description: "Spring 프로젝트에서는 @Inject보다 @Autowired 또는 생성자 주입이 일관성 있습니다."
37
+ enabled: true
38
+ pattern:
39
+ type: "regex"
40
+ regex: "@Inject\\s*$"
41
+ custom:
42
+ rule_id: "SPRING-DI-002"
43
+ fix: "생성자 주입 또는 @Autowired를 사용하세요"
44
+
45
+ - id: "spring-di-003"
46
+ name: "@Resource 필드 주입"
47
+ severity: "medium"
48
+ category: "dependency-injection"
49
+ description: "@Resource 필드 주입은 JSR-250 방식으로, Spring에서는 생성자 주입을 권장합니다."
50
+ enabled: true
51
+ pattern:
52
+ type: "regex"
53
+ regex: "@Resource\\s*$"
54
+ custom:
55
+ rule_id: "SPRING-DI-003"
56
+ fix: "생성자 주입(Constructor Injection)을 사용하세요"
57
+
58
+ # ==================== 2. @Transactional 관련 ====================
59
+
60
+ - id: "spring-tx-001"
61
+ name: "@Transactional 없는 Service public 메서드"
62
+ severity: "low"
63
+ category: "transaction"
64
+ description: "Service 클래스의 public 메서드에 @Transactional이 없으면 트랜잭션 관리가 되지 않을 수 있습니다."
65
+ enabled: false
66
+ pattern:
67
+ type: "regex"
68
+ regex: "(?<!@Transactional\\n\\s*)public\\s+(?!class\\b)\\w+\\s+\\w+\\s*\\("
69
+ custom:
70
+ rule_id: "SPRING-TX-001"
71
+ fix: "Service 메서드에 @Transactional 또는 @Transactional(readOnly=true)를 추가하세요"
72
+
73
+ - id: "spring-tx-002"
74
+ name: "private 메서드에 @Transactional"
75
+ severity: "high"
76
+ category: "transaction"
77
+ description: "private 메서드의 @Transactional은 프록시 기반 AOP에서 동작하지 않습니다."
78
+ enabled: true
79
+ pattern:
80
+ type: "regex-multiline"
81
+ regex: "@Transactional[^}]*?\\n\\s*private\\s+"
82
+ custom:
83
+ rule_id: "SPRING-TX-002"
84
+ fix: "public 메서드로 변경하거나, 별도 Bean으로 분리하세요"
85
+
86
+ - id: "spring-tx-003"
87
+ name: "@Transactional 내 try-catch로 예외 삼킴"
88
+ severity: "high"
89
+ category: "transaction"
90
+ description: "@Transactional 메서드에서 catch로 예외를 삼키면 롤백이 발생하지 않습니다."
91
+ enabled: true
92
+ pattern:
93
+ type: "regex-multiline"
94
+ regex: "@Transactional[\\s\\S]*?catch\\s*\\([^)]*\\)\\s*\\{[^}]*\\}"
95
+ custom:
96
+ rule_id: "SPRING-TX-003"
97
+ fix: "catch 블록에서 예외를 재throw하거나, @Transactional(noRollbackFor=...)를 명시하세요"
98
+
99
+ - id: "spring-tx-004"
100
+ name: "@Transactional 메서드 내 외부 API 호출"
101
+ severity: "high"
102
+ category: "transaction"
103
+ description: "@Transactional 메서드에서 외부 API를 호출하면 긴 트랜잭션/데드락/타임아웃 위험이 있습니다."
104
+ enabled: true
105
+ pattern:
106
+ type: "ast-method-call"
107
+ method: "exchange|execute|getForObject|getForEntity|postForObject|postForEntity|put|delete|patchForObject|send|retrieve|block|call|newCall"
108
+ qualifier: ".*[Rr]est[Tt]emplate|.*[Ww]eb[Cc]lient|.*[Hh]ttp[Cc]lient|.*[Oo]k[Hh]ttp.*|.*[Ff]eign.*"
109
+ context: "has-method-annotation:Transactional"
110
+ custom:
111
+ rule_id: "SPRING-TX-004"
112
+ fix: "외부 API 호출을 트랜잭션 밖으로 분리하거나 @Transactional(propagation=NOT_SUPPORTED)를 사용하세요"
113
+
114
+ - id: "spring-tx-005"
115
+ name: "@Transactional 누락 (다건 CUD)"
116
+ severity: "high"
117
+ category: "transaction"
118
+ description: "2개 이상의 CUD 작업을 호출하지만 @Transactional이 없어 데이터 정합성이 보장되지 않습니다."
119
+ enabled: true
120
+ pattern:
121
+ type: "ast-multi-cud"
122
+ method: "insert|update|delete|save|remove|create|modify"
123
+ qualifier: ".*Dao|.*Repository|.*Mapper|.*Service"
124
+ custom:
125
+ min_cud_calls: 2
126
+ rule_id: "SPRING-TX-005"
127
+ fix: "@Transactional을 추가하거나, 트랜잭션이 있는 메서드로 위임하세요"
128
+
129
+ # ==================== 3. Controller 계층 규칙 ====================
130
+
131
+ - id: "spring-ctrl-001"
132
+ name: "Controller에서 Repository/Mapper 직접 주입"
133
+ severity: "high"
134
+ category: "architecture"
135
+ description: "Controller에서 Repository/Mapper를 직접 사용하면 계층 구조(Controller→Service→Repository)를 위반합니다."
136
+ enabled: true
137
+ pattern:
138
+ type: "regex-multiline"
139
+ regex: "@(Controller|RestController)[\\s\\S]*?(Repository|Mapper|DAO)\\s+\\w+\\s*;"
140
+ custom:
141
+ rule_id: "SPRING-CTRL-001"
142
+ fix: "Service 레이어를 통해 데이터 접근하세요"
143
+
144
+ - id: "spring-ctrl-002"
145
+ name: "Controller에서 직접 SQL/JDBC 사용"
146
+ severity: "critical"
147
+ category: "architecture"
148
+ description: "Controller에서 직접 SQL이나 JdbcTemplate을 사용하면 계층 아키텍처를 심각하게 위반합니다."
149
+ enabled: true
150
+ pattern:
151
+ type: "regex-multiline"
152
+ regex: "@(Controller|RestController)[\\s\\S]*?(JdbcTemplate|DataSource|SqlSession)\\s+\\w+"
153
+ custom:
154
+ rule_id: "SPRING-CTRL-002"
155
+ fix: "데이터 접근 로직을 Service/Repository 레이어로 이동하세요"
156
+
157
+ - id: "spring-ctrl-003"
158
+ name: "Controller 메서드에서 HttpServletRequest/Response 직접 사용"
159
+ severity: "medium"
160
+ category: "design"
161
+ description: "Controller에서 HttpServletRequest/Response를 직접 사용하면 테스트가 어렵습니다. Spring MVC 추상화를 사용하세요."
162
+ enabled: true
163
+ pattern:
164
+ type: "regex"
165
+ regex: "\\b(HttpServletRequest|HttpServletResponse)\\s+\\w+\\s*[,)]"
166
+ custom:
167
+ rule_id: "SPRING-CTRL-003"
168
+ fix: "@RequestParam, @RequestBody, @PathVariable, ResponseEntity 등 Spring 추상화를 사용하세요"
169
+
170
+ - id: "spring-ctrl-004"
171
+ name: "Controller에서 HttpSession 직접 사용"
172
+ severity: "medium"
173
+ category: "design"
174
+ description: "Controller에서 HttpSession을 직접 사용하면 스케일아웃이 어렵습니다. Spring Session이나 @SessionAttributes를 사용하세요."
175
+ enabled: true
176
+ pattern:
177
+ type: "regex"
178
+ regex: "\\bHttpSession\\s+\\w+\\s*[,)]"
179
+ custom:
180
+ rule_id: "SPRING-CTRL-004"
181
+ fix: "@SessionAttributes, Spring Session, 또는 SecurityContextHolder를 사용하세요"
182
+
183
+ - id: "spring-ctrl-005"
184
+ name: "Controller에서 비즈니스 로직 수행"
185
+ severity: "medium"
186
+ category: "architecture"
187
+ description: "Controller에서 조건 분기나 데이터 가공 등 비즈니스 로직이 포함되어 있습니다."
188
+ enabled: true
189
+ pattern:
190
+ type: "ast-class"
191
+ name_pattern: ".*Controller$"
192
+ custom:
193
+ max_methods: 15
194
+ rule_id: "SPRING-CTRL-005"
195
+ fix: "비즈니스 로직을 Service 레이어로 이동하세요"
196
+
197
+ # ==================== 4. REST API 패턴 ====================
198
+
199
+ - id: "spring-rest-001"
200
+ name: "@Controller + @ResponseBody 대신 @RestController 사용"
201
+ severity: "low"
202
+ category: "rest-api"
203
+ description: "@Controller와 @ResponseBody를 같이 쓰는 대신 @RestController를 사용하세요."
204
+ enabled: true
205
+ pattern:
206
+ type: "regex-multiline"
207
+ regex: "@Controller[\\s\\S]{0,200}@ResponseBody"
208
+ custom:
209
+ rule_id: "SPRING-REST-001"
210
+ fix: "클래스 레벨에 @RestController를 사용하세요"
211
+
212
+ - id: "spring-rest-002"
213
+ name: "REST API에서 void 반환"
214
+ severity: "medium"
215
+ category: "rest-api"
216
+ description: "REST API 메서드가 void를 반환하면 응답 상태와 본문을 제어할 수 없습니다. ResponseEntity를 사용하세요."
217
+ enabled: true
218
+ pattern:
219
+ type: "regex-multiline"
220
+ regex: "@(GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping).*\\n\\s*public\\s+void\\s+"
221
+ custom:
222
+ rule_id: "SPRING-REST-002"
223
+ fix: "ResponseEntity<T>를 반환 타입으로 사용하세요"
224
+
225
+ - id: "spring-rest-003"
226
+ name: "PrintWriter로 직접 응답 출력"
227
+ severity: "high"
228
+ category: "rest-api"
229
+ description: "PrintWriter로 직접 응답을 출력하면 인코딩 문제와 XSS 취약점이 발생할 수 있습니다."
230
+ enabled: true
231
+ pattern:
232
+ type: "regex"
233
+ regex: "response\\.getWriter\\s*\\(\\s*\\)\\.print"
234
+ custom:
235
+ rule_id: "SPRING-REST-003"
236
+ fix: "ResponseEntity 또는 @ResponseBody를 사용하세요. JSON은 Jackson이 자동 처리합니다."
237
+
238
+ - id: "spring-rest-004"
239
+ name: "Map<String, Object> 응답 반환"
240
+ severity: "medium"
241
+ category: "rest-api"
242
+ description: "REST API에서 Map<String, Object>를 반환하면 API 문서화가 불가능하고 클라이언트 개발이 어렵습니다."
243
+ enabled: true
244
+ pattern:
245
+ type: "regex-multiline"
246
+ regex: "@(GetMapping|PostMapping|PutMapping|DeleteMapping|RequestMapping)[^{]*\\n[^{]*Map<String,\\s*Object>"
247
+ custom:
248
+ rule_id: "SPRING-REST-004"
249
+ fix: "전용 Response DTO 클래스를 정의하여 반환하세요"
250
+
251
+ # ==================== 5. Bean 설정/스코프 ====================
252
+
253
+ - id: "spring-bean-001"
254
+ name: "Controller 멤버 변수 (상태 보유)"
255
+ severity: "critical"
256
+ category: "thread-safety"
257
+ description: "Controller는 싱글톤 스코프이므로 인스턴스 변수에 요청별 데이터를 저장하면 스레드 안전성 문제가 발생합니다."
258
+ enabled: true
259
+ pattern:
260
+ type: "regex-multiline"
261
+ regex: "@(Controller|RestController)[\\s\\S]*?\\bprivate\\s+(?!(?:static\\s+final|final\\s+static)\\b)(?!.*Service\\b)(?!.*Mapper\\b)(?!.*Repository\\b)(?!.*Logger\\b)(String|int|long|boolean|Integer|Long|Boolean|List|Map|Set)\\s+\\w+\\s*[;=]"
262
+ custom:
263
+ rule_id: "SPRING-BEAN-001"
264
+ fix: "요청별 데이터는 메서드 지역변수나 RequestScope Bean으로 관리하세요"
265
+
266
+ - id: "spring-bean-002"
267
+ name: "prototype 빈을 singleton에 주입"
268
+ severity: "high"
269
+ category: "thread-safety"
270
+ description: "@Scope(\"prototype\") 빈을 싱글톤 빈에 주입하면 프로토타입 효과가 없습니다."
271
+ enabled: true
272
+ pattern:
273
+ type: "regex"
274
+ regex: "@Scope\\s*\\(\\s*\"prototype\"\\s*\\)"
275
+ custom:
276
+ rule_id: "SPRING-BEAN-002"
277
+ fix: "ObjectFactory<T> 또는 Provider<T>를 통해 매번 새 인스턴스를 생성하세요"
278
+
279
+ # ==================== 6. 예외 처리 ====================
280
+
281
+ - id: "spring-ex-001"
282
+ name: "Controller에서 직접 try-catch"
283
+ severity: "medium"
284
+ category: "exception"
285
+ description: "Controller에서 직접 try-catch하는 대신 @ExceptionHandler 또는 @ControllerAdvice를 사용하세요."
286
+ enabled: true
287
+ pattern:
288
+ type: "regex-multiline"
289
+ regex: "@(GetMapping|PostMapping|PutMapping|DeleteMapping|RequestMapping)[\\s\\S]{0,500}?try\\s*\\{"
290
+ custom:
291
+ rule_id: "SPRING-EX-001"
292
+ fix: "@ControllerAdvice + @ExceptionHandler로 전역 예외 처리하세요"
293
+
294
+ - id: "spring-ex-002"
295
+ name: "RuntimeException 직접 throw"
296
+ severity: "medium"
297
+ category: "exception"
298
+ description: "범용 RuntimeException 대신 비즈니스 예외 클래스를 정의하여 사용하세요."
299
+ enabled: true
300
+ pattern:
301
+ type: "regex"
302
+ regex: "throw\\s+new\\s+RuntimeException\\s*\\("
303
+ custom:
304
+ rule_id: "SPRING-EX-002"
305
+ fix: "BusinessException, CustomException 등 도메인 예외 클래스를 정의하세요"
306
+
307
+ - id: "spring-ex-003"
308
+ name: "catch(Exception e) 광범위 예외"
309
+ severity: "medium"
310
+ category: "exception"
311
+ description: "최상위 Exception을 catch하면 의도치 않은 예외까지 처리됩니다. 구체적인 예외 타입을 사용하세요."
312
+ enabled: false # secure-err-005와 동일 regex 중복
313
+ pattern:
314
+ type: "regex"
315
+ regex: "catch\\s*\\(\\s*Exception\\s+\\w+\\s*\\)"
316
+ custom:
317
+ rule_id: "SPRING-EX-003"
318
+ fix: "구체적인 예외 타입(IOException, SQLException 등)을 catch하세요"
319
+
320
+ # ==================== 7. 테스트 패턴 ====================
321
+
322
+ - id: "spring-test-001"
323
+ name: "@SpringBootTest 불필요 사용"
324
+ severity: "low"
325
+ category: "testing"
326
+ description: "단위 테스트에 @SpringBootTest를 사용하면 전체 컨텍스트가 로드되어 느립니다."
327
+ enabled: true
328
+ pattern:
329
+ type: "regex"
330
+ regex: "@SpringBootTest"
331
+ custom:
332
+ rule_id: "SPRING-TEST-001"
333
+ fix: "단위 테스트: @ExtendWith(MockitoExtension.class), 슬라이스 테스트: @WebMvcTest, @DataJpaTest 사용"
334
+
335
+ - id: "spring-test-002"
336
+ name: "Thread.sleep() 테스트"
337
+ severity: "medium"
338
+ category: "testing"
339
+ description: "테스트에서 Thread.sleep()을 사용하면 불안정하고 느립니다. Awaitility 등을 사용하세요."
340
+ enabled: true
341
+ pattern:
342
+ type: "regex"
343
+ regex: "Thread\\.sleep\\s*\\("
344
+ custom:
345
+ rule_id: "SPRING-TEST-002"
346
+ fix: "Awaitility.await() 또는 CountDownLatch를 사용하세요"
347
+
348
+ - id: "spring-test-003"
349
+ name: "@Transactional 테스트 주의"
350
+ severity: "low"
351
+ category: "testing"
352
+ description: "테스트 클래스의 @Transactional은 테스트 후 자동 롤백되어, 실제 커밋 동작을 검증하지 못할 수 있습니다."
353
+ enabled: false
354
+ pattern:
355
+ type: "regex-multiline"
356
+ regex: "@Transactional[\\s\\S]*?@Test"
357
+ custom:
358
+ rule_id: "SPRING-TEST-003"
359
+ fix: "통합 테스트에서는 @Transactional 사용을 재고하세요. 데이터 정리는 @AfterEach로 처리하세요."
360
+
361
+ # ==================== 8. 보안/인증 ====================
362
+
363
+ - id: "spring-sec-001"
364
+ name: "CORS 전체 허용"
365
+ severity: "high"
366
+ category: "security"
367
+ description: "@CrossOrigin(\"*\")은 모든 도메인에서 접근을 허용하여 보안에 취약합니다."
368
+ enabled: true
369
+ pattern:
370
+ type: "regex"
371
+ regex: "@CrossOrigin\\s*\\(\\s*[\"']\\*[\"']\\s*\\)"
372
+ custom:
373
+ rule_id: "SPRING-SEC-001"
374
+ fix: "허용할 도메인을 명시적으로 지정하세요: @CrossOrigin(origins = \"https://example.com\")"
375
+
376
+ - id: "spring-sec-002"
377
+ name: "CSRF 비활성화"
378
+ severity: "high"
379
+ category: "security"
380
+ description: "CSRF 보호를 비활성화하면 CSRF 공격에 취약합니다. REST API가 아닌 경우 활성화하세요."
381
+ enabled: true
382
+ pattern:
383
+ type: "regex"
384
+ regex: "\\.csrf\\s*\\(\\s*\\)\\s*\\.disable\\s*\\("
385
+ custom:
386
+ rule_id: "SPRING-SEC-002"
387
+ fix: "REST API(토큰 인증)가 아닌 경우 CSRF 보호를 유지하세요"
388
+
389
+ # ==================== XML: Spring Security 설정 감사 ====================
390
+ - language: xml
391
+ rules:
392
+ - id: "spring-sec-cfg-001"
393
+ name: "Spring Security: ROLE 분리 없이 isAuthenticated() 단일 정책"
394
+ severity: "medium"
395
+ category: "security-config"
396
+ description: "모든 URL에 isAuthenticated()만 적용하고 hasRole()/hasAuthority()로 권한을 분리하지 않으면, 로그인한 사용자 누구나 관리자 기능에 접근할 수 있습니다."
397
+ enabled: true
398
+ pattern:
399
+ type: "regex"
400
+ regex: "intercept-url\\s+pattern=\"/\\*\\*\"\\s+access=\"isAuthenticated\\(\\)\""
401
+ custom:
402
+ rule_id: "SPRING-SEC-CFG-001"
403
+ fix: "관리자(/admin/**), 일반 사용자(/user/**) 등 URL 패턴별로 hasRole() 또는 hasAuthority()를 분리하세요."
404
+
405
+ - id: "spring-sec-cfg-002"
406
+ name: "Spring Security: XML에서 CSRF 비활성화"
407
+ severity: "high"
408
+ category: "security-config"
409
+ description: "Spring Security XML 설정에서 CSRF 보호가 비활성화되어 있습니다. 세션 기반 인증(JSP)에서는 CSRF 토큰이 필수입니다."
410
+ enabled: true
411
+ pattern:
412
+ type: "regex"
413
+ regex: "<csrf\\s+disabled=\"true\"\\s*/>"
414
+ custom:
415
+ rule_id: "SPRING-SEC-CFG-002"
416
+ fix: "CSRF 보호를 활성화하세요. JSP에서는 <input type='hidden' name='${_csrf.parameterName}' value='${_csrf.token}'/> 추가 필요."
417
+
418
+ - id: "spring-sec-cfg-003"
419
+ name: "Spring Security: security=\"none\" 광범위 패턴"
420
+ severity: "medium"
421
+ category: "security-config"
422
+ description: "security=\"none\"이 광범위한 URL 패턴(/**, /api/**, /edu/** 등)에 적용되어 해당 경로의 모든 요청이 인증 없이 접근 가능합니다."
423
+ enabled: true
424
+ pattern:
425
+ type: "regex"
426
+ regex: "<http\\s+pattern=\"[^\"]*\\*\\*[^\"]*\"\\s+security=\"none\""
427
+ custom:
428
+ rule_id: "SPRING-SEC-CFG-003"
429
+ fix: "security=\"none\"은 정적 리소스(/css/**, /js/**, /images/**)에만 사용하고, 비즈니스 URL에는 permitAll()을 사용하세요."
430
+
431
+ - id: "spring-sec-cfg-004"
432
+ name: "Spring Security: 단일 intercept-url로 전체 URL 커버"
433
+ severity: "low"
434
+ category: "security-config"
435
+ description: "intercept-url이 pattern=\"/**\" 하나만 있어, URL별 세분화된 접근 제어가 없습니다. spring-sec-cfg-001과 함께 확인하세요."
436
+ enabled: false
437
+ pattern:
438
+ type: "regex"
439
+ regex: "intercept-url\\s+pattern=\"/\\*\\*\""
440
+ custom:
441
+ rule_id: "SPRING-SEC-CFG-004"
442
+ fix: "URL 패턴별로 intercept-url을 분리하여 세분화된 접근 제어를 적용하세요."
443
+
444
+ - id: "spring-sec-cfg-005"
445
+ name: "Spring Security 4.x 이하 (EOL) 사용"
446
+ severity: "high"
447
+ category: "security-config"
448
+ description: "Spring Security 4.x 이하 스키마를 사용하고 있습니다. Spring Security 4.x는 EOL(End of Life)로 보안 패치를 받지 못합니다."
449
+ enabled: true
450
+ pattern:
451
+ type: "regex"
452
+ regex: "spring-security-[1-4]\\.[0-9]+\\.xsd"
453
+ custom:
454
+ rule_id: "SPRING-SEC-CFG-005"
455
+ fix: "Spring Security 5.x 이상으로 업그레이드하세요. eGovFrame 4.x는 Spring Security 5.x를 지원합니다."
@@ -0,0 +1,99 @@
1
+ # SQL Format/Style Ruleset
2
+ # SQL 포맷팅 및 코딩 스타일 강제 규칙 (팀별 선택 적용)
3
+ # 사용법: apex ./src --profile=sql-format
4
+ version: "1.0"
5
+ profile: "sql-format"
6
+
7
+ languages:
8
+ - language: sql
9
+ rules:
10
+ # ==================== SQL 포맷 규칙 (7개) ====================
11
+
12
+ - id: "sql-fmt-001"
13
+ name: "SQL 키워드 대문자"
14
+ severity: "low"
15
+ category: "format"
16
+ description: "SQL 키워드는 모두 대문자로 작성해야 합니다."
17
+ enabled: true
18
+ pattern:
19
+ type: "regex"
20
+ regex: "\\b(select|from|where|and|or|insert|update|delete|join|order|group|having|union|into|values|set)\\b"
21
+ custom:
22
+ rule_id: "SQL-FMT-001"
23
+
24
+ - id: "sql-fmt-002"
25
+ name: "라인 길이 80자 초과"
26
+ severity: "low"
27
+ category: "format"
28
+ description: "한 라인 80자 초과는 가독성을 저해합니다."
29
+ enabled: true
30
+ pattern:
31
+ type: "line-length"
32
+ max_length: 80
33
+ custom:
34
+ rule_id: "SQL-FMT-002"
35
+
36
+ - id: "sql-fmt-003"
37
+ name: "SQL 내 공백 라인"
38
+ severity: "low"
39
+ category: "format"
40
+ description: "SQL 중간에 빈 라인이 있으면 안됩니다."
41
+ enabled: true
42
+ pattern:
43
+ type: "method-analysis"
44
+ conditions:
45
+ - "sql-contains-blank-line"
46
+ custom:
47
+ rule_id: "SQL-FMT-003"
48
+
49
+ - id: "sql-sel-004"
50
+ name: "다중 컬럼 한 라인"
51
+ severity: "low"
52
+ category: "select"
53
+ description: "한 라인에 하나의 컬럼만 기술하세요."
54
+ enabled: true
55
+ pattern:
56
+ type: "method-analysis"
57
+ conditions:
58
+ - "multiple-columns-one-line"
59
+ custom:
60
+ rule_id: "SQL-SEL-004"
61
+
62
+ - id: "sql-from-005"
63
+ name: "다중 테이블 한 라인"
64
+ severity: "low"
65
+ category: "from"
66
+ description: "한 라인에 하나의 테이블만 기술하세요."
67
+ enabled: true
68
+ pattern:
69
+ type: "method-analysis"
70
+ conditions:
71
+ - "multiple-tables-one-line"
72
+ custom:
73
+ rule_id: "SQL-FROM-005"
74
+
75
+ - id: "sql-where-007"
76
+ name: "다중 조건 한 라인"
77
+ severity: "low"
78
+ category: "where"
79
+ description: "한 라인에 하나의 조건만 기술하세요."
80
+ enabled: true
81
+ pattern:
82
+ type: "method-analysis"
83
+ conditions:
84
+ - "multiple-conditions-one-line"
85
+ custom:
86
+ rule_id: "SQL-WHERE-007"
87
+
88
+ - id: "sql-sel-006"
89
+ name: "컬럼 주석 형식"
90
+ severity: "low"
91
+ category: "select"
92
+ description: "컬럼 주석은 /* */ 형식을 사용하세요."
93
+ enabled: true
94
+ pattern:
95
+ type: "method-analysis"
96
+ conditions:
97
+ - "column-comment-not-block-style"
98
+ custom:
99
+ rule_id: "SQL-SEL-006"