おそらくはそれさえも平凡な日々

それなりに安心な install.sh を作るツール insmith

https://github.com/Songmu/insmith

度々話題になる悪名高い curl | sh インストーラーだが、告白すると私が開発しているGo製のOSSは大体、リポジトリルートに、install.sh を配置していて、それを使って実行バイナリを curl インストールできるようにもなっている。GitHub ReleasesのAssets上のアーカイブをダウンロードして展開して実行バイナリを配置している。例えば、gocredits だとこういう感じ。

$ curl --proto '=https' --tlsv1.2 -fsSL https://raw.githubusercontent.com/Songmu/gocredits/main/install.sh | sh -s

デフォルトではカレントディレクトリ以下の ./bin/gocredits に配置する。

これは、直接の利用を推奨しているわけではない。ただ、私はリポジトリ上で、GitHub Actions上に実行バイナリをインストールするためのカスタムGitHub Actionも同時に提供することが多く、 gocredits も最近そうした。そのときに、この install.sh を利用している。この場合は curl は使わず、 $GITHUB_ACTION_PATH/install.sh の形で呼び出してはいる。

これによって uses: Songmu/gocredits@v1 や uses: Songmu/gocredits@v1.0.0 のように指定すれば、GitHub Actions上に実行バイナリをインストールできる。勿論ハッシュ指定もできる。

当然、Acitons上で go install github.com/Songmu/gocredits/cmd/gocredits@v1.0.0 としても良いが、GitHub Actions形式には以下のメリットがある。

  • ビルド済みバイナリを配置するだけなので高速である
  • Dependabotでバージョンアップを検知できる

go install でも、 go.mod の tool ディレクティブで管理して、Dependabotにバージョンアップを検知してもらうという手もありそうですが、残念ながらまだ未対応です。

imsmith による install.sh の改善

ということで、私のGo製OSSでは install.sh を配置していますが、これはもともとはgoreleaser/godownloader が生成していた install.sh をベースにしていた。新規OSSを作る時に godzil がプロジェクトに合わせた install.sh 自動生成するようになっている。

ただ、 godownloader はアーカイブされて久しく、この install.sh も古くなってきているのを薄々感じていた。最近のサプライチェーンセキュリティの観点からも改善することにした。そのために作ったのが、この insmith というツール。

https://github.com/Songmu/insmith

これはプロジェクトに即した install.sh を生成してくれるCLIだ。とは言っても、かなり僕のプロジェクト向けに作られていて、デフォルト値の決め方なんかも含め、オレオレツールクオリティではあります。使いたい方がいれば要望などは応えたいです。

具体的に取り組んだ改善ポイントは以下。

アセットの検証を SHA256SUMS ではなく gh attestation verify を優先して使うように

これが一番やりたかったこと。

元々はリリースアセットに SHA256SUMS というチェックサムファイルも上げておき、 インストールするアーカイブとのハッシュ値比較をしていた。よくある方法ではあるが、これだと、チェックサムとアーカイブが同じ場所に置かれているので、ダウンロードファイルの破損検出くらいにしか役に立ちません。

GitHubにはArtifact Attestationsという、GitHub Actions上でビルドした成果物に対して証明を付与できる機能があり、これを使えば、リリースアセットの検証をより強固に出来る。アセットのAttestationは以下のように検証できる。これを install.sh の中で実施している。

gh attestation verify "$artifact" \
    --repo "$REPOSITORY" \
    --source-digest "$commit" \
    --signer-digest "$commit" \
    --signer-workflow "$WORKFLOW" || return 1

gh attestation がない環境では、従来通りの SHA256SUMS による検証に今のところはフォールバックしている。

OSS開発者側のビルド時のAttestationsの付与方法についてはまた別途記事を書くつもりだが、tagprのrelease.yaml が参考になると思う。また以下の記事も参照されたし。(ただ少し情報が古い)

client9/shlib 由来のシェル関数を最新化

元々の godownloader 由来の install.sh でも client9/shlib 由来のシェル関数を使っていたが、これを最新のものに更新した。

install.sh が最終行まで読み込まれないと実行されないように

具体的には、 install.sh の最終行で main "$@" を呼び出すようにして、それ以前の行には変数宣言や関数定義しか書かれていない。これによって、install.sh が最終行まで読み込まれないと実行されないようになっている。install.sh ダウンロード中に途中で切れてしまったりしても、中途半端に実行されることを防げる。

CLIによる再生成アプローチ

これまではプロジェクトをscaffoldingした際の install.sh を悪い秘伝のタレ的に大事に使い続けていて、更新が難しいという問題があったが、生成CLIを切り出して作ったので、もし仮に今後更新が必要になったら、 insmith を更新してから、 $ insmith > install.sh のように再生成すれば良くなった。

生成された install.sh を bashka でも検証して、問題ないことも確認しました。

まとめ

ということで、このエントリーは、私の最近の取り組みの紹介と、安心して使ってもらえるように整備していますという報告でした。とはいえ、この領域は不安や心配が尽きず、見落としもあろうかと思うので、問題がありそうであればお知らせいただけると助かります。

おまけ: k1LoW/gh-setup

今回の私の動機は、 GoのバイナリをインストールするカスタムGitHub Actionを提供したいという話だでした。

実は、その目的であれば、 k1LoW/gh-setup というGitHub Actionsが既に存在していて、これを使えば、GitHub Actions上にGoのバイナリをインストールするカスタムGitHub Actionを簡単に作れて、Attestationsの検証機能もある。

なので、今回はこれを利用することも検討したのだが、これまでのやり方からの移行差分の少なさや、 --signer-workflow の指定などをデフォルトでしたかったこともあり、自前やってみた次第です。

参考: tblsをセットアップするGitHub Actionとしてsetup-tbls(を作るツールとしてgh-setup)を作った - Copy/Cut/Paste/Hatena

created at
last modified at

2026-09-28T01:34:38+0900

comments powered by Disqus