timsquad 3.3.0 → 3.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.
- package/README.ko.md +288 -0
- package/README.md +158 -151
- package/dist/commands/compile.d.ts +3 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +170 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/daemon.d.ts.map +1 -1
- package/dist/commands/daemon.js +95 -5
- package/dist/commands/daemon.js.map +1 -1
- package/dist/commands/full.js +1 -0
- package/dist/commands/full.js.map +1 -1
- package/dist/commands/git/pr.js +6 -5
- package/dist/commands/git/pr.js.map +1 -1
- package/dist/commands/git/release.js +2 -7
- package/dist/commands/git/release.js.map +1 -1
- package/dist/commands/improve.js +2 -2
- package/dist/commands/improve.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +2 -2
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/metrics.d.ts.map +1 -1
- package/dist/commands/metrics.js +6 -2
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/retro.js +8 -8
- package/dist/commands/retro.js.map +1 -1
- package/dist/commands/session.js +3 -3
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/skills.d.ts +12 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +228 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +23 -1
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/daemon/entry.js +3 -3
- package/dist/daemon/entry.js.map +1 -1
- package/dist/daemon/event-queue.d.ts.map +1 -1
- package/dist/daemon/event-queue.js +2 -2
- package/dist/daemon/event-queue.js.map +1 -1
- package/dist/daemon/index.d.ts +4 -2
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +214 -52
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/jsonl-watcher.d.ts +1 -0
- package/dist/daemon/jsonl-watcher.d.ts.map +1 -1
- package/dist/daemon/jsonl-watcher.js.map +1 -1
- package/dist/daemon/meta-cache.d.ts +1 -0
- package/dist/daemon/meta-cache.d.ts.map +1 -1
- package/dist/daemon/meta-cache.js +9 -0
- package/dist/daemon/meta-cache.js.map +1 -1
- package/dist/daemon/session-notes.d.ts +33 -0
- package/dist/daemon/session-notes.d.ts.map +1 -0
- package/dist/daemon/session-notes.js +74 -0
- package/dist/daemon/session-notes.js.map +1 -0
- package/dist/daemon/session-state.d.ts +27 -0
- package/dist/daemon/session-state.d.ts.map +1 -0
- package/dist/daemon/session-state.js +165 -0
- package/dist/daemon/session-state.js.map +1 -0
- package/dist/daemon/shutdown.d.ts.map +1 -1
- package/dist/daemon/shutdown.js +9 -1
- package/dist/daemon/shutdown.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-generator.d.ts +4 -0
- package/dist/lib/agent-generator.d.ts.map +1 -1
- package/dist/lib/agent-generator.js +52 -3
- package/dist/lib/agent-generator.js.map +1 -1
- package/dist/lib/compile-rules.d.ts +66 -0
- package/dist/lib/compile-rules.d.ts.map +1 -0
- package/dist/lib/compile-rules.js +114 -0
- package/dist/lib/compile-rules.js.map +1 -0
- package/dist/lib/compiler.d.ts +105 -0
- package/dist/lib/compiler.d.ts.map +1 -0
- package/dist/lib/compiler.js +368 -0
- package/dist/lib/compiler.js.map +1 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +8 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/project.d.ts.map +1 -1
- package/dist/lib/project.js +8 -3
- package/dist/lib/project.js.map +1 -1
- package/dist/lib/skill-generator.d.ts.map +1 -1
- package/dist/lib/skill-generator.js +22 -1
- package/dist/lib/skill-generator.js.map +1 -1
- package/dist/lib/template.d.ts.map +1 -1
- package/dist/lib/template.js +6 -0
- package/dist/lib/template.js.map +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +12 -1
- package/dist/types/config.js.map +1 -1
- package/dist/types/project.d.ts +1 -1
- package/dist/types/project.d.ts.map +1 -1
- package/dist/types/project.js +2 -0
- package/dist/types/project.js.map +1 -1
- package/package.json +4 -4
- package/templates/base/agents/base/tsq-architect.md +2 -2
- package/templates/base/agents/overlays/domain/mobile/_common.md +13 -0
- package/templates/base/knowledge/checklists/plan-quality.md +31 -0
- package/templates/base/knowledge/checklists/stability-verification.md +14 -0
- package/templates/base/skills/controller/SKILL.md +111 -0
- package/templates/base/skills/controller/references/README.md +35 -0
- package/templates/base/skills/controller/rules/README.md +18 -0
- package/templates/base/skills/mobile/dart/SKILL.md +69 -0
- package/templates/base/skills/mobile/dart/rules/async-patterns.md +112 -0
- package/templates/base/skills/mobile/dart/rules/code-style.md +96 -0
- package/templates/base/skills/mobile/dart/rules/null-safety.md +84 -0
- package/templates/base/skills/mobile/dart/rules/type-system.md +111 -0
- package/templates/base/skills/mobile/flutter/SKILL.md +89 -0
- package/templates/base/skills/mobile/flutter/ci-cd/SKILL.md +82 -0
- package/templates/base/skills/mobile/flutter/ci-cd/references/ci-cd-pipeline.md +314 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/code-signing.md +106 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/codemagic-setup.md +116 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/fastlane-setup.md +105 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/github-actions.md +112 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/store-deployment.md +106 -0
- package/templates/base/skills/mobile/flutter/ci-cd/rules/versioning.md +107 -0
- package/templates/base/skills/mobile/flutter/i18n/SKILL.md +78 -0
- package/templates/base/skills/mobile/flutter/i18n/references/i18n-architecture.md +225 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/arb-files.md +182 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/locale-switching.md +226 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/localization-setup.md +137 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/plural-gender.md +159 -0
- package/templates/base/skills/mobile/flutter/i18n/rules/text-direction.md +199 -0
- package/templates/base/skills/mobile/flutter/monitoring/SKILL.md +81 -0
- package/templates/base/skills/mobile/flutter/monitoring/references/monitoring-architecture.md +269 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/analytics.md +227 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/crashlytics-setup.md +195 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/logging.md +258 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/performance-monitoring.md +248 -0
- package/templates/base/skills/mobile/flutter/monitoring/rules/sentry-integration.md +249 -0
- package/templates/base/skills/mobile/flutter/networking/SKILL.md +88 -0
- package/templates/base/skills/mobile/flutter/networking/references/api-client-architecture.md +305 -0
- package/templates/base/skills/mobile/flutter/networking/rules/caching.md +212 -0
- package/templates/base/skills/mobile/flutter/networking/rules/connectivity.md +213 -0
- package/templates/base/skills/mobile/flutter/networking/rules/dio-setup.md +159 -0
- package/templates/base/skills/mobile/flutter/networking/rules/error-handling.md +209 -0
- package/templates/base/skills/mobile/flutter/networking/rules/interceptors.md +205 -0
- package/templates/base/skills/mobile/flutter/networking/rules/retrofit-patterns.md +194 -0
- package/templates/base/skills/mobile/flutter/push-notifications/SKILL.md +87 -0
- package/templates/base/skills/mobile/flutter/push-notifications/references/notification-architecture.md +340 -0
- package/templates/base/skills/mobile/flutter/push-notifications/references/platform-setup.md +286 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/background-processing.md +308 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/deep-linking.md +217 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/fcm-setup.md +164 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/local-notifications.md +262 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/notification-handling.md +210 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/notification-permissions.md +246 -0
- package/templates/base/skills/mobile/flutter/push-notifications/rules/rich-notifications.md +320 -0
- package/templates/base/skills/mobile/flutter/references/freezed-patterns.md +162 -0
- package/templates/base/skills/mobile/flutter/references/project-structure.md +170 -0
- package/templates/base/skills/mobile/flutter/rules/animations.md +112 -0
- package/templates/base/skills/mobile/flutter/rules/architecture.md +121 -0
- package/templates/base/skills/mobile/flutter/rules/navigation-routing.md +117 -0
- package/templates/base/skills/mobile/flutter/rules/performance.md +112 -0
- package/templates/base/skills/mobile/flutter/rules/platform-adaptive.md +126 -0
- package/templates/base/skills/mobile/flutter/rules/state-management.md +110 -0
- package/templates/base/skills/mobile/flutter/rules/testing.md +131 -0
- package/templates/base/skills/mobile/flutter/rules/widget-conventions.md +122 -0
- package/templates/base/skills/mobile/flutter/security/SKILL.md +86 -0
- package/templates/base/skills/mobile/flutter/security/references/mobile-security-checklist.md +168 -0
- package/templates/base/skills/mobile/flutter/security/rules/api-key-protection.md +206 -0
- package/templates/base/skills/mobile/flutter/security/rules/authentication.md +248 -0
- package/templates/base/skills/mobile/flutter/security/rules/data-protection.md +271 -0
- package/templates/base/skills/mobile/flutter/security/rules/obfuscation.md +213 -0
- package/templates/base/skills/mobile/flutter/security/rules/secure-storage.md +171 -0
- package/templates/base/skills/mobile/flutter/security/rules/ssl-pinning.md +197 -0
- package/templates/base/skills/stability-verification/SKILL.md +64 -0
- package/templates/base/skills/stability-verification/references/release-checklist.md +34 -0
- package/templates/base/skills/stability-verification/references/security-fix-patterns.md +112 -0
- package/templates/base/skills/stability-verification/rules/verification-layers.md +67 -0
- package/templates/base/skills/stability-verification/rules/verification-workflow.md +69 -0
- package/templates/base/skills/stability-verification/scripts/verify.sh +294 -0
- package/templates/platforms/claude-code/CLAUDE.md.template +25 -0
- package/templates/platforms/claude-code/rules/build-gate.md +28 -0
- package/templates/platforms/claude-code/rules/completion-verification.md +30 -0
- package/templates/platforms/claude-code/rules/context-monitor.md +23 -0
- package/templates/platforms/claude-code/rules/plan-review.md +45 -0
- package/templates/platforms/claude-code/rules/quality-guards.md +43 -0
- package/templates/platforms/claude-code/rules/session-notes.md +18 -0
- package/templates/platforms/claude-code/rules/skill-suggest.md +27 -0
- package/templates/platforms/claude-code/scripts/build-gate.sh +73 -0
- package/templates/platforms/claude-code/scripts/completion-guard.sh +93 -0
- package/templates/platforms/claude-code/scripts/phase-guard.sh +79 -0
- package/templates/platforms/claude-code/scripts/safe-guard.sh +83 -0
- package/templates/platforms/claude-code/scripts/skill-rules.json +85 -0
- package/templates/platforms/claude-code/scripts/skill-suggest.sh +105 -0
- package/templates/platforms/claude-code/settings.json +111 -3
- package/templates/project-types/mobile-app/config.yaml +123 -0
- package/templates/project-types/mobile-app/process/workflow.xml +191 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SSL Pinning
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: "미적용 → MITM 공격에 API 통신 노출, 토큰/데이터 탈취"
|
|
5
|
+
tags: ssl, tls, certificate-pinning, public-key-pinning, dio, mitm
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## SSL Pinning
|
|
9
|
+
|
|
10
|
+
**Impact: HIGH (미적용 → MITM 공격에 API 통신 노출, 토큰/데이터 탈취)**
|
|
11
|
+
|
|
12
|
+
Dio SecurityContext 기반 인증서/공개키 pinning.
|
|
13
|
+
프록시 도구(Charles, mitmproxy)를 통한 API 통신 감청 방지.
|
|
14
|
+
|
|
15
|
+
### 의존성
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
# pubspec.yaml
|
|
19
|
+
dependencies:
|
|
20
|
+
dio: ^5.7.0
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 인증서 Pinning
|
|
24
|
+
|
|
25
|
+
**Incorrect (pinning 없이 기본 HTTP 클라이언트 사용):**
|
|
26
|
+
```dart
|
|
27
|
+
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
|
|
28
|
+
// → 루팅 기기 + Charles Proxy → 모든 API 통신 감청 가능
|
|
29
|
+
// → 사용자 토큰, 개인정보 탈취
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Correct (인증서 pinning 적용):**
|
|
33
|
+
```dart
|
|
34
|
+
class PinnedHttpClient {
|
|
35
|
+
/// 인증서 pinning이 적용된 Dio 인스턴스 생성
|
|
36
|
+
static Dio create({required String baseUrl}) {
|
|
37
|
+
final securityContext = SecurityContext(withTrustedRoots: false);
|
|
38
|
+
|
|
39
|
+
// 서버 인증서를 앱에 번들
|
|
40
|
+
// assets/certificates/api_cert.pem
|
|
41
|
+
final certData = rootBundle.load('assets/certificates/api_cert.pem');
|
|
42
|
+
|
|
43
|
+
return Dio(BaseOptions(baseUrl: baseUrl))
|
|
44
|
+
..httpClientAdapter = IOHttpClientAdapter(
|
|
45
|
+
createHttpClient: () {
|
|
46
|
+
final client = HttpClient(context: securityContext);
|
|
47
|
+
|
|
48
|
+
client.badCertificateCallback = (cert, host, port) {
|
|
49
|
+
// 핀 검증 실패 → 연결 거부
|
|
50
|
+
return false;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return client;
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 공개키 Pinning (권장)
|
|
61
|
+
|
|
62
|
+
```dart
|
|
63
|
+
/// 공개키 pinning — 인증서 갱신 시에도 공개키가 동일하면 동작
|
|
64
|
+
class PublicKeyPinnedClient {
|
|
65
|
+
// SHA-256 공개키 해시 (base64)
|
|
66
|
+
// openssl 명령어로 추출:
|
|
67
|
+
// openssl s_client -connect api.example.com:443 | \
|
|
68
|
+
// openssl x509 -pubkey -noout | \
|
|
69
|
+
// openssl pkey -pubin -outform der | \
|
|
70
|
+
// openssl dgst -sha256 -binary | base64
|
|
71
|
+
static const _pinnedKeys = [
|
|
72
|
+
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=', // 현재 키
|
|
73
|
+
'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=', // 백업 키
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
static Dio create({required String baseUrl}) {
|
|
77
|
+
return Dio(BaseOptions(baseUrl: baseUrl))
|
|
78
|
+
..httpClientAdapter = IOHttpClientAdapter(
|
|
79
|
+
createHttpClient: () {
|
|
80
|
+
final client = HttpClient();
|
|
81
|
+
|
|
82
|
+
client.badCertificateCallback = (X509Certificate cert, String host, int port) {
|
|
83
|
+
// 공개키 해시 비교
|
|
84
|
+
final certHash = sha256
|
|
85
|
+
.convert(cert.der)
|
|
86
|
+
.toString();
|
|
87
|
+
|
|
88
|
+
// 핀 목록에 포함되어 있으면 허용
|
|
89
|
+
return _pinnedKeys.contains(certHash);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return client;
|
|
93
|
+
},
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 핀 업데이트 전략
|
|
100
|
+
|
|
101
|
+
```dart
|
|
102
|
+
/// 원격 핀 설정 — 인증서 만료 시 앱 업데이트 없이 핀 교체
|
|
103
|
+
class RemotePinManager {
|
|
104
|
+
final SecureStorageService _storage;
|
|
105
|
+
final Dio _bootstrapDio; // pinning 없는 초기 요청용 (최초 1회)
|
|
106
|
+
|
|
107
|
+
RemotePinManager({
|
|
108
|
+
required SecureStorageService storage,
|
|
109
|
+
required Dio bootstrapDio,
|
|
110
|
+
}) : _storage = storage,
|
|
111
|
+
_bootstrapDio = bootstrapDio;
|
|
112
|
+
|
|
113
|
+
/// 앱 시작 시 핀 목록 갱신
|
|
114
|
+
Future<List<String>> fetchPins() async {
|
|
115
|
+
// 1. 로컬 캐시 확인
|
|
116
|
+
final cached = await _storage.getPinnedKeys();
|
|
117
|
+
if (cached != null && cached.isNotEmpty) {
|
|
118
|
+
return cached;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 2. 서버에서 핀 목록 가져오기 (최초 또는 캐시 만료)
|
|
122
|
+
try {
|
|
123
|
+
final response = await _bootstrapDio.get('/security/pins');
|
|
124
|
+
final pins = (response.data['pins'] as List).cast<String>();
|
|
125
|
+
await _storage.savePinnedKeys(pins);
|
|
126
|
+
return pins;
|
|
127
|
+
} catch (e) {
|
|
128
|
+
// 3. 하드코딩 폴백 (앱 번들)
|
|
129
|
+
return PublicKeyPinnedClient._pinnedKeys;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 디버그/개발 환경 처리
|
|
136
|
+
|
|
137
|
+
```dart
|
|
138
|
+
/// 개발 환경에서만 pinning 비활성화
|
|
139
|
+
Dio createApiClient({required String baseUrl}) {
|
|
140
|
+
if (kDebugMode) {
|
|
141
|
+
// 개발 환경: Charles Proxy 등 디버깅 도구 허용
|
|
142
|
+
return Dio(BaseOptions(baseUrl: baseUrl));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 프로덕션: pinning 적용
|
|
146
|
+
return PublicKeyPinnedClient.create(baseUrl: baseUrl);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 주의: kDebugMode가 아닌 커스텀 플래그 사용 시
|
|
150
|
+
// Release 빌드에서 실수로 pinning 비활성화 위험
|
|
151
|
+
// → kDebugMode (컴파일 타임 상수) 사용 권장
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 플랫폼별 고려사항
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
iOS:
|
|
158
|
+
- App Transport Security (ATS) → TLS 1.2 이상 강제 (기본)
|
|
159
|
+
- NSAllowsArbitraryLoads: false 유지 (HTTP 차단)
|
|
160
|
+
- 개발 서버 예외: NSExceptionDomains에 로컬 서버만 추가
|
|
161
|
+
|
|
162
|
+
Android:
|
|
163
|
+
- Network Security Config (res/xml/network_security_config.xml)
|
|
164
|
+
- 기본: 시스템 CA만 신뢰 (Android 7+)
|
|
165
|
+
- 사용자 CA 차단: <trust-anchors><certificates src="system"/></trust-anchors>
|
|
166
|
+
- 디버그 빌드 예외: <debug-overrides><trust-anchors><certificates src="user"/></trust-anchors></debug-overrides>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```xml
|
|
170
|
+
<!-- android/app/src/main/res/xml/network_security_config.xml -->
|
|
171
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
172
|
+
<network-security-config>
|
|
173
|
+
<base-config cleartextTrafficPermitted="false">
|
|
174
|
+
<trust-anchors>
|
|
175
|
+
<certificates src="system"/>
|
|
176
|
+
</trust-anchors>
|
|
177
|
+
</base-config>
|
|
178
|
+
<debug-overrides>
|
|
179
|
+
<trust-anchors>
|
|
180
|
+
<certificates src="user"/>
|
|
181
|
+
</trust-anchors>
|
|
182
|
+
</debug-overrides>
|
|
183
|
+
</network-security-config>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 규칙
|
|
187
|
+
|
|
188
|
+
- 프로덕션 → SSL pinning 필수 (인증서 또는 공개키)
|
|
189
|
+
- 공개키 pinning 권장 → 인증서 갱신 시에도 동일 키면 동작
|
|
190
|
+
- 백업 핀 최소 1개 → 키 롤오버 시 앱 업데이트 없이 전환
|
|
191
|
+
- `badCertificateCallback` → 핀 불일치 시 `return false` (연결 거부)
|
|
192
|
+
- 디버그 모드 → `kDebugMode`로 pinning 비활성화 (프록시 디버깅용)
|
|
193
|
+
- `kDebugMode` 외 커스텀 플래그 → Release에서 실수로 비활성화 위험
|
|
194
|
+
- Android → `network_security_config.xml` 에서 cleartext 차단 + 사용자 CA 차단
|
|
195
|
+
- iOS → ATS 기본 유지, `NSAllowsArbitraryLoads: false`
|
|
196
|
+
- 핀 만료 대비 → 원격 핀 업데이트 또는 하드코딩 백업 핀
|
|
197
|
+
- 인증서 교체 주기 → 핀 업데이트 배포 일정과 동기화
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stability-verification
|
|
3
|
+
description: |
|
|
4
|
+
프로젝트 안정성 검증 스킬. 릴리스/스프린트 완료 전 6-Layer 자동+수동 검증 수행.
|
|
5
|
+
L0(정적분석) → L1(유닛테스트) → L2(보안스캔) → L3(쉘스크립트) → L4(통합) → L5(패키지).
|
|
6
|
+
각 레이어는 fail-closed(기본) 또는 fail-open 정책 적용.
|
|
7
|
+
사용 시점: 릴리스 전, 스프린트 완료 시, 보안 감사 요청 시.
|
|
8
|
+
version: "1.0.0"
|
|
9
|
+
tags: [verification, security, quality, release]
|
|
10
|
+
user-invocable: false
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Stability Verification
|
|
14
|
+
|
|
15
|
+
프로젝트 안정성을 6-Layer 피라미드로 검증한다. 빠르고 저렴한 검사부터 실행하여 초기 실패를 빠르게 잡는다.
|
|
16
|
+
|
|
17
|
+
## Philosophy
|
|
18
|
+
|
|
19
|
+
- **빠른 것부터**: L0(5초) → L5(30초) 순서로 실행, 첫 실패 시 멈춤
|
|
20
|
+
- **Fail-closed 기본**: 모든 레이어는 기본 차단, 명시적 opt-out만 허용
|
|
21
|
+
- **자동 + 수동 병행**: L0~L5는 스크립트 자동화, L6는 사람이 확인
|
|
22
|
+
|
|
23
|
+
## Resources
|
|
24
|
+
|
|
25
|
+
| Priority | Type | Resource | Description |
|
|
26
|
+
|----------|------|----------|-------------|
|
|
27
|
+
| CRITICAL | script | [verify.sh](scripts/verify.sh) | 전체 레이어 오케스트레이터 |
|
|
28
|
+
| CRITICAL | rule | [verification-layers](rules/verification-layers.md) | 6-Layer 정의 + 실패 정책 |
|
|
29
|
+
| HIGH | rule | [verification-workflow](rules/verification-workflow.md) | 검증 실행 워크플로우 패턴 |
|
|
30
|
+
| HIGH | ref | [security-fix-patterns](references/security-fix-patterns.md) | 취약점별 수정 패턴 모음 |
|
|
31
|
+
| MEDIUM | ref | [release-checklist](references/release-checklist.md) | L6 수동 릴리스 체크리스트 |
|
|
32
|
+
|
|
33
|
+
## Quick Rules
|
|
34
|
+
|
|
35
|
+
### 검증 실행
|
|
36
|
+
- `bash .claude/skills/stability-verification/scripts/verify.sh` 로 전체 실행
|
|
37
|
+
- `--layer L0` 으로 특정 레이어만 실행
|
|
38
|
+
- `--skip L3` 으로 특정 레이어 건너뛰기
|
|
39
|
+
|
|
40
|
+
### Fail Policy
|
|
41
|
+
- L0(정적분석), L1(유닛테스트), L5(패키지): **항상 fail-closed**
|
|
42
|
+
- L2(보안): critical/high = fail-closed, moderate/low = fail-open
|
|
43
|
+
- L3(쉘테스트), L4(통합): fail-closed, `--skip` 가능
|
|
44
|
+
|
|
45
|
+
### 이슈 발견 시 수정 워크플로우
|
|
46
|
+
1. 이슈 분류 (CRITICAL > HIGH > MEDIUM > LOW)
|
|
47
|
+
2. 수정 패턴 리서치 (스킬 검색 + 웹 참조)
|
|
48
|
+
3. 수정 계획 수립 (패턴 기반)
|
|
49
|
+
4. 수정 적용 + 재검증
|
|
50
|
+
|
|
51
|
+
## Checklist
|
|
52
|
+
|
|
53
|
+
| Priority | Item |
|
|
54
|
+
|----------|------|
|
|
55
|
+
| CRITICAL | `tsc --noEmit` 에러 0개 |
|
|
56
|
+
| CRITICAL | `npm run test:unit` 전체 통과 |
|
|
57
|
+
| CRITICAL | `execSync` 대신 `execFileSync` (커맨드 인젝션 방지) |
|
|
58
|
+
| HIGH | `shellcheck --severity=warning` 모든 .sh 경고 0개 |
|
|
59
|
+
| HIGH | `npm audit --audit-level=high` 취약점 0개 |
|
|
60
|
+
| HIGH | JSON 출력은 `jq -n --arg` 사용 (문자열 보간 금지) |
|
|
61
|
+
| HIGH | jq 호출에 `|| echo ""` fail-open 폴백 |
|
|
62
|
+
| MEDIUM | `npm pack --dry-run` 의도한 파일만 포함 |
|
|
63
|
+
| MEDIUM | `.gitignore`에 .env, *.pem, *.key 포함 |
|
|
64
|
+
| MEDIUM | `grep -- "$var"` 분리자 사용 |
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Release Checklist
|
|
3
|
+
category: guide
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# L6: 릴리스 체크리스트 (수동)
|
|
7
|
+
|
|
8
|
+
릴리스 전 사람이 확인하는 항목. `verify.sh`가 커버하지 않는 영역.
|
|
9
|
+
|
|
10
|
+
## 버전 관리
|
|
11
|
+
- [ ] `package.json` version이 의도한 릴리스 버전과 일치
|
|
12
|
+
- [ ] CHANGELOG.md에 모든 변경사항 반영
|
|
13
|
+
- [ ] Breaking changes 별도 섹션에 기술
|
|
14
|
+
|
|
15
|
+
## 문서
|
|
16
|
+
- [ ] README.md에 새 기능/명령 반영
|
|
17
|
+
- [ ] PRD.md 버전 히스토리 업데이트
|
|
18
|
+
- [ ] 메모리 파일 현재 상태 반영
|
|
19
|
+
|
|
20
|
+
## Git
|
|
21
|
+
- [ ] `main` 브랜치에서 릴리스 (clean working tree)
|
|
22
|
+
- [ ] 모든 변경이 커밋됨 (`git status` clean)
|
|
23
|
+
- [ ] 릴리스 태그 생성 (`git tag v{version}`)
|
|
24
|
+
|
|
25
|
+
## npm 배포
|
|
26
|
+
- [ ] `npm run build` 성공
|
|
27
|
+
- [ ] `npm pack --dry-run` 검토 — 의도한 파일만 포함
|
|
28
|
+
- [ ] `templates/domains/` 미포함 (유료 콘텐츠)
|
|
29
|
+
- [ ] `.env`, `*.key` 등 민감 파일 미포함
|
|
30
|
+
- [ ] `npm publish` 실행
|
|
31
|
+
|
|
32
|
+
## 배포 후
|
|
33
|
+
- [ ] `npm info timsquad version` 으로 배포 확인
|
|
34
|
+
- [ ] GitHub Release 생성 (해당 시)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Security Fix Patterns
|
|
3
|
+
category: reference
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 보안 수정 패턴 모음
|
|
7
|
+
|
|
8
|
+
출처: OWASP Node.js Cheat Sheet, ShellCheck Wiki, BashFAQ/048, Shellharden
|
|
9
|
+
|
|
10
|
+
## 1. 커맨드 인젝션 (Node.js)
|
|
11
|
+
|
|
12
|
+
### Incorrect
|
|
13
|
+
```typescript
|
|
14
|
+
execSync(`git clone "${url}" "${dir}"`);
|
|
15
|
+
const sanitized = input.replace(/["`$\\]/g, '');
|
|
16
|
+
execSync(`command "${sanitized}"`);
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Correct
|
|
20
|
+
```typescript
|
|
21
|
+
import { execFileSync } from 'child_process';
|
|
22
|
+
execFileSync('git', ['clone', url, dir]); // shell: false (기본값)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**원칙**: `execSync` → `execFileSync` 배열 기반. 새니타이징은 불완전하므로 의존하지 않는다.
|
|
26
|
+
|
|
27
|
+
## 2. JSON 구성 (Shell Script)
|
|
28
|
+
|
|
29
|
+
### Incorrect
|
|
30
|
+
```bash
|
|
31
|
+
echo "{\"key\":\"$VAR\"}" # $VAR에 " 포함 시 깨짐
|
|
32
|
+
cat > file.json << EOF
|
|
33
|
+
{"key": "$VAR"}
|
|
34
|
+
EOF
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Correct
|
|
38
|
+
```bash
|
|
39
|
+
jq -n --arg key "$VAR" '{"key": $key}'
|
|
40
|
+
jq -n --arg k1 "$A" --arg k2 "$B" '{a: $k1, b: $k2}'
|
|
41
|
+
jq -n --argjson num "$NUMBER" '{count: $num}' # 숫자/불린
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 3. jq + set -e Fail-Open
|
|
45
|
+
|
|
46
|
+
### Incorrect
|
|
47
|
+
```bash
|
|
48
|
+
set -e
|
|
49
|
+
VAR=$(echo "$INPUT" | jq -r '.field' 2>/dev/null) # jq 실패 시 스크립트 종료
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Correct
|
|
53
|
+
```bash
|
|
54
|
+
set -e
|
|
55
|
+
VAR=$(echo "$INPUT" | jq -r '.field // ""' 2>/dev/null || echo "")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 4. source 대신 안전한 설정 읽기
|
|
59
|
+
|
|
60
|
+
### Incorrect
|
|
61
|
+
```bash
|
|
62
|
+
source "$HOME/.config" # 임의 코드 실행 가능
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Correct
|
|
66
|
+
```bash
|
|
67
|
+
VALUE=$(grep -m1 '^KEY=' "$HOME/.config" 2>/dev/null | cut -d'=' -f2- | tr -d '"')
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 5. grep 변수 안전 사용
|
|
71
|
+
|
|
72
|
+
### Incorrect
|
|
73
|
+
```bash
|
|
74
|
+
grep "$var" file # $var가 "-e ..."이면 플래그로 해석
|
|
75
|
+
grep "^${file}" output # $file에 . + [ 등 regex 특수문자
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Correct
|
|
79
|
+
```bash
|
|
80
|
+
grep -- "$var" file # -- 로 옵션 종료
|
|
81
|
+
grep -F -- "$file" output # -F 로 리터럴 매칭
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 6. 사용자 입력 검증
|
|
85
|
+
|
|
86
|
+
### Incorrect
|
|
87
|
+
```bash
|
|
88
|
+
PROJECT_NAME="$1"
|
|
89
|
+
echo "name: $PROJECT_NAME" > config.yaml # 인젝션 가능
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Correct
|
|
93
|
+
```bash
|
|
94
|
+
if [[ ! "$1" =~ ^[a-zA-Z][a-zA-Z0-9_-]{0,63}$ ]]; then
|
|
95
|
+
echo "Error: invalid name" >&2; exit 1
|
|
96
|
+
fi
|
|
97
|
+
PROJECT_NAME="$1"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 7. .gitignore 보안 항목
|
|
101
|
+
|
|
102
|
+
```gitignore
|
|
103
|
+
.env
|
|
104
|
+
.env.*
|
|
105
|
+
!.env.example
|
|
106
|
+
*.pem
|
|
107
|
+
*.key
|
|
108
|
+
*.p12
|
|
109
|
+
*.pfx
|
|
110
|
+
credentials.json
|
|
111
|
+
service-account*.json
|
|
112
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Verification Layers
|
|
3
|
+
description: 6-Layer 안정성 검증 정의. 각 레이어의 검사 항목, 도구, 실패 정책.
|
|
4
|
+
globs:
|
|
5
|
+
- "**/*"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Verification Layers
|
|
9
|
+
|
|
10
|
+
## L0: 정적 분석 (Syntax/Lint) — ~5초, Fail-Closed
|
|
11
|
+
|
|
12
|
+
| 검사 | 명령 | 대상 |
|
|
13
|
+
|------|------|------|
|
|
14
|
+
| TypeScript 컴파일 | `tsc --noEmit` | src/**/*.ts |
|
|
15
|
+
| ShellCheck | `shellcheck --severity=warning` | **/*.sh |
|
|
16
|
+
| Bash 구문 | `bash -n` | **/*.sh |
|
|
17
|
+
| JSON 유효성 | `jq empty < file.json` | **/*.json |
|
|
18
|
+
|
|
19
|
+
## L1: 유닛 테스트 — ~10초, Fail-Closed
|
|
20
|
+
|
|
21
|
+
| 검사 | 명령 |
|
|
22
|
+
|------|------|
|
|
23
|
+
| 전체 유닛 테스트 | `npm run test:unit` |
|
|
24
|
+
| 신규 모듈 테스트 존재 확인 | 수동 확인 |
|
|
25
|
+
|
|
26
|
+
## L2: 보안 스캔 — ~15초, Critical=Fail-Closed
|
|
27
|
+
|
|
28
|
+
| 검사 | 명령 | 실패 정책 |
|
|
29
|
+
|------|------|-----------|
|
|
30
|
+
| npm 취약점 | `npm audit --audit-level=high` | critical/high: 차단, moderate/low: 경고 |
|
|
31
|
+
| execSync 인젝션 | `grep -rn 'execSync(' src/` → 변수 보간 확인 | Fail-closed |
|
|
32
|
+
| eval 사용 | `grep -rn 'eval ' **/*.sh` | Fail-closed |
|
|
33
|
+
| 하드코딩 시크릿 | `check-secrets.sh` 또는 수동 검색 | Fail-closed |
|
|
34
|
+
| JSON 문자열 보간 | 쉘 스크립트에서 `echo "{...\"$VAR\"}"` 패턴 확인 | HIGH |
|
|
35
|
+
| .gitignore 보안 | .env, *.pem, *.key 항목 존재 확인 | MEDIUM |
|
|
36
|
+
|
|
37
|
+
## L3: 쉘 스크립트 테스트 — ~10초, Fail-Closed
|
|
38
|
+
|
|
39
|
+
| 검사 | 방법 |
|
|
40
|
+
|------|------|
|
|
41
|
+
| 빈 stdin → fail-open | `echo "" \| bash script.sh` |
|
|
42
|
+
| malformed JSON → fail-open | `echo "not json" \| bash script.sh` |
|
|
43
|
+
| 정상 입력 → 기대 출력 | 정상 JSON 파이프 |
|
|
44
|
+
| 특수문자 입력 → JSON 무결성 | 인용부호/개행 포함 입력 |
|
|
45
|
+
| jq fallback 동작 확인 | `|| echo ""` 패턴 존재 확인 |
|
|
46
|
+
|
|
47
|
+
## L4: 통합/E2E 테스트 — ~30초, Fail-Closed
|
|
48
|
+
|
|
49
|
+
| 검사 | 명령 |
|
|
50
|
+
|------|------|
|
|
51
|
+
| 통합 테스트 | `npm run test:integration` (있을 경우) |
|
|
52
|
+
| E2E 테스트 | `npm run test:e2e` (있을 경우) |
|
|
53
|
+
| CLI 스모크 테스트 | `node bin/tsq.js --version` |
|
|
54
|
+
|
|
55
|
+
## L5: 패키지 무결성 — ~10초, Fail-Closed
|
|
56
|
+
|
|
57
|
+
| 검사 | 명령 |
|
|
58
|
+
|------|------|
|
|
59
|
+
| 빌드 성공 | `npm run build` |
|
|
60
|
+
| 버전 출력 | `node bin/tsq.js --version` |
|
|
61
|
+
| 패키지 내용물 | `npm pack --dry-run` |
|
|
62
|
+
| 민감 파일 미포함 | grep .env/.key/.pem in pack output |
|
|
63
|
+
| 유료 콘텐츠 미포함 | `templates/domains/` 미포함 확인 |
|
|
64
|
+
|
|
65
|
+
## L6: 릴리스 준비 (수동) — Fail-Closed
|
|
66
|
+
|
|
67
|
+
`references/release-checklist.md` 참조.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Verification Workflow
|
|
3
|
+
description: 안정성 검증 실행 워크플로우. 검증→발견→리서치→수정→재검증 사이클.
|
|
4
|
+
globs:
|
|
5
|
+
- "**/*"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Verification Workflow
|
|
9
|
+
|
|
10
|
+
## 전체 사이클
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
1. 리서치 → 2. 계획 → 3. 스킬 생성/갱신 → 4. 검증 실행 → 5. 이슈 수정 → 6. 재검증
|
|
14
|
+
↑ |
|
|
15
|
+
└──────────────────── 이슈 발견 시 수정 패턴 리서치 ──────────────┘
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Phase 1: 리서치
|
|
19
|
+
|
|
20
|
+
검증 시작 전 반드시 수행:
|
|
21
|
+
|
|
22
|
+
1. **스킬 검색**: `npx skills find "code quality verification"` 등으로 관련 스킬 탐색
|
|
23
|
+
2. **웹 참조**: OWASP, ShellCheck Wiki, npm security best practices 등 참조
|
|
24
|
+
3. **기존 스킬 확인**: `stability-verification` 스킬이 이미 있으면 갱신 여부 판단
|
|
25
|
+
|
|
26
|
+
## Phase 2: 계획
|
|
27
|
+
|
|
28
|
+
리서치 결과를 바탕으로 검증 계획 수립:
|
|
29
|
+
|
|
30
|
+
- 어떤 레이어를 실행할 것인가 (L0~L5 중 해당되는 것)
|
|
31
|
+
- 각 레이어의 fail policy (closed/open)
|
|
32
|
+
- 검증 대상 범위 (전체 프로젝트 vs 변경분)
|
|
33
|
+
|
|
34
|
+
## Phase 3: 검증 실행
|
|
35
|
+
|
|
36
|
+
`verify.sh` 또는 수동으로 각 레이어 순차 실행.
|
|
37
|
+
|
|
38
|
+
## Phase 4: 이슈 발견 시 수정 워크플로우
|
|
39
|
+
|
|
40
|
+
**중요**: 발견 즉시 수정하지 않는다. 리서치 먼저.
|
|
41
|
+
|
|
42
|
+
### 수정 프로세스
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
이슈 분류 (CRITICAL/HIGH/MEDIUM/LOW)
|
|
46
|
+
→ 수정 패턴 리서치
|
|
47
|
+
- 스킬 검색: `npx skills find "{issue-type} prevention"`
|
|
48
|
+
- 웹 검색: OWASP, ShellCheck wiki, 전문가 가이드
|
|
49
|
+
→ 수정 계획 수립 (리서치 기반)
|
|
50
|
+
→ 수정 적용
|
|
51
|
+
→ 해당 레이어 재검증
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 수정 패턴 참조
|
|
55
|
+
|
|
56
|
+
`references/security-fix-patterns.md` — 발견 빈도 높은 취약점별 수정 패턴 모음.
|
|
57
|
+
|
|
58
|
+
## Phase 5: 재검증
|
|
59
|
+
|
|
60
|
+
모든 수정 후 전체 레이어 재실행하여 regression 없음을 확인.
|
|
61
|
+
|
|
62
|
+
## 검증 시점
|
|
63
|
+
|
|
64
|
+
| 시점 | 레이어 | 범위 |
|
|
65
|
+
|------|--------|------|
|
|
66
|
+
| 커밋 전 | L0, L1 | 변경 파일 |
|
|
67
|
+
| 스프린트 완료 | L0~L5 | 전체 프로젝트 |
|
|
68
|
+
| 릴리스 전 | L0~L6 | 전체 프로젝트 |
|
|
69
|
+
| 보안 감사 요청 | L2 집중 | 전체 프로젝트 |
|