create-claude-pipeline 0.1.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 (76) hide show
  1. package/bin/cli.js +359 -0
  2. package/package.json +32 -0
  3. package/template/.claude/agents/be-developer.md +218 -0
  4. package/template/.claude/agents/designer.md +192 -0
  5. package/template/.claude/agents/fe-developer.md +175 -0
  6. package/template/.claude/agents/infra-developer.md +270 -0
  7. package/template/.claude/agents/planner.md +126 -0
  8. package/template/.claude/agents/pm.md +130 -0
  9. package/template/.claude/agents/qa-engineer.md +270 -0
  10. package/template/.claude/agents/security-reviewer.md +281 -0
  11. package/template/.claude/settings.json +5 -0
  12. package/template/.claude/skills/analyze-requirements/SKILL.md +166 -0
  13. package/template/.claude/skills/api-integration/SKILL.md +354 -0
  14. package/template/.claude/skills/assemble-context/SKILL.md +192 -0
  15. package/template/.claude/skills/db-migration/SKILL.md +228 -0
  16. package/template/.claude/skills/explore-be-codebase/SKILL.md +260 -0
  17. package/template/.claude/skills/explore-codebase/SKILL.md +190 -0
  18. package/template/.claude/skills/explore-design-system/SKILL.md +150 -0
  19. package/template/.claude/skills/explore-fe-codebase/SKILL.md +209 -0
  20. package/template/.claude/skills/explore-implementation/SKILL.md +147 -0
  21. package/template/.claude/skills/explore-infra/SKILL.md +242 -0
  22. package/template/.claude/skills/implement-api/SKILL.md +477 -0
  23. package/template/.claude/skills/implement-components/SKILL.md +217 -0
  24. package/template/.claude/skills/review-auth/SKILL.md +175 -0
  25. package/template/.claude/skills/scan-vulnerabilities/SKILL.md +200 -0
  26. package/template/.claude/skills/write-cicd/SKILL.md +293 -0
  27. package/template/.claude/skills/write-design-spec/SKILL.md +363 -0
  28. package/template/.claude/skills/write-dockerfile/SKILL.md +269 -0
  29. package/template/.claude/skills/write-plan-doc/SKILL.md +164 -0
  30. package/template/.claude/skills/write-plan-doc/assets/plan_template.html +251 -0
  31. package/template/.claude/skills/write-qa-report/SKILL.md +151 -0
  32. package/template/.claude/skills/write-security-report/SKILL.md +185 -0
  33. package/template/.claude/skills/write-test-cases/SKILL.md +234 -0
  34. package/template/.claude-pipeline/dashboard/.env.example +1 -0
  35. package/template/.claude-pipeline/dashboard/.eslintrc.json +3 -0
  36. package/template/.claude-pipeline/dashboard/README.md +36 -0
  37. package/template/.claude-pipeline/dashboard/next.config.mjs +6 -0
  38. package/template/.claude-pipeline/dashboard/package-lock.json +8148 -0
  39. package/template/.claude-pipeline/dashboard/package.json +36 -0
  40. package/template/.claude-pipeline/dashboard/postcss.config.mjs +8 -0
  41. package/template/.claude-pipeline/dashboard/server.ts +24 -0
  42. package/template/.claude-pipeline/dashboard/src/app/api/pipelines/[id]/checkpoint/route.ts +23 -0
  43. package/template/.claude-pipeline/dashboard/src/app/api/pipelines/[id]/outputs/[...filepath]/route.ts +18 -0
  44. package/template/.claude-pipeline/dashboard/src/app/api/pipelines/[id]/route.ts +10 -0
  45. package/template/.claude-pipeline/dashboard/src/app/api/pipelines/route.ts +64 -0
  46. package/template/.claude-pipeline/dashboard/src/app/favicon.ico +0 -0
  47. package/template/.claude-pipeline/dashboard/src/app/fonts/GeistMonoVF.woff +0 -0
  48. package/template/.claude-pipeline/dashboard/src/app/fonts/GeistVF.woff +0 -0
  49. package/template/.claude-pipeline/dashboard/src/app/globals.css +52 -0
  50. package/template/.claude-pipeline/dashboard/src/app/layout.tsx +33 -0
  51. package/template/.claude-pipeline/dashboard/src/app/page.tsx +49 -0
  52. package/template/.claude-pipeline/dashboard/src/app/pipeline/[id]/page.tsx +84 -0
  53. package/template/.claude-pipeline/dashboard/src/components/agent-card.tsx +40 -0
  54. package/template/.claude-pipeline/dashboard/src/components/agent-logs.tsx +65 -0
  55. package/template/.claude-pipeline/dashboard/src/components/artifact-viewer.tsx +130 -0
  56. package/template/.claude-pipeline/dashboard/src/components/checkpoint-banner.tsx +59 -0
  57. package/template/.claude-pipeline/dashboard/src/components/new-pipeline-modal.tsx +63 -0
  58. package/template/.claude-pipeline/dashboard/src/components/output-list.tsx +57 -0
  59. package/template/.claude-pipeline/dashboard/src/components/phase-dots.tsx +37 -0
  60. package/template/.claude-pipeline/dashboard/src/components/pipeline-card.tsx +53 -0
  61. package/template/.claude-pipeline/dashboard/src/components/resizable-panels.tsx +91 -0
  62. package/template/.claude-pipeline/dashboard/src/hooks/use-pipeline-detail.ts +65 -0
  63. package/template/.claude-pipeline/dashboard/src/hooks/use-pipelines.ts +60 -0
  64. package/template/.claude-pipeline/dashboard/src/hooks/use-websocket.ts +58 -0
  65. package/template/.claude-pipeline/dashboard/src/lib/agents.ts +30 -0
  66. package/template/.claude-pipeline/dashboard/src/lib/checkpoint.ts +37 -0
  67. package/template/.claude-pipeline/dashboard/src/lib/pipelines.ts +91 -0
  68. package/template/.claude-pipeline/dashboard/src/lib/watcher.ts +90 -0
  69. package/template/.claude-pipeline/dashboard/src/lib/ws-server.ts +123 -0
  70. package/template/.claude-pipeline/dashboard/src/types/pipeline.ts +61 -0
  71. package/template/.claude-pipeline/dashboard/tailwind.config.ts +31 -0
  72. package/template/.claude-pipeline/dashboard/tsconfig.json +26 -0
  73. package/template/CLAUDE.md +301 -0
  74. package/template/references/context-structure.md +34 -0
  75. package/template/references/pm-context-assembly.md +34 -0
  76. package/template/references/task-context-template.md +65 -0
@@ -0,0 +1,217 @@
1
+ ---
2
+ name: implement-components
3
+ description: "FE 개발자가 디자인 명세 기반으로 React/Next.js 컴포넌트를 구현할 때 일관된 패턴을 유지하기 위한 skill. Props 타입 정의, 상태 처리(Loading/Error/Empty), 파일 배치, 반응형 구현까지의 구현 기준을 제공한다. FE Agent가 STEP 4(구현)에서 컴포넌트를 작성할 때, 새 컴포넌트를 만들거나 기존 컴포넌트를 수정할 때 반드시 사용한다."
4
+ ---
5
+
6
+ # Implement Components
7
+
8
+ FE 개발자가 컴포넌트를 구현할 때 일관된 패턴을 따르기 위한 skill이다.
9
+
10
+ 같은 팀에서 작성한 코드처럼 보이려면 모든 컴포넌트가 동일한 구조를 따라야 한다. 이 skill은 "컴포넌트를 어떻게 작성할 것인가"에 대한 팀 규약이다.
11
+
12
+ ---
13
+
14
+ ## 파일 배치 규칙
15
+
16
+ 컴포넌트의 역할에 따라 저장 위치가 정해진다. 이 규칙은 프로젝트가 커져도 파일을 쉽게 찾을 수 있게 해준다.
17
+
18
+ ```
19
+ src/
20
+ ├── components/
21
+ │ ├── ui/ # 공통 UI 컴포넌트 (Button, Input, Modal 등)
22
+ │ │ ├── Button.tsx
23
+ │ │ └── Input.tsx
24
+ │ └── [feature]/ # 기능별 컴포넌트 (ProductCard, CartItem 등)
25
+ │ ├── ProductCard.tsx
26
+ │ └── CartItem.tsx
27
+ ├── hooks/ # 커스텀 훅
28
+ │ ├── useProducts.ts
29
+ │ └── useAuth.ts
30
+ ├── types/ # 타입 정의
31
+ │ ├── product.ts
32
+ │ └── user.ts
33
+ ├── lib/
34
+ │ └── api/ # API 클라이언트 함수
35
+ │ ├── client.ts # axios/fetch 인스턴스
36
+ │ └── products.ts # API 호출 함수
37
+ ├── app/ (또는 pages/) # 페이지
38
+ │ └── products/
39
+ │ └── page.tsx
40
+ └── styles/ # 스타일
41
+ └── globals.css
42
+ ```
43
+
44
+ **판단 기준:**
45
+ - 2개 이상의 페이지에서 사용 → `components/ui/`
46
+ - 특정 기능에서만 사용 → `components/[feature]/`
47
+ - 페이지 자체 → `app/` 또는 `pages/`
48
+
49
+ 기존 프로젝트에 이미 다른 구조가 있으면 **기존 구조를 따른다**. 이 규칙은 신규 프로젝트이거나 구조가 없을 때의 기본값이다.
50
+
51
+ ---
52
+
53
+ ## 컴포넌트 구현 패턴
54
+
55
+ 모든 컴포넌트는 아래 3단계로 구현한다.
56
+
57
+ ### 1단계: Props 타입 정의
58
+
59
+ 컴포넌트의 인터페이스를 먼저 확정한다. 코드를 작성하기 전에 "이 컴포넌트가 무엇을 받고, 무엇을 노출하는지"를 명확히 한다.
60
+
61
+ ```tsx
62
+ interface ProductCardProps {
63
+ product: Product;
64
+ onAddToCart: (productId: string) => void;
65
+ isWishlisted?: boolean;
66
+ onToggleWishlist?: (productId: string) => void;
67
+ }
68
+ ```
69
+
70
+ **규칙:**
71
+ - 필수 props와 선택 props를 구분한다 (`?`로 선택적 표시)
72
+ - 콜백은 `on` 접두어를 사용한다 (`onClick`, `onSubmit`)
73
+ - 데이터 타입은 `types/` 폴더에서 import한다
74
+ - `any` 타입은 사용하지 않는다
75
+
76
+ ### 2단계: 컴포넌트 함수 작성
77
+
78
+ ```tsx
79
+ export function ProductCard({ product, onAddToCart, isWishlisted = false, onToggleWishlist }: ProductCardProps) {
80
+ // 컴포넌트 로직
81
+ }
82
+ ```
83
+
84
+ **규칙:**
85
+ - `export function` 사용 (named export)
86
+ - `default export`는 페이지 컴포넌트에서만 사용
87
+ - destructuring으로 props를 받는다
88
+ - 선택적 props에는 기본값을 지정한다
89
+
90
+ ### 3단계: 상태별 렌더링
91
+
92
+ 모든 데이터 의존 컴포넌트는 4가지 상태를 처리한다. QA에서 빠뜨린 상태가 발견되면 구현이 반려되기 때문에, 처음부터 모두 구현하는 것이 효율적이다.
93
+
94
+ ```tsx
95
+ export function ProductList() {
96
+ const { data, isLoading, error } = useProducts();
97
+
98
+ // ① 로딩 상태
99
+ if (isLoading) {
100
+ return <ProductListSkeleton />;
101
+ }
102
+
103
+ // ② 에러 상태
104
+ if (error) {
105
+ return (
106
+ <ErrorMessage
107
+ message="상품 목록을 불러올 수 없습니다."
108
+ onRetry={() => window.location.reload()}
109
+ />
110
+ );
111
+ }
112
+
113
+ // ③ 빈 상태
114
+ if (!data || data.length === 0) {
115
+ return <EmptyState message="등록된 상품이 없습니다." />;
116
+ }
117
+
118
+ // ④ 정상 상태
119
+ return (
120
+ <div className="product-grid">
121
+ {data.map((product) => (
122
+ <ProductCard key={product.id} product={product} />
123
+ ))}
124
+ </div>
125
+ );
126
+ }
127
+ ```
128
+
129
+ **상태별 처리 가이드:**
130
+
131
+ | 상태 | 표시 내용 | 필수 여부 |
132
+ |------|-----------|-----------|
133
+ | Loading | 스켈레톤 UI 또는 스피너 | 데이터 fetching 시 필수 |
134
+ | Error | 에러 메시지 + 재시도 버튼 | 데이터 fetching 시 필수 |
135
+ | Empty | 빈 상태 일러스트 + 안내 메시지 | 목록형 컴포넌트 필수 |
136
+ | Success | 실제 콘텐츠 | 항상 필수 |
137
+
138
+ **순수 UI 컴포넌트**(Button, Input 등)는 자체 데이터 fetching이 없으므로 이 4상태 처리가 필요 없다. 대신 `disabled`, `loading` 같은 상태 props를 받아 처리한다.
139
+
140
+ ---
141
+
142
+ ## API 연동 (타입, API 함수, 커스텀 훅, 에러 핸들링)
143
+
144
+ API 연동의 상세 패턴은 **`api-integration` skill**을 참조한다. 여기서는 컴포넌트 구현 관점에서의 핵심 원칙만 정리한다.
145
+
146
+ - 컴포넌트에서 직접 fetch/axios를 호출하지 않는다. 반드시 커스텀 훅으로 감싼다.
147
+ - 커스텀 훅은 `data`, `isLoading`, `error`를 반환하여 컴포넌트가 4상태를 처리할 수 있게 한다.
148
+ - 타입 정의, API 함수 작성, 훅 구현, 에러 핸들링의 구체적인 패턴과 순서는 `api-integration` skill에 정의되어 있다.
149
+
150
+ ---
151
+
152
+ ## 스타일링 패턴
153
+
154
+ 기존 프로젝트의 스타일링 방식을 따른다. 프로젝트에 스타일링 체계가 없으면 아래 순서로 권장한다:
155
+
156
+ 1. **Tailwind CSS** — 이미 설치되어 있으면 우선 사용
157
+ 2. **CSS Modules** — Next.js 프로젝트에서 기본 지원
158
+ 3. **바닐라 CSS** — 소규모 프로젝트에서
159
+
160
+ ### 디자인 토큰 적용
161
+
162
+ 디자인 명세에 토큰이 정의되어 있으면 CSS 변수로 등록한다:
163
+
164
+ ```css
165
+ /* styles/tokens.css */
166
+ :root {
167
+ --color-primary: #2563eb;
168
+ --color-error: #dc2626;
169
+ --radius-md: 8px;
170
+ --spacing-4: 16px;
171
+ --font-size-body: 16px;
172
+ }
173
+ ```
174
+
175
+ ### 반응형 (Mobile-First)
176
+
177
+ 작은 화면부터 큰 화면으로 확장하는 방식으로 작성한다:
178
+
179
+ ```css
180
+ /* 기본: 모바일 */
181
+ .product-grid {
182
+ display: grid;
183
+ grid-template-columns: 1fr;
184
+ gap: var(--spacing-4);
185
+ }
186
+
187
+ /* 태블릿 (768px 이상) */
188
+ @media (min-width: 768px) {
189
+ .product-grid {
190
+ grid-template-columns: repeat(2, 1fr);
191
+ }
192
+ }
193
+
194
+ /* 데스크탑 (1024px 이상) */
195
+ @media (min-width: 1024px) {
196
+ .product-grid {
197
+ grid-template-columns: repeat(3, 1fr);
198
+ }
199
+ }
200
+ ```
201
+
202
+ ---
203
+
204
+ ## 구현 순서 체크리스트
205
+
206
+ 컴포넌트를 구현할 때 아래 순서를 따른다:
207
+
208
+ 1. [ ] `types/`에 타입 정의
209
+ 2. [ ] `lib/api/`에 API 함수 작성
210
+ 3. [ ] `hooks/`에 커스텀 훅 작성
211
+ 4. [ ] `components/ui/`에 공통 컴포넌트 구현 (Button, Input 등)
212
+ 5. [ ] `components/[feature]/`에 기능 컴포넌트 구현
213
+ 6. [ ] `app/` 또는 `pages/`에 페이지 컴포넌트 구현
214
+ 7. [ ] 라우팅 연결
215
+ 8. [ ] 4상태 처리 확인 (Loading/Error/Empty/Success)
216
+ 9. [ ] 반응형 확인 (mobile/tablet/desktop)
217
+ 10. [ ] TypeScript 타입 에러 없음 확인
@@ -0,0 +1,175 @@
1
+ ---
2
+ name: review-auth
3
+ description: "보안 리뷰어가 인증/인가 구현을 집중적으로 검토할 때 참조하는 skill. JWT 설정, 미들웨어 적용 범위, 권한 검사, 비밀번호 처리를 체계적으로 검토한다. Security Agent가 인증/인가 관련 코드를 검토할 때, 로그인/회원가입 기능이 구현된 후 보안 점검할 때, JWT나 세션 관련 코드를 확인할 때 반드시 사용한다. '인증 검토', '인가 검토', 'JWT 검토', '미들웨어 적용 확인', '비밀번호 처리 확인', '권한 검사 확인', 'auth 보안 점검' 등의 상황에서 트리거된다."
4
+ context: fork
5
+ agent: Explore
6
+ ---
7
+
8
+ # Review Auth
9
+
10
+ 보안 리뷰어가 인증/인가 구현을 검토하는 skill이다.
11
+
12
+ 인증/인가는 보안의 첫 번째 방어선이다. JWT 설정이 잘못되면 토큰 위조가 가능하고, 미들웨어가 누락되면 비인가 접근이 가능하며, 비밀번호 처리가 잘못되면 사용자 계정이 탈취된다. 이 skill은 이런 취약점을 놓치지 않도록 체계적인 탐색 절차를 제공한다.
13
+
14
+ ---
15
+
16
+ ## 탐색 절차
17
+
18
+ ### 1. JWT 설정 검토
19
+
20
+ JWT 관련 코드를 찾아서 설정을 확인한다.
21
+
22
+ ```
23
+ Grep: "jwt\.sign|jwt\.verify|jsonwebtoken|jose" — 전체 소스에서
24
+ Grep: "expiresIn|exp|secret|algorithm" — JWT 관련 파일에서
25
+ ```
26
+
27
+ 확인할 항목:
28
+
29
+ | 항목 | 안전 기준 | 위험 신호 |
30
+ |------|----------|----------|
31
+ | 서명 알고리즘 | HS256, RS256, ES256 | `none`, 알고리즘 미지정 |
32
+ | 만료 시간 (Access Token) | 15분 ~ 1시간 | `expiresIn` 없음, 24시간 이상 |
33
+ | 만료 시간 (Refresh Token) | 7일 ~ 30일 | 만료 없음 |
34
+ | 시크릿 키 | 환경변수에서 로드, 32자 이상 | 하드코딩, 짧은 문자열 |
35
+ | `none` 알고리즘 | 명시적으로 차단 | `algorithms` 옵션 없이 verify |
36
+
37
+ **`none` 알고리즘 확인이 중요한 이유:** `jwt.verify`에 `algorithms` 옵션을 지정하지 않으면, 공격자가 토큰의 알고리즘을 `none`으로 변경하여 서명 검증을 우회할 수 있다.
38
+
39
+ ```
40
+ // 위험: algorithms 미지정
41
+ jwt.verify(token, secret)
42
+
43
+ // 안전: 허용 알고리즘 명시
44
+ jwt.verify(token, secret, { algorithms: ['HS256'] })
45
+ ```
46
+
47
+ ### 2. 미들웨어 적용 범위 검토
48
+
49
+ 모든 라우트 파일을 탐색하여 인증 미들웨어 적용 여부를 확인한다.
50
+
51
+ ```
52
+ Glob: **/routes/**/*.ts, **/routes/**/*.js
53
+ Grep: "authenticate|auth|protect|guard|requireAuth" — 라우터 파일에서
54
+ ```
55
+
56
+ 각 엔드포인트를 아래 기준으로 분류한다:
57
+
58
+ | 분류 | 예시 | 인증 필요 |
59
+ |------|------|----------|
60
+ | Public | 로그인, 회원가입, 비밀번호 재설정, 헬스체크 | X |
61
+ | Protected | 사용자 정보 조회/수정, 주문, 결제 | O |
62
+ | Admin | 사용자 관리, 시스템 설정 | O + 관리자 권한 |
63
+
64
+ **확인 포인트:**
65
+ - Protected 엔드포인트에 인증 미들웨어가 빠진 곳이 있는가
66
+ - Public 엔드포인트가 의도적인가 (로그인, 회원가입 등만 허용)
67
+ - 미들웨어 순서가 올바른가 (인증 → 권한 → 검증 → Controller)
68
+
69
+ ### 3. 비밀번호 처리 검토
70
+
71
+ 비밀번호 관련 코드를 찾아서 처리 방식을 확인한다.
72
+
73
+ ```
74
+ Grep: "password|passwd|bcrypt|argon2|hash|salt" — 전체 소스에서
75
+ Grep: "compare|verify" — auth 관련 파일에서
76
+ ```
77
+
78
+ 확인할 항목:
79
+
80
+ | 항목 | 안전 기준 | 위험 신호 |
81
+ |------|----------|----------|
82
+ | 해싱 알고리즘 | bcrypt 또는 argon2 | MD5, SHA1, SHA256 단독, 평문 |
83
+ | bcrypt cost factor | 10 이상 | 10 미만, 미지정 |
84
+ | 평문 저장 | DB에 해시값만 저장 | 평문 비밀번호 INSERT |
85
+ | 로그 출력 | 비밀번호 미포함 | `console.log(req.body)` 등으로 노출 |
86
+ | API 응답 | 비밀번호 필드 제외 | `select *` 등으로 전체 반환 |
87
+ | 비교 방식 | `bcrypt.compare()` 사용 | `===` 직접 비교 (타이밍 공격 가능) |
88
+
89
+ **DB 쿼리에서 비밀번호 제외 확인:**
90
+ ```
91
+ Grep: "select|findUnique|findFirst|findMany" — repository/service 파일에서
92
+ ```
93
+ Prisma의 `select`나 `omit`으로 비밀번호 필드를 제외하는지, 또는 응답 전에 삭제하는지 확인한다.
94
+
95
+ ### 4. 권한 검사 검토
96
+
97
+ 역할(Role) 기반 접근 제어가 어디서 이루어지는지 확인한다.
98
+
99
+ ```
100
+ Grep: "role|permission|authorize|isAdmin|canAccess" — 전체 소스에서
101
+ Grep: "req\.user\.role|user\.role|currentUser\.role" — 전체 소스에서
102
+ ```
103
+
104
+ 확인할 항목:
105
+
106
+ | 항목 | 안전 기준 | 위험 신호 |
107
+ |------|----------|----------|
108
+ | 검사 위치 | 서버 (미들웨어 또는 Service) | 클라이언트만 (FE에서 UI 숨기기만) |
109
+ | 리소스 소유권 | 요청자 === 리소스 소유자 검증 | ID만으로 다른 사용자 데이터 접근 가능 |
110
+ | Admin 엔드포인트 | 별도 권한 미들웨어 적용 | 인증만 있고 권한 검사 없음 |
111
+ | 권한 상승 | 역할 변경 API에 관리자 권한 필요 | 일반 사용자가 자기 역할 변경 가능 |
112
+
113
+ **IDOR(Insecure Direct Object Reference) 확인:**
114
+ `GET /api/users/:id` 같은 엔드포인트에서 요청자가 자기 자신인지 확인하는 로직이 있는지 확인한다. `req.params.id`와 `req.user.id`를 비교하는 코드가 없으면 다른 사용자의 데이터에 접근 가능하다.
115
+
116
+ ### 5. 추가 확인 사항
117
+
118
+ ```
119
+ Grep: "rate.limit|rateLimit|throttle|brute" — 전체 소스에서
120
+ Grep: "cookie|httpOnly|sameSite|secure" — 전체 소스에서
121
+ Grep: "cors|origin" — 전체 소스에서
122
+ ```
123
+
124
+ | 항목 | 확인 내용 |
125
+ |------|----------|
126
+ | Brute Force 방어 | 로그인 실패 횟수 제한이 있는가 |
127
+ | 토큰 저장 (FE) | `httpOnly` cookie인가, `localStorage`인가 |
128
+ | CORS | 허용 origin이 `*`가 아닌가 |
129
+ | 비밀번호 재설정 | 토큰이 일회용인가, 만료 시간이 있는가 |
130
+ | 로그아웃 | 서버에서 토큰 무효화가 되는가 |
131
+
132
+ ---
133
+
134
+ ## 출력 형식
135
+
136
+ 탐색 결과를 취약점 형식으로 반환한다.
137
+
138
+ ```
139
+ ## 인증/인가 검토 결과
140
+
141
+ ### JWT 설정
142
+ | 항목 | 현재 값 | 판정 | 비고 |
143
+ |------|--------|------|------|
144
+ | 서명 알고리즘 | HS256 | ✅ | |
145
+ | Access Token 만료 | 1h | ✅ | |
146
+ | Refresh Token 만료 | 미설정 | ❌ SEC-XXX | 만료 없음 |
147
+ | 시크릿 키 관리 | 환경변수 | ✅ | |
148
+ | algorithms 옵션 | 미지정 | ⚠️ SEC-XXX | none 우회 가능 |
149
+
150
+ ### 미들웨어 적용
151
+ | 엔드포인트 | 인증 | 권한 | 판정 |
152
+ |-----------|------|------|------|
153
+ | POST /api/auth/login | - | - | ✅ Public |
154
+ | GET /api/orders | authenticate | - | ✅ |
155
+ | DELETE /api/users/:id | authenticate | - | ⚠️ SEC-XXX 관리자 권한 필요 |
156
+
157
+ ### 비밀번호 처리
158
+ | 항목 | 현재 구현 | 판정 |
159
+ |------|----------|------|
160
+ | 해싱 | bcrypt (cost 12) | ✅ |
161
+ | 응답 제외 | select에서 제외 | ✅ |
162
+ | 로그 출력 | req.body 로깅 | ❌ SEC-XXX |
163
+
164
+ ### 권한 검사
165
+ | 항목 | 현재 구현 | 판정 |
166
+ |------|----------|------|
167
+ | 검사 위치 | Service 레이어 | ✅ |
168
+ | IDOR 방어 | userId 비교 있음 | ✅ |
169
+ | Admin 보호 | 권한 미들웨어 없음 | ❌ SEC-XXX |
170
+
171
+ ### 발견된 취약점 목록
172
+ (SEC-XXX 형식으로 security-reviewer agent의 취약점 보고 형식에 맞춰 작성)
173
+ ```
174
+
175
+ 미들웨어 적용 표가 길어지면 Protected/Admin만 나열하고 Public은 생략해도 된다.
@@ -0,0 +1,200 @@
1
+ ---
2
+ name: scan-vulnerabilities
3
+ description: "보안 리뷰어가 전체 코드베이스에서 일반적인 보안 취약점 패턴을 탐색할 때 사용하는 skill. OWASP Top 10 기준으로 위험한 패턴을 자동으로 찾아서 보고한다. Security Agent 또는 QA Agent가 보안 검토를 수행할 때, 코드 배포 전 보안 점검이 필요할 때, 또는 새 코드가 추가된 후 취약점이 없는지 확인할 때 반드시 사용한다. '보안 검토', '취약점 탐색', 'OWASP', 'XSS 확인', 'SQL Injection 확인', '시크릿 노출', '하드코딩 비밀번호', '인증 누락 확인' 등의 상황에서 트리거된다."
4
+ context: fork
5
+ agent: Explore
6
+ ---
7
+
8
+ # Scan Vulnerabilities
9
+
10
+ 코드베이스에서 일반적인 보안 취약점 패턴을 탐색하는 skill이다.
11
+
12
+ 보안 취약점은 코드 리뷰에서 놓치기 쉽다. `eval()`이 한 곳에 숨어 있거나, 비밀번호가 하드코딩된 테스트 파일이 프로덕션에 포함되거나, 인증 미들웨어가 새 라우트에 빠져 있을 수 있다. 이 skill은 알려진 위험 패턴을 체계적으로 탐색하여 사람이 놓칠 수 있는 취약점을 잡아낸다.
13
+
14
+ 이 skill은 방어적 보안 목적으로만 사용한다 — 자체 프로젝트의 보안 강화를 위한 코드 검토 도구이다.
15
+
16
+ ---
17
+
18
+ ## 탐색 절차
19
+
20
+ Explore agent를 사용하여 아래 5개 카테고리를 순서대로 탐색한다.
21
+
22
+ ### 1. 위험한 함수/패턴 탐색
23
+
24
+ 코드에서 직접 사용하면 보안 위험이 있는 함수와 패턴을 찾는다.
25
+
26
+ ```
27
+ Grep: eval\(|new Function\(
28
+ Grep: exec\(|execSync\(|spawn\(
29
+ Grep: dangerouslySetInnerHTML
30
+ Grep: \.innerHTML\s*=
31
+ Grep: \$\{.*\}.*(?:SELECT|INSERT|UPDATE|DELETE|DROP)
32
+ Grep: query\(.*\+|query\(.*\$\{
33
+ ```
34
+
35
+ | 패턴 | 위험 | OWASP 분류 |
36
+ |------|------|-----------|
37
+ | `eval()`, `new Function()` | 임의 코드 실행 | A03 Injection |
38
+ | `exec()`, `execSync()` | 명령어 인젝션 | A03 Injection |
39
+ | `dangerouslySetInnerHTML` | XSS 공격 | A03 Injection |
40
+ | `.innerHTML =` | XSS 공격 | A03 Injection |
41
+ | SQL 문자열 조합 | SQL Injection | A03 Injection |
42
+
43
+ 모든 발견이 취약점은 아니다. `eval()`이 빌드 스크립트에 있는 것과 사용자 입력을 처리하는 코드에 있는 것은 위험도가 다르다. 발견 위치와 입력 소스를 함께 확인한다.
44
+
45
+ ### 2. 하드코딩된 시크릿 탐색
46
+
47
+ 코드에 직접 작성된 비밀 값을 찾는다. `.env` 파일이 아니라 소스 코드 내 문자열 리터럴을 대상으로 한다.
48
+
49
+ ```
50
+ Grep: (password|passwd|pwd)\s*[:=]\s*['"][^'"]+['"]
51
+ Grep: (secret|SECRET)\s*[:=]\s*['"][^'"]+['"]
52
+ Grep: (api[_-]?key|apiKey|API_KEY)\s*[:=]\s*['"][^'"]+['"]
53
+ Grep: (token|TOKEN)\s*[:=]\s*['"][^'"]+['"]
54
+ Grep: (sk-|pk-|AIza|ghp_|gho_|github_pat_)
55
+ Grep: [A-Za-z0-9+/]{40,}={0,2}
56
+ ```
57
+
58
+ | 패턴 | 위험 | OWASP 분류 |
59
+ |------|------|-----------|
60
+ | `password = "..."` | 자격 증명 노출 | A07 Identification Failures |
61
+ | `sk-`, `AIza` 등 | API 키 노출 | A07 Identification Failures |
62
+ | 긴 Base64 문자열 | 인코딩된 시크릿 | A07 Identification Failures |
63
+
64
+ 제외할 것:
65
+ - `.env.example`의 플레이스홀더 값 (`password = "your-password-here"`)
66
+ - 테스트 파일의 명백한 더미 값 (`password = "test123"` — 단, 실제 서비스 키와 유사하면 보고)
67
+ - 타입 정의 파일의 인터페이스 필드명
68
+
69
+ ### 3. 인증 미들웨어 누락 탐색
70
+
71
+ 데이터를 변경하는 엔드포인트(POST/PUT/PATCH/DELETE)에 인증 미들웨어가 적용되어 있는지 확인한다.
72
+
73
+ ```
74
+ Glob: src/routes/**/*.{ts,js}
75
+ Grep: router\.(post|put|patch|delete)\(
76
+ Grep: @(Post|Put|Patch|Delete)\(
77
+ ```
78
+
79
+ 각 변경 엔드포인트에 대해:
80
+ - `authenticate`, `auth`, `protect`, `guard` 등의 미들웨어가 적용되어 있는지 확인
81
+ - 적용되지 않은 엔드포인트는 의도적인 public API인지 확인 (로그인, 회원가입 등)
82
+
83
+ ### 4. 민감 데이터 응답 포함 탐색
84
+
85
+ API 응답에 노출되면 안 되는 데이터가 포함되는지 확인한다.
86
+
87
+ ```
88
+ Grep: res\.json\(.*user|res\.send\(.*user
89
+ Grep: password|passwordHash|hashedPassword
90
+ Grep: findMany|findAll|find\(\)
91
+ ```
92
+
93
+ 확인할 패턴:
94
+ - DB 레코드를 필터링 없이 그대로 반환 (`res.json(user)` — password 필드 포함 가능)
95
+ - `select`나 `omit` 없이 전체 레코드 조회
96
+ - 응답에 `password`, `token`, `secret` 필드 포함
97
+
98
+ ### 5. 추가 보안 점검
99
+
100
+ ```
101
+ Grep: cors\(\)|cors\(\{\s*origin:\s*['"]\*['"]\s*\}\)
102
+ Grep: http://|HTTP://
103
+ Grep: \.env
104
+ Glob: .gitignore
105
+ ```
106
+
107
+ | 패턴 | 위험 |
108
+ |------|------|
109
+ | `cors()` (와일드카드) | 모든 도메인에서 API 접근 허용 |
110
+ | HTTP URL (HTTPS 아님) | 전송 중 데이터 노출 |
111
+ | `.env`가 `.gitignore`에 없음 | 시크릿이 git에 커밋될 수 있음 |
112
+ | `process.env.XXX` 직접 참조 | config 모듈 미사용 시 검증 누락 |
113
+
114
+ ---
115
+
116
+ ## 출력 형식
117
+
118
+ 탐색 결과를 아래 형식으로 정리하여 반환한다:
119
+
120
+ ```markdown
121
+ # 취약점 탐색 결과
122
+
123
+ ## 요약
124
+
125
+ | 심각도 | 발견 건수 |
126
+ |--------|---------|
127
+ | Critical | N |
128
+ | High | N |
129
+ | Medium | N |
130
+ | Low | N |
131
+ | 총계 | N |
132
+
133
+ ## 즉시 검토 필요 (Critical / High)
134
+
135
+ | # | 심각도 | 카테고리 | 파일 | 라인 | 패턴 | 설명 |
136
+ |---|--------|---------|------|------|------|------|
137
+ | 1 | Critical | 하드코딩 시크릿 | src/config/db.ts | 15 | `password = "real_pass"` | DB 비밀번호 하드코딩 |
138
+ | 2 | High | 인증 누락 | src/routes/admin.ts | 42 | `router.delete("/users/:id")` | 인증 미들웨어 없음 |
139
+
140
+ ## 주의 필요 (Medium / Low)
141
+
142
+ | # | 심각도 | 카테고리 | 파일 | 라인 | 패턴 | 설명 |
143
+ |---|--------|---------|------|------|------|------|
144
+ | 3 | Medium | XSS 위험 | src/components/Comment.tsx | 28 | `dangerouslySetInnerHTML` | 사용자 입력 포함 여부 확인 필요 |
145
+ | 4 | Low | CORS 설정 | src/app.ts | 12 | `cors()` | 와일드카드 CORS — 개발 환경이면 OK |
146
+
147
+ ## 카테고리별 상세
148
+
149
+ ### 위험한 함수/패턴
150
+ - (발견 목록 또는 "발견 없음")
151
+
152
+ ### 하드코딩된 시크릿
153
+ - (발견 목록 또는 "발견 없음")
154
+
155
+ ### 인증 미들웨어 누락
156
+ - (발견 목록 또는 "발견 없음")
157
+
158
+ ### 민감 데이터 응답 포함
159
+ - (발견 목록 또는 "발견 없음")
160
+
161
+ ### 추가 보안 점검
162
+ - (발견 목록 또는 "발견 없음")
163
+
164
+ ## 권장 조치
165
+
166
+ 1. [Critical/High 항목에 대한 구체적 수정 방법]
167
+ 2. [예: "src/config/db.ts:15 — 비밀번호를 환경변수로 이동"]
168
+ 3. [예: "src/routes/admin.ts:42 — authenticate 미들웨어 추가"]
169
+ ```
170
+
171
+ ### 심각도 기준
172
+
173
+ | 심각도 | 기준 |
174
+ |--------|------|
175
+ | Critical | 즉시 악용 가능 — 하드코딩된 실제 시크릿, SQL Injection |
176
+ | High | 악용 가능성 높음 — 인증 누락, 민감 데이터 노출 |
177
+ | Medium | 조건부 위험 — XSS 가능성, 느슨한 CORS |
178
+ | Low | 모범 사례 미준수 — HTTP URL, config 미사용 |
179
+
180
+ ---
181
+
182
+ ## 발견 없음인 경우
183
+
184
+ 취약점이 하나도 발견되지 않으면:
185
+
186
+ ```markdown
187
+ # 취약점 탐색 결과
188
+
189
+ ## 요약
190
+
191
+ 탐색된 위험 패턴: 0건
192
+
193
+ 5개 카테고리 전체에서 알려진 취약점 패턴이 발견되지 않았습니다.
194
+
195
+ ## 참고사항
196
+
197
+ - 이 탐색은 패턴 기반 정적 분석이며, 모든 취약점을 발견하지는 못합니다
198
+ - 비즈니스 로직 취약점, 인가 우회, 타이밍 공격 등은 수동 검토가 필요합니다
199
+ - 의존성 취약점은 `npm audit` 또는 `yarn audit`으로 별도 확인하세요
200
+ ```