defense-in-depth-validation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

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.
当你修复了一个由无效数据引发的bug时,在单一位置添加验证似乎就足够了。但这种单一校验可能会被不同的代码路径、重构操作或模拟数据绕过。
核心原则: 在数据流经的每一层都进行验证,从结构上让bug无产生的可能。

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
单一验证:"我们修复了这个bug" 多层验证:"我们从根源上杜绝了这个bug"
不同的层级可以捕捉不同的场景:
  • 入口验证可拦截绝大多数bug
  • 业务逻辑验证可捕捉边缘场景
  • 环境防护可避免特定上下文下的风险
  • 调试日志可在其他层级失效时提供排查依据

The Four Layers

四个验证层级

Layer 1: Entry Point Validation

层级1:入口点验证

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
}
目标: 在API边界处直接拒绝明显无效的输入
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

层级2:业务逻辑验证

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
}
目标: 确保数据符合当前操作的逻辑要求
typescript
function initializeWorkspace(projectDir: string, sessionId: string) {
  if (!projectDir) {
    throw new Error('projectDir required for workspace initialization');
  }
  // ... proceed
}

Layer 3: Environment Guards

层级3:环境防护

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
}
目标: 防止在特定上下文下执行危险操作
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

层级4:调试工具埋点

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
}
目标: 捕获上下文信息以用于问题排查
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
当你发现一个bug时:
  1. 追踪数据流 - 错误值的来源在哪里?会被用在哪些地方?
  2. 梳理所有检查点 - 列出数据流经的每一个节点
  3. 在每个层级添加验证 - 入口、业务逻辑、环境防护、调试埋点
  4. 测试每个层级 - 尝试绕过层级1的验证,验证层级2是否能拦截

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
Bug场景:空值
projectDir
导致
git init
在源码目录中执行
数据流:
  1. 测试设置 → 传入空字符串
  2. Project.create(name, '')
  3. WorkspaceManager.createWorkspace('')
  4. git init
    process.cwd()
    目录下执行
添加的四个层级验证:
  • 层级1:
    Project.create()
    验证路径非空、存在且可写入
  • 层级2:
    WorkspaceManager
    验证projectDir非空
  • 层级3:
    WorktreeManager
    在测试环境下拒绝在临时目录外执行git init
  • 层级4:执行git init前记录堆栈跟踪日志
结果: 全部1847个测试用例通过,该bug无法再复现

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.
这四个层级的验证缺一不可。在测试过程中,每个层级都捕捉到了其他层级未覆盖的bug:
  • 不同的代码路径绕过了入口验证
  • 模拟数据绕过了业务逻辑校验
  • 不同平台的边缘场景需要环境防护
  • 调试日志发现了结构性误用
不要仅停留在单一验证点。要在每一个层级都添加校验。