Go言語でgo-cve-searchという簡単なcliツールを作ってみました。
作成に当たってのモチベーションとしては以下の4つ。
・Go言語でcliツールを作ってみたい
・Circleci (CI/CD) を使ってみたい
・READMEにterminalのgifとバッジを付けてみたい
・TDDで開発してみたい
(2020/07/20更新 CodeQLバッチ, Github Starバッチも追加も追加しました!また、Github Starが14になりました!
Github Actionsでクロスコンパイルしたバイナリの配信についても追加しました!)
モチベーション
Go言語でcliツールを作ってみたい
最近、私の周りでよく聞くセキュリティのツールの多くがGo言語で開発されており、またcliツールとしてGithubに公開されているものが多くあったので私も作ってみたい!という感情が高まってきたので作ってみました。
私の周りでよく聞くGo言語で作られたCliツール
・vuls
Circleci (CI/CD) を使ってみたい
CI/CDってよく聞きけど使ったことなかったために今更ですがせっかくなので使ってみました。
trivy, dockleでCircleciが使われていたのでとりあえずCircleciにしてみました。
READMEにterminalのgifとバッジを付けてみたい
見栄えのいいREADMEによくあるteminalのgifとCirclciの結果が表示されるバッジを付けてスターが貰えそうなREADMEにしてみました。
バッジというのはこれのこと。
TDDで開発してみたい
アジャイルサムライ−達人開発者への道を読んでTDD(Test-Driven Development)で開発してみたいと思いやってみました。
TDDというのはテストを先に書いてから実装を行う開発手法のことです。
TDDという言葉はよく聞いていましたし、テストの大切さもよく理解していたのですが実際に実践したことがなかったため良い経験となりました。
やはり実際にやってみるとTDDの良い部分、難しい部分が見えてきます。
やったこと
TDDでの開発
TDDの開発でははじめにテストを書いてそれから実装を行なっていきます。
今回書いたテストコードはこちらです。
trivyのテストの書き方を少し参考にしてみました。
trivy/writer_test.go at master · aquasecurity/trivy · GitHub
trivyではTestifyというフレームワークが使用されていたので私もTestifyを利用しました。
Testifyでは以下の3つの機能が用意されているようです。
・Easy assertions
・Mocking
・Testing suite interfaces and functions
今回は単純なテストしか行なっていないためassetionの機能しか利用していませんが、assert.NoError(), assert.True() といった書き方でテストを書けるので使いやすいように思います。
実際にTDDで開発を始めるとテストができるようにコードを書かなくてはいけなくなるため今までと違った形の実装になったと思います。
また、テストで動作が正しく行われていることをすぐに確認できるという安心感はとても大きいと感じました。
テストで動作確認がすぐにできるのでリファクタリングがとてもしやすくなりました。
今までは現状動いている状態を壊したくないためになかなかリファクタリングしない、したくないということが多くありました。
また、VSCodeではGUI上でテストの実行ができるので「go test ./...」のようなコマンドも書かずに実行できます。
(run package tests, run testのようにテストの範囲も簡単に設定できます)
加えて、テスト実行時に実行時間とコードカバレッジも表示されます。
コードカバレッジが%で表示されるとどうしても100%を目指したい、目指さないといけない、と感じてしまいますが、
アジャイルサムライでも100%を無理して目指す必要はないと書かれていたので80%ほどできていれば良さそうです。
無理して100%にするために複雑なテストを書く、実装のエラー処理を減らすといったことをした方が悪影響がありそうな気がします。
cliツールとして開発
go言語でcliツールの開発のためのライブラリはいくつかあります。
・googleのsubcommands (vulsで利用)
・urfave/cli (trivy, dockleで利用)
Githubのスターの数では cobra > urfave/cli > subcommands の順番で
また、cobraはdockerやKubernetesなどにも利用されているようです。
今回は先人の方々に倣ってurfave/cliを利用しました。
ただ、どれも全く異なる書き方になる訳ではなさそうなので次回違うライブラリを利用しても戸惑うことなく利用できそうな気もします。
実際のコードはこちら
BoolFlagでフラグ名、Aliase、Usageなどを設定し、
Actionの部分でどのような処理を実際に実行するのか記述していきます。
詳細はurfave/cliのmanualに詳しく書かれています。
manualがわかりにくい場合は他の人(trivy, dockle等)がどうやって書いているかみてみるとわかりやすいです。
cliライブラリを利用すると-hコマンドでの表示を自動でいい感じにしてくれるのがありがたいです。
Circleci (CI/CD)を使う
Circleciを利用してGithubへpush時にgo testを実行して問題ないか確認するようにしました。
流れとしては、以下の3ステップ
・Circleciに登録
・Circleciに実行してほしい内容をconfig.ymlで記述し、レポジトリに置く
・Circleciでプロジェクトを選択
このブログを参考にしました。
[Go] CicleCI2.1でgo modのデータを共有しながら複数ジョブを実行する - My External Storage
公式で日本語のGo言語向けのconfigファイルの書き方のドキュメントがあるのですがversion2で書かれており、version2.1のドキュメントが見つからなかったので上記のブログを参考にしました。
実際のconfig.yml
今回Circleciで行なっているのはgo testでテストが通っているかどうかの確認のみ
・circleciのGo言語のコンテナ準備 (executors)
・checkoutして、go get, go test (jobs)
READMEにバッジを付ける
今回付けたバッジはこの6つ。
releaseバッジ
releaseバッジを付けることで最新のバージョンがREADMEのバッジに表示されます。
releaseバッジを付けるためにはまずGithubのリリース機能を利用してリリースページを作成する必要があります。
参考サイト リリースの作成 - GitHub ヘルプ
作成するとこのようなページができます。
リリースページを作成することでLatest releaseのリンクが作成されます。
https://github.com/s-index/go-cve-search/releases/latest
このリンクとshields.ioというバッジ作成で大変お世話になるサイトのリンクを組み合わせることでreleaseバッジの作成を行うことができます。
Markdownで書くとこのような感じ。
[![GitHub release](https://img.shields.io/github/v/release/s-index/go-cve-search.svg)](https://github.com/s-index/go-cve-search/releases/latest)
画像のURLとして以下のように「/github/v/release/自分のレポジトリ.svg」でバッジが生成されるようです。
https://img.shields.io/github/v/release/s-index/go-cve-search.svg
Circleciバッジ
CircleciのSetting -> Notifications -> Status Badges にリンクが表示されているのでこちらをコピペしてREADMEに貼ればOKです。
go report バッジ
vuls, trivy, dockle共にgo reportのバッジがあったので私も付けました。
Go Report Card | Go project code quality report cards
こちらのページでgo getのパスを入力するだけで解析結果が表示されます。
Go Report Card | Go project code quality report cards
簡単なツールなので全てで100%になっています。少し嬉しい!笑
このレポートで確認できるものは以下の7つ。
- gofmt gofmt -s を実行 (冗長な部分を確認)
- go vet コンパイルは通るけど良くない部分を確認
- gocyclo 循環的複雑度(サイクロマティック複雑度)を確認
- golint goのlint
- license Licenseファイルがあるかどうかの確認
- ineffassign 意味のない代入を確認
- misspell ミススペルの確認
単純な確認のみですが最低限やっておくべきボトムラインの確認に利用できそうです。
事前にVSCodeのgoのプラグインなどで開発段階で防いでおくべきものが多い気がするのでVSCodeにgoのlintなどを入れておけばgo reportでも良い評価が得られると思います。
Githubでこの結果を載せておくと利用者としては最低限問題のなさそうなコードだということが確認できるので安心できるのかもしれません。
CodeQLバッジ
(2020/07/20 更新)
CodeQLというGithubが買収したSemmleが提供するコードの静的解析ツールの結果も貼り付ける事ができます。
Goだけでなく、C, C++, C#, Java, JavaScript / TypeScript, Pythonに対応しています。
詳しい内容は以下の記事に書きました。
Githubの新しいセキュリティ機能 CodeQLを使ってみる - Security Index
コードの品質をOSSであれば無料で検査でき、バッジで表示できるのでとてもおすすめです。
他のツールとの比較できたり、コードのどの部分にどんな問題があるのか、どう対応すればいいのかも詳しく表示されます。
(例:Disabled TLS certificate check, Missing regular expression anchor)
licenseバッジ
こちらはshields.ioのリンクを使用し、自分のLicenseのリンクを参照するようにすればOKです。
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/s-index/go-cve-search/blob/master/LICENSE)
バッチとして付けなくても右上のライセンスが書かれている部分で確認できますが、バッチとしてあるとよりわかりやすい、見栄えが良い気がします。
Github Starバッジ
(2020/07/20 更新)
こちらもlicenseバッジと同様にshields.ioを使い、Star数は自分のレポジトリのURLの最後に「/stargazers」を付けたリンクを参照するようにすればこちらもOKです。
[![GitHub stars](https://img.shields.io/github/stars/s-index/go-cve-search.svg?style=social)](https://github.com/s-index/go-cve-search/stargazers)
それ以外にもforks数、watch数などつけることもできます。
以下のサイトにREADMEに付けられるMarkdownのバッジリストがあるのでとても参考になります。
READMEにterminalのgif (demo gif)を付ける
gifの作成
実際に作成したものがこちら。
作成方法としては (Macの方向け)
・ショートカットキー ⌘+⌃+5 で画面録画メニューを表示
・範囲を調整して録画
・録画したものをPicGIF Liteでgif化
【小ネタ】Macの画面を録画して、GIFアニメにする方法 | Developers.IO
注意点としては、動画の取り込み時のフレームの設定やgifにするときのフレームの設定、gifの縦横サイズの設定などを調整する必要があります。
また、他の方法としてはterminalizerというツールを使ってterminalのコマンドをキャプチャ、gif化を行うことができます。
READMEに貼り付け
READMEへの貼り付け方法なのですが、レポジトリにgifを置いてそれを参照する、という方法がありますが、gifは利用者には不要なものなのでできれば入れたくないという方もいるかもしれません。
【GitHub】README.mdをカッコ可愛くデザインしてアプリの魅力を120%にする - Qiita
こちらの記事で初めて知ったのですが、Issueに画像を貼り付けると画像がGithub内で保存され、その画像へのリンクが生成されることを利用することができるようです。
私も今回こちらのやり方でリンク生成、READMEへの貼り付けを行いました。
Markdownの形式でリンク生成してくれるのでコピペが楽で助かります。
Github Actionでクロスコンパイルした実行ファイルをリリース
Githubの ReleaseページのAssetsのところに複数の環境で動作する実行ファイルが既に用意されている事があると思います。
これもGithub Actionsを使うことで簡単に作成する事ができます。
以下のサイトを通りに行う事で10分もかからずにできました。
Go で書いた CLI ツールのリリースは GoReleaser と GitHub Actions で個人的には決まり | tellme.tokyo
やることは
- 「.github/workflows/release.yml」をそのままコピペで利用
- 「.goreleaser.yml」の「git-bump」の部分を自分のプロジェクト名に変更
- tagを新規に作成する
tagが新規に作成されるとGithub Actionsがそれをトリガーに動作します。
Github Actionsを追加で設定する必要はなく、「.github/workflows/release.yml」があるかどうかを見て自動で実行してくれるようです。
ここのReleseページのgo-cve-search_darwin_x86_64.tar.gzなどをダウンロードして解凍すればすぐにこのツールが使えるようになります。
また、goreleaserを使うとHomebrewで簡単に配信することもできるそうなのでまたこちらもやってみたいと思います!
以下の公式のドキュメントを読むと色々とオプションもあるので参考になります。
最後に
go-cve-searchという簡単なcliツールをGo言語で作成してGithubで公開してみました。
すごく便利なツールを作って公開してみた!というようなものではないのですが、CVEの脆弱性情報をjson形式で簡単に最新のものを確認したいという状況の時に、セットアップやDBの作成、更新などを気にせずにお手軽にできるものがほしいなぁという自分の小さな悩みを解決するためのツールができて個人的には満足しています。
他にもっといいツールや方法はあるとは思うのですが、せっかくならGo言語でcliツールとして作りたい、GithubでいっぱいバッジがついたREADMEを作りたい、CI/CDツールを経験したい、アジャイルサムライ読んだからTDDやってみたという願望も入れながら進めてみました。
読んだり聞いたりするのと実際にやってみるのではやっぱり全然違うし、大変さや面白さも全然違うと改めて感じました。
今回はgoroutineを使った並列処理が書けなかったのでいつかやってみたいと思っています。
Twitter (@security_index)