saltcandy123

GitHub のライセンス検知機能のバグを修正しました

GitHub には、リポジトリ内のライセンスファイルを検知してライセンスの種類をリポジトリ情報として表示する機能があります。 例えば、 MIT License ライセンス文書を LICENSE というファイルとして置くと、次のスクリーンショットのように、このリポジトリが MIT License であることがウェブ UI 上で表示されます。

GitHub のリポジトリページの一部のスクリーンショット。上から順に "Readme", "Mit license", "Code of conduct", "Security policy", "Activity", "Custom properties", "725 Stars", "54 Watching", "315 forks", "Report repository" と書かれている。

あるとき、あるリポジトリに SIL Open Font License 1.1 という種類のライセンスを追加してみたのですが、なぜか GitHub 上ではライセンスの種類が表示されませんでした。 試行錯誤の結果、どうやら予約フォント名をライセンスに含めたときに検知されないことが分かりました。 予約フォント名というのは、 SIL Open Font License 1.1 固有の情報で、派生フォントがこの予約フォント名を名乗ることを禁止する効力があります。 この情報は著作権表示と共に、ライセンス文書の先頭に次のようなフォーマットで記述されます。(1行目が著作権表示、2行目が予約フォント名の情報)

Copyright (c) <dates>, <Copyright Holder> (<URL|email>),
with Reserved Font Name <Reserved Font Name>.

さらに試行錯誤すると、 "with Reserved Font Name ..." の行を改行せずに直前の著作権表示と同一の行として記述すると、検知されるようになることも分かりました。 なので、そのようにライセンス文書を変更すれば解決できる問題ではあったのですが、他の行が80文字以内に収まっているのにこの行だけ妙に長くなってしまうのは不格好なので、なんとかライセンスファイルを変更せずに解決したい気がしました。

ここで、 GitHub のライセンスに関するドキュメント を読み、この検知機能には オープンソースの Licensee というソフトウェア が使われていることを発見しました。 そこで、 Licensee をローカルマシンで動かして、どのようにライセンスを検知しているのか調べてみることにしました。 当時の最新バージョン (9.15.2) を使って、予約フォント名を含んだ SIL Open Font License 1.1 のファイルで検知を行ってみると、次のような出力になりました。

License:        NOASSERTION
Matched files:  OFL.txt
OFL.txt:
  Content hash:  99d993ef11351abd51dd5ad4dde5150712d90fa4
  License:       NOASSERTION
  Closest non-matching licenses:
    OFL-1.1 similarity:       97.29%
    Vim similarity:           29.27%
    MulanPSL-2.0 similarity:  23.47%

つまり、 Licensee は OFL.txt がほぼ (97.29%) SIL Open Font License 1.1 であると認識しているものの、完全な一致ではないため、未知のライセンスである (NOASSERTION) と出力しているようでした。 試しに、予約フォント名を含まないファイルで検知を行ってみると、 SIL Open Font License 1.1 として検知することを確認しました。 この結果から考えてもやはり、予約フォント名の行がノイズとなって検知に失敗しているようでした。 Licensee のコードを見てみると、著作権表示などいくつかの可変部分を正規表現などを使って検知対象の文書から除外した後、分類を行っていることが分かりました。 したがって、この前処理の著作権表示の正規表現を拡張して予約フォント名にもマッチできるようにするか、予約フォント名を除外するルールを新たに追加するかすれば問題が解決できそうでした。

問題と直し方が分かったので GitHub で Issue を立てようと思ったら、 すでに Issue が立てられていました 。 そこでは、メンテナーがコメント上で著作権表示の正規表現を拡張する方法を提案していましたが、そのまま3ヶ月以上放置されていました。 そこで、その提案通りに修正を行い プルリクエスト を作ったら、すぐにマージされました。 ちなみに、この変更により、予約フォント名を含んだ SIL Open Font License 1.1 のファイルは次のように検知されるようになりました。

License:        OFL-1.1
Matched files:  OFL.txt
OFL.txt:
  Content hash:  f92ca13e3976f94f20b49a007f7592631b4f8e96
  Attribution:   Copyright (c) 2000, Copyright Holder (email@example.com),
with Reserved Font Name "My Awesome Font Name".
  Confidence:    100.00%
  Matcher:       Licensee::Matchers::Exact
  License:       OFL-1.1

ここまでが、 2022年4月に起きた出来事です。

目的達成のために必要な次のステップは、この変更がリリースされることです。 リリースを急かすような重大なバグでもないので、そのまま放置しました。 この変更は 9.15.3 として、2022年11月にリリースされました。

最後のステップは、 GitHub のシステムが最新の Licensee を使うようにすることです。 いつかは分かりませんが、おそらくそのうちシステムの依存関係のアップデートが行われるはずなので、特に何もせずそのまま放置しました。 しかし、待てど暮らせど、例のリポジトリでライセンスが正しく検知される様子がありませんでした。 半ば忘れかけ、久しぶりに思い出して悲しいなと思いながら、例のリポジトリのライセンス文章の年号を 2022-2024 のように今年のものに更新したら、リポジトリページ上で SIL Open Font License 1.1 と表示されるようになりました。 やったー! おそらく、 GitHub のシステムは一度スキャンしたライセンスファイルの検知結果をファイルハッシュに紐付けたキャッシュとして保存していて、ライセンスファイルが更新されるまで再計算しないようになっているのでしょう。

ここまで2年弱もかかってしまいましたが、通常コントリビュートすることができないはずの GitHub のシステムのバグをこのように直すことができたのは面白かったなと思いました。