mcpField
D
dependency-vulnerability-triage

dependency-vulnerability-triage

github.com/patricio0312rev安全63280 次安装41 周前更新
代码仓库

关于 dependency-vulnerability-triage

这项 Skill 将依赖漏洞报告转化为分级修复计划,涵盖风险评估、升级排序、补丁自动化、CI 门禁和回滚流程。

主要功能

  1. 01解析审计报告
  2. 02按严重度和时限排列补丁
  3. 03评估升级风险
  4. 04按依赖关系安排升级顺序
  5. 05提供补丁与回滚流程
  6. 06说明 CI 漏洞门禁

适用场景

  1. 01处理新的依赖审计结果
  2. 02规划相互依赖的软件包升级
  3. 03为版本发布确定补丁优先级
  4. 04准备回滚有问题的补丁

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/patricio0312rev/skills --skill dependency-vulnerability-triage

安装后在 Claude Code 中输入/dependency-vulnerability-triage确认已加载。

详细介绍

依赖项漏洞分诊

将漏洞报告转化为可执行的修补计划。

漏洞严重性矩阵

// severity-matrix.ts
export interface Vulnerability {
  id: string;
  package: string;
  currentVersion: string;
  patchedVersion: string;
  severity: "critical" | "high" | "medium" | "low";
  cvss: number;
  cwe: string[];
  exploitability: "high" | "medium" | "low";
  impact: string;
  path: string[];
}

export interface PatchPriority {
  vulnerability: Vulnerability;
  priority: 1 | 2 | 3 | 4;
  reasoning: string;
  patchWindow: "24h" | "1week" | "1month" | "next-release";
  breakingChange: boolean;
  testingRequired: "minimal" | "moderate" | "extensive";
}

export function calculatePriority(vuln: Vulnerability): PatchPriority {
  let priority: 1 | 2 | 3 | 4 = 4;
  let patchWindow: "24h" | "1week" | "1month" | "next-release" = "next-release";
  let testingRequired: "minimal" | "moderate" | "extensive" = "minimal";

  // P1: Critical + High Exploitability + Production
  if (
    vuln.severity === "critical" &&
    vuln.exploitability === "high" &&
    isProductionDependency(vuln.package)
  ) {
    priority = 1;
    patchWindow = "24h";
    testingRequired = "moderate";
  }
  // P2: High + Medium/High Exploitability
  else if (
    vuln.severity === "high" &&
    ["high", "medium"].includes(vuln.exploitability)
  ) {
    priority = 2;
    patchWindow = "1week";
    testingRequired = "moderate";
  }
  // P3: Medium or Low Exploitability High
  else if (
    vuln.severity === "medium" ||
    (vuln.severity === "high" && vuln.exploitability === "low")
  ) {
    priority = 3;
    patchWindow = "1month";
    testingRequired = "minimal";
  }

  return {
    vulnerability: vuln,
    priority,
    reasoning: `${vuln.severity} severity, ${vuln.exploitability} exploitability`,
    patchWindow,
    breakingChange: isBreakingChange(vuln.currentVersion, vuln.patchedVersion),
    testingRequired,
  };
}

审计报告解析器

// scripts/parse-audit.ts
import { execSync } from "child_process";

interface NpmAuditResult {
  vulnerabilities: Record<string, any>;
  metadata: {
    vulnerabilities: {
      critical: number;
      high: number;
      moderate: number;
      low: number;
    };
  };
}

function parseNpmAudit(): Vulnerability[] {
  const auditOutput = execSync("npm audit --json", { encoding: "utf-8" });
  const audit: NpmAuditResult = JSON.parse(auditOutput);

  const vulnerabilities: Vulnerability[] = [];

  Object.entries(audit.vulnerabilities).forEach(([pkg, data]) => {
    vulnerabilities.push({
      id: data.via[0]?.url || `vuln-${pkg}`,
      package: pkg,
      currentVersion: data.range,
      patchedVersion: data.fixAvailable?.version || "N/A",
      severity: data.severity,
      cvss: data.via[0]?.cvss?.score || 0,
      cwe: data.via[0]?.cwe || [],
      exploitability: determineExploitability(data),
      impact: data.via[0]?.title || "Unknown",
      path: data.via.map((v: any) => v.name),
    });
  });

  return vulnerabilities;
}

function determineExploitability(data: any): "high" | "medium" | "low" {
  // Check if actively exploited
  if (
    data.via[0]?.findings?.some((f: any) => f.exploit === "proof-of-concept")
  ) {
    return "high";
  }

  // Check CVSS exploitability subscore
  const exploitScore = data.via[0]?.cvss?.exploitabilityScore;
  if (exploitScore > 3.5) return "high";
  if (exploitScore > 2.0) return "medium";
  return "low";
}

修补计划生成器

// scripts/generate-patch-plan.ts
interface PatchPlan {
  immediate: PatchPriority[]; // P1 - 24h
  shortTerm: PatchPriority[]; // P2 - 1 week
  mediumTerm: PatchPriority[]; // P3 - 1 month
  longTerm: PatchPriority[]; // P4 - next release
  breakingChanges: PatchPriority[];
  safeUpgrades: PatchPriority[];
}

function generatePatchPlan(vulnerabilities: Vulnerability[]): PatchPlan {
  const prioritized = vulnerabilities.map(calculatePriority);

  return {
    immediate: prioritized.filter((p) => p.priority === 1),
    shortTerm: prioritized.filter((p) => p.priority === 2),
    mediumTerm: prioritized.filter((p) => p.priority === 3),
    longTerm: prioritized.filter((p) => p.priority === 4),
    breakingChanges: prioritized.filter((p) => p.breakingChange),
    safeUpgrades: prioritized.filter((p) => !p.breakingChange),
  };
}

function printPatchPlan(plan: PatchPlan) {
  console.log("# Security Patch Plan\n");

  console.log("## 🚨 Immediate (24 hours)\n");
  plan.immediate.forEach((p) => {
    console.log(
      `- **${p.vulnerability.package}** ${p.vulnerability.currentVersion} → ${p.vulnerability.patchedVersion}`
    );
    console.log(`  ${p.vulnerability.impact}`);
    console.log(`  Breaking: ${p.breakingChange ? "YES ⚠️" : "No"}`);
  });

  console.log("\n## ⚡ Short-term (1 week)\n");
  plan.shortTerm.forEach((p) => {
    console.log(
      `- **${p.vulnerability.package}** ${p.vulnerability.currentVersion} → ${p.vulnerability.patchedVersion}`
    );
  });

  console.log("\n## 📅 Medium-term (1 month)\n");
  plan.mediumTerm.forEach((p) => {
    console.log(
      `- ${p.vulnerability.package} ${p.vulnerability.currentVersion} → ${p.vulnerability.patchedVersion}`
    );
  });

  console.log("\n## ⚠️ Breaking Changes\n");
  plan.breakingChanges.forEach((p) => {
    console.log(`- ${p.vulnerability.package}: Review migration guide`);
  });
}

安全升级顺序

// Dependency graph-based upgrade order
interface DependencyGraph {
  [pkg: string]: string[];
}

function determineSafeUpgradeOrder(
  patches: PatchPriority[]
): PatchPriority[][] {
  const graph = buildDependencyGraph();
  const ordered: PatchPriority[][] = [];

  // Level 0: No dependencies on other patches
  const level0 = patches.filter(
    (p) => !hasUpgradeDependencies(p.vulnerability.package, patches, graph)
  );
  ordered.push(level0);

  // Level 1+: Depends on previous levels
  let remaining = patches.filter((p) => !level0.includes(p));
  let level = 1;

  while (remaining.length > 0 && level < 10) {
    const currentLevel = remaining.filter((p) =>
      canUpgradeNow(p.vulnerability.package, ordered.flat(), graph)
    );

    if (currentLevel.length === 0) break; // Circular dependency

    ordered.push(currentLevel);
    remaining = remaining.filter((p) => !currentLevel.includes(p));
    level++;
  }

  return ordered;
}

// Example output:
// Level 0: [lodash, axios] - No dependencies
// Level 1: [express] - Depends on lodash
// Level 2: [next] - Depends on express

风险评估

interface RiskAssessment {
  package: string;
  riskFactors: string[];
  riskScore: number; // 1-10
  mitigations: string[];
}

function assessUpgradeRisk(patch: PatchPriority): RiskAssessment {
  const risks: string[] = [];
  let score = 0;

  // Check for breaking changes
  if (patch.breakingChange) {
    risks.push("Breaking changes detected");
    score += 4;
  }

  // Check for major version bump
  if (
    isMajorVersionBump(
      patch.vulnerability.currentVersion,
      patch.vulnerability.patchedVersion
    )
  ) {
    risks.push("Major version upgrade");
    score += 3;
  }

  // Check usage patterns
  const usage = analyzePackageUsage(patch.vulnerability.package);
  if (usage.importCount > 50) {
    risks.push("Heavily used in codebase");
    score += 2;
  }

  // Check test coverage
  if (usage.testCoverage < 0.7) {
    risks.push("Low test coverage");
    score += 2;
  }

  return {
    package: patch.vulnerability.package,
    riskFactors: risks,
    riskScore: Math.min(score, 10),
    mitigations: generateMitigations(risks),
  };
}

function generateMitigations(risks: string[]): string[] {
  const mitigations: string[] = [];

  if (risks.includes("Breaking changes detected")) {
    mitigations.push("Read CHANGELOG and migration guide");
    mitigations.push("Test on feature branch first");
    mitigations.push("Deploy to staging before production");
  }

  if (risks.includes("Heavily used in codebase")) {
    mitigations.push("Run full test suite");
    mitigations.push("Perform manual smoke tests");
    mitigations.push("Monitor error rates after deploy");
  }

  if (risks.includes("Low test coverage")) {
    mitigations.push("Add tests for critical paths");
    mitigations.push("Extend monitoring");
  }

  return mitigations;
}

自动修补脚本

#!/bin/bash
# scripts/apply-patches.sh

set -e

PRIORITY=$1  # immediate, short-term, medium-term

if [ -z "$PRIORITY" ]; then
  echo "Usage: ./apply-patches.sh [immediate|short-term|medium-term]"
  exit 1
fi

echo "🔧 Applying $PRIORITY patches..."

# Generate patch plan
npm audit --json > audit-report.json
node scripts/generate-patch-plan.js --priority=$PRIORITY > patch-plan.json

# Apply patches
while IFS= read -r package; do
  echo "Updating $package..."

  # Try to apply fix
  npm audit fix --package-lock-only --package=$package

  # Run tests
  if npm test; then
    echo "✅ Tests passed for $package"
    git add package.json package-lock.json
    git commit -m "security: patch $package vulnerability"
  else
    echo "❌ Tests failed for $package - reverting"
    git checkout package.json package-lock.json
  fi
done < <(jq -r '.packages[]' patch-plan.json)

echo "✅ Patches applied"

CI 漏洞门禁

# .github/workflows/security-audit.yml
name: Security Audit

on:
  pull_request:
  schedule:
    - cron: "0 0 * * *" # Daily

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Install dependencies
        run: npm ci

      - name: Run npm audit
        run: npm audit --audit-level=moderate
        continue-on-error: true

      - name: Run Snyk test
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

      - name: Generate patch plan
        if: failure()
        run: npm run generate-patch-plan

      - name: Comment PR
        if: failure() && github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const plan = fs.readFileSync('patch-plan.md', 'utf8');
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: plan
            });

修补回滚策略

## Vulnerability Patch Rollback Plan

### Before Patching

1. **Create rollback tag**
   ```bash
   git tag -a pre-security-patch-$(date +%Y%m%d) -m "Pre-patch checkpoint"
   ```
  1. 记录当前版本

    npm list --depth=0 > versions-before.txt
    
  2. 运行基准测试

    npm test > test-results-before.txt
    
回滚步骤

如果修补后检测到问题:

  1. 立即还原

    git revert HEAD
    git push origin main
    
  2. 重新部署先前版本

    git checkout pre-security-patch-$(date +%Y%m%d)
    npm ci
    npm run build
    npm run deploy
    
  3. 验证回滚

    npm test
    npm run smoke-tests
    
  4. 事件报告

    • 记录失败原因
    • 根据新的风险因素更新修补计划
    • 安排重试并增加测试

## Best Practices

1. **Triage weekly**: Review new vulnerabilities
2. **Prioritize by impact**: Not just severity score
3. **Test before merging**: Automated + manual testing
4. **Stage deployments**: Dev → Staging → Production
5. **Monitor after patch**: Watch error rates
6. **Document breaking changes**: Migration guides
7. **Keep dependencies updated**: Reduce vulnerability surface

## Output Checklist

- [ ] Severity matrix defined
- [ ] Audit parser implemented
- [ ] Patch plan generated
- [ ] Safe upgrade order determined
- [ ] Risk assessment completed
- [ ] Breaking changes identified
- [ ] Automated patch script
- [ ] CI vulnerability gating
- [ ] Rollback strategy documented
- [ ] Team notified of critical patches

评论

支持 Markdown