弊社では各種シークレットは1Passwordで管理しています。 シークレットの棚卸し作業をしていて不便を感じたので、 1Passwordで管理しているシークレットを各種サービスに同期するプログラムを書いてみました。
shogo82148/op-sync 背景 何が困るって、シークレットの出処がわからないこと。
たとえばCI/CDサービスのシークレット管理機能にシークレットが登録されている場合、 ヒントが FIREBASE_SECRET という名前だけ、ということがよくあります。 このヒントだけだと、Firebaseで使われていそうなのはわかる・・・でもFirebaseのプロジェクトたくさんあるんだよな、どれだろう・・・ってなります。 プロジェクト名やサービスアカウント名までわからないと、シークレットの出処を特定できません。
1Passwordにはシークレットの出処をメモとして残しておけるので、 せめて「このシークレットは、1Passwordのこの項目と対応しています」という情報が分かれば特定が簡単になります。
「シークレットと1Passwordの項目の対応付け」、ちょっとしたテキストを書くだけで十分なんですが、それができないのが人間というもの・・・。 そこでさらに推し進めて「シークレットと1Passwordの項目の対応付け」を機械可読な形式にして、「1Passwordの項目からシークレットの自動反映」を行います。 普段から自動反映する習慣をつけておけば、対応付けが漏れる心配はありません。
使い方 1Passwordとの連携には1Password CLIを使用しています。 あらかじめインストールしておいてください。
シークレットをファイルに書き出す Private Vaultに入っている、Testという名前のアイテムを読み出す設定例です。
# .op-sync.yml secrets: MyPassword: type: template output: .envrc template: | MY_PASSWORD={{ op://Private/Test/password }} 1Password CLIでサインインして、 op-sync コマンドを叩けば 1Password からパスワードを引っ張ってきてファイルに書き出してくれます。
$ eval $(op signin) Enter the password for shogo82148@gmail.com at my.1password.com: $ op-sync 2023/10/21 16:58:32 INFO 1password user information url=https://my.1password.com email=shogo82148@gmail.com The following changes will be applied: file ".
半精度浮動小数点数をあつかうGoのライブラリを書いてみました。
shogo82148/float16 背景 なぜ書いたかというと、半精度浮動小数点数について勉強するためです。
最近のAIブームでビット数の少ない浮動小数点数が注目されていて興味を持ったため 最近の研究で、有効桁数はそこまで重要でないことがわかってきた パラメーターの数が膨大なので、少しでもモデルを圧縮したい CBORの実装読んでいたら、仕様の一部に半精度浮動小数点数が出てきたため 使い方 FromFloat64で倍精度浮動小数点型から半精度浮動小数点数へ変換できます。
import "github.com/shogo82148/float16" func main() { a := float16.FromFloat64(1.0) fmt.Printf("%04x", a.Bits()) } Float16.Bitsで内部表現を取得できるので、 この結果をシリアライズに使うのが主な使い方になると思います。
一応四則演算も実装してあります。
import "github.com/shogo82148/float16" func main() { a := float16.FromFloat64(1.0) b := float16.FromFloat64(2.0) fmt.Printf("%f + %f = %f", a.Add(b)) fmt.Printf("%f - %f = %f", a.Sub(b)) fmt.Printf("%f * %f = %f", a.Mul(b)) fmt.Printf("%f / %f = %f", a.Div(b)) } ただし(自分で書いておいてなんですが)あまり実用性はないです。 というのも半精度浮動小数点数同士の演算結果は float64 型で正確に表現できます。 そのため float64 型で計算したあと半精度浮動小数点数に戻せば、まったく同じ計算ができます。
import "github.com/shogo82148/float16" func main() { a := float16.
GitHub ActionsからSlackへ通知したいとき、一番お手軽なのはSlack Incoming Webhookです。 直接curlで叩いてもいいですし、マーケットプレイスにも通知用のアクションがたくさんあります。
しかし、Incoming Webhookは一般公開してはいけないシークレットです。 迂闊にレポジトリにコミットしてはいけません。 GitHub Actions Secrets へ突っ込む等して、適切に管理する必要があります。 一個や二個ならまだしも、いくつもレポジトリがあると管理が大変です。
そういうわけで、OIDCを使ってSlackへの通知を行うアクションを書きました。
actions-notify-slack 使い方 gha-notify.shogo82148.com へアクセスします。 「Add to Slack」をクリックして、アプリをSlackにインストールします。 @actions-notify-slack というボットが追加されるので、こいつを通知を流したいチャンネルに招待します。 投稿先のチャンネルで /gha-notify allow ORG/REPO スラッシュコマンドを実行します。これにより ORG/REPO からの投稿が許可されます。 ワークフローにアクションを追加して完成! - uses: shogo82148/actions-notify-slack@v0 with: team-id: T3G1HAY66 # 自分のチームIDに置き換え channel-id: C3GMGG162 # 自分のチャンネルIDに置き換え payload: '{"text": "hello world"}' 仕組み 早い話が、過去 GitHub や AWS 向けに作ったアクションを Slack 向けに焼き直したものです。
actions-github-app-tokenの紹介 AWS_SECRET_ACCESS_KEY を GitHub Actions secrets へ突っ込むのに疲れた俺達は GitHub Actions は直接 Slack とやり取りするかわりに、中継サーバーにリクエストを投げます。 中継サーバーは、OIDC ID Tokenを検証し、Slackへの投稿権限をチェックします。 権限を確認できたら、ボットユーザーとして投稿する、という流れです。
GitHub App Tokenを発行するための actions-github-app-token という GitHub アクションを書きました。
実験的なアクションだったので、マーケットには公開していませんでした。 最近になって「安定して動作しているし、マーケットに公開するか!」という気持ちになったので、 改めてご紹介です。
背景 GitHub Actionsのワークフローから、GitHub APIを叩きたいこと、よくありますよね?
GITHUB_TOKEN そんなとき第一候補に挙がるのは secrets.GITHUB_TOKEN です。
Automatic token authentication 特段複雑な設定をせずとも使えるのでお手軽です。 しかし、 secrets.GITHUB_TOKEN には大きな制限があります。 それは「他のGitHub Actions Workflowを起動できない」ということ。 これは無限ループで大量のジョブが投入されるのを防ぐための制限です。 理由もはっきりしていて妥当な制限だとは思うのですが、 必要なワークフローが起動しなくて困ることがときどきあります。
PAT (Personal Access Token) (Classic) 「他のGitHub Actions Workflowを起動できない」制限を回避する簡単な方法は、 Personal Access Token を使うことです。 このトークンにはこの制限はありません。
ただし、トークンを発行したユーザーの権限でAPIを叩くので、権限の範囲が広すぎる、という問題があります。 実行できるアクションは制限できるのですが、レポジトリの範囲までは調整できません。
また、トークンは「ユーザー」に紐づきます。 個人のレポジトリならまだいいんですが、Organization管理のレポジトリ困ることがあります。 一番のあるあるは「トークンを発行したユーザーがOrganizationを抜けるとワークフローが止まる」ですかね。 属人化が進み、健全とは言い難い状態です。
fine-grained personal access tokens 「権限の範囲が広すぎる」問題を解決するのが fine-grained personal access tokens です。 レポジトリ単位でアクセス権を設定できます。
しかし、権限の広さは解決しますが、「トークンがユーザーに紐づいていることの弊害」は解消しません。
また、fine-grained personal access tokensは有効期限の設定が必須です。 管理するレポジトリの数が多いと、トークン更新行脚をする必要があります。
GitHub Apps ここで本命、 GitHub Apps の出番です。
これまで何度か HTTP Server の Graceful Shutdown について記事を書きました。
Go 言語で Graceful Restart をする Go 言語で Graceful Restart をするときに取りこぼしを少なくする Go1.8 の Graceful Shutdown と go-gracedown の対応 最終的に Go 1.8 で Server.Shutdown が導入され、この件は解決を見ました。 しかし、最近「あれ?本当に正しく Server.Shutdown 使えている?」と疑問に思い、少し考えてみました。 というか ↑ の記事もまだ考慮が足りない気がする。
ぼくのかんがえたさいきょうの Go HTTP サーバー起動方法 とりあえず完成形のコード。
package main import ( "context" "log" "net/http" "os" "os/signal" "syscall" "time" ) func main() { // シグナルを待ち受ける chSignal := make(chan os.Signal, 1) signal.Notify(chSignal, syscall.SIGINT, syscall.SIGTERM) defer signal.Stop(chSignal) // 起動したいサーバーを準備 mux := http.
深遠な理由で、ソースコードからコメントをすべて抹消したくなったことはありませんか?
そんなときに使えるツールを作りました。
shogo82148/go-comment-eraser Go製コマンドなので、 go install でインストール。
go install github.com/shogo82148/go-comment-eraser@latest ソースコードのおいてあるディレクトリを指定すると、 そのディレクトリ以下の *.go からすべてコメントを削除します。
go-comment-eraser ソースコードのあるディレクトリ 実際に shogo82148/go-comment-eraser 自身のソースコードで試した結果がこちら。
diff --git a/main.go b/main.go index 5087d08..913debc 100644 --- a/main.go +++ b/main.go @@ -65,22 +65,18 @@ func eraseComment(src string) error { return nil } -// parseFile parses the Go source code file and returns the Go source -// that is modified to erase all comments. func parseFile(src string) ([]byte, error) { - // Parse the Go source code file + fset := token.
ChooseALicense.com の日本語訳を公開しました。
choosealicense.shogo82148.com 背景 いつの間にか「オープンソースライセンスを適切に管理する係」になってしまい、 最近はライセンス文章とにらめっこする毎日のいっちーです。
そんな中お世話になったのがChooseALicense.comの付録です。 ライセンスの概要が大まかにわかります。 まあ、最終的には原文を読まないといけないわけですが、読む手がかりにはなります。
母国語が日本語の僕にとって、毎回英語読むのはきつい・・・日本語版欲しいな・・・ってことで作りました。
ツール 今回お世話になったツールたちです。
GitHub Pages BudouX GitHub Pages ChooseALicense.com は GitHub Pages でホストされています。 自然とchoosealicense.shogo82148.comのホスト先もGitHub Pagesになりました。
GitHub Pages自体はこのブログでもお世話になっている機能です。 今回個人的に初挑戦だったのは、独自ドメインの割り当てでした。 ChooseALicense.comのコードがカスタムドメインでの提供前提で組まれており、サブディレクトリでの提供では表示が崩れてしまうからです。
とは言ってもドキュメントにしたがい、GitHub側の設定を済ませたあと、自分のドメインにCNAMEレコードを挿入するだけでした。
Managing a custom domain for your GitHub Pages site お手軽なので、今後なにかに使えるかもしれないですね。
BudouX タイトルの「Choose an open source license」は「オープンソースライセンスを選ぼう」と翻訳しました。 が、これをそのまま表示すると、こうなります。
オープンソースライセンスを選ぼ う 「う」の位置がなんか気に食わない・・・。 この問題の解決のため、BudouXを利用しました。 自動でいい感じの改行位置を決めてくれます。
オープンソースライセンスを 選ぼう まとめ ChooseALicense.com の日本語訳を公開しました。
choosealicense.shogo82148.com 参考 ChooseALicense.com choosealicense.shogo82148.com オープンソースライセンスの日本語参考訳 Managing a custom domain for your GitHub Pages site GitHub Pages BudouX
2022 年 11 月から ECDSA(楕円曲線デジタル署名アルゴリズム)に対応しています。
AWS Certificate Manager が楕円曲線デジタル署名アルゴリズム TLS 証明書のサポートを開始 しかし、
CloudFormation のサポートは近日中に提供が開始されます。
と書いてあるように、CloudFormation からの利用はできませんでした。
今日試してみたら、行けたっぽい(?)ので、設定方法のメモです。
設定方法 KeyAlgorithm に EC_prime256v1 もしくは EC_secp384r1 を指定します。
AWSTemplateFormatVersion: "2010-09-09" Resources: Certificate: Type: AWS::CertificateManager::Certificate Properties: DomainName: shogo82148.com ValidationMethod: DNS DomainValidationOptions: - DomainName: shogo82148.com HostedZoneId: Z1TR8BQNS8S1I7 KeyAlgorithm: EC_prime256v1 注意 ふと、AWS::CertificateManager::Certificate リソースのドキュメントを読んでいたら KeyAlgorithm という属性を見つけたので試してみました。 しかし、2023-09-14 現在説明文は
Property description not available.
の一文のみ。 リリースの案内も見つけられなかったので、心配な人は正式リリースの案内を待ちましょう。
基本的に CloudFormation のプロパティーはサービスの API と同じ名前です。 今回試してみた EC_prime256v1 という値も、ACM の API リファレンスの KeyAlgorithm を参照しました。
ACM API Reference: RequestCertificate KeyAlgorithm 参考 AWS Certificate Manager が楕円曲線デジタル署名アルゴリズム TLS 証明書のサポートを開始 ACM API Reference: RequestCertificate KeyAlgorithm AWS::CertificateManager::Certificate: KeyAlgorithm
長らく構造化ログの仕組みが標準ライブラリになかったGoですが、 Go 1.21がリリースされて晴れて log/slog が使えるようになりました。 弊社ではlogrusを使っているので、log/slogを連携するためのフックを書きました。
背景 弊社ではlogrusをメインに使っています。 特段困ったこともなく 素晴らしいライブラリだと思います!!!(大事) 強いて問題点を上げるとすれば、メンテナンスモードに入ってしまってあまり開発が活発でない、ということでしょうか。 重大なバグがあれば別ですが、新規機能の追加等は行わない方針のようです。
一方 log/slog は公式ライブラリなので、log/slogの仕様を前提としたエコシステムが、今後発展してくでしょう。
logrusを使いながらlog/slogのいいとこ取りとする方法はないか?と考えた結果作ったのが shogo82148/logrus-slog-hook です。
SYNOPSIS sloghook.New で作成したフックを差し込むだけです。 logrusに流したログがlog/slogの設定で流れてきます。
package main import ( "io" "log/slog" "os" sloghook "github.com/shogo82148/logrus-slog-hook" "github.com/sirupsen/logrus" ) func main() { h := slog.NewTextHandler(os.Stderr, nil) logrus.AddHook(sloghook.New(h)) // logrus も logrus-slog-hook もSTDERRに書き込むので、同じログが二回表示されてしまう。 // logrus側を止めて防止。 logrus.SetFormatter(sloghook.NewFormatter()) logrus.SetOutput(io.Discard) logrus.WithFields(logrus.Fields{ "name": "joe", "age": 42, }).Error("Hello world!") // Output: // time=2023-09-10T23:32:41.229+09:00 level=ERROR msg="Hello world!" age=42 name=joe } 注意点 logrusはエラーレベルが Trace, Debug, Info, Warn, Error, Panic, Fatal と7段階ありますが、 log/slogには Debug, Info, Warn, Error しかありません。 しかし実は整数をレベルを設定できるので、適当に割り当てました。
先日 actions/checkout@v4 がリリースされましたね。
actions/checkout@v4 まあ、何が言いたいかというと、「メジャーバージョンアップ多すぎじゃない???」という話。
actions/checkout@v4の襲撃 新規に作成したレポジトリには基本的にdependabotをセットアップしています。 まあそんな状況下で actions/checkout@v4 なんてリリースされたら、こうなるわけですよ。
actions/checkout のアップデートつらい pic.twitter.com/4bNeCFsE4Y
— f96fd3a0-bdb9-4f10-b69f-8f765c1d341c ICHINOSEShogo (@shogo82148) September 5, 2023 よほど単純なワークフローでない限り、 actions/checkout は必須のアクションです。 GitHub Actions でCIを組んでいるレポジトリはもれなく使っています。 @shogo82148以下にあるレポジトリだけで、76個のプルリクエストが来ました。 心を無にしてマージボタンを押しまくりました。 他のorgにも参加しているので、実際に対応したプルリクエストはもっと多いです。
Node.js 16 のEOLが近い 背景には Node.js 16 が9月11日にEOLになるという話があります。 actions/checkout@v3 は Node.js 16 で動くので、当然サポート対象外になります。 そこで新しいバージョンが必要なわけです。
actions/checkout@v4 は Node.js 20 で動くようになりました。 GitHub Actions はセフルホストできるので、まだ Node.js 20 が動かない環境も残っています。 そのような環境でオプトインできるよう、メジャーバージョンアップにしたのだと思います。
Node.js 18 がスキップされた話 ちなみに Node.js 16 と Node.js 20 の間には Node.js 18 が存在するわけですが、 Node.js 18 はスキップされました。 (Node.