feat: improved the Claude Kit as a plugin

This commit is contained in:
duthaho
2026-04-19 14:10:38 +07:00
parent 3103a8da1b
commit d1a6d2a2bc
186 changed files with 771 additions and 1691 deletions
+300
View File
@@ -0,0 +1,300 @@
---
name: defense-in-depth
user-invocable: false
description: >
Use when fixing any data-related bug, when building validation for critical data paths, or when a single validation point has already failed in production. Also activate whenever you hear "it slipped through," "the check was bypassed," or "it worked in tests but not production." Apply aggressively to any scenario involving data integrity, input validation across layers, or preventing bug recurrence through structural guarantees rather than single-point fixes.
---
# Defense-in-Depth
## When to Use
- After fixing any data-related bug
- Protecting critical data paths
- Preventing bug recurrence
- Building robust systems
- When single validation points have failed
## When NOT to Use
- Greenfield prototyping where speed matters more than robustness and requirements are still fluid
- Non-data-related bugs such as logic errors, race conditions, or algorithmic mistakes
- UI styling issues where visual correctness is the concern, not data integrity
---
## Core Concept
**"Validate at EVERY layer data passes through. Make the bug structurally impossible."**
Single validation points can be bypassed:
- Alternative code paths skip validation
- Refactoring accidentally removes checks
- Tests mock away the validation
Multiple layers create redundancy:
- Different layers catch different cases
- If one check fails, another catches it
- Bug becomes impossible, not just unlikely
---
## The Four-Layer Approach
### Layer 1: Entry Point Validation
Reject invalid input at API/system boundaries:
```typescript
// API endpoint - first line of defense
app.post('/orders', (req, res) => {
// Type check
if (typeof req.body.userId !== 'string') {
return res.status(400).json({ error: 'userId must be a string' });
}
// Existence check
if (!req.body.userId) {
return res.status(400).json({ error: 'userId is required' });
}
// Format validation
if (!isValidUUID(req.body.userId)) {
return res.status(400).json({ error: 'userId must be a valid UUID' });
}
// Proceed with valid data
orderService.createOrder(req.body);
});
```
### Layer 2: Business Logic Validation
Ensure data semantically makes sense for the operation:
```typescript
// Service layer - business rules
class OrderService {
async createOrder(data: OrderData) {
// Business validation
const user = await this.userRepo.findById(data.userId);
if (!user) {
throw new BusinessError('User does not exist');
}
if (!user.canPlaceOrders) {
throw new BusinessError('User is not allowed to place orders');
}
if (data.items.length === 0) {
throw new BusinessError('Order must have at least one item');
}
// Proceed with valid business state
return this.orderRepo.create(data);
}
}
```
### Layer 3: Environment Guards
Add context-specific safeguards:
```typescript
// Repository layer - environment guards
class OrderRepository {
async create(order: Order) {
// Test environment guard
if (process.env.NODE_ENV === 'test' && !process.env.ALLOW_DB_WRITES) {
throw new Error('Database writes disabled in test environment');
}
// Production safety guard
if (order.total > 100000 && !order.managerApproval) {
throw new Error('Large orders require manager approval');
}
// Dangerous operation guard
if (order.userId === SYSTEM_USER_ID) {
throw new Error('Cannot create orders for system user');
}
return this.db.insert('orders', order);
}
}
```
### Layer 4: Debug Instrumentation
Capture execution context for forensic analysis:
```typescript
// Logging layer - forensic evidence
class OrderRepository {
async create(order: Order) {
// Log entry for debugging
this.logger.debug('Creating order', {
orderId: order.id,
userId: order.userId,
itemCount: order.items.length,
total: order.total,
timestamp: new Date().toISOString(),
requestId: context.requestId
});
try {
const result = await this.db.insert('orders', order);
this.logger.info('Order created successfully', {
orderId: result.id,
duration: Date.now() - start
});
return result;
} catch (error) {
this.logger.error('Order creation failed', {
orderId: order.id,
error: error.message,
stack: error.stack,
order: JSON.stringify(order)
});
throw error;
}
}
}
```
---
## Why Multiple Layers?
### Single Point Failure
```typescript
// Only one check - easily bypassed
function createOrder(data) {
if (!data.userId) throw new Error('userId required'); // Single check
// ...
}
// Direct repository call bypasses validation
orderRepository.create({ items: [] }); // No userId check!
```
### Multi-Layer Protection
```typescript
// Multiple checks - defense in depth
// Layer 1: API validates
// Layer 2: Service validates
// Layer 3: Repository validates
// Even if one is bypassed, others catch it
orderRepository.create({ items: [] });
// Repository throws: "userId is required"
```
---
## Implementation Strategy
When debugging, use this approach:
### 1. Trace the Data Flow
```markdown
User Input → API → Service → Repository → Database
```
### 2. Identify Checkpoints
```markdown
Where does this data pass through?
- API endpoint (Layer 1)
- Service method (Layer 2)
- Repository method (Layer 3)
- Database constraints (Layer 4)
```
### 3. Add Validation at Each
```markdown
For each checkpoint:
- What could be wrong at this point?
- What validation makes sense here?
- What error message helps debug?
```
### 4. Test Layer Independence
```markdown
Remove each layer one at a time:
- Does the bug still get caught?
- Which layer catches it?
- Is there a gap in coverage?
```
---
## Validation by Layer Type
| Layer | What to Validate | Example |
|-------|------------------|---------|
| Entry Point | Type, format, presence | `userId` is string, not empty |
| Business Logic | Semantic correctness | User exists, can place orders |
| Environment | Context-specific rules | Test mode restrictions |
| Data Access | Integrity constraints | Foreign keys, not null |
---
## Anti-Patterns
### Single Checkpoint Fallacy
```typescript
// BAD: One validation point
if (isValid(data)) {
// Assume valid everywhere else
}
```
### Validation in Tests Only
```typescript
// BAD: Tests validate, production doesn't
beforeEach(() => {
validateTestData(data); // This doesn't help production
});
```
### Trust After First Check
```typescript
// BAD: Validated once, trusted forever
const validatedData = validate(input);
// ... many lines later ...
process(validatedData); // Is it still valid?
```
---
## Checklist
After fixing any bug:
- [ ] Root cause identified
- [ ] Fix applied at source
- [ ] Layer 1 validation added (entry point)
- [ ] Layer 2 validation added (business logic)
- [ ] Layer 3 guards added (environment)
- [ ] Layer 4 logging added (instrumentation)
- [ ] Tested: removing any single layer still catches bug
- [ ] Bug is structurally impossible, not just fixed
---
## Related Skills
- `root-cause-tracing` - Use before defense-in-depth to find the actual source of the bug before adding multi-layer validation
- `systematic-debugging` - General debugging methodology that pairs with defense-in-depth for comprehensive bug resolution
- `owasp` - Security-specific validation patterns that complement defense-in-depth for security-sensitive code paths
@@ -0,0 +1,197 @@
# Validation Layers Reference
Multi-layer validation strategy ensuring no single point of failure.
## Overview
```
Request -> [Layer 1: Input] -> [Layer 2: Business] -> [Layer 3: Persistence] -> [Layer 4: Output] -> Response
```
Each layer validates independently. A failure at any layer should produce a clear, actionable error. Never rely on a single layer.
## Layer 1: Input Boundary
**Purpose**: Reject malformed, oversized, or obviously invalid data at the edge.
### What to Validate
- Data types and shapes (string, number, object structure)
- Required vs optional fields
- String length, numeric ranges, allowed values
- Format patterns (email, URL, UUID, date)
- Content-Type headers, encoding
- File upload size and MIME type
- Request rate and authentication tokens
### Python (FastAPI + Pydantic)
```python
from pydantic import BaseModel, Field, EmailStr
from fastapi import FastAPI, Query
class CreateUserRequest(BaseModel):
email: EmailStr
name: str = Field(min_length=1, max_length=200)
age: int = Field(ge=0, le=150)
role: Literal["admin", "user", "viewer"]
@app.post("/users")
async def create_user(req: CreateUserRequest):
# req is already validated by Pydantic
...
```
### TypeScript (Zod + Express)
```typescript
import { z } from "zod";
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(200),
age: z.number().int().min(0).max(150),
role: z.enum(["admin", "user", "viewer"]),
});
app.post("/users", (req, res) => {
const result = CreateUserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.issues });
}
// result.data is typed and validated
});
```
### Tools
| Language | Library | Purpose |
|---|---|---|
| Python | Pydantic, marshmallow, cerberus | Schema validation |
| TypeScript | Zod, Yup, io-ts, Ajv | Schema validation |
| Any | JSON Schema | Language-agnostic schema |
## Layer 2: Business Logic
**Purpose**: Enforce domain rules, state transitions, and authorization.
### What to Validate
- Business rules (e.g., "cannot cancel a shipped order")
- State machine transitions (e.g., draft -> published, not draft -> archived)
- Cross-field dependencies (e.g., "end_date must be after start_date")
- Authorization (e.g., "only the owner can modify this resource")
- Resource existence (e.g., "referenced entity must exist")
- Idempotency and duplicate detection
### Python
```python
class OrderService:
def cancel_order(self, order_id: str, user_id: str) -> Order:
order = self.repo.get(order_id)
if order is None:
raise NotFoundError(f"Order {order_id} not found")
if order.owner_id != user_id:
raise ForbiddenError("Only the order owner can cancel")
if order.status not in ("pending", "confirmed"):
raise BusinessRuleError(
f"Cannot cancel order in '{order.status}' status"
)
order.status = "cancelled"
return self.repo.save(order)
```
### TypeScript
```typescript
class OrderService {
cancelOrder(orderId: string, userId: string): Order {
const order = this.repo.get(orderId);
if (!order) throw new NotFoundError(`Order ${orderId} not found`);
if (order.ownerId !== userId) throw new ForbiddenError("Only the order owner can cancel");
const cancellableStatuses = ["pending", "confirmed"] as const;
if (!cancellableStatuses.includes(order.status)) {
throw new BusinessRuleError(`Cannot cancel order in '${order.status}' status`);
}
order.status = "cancelled";
return this.repo.save(order);
}
}
```
### Guidelines
- Keep validation logic in the service/domain layer, not in controllers
- Use custom exception types that map to HTTP status codes
- Business rules should be testable independently of HTTP/DB
## Layer 3: Data Persistence
**Purpose**: Enforce data integrity at the database level as the last line of defense.
### What to Validate
- NOT NULL constraints
- UNIQUE constraints (email, username)
- FOREIGN KEY constraints (referential integrity)
- CHECK constraints (value ranges, enums)
- Data types and precision
- Default values
### PostgreSQL Examples
```sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(200) NOT NULL CHECK (char_length(name) > 0),
age INTEGER CHECK (age >= 0 AND age <= 150),
role VARCHAR(20) NOT NULL CHECK (role IN ('admin', 'user', 'viewer')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'confirmed', 'shipped', 'cancelled')),
total_cents INTEGER NOT NULL CHECK (total_cents >= 0)
);
```
### Guidelines
- Mirror constraints in your ORM (SQLAlchemy `CheckConstraint`, Prisma `@unique`, etc.)
- Database constraints are the safety net; they catch bugs in application code
- Always handle constraint violation errors gracefully (unique violation -> 409 Conflict)
- Use migrations to manage schema changes
## Layer 4: Output Boundary
**Purpose**: Ensure responses are safe, well-formed, and contain only intended data.
### What to Validate
- Strip sensitive fields (passwords, internal IDs, tokens)
- HTML-encode user-generated content to prevent XSS
- Validate response schema (catch accidental data leaks)
- Set security headers (Content-Type, X-Content-Type-Options)
- Limit response size
### Techniques
- **Python**: Use Pydantic `response_model` to exclude fields not in the response schema
- **TypeScript**: Create explicit mapper functions (`toUserResponse()`) that pick only safe fields
- **Headers**: Set `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Content-Security-Policy`
- **Encoding**: HTML-encode user-generated content before rendering
## Layer Interaction Summary
| Layer | Catches | If Missing |
|---|---|---|
| Input | Malformed data, injection attempts | Bad data flows into business logic |
| Business | Invalid operations, auth bypass | Violated business rules, data corruption |
| Persistence | Constraint violations, duplicates | Inconsistent data in database |
| Output | Data leaks, XSS | Sensitive data exposed to clients |