Security Index

セキュリティやソフトウェアについてのあれこれ

go-cve-search 作ってみた - TDD, Circleci, README Badge, Terminal Gif, Cliツール開発の話

Go言語でgo-cve-searchという簡単なcliツールを作ってみました。

 

f:id:security_index:20200720101545p:plain

 

作成に当たってのモチベーションとしては以下の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 

trivy

dockle

dockertags

 

Circleci (CI/CD) を使ってみたい

CI/CDってよく聞きけど使ったことなかったために今更ですがせっかくなので使ってみました。

trivy, dockleでCircleciが使われていたのでとりあえずCircleciにしてみました。

 

READMEにterminalのgifとバッジを付けてみたい

見栄えのいいREADMEによくあるteminalのgifとCirclciの結果が表示されるバッジを付けてスターが貰えそうなREADMEにしてみました。

バッジというのはこれのこと。

 CircleCI

 

TDDで開発してみたい

アジャイルサムライ−達人開発者への道を読んでTDD(Test-Driven Development)で開発してみたいと思いやってみました。

 

f:id:security_index:20200128204535j:plain

 

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のようにテストの範囲も簡単に設定できます)

f:id:security_index:20200129130544p:plain

 

加えて、テスト実行時に実行時間とコードカバレッジも表示されます。

f:id:security_index:20200129132719p:plain

 

コードカバレッジが%で表示されるとどうしても100%を目指したい、目指さないといけない、と感じてしまいますが、

アジャイルサムライでも100%を無理して目指す必要はないと書かれていたので80%ほどできていれば良さそうです。

無理して100%にするために複雑なテストを書く、実装のエラー処理を減らすといったことをした方が悪影響がありそうな気がします。 

 

cliツールとして開発

go言語でcliツールの開発のためのライブラリはいくつかあります。

・googleのsubcommands (vulsで利用)

urfave/cli (trivy, dockleで利用)

cobra

 

Githubのスターの数では cobra > urfave/cli > subcommands の順番で

また、cobraはdockerやKubernetesなどにも利用されているようです。

今回は先人の方々に倣ってurfave/cliを利用しました。

ただ、どれも全く異なる書き方になる訳ではなさそうなので次回違うライブラリを利用しても戸惑うことなく利用できそうな気もします。

 

実際のコードはこちら

f:id:security_index:20200129133458p:plain

 

BoolFlagでフラグ名、Aliase、Usageなどを設定し、

Actionの部分でどのような処理を実際に実行するのか記述していきます。

詳細はurfave/cliのmanualに詳しく書かれています。

manualがわかりにくい場合は他の人(trivy, dockle等)がどうやって書いているかみてみるとわかりやすいです。

 

cliライブラリを利用すると-hコマンドでの表示を自動でいい感じにしてくれるのがありがたいです。

f:id:security_index:20200129134314p:plain

 

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

f:id:security_index:20200129154055p:plain

 

今回Circleciで行なっているのはgo testでテストが通っているかどうかの確認のみ

・circleciのGo言語のコンテナ準備 (executors)

・checkoutして、go get, go test (jobs)

 

READMEにバッジを付ける

今回付けたバッジはこの6つ。 

GitHub release CircleCI Go Report Card Total alerts MIT License GitHub stars

 

releaseバッジ GitHub release 

releaseバッジを付けることで最新のバージョンがREADMEのバッジに表示されます。

releaseバッジを付けるためにはまずGithubのリリース機能を利用してリリースページを作成する必要があります。

参考サイト リリースの作成 - GitHub ヘルプ

 

作成するとこのようなページができます。

f:id:security_index:20200129205033p:plain

 

リリースページを作成することで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

CircleciのSetting -> Notifications -> Status Badges にリンクが表示されているのでこちらをコピペしてREADMEに貼ればOKです。

f:id:security_index:20200129210728p:plain

CircleCIのバッジを追加する - CircleCI

 

 

go report バッジ Go Report Card

vuls, trivy, dockle共にgo reportのバッジがあったので私も付けました。

 

Go Report Card | Go project code quality report cards

f:id:security_index:20200129211046p:plain



こちらのページでgo getのパスを入力するだけで解析結果が表示されます。

Go Report Card | Go project code quality report cards

f:id:security_index:20200129211250p:plain



簡単なツールなので全てで100%になっています。少し嬉しい!笑

このレポートで確認できるものは以下の7つ。

  • gofmt gofmt -s を実行 (冗長な部分を確認)
  • go vet コンパイルは通るけど良くない部分を確認
  • gocyclo 循環的複雑度(サイクロマティック複雑度)を確認
  • golint goのlint 
  • license Licenseファイルがあるかどうかの確認
  • ineffassign  意味のない代入を確認
  • misspell ミススペルの確認

 

単純な確認のみですが最低限やっておくべきボトムラインの確認に利用できそうです。

 

事前にVSCodeのgoのプラグインなどで開発段階で防いでおくべきものが多い気がするのでVSCodeにgoのlintなどを入れておけばgo reportでも良い評価が得られると思います。

 

Githubでこの結果を載せておくと利用者としては最低限問題のなさそうなコードだということが確認できるので安心できるのかもしれません。 

 

CodeQLバッジ  Total alerts 

(2020/07/20 更新)

CodeQLというGithubが買収したSemmleが提供するコードの静的解析ツールの結果も貼り付ける事ができます。

Goだけでなく、C, C++, C#, Java, JavaScript / TypeScript, Pythonに対応しています。

詳しい内容は以下の記事に書きました。

Githubの新しいセキュリティ機能 CodeQLを使ってみる - Security Index

 

コードの品質をOSSであれば無料で検査でき、バッジで表示できるのでとてもおすすめです。

他のツールとの比較できたり、コードのどの部分にどんな問題があるのか、どう対応すればいいのかも詳しく表示されます。

 

f:id:security_index:20200720104011p:plain
(例:Disabled TLS certificate check, Missing regular expression anchor)

 

licenseバッジ MIT 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バッジ GitHub stars

(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のバッジリストがあるのでとても参考になります。

GitHub - Naereen/badges: Markdown code for lots of small badges (shields.io, forthebadge.com etc) . Contributions are welcome! Please add yours!

 

READMEにterminalのgif (demo gif)を付ける

gifの作成

実際に作成したものがこちら。

f:id:security_index:20200130110736g:plain

 

作成方法としては (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内で保存され、その画像へのリンクが生成されることを利用することができるようです。

 

f:id:security_index:20200130112354p:plain

 

私も今回こちらのやり方でリンク生成、READMEへの貼り付けを行いました。

 

f:id:security_index:20200130112533p:plain

 

Markdownの形式でリンク生成してくれるのでコピペが楽で助かります。

 

Github Actionでクロスコンパイルした実行ファイルをリリース

Githubの ReleaseページのAssetsのところに複数の環境で動作する実行ファイルが既に用意されている事があると思います。

これもGithub Actionsを使うことで簡単に作成する事ができます。

 

f:id:security_index:20200720114040p:plain

 

以下のサイトを通りに行う事で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で簡単に配信することもできるそうなのでまたこちらもやってみたいと思います!

 

以下の公式のドキュメントを読むと色々とオプションもあるので参考になります。

Archive - GoReleaser

 

最後に

go-cve-searchという簡単なcliツールをGo言語で作成してGithubで公開してみました。

すごく便利なツールを作って公開してみた!というようなものではないのですが、CVEの脆弱性情報をjson形式で簡単に最新のものを確認したいという状況の時に、セットアップやDBの作成、更新などを気にせずにお手軽にできるものがほしいなぁという自分の小さな悩みを解決するためのツールができて個人的には満足しています。

 

他にもっといいツールや方法はあるとは思うのですが、せっかくならGo言語でcliツールとして作りたい、GithubでいっぱいバッジがついたREADMEを作りたい、CI/CDツールを経験したい、アジャイルサムライ読んだからTDDやってみたという願望も入れながら進めてみました。

 

読んだり聞いたりするのと実際にやってみるのではやっぱり全然違うし、大変さや面白さも全然違うと改めて感じました。

 

今回はgoroutineを使った並列処理が書けなかったのでいつかやってみたいと思っています。

 

スターティングGo言語

改訂2版 みんなのGo言語

Go言語でつくるインタプリタ

 

Twitter (@security_index)