1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OSV-Scanner-MCP v0.17.0: PHP(Composer)に対応してみた

1
Posted at

Google製OSV-ScannerをMCPサーバーとして使える「OSV-Scanner-MCP」の v0.17.0 をnpmで公開しました。

前回のv0.16.0で.NET(NuGet)に対応しました。
今回は PHP(Composerのcomposer.lock) を加えました。
脆弱性のスキャン(scan_project)に加えて、修正版の推奨(suggest_fix)にも対応しています。

使い方は変わりません

scan_project・suggest_fixにプロジェクトのディレクトリ(またはcomposer.lock・composer.json)を渡すと、composer.lockも他の言語のlockfileと一緒に検出してスキャンします。

{
  "project_path": "/absolute/path/to/php-app"
}
  • packages(本番の依存)とpackages-dev(開発用の依存)の両方を対象にします。開発用の依存にはdependency_groups: ["dev"]が付きます
  • ComposerもPHPのコードも実行しません。 lockfileを読むだけです
  • composer.lockの無いcomposer.jsonは、coverage.lockfile_missingに生成方法の案内付きで示します。vendorディレクトリは走査しません

composer.lockはそのまま渡さない

composer.lockには、パッケージの名前と版のほかに、取得元のURL、コミットID、スクリプトなどが含まれます。非公開のリポジトリを使っていれば、そのURLも入ります。

OSV-Scanner-MCPは元のcomposer.lockをosv-scannerに渡しません。
安全に読み込んだうえで、パッケージの名前とリリースの版だけを書いたコピーをスキャンします。URL・コミットID・スクリプト・認証情報は、osv-scannerにも照会先にも渡りません。

コピーは次のような形です。

{
  "packages": [{ "name": "symfony/http-kernel", "version": "v5.4.1" }],
  "packages-dev": [{ "name": "phpunit/phpunit", "version": "9.5.0" }]
}

osv-scanner 2.7.0と2.4.0のどちらでも、このコピーを元のファイルと同じように読むことを確かめました。Symfonyのようなv付きの版も、OSVでは付けない場合と同じ結果になります。

自分のパッケージ(pathリポジトリ)は照会しない

monorepoでは、自分のパッケージをpathリポジトリで参照することがあります。composer.lockには次のように記録されます。

{ "name": "guzzlehttp/psr7", "version": "1.8.1", "dist": { "type": "path", "url": "packages/psr7" } }

osv-scannerはこれもPackagistのパッケージとして照会します。 試しに、公開パッケージと同じ名前・版(guzzlehttp/psr7 1.8.1)のローカルのパッケージを置くと、中身は自分のコードなのに脆弱性が6件報告されました。また、社内向けの名前(例: acme/internal-billing)もapi.osv.devに送られます。Rustのローカルのcrateや、.NETの自分のプロジェクトと同じ問題です。

そこで、dist.typeがpathのパッケージは照会も送信もせず、数だけをcoverage.local_composer_packagesに示します。

{
  "coverage": {
    "complete": true,
    "local_composer_packages": 2,
    "skipped_files": []
  }
}

自分のコードなので、completeには影響させません。そのパッケージが依存する第三者のパッケージはcomposer.lockに載っているので、通常どおりスキャンされます。

リリースの版だけを照会する

dev-mainや1.x-devのようなブランチの版、エイリアス(1.0 as 2.0)などは、リリースではないので照会しません。理由とともにcoverage.skipped_filesに示し、complete: falseになります。

{
  "skipped_files": [
    {
      "path": "composer.lock",
      "reason": "3 entries in packages were not scanned: invalid package names or non-release versions (branches, aliases, and dev versions are not evaluated)"
    }
  ]
}

修正版の推奨(suggest_fix)

Composerの版の順序(1〜4個の数字、v接頭辞、alpha・beta・RC・stable・patchとその短縮形)に合わせて比較し、現在のリリース系列にできるだけ近い修正版を推奨します。

パッケージ 現在 推奨 距離
symfony/http-kernel v5.4.1 5.4.20 same_minor(同じ5.4系)
guzzlehttp/psr7 1.8.1 2.12.3 cross_major(1.x系では一部の脆弱性が修正されていないため)

推奨版はOSVに照会し直し、別の既知の脆弱性が無いことも確かめます(candidate_check)。update_hintでは、composer.jsonの制約を更新し、信頼できる環境でcomposer update vendor/package --with-all-dependencies --no-scripts --no-pluginsでlockfileを作り直す方法を案内します。更新の前に、PHPと拡張モジュールの要件も確認してください。

比較できない版の境界を持つアドバイザリでは、修正版を「確認済み」として推奨しません。

実物のcomposer.lockで確かめました

公開リポジトリの実物のlockfileで、osv-scannerが元のファイルから読むパッケージと、本サーバーが照会するパッケージを比べました。

リポジトリ osv-scanner(元のファイル) 本サーバー 差
phpmyadmin/phpmyadmin 137 137 なし
matomo-org/matomo 87 83 dev-masterの4件(意図して除外)
firefly-iii/firefly-iii 186 185 dev-mainの1件(意図して除外)

意図して除外したブランチの版以外は完全に一致し、検出結果も同じでした。

通信先とパッケージの取得元について

Composerのスキャンで通信するのは api.osv.devだけ です。
送るのはパッケージの名前とリリースの版で、pathのパッケージは送りません。

ただし、lockfileだけでは、パッケージがPackagistから来たのかを証明できません。 そのため、非公開のリポジトリ(Private Packagist・Satis・VCSリポジトリなど)のパッケージの名前と版も送られます。公開パッケージと同じ名前の非公開パッケージは、誤検知になることがあります。

Packagistのパッケージには、通常"notification-url": "https://packagist.org/downloads/"が記録されます。これが無いエントリがあれば、coverage.composer_warningsで知らせます(目安であって、取得元の証明ではありません)。

導入

Node.js 20.19以上が必要です。Claude Codeの場合:

claude mcp add osv-scanner -- npx -y osv-scanner-mcp

既に使っている方は、npx -y osv-scanner-mcpであれば次の起動時に最新版になります(@0.16.0のように版を固定している場合は更新してください)。Claude Desktop・Codex CLI・VS Code(GitHub Copilot)・Antigravityの設定例はREADMEのSetupにあります。

設定後は、例えば次のように依頼できます。

/absolute/path/to/my-laravel-app の依存の脆弱性を suggest_fix で調べて、修正版と更新方法を教えてください。開発用の依存は分けてください。

注意点と今後

  • 検出0件は安全の保証ではありません。 必ずcoverageを確認してください
  • coverage.completeは、lockfileに載っているエントリを調べられたかを表します。lockfileがcomposer.jsonと食い違っていないか(古くないか)、PHPの版や拡張モジュールの要件は確かめません
  • Composerのパッケージのdependency_relation(直接・推移的の区別)は、今はunknownです
  • .NET(NuGet)のsuggest_fixは引き続き準備中です

まとめ

OSV-Scanner-MCPがPHPのプロジェクトにも使えるようになりました。
composer.lockをそのまま渡すと、自分のパッケージが公開パッケージと取り違えられ、取得元のURLなども含まれます。名前とリリースの版だけを照会し、確かめられなかったものはcoverageで隠さずに返すことを重視しました。

不具合や改善案はGitHub Issuesでお知らせください。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?