0
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.12.0: Rust(Cargo.lock)に対応してみた

0
Posted at

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

前回のv0.11.0で、Java・JavaScript・Python・Goの依存をまとめてスキャンできるようになりました。今回は Rust(Cargo.lock) を加えました。

使い方は変わりません

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

{
  "project_path": "/absolute/path/to/project"
}
エコシステム 対応ファイル
Java(Maven) pom.xml、gradle.lockfile
JavaScript(npm) package-lock.json、npm-shrinkwrap.json、yarn.lock、pnpm-lock.yaml、bun.lock
Python(PyPI) poetry.lock、uv.lock、Pipfile.lock、pdm.lock、requirements.txt
Go go.mod
Rust(crates.io) Cargo.lock(lockfileの形式v1〜v4)

これまでと同じく、cargoは実行しません。
lockfileを読むだけです。

osv-scannerにCargo.lockをそのまま渡すと誤検知する

実装前に、osv-scanner v2.4.0に手書きのCargo.lockを渡して挙動を確認しました。すると、Cargo.lockのsource(どこから来たcrateか)を見ずに、すべてのパッケージをcrates.ioのcrateとして照会することが分かりました。

crateの種類 Cargo.lockのsource osv-scanner単体の挙動
自分のcrate(workspaceのメンバー・pathの依存) なし crates.ioとして照会
gitの依存(forkなど) git+https://... crates.ioとして照会
社内レジストリのcrate registry+https://社内/... crates.ioとして照会

試しに、ローカルのcrateをfailure 0.1.8、gitのforkをsmallvec 1.6.0、社内レジストリのcrateをatty 0.2.14という名前と版にしたところ、3つともcrates.ioの同名crateの脆弱性が報告されました。中身はまったく別物なので誤検知です。しかも、社内crateの名前がapi.osv.devへ送られます。

そこでOSV-Scanner-MCPでは、元のCargo.lockはosv-scannerに渡しません。本サーバーが解析し、sourceがcrates.ioのパッケージだけを書いたコピーをスキャンします(cargo auditと同じ考え方です)。

{
  "coverage": {
    "complete": false,
    "local_crates": 2,
    "unscannable_crates": [
      {
        "file": "Cargo.lock",
        "name": "gitdep",
        "version": "0.3.0",
        "reason": "Git dependency: its version does not correspond to a crates.io release, so it was not checked against crates.io advisories"
      }
    ]
  }
}
項目 意味
local_crates スキャンしなかった自分のcrateの数。自分のコードなので、completeには影響しません
unscannable_crates スキャンしなかったgitの依存・社内レジストリのcrateと理由。第三者のコードが未検査なので、complete: falseになります。sourceのURLは応答に含めません

解析は、cargoが書き出す形式だけを受け付ける厳格なものにしました。
想定外の行が1つでもあれば、ファイル全体をスキャン対象から外して理由を示します。一部だけ読んで「取りこぼしたのに0件」となるのを避けるためです。

[replace]で置き換えたcrateも扱います。置き換え前のcrates.ioのcrateは実際には使われないので、スキャンしません(osv-scanner単体では置き換え前の版を照会します)。

「保守終了」は脆弱性と分けて数える

Rustの脆弱性データベースであるRustSecには、脆弱性ではない 情報提供のアドバイザリ があります。

種類 意味
unmaintained crateの保守が終了している
unsound 健全性(soundness)の欠陥がある
notice その他の通知

osv-scannerはこれらも脆弱性と同じように返します。多くは修正版がありません(保守終了は版を上げても解消しないため)。そのまま数えると、脆弱性の件数が水増しされ、LLMが「修正版のない脆弱性がある」と要約しかねません。

そこで、情報提供のアドバイザリにはinformationalを付け、vulnerability_countではなく informational_count に数えるようにしました。実際の応答では次のようになります(atty 0.2.14)。

[
  {
    "id": "RUSTSEC-2021-0145",
    "severity": "unknown",
    "summary": "Potential unaligned read"
  },
  {
    "id": "RUSTSEC-2024-0375",
    "severity": "unknown",
    "informational": "unmaintained",
    "summary": "`atty` is unmaintained"
  }
]

1件目のRUSTSEC-2021-0145はRustSecではunsound(情報提供)ですが、GitHubのアドバイザリデータベースが同じ欠陥を脆弱性として登録しています。このように 別のデータベースが脆弱性として扱っているものは、脆弱性のまま数えます。関連するIDの詳細が欠けていて分類を確かめられない場合も、脆弱性側に倒しています。

lockfileが無いcrateも知らせる

ライブラリのcrateは、Cargo.lockをリポジトリに含めない慣習が長く続いていました。Cargo.lockの無いCargo.tomlは、応答のcoverage.lockfile_missingに「cargo generate-lockfileを信頼できる環境で実行してから再スキャン」という案内付きで示します。

workspaceでは、メンバーのCargo.tomlはサブディレクトリにあり、Cargo.lockはルートにだけあります。メンバーかどうかは、ルートのCargo.tomlの[workspace]のmembers・excludeで確認します。globの展開やexcludeの扱いは、cargo 1.98の実際の挙動に合わせました。

導入

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

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

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

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

/absolute/path/to/my-rust-app の依存の脆弱性を scan_project で調べてください。スキャンできなかったcrateと、保守終了のcrateがあれば分けて教えてください。

通信先について

Cargo.lockのスキャンで通信するのは api.osv.devだけ です(プロキシで接続先を記録して確認しました)。送られるのはcrates.io由来のcrateの名前と版で、自分のcrate・gitの依存・社内レジストリのcrateの名前は送りません。

注意点と今後

  • 検出0件は安全の保証ではありません。 必ずcoverageを確認してください
  • suggest_fix(修正版の推奨)は、Rustにはまだ対応していません(unsupported_ecosystemを返します)。次のv0.13.0で、推奨版、直接依存・推移的依存の区別、cargo update -p <crate>@<版> --precise <推奨版>による更新方法の案内に対応する予定です
  • workspaceの外にあるpathの依存は、実際にはルートのCargo.lockに含まれていても、同名の別crateと区別できないためlockfile_missingにunconfirmedとして示します

まとめ

  • OSV-Scanner-MCPがRustのプロジェクトにも使えるようになりました。
  • osv-scannerにCargo.lockを渡すだけでは、自分のcrateやgitの依存がcrates.ioのcrateと取り違えられます。それを防ぎ、スキャンできなかったものはcoverageで隠さずに返すことを重視しました。

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

0
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
0
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?