mcpField
D
dependency-update-bot

dependency-update-bot

github.com/varnan-tech开发68743 次安装2 周前更新
代码仓库

关于 dependency-update-bot

Dependency Update Bot 是面向维护软件依赖项的开发者的更新自动化技能。它检查多个包管理器报告的过期包,进行安全审计并汇总变更,再按风险组创建 PR。

主要功能

  1. 01检测过期依赖项
  2. 02按版本变更分类风险
  3. 03执行安全漏洞审计
  4. 04获取并汇总更新日志
  5. 05按风险组创建 PR

适用场景

  1. 01定期检查项目依赖项更新
  2. 02优先处理包含高危漏洞的更新
  3. 03将重大版本升级拆分为独立 PR

安装

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

$npx skills add https://github.com/varnan-tech/opendirectory --skill dependency-update-bot

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

.env.example
README.md
evals/
evals.json
references/
changelog-patterns.md

详细介绍

依赖更新机器人

扫描过时的软件包。运行安全审计。获取变更日志。总结破坏性变更。按风险组分别创建一个 PR。


重要规则: 仅更新软件包管理器的过时命令实际报告的软件包。切勿猜测或编造版本号。如果无法获取变更日志,请注明缺失,而不要编造内容。


第 1 步:设置检查

echo "GEMINI_API_KEY: ${GEMINI_API_KEY:+set}"
echo "GITHUB_TOKEN: ${GITHUB_TOKEN:-not set, changelog fetching rate-limited to 60/hour}"
gh auth status 2>/dev/null | head -1 || echo "gh: not authenticated"

如果缺少 GEMINI_API_KEY: 停止。告知用户:“GEMINI_API_KEY 是必需的。请前往 aistudio.google.com 获取,并将其添加到 .env 文件中。”

如果 gh 尚未通过身份验证: 停止。告知用户:“GitHub CLI 必须通过身份验证。请运行:gh auth login”

检测软件包管理器:

ls package.json 2>/dev/null && echo "npm"
ls requirements.txt pyproject.toml 2>/dev/null && echo "pip"
ls Cargo.toml 2>/dev/null && echo "cargo"
ls go.mod 2>/dev/null && echo "go"
ls Gemfile 2>/dev/null && echo "ruby"

如果检测到多个,请询问:“找到 [list]。要扫描哪些?(all / npm / pip / cargo / go / ruby)”


第 2 步:检测过时的软件包

npm:

npm outdated --json --long 2>/dev/null | python3 -c "
import sys, json
data = json.load(sys.stdin)
for name, info in data.items():
    print(json.dumps({'name': name, 'current': info.get('current','?'), 'latest': info.get('latest','?'), 'dep_type': info.get('type','dependencies')}))
"

pip:

pip list --outdated --format=json 2>/dev/null | python3 -c "
import sys, json
for p in json.load(sys.stdin):
    print(json.dumps({'name': p['name'], 'current': p['version'], 'latest': p['latest_version']}))
"

Cargo(Rust):

cargo outdated --format json 2>/dev/null || \
  cargo outdated 2>/dev/null | grep -v "^---" | tail -n +3 | head -30
# If cargo-outdated not installed: cargo install cargo-outdated

Go 模块:

go list -u -m -json all 2>/dev/null | python3 -c "
import sys, json
decoder = json.JSONDecoder()
buf = sys.stdin.read()
pos = 0
while pos < len(buf):
    try:
        obj, idx = decoder.raw_decode(buf, pos)
        if obj.get('Update'):
            print(json.dumps({'name': obj['Path'], 'current': obj['Version'], 'latest': obj['Update']['Version']}))
        pos += idx
    except: break
"

Ruby(Bundler):

bundle outdated --parseable 2>/dev/null | python3 -c "
import sys
for line in sys.stdin:
    parts = line.strip().split()
    if len(parts) >= 4:
        print('{\"name\":\"' + parts[0] + '\",\"current\":\"' + parts[3].strip('()') + '\",\"latest\":\"' + parts[1] + '\"}')
"

如果所有结果都为空:“所有软件包均为最新版本。”停止。

继续前报告数量:“发现 X 个过时的软件包。”


第 3 步:按风险级别分类

解析版本升级(当前版本 → 最新版本):

  • MAJOR:第一位数字变化(1.x.x → 2.x.x)
  • MINOR:第二位数字变化(1.2.x → 1.3.x)
  • PATCH:第三位数字变化(1.2.3 → 1.2.4)
python3 -c "
def classify(current, latest):
    try:
        c = [int(x) for x in current.lstrip('v').split('.')[:3]]
        l = [int(x) for x in latest.lstrip('v').split('.')[:3]]
        if l[0] > c[0]: return 'major'
        if len(l) > 1 and len(c) > 1 and l[1] > c[1]: return 'minor'
        return 'patch'
    except: return 'unknown'
"

报告分类结果:“Patch:X 个软件包。Minor:Y 个软件包。Major:Z 个软件包。”


第 4 步:安全审计

创建任何 PR 之前,先运行 CVE 扫描。扫描结果决定处理优先级。

npm:

npm audit --json 2>/dev/null | python3 -c "
import sys, json
d = json.load(sys.stdin)
vulns = d.get('vulnerabilities', {})
for pkg, info in vulns.items():
    sev = info.get('severity', 'unknown')
    via = [v.get('title','') for v in info.get('via',[]) if isinstance(v, dict)]
    print(f'  [{sev.upper()}] {pkg}: {via[0] if via else \"see npm audit\"}')
" 2>/dev/null || echo "No vulnerabilities found or npm audit not available"

pip:

pip-audit --format=json 2>/dev/null | python3 -c "
import sys, json
for vuln in json.load(sys.stdin):
    print(f'  [{vuln.get(\"aliases\",[\"\"])[0]}] {vuln[\"name\"]} {vuln[\"version\"]}: {vuln[\"description\"][:80]}')
" 2>/dev/null || echo "pip-audit not installed. Run: pip install pip-audit"

Cargo:

cargo audit 2>/dev/null | grep -E "^(ID|Package|Severity|URL)" | head -30 \
  || echo "cargo-audit not installed. Run: cargo install cargo-audit"

升级规则: 如果 PATCH 或 MINOR 更新存在严重或高危 CVE,则将其提升为 MAJOR 优先级:为其单独创建 PR,并在 PR 正文中写明 CVE 详情。

继续前报告安全发现:

Security audit: [N] vulnerabilities found
  [CRITICAL] lodash 4.17.19: Prototype Pollution (CVE-2021-23337)
  [HIGH] axios 0.21.1: Server-Side Request Forgery (CVE-2021-3749)

如果没有漏洞:“安全审计:未发现问题。”


第 5 步:获取变更日志

为每个软件包按顺序尝试以下来源。遇到首个返回内容的来源后即停止。

来源 1:GitHub Releases API

从注册表获取仓库 URL:

# npm
curl -s "https://registry.npmjs.org/{PACKAGE}/latest" \
  | python3 -c "import sys,json; d=json.load(sys.stdin); r=d.get('repository',{}); print(r.get('url','') if isinstance(r,dict) else str(r))"

# pip
curl -s "https://pypi.org/pypi/{PACKAGE}/json" \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('info',{}).get('home_page','') or d.get('info',{}).get('project_urls',{}).get('Source',''))"

获取最近 5 个版本:

AUTH_HEADER=""
[ -n "$GITHUB_TOKEN" ] && AUTH_HEADER="-H \"Authorization: Bearer $GITHUB_TOKEN\""
curl -s $AUTH_HEADER \
  "https://api.github.com/repos/{OWNER}/{REPO}/releases?per_page=5" \
  | python3 -c "import sys,json; [print(json.dumps({'tag':r.get('tag_name',''),'body':r.get('body','')[:1500]})) for r in json.load(sys.stdin)]"

仅保留当前版本与最新版本之间的版本。

来源 2:npm 注册表 README(备用)

curl -s "https://registry.npmjs.org/{PACKAGE}" \
  | python3 -c "import sys,json; print(json.load(sys.stdin).get('readme','')[:3000])"

来源 3:PyPI 描述(pip 的最后手段)

curl -s "https://pypi.org/pypi/{PACKAGE}/json" \
  | python3 -c "import sys,json; print(json.load(sys.stdin).get('info',{}).get('description','')[:2000])"

如果所有来源都未返回内容,请注明“未找到变更日志”并继续。


第 6 步:使用 Gemini 生成摘要

每个风险组发送一个请求。对于受 CVE 影响的软件包,需包含安全发现:

cat > /tmp/deps-summary-request.json << 'ENDJSON'
{
  "system_instruction": {
    "parts": [{
      "text": "You are a developer writing a GitHub PR description for a dependency update. Given a list of packages being updated and their raw changelog content, write a concise PR body in Markdown. Rules: For each package, list only what changed between the OLD version and the NEW version. Use bullet points. Flag breaking changes with a BREAKING prefix. Flag CVE fixes with a SECURITY prefix and include the CVE ID. Keep each package section to 3-5 bullets maximum. If no changelog was found for a package, write 'No changelog available.' Do not use em dashes. Do not use these words: seamless, robust, leverage, transform, innovative. Output only the Markdown PR body, no commentary."
    }]
  },
  "contents": [{
    "parts": [{
      "text": "PACKAGES_AND_CHANGELOGS_HERE"
    }]
  }],
  "generationConfig": {
    "temperature": 0.2,
    "maxOutputTokens": 2048
  }
}
ENDJSON

curl -s -X POST \
  "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @/tmp/deps-summary-request.json \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['candidates'][0]['content']['parts'][0]['text'])"

第 7 步:创建 PR

每个非空风险组创建一个 PR。每个 MAJOR 更新单独创建一个 PR(需要单独审查)。

1. 创建分支:

BRANCH="deps/{RISK}-updates-$(date +%Y%m%d)"
git checkout -b "$BRANCH"

2. 更新软件包文件:

npm:

npm install {package}@{latest_version} --save-exact
# devDependencies:
npm install {package}@{latest_version} --save-dev --save-exact

pip:

python3 -c "
import re, sys
pkg, version, filename = sys.argv[1], sys.argv[2], sys.argv[3]
with open(filename) as f: content = f.read()
pattern = rf'^{re.escape(pkg)}[>=<!\s].*$'
new_content = re.sub(pattern, f'{pkg}=={version}', content, flags=re.MULTILINE|re.IGNORECASE)
if new_content == content: new_content = content + f'\n{pkg}=={version}'
open(filename, 'w').write(new_content)
" "{PACKAGE}" "{LATEST}" "requirements.txt"

Cargo:

# Edit Cargo.toml version field for the package, then:
cargo update {package}

Go:

go get {module}@{latest_version}
go mod tidy

Ruby:

bundle update {gem_name}

3. 提交:

git add -A
git commit -m "chore(deps): update {RISK} dependencies $(date +%Y-%m-%d)"

4. 创建 PR:

cat > /tmp/dep-pr-body-{RISK}.md << 'ENDMD'
PR_BODY_FROM_GEMINI
ENDMD

gh pr create \
  --title "chore(deps): update {RISK} dependencies" \
  --body-file /tmp/dep-pr-body-{RISK}.md \
  --label "dependencies" \
  --base main

MAJOR 更新添加标签 dependencies,breaking-change。修复 CVE 的更新添加标签 dependencies,security。

每次创建 PR 后,返回 main:git checkout main


第 8 步:诊断模式

触发条件: 如果运行过程中任何软件包安装命令失败,则进入诊断模式,而不是停止。

检测失败类型:

错误模式可能原因建议修复方法
peer dep conflict对等依赖不兼容显示冲突的软件包对,建议使用 --legacy-peer-deps 标志或降级
ERESOLVEnpm 解析冲突对受影响的软件包运行 npm install --legacy-peer-deps
version not found注册表中不存在该版本使用 npm view {pkg} versions 检查注册表
python requiresPython 版本不兼容记录所需的 Python 版本,跳过该软件包
cargo E0463Rust 版本不兼容标记为需要手动审查

提供诊断摘要:

Install failed for {package}: {error type}
Likely cause: {explanation}
Suggested fix: {specific command or action}
Remaining packages: proceeding with {N} that succeeded.

单个软件包失败时,不要停止整个流程。继续处理安装成功的软件包。


第 9 步:输出摘要

## Dependency Update Summary: [YYYY-MM-DD]

### Security
[CRITICAL] lodash: CVE-2021-23337 fixed in 4.17.21: PR #42
[HIGH] axios: CVE-2021-3749 fixed in 0.21.4: PR #42

| Risk Level | Packages | PR |
|------------|----------|-----|
| Patch | lodash 4.17.19→4.17.21, axios 0.21.1→0.21.4 | #42 |
| Minor | express 4.17.1→4.18.2 | #43 |
| Major | react 17.0.2→18.2.0 | #44 |

PRs opened: 3

Packages with no changelog: some-obscure-pkg (no GitHub repo in registry)
Install failures: none

Next action: Review major update PRs individually before merging.

评论

支持 Markdown