home / skills / jackspace / claudeskillz / defense-in-depth_obra

defense-in-depth_obra skill

/skills/defense-in-depth_obra

This skill enforces defense-in-depth validation by validating data at entry, business logic, environment, and debugging layers to prevent bugs.

This is most likely a fork of the defense-in-depth skill from microck
npx playbooks add skill jackspace/claudeskillz --skill defense-in-depth_obra

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
3.8 KB
---
name: defense-in-depth
description: Use when invalid data causes failures deep in execution, requiring validation at multiple system layers - validates at every layer data passes through to make bugs structurally impossible
---

# Defense-in-Depth Validation

## Overview

When you fix a bug caused by invalid data, adding validation at one place feels sufficient. But that single check can be bypassed by different code paths, refactoring, or mocks.

**Core principle:** Validate at EVERY layer data passes through. Make the bug structurally impossible.

## Why Multiple Layers

Single validation: "We fixed the bug"
Multiple layers: "We made the bug impossible"

Different layers catch different cases:
- Entry validation catches most bugs
- Business logic catches edge cases
- Environment guards prevent context-specific dangers
- Debug logging helps when other layers fail

## The Four Layers

### Layer 1: Entry Point Validation
**Purpose:** Reject obviously invalid input at API boundary

```typescript
function createProject(name: string, workingDirectory: string) {
  if (!workingDirectory || workingDirectory.trim() === '') {
    throw new Error('workingDirectory cannot be empty');
  }
  if (!existsSync(workingDirectory)) {
    throw new Error(`workingDirectory does not exist: ${workingDirectory}`);
  }
  if (!statSync(workingDirectory).isDirectory()) {
    throw new Error(`workingDirectory is not a directory: ${workingDirectory}`);
  }
  // ... proceed
}
```

### Layer 2: Business Logic Validation
**Purpose:** Ensure data makes sense for this operation

```typescript
function initializeWorkspace(projectDir: string, sessionId: string) {
  if (!projectDir) {
    throw new Error('projectDir required for workspace initialization');
  }
  // ... proceed
}
```

### Layer 3: Environment Guards
**Purpose:** Prevent dangerous operations in specific contexts

```typescript
async function gitInit(directory: string) {
  // In tests, refuse git init outside temp directories
  if (process.env.NODE_ENV === 'test') {
    const normalized = normalize(resolve(directory));
    const tmpDir = normalize(resolve(tmpdir()));

    if (!normalized.startsWith(tmpDir)) {
      throw new Error(
        `Refusing git init outside temp dir during tests: ${directory}`
      );
    }
  }
  // ... proceed
}
```

### Layer 4: Debug Instrumentation
**Purpose:** Capture context for forensics

```typescript
async function gitInit(directory: string) {
  const stack = new Error().stack;
  logger.debug('About to git init', {
    directory,
    cwd: process.cwd(),
    stack,
  });
  // ... proceed
}
```

## Applying the Pattern

When you find a bug:

1. **Trace the data flow** - Where does bad value originate? Where used?
2. **Map all checkpoints** - List every point data passes through
3. **Add validation at each layer** - Entry, business, environment, debug
4. **Test each layer** - Try to bypass layer 1, verify layer 2 catches it

## Example from Session

Bug: Empty `projectDir` caused `git init` in source code

**Data flow:**
1. Test setup → empty string
2. `Project.create(name, '')`
3. `WorkspaceManager.createWorkspace('')`
4. `git init` runs in `process.cwd()`

**Four layers added:**
- Layer 1: `Project.create()` validates not empty/exists/writable
- Layer 2: `WorkspaceManager` validates projectDir not empty
- Layer 3: `WorktreeManager` refuses git init outside tmpdir in tests
- Layer 4: Stack trace logging before git init

**Result:** All 1847 tests passed, bug impossible to reproduce

## Key Insight

All four layers were necessary. During testing, each layer caught bugs the others missed:
- Different code paths bypassed entry validation
- Mocks bypassed business logic checks
- Edge cases on different platforms needed environment guards
- Debug logging identified structural misuse

**Don't stop at one validation point.** Add checks at every layer.

Overview

This skill codifies a defense-in-depth validation pattern that prevents invalid input from causing failures deep in execution. It enforces checks at every layer data traverses so bugs become structurally impossible. Use it to harden APIs, business logic, environment-sensitive operations, and forensic logging.

How this skill works

The skill instruments four validation layers: entry-point checks that reject malformed input, business-logic validations that assert operation-specific invariants, environment guards that block dangerous actions in particular contexts, and debug instrumentation that records context for post-mortem analysis. When bad data appears, the system traces data flow, maps checkpoints, and applies tests to ensure each layer catches or contains errors.

When to use it

  • When a bug is caused by invalid or unexpected input that surfaces far from its origin
  • When unit or integration tests bypass a single validation and produce flaky failures
  • Before performing environment-sensitive or destructive operations (e.g., git init, file writes, external commands)
  • When you need stronger guarantees than a single validation point provides
  • When you want rich context for diagnosing failures in CI, tests, or production

Best practices

  • Validate at the API boundary: reject empty, missing, or clearly invalid values immediately
  • Add business-level assertions where data is actually used, not just at entry points
  • Implement environment guards that detect and refuse risky operations in CI, tests, or constrained runtimes
  • Log contextual debug data (inputs, cwd, stack) before sensitive actions for fast forensics
  • Write tests that attempt to bypass each layer to prove the defense-in-depth stance
  • Favor explicit, small checks over brittle heuristics; fail fast with clear errors

Example use cases

  • Protect a project creation endpoint from empty or nonexistent directories by validating inputs and existence before proceeding
  • Prevent tests from running destructive commands by refusing operations outside temp directories
  • Harden data pipelines by asserting invariants in transformation stages, plus environment checks for resource access
  • Instrument build or deployment steps with preflight guards and debug logs to make CI failures actionable
  • Fix recurring flaky tests by mapping data flow and adding layered validations to stop unexpected defaults

FAQ

Will adding many validations slow my system?

No—checks are typically cheap and localized. Use inexpensive guards at entry points and business logic; reserve heavier diagnostics for debug paths.

How do I avoid duplication across layers?

Keep validations focused: entry points detect syntactic issues, business logic enforces semantics, environment guards check context, and logs provide context. Share common helper validators where appropriate.