メンテナンスが終了している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月時点で少なくとも私が探した限りは見つかりませんでした。

第8回Web System Architecture研究会に参加して「システムの変化に追従可能でかつ理解し易いドキュメントシステムのモデル化」について発表した #wsa研

wsa.connpass.com

オンライン開催に参加してきました。

予稿

github.com

発表資料

システムの変化に追従可能でかつ理解し易いドキュメントシステム

発表内容はドキュメントシステム(ドキュメンテーションツール)についてです。

私は、システムを理解するためにかかる時間(いわゆる「オンボーディングまでのコスト」。私は「開発開始までのオーバーヘッド」と呼んでいます)をいかに継続的に削減できるかに興味をもっています。

それはなぜかというと「私がシステムの理解のセンスがないからそれをなんとか技術で解決したい」という個人的欲求に他ならないのですが、「まあオンボーディングのコストが小さくなればそれはエンジニア全員にも良いことだろうな」と勝手に思い込んでいろいろ作ったりしています。

実は今回の発表にいたるまでには過程があって、July Tech Festa 2021 winter ではDocumentation as Codeというキーワードで継続的なドキュメント運用の実現方法について主張しPHPerKaigi 2021ではその主張をさらに進めて発表しました

www.youtube.com

そして今回のWSA研では、集合を使って「継続的なドキュメント運用」「理解しやすいドキュメント」についてモデル化し、有効性を主張してみました。まだまだ前提などが甘々ですが、やはりWSA研、有用なフィードバックを多くいただきました。ありがとうございました。

実装としてのndiag

さて、上記の発表の主張に沿って実装しているのが ndiag です。

github.com

嘘です。

実際には逆で、いかに継続的にドキュメントを運用できるかウンウン考えて試行錯誤しながらndiagを開発し、その設計思想を整理したのが上記の発表です。

ndiagがどのようなドキュメンテーションツールなのか?については割愛します。公式チュートリアルや、実際に使ってみたエントリを書いてくださっている方もいらっしゃるので(本当にありがとうございます!!)そちらをご覧ください。

zenn.dev

「システムが頻繁に更新されるならシステム自体を観測してそこからドキュメントを作成すればいい」というアイデアは、真新しいものではありません(PHPerKaigi 2021の資料にその例が掲載されていて、わかりやすいと思います)。私自身も tbls という自身で作成したデータベースドキュメンテーションツールの開発で効果を実感しています。

github.com

ndiagで実現したいと思っていることは、まだまだ全ては実装できていません。それは、主に私の技術力や、開発に確保できる時間、ついつい発散してしまうモチベーションなどが原因です。

ただ、システムの継続的なドキュメンテーションを実現するのに有用そうな技術もどんどん生まれてきているので、もう1、2歩進めることができるんじゃないかなあと思っています。

とりあえず今の主張は以下です。

まとめ

今回もWSA研は楽しかったです。いつも受け入れていただいてありがたいです。

特に @YutaroHayakawaさん の発表と、懇親会でのいろいろなお話が「頑張らないとな」と思うことが多々あり「頑張らないとな」という気持ちです。

みなさんお疲れ様でした!!

任意のPull Requestの内容を複数のリポジトリに対して一括コピーするツールpr-bulletを作った

GitHub Actions便利ですよね。

ペパボではGitHub Enterprise Server(以下、GHES)が運用されており、GHESでもGitHub Actionsが利用できます。

uses: だけで利用できるリポジトリを横断で再利用可能なActionの存在はかなり生産性を上げていると思います。

そういった便利なワークフローを複数のリポジトリに対して適用していきたいことが時々あります。

一気に複数のリポジトリに同じワークフローを適用したいこともあれば、「あ、このリポジトリにはあのリポジトリのワークフローをいれたほうがいいな」となることもあります。

その時、それぞれのリポジトリに対して「突然のデフォルトブランチへのpush」はあまりにも乱暴なのでPull Requestを作成していくことになります。

ただ、適用したいレポジトリが2桁あったとき、Pull Requestを作成するのも心が折れそうになります。

そこで、任意のPull Requestの内容を他の複数のリポジトリに対して「コピーPull Request」として一括作成するツールpr-bulletを作ってみました。

github.com

pr-bullet

ちなみに、同様の、pr-bulletよりも高機能なツールとして NerdWalletOSS/shepherd があります。

それなのに、なぜわざわざ作ったかというと

  • 単機能で迷わない
  • 設定ファイルが必要ない
  • 全てオンメモリで完結

を実現したかったからです。

pr-bulletの使い方は簡単で、

  1. どこか適当なリポジトリでオリジナルとなるPull Requestを作成
  2. pr-bulletを実行して指定のリポジトリへPull Requestをコピー

で終わりです。

実行している様子は以下のような感じです。

$ pr-bullet https://github.com/k1LoW/my-bullets/pull/3 k1LoW/tbls k1LoW/ndiag
Original pull request:
  Title ... Add allow-auto-merge label action using ghdag
  URL   ... https://github.com/k1LoW/my-bullets/pull/3
  Files ... 34
Target repositories:
  k1LoW/tbls, k1LoW/ndiag
Do you want to create pull requests? (y/n) [y]: y

Copying k1LoW/my-bullets pull request #3 to k1LoW/tbls ... https://github.com/k1LoW/tbls/pull/999 as draft
Copying k1LoW/my-bullets pull request #3 to k1LoW/ndiag ... https://github.com/k1LoW/ndiag/pull/333 as draft
$

実際は

  • 追加もしくは修正したファイルのみサポート(削除やリネームは未対応)
  • ファイルのパーミッションは一律 100644 v0.3.0 で修正しました
  • オリジナルPull Requestのコミットは強制で1つにまとめられる
  • ラベルやAssigneesはコピーされない

といった感じで本当の意味での「コピー」ではないのですが、それでも毎回Pull Requestタイトルや文章をコピペしなくて良いだけだいぶ楽です。

とりあえず社内のGHESに k1low/my-bullets リポジトリを作成して、Pull Request発射基地としてみました。

1コマンドでPull Requestがコピーできてしまうので、ついつい濫用しそうですが気をつけていこうと思います。

`container:` でUbuntuのBionic以下のDockerイメージを指定してactions/checkout@v2を利用する場合は注意が必要

GitHub Actionsを使っているとき、あまり container: を指定することはないかもしれませんが、例えば以下のように ubuntu:bionic を指定して事前にGitをインストールした上で actions/checkout@v2 を実行したとき

name: CI

on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    container: ubuntu:bionic
    steps:
      - run: |
          apt-get update -qqy
          apt-get install -qqy git
      - uses: actions/checkout@v2
      - run: git status

最後の git status が失敗します。

f:id:k1LoW:20210317230131p:plain

actions/checkout@v2 は Git 2.18 以上を要求している。しかし...

これの答えは actions/checkout@v2 のログに書かれています。

f:id:k1LoW:20210317230346p:plain

The repository will be downloaded using the GitHub REST API To create a local Git repository instead, add Git 2.18 or higher to the PATH

Git 2.18 以上がインストールされていないと git clone ではなくGitHub REST APIを使ってダウンロードしてくるのですね。

しかし、Ubuntu BionicにインストールされるGitのバージョンは

f:id:k1LoW:20210317230707p:plain

残念ながら1ポイント及ばす 2.17 なのです(2021年3月17日)

actions/checkout@v2 on Ubuntu Bionicでgit cloneしてもらうにはGitのバージョンをあげるしかない

ということで、私は以下のようにしています。

name: CI

on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    container: ubuntu:bionic
    steps:
      - name: Update Git
        run: |
          apt-get update -qqy
          apt-get -qqy install software-properties-common
          add-apt-repository -y ppa:git-core/ppa
          apt-get update -qqy
          apt-get -qqy install git
      - uses: actions/checkout@v2
      - run: git status
  1. add-apt-repository を使いたいので software-properties-common をインストール
  2. “Ubuntu Git Maintainers” teamのPPAをリポジトリとして追加
  3. Gitをインストール

f:id:k1LoW:20210317232218p:plain

無事 git clone されました。

以上、メモでした。

GitHub Container RegistoryのDockerイメージをリポジトリに紐づける方法

GitHub Container Registoryは、GitHub Package Registryとは異なりPublicなDockerイメージのpullにGitHub認証の必要がないなど、利用者にとって便利です。

また、リポジトリとの紐付けが強制されていないので自由に様々なイメージを管理できます。

イメージはProfileページのPackagesタブにリストアップされます。

f:id:k1LoW:20210306193712p:plain

ただ、私の主な用途としてはリポジトリで公開しているライブラリのDockerイメージの提供なのでリポジトリと紐付けたい。

具体的にはリポジトリの Packages の欄に表示させたい。

f:id:k1LoW:20210306193956p:plain

どう紐づければいいのかわからなかったのですが、やっとわかりました。

DockerfileにLABELとして org.opencontainers.image.source を設定すればいいようです。

LABEL org.opencontainers.image.source=https://github.com/k1LoW/tbls

もしくはdocker build時にビルドフラグとして --label=org.opencontainers.image.source=https://github.com/k1LoW/tbls を渡せばいいみたいです。

私はGoReleaserを利用しているので以下のような設定を追加しています。

dockers:
  -
    goos: linux
    goarch: amd64
    image_templates:
      - 'ghcr.io/k1low/tbls:v{{ .Version }}'
      - 'ghcr.io/k1low/tbls:latest'
    dockerfile: docker/Dockerfile.ghcr.io
    build_flag_templates:
      - "--pull"
      - "--label=org.opencontainers.image.created={{.Date}}"
      - "--label=org.opencontainers.image.name={{.ProjectName}}"
      - "--label=org.opencontainers.image.revision={{.FullCommit}}"
      - "--label=org.opencontainers.image.version={{.Version}}"
      - "--label=org.opencontainers.image.source=https://github.com/k1LoW/tbls"

これで、無事リポジトリにDockerイメージを紐づけることができました。Dockerイメージの設定画面でも青の認証バッジがつきます。

f:id:k1LoW:20210306194539p:plain

そして、最後にDockerイメージをPublicにするのを忘れないでください。

どうやらGitHub Container RegistoryにpushしたイメージはデフォルトはPrivateなようです。

これを忘れると誰にも使ってもらえません。

というわけでメモでした。