dependency-update-bot について
Dependency Update Botは、ソフトウェア依存関係を管理する開発者向けの更新自動化スキルです。各パッケージマネージャーが検出した更新を調べてセキュリティ監査と変更要約を行い、リスク別にPRを作成します。
主な機能
- 01古い依存関係の検出
- 02バージョン変更に基づくリスク分類
- 03セキュリティ監査の実行
- 04変更履歴の取得と要約
- 05リスク別のPR作成
活用シーン
- 01プロジェクト依存関係の更新確認
- 02重大な脆弱性を修正する更新の優先処理
- 03メジャーバージョン更新の個別PR化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ varnan-tech/ opendirectory --skill dependency-update-botインストール後、Claude Code で/dependency-update-botを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.env.exampleREADME.mdevals/evals.jsonreferences/changelog-patterns.md詳細
依存関係更新ボット
古くなったパッケージをスキャンします。セキュリティ監査を実行します。変更履歴を取得します。破壊的変更を要約します。リスクグループごとに PR を 1 件作成します。
重要なルール: パッケージマネージャーの outdated コマンドが実際に報告したパッケージのみを更新してください。バージョン番号を推測したり、作り出したりしてはいけません。変更履歴を取得できない場合は、内容を作り出さず、情報が不足していることを記載してください。
ステップ 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:2 番目の数字が変わる(1.2.x → 1.3.x)
- PATCH:3 番目の数字が変わる(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 の更新に Critical または High の CVE がある場合、MAJOR 優先度に引き上げます。個別の PR を作成し、CVE の詳細を PR の本文に記載します。
続行する前にセキュリティの検出結果を報告します:
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 registry 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 で要約する
リスクグループごとにリクエストを 1 件送信します。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 を 1 件作成します。MAJOR 更新はパッケージごとに PR を 1 件作成します(個別レビューが必要です)。
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 フラグの使用またはダウングレードを提案 |
ERESOLVE | npm の依存関係解決の競合 | 影響を受けるパッケージに対してのみ npm install --legacy-peer-deps を実行 |
version not found | レジストリにバージョンが存在しない | npm view {pkg} versions でレジストリを確認 |
python requires | Python バージョンの非互換性 | 必要な Python バージョンを記載し、パッケージをスキップ |
cargo E0463 | Rust エディションの非互換性 | 手動レビューが必要として報告 |
診断の概要を提示します:
Install failed for {package}: {error type}
Likely cause: {explanation}
Suggested fix: {specific command or action}
Remaining packages: proceeding with {N} that succeeded.
1 つのパッケージが失敗しても、実行全体を停止しないでください。成功したパッケージについては続行します。
ステップ 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.