KAYAC Engineers' Blog

GitHub Actionsの外部ActionでVersionTagを使ってるものを一括でCommitHashにしたい。

こんにちは。今年からグループ情報部という部署にいる 池田(@mashiike) です。

背景

先日、GitHub Actionsの tj-actions/changed-files にセキュリティインシデントがありました。実は、 reviewdog/action-setup 経由らしいという話が直近の話題です。

nvd.nist.gov

www.wiz.io

サプライチェーン攻撃が本格的に心配になってきた今日このごろです。 さて、このような状況で、GitHub Actionsの外部actionへの攻撃に対する対策はどうしたら良いのでしょうか?

そんなとき、ちょうど次の記事が公開されまして、「へぇーRenovateとDependabotならCommitHash直指定でも自動で上げてくれるんだ〜」と知りました。

developer.hatenastaff.com

やっぱり、対策はCommitHashで直指定して、あとはRenovateやDependabotつくったPRを精査という感じなのでしょう。 これから、たくさんのリポジトリのものを置き換えねば!

実際にやってみたら・・・

試しに1つのリポジトリでやってみました。

しっかりCI/CDを整えていると、48行と地味に差分が多くなります。
さらに、現行で使っているバージョンのコミットハッシュが何なのかを調べる作業が地味にトイルでした。

これを、多数のリポジトリにやるのは面倒だ!と思いました。 そこで、誰かが作ってそうですがシュッと小物を作成しました。

github.com

$ brew install mashiike/tap/actionspin

homebrew tapもあるので、インストールも簡単です。

このツールでは、リポジトリルートで actionspin と実行すると、 .github 配下のワークフローの uses の中で、version tag で参照しているものを見つけて、 commit hash に変換してくれます。

$ actionspin
{"time":"2025-03-18T14:42:20.911018+09:00","level":"INFO","msg":"replace uses","path":"workflows/test.yaml","owner":"actions","repo":"setup-go","ref":"v5","commitHash":"f111f3307d8850f501ac008e886eec1fd1932a34"}
{"time":"2025-03-18T14:42:21.415795+09:00","level":"INFO","msg":"replace uses","path":"workflows/test.yaml","owner":"actions","repo":"checkout","ref":"v4","commitHash":"11bd71901bbe5b1630ceea73d27597364c9af683"}
Replaced uses:
  - actions/setup-go@v5 -> f111f3307d8850f501ac008e886eec1fd1932a34
  - actions/checkout@v4 -> 11bd71901bbe5b1630ceea73d27597364c9af683

Replaced files:
  - .github/workflows/test.yaml

実際に実行してみるとこんな感じですね。

--- a/.github/workflows/test.yaml        2025-03-18 11:41:16
+++ b/.github/workflows/test.yaml        2025-03-18 14:36:32
@@ -20,13 +20,13 @@
     runs-on: ubuntu-latest
     steps:
       - name: Set up Go
-        uses: actions/setup-go@v5
+        uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5
         with:
           go-version: ${{ matrix.go }}
         id: go
 
       - name: Check out code into the Go module directory
-        uses: actions/checkout@v4
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
 
       - name: Build & Test
         run: |

これで、一括で commit hash に変換できました。

余談&まとめ

そこで、誰かが作ってそうですがシュッと小物を作成しました。

x.com

ツール作成の告知に、類似ツールがあるそうですというご報告をいただきました。 ちょっとした作業を自動化するときに、100行くらいかーとすぐに書いてしまうのが、エンジニアの性なのかもしれませんね。
このようなツールはいくつかがあるようなので、今回を期にGitHub Actionsの外部Actionはcommit hashでピン留めすることをご検討ください。

カヤックでは、ちょっとしたモノを書くのが好きなエンジニアも募集しています!

【JS体操】応援ありがとうございました!〜全5問の振り返り〜

こんにちは!面白プロデュース事業部のおばらです。
本記事では JavaScript のコードゴルフ大会『JS体操』の全5問を、作問の裏話とあわせて振り返ってみよう思います!



目次


『JS体操とは』

『JS体操』とはカヤックが主催する JavaScript のコードゴルフ大会です。
もともとは社内の勉強会として始めた施策です。 その詳細は以下のブログ記事を御覧ください!

techblog.kayac.com




第1回「波形の整形」

【問題】https://hubspot.kayac.com/js-taiso-001
【解説】https://techblog.kayac.com/js-taiso-001-commentary-vol1


作問の裏話

記念すべき第1弾!

最初の問題を何にするか、とても迷いました。
運営チームでいくつか問題の候補を出して議論し、問題の意図が見た目にもわかりやすい&過去に似たような事例が少ないということで、グラフを描画する問題にしました。

グラフの形状はいろんなものを試しましたが、グラフの形が面白く、かつコードゴルフのしがいがあるもの、という観点でセレクトしました。


最短文字数の回答

なんと44文字まで縮められます!

export default x=>x-(x%=.2)+.2-(.04-x*x)**.5

以下の5名の方がみごと達成されました!

  • halwhite さん
  • koyama41 さん
  • sugyan さん
  • tkihira さん
  • たつけん さん


面白いコード

ここで tkihira さんのとても面白いアプローチの回答をご紹介します。

let r=0;export default x=>r+=x%.2/(1-(5*x%1)**2)**.5/2e5

どういうロジックか、わかりますか?
円の式を微分して、、、微小なΔx分を足していって、、、
こんなアプローチは全く思いつきませんでした。あっぱれです。
赤い点線からちょっとズレているのが御愛嬌ですね!

王道の回答以外にもいろいろ楽しんでいただけるのは出題者としても嬉しいです!




第2問

【問題】https://hubspot.kayac.com/js-taiso-002
【解説①】https://techblog.kayac.com/js-taiso-002-commentary-vol1
【解説②】https://techblog.kayac.com/js-taiso-002-commentary-vol2


作問の裏話

もともとは「縦横比」のような概念、無次元の概念を導入するとロジックをシンプルにできる!という社内勉強会用のデモでしたが、そこからとんでもないハックが可能な賛否両論の問題になってしまいました。


最短文字数の回答

真面目なアプローチだと66文字!

export default(a,b,f=e=>e.naturalWidth/e.naturalHeight)=>f(a)-f(b)

以下の2名のみなさん、CONGRATULATIONS♪

  • 🥇 ぺち さん
  • 🥇 halwhite さん

デフォルト引数の仕組みを利用するのがポイントですね!


鬼コード

export default()=>9e9<<length+++9

ハック部門では上記コードも想定していましたが、ちょっとやりすぎました。反省。。




第3問

【問題】https://hubspot.kayac.com/js-taiso-003
【ヒント①】https://techblog.kayac.com/generating-zalgo-text 【ヒント②】https://techblog.kayac.com/unicode-code-point-vs-code-unit 【ヒント③】https://techblog.kayac.com/12-ways-to-convert-sparse-array-to-dense-array-on-the-fly 【ヒント④】https://techblog.kayac.com/22-ways-to-generate-strings-from-code-points 【解説①】https://techblog.kayac.com/js-taiso-003-extension-match-announcement
【解説②】https://techblog.kayac.com/js-taiso-003-commentary-vol1


作問の裏話

Unicode について調べているときに思いついた問題です。こういうテキストを Zalgo Text と呼ぶこともこのとき初めて知りました。


最短文字数の回答

3連覇の halwhite さんのおかげで以下まで短くできることが判明しました!

export default(s,r=Math.random)=>s.replace(/./g,c=>(s=n=>~--n?s(n)+String.fromCharCode(768+r()*112):c)(r()*8))


面白いコード

export default s=>s.replace(/./g,c=>c+eval(`''`+`+eval('"\\\\'+'u{'+(768+s()*112|0).toString(16)+'}"')`.repeat(1+(s=Math.random)()*8)))

社内の QA で生まれた、eval() を2重に使うトンデモ激重コードです。そして文字数はむしろ長くなってますね。テストに本当にものすごく時間がかかるのでお試しいただく際は要注意。




第4問

【問題】https://hubspot.kayac.com/js-taiso-004
【解説】https://techblog.kayac.com/js-taiso-004-commentary


作問の裏話

社内では、

  • 安定ソート版
  • 安定じゃないソート版

の2種類のセットで出した問題でした。
それぞれでロジックも変わってくるので面白いです。もし興味のある方はぜひお試しあれ。


最短文字数の回答

1位は ksk1015 さんの109文字でした!予想外のロジック、さすが過ぎます。

export default s=>'くしつのへいうこてとひめりるろんあえかけさすせそちにみもやゆよられわおきたぬねはふまむをなほ'.replace(/./g,c=>[...s.matchAll(c)].join``)




第5問

【問題】https://hubspot.kayac.com/js-taiso-005
【解説】https://techblog.kayac.com/js-taiso-005-commentary


作問の裏話

社内向けのバージョンでは、フリー素材と化している弊社 CBO の写真を AA にする問題でした。


Zalgo Text と AA を組み合わせる案なんてのもありました。薄いピクセルはダイアクリティカルマークを少なく、濃いピクセルはダイアクリティカルマークを多くする、という具合です。



その後、YAPC:Hakodate 2024 開催にあわせた問題にすることが決まり、

  • 北海道の地図
  • 北海道の特産物の写真
  • 「北海道」という漢字

などいろいろ考えた結果 YAPC とカヤックのロゴでいくことにしました。


最短文字数の回答

export default(t,W=128,c=new OffscreenCanvas(W,W).getContext`2d`)=>c.getImageData(~~c.drawImage(t,0,0,W,64),0,W,64).data.reduce((a,p,i)=>a+=i%4?~i%512?'':`
`:'#`'[p>>7],'')


面白い回答

いろいろ遊べるようにあえて非同期の処理も可能にしていたのですが、さすが halwhite さん、見逃しませんね笑
とてもスマートな回答です!

export default(b,t=document.createElement`canvas`.getContext`2d`)=>fetch(`test-cases/${t.drawImage(b,0,0),t.getImageData(8,32,1,1).data[0]?'kaya':'yap'}c.txt`).then(r=>r.text()




おまけ

ついでに『JS体操』マスコットキャラクターたちの紹介もしておきます!
お察しの通り、JavaScript で使用する演算子・記号類をキャラクター化したもの。跳び箱などの小物も実は作ってました。笑
3Dモデルは Blender で作成しています!




まとめ

さて、第1問〜第5問までを振り返ってみましたがいかがだったでしょうか?これで『JS体操』の施策は一旦区切りとなります。 問題を作るにあたって JavaScript の言語仕様を学び直したことで私自身とても勉強になりました。オライリーのサイ本第7版を読みながら、あ!これは問題にできそう、みたいなこともありました。業務でハマった経験を問題にすることもありました。そしてなにより挑戦者のみなさんが予想もしていなかったアプローチの回答で想定文字数を超えてくださるのがとても楽しく嬉しかったです。
最近では生の JavaScript を書く機会、細かいロジックを考える機会もなかなか減っているかもしれませんが、こういった形でコードゴルフという形で楽しむのも良いかもしれません。

『JS体操』は一旦終わりですが、社内勉強会用に作った問題は60問以上あるので、いつかまた再開するかもしれません。 なお、過去の問題に関してはいつでも挑戦可能ですので、まだやっていなかったという方は以下よりぜひ!

サポートいただいたたくさんの皆様ありがとうございました!
それではまた!!

hubspot.kayac.com