Back to skills

Defense In Depth

Multi-layer validation strategy that makes bugs structurally impossible rather than merely fixed. After finding and fixing a bug's root cause, implement validation at every layer data passes through.

26 stars
0 votes
0 copies
0 views
Added 12/19/2025
toolstypescriptrustnodedebuggingrefactoringapidatabase

Works with

api

Install via CLI

$openskills install duthaho/claudekit
Download Zip
Files
SKILL.md
# Defense-in-Depth

## Description

Multi-layer validation strategy that makes bugs structurally impossible rather than merely fixed. After finding and fixing a bug's root cause, implement validation at every layer data passes through.

## 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

---

## 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

---

Comments (0)

No comments yet. Be the first to comment!