crates.io 開発アップデート
(blog.rust-lang.org)- この6か月間で crates.io は、公開済みパッケージを直接確認できるソースコードビューアを追加し、GitHub から独立したアカウント体系を導入し、セキュリティおよび標準ライブラリ代替の案内を強化した
- 新しい
Codeタブは、ファイル検索、シンタックスハイライト、共有可能な行選択をサポートし、CDN 上の ZIP・JSON マニフェストとHTTP Range Requestによって、API サーバーに負荷をかけず必要なファイルだけを読み込む - RFC #3946 に基づき、crates.io 固有のユーザー名の実装を開始し、ユーザー名変更とセキュリティレビューを経て、今後は GitHub 以外の認証プロバイダーにも対応する予定
- フロントエンドを Ember.js から Svelte に完全移行し、検索・逆依存関係の参照・CDN キャッシュ・Git インデックス処理も、性能と安定性を高める方向で改善した
- RustSec のメンテナンス終了警告と、
std::sync::LazyLockのような標準ライブラリ代替 APIをパッケージページに表示し、依存関係の監査や不要な依存の削減を支援する
公開済みパッケージを確認できるソースコードビューア
- パッケージページの新しい
Codeタブで、公開された各バージョンのファイルを crates.io 内で閲覧できる- 紐付けられたリポジトリではなく、依存関係追加時に
cargoが実際にダウンロードするファイルを表示する cargoが生成した正規化済みCargo.tomlのように、リポジトリには存在しないファイルも確認できるため、依存関係の監査がしやすい
- 紐付けられたリポジトリではなく、依存関係追加時に
- ビューアはファイルツリー検索、シンタックスハイライト、GitHub 方式の行選択に対応する
- 行番号をクリックまたはドラッグすると、
#L10-L20形式の共有可能な URL が生成される
- 行番号をクリックまたはドラッグすると、
- サーバーは、公開されたすべてのバージョンについて ZIP ファイルと、ファイル構成を記述するJSON マニフェストを生成する
cargoが使う.crateファイルは、ランダムアクセスをサポートしない gzip 圧縮 tarball なので、バックグラウンドジョブで閲覧可能な ZIP に再パッケージする- ZIP とマニフェストは静的 CDN 経由で提供される
- フロントエンドはまずマニフェストを取得し、その後各ファイルを HTTP Range Request で必要なときだけ読み込む
- ソース閲覧は crates.io API サーバーに実質的な追加負荷を与えず、既存バージョンも一括処理して古いリリースまで対応する
- コードビューアのレンダリングライブラリは、もともと差分レンダラーであり、同じ基盤を使ったバージョン間比較ビューアも開発中
- 完成すれば、crates.io 上で公開バージョン同士の正確な変更点を確認できる
GitHub から独立する crates.io アカウント
- crates.io チームは 5 月末に RFC #3946 を承認した
- 従来は GitHub ログインと crates.io の本人性が強く結び付いており、ユーザー名も GitHub アカウントで決まっていたが、この RFC では連携アカウントとは独立したcrates.io 固有のユーザー名を導入する
- この固有ユーザー名は、将来的に GitHub 以外の認証プロバイダーでのログインをサポートするための前提条件となる
- 実装は始まっているが、ユーザーから見える主要な未完成機能としてユーザー名変更が残っている
- これを終えた後、他の認証プロバイダーによるログインに関する追加 RFC と実装を進める予定
- 認証とアカウントセキュリティに直接関わるため、小さく慎重にレビューされた段階ごとにゆっくり展開する
セキュリティ勧告と標準ライブラリ代替の案内
- 既存の
Securityタブでは RustSec データベースのセキュリティ勧告を表示しており、今後は RustSec がメンテナンス終了としてマークしたパッケージに対し、ページ上部に警告バナーも表示される- バナーから、詳細情報や代替候補を含む該当勧告へ移動できる
- 標準ライブラリに機能が取り込まれたパッケージには、「You might not need this dependency」バナーが表示される
- たとえば
lazy_staticは Rust 1.80 以降、std::sync::LazyLockで置き換えられる - 依存関係一覧では、代替済みパッケージに同じ案内を示す小さな電球アイコンが付く
- たとえば
- 関連データは新しい rust-lang/std-replacement-data リポジトリで管理される
- 標準ライブラリ代替項目のみを受け付ける
- すべての項目は、安定化済みの
std、core、allocAPI と対応する Rust バージョンを引用しなければならない - 項目追加前には、パッケージメンテナーへ通知し、意見を受け取る期間を設ける
- 新しい項目はこのリポジトリに提案でき、蓄積されたデータは他ツールでも利用可能
Svelte フロントエンド移行完了
- crates.io フロントエンドを Ember.js から Svelte へ移行する実験は成功裏に完了した
- 新フロントエンドは既存機能と同等の水準に到達した
- 4 月の公開テストを経て、5 月初旬にデフォルトのフロントエンドへ切り替えられた
- Ember.js アプリケーションはリポジトリから削除された
- 既存のデザインと機能をそのまま移した1 対 1 の移行であり、ユーザーが変化を感じないよう設計されている
- チームとコントリビューターは、モダンなフレームワークを使いながら新規貢献者の参入障壁を下げ、反復開発の速度を高められるようになり、ソースコードビューアはその一例となっている
- crates.io が長年利用してきた Ember.js と、移行を支援した Svelte の両チームに感謝を述べている
Ferris エラーページ
- crates.io のエラーページにいるFerrisが、目でマウスカーソルを追うようになった
- 404 エラーページにも小さなインタラクションを追加した
検索と逆依存関係参照の性能
- 関連度順検索では以前、検索語に一致するすべてのパッケージの順位を計算していたため、短い語や一般的な語では1〜2 秒かかることがあった
- 現在は、最近のダウンロード数が最も多い一致パッケージ 1,000 件に順位計算対象を制限している
- 逆依存関係エンドポイントでは、リクエストごとに依存パッケージ集合全体を再計算しない
- データベーストリガーで同期される事前計算テーブルから結果を返す
- 高コストな join を限定的なインデックススキャンに置き換え、タイムアウトの可能性を大きく下げた
アーキテクチャ文書と Markdown レンダリング
ARCHITECTURE.mdを全面的に改訂し、crates.io の上位システムと相互接続の仕組みを中心に構成したcargo publish実行時に発生する処理の流れ- 一般的なパッケージダウンロードが API サーバーを経由しない理由
- CDN アクセスログからダウンロード数を算出する方法を含む
- README は、広く使われている Markdown 拡張である定義リストをレンダリングするようになった
- Markdown レンダラー comrak はすでに定義リストをサポートしていたが、その拡張は有効化されていなかった
CDN キャッシュ効率の改善
- 静的 CDN にアップロードされるファイルへキャッシュタグメタデータを追加した
- ファイル URL ごとに個別の無効化リクエストを送る代わりに、特定パッケージやリリースに属するすべてのキャッシュファイルを一度に無効化できる
- 公開 API レスポンスとフロントエンド資産の CDN キャッシュを妨げていたグローバルな
Vary: Cookieレスポンスヘッダーを削除した- ユーザーごとのレスポンスには代わりに
Cache-Control: no-storeを適用する - その結果、CDN エッジでのキャッシュヒット率が改善した
- ユーザーごとのレスポンスには代わりに
アクセシビリティと Git インデックス処理
- スクリーンリーダー利用者向けに、crates.io のアクセシビリティを改善した
- 装飾アイコンをアクセシビリティツリーから除外
- 見出し階層を修正
- リストに正しいリストマークアップを適用
- ARIA スナップショットテストを導入し、回帰が見逃されたまま反映される事態を防止
- 今後数か月にわたりアクセシビリティ改善を継続する予定
- バックグラウンドワーカーのローカル Git インデックス複製をbare・shallow リポジトリに変更した
- 約 25 万件のチェックアウト済みファイルと完全なコミット履歴をディスク上から削除した
- パッケージ公開頻度が高まる中で処理性能を改善する
- 定期的なインデックス squash では、ローカルで巨大な Git pack を生成する代わりに GitHub API を使用する
- 以前のローカル pack 生成方式では、本番ワーカーでメモリ不足を引き起こしたことがあった
フィードバックチャネル
- crates.io に関する意見や質問は Zulip または GitHub Discussions で送ることができる
1件のコメント
Lobste.rsの反応
crates.io のアカウントを GitHubから分離しようとする取り組みが進んでいるのはうれしい
自分のドメインのメール
example@example.comでログインするには、https://example.com/.well-known/webfingerに、subjectがacct:example@example.comで OpenID Connect issuer のhrefがhttps://codeberg.orgである JSON ファイルを置くCodeberg の設定では、リダイレクト URI が
https://login.tailscale.com/a/oauth_responseの OAuth2 アプリケーションを作成し、発行されたClient IDとClient Secretを Tailscale に入力すればよい。今後は crates.io も似たような方式を提供しそうだ最近の crates.io の改善幅がここまで大きいとは知らなかった。普段はまず lib.rs を見ていたが、もうすぐその習慣が変わるかもしれず、いちばん気に入っている変化は Ferris だ
Ferris の目の変化は物理的にはあまり筋が通っていない。黒い目の白い部分は 鏡面反射ハイライトだが、マウスカーソルが光源だとすると、目がカーソルを追っている表現だとも言いにくい
依存関係を監査するときは、まず
~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/を~/cargosrcにシンボリックリンクして、Cargo がダウンロードしたファイルに簡単にアクセスできるようにしている監査対象の依存関係ごとに Git リポジトリを複製して対象バージョンをチェックアウトし、追跡対象ファイルをローカルで削除したうえで rust-analyzer プロセスに
SIGSTOPを送る。プロジェクトのCargo.tomlに依存関係を追加してcargo fetchを実行し、その後ダウンロードされた$dependency-$versionディレクトリの内容を複製したリポジトリへコピーしてコミットし、Git 履歴ビューアで差分を確認する確認を終えたら、
Cargo.lockの依存関係・バージョン・ハッシュの組み合わせをスクリプトで信頼できるデータベースに保存し、同じバージョンを二度と確認しないようにしている。手順は複雑に見えてもほとんど自動化してあるので Web UI より効率的で、Cargo がコマンドラインでこうした レビュー手順をサポートしてくれるとよいと思う。cargo-crev のようなツールより、レビューそのものを助けるプラグインがあるのかも気になるフロントエンドがマニフェストだけを取得したあと、各ファイルを HTTP Range Request で必要なときに読み込む実装は こちら にあり、ブラウザ組み込みの
DecompressionStreamを使っている