Monorepoなリポジトリでgo.modがネストされた位置にあるときのgoplsの設定

$ gopls version
golang.org/x/tools/gopls v0.7.3
    golang.org/x/tools/gopls@v0.7.3 h1:Lru57ht8vtDMouRskFC085VAjBAZRAISd/lwvwOOV0Q=

Monorepoなリポジトリ内のサブプロジェクトの開発でEmacs + goplsが動かないなーと思っていて *lsp-log* bufferをみると以下のようなエラーが出ていました。

 errors loading workspace: gopls requires a module at the root of your workspace.
You can work with multiple modules by opening each one as a workspace folder.
Improvements to this workflow will be coming soon, and you can learn more here:
https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.
  snapshot=0
  directory=file:///Users/k1low/src/path/to/monorepo

https://github.com/golang/tools/blob/master/gopls/doc/workspace.md によると、通常の設定+Multiple modules構成*1では動かないらしいとのこと。

goplsの experimentalWorkspaceModule の設定を有効にすることで、The workspace moduleという機能を有効になりMultiple modules構成に対応ができるとのこと。

手元の環境では上記を設定とりあえず有効にしてみたらちゃんと補完されました。

Emacsだと以下のような感じ。

(lsp-register-custom-settings
 '(
;; [...]
   ("gopls.experimentalWorkspaceModule" t t)
;; [...]
   ))

*1:私は、「プロジェクトルート以外にgo.modがある構成」と理解しました

GitHub上にあるリポジトリに対してAPIを通じてgit grepライクに走査できるツール gh-grep (gh grep) を作った

git grep 便利ですよね。

私は git grepgit gsub は本当によく使います。

ところで git grep はローカルリポジトリがないと実行できません。

ローカルにリポジトリがなければ git clone して、 git grep すればいいのですが、もう少し簡単にgrepするために gh-grep を作りました。

github.com

gh-grep

gh-grepGitHub APIを使ってGitHub上のリポジトリに対してgrepをするツールです。

特徴は、全てGitHub APIを通じて実行するためローカルに git clone することなくgrepできることです。

また、APIを使っている特徴を活用して複数リポジトリに対してgrepすることなども可能になっています。

あと実行が遅いです。ひたすらGitHub APIを叩いているので...*1

インストール

gh-grep というコマンドとしてHomebrewなどでのインストールも可能ですが、

$ brew install k1LoW/tap/gh-grep

GitHub CLI extensionとしてもインストールできるようにしています。この場合は gh grep というサブコマンドになります。

$ gh extension install k1LoW/gh-grep

使い方

git grep に近いですが、 --owner だけは必須オプションになっています。

例えば、自分のリポジトリのプロジェクトルートにおいてあるDockerfileのベースイメージを検索したい時、

$ gh grep ^FROM --include=Dockerfile --owner k1LoW
k1LoW/centve:Dockerfile:FROM centos:7
k1LoW/docker-alpine-pandoc-ja:Dockerfile:FROM frolvlad/alpine-glibc
k1LoW/docker-sshd:Dockerfile:FROM docker.io/alpine:3.9
k1LoW/gh-grep:Dockerfile:FROM debian:buster-slim
k1LoW/ghdag:Dockerfile:FROM debian:buster-slim
k1LoW/ghdag-action:Dockerfile:FROM ghcr.io/k1low/ghdag:v0.16.0
k1LoW/ghput:Dockerfile:FROM alpine:3.13
k1LoW/ghput-release-action:Dockerfile:FROM ghcr.io/k1low/ghput:v0.12.0
k1LoW/github-script-ruby:Dockerfile:FROM ghcr.io/k1low/github-script-ruby-base:v1.1.0
[...]

という感じで書けます。

「使っているActionをリストアップする」などは、以下のように書けます。

$ gh grep uses: --include=.github/workflows/* --owner k1LoW | sed -e 's/.*uses:\s*//g' | sort | uniq -c
   9 ./
   1 EndBug/add-and-commit@v7
   2 actions/checkout@master
  10 actions/checkout@v1
  50 actions/checkout@v2
  18 actions/setup-go@v1
  21 actions/setup-go@v2
   4 aquasecurity/trivy-action@master
[...]

--owner オプションは Organization(org) に対してもそのまま使えますので、「orgで使っているActionをリストアップする」ということも実施可能です。

また、gh-grep ならではのオプションとして --url というのがあり、grepでマッチした行のURLを出力してくれます。

「まだioutilを使っているところを探してWebUIで確認したい」というときなどは

$ gh grep 'ioutil\.' --include=**/*.go --owner k1LoW --repo ghput --url
https://github.com/k1LoW/ghput/blob/main/gh/gh.go#L300
https://github.com/k1LoW/ghput/blob/main/gh/gh.go#L313
$ gh grep 'ioutil\.' --include=**/*.go --owner k1LoW --repo ghput --url | xargs open

という感じで、macOSならパイプで open コマンドに値を渡すことでそれぞれブラウザで開いてくれます。

今後

git grep を参考に、欲しいと思ったオプションを追加していこうと思います。UTF-8以外の文字コードにも対応したいです。

あと、APIに優しくできる機能は追加したいです。

カジュアルにリポジトリgrepしたくなったとき、是非使ってみてください。

*1:並行処理できるようにすればもう少し早くなるとは思いますが、APIエンドポイントに対して優しくないので高速化だけを目的としたチューニングは今のところしない予定です。

Colima(Lima + Docker)で開発をしてみている

ふとDocker Desktop for Mac以外の環境でDockerイメージを使った開発できるか試したくなったのでやってみています。

私が今選択しているのは Colima というツールです(このエントリ時点でv0.2.2です)。

github.com

Colimaは何をしているかというとLimaとDocker(や、必要に応じてcontainerdやKubernatesも)をいい感じに設定してくれるツールです*1

Lima

LimaはmacOS上でLinuxVMを起動して使えるようにしてくれるツールです。

github.com

READMEでは

Lima can be considered as a some sort of unofficial "macOS subsystem for Linux", or "containerd for Mac".

と書いてありますので、上記のようなイメージを持ってもらうと良さそうです。

Colima

Limaだけでも便利なのですが、Colimaはそこからさらに1コマンドで

  • Limaの設定ファイルを生成してLinux環境を作ってくれる
  • Linux on Limaの環境にDockerをインストールしてセットアップしてくれる
  • ホスト側(つまりmacOS側)のDocker CLIとDocker on Linux on Limaを透過的に接続できるような設定をホスト側にしてくれる

ということをしてくれます。

Colimaのはじめ方

1. Docker Desktop for Mac のアンインストール

まず、Docker Desktop for Macをアンインストールする必要があります。これが一番大きな障壁かもです。

FAQにも

Can it run alongside Docker for Mac?

No, except when started with Containerd runtime. Colima assumes to be the default Docker context and will conflict with Docker for Mac. You should run either, not both.

とあり、Colimaの「Docker CLIとDocker on Linux on Limaを透過的に接続できるような設定」が競合すると思われます。

ちなみに、全く保証はできませんが 私の環境では、Docker Desktop for Macをアンインストールしても、再インストールしたら使っていたDockerコンテナやDockerイメージは残っていました。「試しにColimaを使ってみる」もできそうです。 全く保証はできませんが

とりあえず、Docker Desktop for Macをアンインストールする必要があります。

私の場合はDocker Desktop for MacをHomebrew Caskでインストールしていたので、以下のコマンドを実行してアンインストールしました。

$ brew uninstall --casks docker

2. Colima(とLima)とDockerのインストール

Homebrewで以下をインストールします。

  • Colima(と依存しているLima)
  • ホスト側で docker コマンドと docker compose コマンドを使うためのDockerとdocker-compose
$ brew install colima docker docker-compose
$ ln -sfn $(brew --prefix docker-compose)/bin/docker-compose ~/.docker/cli-plugins/docker-compose # docker-composeを `docker compose` とサブコマンドとして実行できるようにするためにsymlink

3. colima start でDocker on Linux on Limaを起動

あとはColimaを通じてLima上のLinuxを起動して、その上でDockerデーモンを起動するだけです。

Colimaは起動時にVMで使用するコンピューティングリソースやマウントするホスト側のディレクトリを指定できます。指定した設定はLimaの設定ファイルに反映されます*2

私は以下のように実行しています。

$ colima start --cpu 8 --memory 8 --disk 128 --mount '~/src:w' --mount '~/tmp:w'

特に、私はソースコードghq~/src 以下に置いているので --mount ~/src:w というように :w を渡して書き込み可能にしています*3

あとは普通にホスト側から docker ps なり docker pull なりすれば良いです。

たったこれだけです。今までと同じようにDockerなのも良いと感じています。

Colima環境の現時点の課題

今2週間ほどColima環境を使っているのですが、ただ1つを除いて特に問題なくDockerを使った開発ができています*4

その1つの課題というのがホストからマウントしているファイルシステムに関するものです。

ホストとLima VM間はSSHで接続されています。 マウントはsshfsを使用していますし、Colima環境ではホストとDocker on Linux on Limaのdocker.sock の共有もSSHを経由して実行されています。 そのためホスト側のファイルシステムをLima VMを経由してマウントしているファイルを、Dockerコンテナ内からパーミッション変更などをすると失敗します。

以下のIssueが上記の問題に関係するものだと思います。

github.com

環境によっては厳しい条件かもしれません。私の場合は今のところはワークアラウンドは考えたり手元でそのワークアラウンドを適用したりできているので大丈夫です。ただ少し面倒ですね。

というわけで

Colimaの利用レポートでした。

*1:v0.1.xまではBashで書かれていたのですが、最近v0.2.xからGoでリライトされました。それくらいシンプルです

*2:デフォルトだと ~/.lima/colima/lima.yml になると思います

*3:前までは--mountオプションはなく、Limaの設定ファイルを書き換える必要があったのですが、https://github.com/abiosoft/colima/pull/17 を通じて機能要望をし、v0.2で導入してもらいました

*4:この間に更新しているOSSなDockerイメージなどは全部Colima環境です。 https://github.com/k1LoW?tab=packages

YAMLファイルの全ての値にos.Expandenv(os.Expand)を適用するgithub.com/k1LoW/expandを作った

私は作るツールの設定ファイルのフォーマットをYAMLにすることが多いです。

そして各値で環境変数を展開できるようにする機能を追加することがあります。

以下のような設定ファイルを読み込んだ際に、 ${COVERAGE_ACCEPTABLE}${COVERAGE_BADGE_PATH}環境変数から読み込んで変数展開してあげる機能を追加します。

coverage:
  acceptable: ${COVERAGE_ACCEPTABLE}
  badge:
    path: ${COVERAGE_BADGE_PATH}
comment:
  enable: ${COMMENT_ENABLE}

値が文字列であればYAMLファイルをエンコードしてから os.Expandenv を呼べばいいですし、今まではそのように作っていたのですが以下のような課題がありました。

数値や真偽値の変数展開の実装が面倒

${xxxxx} はどう見ても文字列なので、数値や真偽値の変数展開を実現するためにはUnmarshalする際に一工夫が必要になります。

そこまでの実装のモチベーションが持てず、大抵「環境変数展開対象外」にしていました。

os.Expandenv をひたすら書く必要がある

YAMLの文字列を構造体に変更した後に変数展開をする場合、os.Expandenvを各値に対してひたすら適用する必要があります*1。適用漏れもあったり。

そういったYAMLを設定ファイルに採用しているツールが手元に増えてきたので、YAMLファイルの全ての値に対してos.Expandenv(os.Expand)を適用する関数を作ってみました。

github.com

github.com/k1LoW/expand

使い方は簡単で、以下のように expand.Expand* を呼べば []byte や string なYAMLの各値にだけos.Expandenv(os.Expand)を適用します。

c := &Config{}
p := "config.yml"
buf, err := os.ReadFile(p)
if err != nil {
    return err
}
if err := yaml.Unmarshal(expand.ExpandenvYAMLBytes(buf), c); err != nil {
    return err
}

提供している関数は expand package - github.com/k1LoW/expand - pkg.go.dev をみてください。

実装は、ありがたいことに github.com/goccy/go-yaml が Lexer をpublicなAPIとして公開してくれているので、それを利用させてもらっています。 Lexer の活用事例として ycat があり、かなり参考にさせてもらいました*2

github.com

今後

せっかくYAMLのための関数を作ったので、他のフォーマットや構造体の関数も作ってみようかなとは思いました。思っただけです。

もし何かあればフィードバックもらえると嬉しいです。

*1:全ての値を走査するために「reflectを使って再帰的に」という手段もあるとは思います

*2:特に func (p *Printer) PrintTokens(tokens token.Tokens) string。ほぼそのままといってもいいです

メンテナンスが終了しているgithub.com/dgrijalva/jwt-goの脆弱性CVE-2020-26160に対応する

go.modでコミュニティメンテナンスバージョンの github.com/golang-jwt/jwt に replace すれば良さそうです。

replace github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt v3.2.2+incompatible

github.com/dgrijalva/jwt-goは様々なパッケージで利用されており、自分のアプリケーションで直接利用しているわけではなくても依存に含まれることがあります。 どうしようかなーと思っていたのですが、コミュニティでメンテナンスされていることを知ったのでreplaceしました。

全方位に感謝。

GitHub Actionsのサプライチェーンを構成しているDockerイメージやサードパーティActionのコード対して任意のコマンドを実行するツールを作ってみた

注意: 本エントリで紹介するツールは現時点でPoCな実装であり、効果や効率を保証するものではありません。


ちょっと前に社内でGitHub Actionsのサプライチェーン攻撃についての話題があがって、「なるほどー。今時は、リポジトリのコードだけの脆弱性や第三者コードの混入とかだけを気にしていても足りない時があるのか」いう感想でした。

いろいろな軽減策が提案されているので*1基本的にそれらを実践するが良いとする上で、「GitHub Actionsのサプライチェーンをたどって脆弱性スキャンとか危険なコード混入をチェックできたら意味あったりするかなあ」とふと思って、その「GitHub Actionsのサプライチェーンをたどる」というところに興味がでてきたのでツールとして作ってみました。

github.com

oshka

oshka*2の振る舞いは以下の通りです。

  1. 指定したディレクトリ( fs )や、リポジトリrepo )、アクション( action )、Dockerイメージ( image )をローカルのファイルシステムのテンポラリディレクトリに展開する。
  2. 1で展開したテンポラリディレクトリに対して指定のコマンド(デフォルトは trivy fs . --exit-code 1 )を実行する。
  3. 展開したディレクトリからGitHub Actionsのサプライチェーンを解析して( .github/workflows/*.yml とか action.yml とか、action.ymlで使っているDockerfileとか)、構成しているDockerイメージやサードパーティActionを特定する。
  4. 3で特定したDockerイメージやサードパーティActionをローカルのファイルシステムのテンポラリディレクトリに展開する。
  5. 4で展開したテンポラリディレクトリに対して指定のコマンド(デフォルトは trivy fs . --exit-code 1 )を実行する。
  6. 3-5を指定の深さ( --depth、デフォルトは1)繰り返す。
  7. 実行結果のサマリを出力する。

使い方

インストールは簡単でHomebrewだと

$ brew install k1LoW/tap/oshka

です。

デフォルトコマンドにTrivyを採用しているので合わせてTrivyのインストールもしてください。

実際に実行してみると面白くて「これがサプライチェーンかー」となります。

試しに oshka のリポジトリに対して実行してみます。

$ oshka run repo k1LoW/oshka

2021-09-02T07:26:34+09:00 [INFO] Create temporary directory for extracting supply chains: /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/
2021-09-02T07:26:34+09:00 [INFO] Extract repo github.com/k1LoW/oshka to /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/github.com/k1LoW/oshka
Enumerating objects: 131, done.
Counting objects: 100% (131/131), done.
Compressing objects: 100% (92/92), done.
Total 131 (delta 41), reused 85 (delta 14), pack-reused 0
2021-09-02T07:26:35+09:00 [INFO] Run `trivy fs --exit-code 1 .` on /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/github.com/k1LoW/oshka
2021-09-02T07:26:35.864+0900    INFO    Using your github token
2021-09-02T07:26:35.866+0900    INFO    Need to update DB
2021-09-02T07:26:35.866+0900    INFO    Downloading DB...
3.17 MiB / 23.43 MiB [------------------------>_______________________________________________________________________________________________________________________________________________________________] 13.55% ? p/s ?9.22 MiB / 23.43 MiB [------------------------------------------------------------------------>_______________________________________________________________________________________________________________] 39.36% ? p/s ?14.48 MiB / 23.43 MiB [----------------------------------------------------------------------------------------------------------------->_____________________________________________________________________] 61.80% ? p/s ?20.04 MiB / 23.43 MiB [------------------------------------------------------------------------------------------------------------------------------------------------->________________________] 85.53% 28.05 MiB p/s ETA 0s23.43 MiB / 23.43 MiB [-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------] 100.00% 33.59 MiB p/s 1s2021-09-02T07:26:37.914+0900    INFO    Number of language-specific files: 1
2021-09-02T07:26:37.914+0900    INFO    Detecting gomod vulnerabilities...

go.sum (gomod)
==============
Total: 18 (UNKNOWN: 3, LOW: 0, MEDIUM: 7, HIGH: 8, CRITICAL: 0)

+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
|              LIBRARY               | VULNERABILITY ID | SEVERITY |         INSTALLED VERSION         |             FIXED VERSION             |                  TITLE                  |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/apache/thrift           | CVE-2019-0205    | HIGH     | 0.12.0                            | 0.13.0                                | thrift: Endless loop when               |
|                                    |                  |          |                                   |                                       | feed with specific input data           |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2019-0205    |
+                                    +------------------+          +                                   +                                       +-----------------------------------------+
|                                    | CVE-2019-0210    |          |                                   |                                       | thrift: Out-of-bounds read              |
|                                    |                  |          |                                   |                                       | related to TJSONProtocol                |
|                                    |                  |          |                                   |                                       | or TSimpleJSONProtocol                  |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2019-0210    |
+                                    +------------------+          +                                   +---------------------------------------+-----------------------------------------+
|                                    | CVE-2020-13949   |          |                                   | v0.14.0                               | libthrift: potential DoS when           |
|                                    |                  |          |                                   |                                       | processing untrusted payloads           |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-13949   |
+------------------------------------+------------------+          +-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/buger/jsonparser        | CVE-2020-10675   |          | 0.0.0-20180808090653-f4dd9f5a6b44 | v0.0.0-20200321185410-91ac96899e49    | golang-github-buger-jsonparser:         |
|                                    |                  |          |                                   |                                       | infinite loop via a Delete call         |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-10675   |
+                                    +------------------+          +                                   +---------------------------------------+-----------------------------------------+
|                                    | CVE-2020-35381   |          |                                   | v1.1.1                                | jsonparser: GET call can lead to        |
|                                    |                  |          |                                   |                                       | a slice bounds out of range...          |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-35381   |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/containerd/containerd   | CVE-2021-32760   | MEDIUM   | 1.5.3                             | v1.4.8, v1.5.4                        | containerd: pulling and                 |
|                                    |                  |          |                                   |                                       | extracting crafted container            |
|                                    |                  |          |                                   |                                       | image may result in Unix file...        |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2021-32760   |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/dgrijalva/jwt-go        | CVE-2020-26160   | HIGH     | 3.2.0+incompatible                |                                       | jwt-go: access restriction              |
|                                    |                  |          |                                   |                                       | bypass vulnerability                    |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-26160   |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/gorilla/handlers        | GO-2020-0020     | UNKNOWN  | 0.0.0-20150720190736-60c7bfde3e33 | v1.3.0                                |                                         |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/miekg/dns               | CVE-2019-19794   | MEDIUM   | 1.0.14                            | v1.1.25-0.20191211073109-8ebf2e419df7 | golang-github-miekg-dns: predictable    |
|                                    |                  |          |                                   |                                       | TXID can lead to response forgeries     |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2019-19794   |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/sassoftware/go-rpmutils | CVE-2020-7667    | HIGH     | 0.0.0-20190420191620-a8f1baeba37b | v0.1.0                                | In package                              |
|                                    |                  |          |                                   |                                       | github.com/sassoftware/go-rpmutils/cpio |
|                                    |                  |          |                                   |                                       | before version 0.1.0, the               |
|                                    |                  |          |                                   |                                       | CPIO extraction functionality           |
|                                    |                  |          |                                   |                                       | doesn't sanitize...                     |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-7667    |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/satori/go.uuid          | GO-2020-0018     | UNKNOWN  | 1.2.0                             | v1.2.1-0.20181016170032-d91630c85102  |                                         |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| github.com/ulikunitz/xz            | CVE-2021-29482   | HIGH     | 0.5.7                             | v0.5.8                                | ulikunitz/xz: Infinite                  |
|                                    |                  |          |                                   |                                       | loop in readUvarint allows              |
|                                    |                  |          |                                   |                                       | for denial of service                   |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2021-29482   |
+                                    +------------------+----------+                                   +                                       +-----------------------------------------+
|                                    | GO-2020-0016     | UNKNOWN  |                                   |                                       |                                         |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
| k8s.io/kubernetes                  | CVE-2019-1002101 | MEDIUM   | 1.13.0                            | 1.11.9, 1.12.7, 1.13.5,               | kubernetes: Mishandling of              |
|                                    |                  |          |                                   | 1.14.1-beta.0                         | symlinks allows for arbitrary           |
|                                    |                  |          |                                   |                                       | file write via `kubectl cp`...          |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2019-1002101 |
+                                    +------------------+          +                                   +---------------------------------------+-----------------------------------------+
|                                    | CVE-2019-11250   |          |                                   | v1.16.0-beta.1                        | kubernetes: Bearer tokens               |
|                                    |                  |          |                                   |                                       | written to logs at high                 |
|                                    |                  |          |                                   |                                       | verbosity levels (>= 7)...              |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2019-11250   |
+                                    +------------------+          +                                   +---------------------------------------+-----------------------------------------+
|                                    | CVE-2020-8554    |          |                                   |                                       | kubernetes: MITM using                  |
|                                    |                  |          |                                   |                                       | LoadBalancer or ExternalIPs             |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-8554    |
+                                    +------------------+          +                                   +---------------------------------------+-----------------------------------------+
|                                    | CVE-2020-8564    |          |                                   | v1.20.0-alpha.1                       | kubernetes: Docker config               |
|                                    |                  |          |                                   |                                       | secrets leaked when file is             |
|                                    |                  |          |                                   |                                       | malformed and loglevel >=...            |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-8564    |
+                                    +------------------+          +                                   +---------------------------------------+-----------------------------------------+
|                                    | CVE-2020-8565    |          |                                   | v1.20.0-alpha.2                       | kubernetes: Incomplete fix              |
|                                    |                  |          |                                   |                                       | for CVE-2019-11250 allows for           |
|                                    |                  |          |                                   |                                       | token leak in logs when...              |
|                                    |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-8565    |
+------------------------------------+------------------+----------+-----------------------------------+---------------------------------------+-----------------------------------------+
2021-09-02T07:26:37+09:00 [INFO] Detect action actions/setup-go@v2 from /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/github.com/k1LoW/oshka
2021-09-02T07:26:37+09:00 [INFO] Detect action actions/checkout@v2 from /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/github.com/k1LoW/oshka
2021-09-02T07:26:37+09:00 [INFO] Detect action golangci/golangci-lint-action@v2 from /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/github.com/k1LoW/oshka
2021-09-02T07:26:37+09:00 [INFO] Extract action actions/checkout@v2 to /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/actions/checkout@v2
Enumerating objects: 997, done.
Counting objects: 100% (27/27), done.
Compressing objects: 100% (20/20), done.
Total 997 (delta 10), reused 11 (delta 6), pack-reused 970
2021-09-02T07:26:39+09:00 [INFO] Run `trivy fs --exit-code 1 .` on /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/actions/checkout@v2
2021-09-02T07:26:39.114+0900    INFO    Using your github token
2021-09-02T07:26:39.177+0900    INFO    Number of language-specific files: 1
2021-09-02T07:26:39.177+0900    INFO    Detecting npm vulnerabilities...

package-lock.json (npm)
=======================
Total: 3 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 1, CRITICAL: 0)

+---------------+------------------+----------+-------------------+---------------------+---------------------------------------+
|    LIBRARY    | VULNERABILITY ID | SEVERITY | INSTALLED VERSION |    FIXED VERSION    |                 TITLE                 |
+---------------+------------------+----------+-------------------+---------------------+---------------------------------------+
| @actions/core | CVE-2020-15228   | MEDIUM   | 1.1.3             | 1.2.6               | Environment Variable                  |
|               |                  |          |                   |                     | Injection in GitHub Actions           |
|               |                  |          |                   |                     | -->avd.aquasec.com/nvd/cve-2020-15228 |
+---------------+------------------+          +-------------------+---------------------+---------------------------------------+
| node-fetch    | CVE-2020-15168   |          | 2.6.0             | 3.0.0-beta.9, 2.6.1 | node-fetch: size of data after        |
|               |                  |          |                   |                     | fetch() JS thread leads to DoS        |
|               |                  |          |                   |                     | -->avd.aquasec.com/nvd/cve-2020-15168 |
+---------------+------------------+----------+-------------------+---------------------+---------------------------------------+
| underscore    | CVE-2021-23358   | HIGH     | 1.8.3             | 1.12.1              | nodejs-underscore: Arbitrary code     |
|               |                  |          |                   |                     | execution via the template function   |
|               |                  |          |                   |                     | -->avd.aquasec.com/nvd/cve-2021-23358 |
+---------------+------------------+----------+-------------------+---------------------+---------------------------------------+
2021-09-02T07:26:39+09:00 [INFO] Extract action golangci/golangci-lint-action@v2 to /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/golangci/golangci-lint-action@v2
Enumerating objects: 1342, done.
Counting objects: 100% (431/431), done.
Compressing objects: 100% (237/237), done.
Total 1342 (delta 329), reused 272 (delta 192), pack-reused 911
2021-09-02T07:26:40+09:00 [INFO] Run `trivy fs --exit-code 1 .` on /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/golangci/golangci-lint-action@v2
2021-09-02T07:26:40.707+0900    INFO    Using your github token
2021-09-02T07:26:40.764+0900    INFO    Number of language-specific files: 2
2021-09-02T07:26:40.764+0900    INFO    Detecting gomod vulnerabilities...
2021-09-02T07:26:40.765+0900    INFO    Detecting npm vulnerabilities...

package-lock.json (npm)
=======================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)


sample-go-mod/go.sum (gomod)
============================
Total: 4 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 3, CRITICAL: 0)

+-----------------------------+------------------+----------+-----------------------------------+---------------------------------------+---------------------------------------+
|           LIBRARY           | VULNERABILITY ID | SEVERITY |         INSTALLED VERSION         |             FIXED VERSION             |                 TITLE                 |
+-----------------------------+------------------+----------+-----------------------------------+---------------------------------------+---------------------------------------+
| github.com/dgrijalva/jwt-go | CVE-2020-26160   | HIGH     | 3.2.0+incompatible                |                                       | jwt-go: access restriction            |
|                             |                  |          |                                   |                                       | bypass vulnerability                  |
|                             |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-26160 |
+-----------------------------+------------------+          +-----------------------------------+---------------------------------------+---------------------------------------+
| github.com/gogo/protobuf    | CVE-2021-3121    |          | 1.2.1                             | v1.3.2                                | gogo/protobuf:                        |
|                             |                  |          |                                   |                                       | plugin/unmarshal/unmarshal.go         |
|                             |                  |          |                                   |                                       | lacks certain index validation        |
|                             |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2021-3121  |
+-----------------------------+------------------+----------+-----------------------------------+---------------------------------------+---------------------------------------+
| github.com/miekg/dns        | CVE-2019-19794   | MEDIUM   | 1.0.14                            | v1.1.25-0.20191211073109-8ebf2e419df7 | golang-github-miekg-dns: predictable  |
|                             |                  |          |                                   |                                       | TXID can lead to response forgeries   |
|                             |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2019-19794 |
+-----------------------------+------------------+----------+-----------------------------------+---------------------------------------+---------------------------------------+
| golang.org/x/crypto         | CVE-2020-29652   | HIGH     | 0.0.0-20200622213623-75b288015ac9 | v0.0.0-20201216223049-8b5274cf687f    | golang: crypto/ssh: crafted           |
|                             |                  |          |                                   |                                       | authentication request can            |
|                             |                  |          |                                   |                                       | lead to nil pointer dereference       |
|                             |                  |          |                                   |                                       | -->avd.aquasec.com/nvd/cve-2020-29652 |
+-----------------------------+------------------+----------+-----------------------------------+---------------------------------------+---------------------------------------+
2021-09-02T07:26:40+09:00 [INFO] Extract action actions/setup-go@v2 to /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/actions/setup-go@v2
Enumerating objects: 1043, done.
Counting objects: 100% (39/39), done.
Compressing objects: 100% (31/31), done.
Total 1043 (delta 13), reused 19 (delta 3), pack-reused 1004
2021-09-02T07:26:41+09:00 [INFO] Run `trivy fs --exit-code 1 .` on /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/actions/setup-go@v2
2021-09-02T07:26:41.822+0900    INFO    Using your github token
2021-09-02T07:26:41.883+0900    INFO    Number of language-specific files: 1
2021-09-02T07:26:41.883+0900    INFO    Detecting npm vulnerabilities...

package-lock.json (npm)
=======================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)

2021-09-02T07:26:41+09:00 [INFO] Cleanup temporary directory for extracting supply chains: /var/folders/fp/hk95_wsj7s18mmc9drvrxdp1tt294n/T/

Run results
===========
+----------------------------------+--------+--------------------------+-----------+-------+------------------------------------------+
|               NAME               |  TYPE  |         COMMAND          | EXIT CODE | DEPTH |                   HASH                   |
+----------------------------------+--------+--------------------------+-----------+-------+------------------------------------------+
| github.com/k1LoW/oshka           | repo   | trivy fs --exit-code 1 . | 1         | 0     | ca36be55f7fcfbc31cc7dc5e80b6fb7d01c53981 |
|                                  |        |                          |           |       | (commit hash)                            |
| actions/setup-go@v2              | action | trivy fs --exit-code 1 . | 0         | 1     | 331ce1d993939866bb63c32c6cbbfd48fa76fc57 |
|                                  |        |                          |           |       | (commit hash)                            |
| actions/checkout@v2              | action | trivy fs --exit-code 1 . | 1         | 1     | 5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f |
|                                  |        |                          |           |       | (commit hash)                            |
| golangci/golangci-lint-action@v2 | action | trivy fs --exit-code 1 . | 1         | 1     | 5c56cd6c9dc07901af25baab6f2b0d9f3b7c3018 |
|                                  |        |                          |           |       | (commit hash)                            |
+----------------------------------+--------+--------------------------+-----------+-------+------------------------------------------+
$

--depth 2 にすると、さらに深くサプライチェーンをたどります。

$ oshka run repo k1LoW/oshka --depth 2

[...]

Run results
===========
+----------------------------------+--------+--------------------------+-----------+-------+-------------------------------------------------------------------------+
|               NAME               |  TYPE  |         COMMAND          | EXIT CODE | DEPTH |                                  HASH                                   |
+----------------------------------+--------+--------------------------+-----------+-------+-------------------------------------------------------------------------+
| github.com/k1LoW/oshka           | repo   | trivy fs --exit-code 1 . | 1         | 0     | ca36be55f7fcfbc31cc7dc5e80b6fb7d01c53981                                |
|                                  |        |                          |           |       | (commit hash)                                                           |
| actions/setup-go@v2              | action | trivy fs --exit-code 1 . | 0         | 1     | 331ce1d993939866bb63c32c6cbbfd48fa76fc57                                |
|                                  |        |                          |           |       | (commit hash)                                                           |
| actions/checkout@v2              | action | trivy fs --exit-code 1 . | 1         | 1, 2  | 5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f                                |
|                                  |        |                          |           |       | (commit hash)                                                           |
| golangci/golangci-lint-action@v2 | action | trivy fs --exit-code 1 . | 1         | 1     | 5c56cd6c9dc07901af25baab6f2b0d9f3b7c3018                                |
|                                  |        |                          |           |       | (commit hash)                                                           |
| github/codeql-action/init@v1     | action | trivy fs --exit-code 1 . | 1         | 2     | 33f3438c1d59883f5e769fdf2b6adb6794d91d0f                                |
|                                  |        |                          |           |       | (commit hash)                                                           |
| github/codeql-action/analyze@v1  | action | trivy fs --exit-code 1 . | 1         | 2     | 33f3438c1d59883f5e769fdf2b6adb6794d91d0f                                |
|                                  |        |                          |           |       | (commit hash)                                                           |
| actions/publish-action@v0.1.0    | action | trivy fs --exit-code 1 . | 0         | 2     | 63abd0d521e21329399edb30e8f577a7ab85443c                                |
|                                  |        |                          |           |       | (commit hash)                                                           |
| actions/setup-node@v1            | action | trivy fs --exit-code 1 . | 1         | 2     | f1f314fca9dfce2769ece7d933488f076716723e                                |
|                                  |        |                          |           |       | (commit hash)                                                           |
| alpine/git:latest                | image  | trivy fs --exit-code 1 . | 1         | 2     | sha256:70f7b70d9324314642b324ac79655862656255dd71b4d18357e5a22f76215ade |
|                                  |        |                          |           |       | (digest)                                                                |
| datadog/squid:latest             | image  | trivy fs --exit-code 1 . | 1         | 2     | sha256:f7d19d5e3f4163771291d91de393ce667f2327a3e080c39b9b7ea9e19f91488f |
|                                  |        |                          |           |       | (digest)                                                                |
+----------------------------------+--------+--------------------------+-----------+-------+-------------------------------------------------------------------------+

デフォルトコマンドは trivy fs --exit-code 1 . ですが、全てローカルのファイルシステムのテンポラリディレクトリに展開する実装になっているので、ローカルにインストールされているコマンドならなんでも実行できるはずです。複数コマンドも以下のように指定可能です。

$ oshka run repo k1LoW/tbls -c 'command1' -c 'command2' -c ...

起点とできるのはリポジトリrepo )以外にも、ディレクトリ( fs )やアクション( action )、Dockerイメージ( image )が指定可能です。コマンドの作りはTrivyを参考にしています。

$ oshka run fs .
$ oshka run action actions/cache@v2
$ oshka run image nginx:alpine

というわけで

GitHub Actionsのサプライチェーンをたどって任意のコマンドを実行できるツール oshka を作ってみたというお話でした。

感想としては、

  • これがサプライチェーン
  • Trivyすごい。いろいろスキャンしてくれる。
  • ついでにサードパーティアクションがcommit SHAでピン留めされているか確認する機能を追加すると良さそう
  • ついでにサードパーティアクションでリポジトリリダイレクト*3が発生しているか確認すする機能を追加すると良さそう
  • こういうサプライチェーン攻撃に対する何かしらの機能にニーズがあるならどこかのセキュリティツールが実装してくれたらいいなあ

という感じです。

以上、夏休みの自由研究発表でした。

参考

*1:「参考」の項を参照

*2:oʊʃkə

*3:「参考」の項を参照

Pull Requestベースでgit revertできる pr-revert / pr-revert-action を作った

記事タイトルをみて「え?それもうあるじゃん」と思った方、半分正解で半分不正解かもしれません(私が知らないだけかもしれません)。

マージしたPull Requestをリバート(して新たなPull Requestを作成)する機能はあります。

f:id:k1LoW:20210802231024p:plain

マージ済みのPull Requestのページの上記画像でいうと赤枠の部分にあります。

リバート機能はあります。ただし、Web UI上にだけです。

マージ済みPull Requestを指定してリバートする機能は、実は公式のghコマンドにもGitHub APIにもないのです*1

ところで、開発の現場では必ずPull Requestでレビューを実施したあとマージ、そしてリリースという流れになっていることが多いです。

Pull Requestは何かしらの意味をもったコード差分の塊になっているため、「マージ済みPull Request単位でのリバート」は何かあった場合の有効な選択肢の1つとなります。

というわけで、様々な自動化のための1つのパーツとして「マージ済みPull Request単位でのリバート」を実現する pr-revert を作成しました。

github.com

pr-revert

pr-revertのデフォルトの振る舞いとしては以下の通りです。

  1. 対象のリポジトリ(リモートリポジトリ)を一時的なディレクトリにclone。
  2. リバートコミットを積むブランチ(リバートブランチ)を作成。
  3. Pull Requestをリバート。
  4. リバートブランチをリモートリポジトリにPush。
  5. リバートブランチでPull Requestを作成。
  6. 一時的なディレクトリを削除。

また、事項には以下の環境変数の設定が必要です( GITHUB_TOKEN 以外はGitHub Actions上では自動で設定される値です)。

環境変数 説明 デフォルト値
GITHUB_TOKEN リポジトリのアクセストーク -
GITHUB_REPOSITORY 対象リポジトリ ( owner/repo ) -
GITHUB_SERVER_URL GitHubのWeb UIのURL https://github.com
GITHUB_API_URL GitHub APIのURL https://api.github.com
GITHUB_GRAPHQL_URL GitHub GraphQL APIのURL https://api.github.com/graphql
$ export GITHUB_TOKEN=XXXxxxxxxXXXXxXXXXXXXX
$ export GITHUB_REPOSITORY=owner/repo

あとは、pr-revertコマンドを用途に合わせたオプションをつけて実行するだけです。

マージ済みPull Requestを指定してリバートする

(実装が間違っていなければ)Web UIとほぼ同じ機能になります。

$ pr-revert --number 3

マージされた最新5件のマージ済みPull Requestをまとめてリバートする

複数のマージ済みPull RequestをまとめてリバートするPull Requestを作ることが可能です。

$ pr-revert --latest 5

2時間前までにマージされたPull Requstをまとめてリバートする

期間指定も可能です。

$ pr-revert --until '2 hours'

新しいリバートPull Requestを作らずにブランチのPushだけをする

デフォルトの振る舞いの5番を実施しません。

$ pr-revert --latest 3 --no-pull-request

一時ディレクトリ を削除しない

デフォルトの振る舞いの6番を実施しません。

$ pr-revert --latest 3 --no-cleanup

ブランチを作成せずに直接デフォルトブランチにリバートする

デフォルトの振る舞いの2番を実施しません。

$ pr-revert --latest 3 --no-branch

pr-revert-action

pr-revertは最終的に自動化の一部として使われることを想定しています。GitHub Actionsによる自動化のためにactionも作成しています。

github.com

pr-revertに渡すオプションは全て環境変数で受け取れるようになっているので、例えば workflow_dispatch を作成する場合などは以下のようなワークフローを作成できます。

# .github/workflows/revert.yml
name: Revert

on:
  workflow_dispatch:
    inputs:
      latest:
        description: '--latest: マージ済みPull Requestを何件リバートするか指定してください'
        required: false
      until:
        description: '--until: マージ済みPull Requestをどれくらいの期間リバートするか指定してください'
        required: false
      number:
        description: '--number: マージ済みPull Requestの番号を指定してください'
        required: false

jobs:
  revert:
    runs-on: ubuntu-latest
    steps:
      -
        uses: k1LoW/pr-revert-action@v0
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_REVERT_LATEST: ${{ github.event.inputs.latest }}
          PR_REVERT_UNTIL: ${{ github.event.inputs.until }}
          PR_REVERT_NUMBER: ${{ github.event.inputs.number }}

というわけで

とりあえずパーツを作っただけですが、これからこれをうまく組み込んで、いろいろ作ってみたいと思っています(まだ)。

もし使ってみた方が現れましたらフィードバックお待ちしています。

*1:2021年7月時点で少なくとも私が探した限りは見つかりませんでした。