返回知识库
0

第十六章:Webhook 与外部事件

本章目标:帮助你理解 dsh 的 Webhook 机制——验证外部事件的签名机制、可信规则(Trusted Rules)的配置、Workspace Session 的创建流程、以及与 CI/CD 的集成模式。阅读本章后,你应该能回答"外部事件如何触发 Agent 行为"以及"如何安全地处理 Webhook"。


16.1 Webhook 架构

16.1.1 概念

Webhook 允许外部系统通过 HTTP 请求触发 Agent 行为。dsh 提供:

  1. 签名验证:确保请求来自可信来源

  2. 可信规则:配置哪些事件触发哪些行为

  3. Workspace Session:为每个 Webhook 创建独立的会话

预览
源码

Agent

dsh Webhook

外部系统

GitHub

GitLab

CI/CD

HTTP 端点

签名验证

规则匹配

Session 创建

Agent Loop

工具执行

graph TB
    subgraph "外部系统"
        A[GitHub]
        B[GitLab]
        C[CI/CD]
    end

    subgraph "dsh Webhook"
        D[HTTP 端点]
        E[签名验证]
        F[规则匹配]
        G[Session 创建]
    end

    subgraph "Agent"
        H[Agent Loop]
        I[工具执行]
    end

    A --> D
    B --> D
    C --> D
    D --> E
    E --> F
    F --> G
    G --> H
    H --> I

16.2 签名验证

16.2.1 HMAC 签名

Webhook 使用 HMAC-SHA256 签名验证请求:

// 来自 packages/webhook/webhook/src/index.ts(概念性)
class WebhookVerifier {
  /** 验证签名 */
  verify(payload: string, signature: string, secret: string): boolean {
    // 计算期望的签名
    const expectedSignature = crypto
      .createHmac('sha256', secret)
      .update(payload)
      .digest('hex')
    
    // 比较签名
    return crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expectedSignature)
    )
  }
}

16.2.2 验证流程

预览
源码
规则匹配签名验证Webhook 端点外部系统规则匹配签名验证Webhook 端点外部系统POST /webhookverify(payload, signature)valid = truematchRule(payload)rule = "github-push"createSession(rule)
sequenceDiagram
    participant External as 外部系统
    participant Webhook as Webhook 端点
    participant Verifier as 签名验证
    participant Rule as 规则匹配

    External->>Webhook: POST /webhook
    Webhook->>Verifier: verify(payload, signature)
    Verifier-->>Webhook: valid = true
    Webhook->>Rule: matchRule(payload)
    Rule-->>Webhook: rule = "github-push"
    Webhook->>Webhook: createSession(rule)

16.3 可信规则

16.3.1 规则定义

// 来自 packages/webhook/webhook/src/index.ts(概念性)
interface WebhookRule {
  /** 规则名称 */
  name: string
  /** 匹配条件 */
  match: {
    /** 来源 */
    source?: string  // 'github' | 'gitlab' | 'custom'
    /** 事件类型 */
    eventType?: string
    /** 路径模式 */
    pathPattern?: string
  }
  /** 触发的行为 */
  action: {
    /** Agent 预设 */
    agentPreset?: string
    /** 系统提示 */
    systemPrompt?: string
    /** 工具限制 */
    allowedTools?: string[]
  }
}

16.3.2 规则配置

# cordis.patch.yml
- id: webhook
  config:
    # 可信规则
    rules:
      - name: 'github-push'
        match:
          source: 'github'
          eventType: 'push'
        action:
          agentPreset: 'code-reviewer'
          systemPrompt: 'Review the pushed changes'
          allowedTools:
            - 'file_read'
            - 'bash'
      
      - name: 'github-issue'
        match:
          source: 'github'
          eventType: 'issues'
        action:
          agentPreset: 'issue-handler'
          systemPrompt: 'Handle the new issue'
    
    # 端点配置
    endpoint:
      port: 3001
      path: '/webhook'
    
    # 签名密钥
    secrets:
      github: '${GITHUB_WEBHOOK_SECRET}'
      gitlab: '${GITLAB_WEBHOOK_SECRET}'

16.4 Workspace Session

16.4.1 概念

每个 Webhook 事件创建一个独立的 Workspace Session,确保:

  1. 隔离:不同事件的会话互不影响

  2. 追踪:每个事件有完整的审计日志

  3. 清理:会话完成后自动清理

// 来自 packages/webhook/webhook/src/index.ts(概念性)
class WebhookRuntime {
  /** 处理 Webhook 事件 */
  async handleEvent(event: WebhookEvent): Promise<void> {
    // 1. 验证签名
    const isValid = this.verifier.verify(
      event.payload,
      event.signature,
      this.getSecret(event.source)
    )
    
    if (!isValid) {
      throw new Error('Invalid webhook signature')
    }
    
    // 2. 匹配规则
    const rule = this.matchRule(event)
    if (!rule) {
      console.log('No matching rule for event')
      return
    }
    
    // 3. 创建 Workspace Session
    const session = await this.createWorkspaceSession(event, rule)
    
    // 4. 触发 Agent
    await this.triggerAgent(session, rule)
  }
  
  /** 创建 Workspace Session */
  private async createWorkspaceSession(
    event: WebhookEvent,
    rule: WebhookRule
  ): Promise<Session> {
    return this.ctx.agents.create({
      sessionId: generateSessionId(),
      meta: {
        origin: 'webhook',
        cwd: '/workspace'
      }
    })
  }
}

16.5 与 CI/CD 集成

16.5.1 GitHub Actions 集成

# .github/workflows/dsh-webhook.yml
name: DSH Webhook
on:
  push:
    branches: [main]
  pull_request:
    types: [opened, synchronize]

jobs:
  trigger-dsh:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger DSH Webhook
        run: |
          curl -X POST \
            -H "Content-Type: application/json" \
            -H "X-Hub-Signature-256: sha256=${{ secrets.WEBHOOK_SIGNATURE }}" \
            -d '{"event": "push", "ref": "${{ github.ref }}"}' \
            https://your-dsh-instance.com/webhook

16.5.2 GitLab 集成

# .gitlab-ci.yml
stages:
  - trigger

trigger-dsh:
  stage: trigger
  script:
    - |
      curl -X POST \
        -H "Content-Type: application/json" \
        -H "X-Gitlab-Token: ${WEBHOOK_SECRET}" \
        -d '{"event": "push", "ref": "${CI_COMMIT_REF_NAME}"}' \
        https://your-dsh-instance.com/webhook
  only:
    - main

16.6 安全考虑

16.6.1 签名验证

// 确保使用 timing-safe 比较
function timingSafeEqual(a: Buffer, b: Buffer): boolean {
  if (a.length !== b.length) return false
  
  let result = 0
  for (let i = 0; i < a.length; i++) {
    result |= a[i] ^ b[i]
  }
  
  return result === 0
}

16.6.2 速率限制

// 概念性描述
class RateLimiter {
  private requests = new Map<string, number[]>()
  
  /** 检查速率限制 */
  check(source: string, limit: number, window: number): boolean {
    const now = Date.now()
    const timestamps = this.requests.get(source) ?? []
    
    // 清理过期的请求
    const validTimestamps = timestamps.filter(t => now - t < window)
    
    if (validTimestamps.length >= limit) {
      return false  // 超过速率限制
    }
    
    validTimestamps.push(now)
    this.requests.set(source, validTimestamps)
    
    return true
  }
}

16.7 配置

16.7.1 Webhook 配置

# cordis.patch.yml
- id: webhook
  config:
    # 端点
    endpoint:
      port: 3001
      path: '/webhook'
    
    # 签名验证
    verification:
      enabled: true
      tolerance: 300  # 5 分钟
    
    # 速率限制
    rateLimit:
      enabled: true
      limit: 100
      window: 60000  # 1 分钟
    
    # 会话配置
    session:
      autoCleanup: true
      maxAge: 3600000  # 1 小时

16.8 小结

概念一句话解释
Webhook外部事件触发 Agent 行为
签名验证HMAC-SHA256 验证请求来源
可信规则配置事件到行为的映射
Workspace Session为每个事件创建独立会话
速率限制防止滥用

下一步第十七章:Self-Modification 扩展——深入理解 Agent 如何检查和挂载自己的插件。

DeepSeek-Harness / 16-Webhook 与外部事件 0 0 iliuqi
2026-09-04T07:48:53.521066890Z 2026-09-04T07:58:34.738408936Z