CircleCIのGitHub連携でPermission denied (publickey)が起きたときの対処

CircleCI を使った GitHub リポジトリの CI で、ある日突然以下のようなエラーが起きるようになりました。

現象

CircleCI のログを見たところ、GitHub からソースコードをチェックアウトする際に、以下のようなエラーになっていました。

if [ "$existing_repo" = 'true' ] || [ 'false' = 'true' ]; then
  echo 'Fetching from remote repository'
  if [ -n "$CIRCLE_TAG" ]; then
    git fetch --force --tags origin
  else
    git fetch --force origin +refs/heads/master:refs/remotes/origin/master
  fi
fi

if [ -n "$CIRCLE_TAG" ]; then
  echo 'Checking out tag'
  git checkout --force "$CIRCLE_TAG"
  git reset --hard "$CIRCLE_SHA1"
else
  echo 'Checking out branch'
  git checkout --force -B "$CIRCLE_BRANCH" "$CIRCLE_SHA1"
  git --no-pager log --no-color -n 1 --format='HEAD is now at %h %s'
fi

Using SSH Config Dir '/home/circleci/.ssh'
git version 2.35.1
Cloning git repository
Cloning into '.'...
Warning: Permanently added the ECDSA host key for IP address '140.82.112.3' to the list of known hosts.
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

exit status 128
CircleCI received exit code 128

https://app.circleci.com/pipelines/github/rubocop/rubocop-performance/811/workflows/536d4094-27ac-4714-9686-0c63887fdf50/jobs/5386

原因

GitHub 上の設定を見たところ、なぜか Deploy Keys が空になっていました。

対処方法

CircleCI 側のプロジェクト設定を「Project Settings」で開きます。

SSH Keys」を開いて、 (連携できていない) 既存の Deploy Key を削除します。

"Add Deploy Key" を押して SSH Key を追加します。

GitHub 側にも Deploy Keys への設定がされますので、ソースコードのチェックアウト可能になっていると思います。CircleCI のテストを Re-run してみましょう。

この問題が起きるようになった原因はわかりませんが、不特定のリポジトリで起きているようです。

現象に遭遇したとき参考までにどうぞ。

RubyKaigi 2022 に登壇した

RubyKaigi 2022 に登壇した。

rubykaigi.org

当日の発表スライドは以下です。

今回はリアルタイムでのリモート登壇でした。

本編

概ねサーバーモードなしの RuboCop のブートと、サーバーモードありの RuboCop のブートの違いと中身の概略について話せたかと思います。

今回話した高速化は、rubocop のブートに関わるモジュールローディング部分であり、解析自体が速くなったわけではないですが、起動時間の高速化ということで繰り返し起動することの多いツール特性に対しては有用な高速化だったかなと思います。

ふつうに使っている分には rubocop --server としてオプションありで使って問題ないと思いますが、RuboCop Performance や RuboCop Rails といったサードパーティー gem への bundle update があると、現状ではそれらを検知できないので rubocop --restart-server が必要になります (RuboCop 本体のアップデートは検知して、自動再起動するようにしています) 。Spring のように起動しているとハマったときに面倒みたいなことを減らせるよう、このあたりは早めに対応しようかなという気持ち。

ちなみに .rubocop.yml の構成を変えた場合は rubocop --restart-server は不要です。これは現状だとサーバー側で実行のたび設定読み込まれ、構成変更が都度反映されるためです。ただ、これは予期せず実装がそうなっていたというもので (!) 、将来的にこのあたりへのキャッシュ導入 (と変更検知導入) とのベンチマーク次第で少し動きが変わるかもしれません。

サーバーモードの実装で一番どうするか悩んだのはコマンドラインインタフェースをどうするかでした。そのあたりの話はコードとしては残っていませんが、決定を下した経緯として話しておこうと思って私の頭の中にしか残っていないことと、プルリクエストで行った議論をベースにしてコンテンツに含んでおきました。完全にうなすけくんの言ってくれているこれ。

また、本編で話していないプロセスの基礎的な話は『なるほどUnixプロセス ― Rubyで学ぶUnixの基礎』がおすすめなので、参考図書として記しておきます。

tatsu-zine.com

サーバーモードについては公式ドキュメントにも記載していますので、どうぞお試しください。

docs.rubocop.org

(おまけ) 放送事故

バーチャル会場の音声をつけっぱなし (というのにあとで気づいた) のままヘッドホンをしていたので、話すのに集中するためヘッドホンを外したら同期されていたらしいマイクも切れて、無音放送になるという放送事故の登壇実績を解除してしまいました。読唇術の技術を求めてしまってすみません。

タイムキープ用に手元に置いていたスマホに、勤務先の事業部長の @m_pixy から電話があって気づきました。おかげで本題では音声復旧できました (無音になった導入部分は時間の都合であきらめて先に進みました) 。音声トラブルで電話をくれた @m_pixy は m_pix "y" だったので、まさか matz のキーノートが自分にとってこういった伏線になるとは。@m_pixy ends with "y".

放送事故中、メンションしてくれた方々ありがとうございました。のちのリアルタイムリモートスピーカーに伝えられる教訓としては、ヘッドホン、イヤホンを外すときは連動してマイクオフにならないか気をつけましょう (気を付けます) 。

最後に、RubyKaigi チームのみなさん、通訳のみなさんありがとうございました。また、@yahonda さんに、昨年に引き続き事前に英文や構成レビューをしていただきました。いつもありがとうございます。

そして、miwa さんのツイートによると、だいたい満席だったようでありがとうございました!RubyKaigi はドラマがあって良いですね。

2022年9月12日(月) 追記

同僚で登壇者でもある @fugakkbn が、Togetter でこの登壇のまとめを作ってくれていました。ありがとうございます!

togetter.com

2022年9月13日(火) 追記

さっそく VS CodeServer モードの連携を試してくれた結果を文書にまとめていただけたようです。cumet04 さん、ありがとうございます!

zenn.dev

RubyKaigi 2022 に登壇します

RubyKaigi 2022 に『Make RuboCop super fast』というタイトルで登壇します。

私の登壇は2日目である 2022年9月9日(金) の 11:30-12:00 です (昨年と同じ日時だった) 。

rubykaigi.org

最近 RuboCop に追加した server mode の話です。server mode 導入のはじまりの PR は以下。

github.com

server mode の導入に至った課題点とその解決の仕組み。現状での弱点や今後の展望といった利用者として知っておくと良さそうな話なんかも含めて話す予定です。server mode は絶賛開発途上でもあるので、割りと鮮度高めの話になるのではと思っています。

また、今年の RubyKaigi には勤務先の永和システムマネジメントから同僚の @ima1zumi@fugakkbn も登壇します。お楽しみに。

test-queue 0.5.0 をリリースした

前回の v0.4.2 のリリースが 2017年1月らしいので、5年越しのリリースになった。

rubygems.org

自分が欲しかったのは以下の警告を抑制するパッチだったけれど、前回リリースからの差分が他にもあったので、ざっと見ておいたことも書き残しておく。

rspec-queue spec
Starting test-queue master (/tmp/test_queue_69954_4740.sock)
/Users/koic/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/test-queue-0.4.2/lib/test_queue/runner.rb:299: warning: instance variable @early_failure_limit not initialized

今回 v0.5.0 リリース前に確認したところ、TEST_QUEUE_SLAVE_MESSAGE という環境変数設定の名前が、非推奨警告も何もなくカジュアルに TEST_QUEUE_REMOTE_MASTER_MESSAGE に変更されていてユーザーフレンドリーじゃないだろうと、既存の環境変数は非推奨警告付きで利用可能な形にしておいた。

`TEST_QUEUE_SLAVE_MESSAGE` is deprecated. Use `TEST_QUEUE_REMOTE_MASTER_MESSAGE` instead.

いちおう slave という言葉は控えましょうという世論が背景に強かった頃の変更らしいけれど、変更先に master が入っているのはいいのか?という疑問は残りつつ、私自身はベターネームを付けたいための時間も強い意思もないので、そこはそっとしておいた。

ということで、v0.5.0 についての変更要点は以下を参照してください。

github.com

今後、test-queue 開発の内部改善としては CI 環境が travis.org のままで動いていないので、travis.com 移行をするかどうするかというのがあり、そのあたりは GitHub Actions か何かに引越しすれば良いだろうかというお気持ち。

ユーザー向けの機能的には RSpec 4 (beta) に向けた PR が来ていて、そのレビューとかあるけれど、RuboCop で試してみたらどうも RSpec 4 対応のそのパッチ自体不正確なようで期待どおりの動きをしていないのだった (端的にいうとパスすべきテストが落ちている) 。とりわけ RSpec 4 (beta) の API がどの程度安定しているのかも分かっていないし、急ぐ話でもないので追い追い無理ないくらいに。

とりあえず、RSpec 4 が出る頃には次のバージョンを出そうかなという気持ちはあるものの、他とのトリアージなので、もし急ぎの何かがあればメンションなりしてください。

test-queue のコミッターになった

Ruby の parallel test runner である、test-queue のコミッターになった。

github.com

数年前に送った自分のパッチのリリースが欲しくて、RubyKaigi 2014 のクロージングキーノートスピーカーでもある @tmm1 とやりとりしたのがきっかけ。@tmm1 は現在使っていないとのことで、私の方でいくらかのメンテナンスを巻き取る予定でリリース権ももらっています。

現状でサッとリリースできないか最新安定版 v0.4.2 からの差分を眺めたところ、緩和すべき Breaking Change があったりしたので、もろもろ調整した後にリリースする予定です。

RuboCop 1.30 で非推奨になった自動修正オプション名

RuboCop 1.30 で、自動修正する際のオプションである --auto-correct--auto-correct-all は非推奨になり、それぞれ --autocorrect--autocorrect-all になりました。

変更対象のオプション名は long name のみで、short name である -a-A に変更はありません。

まとめると、自動修正に関するオプションは今後以下が正です。

安全な自動修正

  • rubocop -a
  • rubocop --autocorrect

安全でない自動修正

  • rubocop -A
  • rubocop --autocorrect-all

今回の変更は自動修正に関する用語として混在していた auto-correct と autocorrect を、autocorrect の方に統一することを目的としたものです。

なお、この変更が行われた PR は以下です。

github.com

おそらく RuboCop 2.0 あたりで非推奨になったオプションは削除されます。

long name のオプション名を組み込んでいるプログラムはもちろんのこと、書籍やインターネット文献では非推奨になったオプション名を見かけることになると思うため、書き残しておきます。

RuboCopの解析バージョンサポートを見直した

RuboCop は Ruby の EOL バージョンについて、EOL の 1年後までサポートしています。

RuboCop の Ruby バージョンサポートといった時に「ランタイムバージョン」と「解析バージョン」の 2 つがあり、このエントリを書いている時点の最新 RuboCop 1.30 リリースまで、このふたつのバージョンが混同された状態でライフサイクルを共にしていました。

ここでそれぞれのバージョンをおさらい。

  • ランタイムバージョン ... RuboCop を実行する Ruby のバージョン。rubocop コマンドを実行する ruby 処理系のバージョンです。
  • 解析バージョン ... RuboCop が解析する Ruby コードのバージョン。.rubocop.yml の TargetRubyVersion などで指定しているバージョンです。詳しくはこちらの過去記事をどうぞ。

例えば Ruby 2.5 は RuboCop 1.28 でサポート打ち切り、Ruby 2.4 は RuboCop 1.12 でサポート打ち切りとなっていますが、これは 「ランタイムバージョン」と「解析バージョン」の両方を意味していました。

RuboCop 1.30 では、Ruby 2.5 以下をランタイムバージョンは使うことはできませんが、TargetRubyVersionRuby 2.0 以上を指定することができるようになっています。

例えば、Gem 開発で古い Ruby バージョンから新しい Ruby バージョンまでをサポートしたいというニーズや、古い Ruby バージョンのアプリケーションだけど RuboCop はアップグレードして新しい機能を使いたいといったことに対応できます。

特に前者は「RuboCop がサポートバージョンを打ち切ったため、Gem の Ruby 最小要求バージョンが繰り上げる」という事例をいくつか見てきており、RuboCop が Gem のメンテナンスサイクルに作用するのがエンドユーザーにとって幸せかという疑問を解決する形になります (TargetRubyVersionRuby 2.0 まで解析可能になったので) 。

GitHub Actions などで RuboCop をリンターとしている場合は、Ruby 2.6 以上をワークフローのランタイム Ruby バージョンに指定して、.rubocop.yml の TargetRubyVersion に最小要求の Ruby バージョンを指定すると良いでしょう。

ちなみに、Ruby 1.9Ruby 2.0 以降との非互換による Cop のメンテナンスコストの方が高くつきそうなので、いずれもサポートしません。

github.com

先日公開された『2022 Ruby on Rails Community Survey Results』の Ruby バージョンの利用率調査だと、EOL の利用は Ruby 2.6 (15%) 、Ruby 2.5 (8%) 、Ruby 2.4 (4%) 、Ruby 2.3 (3%) 、Ruby 2.2 (1%) 、Ruby 2.1 (1%) 、Ruby 2.0 (0%) 、Ruby 1.9 (2%) 、Ruby 1.8 (1%) ということで、全体の 35% くらいあるようです。そのうち Ruby 2.0 ~ 2.6 までの 32% くらいは救えるだろうか?といったところ。

rails-hosting.com

とはいえ、アプリケーションであればはやめに Ruby バージョンのアップグレードをしていけると良いですね。