CLOVER🍀

That was when it all began.

Goプロジェクトで使っているモジュールのライセンスを調べたり、集めたりしたい

これは、なにをしたくて書いたもの?

こちらのエントリで、Goで書いたアプリケーションに含まれるモジュールなどがわかるだろうか?という確認をしました。

go tool nmコマンドで、Goの実行可能ファイルの定義やシンボルを表示する - CLOVER🍀

次は、使用しているモジュールのライセンスを確認したいな、と。

Goとライセンス

そもそも、Goのライセンスは?というと、BSDライセンスです。

Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file.

https://github.com/golang/go/blob/master/LICENSE

・ Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

・ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

・ Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

なので、再頒布にあたってはライセンスファイルのコピーが必要だ、ということになります。

Every program that you distribute to a third party in binary form, yes. Technically it should have a copy of the LICENSE file, not just a reference to it.

Standard library licensing question · Issue #19893 · golang/go · GitHub

Goってアプリケーションをビルドするとシングルバイナリになりますし、こういうところも気をつけないとですね。

Chromeも、以下で使用しているライブラリのライセンスを確認できるようです。知らなかった…。

chrome://credits/

で、Goプロジェクトで使っているモジュールのライセンスを調べるには、このあたりを使えばよさそうです。

GitHub - google/go-licenses: Reports on the licenses used by a Go package and its dependencies.

GitHub - mitchellh/golicense: Scan and analyze OSS dependencies and licenses from compiled Go binaries

GitHub - ribice/glice: Go license and dependency checker

ライセンスファイルをまとめたファイルを作るには、こちら。

GitHub - Songmu/gocredits: creates CREDITS file from LICENSE files of dependencies

いくつか試してみましょう。

環境とサンプルプログラム

今回の環境は、こちらです。

$ go version
go version go1.15.6 linux/amd64

モジュールの作成。

$ go mod init view-licenses
go: creating new go.mod: module view-licenses

依存モジュールは、こちら。
go.mod

module view-licenses

go 1.15

require (
    github.com/google/uuid v1.1.4 // indirect
    github.com/labstack/echo/v4 v4.1.17 // indirect
)

go.sum

github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/google/uuid v1.1.4 h1:0ecGp3skIrHWPNGPJDaBIghfA6Sp7Ruo2Io8eLKzWm0=
github.com/google/uuid v1.1.4/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/labstack/echo v1.4.4 h1:1bEiBNeGSUKxcPDGfZ/7IgdhJJZx8wV/pICJh4W2NJI=
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
github.com/labstack/echo/v4 v4.1.17 h1:PQIBaRplyRy3OjwILGkPg89JRtH2x5bssi59G2EL3fo=
github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

サンプルプログラムとしては、こちらを用意。
main.go

package main

import (
    "github.com/google/uuid"
    "github.com/labstack/echo/v4"
    "net/http"
)

func main() {
    e := echo.New()
    e.GET("/", func(c echo.Context) error {
        uuid4, _ := uuid.NewRandom()
        return c.String(http.StatusOK, "UUID v4 = "+uuid4.String())

    })
    e.Logger.Fatal(e.Start(":1323"))
}

ビルドもしておきます。

$ go build
$ ./view-licenses  # 動作確認のため

このGoプロジェクトを対象に、依存プロジェクトのライセンスを解析してみましょう。

google/go-licenses

まずは、こちらを使ってみましょう。

GitHub - google/go-licenses: Reports on the licenses used by a Go package and its dependencies.

依存ライブラリを分析し、ライセンスに関するレポートを出力できます。また、ソースコード、ライセンスファイル、ソースコード
まとめることも可能なようです。

インストール。

# Goプロジェクト外で実行
$ GO111MODULE=on go get github.com/google/go-licenses

今回取得したバージョン。

go: downloading github.com/google/go-licenses v0.0.0-20201026145851-73411c8fa237
go: github.com/google/go-licenses upgrade => v0.0.0-20201026145851-73411c8fa237

ヘルプの表示。

$ go-licenses help
Usage:
  licenses [command]

Available Commands:
  check       Checks whether licenses for a package are not Forbidden.
  csv         Prints all licenses that apply to a Go package and its dependencies
  help        Help about any command
  save        Saves licenses, copyright notices and source code, as required by a Go package's dependencies, to a directory.

Flags:
      --alsologtostderr                  log to standard error as well as files
      --confidence_threshold float       Minimum confidence required in order to positively identify a license. (default 0.9)
  -h, --help                             help for licenses
      --log_backtrace_at traceLocation   when logging hits line file:N, emit a stack trace (default :0)
      --log_dir string                   If non-empty, write log files in this directory
      --logtostderr                      log to standard error instead of files
      --stderrthreshold severity         logs at or above this threshold go to stderr (default 2)
  -v, --v Level                          log level for V logs
      --vmodule moduleSpec               comma-separated list of pattern=N settings for file-filtered logging

Use "licenses [command] --help" for more information about a command.

csvコマンドを使うと、レポート表示ができます。

Reports

このツールに関しては自プロジェクトにLICENSEがあった状態で実行した方が良さそうだったので、LICENSEファイルを
作成しておきました。まずはMITライセンスにしています。

この状態で、プロジェクト内で以下のコマンドを実行。

$ go-licenses csv .
E0113 00:09:20.566415   19924 csv.go:84] Error discovering URL for "$HOME/go/pkg/mod/golang.org/x/net@v0.0.0-20200822124328-c89045814202/LICENSE":
- unsupported package host "golang.org" for "golang.org/x/net"
E0113 00:09:20.574686   19924 csv.go:84] Error discovering URL for "$HOME/go/pkg/mod/golang.org/x/text@v0.3.3/LICENSE":
- unsupported package host "golang.org" for "golang.org/x/text"
E0113 00:09:20.583300   19924 csv.go:84] Error discovering URL for "/path/to/view-licenses/LICENSE":
- cannot determine URL for "view-licenses" package
E0113 00:09:20.626889   19924 csv.go:84] Error discovering URL for "$HOME/go/pkg/mod/golang.org/x/sys@v0.0.0-20200826173525-f9321e4c35a6/LICENSE":
- unsupported package host "golang.org" for "golang.org/x/sys"
E0113 00:09:20.641393   19924 csv.go:84] Error discovering URL for "$HOME/go/pkg/mod/golang.org/x/crypto@v0.0.0-20200820211705-5c72a883971a/LICENSE":
- unsupported package host "golang.org" for "golang.org/x/crypto/acme"
golang.org/x/net,Unknown,BSD-3-Clause
golang.org/x/text,Unknown,BSD-3-Clause
view-licenses,Unknown,MIT
github.com/google/uuid,https://github.com/google/uuid/blob/master/LICENSE,BSD-3-Clause
github.com/mattn/go-colorable,https://github.com/mattn/go-colorable/blob/master/LICENSE,MIT
github.com/mattn/go-isatty,https://github.com/mattn/go-isatty/blob/master/LICENSE,MIT
github.com/valyala/fasttemplate,https://github.com/valyala/fasttemplate/blob/master/LICENSE,MIT
github.com/labstack/echo/v4,https://github.com/labstack/echo/blob/master/v4/LICENSE,MIT
github.com/labstack/gommon,https://github.com/labstack/gommon/blob/master/LICENSE,MIT
golang.org/x/sys,Unknown,BSD-3-Clause
github.com/valyala/bytebufferpool,https://github.com/valyala/bytebufferpool/blob/master/LICENSE,MIT
golang.org/x/crypto/acme,Unknown,BSD-3-Clause

バイナリファイルを指定してもOKのようです。今回は、すべて.指定で行うことにします。

### go-licenses csv [バイナリファイル]
$ go-licenses csv view-licenses

結果の一部がエラーになっていますが、理由はこれっぽいですね…。

URLs may not be available if the library is not checked out as a Git repository (e.g. as is the case when Go Modules are enabled).

Reports

Warnings and errors

少なくとも、このあたりを見るとライセンスの確認はできます。

golang.org/x/net,Unknown,BSD-3-Clause
golang.org/x/text,Unknown,BSD-3-Clause
view-licenses,Unknown,MIT
github.com/google/uuid,https://github.com/google/uuid/blob/master/LICENSE,BSD-3-Clause
github.com/mattn/go-colorable,https://github.com/mattn/go-colorable/blob/master/LICENSE,MIT
github.com/mattn/go-isatty,https://github.com/mattn/go-isatty/blob/master/LICENSE,MIT
github.com/valyala/fasttemplate,https://github.com/valyala/fasttemplate/blob/master/LICENSE,MIT
github.com/labstack/echo/v4,https://github.com/labstack/echo/blob/master/v4/LICENSE,MIT
github.com/labstack/gommon,https://github.com/labstack/gommon/blob/master/LICENSE,MIT
golang.org/x/sys,Unknown,BSD-3-Clause
github.com/valyala/bytebufferpool,https://github.com/valyala/bytebufferpool/blob/master/LICENSE,MIT
golang.org/x/crypto/acme,Unknown,BSD-3-Clause

過不足は、go tool nmコマンドで確認すると良いかな、と。

続いてはsaveです。こちらで、ライセンスファイルを収集することができます。

Complying with license terms

--save_pathオプションが必須で、ライセンスファイルの出力先を指定します。

$ go-licenses save . --save_path licenses

結果は、こんな感じになります。

$ find licenses -type f
licenses/golang.org/x/text/LICENSE
licenses/golang.org/x/crypto/acme/LICENSE
licenses/golang.org/x/net/LICENSE
licenses/golang.org/x/sys/LICENSE
licenses/view-licenses/LICENSE
licenses/github.com/mattn/go-colorable/LICENSE
licenses/github.com/mattn/go-isatty/LICENSE
licenses/github.com/google/uuid/LICENSE
licenses/github.com/labstack/gommon/LICENSE
licenses/github.com/labstack/echo/v4/LICENSE
licenses/github.com/valyala/fasttemplate/LICENSE
licenses/github.com/valyala/bytebufferpool/LICENSE

最後はcheck。ライセンスの分類によって禁止されていないものがないかを確認します。

Checking for forbidden licenses

具体的には、ここで"禁止"と定められたリストです。

https://github.com/google/licenseclassifier/blob/842c0d70d7027215932deb13801890992c9ba364/license_type.go#L323-L346

ライセンスのテキストから、ライセンスの種類を判別できるモジュールを使用しています。

GitHub - google/licenseclassifier: A License Classifier

これ、なんで"禁止"になってるかは、確認しとかないとですね…。

今回のプロジェクトの状態で実行すると、なにも出ません。

$ go-licenses check .

試しに、手元のLICENSEファイルの内容をAGPL 3.0にして再実行。

$ go-licenses check .
Forbidden license type AGPL-3.0 for library view-licenses

こうなりました、なるほど。

自プロジェクトのライセンスは、MITライセンスに戻しておきます。

mitchellh/golicense

次は、こちら。

GitHub - mitchellh/golicense: Scan and analyze OSS dependencies and licenses from compiled Go binaries

こちらは、ビルドされたGoのバイナリファイルを解析して、依存関係やライセンスを出力できるツールです。

インストール。

# Goプロジェクト外で実行
$ GO111MODULE=on go get github.com/mitchellh/golicense

今回使うバージョン。

go: downloading github.com/mitchellh/golicense v0.2.0
go: github.com/mitchellh/golicense upgrade => v0.2.0

ヘルプ。

$ golicense -h
Usage of golicense:
  -license
        look up and verify license. If false, dependencies are
        printed without licenses. (default true)
  -out-xlsx string
        save report in Excel XLSX format to the given path
  -plain
        plain terminal output, no colors or live updates
  -verbose
        additional logging to terminal, requires -plain

実行してみます。こちらは、コマンドの引数に解析対象のバイナリファイルを指定する必要があります。

### golicense [バイナリファイル]
$ golicense view-licenses

結果は、こちら。

github.com/valyala/bytebufferpool MIT License     
github.com/labstack/echo          MIT License                                                     
github.com/labstack/gommon        MIT License                                                     
github.com/mattn/go-isatty        MIT License                                                     
github.com/valyala/fasttemplate   MIT License                                                     
github.com/mattn/go-colorable     MIT License                                                     
github.com/google/uuid            BSD 3-Clause "New" or "Revised" License                         
golang.org/x/net                  BSD 3-Clause "New" or "Revised" License                         
golang.org/x/text                 BSD 3-Clause "New" or "Revised" License                         
golang.org/x/sys                  BSD 3-Clause "New" or "Revised" License                         
golang.org/x/crypto               BSD 3-Clause "New" or "Revised" License

解析したバイナリ自身の情報は入っていませんね。

あとはライセンスの許可、拒否を設定したり

Configuration File

Excel形式での出力も可能なようです。

Excel (XLSX) Reporting Output

制限事項の記載はありますが、使用しているモジュールのライセンスが途中で変わった時に問題になるかも…ってところですね。

Limitaiton

つまりこのツールは、GitHubへのアクセスを行います。

GitHub Authentication

ribice/glice

$GOPATH内のものでないと解析できないようなので、今回はパスしました。

GitHub - ribice/glice: Go license and dependency checker

Songmu/gocredits

最後は、こちら。

GitHub - Songmu/gocredits: creates CREDITS file from LICENSE files of dependencies

依存モジュールのライセンスをまとめてファイル出力するツールです。

インストール。

# Goプロジェクト外で実行
$ GO111MODULE=on go get github.com/Songmu/gocredits/cmd/gocredits

今回使用するバージョン。

go: downloading github.com/Songmu/gocredits v0.2.0
go: found github.com/Songmu/gocredits/cmd/gocredits in github.com/Songmu/gocredits v0.2.0

ヘルプ。

$ gocredits -h
Usage of gocredits (v0.2.0 rev:HEAD):
  -f string
        format
  -json
        data to be printed in JSON format
  -skip-missing
        skip when gocredits can't find the license
  -version
        display version
  -w    write result to CREDITS file instead of stdout

Goプロジェクト内で、以下のコマンドを実行すると、ライセンスファイル(がまとまったもの)が出力されます。

$ gocredits

ファイルとしてまとめるには、次のどちらかの方法を使います。-wの場合はファイル名はCREDITS固定になります。

$ gocredits > CREDITS


$ gocredits -w

https://github.com/Songmu/gocredits/blob/v0.2.0/gocredits.go#L77

できあがったファイルは、ライセンスファイルが結合した状態になっています。

また、JSON形式で出力したり

$ gocredits -json

出力フォーマットを-fで指定することもできます。

デフォルトのフォーマットはこちらで、text/templateを使っています。

https://github.com/Songmu/gocredits/blob/v0.2.0/gocredits.go#L21-L28

とまあ、こんなところで。

まとめ

Goプロジェクトで、依存モジュールのライセンスを調べたり、まとめたりできるツールを調べてみました。

このあたりを使って、ちゃんとライセンスを把握していきたいものですねぇ。