TL;DR shogo82148/actions-setup-mysql には「GitHub Actionsのコード」と「MySQLをビルドするためのスクリプト群」が一緒に入っていたのですが、 このたび「MySQLをビルドするためのスクリプト群」を以下のレポジトリーに移行することにしました。
shogo82148/build-mysql ユーザー側での対応は不要です。
背景・目的 shogo82148/actions-setup-mysql のビルド済みMySQLバイナリー置き場には紆余曲折ありました。 以下のブログ記事はPerlのものですが、MySQLも同じような道筋を辿っています。
Setup Perl GitHub Action を公開しました Setup Perl Environment Action のストレージを Azure Blob Storage に移行しました 紆余曲折あり最終的には GitHub Releases に保存することにしました。 GitHubネイティブの機能で安心感があるのと、なんたって無料なのが魅力的ですね。
v1.45.0 をリリースしたら、 v1.45.0の関連アセットに必要なバイナリーを全部突っ込む、という作戦で運用を続けてきました。 しかし、この方法では以下のような問題がありました。
リリースのたびにすべてのプラットフォームのビルドをし直さなければならない ひとつのリリースに含める事のできるアセットの上限 1000 が見えてきた というわけで、「MySQLをビルドするためのスクリプト群」を別レポジトリーに移行し、 shogo82148/actions-setup-mysql 自体のリリースサイクルとは別に管理するようにしました。
移行作業 shogo82148/build-mysql のセットアップ 「MySQLをビルドするための秘伝のスクリプト群」はすでに手元にあるので、スクリプト群をコピーするたけです。 完成したバイナリーは gh コマンドでアップロードします。
同じMySQLバージョンの再ビルドを行いたい(たとえば、将来リリースされるであろうubuntu-26.04版ビルドの追加とか)ケースも考えて、リリース名に mysql-8.4.6-20251026153058 のようにリリースした日付を入れておきます。 これは、変更不可リリースを有効化しており、過去のリリースを直接書き換えることができないためです。
shogo82148/actions-setup-mysql のダウンロードURL書き換え 毎回 shogo82148/build-mysql のリリースを検索するのも大変なので、 shogo82148/build-mysql の全リリースを gh api --paginate --slurp '/repos/shogo82148/build-mysql/releases?per_page=100' コマンドで取得し、整形したものをソースコードに埋め込んでいます。
[ { "arch": "arm64", "distribution": "mysql", "os": "darwin", "sha256": "874d49f26f0bcb1cdd186bf768d863cb1da227091609e5873e25255f19e46753", "url": "https://github.
背景・目的 弊社では依存性注入(DI)に google/wire を使用しています。 しかし、一部 Gopher 界隈で話題となったように 2025年8月25日 google/wire はアーカイブされてしまいました!
google/wire がアーカイブされたけどどうすればいいの? しばらく静観してきたのですが、そうも言ってられなくなったので移行先を考えることにしました。 軽く調べた感じでは uber-go/dig が依存関係も少なく、導入も楽そうです。 しかし google/wire でできたことが uber-go/dig に移行した途端できなくなっては困ります。
検証 そこで、弊社が google/wire で使っている機能が uber-go/dig でも実現できるのか、調査してみました。
依存関係の事前チェック 個人的に一番欲しいのが依存関係の事前チェックです。
たとえばプロバイダーの不足はよくあるミスだと思います。 google/wire は事前にコード生成を行うため、このようなミスに気が付きやすいです。 しかし uber-go/dig では実行時までエラーに気がつけません。
package main import ( "github.com/k0kubun/pp" "go.uber.org/dig" ) type foo struct { } func main() { c := dig.New() // foo のプロバイダーが登録されていない!!! if err := c.Invoke(func(foo *foo) { pp.Println(foo) }); err != nil { panic(err) // panic: missing dependencies for function "main".
背景・目的 ULIDを使っているプロジェクトを見かけました。 Go言語のULID実装は oklog/ulid が有名です。 見かけたプロジェクトでも oklog/ulid を利用していました。
しかし最新版 oklog/ulid v2.1.1 のソースコードを読んでみると色々と気になる実装があります。
まずはデフォルトのエントロピー源が math/rand であること。 math/rand は暗号論的に安全な乱数ではありません。 過去の採番履歴から、次に採番されるIDが予測されてしまう可能性があります。
さらに疑似乱数のSeedに現在時刻(time.Now().UnixNano())を使用している点。 1秒って10億ナノ秒しかないので、たとえば1秒間に約3.7万プロセスが一斉に起動するような大規模システムの場合、誕生日のパラドックス から50%の確率でSeedが衝突します。 意外と衝突確率高いと思いませんか? Seedが衝突したということは生成される乱数列も同じなので、ULIDが衝突する確率も高くなります。
最後に、Base32に含まれていない文字が入力された場合、Parse 関数はエラーを報告しないという点。 この場合どのようなULIDが返却されるかは未定義です。
Parse parses an encoded ULID, returning an error in case of failure. ErrDataSize is returned if the len(ulid) is different from an encoded ULID’s length. Invalid encodings produce undefined ULIDs. For a version that returns an error instead, see ParseStrict.
from https://pkg.go.dev/github.com/oklog/ulid/v2@v2.1.1#Parse
外部からの入力を受け付けるには心もとない挙動です。
実装 これらの点が気になったので、車輪の再発明ですが、自分でULIDの実装をしてみることにしました。
こんな罠に引っかかるのは僕だけだと思うんですが、一応記録として残しておきます・・・。
TL;DR 2025-08-09あたりから、GitHubがJWTのb64ヘッダーパラメーターを認識するようになった 具体的にはJWTのヘッダーに {"b64": false} が含まれている場合に、“A JSON web token could not be decoded, documentation_url: https://docs.github.com/rest" というエラーメッセージが返ってくる 原因 GitHub Appsにアクセスするのに、お勉強も兼ねて自前実装のJWTエンコーダーを使っていました。
https://github.com/shogo82148/goat JWSのペイロードは普通base64エンコードされていますが、base64エンコードをスキップする拡張が提案されています。
RFC 7797: JSON Web Signature (JWS) Unencoded Payload Option もちろん時前実装のJWTエンコーダーでも対応しました。
しかし、そこにバグがあったのです! payloadをbase64エンコードしているのにもかかわらず、{"b64": false} が設定された状態になっていました。
JWTのヘッダーの中身:
{ "cty": "JWT", "alg": "RS256", "b64": false } 実際のペイロードの内容と、ヘッダーの情報が食い違っており、要するにもとから壊れたJWTを送っていたのです。 今まではたまたまGitHubが受け入れてくれる状態でした。
GitHub 側の改修 おそらく b64 ヘッダーパラメーターをチェックするようになったのだと思います。 この改修により、今までは許容されていた {"b64": false} 付きのJWTが使えなくなりました。
対応 そもそも {"b64": false} のJWTは使用してはならない (MUST NOT) とRFC 7797 Section 7で明記されています。
For interoperability reasons, JSON Web Tokens [JWT] MUST NOT use “b64” with a “false” value.
TL;DR Goは x*y + z を math.FMA(x, y, z) にコンパイルする場合がある 再現性のある実行結果を得たい場合は float64(x*y) + z と書くか、明示的に math.FMA(x, y, z) を呼び出す 再現性は求めずに速度を出したい場合は x*y + z と書く FMAのバグ発生条件の謎 先日Goに math.FMA のバグ修正のパッチを送りました。
Goのmath.FMAの挙動を修正した ありがたいことにスッとマージしてもらえたのですが、実は発生条件にちょっと謎がありました。
検証の結果こんな感じです。
arm64のFMA命令: -0
arm64のmath.FMA: -0
x86_64のFMA命令: -0
x86_64のmath.FMA: 0
Pure Goで書かれた math.FMA の実行結果が変わるのが謎なんですよね 🤔
— f96fd3a0-bdb9-4f10-b69f-8f765c1d341c ICHINOSEShogo (@shogo82148) May 18, 2025 問題となったのは以下のコードです。
package main import ( "fmt" "math" ) var portableFMA = math.FMA func main() { fmt.Println(math.FMA(0x1p-1022, -0x1p-1022, 0)) fmt.Println(portableFMA(0x1p-1022, -0x1p-1022, 0)) } go version go1.
Goのコントリビューターになったぞ!
673856: math: fix portable FMA implementation when xy ~ 0, xy < 0 and z = 0 どんなバグがあって、どう修正したかを記録として残しておきます。
バグの内容 以下のコードを実行すると期待と異なる結果が返ってくる、というものです。
https://go.dev/play/p/DgFhrLf1CuF package main import ( "fmt" "math" ) var portableFMA = math.FMA func main() { fmt.Println(math.FMA(0x1p-1022, -0x1p-1022, 0)) fmt.Println(portableFMA(0x1p-1022, -0x1p-1022, 0)) } go version go1.24.3 linux/amd64 で実行すると、以下のような結果になります。
実際の出力:
-0 0 呼び出し方が違うだけで同じ関数を呼び出しているので、同じ結果が返ってきてほしいところです。
期待される出力:
-0 -0 そもそもFMAって何をする関数? そもそもFMAが何をする関数かというと、融合積和演算(Fused Multiply-Add, FMA) を計算する関数です。 $\mathrm{FMA}(x, y, z) = x \times y + z$ を高い精度で計算してくれます。
Akamai とユニクロのコラボTシャツに新しいデザインが登場しました。
[プレスリリース] @UNIQLO_JP のチャリティTシャツプロジェクト「PEACE FOR ALL」に Akamai Tシャツ第2弾のデザインが加わります❤️ 6月20日(金)より世界各国で発売されます❤️今回のカラーはレトロホワイト❤️https://t.co/YsWPPmgkZS#AkamaiPeaceForAll #ユニクロ #アカマイ pic.twitter.com/FkH5PmXzJL
— アカマイ・テクノロジーズ (@akamai_jp) April 25, 2025 背中になにかコードのようなものが書いてあります。 これは解読せずにはいられない。
前回の解読記事はこちら:
RE: Akamai x UNIQLOコラボTシャツに書かれたプログラムを解読してみる 写経 頑張って写経しました・・・大変でした。 OCRの力もちょっと借りましたが、lと1、0とOをときどき間違える。 通常のOCRの用途ならそれでも十分かもしれませんが、今回は一箇所でもタイポすると動かなくなります。 最後に頼れるのはやはり人間の目でした。
#!/bin/bash eval "$(base64 -d <<< 'IyEvYmluL2Jhc2gKCiMgQ29uZ3Jhd HVsYXRpb25zISBZb3UgZm91bmQgdGhlIGVhc3RlciBlZ2chIOKdpO+4jwojIOOBiuO CgeOBp+OBqOOBhuOBlOOBluOBhOOBvuOBme+8gemaoOOBleOCjOOBn+OCteODl+OD qeOCpOOCuuOCkuimi+OBpOOBkeOBvuOBl+OBn++8geKdpO+4jwoKIyBEZWZpbmUgd GhlIHRleHQgdG8gYW5pbWF0ZQp0ZXh0PSLimaVQRUFDReKZpUZPUuKZpUFMTOKZpV BFQUNF4pmlRk9S4pmlQUxM4pmlUEVBQ0XimaVGT1LimaVBTEzimaVQRUFDReKZpUZ PUuKZpUFMTOKZpVBFQUNF4pmlRk9S4pmlQUxM4pmlIgoKIyBHZXQgdGVybWluYWwg ZGltZW5zaW9ucwpjb2xzPSQodHB1dCBjb2xzKQpsaW5lcz0kKHRwdXQgbGluZXMpC gojIENhbGN1bGF0ZSB0aGUgbGVuZ3RoIG9mIHRoZSB0ZXh0CnRleHRfbGVuZ3RoPS R7I3RleHR9CgojIEhpZGUgdGhlIGN1cnNvcgp0cHV0IGNpdmlzCgojIFRyYXAgQ1RS TCtDIHRvIHNob3cgdGhlIGN1cnNvciBiZWZvcmUgZXhpdGluZwp0cmFwICJ0cHV0I GNub3JtOyBleGl0IiBTSUdJTlQKCiMgU2V0IGZyZXF1ZW5jeSBzY2FsaW5nIGZhY3R vcgpmcmVxPTAuMgoKIyBJbmZpbml0ZSBsb29wIGZvciBjb250aW51b3VzIGFuaW1hd Glvbgpmb3IgKCggdD0wOyA7IHQrPTEgKSk7IGRvCiAgICAjIEV4dHJhY3Qgb25lIGN oYXJhY3RlciBhdCBhIHRpbWUKICAgIGNoYXI9IiR7dGV4dDp0ICUgdGV4dF9sZW5nd Gg6MX0iCiAgICAKICAgICMgQ2FsY3VsYXRlIHRoZSBhbmdsZSBpbiByYWRpYW5zCiA gICBhbmdsZT0kKGVjaG8gIigkdCkgKiAkZnJlcSIgfCBiYyAtbCkKCiAgICAjIENhb GN1bGF0ZSB0aGUgc2luZSBvZiB0aGUgYW5nbGUKICAgIHNpbmVfdmFsdWU9JChlY2 hvICJzKCRhbmdsZSkiIHwgYmMgLWwpCgogICAgIyBDYWxjdWxhdGUgeCBwb3NpdGl vbiB1c2luZyB0aGUgc2luZSB2YWx1ZQogICAgeD0kKGVjaG8gIigkY29scyAvIDIpIC sgKCRjb2xzIC8gNCkgKiAkc2luZV92YWx1ZSIgfCBiYyAtbCkKICAgIHg9JChwcmlu dGYgIiUuMGYiICIkeCIpCgogICAgIyBFbnN1cmUgeCBpcyB3aXRoaW4gdGVybWluY WwgYm91bmRzCiAgICBpZiAoKCB4IDwgMCApKTsgdGhlbiB4PTA7IGZpCiAgICBpZi AoKCB4ID49IGNvbHMgKSk7IHRoZW4geD0kKChjb2xzIC0gMSkpOyBmaQoKICAgICM gQ2FsY3VsYXRlIGNvbG9yIGdyYWRpZW50IGJldHdlZW4gMTIgKGN5YW4pIGFuZCAyM DggKG9yYW5nZSkKICAgIGNvbG9yX3N0YXJ0PTEyCiAgICBjb2xvcl9lbmQ9MjA4CiA gICBjb2xvcl9yYW5nZT0kKChjb2xvcl9lbmQgLSBjb2xvcl9zdGFydCkpCiAgICBjb 2xvcj0kKChjb2xvcl9zdGFydCArIChjb2xvcl9yYW5nZSAqIHQgLyBsaW5lcykgJSBj b2xvcl9yYW5nZSkpCgogICAgIyBQcmludCB0aGUgY2hhcmFjdGVyIHdpdGggMjU2L WNvbG9yIHN1cHBvcnQKICAgIGVjaG8gLW5lICJcMDMzWzM4OzU7JHtjb2xvcn1tIiQ odHB1dCBjdXAgJHQgJHgpIiRjaGFyXDAzM1swbSIKCiAgICAjIExpbmUgZmVlZCB0b yBtb3ZlIGRvd253YXJkCiAgICBlY2hvICIiCgpkb25lCgo= ')" PEACE FOR ALL 動かしてみる どうやらBashのコードのようですが、残念ながらそのままでは動きませんでした。 Tシャツにプリントするために適宜改行が入っているようです。 この改行を取り除くと動くようになります。
shogo82148/actions-setup-redis はRedisのバイナリーをGitHub Releasesからダウンロードしています。 このバイナリーをGitHub Artifact Attestationsで署名して、 ダウンロード時に検証するようにしました。
背景 今年3月に発生したGitHub Actionsのサプライチェーン攻撃を受けての対応です。
[Security Advisory] Supply Chain Attack on reviewdog GitHub Actions during a specific time period #2079 New GitHub Action supply chain attack: reviewdog/action-setup GitHub Actions Supply Chain Attack: A Targeted Attack on Coinbase Expanded to the Widespread tj-actions/changed-files Incident: Threat Assessment (Updated 4/2) tj-actions のインシデントレポートを読んだ 個人的にはreviewdog/action-setupをよく利用しているので、びっくりしました。 (インシデントレポートに自分のコミット載ってるし) さいわい侵害を受けたのが日本時間深夜ということもあり、被害を受けたレポジトリーは見つかりませんでした。
しかし、こういった攻撃が身近に迫っていることを、改めて感じた事件でした。 自分自身もいくつかGitHub Actionsを公開しているので、他人事ではありません。 少しでも安全に利用できるよう、何等かの対応をすることにしました。
対応 GitHub Actionsのピン留め 今回の侵害事件においてもっとも効果的なのはGitHub ActionsのSHA1ハッシュによりピン留めです。 他の方もたくさんブログを書いてくれているので、そちらをどうぞ。
GitHub Actionsの侵害・サプライチェーンリスクを軽減:pinactを使ってアクションをバージョンではなくハッシュ値で指定 GitHub Actionsの外部Actionのバージョンをhash指定にし、可読性を維持しつつバージョンを上げる GitHub Actionsの外部ActionでVersionTagを使ってるものを一括でCommitHashにしたい。 shogo82148/actions-setup-redis でも同様の対応を行いました。
shogo82148/go-header-csvのv0.1.0をリリースしました。
shogo82148/go-header-csv このライブラリについてブログで紹介していなかったので、shogo82148/go-header-csv の簡単な紹介と、v0.1.0での変更点についてお知らせします。
go-header-csvの紹介 令和の世になってもCSVを扱いたいという要望はなくなることはありません。 とくに一行目がフィールド名になっているCSVを扱うことが多いです。 具体的には以下のようなイメージです。
name,text Ed,Knock knock. Sam,Who's there? Ed,Go fmt. Sam,Go fmt who? Ed,Go fmt yourself! これを以下のような構造体に変換したい。
[]struct { Name string Text string }{ { Name: "Ed", Text: "Knock knock.", }, { Name: "Sam", Text: "Who's there?", }, { Name: "Ed", Text: "Go fmt.", }, { Name: "Sam", Text: "Go fmt who?", }, { Name: "Ed", Text: "Go fmt yourself!", }, } Go言語にもCSVを扱う標準パッケージはありますが、サポートしているのは [][]string への変換のみです。 一行目を特別扱いしてくれる機能はありません。
MeCabのPython BindingをPyPIに上げました。
mecab はじめてのPyPI公開なので、モジュールの紹介と、公開までに行った作業についてのメモを残しておきたいと思います。
使い方 pip install mecab もしくは
python -m pip install mecab でインストール可能です。 辞書は含まれていないので、別途インストールしてください。 たとえば ipadic であれば、
pip install ipadic でインストール可能です。 以下のように辞書の場所を指定すればすぐに使えます。
import MeCab import ipadic tagger = MeCab.Tagger(ipadic.MECAB_ARGS) print(tagger.parse("図書館にいた事がバレた")) mecab-python3 のドロップインリプレイスメントになるように作ったので、 pip install mecab-python3 の代わりに pip install mecab するだけで使えるはずです。
なぜ今更MeCabなのか KyTea, JUMAN++, Sudachi, SentencePiece 等の 後発の形態素解析エンジンも進んでおり、 MeCab は形態素解析エンジンとしては古株です。 しかしながら、使い勝手の良さや使用例の多さから今なお現役で利用されています。
たとえば、先日リリースされたASMR言葉は分からないが、やたら耳かきが上手い部族に捕まった。の制作には グロンギ語翻訳機が利用されています。翻訳機のバックエンドはMeCabです。
日本語とグロンギ語の相互翻訳やってみた MeCabをAWS Lambdaで動かす(2017年版) このように今現在も利用されるMeCabですが、2025年3月19日現在、オリジナルのMeCabの最終リリースは 2013-02-18 MeCab 0.996 です。 OSやコンパイラのアップデートへの追従、バグフィックス等のメンテナンス作業が完全に止まっています。
このままではマズいということで、勝手にフォークしてパッチを当てたものを作成しました。
shogo82148/mecab なぜ今更Python Bindingを公開するのか MeCabのPython Bindingには、すでにmecab-python3という素晴らしいモジュールがあります。 しかしオリジナルのMeCabに依存しているため、「本当にこのままメンテナンスを続けていけるか?」という点には疑問が残ります。