archrisk-engine 1.0.2 → 1.0.3

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,160 @@
1
+ export declare const LOCALES: {
2
+ en: {
3
+ 'RR-SEC-001': {
4
+ title: string;
5
+ category: string;
6
+ standard: string;
7
+ impact: string;
8
+ action: string;
9
+ reference: string;
10
+ whenItMatters: string;
11
+ };
12
+ 'RR-TEST-001': {
13
+ title: string;
14
+ category: string;
15
+ evidence: string;
16
+ standard: string;
17
+ impact: string;
18
+ action: string;
19
+ reference: string;
20
+ whenItMatters: string;
21
+ };
22
+ 'RR-CI-001': {
23
+ title: string;
24
+ category: string;
25
+ evidence: string;
26
+ standard: string;
27
+ impact: string;
28
+ action: string;
29
+ reference: string;
30
+ whenItMatters: string;
31
+ };
32
+ 'RR-OPS-001': {
33
+ title: string;
34
+ category: string;
35
+ standard: string;
36
+ impact: string;
37
+ action: string;
38
+ reference: string;
39
+ whenItMatters: string;
40
+ };
41
+ 'RR-LOG-001': {
42
+ title: string;
43
+ category: string;
44
+ evidence: string;
45
+ standard: string;
46
+ impact: string;
47
+ action: string;
48
+ reference: string;
49
+ whenItMatters: string;
50
+ };
51
+ 'RR-DEP-001': {
52
+ title: string;
53
+ category: string;
54
+ standard: string;
55
+ impact: string;
56
+ action: string;
57
+ reference: string;
58
+ whenItMatters: string;
59
+ };
60
+ 'RR-LINT-001': {
61
+ title: string;
62
+ category: string;
63
+ standard: string;
64
+ impact: string;
65
+ action: string;
66
+ reference: string;
67
+ whenItMatters: string;
68
+ };
69
+ DEFAULT: {
70
+ title: string;
71
+ category: string;
72
+ standard: string;
73
+ impact: string;
74
+ action: string;
75
+ reference: string;
76
+ whenItMatters: string;
77
+ };
78
+ DISCLOSURE: string;
79
+ CTA: string;
80
+ };
81
+ ko: {
82
+ 'RR-SEC-001': {
83
+ title: string;
84
+ category: string;
85
+ standard: string;
86
+ impact: string;
87
+ action: string;
88
+ reference: string;
89
+ whenItMatters: string;
90
+ };
91
+ 'RR-TEST-001': {
92
+ title: string;
93
+ category: string;
94
+ evidence: string;
95
+ standard: string;
96
+ impact: string;
97
+ action: string;
98
+ reference: string;
99
+ whenItMatters: string;
100
+ };
101
+ 'RR-CI-001': {
102
+ title: string;
103
+ category: string;
104
+ evidence: string;
105
+ standard: string;
106
+ impact: string;
107
+ action: string;
108
+ reference: string;
109
+ whenItMatters: string;
110
+ };
111
+ 'RR-OPS-001': {
112
+ title: string;
113
+ category: string;
114
+ standard: string;
115
+ impact: string;
116
+ action: string;
117
+ reference: string;
118
+ whenItMatters: string;
119
+ };
120
+ 'RR-LOG-001': {
121
+ title: string;
122
+ category: string;
123
+ evidence: string;
124
+ standard: string;
125
+ impact: string;
126
+ action: string;
127
+ reference: string;
128
+ whenItMatters: string;
129
+ };
130
+ 'RR-DEP-001': {
131
+ title: string;
132
+ category: string;
133
+ standard: string;
134
+ impact: string;
135
+ action: string;
136
+ reference: string;
137
+ whenItMatters: string;
138
+ };
139
+ 'RR-LINT-001': {
140
+ title: string;
141
+ category: string;
142
+ standard: string;
143
+ impact: string;
144
+ action: string;
145
+ reference: string;
146
+ whenItMatters: string;
147
+ };
148
+ DEFAULT: {
149
+ title: string;
150
+ category: string;
151
+ standard: string;
152
+ impact: string;
153
+ action: string;
154
+ reference: string;
155
+ whenItMatters: string;
156
+ };
157
+ DISCLOSURE: string;
158
+ CTA: string;
159
+ };
160
+ };
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOCALES = void 0;
4
+ exports.LOCALES = {
5
+ en: {
6
+ 'RR-SEC-001': {
7
+ title: "Security Vulnerability Detected",
8
+ category: 'Security',
9
+ standard: "OWASP Top 10 A03:2021 – Injection",
10
+ impact: "Potential for unauthorized access or data leakage through injection attacks.",
11
+ action: `
12
+ # Action: Isolate and use Environment Variables
13
+ subprocess.run(..., shell=False) # Recommended
14
+ # Or use .env file
15
+ import os
16
+ SECRET = os.getenv('MY_SECRET')
17
+ `,
18
+ reference: "https://docs.python.org/3/library/subprocess.html#security-considerations",
19
+ whenItMatters: "Immediately upon deployment, as scanners can detect this."
20
+ },
21
+ 'RR-TEST-001': {
22
+ title: "Missing Automated Tests",
23
+ category: 'Service Interruption',
24
+ evidence: "No tests/ directory or pytest/unittest configuration found.",
25
+ standard: "pytest Framework Documentation",
26
+ impact: "Unable to verify if validation logic breaks existing features. High risk of regression.",
27
+ action: `
28
+ # Action: Create tests/test_smoke.py
29
+ def test_health_check():
30
+ assert True # Basic sanity check
31
+ `,
32
+ reference: "https://docs.pytest.org/",
33
+ whenItMatters: "When team size > 2 or deployment frequency increases."
34
+ },
35
+ 'RR-CI-001': {
36
+ title: "Missing CI Pipeline",
37
+ category: 'Service Interruption',
38
+ evidence: "No GitHub Actions (.github/workflows/*.yml) or CI configuration found.",
39
+ standard: "GitHub Actions Documentation",
40
+ impact: "Manual deployments are prone to human error and lack consistency.",
41
+ action: `
42
+ # Action: Create .github/workflows/ci.yml
43
+ name: CI
44
+ on: [push]
45
+ jobs:
46
+ test:
47
+ runs-on: ubuntu-latest
48
+ steps:
49
+ - uses: actions/checkout@v3
50
+ - run: npm test
51
+ `,
52
+ reference: "https://docs.github.com/en/actions",
53
+ whenItMatters: "When deploying more than twice a week."
54
+ },
55
+ 'RR-OPS-001': {
56
+ title: "Project Hygiene Check Failed",
57
+ category: 'Service Interruption',
58
+ standard: "12-Factor App / Docker Documentation",
59
+ impact: "Inconsistency between dev and prod environments (\"It works on my machine\").",
60
+ action: `
61
+ # Checklist to Fix:
62
+ 1. Create 'Dockerfile'
63
+ 2. Create '.gitignore' (use gitignore.io)
64
+ 3. Create 'requirements.txt' or 'package.json'
65
+ 4. Create '.env.example'
66
+ `,
67
+ reference: "https://12factor.net/",
68
+ whenItMatters: "Onboarding new members or migrating servers."
69
+ },
70
+ 'RR-LOG-001': {
71
+ title: "Insufficient Logging",
72
+ category: 'Maintenance',
73
+ evidence: "No logging configuration (logging, loguru) found in codebase.",
74
+ standard: "Python Logging Cookbook",
75
+ impact: "Zero visibility into runtime errors, making debugging impossible during outages.",
76
+ action: `
77
+ # Action: Python Logging Setup
78
+ import logging
79
+ logging.basicConfig(level=logging.INFO)
80
+ logger = logging.getLogger(__name__)
81
+ logger.info("Server started")
82
+ `,
83
+ reference: "https://docs.python.org/3/howto/logging-cookbook.html",
84
+ whenItMatters: "When a 500 error occurs in production."
85
+ },
86
+ 'RR-DEP-001': {
87
+ title: "Structural Dependency Issue",
88
+ category: 'Scalability',
89
+ standard: "Clean Architecture: Dependency Rule",
90
+ impact: "High coupling between modules makes maintenance difficult and increases side effects.",
91
+ action: "Refactor to decouple modules or extract common logic.",
92
+ reference: "https://refactoring.guru/design-patterns",
93
+ whenItMatters: "As the codebase grows, refactoring costs explode."
94
+ },
95
+ 'RR-LINT-001': {
96
+ title: "God Module Detected",
97
+ category: 'Maintenance',
98
+ standard: "Clean Code: Functions",
99
+ impact: "Single file has too many responsibilities, making changes risky.",
100
+ action: "Split file based on responsibilities (Separation of Concerns).",
101
+ reference: "https://pypi.org/project/flake8/",
102
+ whenItMatters: "When every feature addition causes a regression bug."
103
+ },
104
+ 'DEFAULT': {
105
+ title: "Other Potential Risks",
106
+ category: 'Maintenance',
107
+ standard: "General Coding Best Practices",
108
+ impact: "Potential bugs or maintenance debt.",
109
+ action: "Review and consider refactoring.",
110
+ reference: "#",
111
+ whenItMatters: "When code quality starts to degrade."
112
+ },
113
+ 'DISCLOSURE': "Pre-deploy audit complete. Detected risks may cause service interruptions or data loss in production.",
114
+ 'CTA': "Automate this ritual. Install the GitHub App to manage Release Readiness continuously."
115
+ },
116
+ ko: {
117
+ 'RR-SEC-001': {
118
+ title: "보안 취약점 위험 (Security Vulnerability)",
119
+ category: 'Security',
120
+ standard: "OWASP Top 10 A03:2021 – Injection",
121
+ impact: "외부 공격자가 시스템 권한을 탈취하거나 민감 정보를 유출할 수 있는 조건이 형성됩니다.",
122
+ action: `
123
+ # Action: 격리 및 환경변수 사용
124
+ subprocess.run(..., shell=False) # 권장
125
+ # 또는 .env 파일 사용
126
+ import os
127
+ SECRET = os.getenv('MY_SECRET')
128
+ `,
129
+ reference: "https://docs.python.org/3/library/subprocess.html#security-considerations",
130
+ whenItMatters: "배포 즉시 자동화된 스캐너나 공격자에 의해 탐지될 수 있습니다."
131
+ },
132
+ 'RR-TEST-001': {
133
+ title: "자동화 테스트 부재 (Missing Automated Tests)",
134
+ category: 'Service Interruption',
135
+ evidence: "tests/ 디렉토리 또는 pytest/unittest 관련 설정을 찾을 수 없습니다.",
136
+ standard: "pytest Framework Documentation",
137
+ impact: "코드 변경 시 기존 기능이 파괴되었는지 확인할 방법이 없어, 배포 후 장애 발생 확률이 높아집니다.",
138
+ action: `
139
+ # Action: Create tests/test_smoke.py
140
+ def test_health_check():
141
+ assert True # Basic sanity check
142
+ `,
143
+ reference: "https://docs.pytest.org/",
144
+ whenItMatters: "팀원이 2명 이상으로 늘어나거나 배포 주기가 빨라질 때."
145
+ },
146
+ 'RR-CI-001': {
147
+ title: "배포 자동화 파이프라인 부재 (Missing CI Pipeline)",
148
+ category: 'Service Interruption',
149
+ evidence: "GitHub Actions (.github/workflows/*.yml) 또는 CI 설정 파일이 없습니다.",
150
+ standard: "GitHub Actions Documentation",
151
+ impact: "사람의 수동 배포 과정에서 실수가 발생할 수 있으며, 일관된 배포 상태를 보장할 수 없습니다.",
152
+ action: `
153
+ # Action: Create .github/workflows/ci.yml
154
+ name: CI
155
+ on: [push]
156
+ jobs:
157
+ test:
158
+ runs-on: ubuntu-latest
159
+ steps:
160
+ - uses: actions/checkout@v3
161
+ - run: npm test
162
+ `,
163
+ reference: "https://docs.github.com/en/actions",
164
+ whenItMatters: "배포 빈도가 주 2회 이상으로 증가할 때."
165
+ },
166
+ 'RR-OPS-001': {
167
+ title: "운영 기본 위생 체크 실패 (Project Hygiene)",
168
+ category: 'Service Interruption',
169
+ standard: "12-Factor App / Docker Documentation",
170
+ impact: "개발 환경과 운영 환경의 불일치로 인해 '내 컴퓨터에서는 되는데 서버에서는 안 되는' 문제가 발생합니다.",
171
+ action: `
172
+ # Checklist to Fix:
173
+ 1. Create 'Dockerfile'
174
+ 2. Create '.gitignore' (use gitignore.io)
175
+ 3. Create 'requirements.txt' or 'package.json'
176
+ 4. Create '.env.example'
177
+ `,
178
+ reference: "https://12factor.net/",
179
+ whenItMatters: "신규 입사자 온보딩 또는 서버 이관 시."
180
+ },
181
+ 'RR-LOG-001': {
182
+ title: "로깅 설정 미흡 (Insufficient Logging)",
183
+ category: 'Maintenance',
184
+ evidence: "코드 내에서 로깅 설정(logging, loguru 등)이 발견되지 않았습니다.",
185
+ standard: "Python Logging Cookbook",
186
+ impact: "장애 발생 시 원인을 추적할 수 있는 데이터가 없어 해결 시간이 길어집니다.",
187
+ action: `
188
+ # Action: Python Logging Setup
189
+ import logging
190
+ logging.basicConfig(level=logging.INFO)
191
+ logger = logging.getLogger(__name__)
192
+ logger.info("Server started")
193
+ `,
194
+ reference: "https://docs.python.org/3/howto/logging-cookbook.html",
195
+ whenItMatters: "운영 중 알 수 없는 500 에러가 발생했을 때."
196
+ },
197
+ 'RR-DEP-001': {
198
+ title: "구조적 의존성 결함 (Structural Dependency Issue)",
199
+ category: 'Scalability',
200
+ standard: "Clean Architecture: Dependency Rule",
201
+ impact: "모듈 간 결합도가 높아져 유지보수가 어려워지고, 사이드 이펙트가 발생하기 쉽습니다.",
202
+ action: "상호 참조하는 모듈을 분리하거나 공통 모듈로 추출하세요.",
203
+ reference: "https://refactoring.guru/design-patterns",
204
+ whenItMatters: "프로젝트 규모가 커질수록 리팩토링 비용이 기하급수적으로 증가합니다."
205
+ },
206
+ 'RR-LINT-001': {
207
+ title: "거대 모듈 감지 (God Module)",
208
+ category: 'Maintenance',
209
+ standard: "Clean Code: Functions",
210
+ impact: "단일 파일의 책임이 과도하여 변경 시 영향 범위를 예측하기 어렵습니다.",
211
+ action: "책임에 따라 파일을 분리하세요 (Separation of Concerns).",
212
+ reference: "https://pypi.org/project/flake8/",
213
+ whenItMatters: "기능 추가 시마다 버그가 발생할 때."
214
+ },
215
+ 'DEFAULT': {
216
+ title: "기타 잠재적 리스크 (Other Potential Risks)",
217
+ category: 'Maintenance',
218
+ standard: "General Coding Best Practices",
219
+ impact: "잠재적인 버그나 유지보수 어려움이 있을 수 있습니다.",
220
+ action: "해당 코드를 리뷰하고 리팩토링을 고려하세요.",
221
+ reference: "#",
222
+ whenItMatters: "지속적인 코드 품질 저하가 우려될 때."
223
+ },
224
+ 'DISCLOSURE': "배포 전 감사가 완료되었습니다. 발견된 리스크들은 실제 운영 환경에서 예기치 못한 서비스 중단이나 데이터 손실을 야기할 수 있는 항목들입니다.",
225
+ 'CTA': "배포 루틴 자동화를 위해 GitHub App을 설치하고 지속적인 배포 준비도(Release Readiness)를 관리하세요。"
226
+ }
227
+ };
package/dist/index.d.ts CHANGED
@@ -4,3 +4,4 @@ export * from './archScanner.js';
4
4
  export * from './repoAnalyzer.js';
5
5
  export * from './deepAnalysis.js';
6
6
  export * from './jsAnalyzer.js';
7
+ export { LOCALES } from './i18n/locales.js';
package/dist/index.js CHANGED
@@ -14,9 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.LOCALES = void 0;
17
18
  __exportStar(require("./analyzer.js"), exports);
18
19
  __exportStar(require("./aiDiagnosis.js"), exports);
19
20
  __exportStar(require("./archScanner.js"), exports);
20
21
  __exportStar(require("./repoAnalyzer.js"), exports);
21
22
  __exportStar(require("./deepAnalysis.js"), exports);
22
23
  __exportStar(require("./jsAnalyzer.js"), exports);
24
+ var locales_js_1 = require("./i18n/locales.js");
25
+ Object.defineProperty(exports, "LOCALES", { enumerable: true, get: function () { return locales_js_1.LOCALES; } });
@@ -25,16 +25,7 @@ export interface RepoAnalysisResult {
25
25
  disclosure?: string;
26
26
  cta?: string;
27
27
  }
28
- /**
29
- * CEO-ready "Business Translation" for technical risks
30
- */
31
- /**
32
- * 3-Tier Business Audit Translation
33
- */
34
- /**
35
- * 3-Tier Business Audit Translation with Standard IDs
36
- */
37
- export declare function getAuditDetails(id: string, type: string, issue: string): {
28
+ export declare function getAuditDetails(id: string, type: string, issue: string, lang?: 'en' | 'ko'): {
38
29
  id: string;
39
30
  title: string;
40
31
  category: RepoAnalysisResult['findings'][0]['category'];
@@ -45,4 +36,7 @@ export declare function getAuditDetails(id: string, type: string, issue: string)
45
36
  reference: string;
46
37
  whenItMatters: string;
47
38
  };
48
- export declare function analyzeRepository(repoPath: string, resultsDir?: string): Promise<RepoAnalysisResult>;
39
+ export declare function analyzeRepository(repoPath: string, options?: {
40
+ lang?: 'en' | 'ko';
41
+ resultsDir?: string;
42
+ }): Promise<RepoAnalysisResult>;
@@ -50,144 +50,38 @@ const archScanner_js_1 = require("./archScanner.js");
50
50
  /**
51
51
  * 3-Tier Business Audit Translation with Standard IDs
52
52
  */
53
- function getAuditDetails(id, type, issue) {
53
+ const locales_js_1 = require("./i18n/locales.js");
54
+ function getAuditDetails(id, type, issue, lang = 'en') {
54
55
  const commonFields = { id };
55
- if (id === 'RR-SEC-001' || type === 'SecurityRisk') {
56
- return {
57
- ...commonFields,
58
- title: "보안 취약점 위험 (Security Vulnerability)",
59
- category: 'Security',
60
- evidence: issue,
61
- standard: "OWASP Top 10 A03:2021 – Injection",
62
- impact: "외부 공격자가 시스템 권한을 탈취하거나 민감 정보를 유출할 수 있는 조건이 형성됩니다.",
63
- action: `
64
- # Action: 격리 및 환경변수 사용
65
- subprocess.run(..., shell=False) # 권장
66
- # 또는 .env 파일 사용
67
- import os
68
- SECRET = os.getenv('MY_SECRET')
69
- `,
70
- reference: "https://docs.python.org/3/library/subprocess.html#security-considerations",
71
- whenItMatters: "배포 즉시 자동화된 스캐너나 공격자에 의해 탐지될 수 있습니다."
72
- };
73
- }
74
- if (id === 'RR-TEST-001') {
75
- return {
76
- ...commonFields,
77
- title: "자동화 테스트 부재 (Missing Automated Tests)",
78
- category: 'Service Interruption',
79
- evidence: "tests/ 디렉토리 또는 pytest/unittest 관련 설정을 찾을 수 없습니다.",
80
- standard: "pytest Framework Documentation",
81
- impact: "코드 변경 시 기존 기능이 파괴되었는지 확인할 방법이 없어, 배포 후 장애 발생 확률이 높아집니다.",
82
- action: `
83
- # Action: Create tests/test_smoke.py
84
- def test_health_check():
85
- assert True # Basic sanity check
86
- `,
87
- reference: "https://docs.pytest.org/",
88
- whenItMatters: "팀원이 2명 이상으로 늘어나거나 배포 주기가 빨라질 때."
89
- };
90
- }
91
- if (id === 'RR-CI-001') {
92
- return {
93
- ...commonFields,
94
- title: "배포 자동화 파이프라인 부재 (Missing CI Pipeline)",
95
- category: 'Service Interruption',
96
- evidence: "GitHub Actions (.github/workflows/*.yml) 또는 CI 설정 파일이 없습니다.",
97
- standard: "GitHub Actions Documentation",
98
- impact: "사람의 수동 배포 과정에서 실수가 발생할 수 있으며, 일관된 배포 상태를 보장할 수 없습니다.",
99
- action: `
100
- # Action: Create .github/workflows/ci.yml
101
- name: CI
102
- on: [push]
103
- jobs:
104
- test:
105
- runs-on: ubuntu-latest
106
- steps:
107
- - uses: actions/checkout@v3
108
- - run: npm test
109
- `,
110
- reference: "https://docs.github.com/en/actions",
111
- whenItMatters: "배포 빈도가 주 2회 이상으로 증가할 때."
112
- };
56
+ const messages = locales_js_1.LOCALES[lang] || locales_js_1.LOCALES['en'];
57
+ let details = messages['DEFAULT'];
58
+ if (messages[id]) {
59
+ details = messages[id];
113
60
  }
114
- if (id === 'RR-OPS-001') {
115
- return {
116
- ...commonFields,
117
- title: "운영 기본 위생 체크 실패 (Project Hygiene)",
118
- category: 'Service Interruption',
119
- evidence: issue, // Consolidated list will be passed here
120
- standard: "12-Factor App / Docker Documentation",
121
- impact: "개발 환경과 운영 환경의 불일치로 인해 '내 컴퓨터에서는 되는데 서버에서는 안 되는' 문제가 발생합니다.",
122
- action: `
123
- # Checklist to Fix:
124
- 1. Create 'Dockerfile'
125
- 2. Create '.gitignore' (use gitignore.io)
126
- 3. Create 'requirements.txt' or 'package.json'
127
- 4. Create '.env.example'
128
- `,
129
- reference: "https://12factor.net/",
130
- whenItMatters: "신규 입사자 온보딩 또는 서버 이관 시."
131
- };
61
+ else if (type === 'SecurityRisk') { // Fallback for general security type if ID not matched
62
+ details = messages['RR-SEC-001'];
132
63
  }
133
- if (id === 'RR-LOG-001') {
134
- return {
135
- ...commonFields,
136
- title: "로깅 설정 미흡 (Insufficient Logging)",
137
- category: 'Maintenance',
138
- evidence: "코드 내에서 로깅 설정(logging, loguru 등)이 발견되지 않았습니다.",
139
- standard: "Python Logging Cookbook",
140
- impact: "장애 발생 시 원인을 추적할 수 있는 데이터가 없어 해결 시간이 길어집니다.",
141
- action: `
142
- # Action: Python Logging Setup
143
- import logging
144
- logging.basicConfig(level=logging.INFO)
145
- logger = logging.getLogger(__name__)
146
- logger.info("Server started")
147
- `,
148
- reference: "https://docs.python.org/3/howto/logging-cookbook.html",
149
- whenItMatters: "운영 중 알 수 없는 500 에러가 발생했을 때."
150
- };
64
+ else if (type === 'CircularDependency') {
65
+ details = messages['RR-DEP-001'];
151
66
  }
152
- if (id === 'RR-DEP-001' || type === 'CircularDependency') {
153
- return {
154
- ...commonFields,
155
- title: "구조적 의존성 결함 (Structural Dependency Issue)",
156
- category: 'Scalability',
157
- evidence: issue,
158
- standard: "Clean Architecture: Dependency Rule",
159
- impact: "모듈 간 결합도가 높아져 유지보수가 어려워지고, 사이드 이펙트가 발생하기 쉽습니다.",
160
- action: "상호 참조하는 모듈을 분리하거나 공통 모듈로 추출하세요.",
161
- reference: "https://refactoring.guru/design-patterns",
162
- whenItMatters: "프로젝트 규모가 커질수록 리팩토링 비용이 기하급수적으로 증가합니다."
163
- };
164
- }
165
- if (id === 'RR-LINT-001' || type === 'GodModule') {
166
- return {
167
- ...commonFields,
168
- title: "거대 모듈 감지 (God Module)",
169
- category: 'Maintenance',
170
- evidence: issue,
171
- standard: "Clean Code: Functions",
172
- impact: "단일 파일의 책임이 과도하여 변경 시 영향 범위를 예측하기 어렵습니다.",
173
- action: "책임에 따라 파일을 분리하세요 (Separation of Concerns).",
174
- reference: "https://pypi.org/project/flake8/",
175
- whenItMatters: "기능 추가 시마다 버그가 발생할 때."
176
- };
67
+ else if (type === 'GodModule') {
68
+ details = messages['RR-LINT-001'];
177
69
  }
178
70
  return {
179
71
  ...commonFields,
180
- title: "기타 잠재적 리스크 (Other Potential Risks)",
181
- category: 'Maintenance',
182
- evidence: issue,
183
- standard: "General Coding Best Practices",
184
- impact: "잠재적인 버그나 유지보수 어려움이 있을 수 있습니다.",
185
- action: "해당 코드를 리뷰하고 리팩토링을 고려하세요.",
186
- reference: "#",
187
- whenItMatters: "지속적인 코드 품질 저하가 우려될 때."
72
+ title: details.title,
73
+ category: details.category,
74
+ evidence: details.evidence || issue, // Use predefined evidence if exists, else dynamic issue
75
+ standard: details.standard,
76
+ impact: details.impact,
77
+ action: details.action,
78
+ reference: details.reference,
79
+ whenItMatters: details.whenItMatters
188
80
  };
189
81
  }
190
- async function analyzeRepository(repoPath, resultsDir) {
82
+ async function analyzeRepository(repoPath, options) {
83
+ const lang = options?.lang || 'en';
84
+ const resultsDir = options?.resultsDir;
191
85
  const files = [];
192
86
  const IGNORE_DIRS = ["node_modules", ".git", "dist", "build", "venv", ".venv", "__pycache__"];
193
87
  function walk(dir) {
@@ -221,7 +115,7 @@ async function analyzeRepository(repoPath, resultsDir) {
221
115
  const hasTests = fs.readdirSync(repoPath, { withFileTypes: true })
222
116
  .some(d => d.isDirectory() && /tests?|spec/i.test(d.name));
223
117
  if (!hasTests) {
224
- const details = getAuditDetails('RR-TEST-001', 'ProductionRisk', '');
118
+ const details = getAuditDetails('RR-TEST-001', 'ProductionRisk', '', lang);
225
119
  findings.push({
226
120
  file: 'Repository Root',
227
121
  line: 0,
@@ -234,7 +128,7 @@ async function analyzeRepository(repoPath, resultsDir) {
234
128
  const hasCI = fs.readdirSync(repoPath, { withFileTypes: true })
235
129
  .some(d => d.isDirectory() && /(\.github|\.circleci|jenkins|gitlab)/i.test(d.name));
236
130
  if (!hasCI) {
237
- const details = getAuditDetails('RR-CI-001', 'ProductionRisk', '');
131
+ const details = getAuditDetails('RR-CI-001', 'ProductionRisk', '', lang);
238
132
  findings.push({
239
133
  file: 'Repository Root',
240
134
  line: 0,
@@ -263,7 +157,7 @@ async function analyzeRepository(repoPath, resultsDir) {
263
157
  }
264
158
  if (hygieneMissing.length > 0) {
265
159
  const evidenceBlock = "\n" + hygieneMissing.join("\n");
266
- const details = getAuditDetails('RR-OPS-001', 'ProductionRisk', evidenceBlock);
160
+ const details = getAuditDetails('RR-OPS-001', 'ProductionRisk', evidenceBlock, lang);
267
161
  findings.push({
268
162
  file: 'Repository Root',
269
163
  line: 0,
@@ -285,13 +179,13 @@ async function analyzeRepository(repoPath, resultsDir) {
285
179
  }
286
180
  // God Module Check (>500 lines)
287
181
  if (lines.length > 500) {
288
- const details = getAuditDetails('RR-LINT-001', 'GodModule', `File length: ${lines.length} lines`);
182
+ const details = getAuditDetails('RR-LINT-001', 'GodModule', `File length: ${lines.length} lines`, lang);
289
183
  findings.push({ file: relativePath, line: 0, type: 'ProductionRisk', ...details });
290
184
  operationalGapCount++;
291
185
  }
292
186
  const result = await (0, analyzer_js_1.analyzePythonCode)(code, relativePath);
293
187
  if (result.hasError) {
294
- const details = getAuditDetails('RR-SEC-001', result.type || 'Error', result.error || 'Unknown Issue');
188
+ const details = getAuditDetails('RR-SEC-001', result.type || 'Error', result.error || 'Unknown Issue', lang);
295
189
  findings.push({
296
190
  file: relativePath,
297
191
  line: result.line || 0,
@@ -315,7 +209,7 @@ async function analyzeRepository(repoPath, resultsDir) {
315
209
  // We rely on rules for now.
316
210
  const result = await (0, jsAnalyzer_js_1.analyzeJsTsCode)(code, relativePath);
317
211
  if (result.hasError) {
318
- const details = getAuditDetails('RR-SEC-002', result.type || 'Error', result.error || 'Unknown Issue'); // Use SEC-002 for JS? Or reuse.
212
+ const details = getAuditDetails('RR-SEC-002', result.type || 'Error', result.error || 'Unknown Issue', lang); // Use SEC-002 for JS? Or reuse.
319
213
  findings.push({
320
214
  file: relativePath,
321
215
  line: result.line || 0,
@@ -331,14 +225,14 @@ async function analyzeRepository(repoPath, resultsDir) {
331
225
  }
332
226
  }
333
227
  if (!hasLogging && files.filter(f => f.endsWith('.py')).length > 0) {
334
- const details = getAuditDetails('RR-LOG-001', 'ProductionRisk', '');
228
+ const details = getAuditDetails('RR-LOG-001', 'ProductionRisk', '', lang);
335
229
  findings.push({ file: 'Repository Root', line: 0, type: 'ProductionRisk', ...details });
336
230
  operationalGapCount++;
337
231
  }
338
232
  // 3. Dependency Scan (Scalability -15)
339
233
  const { adj, cycles } = (0, archScanner_js_1.depsScan)(repoPath);
340
234
  for (const cycle of cycles) {
341
- const details = getAuditDetails('RR-DEP-001', 'CircularDependency', `Cycle: ${cycle.join(' -> ')}`);
235
+ const details = getAuditDetails('RR-DEP-001', 'CircularDependency', `Cycle: ${cycle.join(' -> ')}`, lang);
342
236
  findings.push({
343
237
  file: cycle[0],
344
238
  line: 0,
@@ -391,7 +285,7 @@ async function analyzeRepository(repoPath, resultsDir) {
391
285
  operationalGaps: operationalGapCount
392
286
  },
393
287
  graphUrl,
394
- disclosure: `배포 감사가 완료되었습니다. 발견된 리스크들은 실제 운영 환경에서 예기치 못한 서비스 중단이나 데이터 손실을 야기할 수 있는 항목들입니다.`,
395
- cta: `배포 루틴 자동화를 위해 GitHub App을 설치하고 지속적인 배포 준비도(Release Readiness)를 관리하세요.`
288
+ disclosure: locales_js_1.LOCALES[lang]?.DISCLOSURE || locales_js_1.LOCALES['en'].DISCLOSURE,
289
+ cta: locales_js_1.LOCALES[lang]?.CTA || locales_js_1.LOCALES['en'].CTA
396
290
  };
397
291
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archrisk-engine",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -0,0 +1,225 @@
1
+
2
+ export const LOCALES = {
3
+ en: {
4
+ 'RR-SEC-001': {
5
+ title: "Security Vulnerability Detected",
6
+ category: 'Security',
7
+ standard: "OWASP Top 10 A03:2021 – Injection",
8
+ impact: "Potential for unauthorized access or data leakage through injection attacks.",
9
+ action: `
10
+ # Action: Isolate and use Environment Variables
11
+ subprocess.run(..., shell=False) # Recommended
12
+ # Or use .env file
13
+ import os
14
+ SECRET = os.getenv('MY_SECRET')
15
+ `,
16
+ reference: "https://docs.python.org/3/library/subprocess.html#security-considerations",
17
+ whenItMatters: "Immediately upon deployment, as scanners can detect this."
18
+ },
19
+ 'RR-TEST-001': {
20
+ title: "Missing Automated Tests",
21
+ category: 'Service Interruption',
22
+ evidence: "No tests/ directory or pytest/unittest configuration found.",
23
+ standard: "pytest Framework Documentation",
24
+ impact: "Unable to verify if validation logic breaks existing features. High risk of regression.",
25
+ action: `
26
+ # Action: Create tests/test_smoke.py
27
+ def test_health_check():
28
+ assert True # Basic sanity check
29
+ `,
30
+ reference: "https://docs.pytest.org/",
31
+ whenItMatters: "When team size > 2 or deployment frequency increases."
32
+ },
33
+ 'RR-CI-001': {
34
+ title: "Missing CI Pipeline",
35
+ category: 'Service Interruption',
36
+ evidence: "No GitHub Actions (.github/workflows/*.yml) or CI configuration found.",
37
+ standard: "GitHub Actions Documentation",
38
+ impact: "Manual deployments are prone to human error and lack consistency.",
39
+ action: `
40
+ # Action: Create .github/workflows/ci.yml
41
+ name: CI
42
+ on: [push]
43
+ jobs:
44
+ test:
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v3
48
+ - run: npm test
49
+ `,
50
+ reference: "https://docs.github.com/en/actions",
51
+ whenItMatters: "When deploying more than twice a week."
52
+ },
53
+ 'RR-OPS-001': {
54
+ title: "Project Hygiene Check Failed",
55
+ category: 'Service Interruption',
56
+ standard: "12-Factor App / Docker Documentation",
57
+ impact: "Inconsistency between dev and prod environments (\"It works on my machine\").",
58
+ action: `
59
+ # Checklist to Fix:
60
+ 1. Create 'Dockerfile'
61
+ 2. Create '.gitignore' (use gitignore.io)
62
+ 3. Create 'requirements.txt' or 'package.json'
63
+ 4. Create '.env.example'
64
+ `,
65
+ reference: "https://12factor.net/",
66
+ whenItMatters: "Onboarding new members or migrating servers."
67
+ },
68
+ 'RR-LOG-001': {
69
+ title: "Insufficient Logging",
70
+ category: 'Maintenance',
71
+ evidence: "No logging configuration (logging, loguru) found in codebase.",
72
+ standard: "Python Logging Cookbook",
73
+ impact: "Zero visibility into runtime errors, making debugging impossible during outages.",
74
+ action: `
75
+ # Action: Python Logging Setup
76
+ import logging
77
+ logging.basicConfig(level=logging.INFO)
78
+ logger = logging.getLogger(__name__)
79
+ logger.info("Server started")
80
+ `,
81
+ reference: "https://docs.python.org/3/howto/logging-cookbook.html",
82
+ whenItMatters: "When a 500 error occurs in production."
83
+ },
84
+ 'RR-DEP-001': {
85
+ title: "Structural Dependency Issue",
86
+ category: 'Scalability',
87
+ standard: "Clean Architecture: Dependency Rule",
88
+ impact: "High coupling between modules makes maintenance difficult and increases side effects.",
89
+ action: "Refactor to decouple modules or extract common logic.",
90
+ reference: "https://refactoring.guru/design-patterns",
91
+ whenItMatters: "As the codebase grows, refactoring costs explode."
92
+ },
93
+ 'RR-LINT-001': {
94
+ title: "God Module Detected",
95
+ category: 'Maintenance',
96
+ standard: "Clean Code: Functions",
97
+ impact: "Single file has too many responsibilities, making changes risky.",
98
+ action: "Split file based on responsibilities (Separation of Concerns).",
99
+ reference: "https://pypi.org/project/flake8/",
100
+ whenItMatters: "When every feature addition causes a regression bug."
101
+ },
102
+ 'DEFAULT': {
103
+ title: "Other Potential Risks",
104
+ category: 'Maintenance',
105
+ standard: "General Coding Best Practices",
106
+ impact: "Potential bugs or maintenance debt.",
107
+ action: "Review and consider refactoring.",
108
+ reference: "#",
109
+ whenItMatters: "When code quality starts to degrade."
110
+ },
111
+ 'DISCLOSURE': "Pre-deploy audit complete. Detected risks may cause service interruptions or data loss in production.",
112
+ 'CTA': "Automate this ritual. Install the GitHub App to manage Release Readiness continuously."
113
+ },
114
+ ko: {
115
+ 'RR-SEC-001': {
116
+ title: "보안 취약점 위험 (Security Vulnerability)",
117
+ category: 'Security',
118
+ standard: "OWASP Top 10 A03:2021 – Injection",
119
+ impact: "외부 공격자가 시스템 권한을 탈취하거나 민감 정보를 유출할 수 있는 조건이 형성됩니다.",
120
+ action: `
121
+ # Action: 격리 및 환경변수 사용
122
+ subprocess.run(..., shell=False) # 권장
123
+ # 또는 .env 파일 사용
124
+ import os
125
+ SECRET = os.getenv('MY_SECRET')
126
+ `,
127
+ reference: "https://docs.python.org/3/library/subprocess.html#security-considerations",
128
+ whenItMatters: "배포 즉시 자동화된 스캐너나 공격자에 의해 탐지될 수 있습니다."
129
+ },
130
+ 'RR-TEST-001': {
131
+ title: "자동화 테스트 부재 (Missing Automated Tests)",
132
+ category: 'Service Interruption',
133
+ evidence: "tests/ 디렉토리 또는 pytest/unittest 관련 설정을 찾을 수 없습니다.",
134
+ standard: "pytest Framework Documentation",
135
+ impact: "코드 변경 시 기존 기능이 파괴되었는지 확인할 방법이 없어, 배포 후 장애 발생 확률이 높아집니다.",
136
+ action: `
137
+ # Action: Create tests/test_smoke.py
138
+ def test_health_check():
139
+ assert True # Basic sanity check
140
+ `,
141
+ reference: "https://docs.pytest.org/",
142
+ whenItMatters: "팀원이 2명 이상으로 늘어나거나 배포 주기가 빨라질 때."
143
+ },
144
+ 'RR-CI-001': {
145
+ title: "배포 자동화 파이프라인 부재 (Missing CI Pipeline)",
146
+ category: 'Service Interruption',
147
+ evidence: "GitHub Actions (.github/workflows/*.yml) 또는 CI 설정 파일이 없습니다.",
148
+ standard: "GitHub Actions Documentation",
149
+ impact: "사람의 수동 배포 과정에서 실수가 발생할 수 있으며, 일관된 배포 상태를 보장할 수 없습니다.",
150
+ action: `
151
+ # Action: Create .github/workflows/ci.yml
152
+ name: CI
153
+ on: [push]
154
+ jobs:
155
+ test:
156
+ runs-on: ubuntu-latest
157
+ steps:
158
+ - uses: actions/checkout@v3
159
+ - run: npm test
160
+ `,
161
+ reference: "https://docs.github.com/en/actions",
162
+ whenItMatters: "배포 빈도가 주 2회 이상으로 증가할 때."
163
+ },
164
+ 'RR-OPS-001': {
165
+ title: "운영 기본 위생 체크 실패 (Project Hygiene)",
166
+ category: 'Service Interruption',
167
+ standard: "12-Factor App / Docker Documentation",
168
+ impact: "개발 환경과 운영 환경의 불일치로 인해 '내 컴퓨터에서는 되는데 서버에서는 안 되는' 문제가 발생합니다.",
169
+ action: `
170
+ # Checklist to Fix:
171
+ 1. Create 'Dockerfile'
172
+ 2. Create '.gitignore' (use gitignore.io)
173
+ 3. Create 'requirements.txt' or 'package.json'
174
+ 4. Create '.env.example'
175
+ `,
176
+ reference: "https://12factor.net/",
177
+ whenItMatters: "신규 입사자 온보딩 또는 서버 이관 시."
178
+ },
179
+ 'RR-LOG-001': {
180
+ title: "로깅 설정 미흡 (Insufficient Logging)",
181
+ category: 'Maintenance',
182
+ evidence: "코드 내에서 로깅 설정(logging, loguru 등)이 발견되지 않았습니다.",
183
+ standard: "Python Logging Cookbook",
184
+ impact: "장애 발생 시 원인을 추적할 수 있는 데이터가 없어 해결 시간이 길어집니다.",
185
+ action: `
186
+ # Action: Python Logging Setup
187
+ import logging
188
+ logging.basicConfig(level=logging.INFO)
189
+ logger = logging.getLogger(__name__)
190
+ logger.info("Server started")
191
+ `,
192
+ reference: "https://docs.python.org/3/howto/logging-cookbook.html",
193
+ whenItMatters: "운영 중 알 수 없는 500 에러가 발생했을 때."
194
+ },
195
+ 'RR-DEP-001': {
196
+ title: "구조적 의존성 결함 (Structural Dependency Issue)",
197
+ category: 'Scalability',
198
+ standard: "Clean Architecture: Dependency Rule",
199
+ impact: "모듈 간 결합도가 높아져 유지보수가 어려워지고, 사이드 이펙트가 발생하기 쉽습니다.",
200
+ action: "상호 참조하는 모듈을 분리하거나 공통 모듈로 추출하세요.",
201
+ reference: "https://refactoring.guru/design-patterns",
202
+ whenItMatters: "프로젝트 규모가 커질수록 리팩토링 비용이 기하급수적으로 증가합니다."
203
+ },
204
+ 'RR-LINT-001': {
205
+ title: "거대 모듈 감지 (God Module)",
206
+ category: 'Maintenance',
207
+ standard: "Clean Code: Functions",
208
+ impact: "단일 파일의 책임이 과도하여 변경 시 영향 범위를 예측하기 어렵습니다.",
209
+ action: "책임에 따라 파일을 분리하세요 (Separation of Concerns).",
210
+ reference: "https://pypi.org/project/flake8/",
211
+ whenItMatters: "기능 추가 시마다 버그가 발생할 때."
212
+ },
213
+ 'DEFAULT': {
214
+ title: "기타 잠재적 리스크 (Other Potential Risks)",
215
+ category: 'Maintenance',
216
+ standard: "General Coding Best Practices",
217
+ impact: "잠재적인 버그나 유지보수 어려움이 있을 수 있습니다.",
218
+ action: "해당 코드를 리뷰하고 리팩토링을 고려하세요.",
219
+ reference: "#",
220
+ whenItMatters: "지속적인 코드 품질 저하가 우려될 때."
221
+ },
222
+ 'DISCLOSURE': "배포 전 감사가 완료되었습니다. 발견된 리스크들은 실제 운영 환경에서 예기치 못한 서비스 중단이나 데이터 손실을 야기할 수 있는 항목들입니다.",
223
+ 'CTA': "배포 루틴 자동화를 위해 GitHub App을 설치하고 지속적인 배포 준비도(Release Readiness)를 관리하세요。"
224
+ }
225
+ };
package/src/index.ts CHANGED
@@ -4,3 +4,4 @@ export * from './archScanner.js';
4
4
  export * from './repoAnalyzer.js';
5
5
  export * from './deepAnalysis.js';
6
6
  export * from './jsAnalyzer.js';
7
+ export { LOCALES } from './i18n/locales.js';
@@ -42,153 +42,39 @@ export interface RepoAnalysisResult {
42
42
  /**
43
43
  * 3-Tier Business Audit Translation with Standard IDs
44
44
  */
45
- export function getAuditDetails(id: string, type: string, issue: string): { id: string; title: string; category: RepoAnalysisResult['findings'][0]['category']; evidence: string; standard: string; impact: string; action: string; reference: string; whenItMatters: string } {
46
- const commonFields = { id };
47
-
48
- if (id === 'RR-SEC-001' || type === 'SecurityRisk') {
49
- return {
50
- ...commonFields,
51
- title: "보안 취약점 위험 (Security Vulnerability)",
52
- category: 'Security',
53
- evidence: issue,
54
- standard: "OWASP Top 10 A03:2021 – Injection",
55
- impact: "외부 공격자가 시스템 권한을 탈취하거나 민감 정보를 유출할 수 있는 조건이 형성됩니다.",
56
- action: `
57
- # Action: 격리 및 환경변수 사용
58
- subprocess.run(..., shell=False) # 권장
59
- # 또는 .env 파일 사용
60
- import os
61
- SECRET = os.getenv('MY_SECRET')
62
- `,
63
- reference: "https://docs.python.org/3/library/subprocess.html#security-considerations",
64
- whenItMatters: "배포 즉시 자동화된 스캐너나 공격자에 의해 탐지될 수 있습니다."
65
- };
66
- }
67
-
68
- if (id === 'RR-TEST-001') {
69
- return {
70
- ...commonFields,
71
- title: "자동화 테스트 부재 (Missing Automated Tests)",
72
- category: 'Service Interruption',
73
- evidence: "tests/ 디렉토리 또는 pytest/unittest 관련 설정을 찾을 수 없습니다.",
74
- standard: "pytest Framework Documentation",
75
- impact: "코드 변경 시 기존 기능이 파괴되었는지 확인할 방법이 없어, 배포 후 장애 발생 확률이 높아집니다.",
76
- action: `
77
- # Action: Create tests/test_smoke.py
78
- def test_health_check():
79
- assert True # Basic sanity check
80
- `,
81
- reference: "https://docs.pytest.org/",
82
- whenItMatters: "팀원이 2명 이상으로 늘어나거나 배포 주기가 빨라질 때."
83
- };
84
- }
85
-
86
- if (id === 'RR-CI-001') {
87
- return {
88
- ...commonFields,
89
- title: "배포 자동화 파이프라인 부재 (Missing CI Pipeline)",
90
- category: 'Service Interruption',
91
- evidence: "GitHub Actions (.github/workflows/*.yml) 또는 CI 설정 파일이 없습니다.",
92
- standard: "GitHub Actions Documentation",
93
- impact: "사람의 수동 배포 과정에서 실수가 발생할 수 있으며, 일관된 배포 상태를 보장할 수 없습니다.",
94
- action: `
95
- # Action: Create .github/workflows/ci.yml
96
- name: CI
97
- on: [push]
98
- jobs:
99
- test:
100
- runs-on: ubuntu-latest
101
- steps:
102
- - uses: actions/checkout@v3
103
- - run: npm test
104
- `,
105
- reference: "https://docs.github.com/en/actions",
106
- whenItMatters: "배포 빈도가 주 2회 이상으로 증가할 때."
107
- };
108
- }
45
+ import { LOCALES } from './i18n/locales.js';
109
46
 
110
- if (id === 'RR-OPS-001') {
111
- return {
112
- ...commonFields,
113
- title: "운영 기본 위생 체크 실패 (Project Hygiene)",
114
- category: 'Service Interruption',
115
- evidence: issue, // Consolidated list will be passed here
116
- standard: "12-Factor App / Docker Documentation",
117
- impact: "개발 환경과 운영 환경의 불일치로 인해 '내 컴퓨터에서는 되는데 서버에서는 되는' 문제가 발생합니다.",
118
- action: `
119
- # Checklist to Fix:
120
- 1. Create 'Dockerfile'
121
- 2. Create '.gitignore' (use gitignore.io)
122
- 3. Create 'requirements.txt' or 'package.json'
123
- 4. Create '.env.example'
124
- `,
125
- reference: "https://12factor.net/",
126
- whenItMatters: "신규 입사자 온보딩 또는 서버 이관 시."
127
- };
128
- }
129
-
130
- if (id === 'RR-LOG-001') {
131
- return {
132
- ...commonFields,
133
- title: "로깅 설정 미흡 (Insufficient Logging)",
134
- category: 'Maintenance',
135
- evidence: "코드 내에서 로깅 설정(logging, loguru 등)이 발견되지 않았습니다.",
136
- standard: "Python Logging Cookbook",
137
- impact: "장애 발생 시 원인을 추적할 수 있는 데이터가 없어 해결 시간이 길어집니다.",
138
- action: `
139
- # Action: Python Logging Setup
140
- import logging
141
- logging.basicConfig(level=logging.INFO)
142
- logger = logging.getLogger(__name__)
143
- logger.info("Server started")
144
- `,
145
- reference: "https://docs.python.org/3/howto/logging-cookbook.html",
146
- whenItMatters: "운영 중 알 수 없는 500 에러가 발생했을 때."
147
- };
148
- }
149
-
150
- if (id === 'RR-DEP-001' || type === 'CircularDependency') {
151
- return {
152
- ...commonFields,
153
- title: "구조적 의존성 결함 (Structural Dependency Issue)",
154
- category: 'Scalability',
155
- evidence: issue,
156
- standard: "Clean Architecture: Dependency Rule",
157
- impact: "모듈 간 결합도가 높아져 유지보수가 어려워지고, 사이드 이펙트가 발생하기 쉽습니다.",
158
- action: "상호 참조하는 모듈을 분리하거나 공통 모듈로 추출하세요.",
159
- reference: "https://refactoring.guru/design-patterns",
160
- whenItMatters: "프로젝트 규모가 커질수록 리팩토링 비용이 기하급수적으로 증가합니다."
161
- };
162
- }
163
-
164
- if (id === 'RR-LINT-001' || type === 'GodModule') {
165
- return {
166
- ...commonFields,
167
- title: "거대 모듈 감지 (God Module)",
168
- category: 'Maintenance',
169
- evidence: issue,
170
- standard: "Clean Code: Functions",
171
- impact: "단일 파일의 책임이 과도하여 변경 시 영향 범위를 예측하기 어렵습니다.",
172
- action: "책임에 따라 파일을 분리하세요 (Separation of Concerns).",
173
- reference: "https://pypi.org/project/flake8/",
174
- whenItMatters: "기능 추가 시마다 버그가 발생할 때."
175
- };
47
+ export function getAuditDetails(id: string, type: string, issue: string, lang: 'en' | 'ko' = 'en'): { id: string; title: string; category: RepoAnalysisResult['findings'][0]['category']; evidence: string; standard: string; impact: string; action: string; reference: string; whenItMatters: string } {
48
+ const commonFields = { id };
49
+ const messages = LOCALES[lang] || LOCALES['en'];
50
+ let details: any = messages['DEFAULT'];
51
+
52
+ if (messages[id as keyof typeof messages]) {
53
+ details = messages[id as keyof typeof messages];
54
+ } else if (type === 'SecurityRisk') { // Fallback for general security type if ID not matched
55
+ details = messages['RR-SEC-001'];
56
+ } else if (type === 'CircularDependency') {
57
+ details = messages['RR-DEP-001'];
58
+ } else if (type === 'GodModule') {
59
+ details = messages['RR-LINT-001'];
176
60
  }
177
61
 
178
62
  return {
179
63
  ...commonFields,
180
- title: "기타 잠재적 리스크 (Other Potential Risks)",
181
- category: 'Maintenance',
182
- evidence: issue,
183
- standard: "General Coding Best Practices",
184
- impact: "잠재적인 버그나 유지보수 어려움이 있을 수 있습니다.",
185
- action: "해당 코드를 리뷰하고 리팩토링을 고려하세요.",
186
- reference: "#",
187
- whenItMatters: "지속적인 코드 품질 저하가 우려될 때."
64
+ title: details.title,
65
+ category: details.category as any,
66
+ evidence: details.evidence || issue, // Use predefined evidence if exists, else dynamic issue
67
+ standard: details.standard,
68
+ impact: details.impact,
69
+ action: details.action,
70
+ reference: details.reference,
71
+ whenItMatters: details.whenItMatters
188
72
  };
189
73
  }
190
74
 
191
- export async function analyzeRepository(repoPath: string, resultsDir?: string): Promise<RepoAnalysisResult> {
75
+ export async function analyzeRepository(repoPath: string, options?: { lang?: 'en' | 'ko', resultsDir?: string }): Promise<RepoAnalysisResult> {
76
+ const lang = options?.lang || 'en';
77
+ const resultsDir = options?.resultsDir;
192
78
  const files: string[] = [];
193
79
  const IGNORE_DIRS = ["node_modules", ".git", "dist", "build", "venv", ".venv", "__pycache__"];
194
80
 
@@ -220,7 +106,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
220
106
  const hasTests = fs.readdirSync(repoPath, { withFileTypes: true })
221
107
  .some(d => d.isDirectory() && /tests?|spec/i.test(d.name));
222
108
  if (!hasTests) {
223
- const details = getAuditDetails('RR-TEST-001', 'ProductionRisk', '');
109
+ const details = getAuditDetails('RR-TEST-001', 'ProductionRisk', '', lang);
224
110
  findings.push({
225
111
  file: 'Repository Root',
226
112
  line: 0,
@@ -234,7 +120,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
234
120
  const hasCI = fs.readdirSync(repoPath, { withFileTypes: true })
235
121
  .some(d => d.isDirectory() && /(\.github|\.circleci|jenkins|gitlab)/i.test(d.name));
236
122
  if (!hasCI) {
237
- const details = getAuditDetails('RR-CI-001', 'ProductionRisk', '');
123
+ const details = getAuditDetails('RR-CI-001', 'ProductionRisk', '', lang);
238
124
  findings.push({
239
125
  file: 'Repository Root',
240
126
  line: 0,
@@ -266,7 +152,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
266
152
 
267
153
  if (hygieneMissing.length > 0) {
268
154
  const evidenceBlock = "\n" + hygieneMissing.join("\n");
269
- const details = getAuditDetails('RR-OPS-001', 'ProductionRisk', evidenceBlock);
155
+ const details = getAuditDetails('RR-OPS-001', 'ProductionRisk', evidenceBlock, lang);
270
156
  findings.push({
271
157
  file: 'Repository Root',
272
158
  line: 0,
@@ -292,7 +178,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
292
178
 
293
179
  // God Module Check (>500 lines)
294
180
  if (lines.length > 500) {
295
- const details = getAuditDetails('RR-LINT-001', 'GodModule', `File length: ${lines.length} lines`);
181
+ const details = getAuditDetails('RR-LINT-001', 'GodModule', `File length: ${lines.length} lines`, lang);
296
182
  findings.push({ file: relativePath, line: 0, type: 'ProductionRisk', ...details });
297
183
  operationalGapCount++;
298
184
  }
@@ -300,7 +186,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
300
186
  const result = await analyzePythonCode(code, relativePath);
301
187
 
302
188
  if (result.hasError) {
303
- const details = getAuditDetails('RR-SEC-001', result.type || 'Error', result.error || 'Unknown Issue');
189
+ const details = getAuditDetails('RR-SEC-001', result.type || 'Error', result.error || 'Unknown Issue', lang);
304
190
  findings.push({
305
191
  file: relativePath,
306
192
  line: result.line || 0,
@@ -327,7 +213,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
327
213
  const result = await analyzeJsTsCode(code, relativePath);
328
214
 
329
215
  if (result.hasError) {
330
- const details = getAuditDetails('RR-SEC-002', result.type || 'Error', result.error || 'Unknown Issue'); // Use SEC-002 for JS? Or reuse.
216
+ const details = getAuditDetails('RR-SEC-002', result.type || 'Error', result.error || 'Unknown Issue', lang); // Use SEC-002 for JS? Or reuse.
331
217
  findings.push({
332
218
  file: relativePath,
333
219
  line: result.line || 0,
@@ -343,7 +229,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
343
229
  }
344
230
 
345
231
  if (!hasLogging && files.filter(f => f.endsWith('.py')).length > 0) {
346
- const details = getAuditDetails('RR-LOG-001', 'ProductionRisk', '');
232
+ const details = getAuditDetails('RR-LOG-001', 'ProductionRisk', '', lang);
347
233
  findings.push({ file: 'Repository Root', line: 0, type: 'ProductionRisk', ...details });
348
234
  operationalGapCount++;
349
235
  }
@@ -351,7 +237,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
351
237
  // 3. Dependency Scan (Scalability -15)
352
238
  const { adj, cycles } = depsScan(repoPath);
353
239
  for (const cycle of cycles) {
354
- const details = getAuditDetails('RR-DEP-001', 'CircularDependency', `Cycle: ${cycle.join(' -> ')}`);
240
+ const details = getAuditDetails('RR-DEP-001', 'CircularDependency', `Cycle: ${cycle.join(' -> ')}`, lang);
355
241
  findings.push({
356
242
  file: cycle[0],
357
243
  line: 0,
@@ -408,7 +294,7 @@ export async function analyzeRepository(repoPath: string, resultsDir?: string):
408
294
  operationalGaps: operationalGapCount
409
295
  },
410
296
  graphUrl,
411
- disclosure: `배포 감사가 완료되었습니다. 발견된 리스크들은 실제 운영 환경에서 예기치 못한 서비스 중단이나 데이터 손실을 야기할 수 있는 항목들입니다.`,
412
- cta: `배포 루틴 자동화를 위해 GitHub App을 설치하고 지속적인 배포 준비도(Release Readiness)를 관리하세요.`
297
+ disclosure: LOCALES[lang]?.DISCLOSURE || LOCALES['en'].DISCLOSURE,
298
+ cta: LOCALES[lang]?.CTA || LOCALES['en'].CTA
413
299
  };
414
300
  }