devflow-kit 0.3.2 → 0.4.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/CHANGELOG.md +97 -0
- package/README.md +47 -13
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +72 -31
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +17 -28
- package/dist/commands/uninstall.js.map +1 -1
- package/package.json +1 -1
- package/src/claude/CLAUDE.md +76 -8
- package/src/claude/agents/devflow/audit-architecture.md +67 -1
- package/src/claude/agents/devflow/audit-complexity.md +67 -1
- package/src/claude/agents/devflow/audit-database.md +67 -1
- package/src/claude/agents/devflow/audit-dependencies.md +67 -1
- package/src/claude/agents/devflow/audit-documentation.md +66 -0
- package/src/claude/agents/devflow/audit-performance.md +67 -1
- package/src/claude/agents/devflow/audit-security.md +67 -1
- package/src/claude/agents/devflow/audit-tests.md +67 -1
- package/src/claude/agents/devflow/audit-typescript.md +66 -0
- package/src/claude/agents/devflow/debug.md +475 -0
- package/src/claude/agents/devflow/project-state.md +419 -0
- package/src/claude/agents/devflow/release.md +283 -8
- package/src/claude/commands/devflow/code-review.md +51 -12
- package/src/claude/commands/devflow/debug.md +29 -201
- package/src/claude/commands/devflow/devlog.md +211 -172
- package/src/claude/commands/devflow/implement.md +507 -0
- package/src/claude/skills/devflow/code-smell/SKILL.md +428 -0
- package/src/claude/skills/devflow/debug/SKILL.md +119 -0
- package/src/claude/skills/devflow/error-handling/SKILL.md +597 -0
- package/src/claude/skills/devflow/input-validation/SKILL.md +514 -0
- package/src/claude/skills/devflow/pattern-check/SKILL.md +238 -0
- package/src/claude/skills/devflow/research/SKILL.md +135 -0
- package/src/claude/skills/devflow/test-design/SKILL.md +384 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: input-validation
|
|
3
|
+
description: Automatically enforce input validation at system boundaries when handling user input, API endpoints, or external data. Use when creating API routes, processing form data, or integrating with external services. Enforces parse-don't-validate pattern.
|
|
4
|
+
allowed-tools: Read, Grep, Glob, AskUserQuestion
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Input Validation Skill
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Enforce security-critical validation at all system boundaries:
|
|
12
|
+
1. **Parse-don't-validate** - Use schema validation, not manual checks
|
|
13
|
+
2. **Boundary enforcement** - Validate at entry points only
|
|
14
|
+
3. **Type safety** - Leverage type system after validation
|
|
15
|
+
4. **Security first** - Prevent injection, overflow, and malformed data
|
|
16
|
+
|
|
17
|
+
## When This Skill Activates
|
|
18
|
+
|
|
19
|
+
Automatically triggers when:
|
|
20
|
+
- Creating API endpoints or routes
|
|
21
|
+
- Processing user-submitted data (forms, uploads, etc.)
|
|
22
|
+
- Integrating with external APIs
|
|
23
|
+
- Accepting configuration or environment variables
|
|
24
|
+
- Handling database queries with user input
|
|
25
|
+
- Processing command-line arguments
|
|
26
|
+
|
|
27
|
+
## Core Principle: Parse, Don't Validate
|
|
28
|
+
|
|
29
|
+
**CRITICAL**: Use schema validation libraries, not manual checks.
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// ❌ VIOLATION: Manual validation scatters checks
|
|
33
|
+
function createUser(data: any): User {
|
|
34
|
+
if (!data.email || typeof data.email !== 'string') {
|
|
35
|
+
throw new Error('Invalid email');
|
|
36
|
+
}
|
|
37
|
+
if (!data.age || typeof data.age !== 'number' || data.age < 0) {
|
|
38
|
+
throw new Error('Invalid age');
|
|
39
|
+
}
|
|
40
|
+
if (!data.name || data.name.length > 100) {
|
|
41
|
+
throw new Error('Invalid name');
|
|
42
|
+
}
|
|
43
|
+
// ... more manual checks
|
|
44
|
+
|
|
45
|
+
return { email: data.email, age: data.age, name: data.name };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ✅ CORRECT: Schema validation at boundary
|
|
49
|
+
import { z } from 'zod';
|
|
50
|
+
|
|
51
|
+
const UserSchema = z.object({
|
|
52
|
+
email: z.string().email().max(255),
|
|
53
|
+
age: z.number().int().min(0).max(150),
|
|
54
|
+
name: z.string().min(1).max(100)
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
type User = z.infer<typeof UserSchema>;
|
|
58
|
+
|
|
59
|
+
function createUser(data: unknown): Result<User, ValidationError> {
|
|
60
|
+
const validation = UserSchema.safeParse(data);
|
|
61
|
+
|
|
62
|
+
if (!validation.success) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
error: new ValidationError('Invalid user data', validation.error)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// After this point, data is guaranteed valid User type
|
|
70
|
+
return { ok: true, value: validation.data };
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Boundary Detection
|
|
75
|
+
|
|
76
|
+
### API Endpoints (Critical Boundary)
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// ❌ VIOLATION: No validation at API boundary
|
|
80
|
+
app.post('/api/users', async (req, res) => {
|
|
81
|
+
const user = await createUser(req.body); // Trusting external data!
|
|
82
|
+
res.json(user);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// ✅ CORRECT: Validation at boundary
|
|
86
|
+
const CreateUserRequestSchema = z.object({
|
|
87
|
+
body: UserSchema
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
app.post('/api/users', async (req, res) => {
|
|
91
|
+
const validation = CreateUserRequestSchema.safeParse(req);
|
|
92
|
+
|
|
93
|
+
if (!validation.success) {
|
|
94
|
+
return res.status(400).json({
|
|
95
|
+
error: 'Validation failed',
|
|
96
|
+
details: validation.error.issues
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Now req.body is safely typed as User
|
|
101
|
+
const result = await createUser(validation.data.body);
|
|
102
|
+
|
|
103
|
+
if (!result.ok) {
|
|
104
|
+
return res.status(500).json({ error: result.error.message });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
res.json(result.value);
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### External API Integration (Boundary)
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// ❌ VIOLATION: Trusting external API response
|
|
115
|
+
async function fetchUserData(userId: string): Promise<UserData> {
|
|
116
|
+
const response = await fetch(`https://api.example.com/users/${userId}`);
|
|
117
|
+
const data = await response.json();
|
|
118
|
+
return data; // No validation!
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ✅ CORRECT: Validate external data
|
|
122
|
+
const ExternalUserSchema = z.object({
|
|
123
|
+
id: z.string().uuid(),
|
|
124
|
+
name: z.string(),
|
|
125
|
+
email: z.string().email(),
|
|
126
|
+
// Define exact structure we expect
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
async function fetchUserData(userId: string): Promise<Result<UserData, Error>> {
|
|
130
|
+
try {
|
|
131
|
+
const response = await fetch(`https://api.example.com/users/${userId}`);
|
|
132
|
+
const rawData = await response.json();
|
|
133
|
+
|
|
134
|
+
const validation = ExternalUserSchema.safeParse(rawData);
|
|
135
|
+
|
|
136
|
+
if (!validation.success) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
error: new Error('External API returned invalid data')
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return { ok: true, value: validation.data };
|
|
144
|
+
} catch (error) {
|
|
145
|
+
return { ok: false, error: error as Error };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Environment Variables (Boundary)
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// ❌ VIOLATION: Trusting environment variables
|
|
154
|
+
const config = {
|
|
155
|
+
port: process.env.PORT, // Could be undefined or invalid
|
|
156
|
+
dbUrl: process.env.DATABASE_URL, // No validation
|
|
157
|
+
apiKey: process.env.API_KEY // Could be empty or malformed
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// ✅ CORRECT: Validate configuration
|
|
161
|
+
const ConfigSchema = z.object({
|
|
162
|
+
port: z.string().regex(/^\d+$/).transform(Number).pipe(z.number().min(1).max(65535)),
|
|
163
|
+
dbUrl: z.string().url().startsWith('postgresql://'),
|
|
164
|
+
apiKey: z.string().min(32).max(128)
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
function loadConfig(): Result<Config, Error> {
|
|
168
|
+
const validation = ConfigSchema.safeParse({
|
|
169
|
+
port: process.env.PORT,
|
|
170
|
+
dbUrl: process.env.DATABASE_URL,
|
|
171
|
+
apiKey: process.env.API_KEY
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (!validation.success) {
|
|
175
|
+
return {
|
|
176
|
+
ok: false,
|
|
177
|
+
error: new Error(`Invalid configuration: ${validation.error.message}`)
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { ok: true, value: validation.data };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Application initialization
|
|
185
|
+
const configResult = loadConfig();
|
|
186
|
+
if (!configResult.ok) {
|
|
187
|
+
console.error('Failed to load configuration:', configResult.error);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const config = configResult.value; // Type-safe, validated config
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Database Queries (SQL Injection Prevention)
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// ❌ VIOLATION: Direct string interpolation (SQL injection risk)
|
|
198
|
+
async function getUserByEmail(email: string): Promise<User> {
|
|
199
|
+
const query = `SELECT * FROM users WHERE email = '${email}'`;
|
|
200
|
+
return db.query(query);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ❌ VIOLATION: No input validation before query
|
|
204
|
+
async function searchUsers(searchTerm: string): Promise<User[]> {
|
|
205
|
+
return db.query('SELECT * FROM users WHERE name LIKE $1', [`%${searchTerm}%`]);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ✅ CORRECT: Validate input + parameterized query
|
|
209
|
+
const EmailSchema = z.string().email().max(255);
|
|
210
|
+
const SearchTermSchema = z.string().min(1).max(100).regex(/^[a-zA-Z0-9\s-]+$/);
|
|
211
|
+
|
|
212
|
+
async function getUserByEmail(email: unknown): Promise<Result<User, Error>> {
|
|
213
|
+
const validation = EmailSchema.safeParse(email);
|
|
214
|
+
|
|
215
|
+
if (!validation.success) {
|
|
216
|
+
return { ok: false, error: new Error('Invalid email format') };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
// Parameterized query prevents SQL injection
|
|
221
|
+
const user = await db.query('SELECT * FROM users WHERE email = $1', [validation.data]);
|
|
222
|
+
return { ok: true, value: user };
|
|
223
|
+
} catch (error) {
|
|
224
|
+
return { ok: false, error: error as Error };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async function searchUsers(searchTerm: unknown): Promise<Result<User[], Error>> {
|
|
229
|
+
const validation = SearchTermSchema.safeParse(searchTerm);
|
|
230
|
+
|
|
231
|
+
if (!validation.success) {
|
|
232
|
+
return { ok: false, error: new Error('Invalid search term') };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
const users = await db.query(
|
|
237
|
+
'SELECT * FROM users WHERE name ILIKE $1',
|
|
238
|
+
[`%${validation.data}%`]
|
|
239
|
+
);
|
|
240
|
+
return { ok: true, value: users };
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return { ok: false, error: error as Error };
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Validation Libraries
|
|
248
|
+
|
|
249
|
+
Recommended schema validation libraries by language:
|
|
250
|
+
|
|
251
|
+
**TypeScript/JavaScript**:
|
|
252
|
+
- Zod (recommended)
|
|
253
|
+
- Yup
|
|
254
|
+
- joi
|
|
255
|
+
- io-ts
|
|
256
|
+
|
|
257
|
+
**Python**:
|
|
258
|
+
- Pydantic (recommended)
|
|
259
|
+
- marshmallow
|
|
260
|
+
- dataclasses with validation
|
|
261
|
+
|
|
262
|
+
**Go**:
|
|
263
|
+
- go-playground/validator
|
|
264
|
+
- ozzo-validation
|
|
265
|
+
|
|
266
|
+
**Rust**:
|
|
267
|
+
- serde with validation
|
|
268
|
+
- validator crate
|
|
269
|
+
|
|
270
|
+
## Validation Report Format
|
|
271
|
+
|
|
272
|
+
When validation issues detected:
|
|
273
|
+
|
|
274
|
+
```markdown
|
|
275
|
+
🚨 INPUT VALIDATION ISSUES DETECTED
|
|
276
|
+
|
|
277
|
+
## 🔴 CRITICAL - Missing Boundary Validation
|
|
278
|
+
**File**: src/api/routes/users.ts:45
|
|
279
|
+
**Issue**: API endpoint accepts unvalidated user input
|
|
280
|
+
**Security Risk**: HIGH - Injection attacks, data corruption possible
|
|
281
|
+
|
|
282
|
+
**Current Code**:
|
|
283
|
+
```typescript
|
|
284
|
+
app.post('/api/users', async (req, res) => {
|
|
285
|
+
const user = await createUser(req.body); // NO VALIDATION
|
|
286
|
+
res.json(user);
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Required Fix**:
|
|
291
|
+
```typescript
|
|
292
|
+
const UserRequestSchema = z.object({
|
|
293
|
+
body: z.object({
|
|
294
|
+
email: z.string().email().max(255),
|
|
295
|
+
name: z.string().min(1).max(100),
|
|
296
|
+
age: z.number().int().min(0).max(150)
|
|
297
|
+
})
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
app.post('/api/users', async (req, res) => {
|
|
301
|
+
const validation = UserRequestSchema.safeParse(req);
|
|
302
|
+
|
|
303
|
+
if (!validation.success) {
|
|
304
|
+
return res.status(400).json({ error: validation.error });
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const result = await createUser(validation.data.body);
|
|
308
|
+
// ... handle result
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Impact**: Prevents malicious input, ensures data integrity
|
|
313
|
+
|
|
314
|
+
## 🔴 CRITICAL - Manual Validation Instead of Schema
|
|
315
|
+
**File**: src/services/validation.ts:23
|
|
316
|
+
**Issue**: Manual type checking instead of schema validation
|
|
317
|
+
**Problem**: Scattered validation logic, incomplete checks
|
|
318
|
+
|
|
319
|
+
**Current Code**:
|
|
320
|
+
```typescript
|
|
321
|
+
if (!data.email || typeof data.email !== 'string') {
|
|
322
|
+
throw new Error('Invalid email');
|
|
323
|
+
}
|
|
324
|
+
if (!data.age || typeof data.age !== 'number') {
|
|
325
|
+
throw new Error('Invalid age');
|
|
326
|
+
}
|
|
327
|
+
// ... 15 more manual checks
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Required Fix**:
|
|
331
|
+
```typescript
|
|
332
|
+
const UserSchema = z.object({
|
|
333
|
+
email: z.string().email().max(255),
|
|
334
|
+
age: z.number().int().min(0).max(150),
|
|
335
|
+
name: z.string().min(1).max(100),
|
|
336
|
+
// All validation rules in one place
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const validation = UserSchema.safeParse(data);
|
|
340
|
+
if (!validation.success) {
|
|
341
|
+
return { ok: false, error: validation.error };
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Impact**: Centralized validation, type safety, better error messages
|
|
346
|
+
|
|
347
|
+
## 🔴 CRITICAL - SQL Injection Risk
|
|
348
|
+
**File**: src/database/queries.ts:67
|
|
349
|
+
**Issue**: String interpolation in SQL query
|
|
350
|
+
**Security Risk**: CRITICAL - SQL injection possible
|
|
351
|
+
|
|
352
|
+
**Current Code**:
|
|
353
|
+
```typescript
|
|
354
|
+
const query = `SELECT * FROM users WHERE email = '${email}'`;
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Required Fix**:
|
|
358
|
+
```typescript
|
|
359
|
+
// 1. Validate input
|
|
360
|
+
const validation = EmailSchema.safeParse(email);
|
|
361
|
+
if (!validation.success) {
|
|
362
|
+
return { ok: false, error: new Error('Invalid email') };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// 2. Use parameterized query
|
|
366
|
+
const query = 'SELECT * FROM users WHERE email = $1';
|
|
367
|
+
const result = await db.query(query, [validation.data]);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Impact**: Prevents SQL injection attacks (critical security issue)
|
|
371
|
+
|
|
372
|
+
## 🟡 HIGH - External API Response Not Validated
|
|
373
|
+
**File**: src/integrations/payment.ts:89
|
|
374
|
+
**Issue**: Trusting external API response without validation
|
|
375
|
+
**Risk**: Application crash if API changes structure
|
|
376
|
+
|
|
377
|
+
**Current Code**:
|
|
378
|
+
```typescript
|
|
379
|
+
const data = await response.json();
|
|
380
|
+
return data.amount; // No validation
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**Required Fix**:
|
|
384
|
+
```typescript
|
|
385
|
+
const PaymentResponseSchema = z.object({
|
|
386
|
+
amount: z.number().positive(),
|
|
387
|
+
currency: z.string().length(3),
|
|
388
|
+
status: z.enum(['success', 'failed', 'pending'])
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
const validation = PaymentResponseSchema.safeParse(await response.json());
|
|
392
|
+
if (!validation.success) {
|
|
393
|
+
return { ok: false, error: new Error('Invalid payment response') };
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return { ok: true, value: validation.data.amount };
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## 📊 Summary
|
|
400
|
+
- **Critical**: 8 validation issues (6 missing, 2 SQL injection risks)
|
|
401
|
+
- **High**: 4 external data issues
|
|
402
|
+
- **Security Risk**: CRITICAL (SQL injection possible)
|
|
403
|
+
- **Files affected**: 7
|
|
404
|
+
|
|
405
|
+
## 🛑 SECURITY GATE FAILED
|
|
406
|
+
|
|
407
|
+
These validation gaps create serious security vulnerabilities:
|
|
408
|
+
1. SQL injection possible in 2 locations
|
|
409
|
+
2. Unvalidated user input in 6 API endpoints
|
|
410
|
+
3. External data trusted without validation
|
|
411
|
+
|
|
412
|
+
**DO NOT deploy until these are fixed.**
|
|
413
|
+
|
|
414
|
+
## ✅ Required Actions
|
|
415
|
+
|
|
416
|
+
1. **Immediate** (Security Critical):
|
|
417
|
+
- Fix SQL injection risks (2 locations)
|
|
418
|
+
- Add validation to all API endpoints
|
|
419
|
+
|
|
420
|
+
2. **High Priority**:
|
|
421
|
+
- Validate all external API responses
|
|
422
|
+
- Validate environment variables on startup
|
|
423
|
+
|
|
424
|
+
3. **Standard**:
|
|
425
|
+
- Replace manual validation with schemas
|
|
426
|
+
- Add validation tests
|
|
427
|
+
|
|
428
|
+
## 📚 Implementation Guide
|
|
429
|
+
|
|
430
|
+
**Step 1**: Install validation library
|
|
431
|
+
```bash
|
|
432
|
+
npm install zod # or appropriate library
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Step 2**: Define schemas for all boundaries
|
|
436
|
+
```typescript
|
|
437
|
+
// src/validation/schemas.ts
|
|
438
|
+
export const schemas = {
|
|
439
|
+
createUser: UserSchema,
|
|
440
|
+
updateUser: UpdateUserSchema,
|
|
441
|
+
searchQuery: SearchQuerySchema,
|
|
442
|
+
// ... all input shapes
|
|
443
|
+
};
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**Step 3**: Apply at boundaries
|
|
447
|
+
```typescript
|
|
448
|
+
// Validate at entry point
|
|
449
|
+
const validation = schema.safeParse(input);
|
|
450
|
+
// Check result and proceed
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**Step 4**: Add tests
|
|
454
|
+
```typescript
|
|
455
|
+
// Verify validation catches invalid input
|
|
456
|
+
```
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
## Validation Checklist
|
|
460
|
+
|
|
461
|
+
Before declaring endpoint/integration complete:
|
|
462
|
+
|
|
463
|
+
- ✅ All user input validated with schema
|
|
464
|
+
- ✅ External API responses validated
|
|
465
|
+
- ✅ Environment variables validated on startup
|
|
466
|
+
- ✅ Database queries use parameterized statements
|
|
467
|
+
- ✅ File uploads validated (type, size, content)
|
|
468
|
+
- ✅ URL parameters validated
|
|
469
|
+
- ✅ Query strings validated
|
|
470
|
+
- ✅ Request headers validated (if used for logic)
|
|
471
|
+
|
|
472
|
+
## Integration Points
|
|
473
|
+
|
|
474
|
+
This skill works with:
|
|
475
|
+
|
|
476
|
+
**pattern-check**: Ensures validation uses Result types
|
|
477
|
+
**code-smell**: Catches fake/incomplete validation
|
|
478
|
+
**test-design**: Validates boundary tests exist
|
|
479
|
+
**error-handling**: Ensures validation errors handled consistently
|
|
480
|
+
|
|
481
|
+
## Security Principles
|
|
482
|
+
|
|
483
|
+
1. **Trust Nothing**: All external data is potentially malicious
|
|
484
|
+
2. **Validate Once**: At the boundary, then trust typed data
|
|
485
|
+
3. **Fail Secure**: Invalid input = reject, not accept with warning
|
|
486
|
+
4. **Clear Errors**: Help legitimate users fix issues
|
|
487
|
+
5. **No Bypass**: No "skip validation" flags or backdoors
|
|
488
|
+
|
|
489
|
+
## Success Criteria
|
|
490
|
+
|
|
491
|
+
Input validation passes when:
|
|
492
|
+
- ✅ All boundaries identified and validated
|
|
493
|
+
- ✅ Schema validation used (not manual checks)
|
|
494
|
+
- ✅ No SQL injection risks
|
|
495
|
+
- ✅ External data validated before use
|
|
496
|
+
- ✅ Configuration validated on startup
|
|
497
|
+
- ✅ Validation errors return Result types
|
|
498
|
+
- ✅ Tests cover invalid input scenarios
|
|
499
|
+
|
|
500
|
+
## Example Scenario
|
|
501
|
+
|
|
502
|
+
```
|
|
503
|
+
User: "Add API endpoint to create orders"
|
|
504
|
+
→ input-validation activates
|
|
505
|
+
→ Analyzes: New API endpoint = boundary
|
|
506
|
+
→ Checks: Is request body validated?
|
|
507
|
+
→ Reports: Missing validation
|
|
508
|
+
→ Blocks: Until schema validation added
|
|
509
|
+
→ Verifies: Validation implemented correctly
|
|
510
|
+
→ Confirms: SQL queries parameterized
|
|
511
|
+
→ Approves: Safe to proceed
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
This prevents shipping security vulnerabilities.
|