TechTips
Categories
├─Books Cloud services Events Standard TechTips Others
├─Software
│ ├─Mac OS Programming languages Windows Others
│ ├─Libraries
│ │ └─C C++ Java JavaScript Python Ruby Rust Others
│ └─Unix
│ └─Unix commands Others
└─Web
└─Document Service Others
Ruby 4.0でrdocを追加インストールするとwarningが出るようになる
Ruby 4.0では、rdoc gemについて最新バージョンなどを追加インストールすると、gemコマンドの実行で大量のwarningが表示される状態に陥いります。
なお、開発サイドもこの状態を把握しているようですので、個人的には解決されるまで様子を見ようと思っています。
Docker Composeのサービス名にappやdevを使うとSeleniumのHTTP接続がSSLエラーになる原因と対策
要点
Docker Compose の
compose.yamlでサービス名を付ける際は、HTTP での接続先となるコンテナのサービス名にはappやdevといったトップレベルドメイン(TLD)として実在する文字列を使わないほうが安全です。具体的な対策
HTTP で接続するサービス(コンテナ)には、ハイフン(
-)を用いて複数の単語を組み合わせた名前をつけるのが、簡単な解決策です。app,devrails-app,web-serverなぜエラーになるのか
Docker Compose のネットワーク内では、サービス名で名前解決をして他コンテナへアクセスできます。そのため、Selenium コンテナ内のブラウザから
http://app/のようにアクセスする設定にすることがあります。しかしブラウザは、その
appを Docker 内部の名前としてではなく、通常のホスト名として扱います。appやdevは実在の TLD であり、しかも HSTS(HTTP Strict Transport Security)を強制する対象なので、ブラウザはhttp://app/をhttps://app/に書き換えます。 接続先が HTTPS 非対応なら、結果としてERR_SSL_PROTOCOL_ERRORやAre you trying to open an SSL connection to a non-SSL Puma?のようなエラーになります。一方、
rails-appのように、TLD と一致しない名前にすれば、HSTS 強制の対象から外れ、HTTPS に書き換えられないため、エラーを防ぐことができます。背景:何が起きているか
Docker の
compose.yamlのservicesで定義したサービス名は、Docker ネットワーク内で他コンテナへアクセスする際のホスト名として使えます。ここでのホスト名とは、http://example.com/のexample.comに当たります。サービス名にドット(
.)が含まれていない場合、単一ラベルのホスト名となり、ブラウザはその名前を TLD として扱います。例えば、appというサービス名は、appという TLD のみからなるホスト名として認識されます。TLD のみのホスト名のうち、
appやdevは HSTS 強制の対象となっており、HSTS プレロードリストなどの仕組みにより、HTTPS 接続が強制されます。そのため、http://app/という HTTP での接続になるよう設定しても、ブラウザは強制的にhttps://app/という HTTPS での接続へと書き換えて接続しようとします。結果、
appやdevのような HSTS が強制される名前を持つサービス(コンテナ)に対して、Selenium コンテナ内のブラウザは、HTTP で接続するよう設定されていても、HTTPS で接続してしまいます。 さらに、接続される側のコンテナが HTTPS に対応していない場合、接続がエラーとなります。このように、E2E テストやシステムテストでは「ブラウザがどう解釈するか」は無視できない事項です。 コンテナ間疎通の都合だけで名前を決めるのではなく、ブラウザが特殊な扱いをする名前ではないか、という観点も持っておくとトラブルを減らせます。
注意点
http://app:3000/のような URL でもエラーになり得ます。facebook.comやwww.amazon.comといったドットを含むホスト名も多数存在するためです。接続エラーに遭遇した状況
compose.yamlにおいて、selenium/standalone-chromiumイメージの Selenium コンテナからサービス名がappのコンテナへ HTTP で接続する設定をしたところ、以下のエラーが発生しました。なお、サービス名を
appからrails-appに変更したところ、無事意図したとおりに動くようになりました。 HSTS 強制の対象となる TLD(app)との一致を回避した結果、ブラウザが HTTPS へ強制的に書き換えなくなったためと考えられます。参考資料
PmRails v1.1.0 をリリースしました。
リリースの概要
pmrails-new-plus: アプリの作成・gem のインストール・.gitignore の更新を1ステップで自動化します。.pmrails/var/: gem・キャッシュ・設定ファイルなどをプロジェクトごとに隔離して管理するようになりました。--userns=keep-idオプションを追加しました。リリースノートと変更履歴はGitHubで確認できます: https://github.com/wakairo/pmrails/releases/tag/v1.1.0
Rails 8.0からRails 8.1への移行(アップデート、アップグレード)で必要な作業
Rails 8.1におけるconfig.content_security_policy_nonce_auto
config.content_security_policy_nonce_autoは、 Rails 8.1で追加された「CSPのnonceを自動で追加する機能」を有効にするかどうかの設定です。rails newで生成されるconfig/initializers/content_security_policy.rbにおいて、 8.1からは以下のようにこの設定のコードが追加されました(この変更のPRとこの変更のCommit)。デフォルトではCSP設定自体がコメントアウトされており、この機能の設定もコメントアウトされています。
Railsガイドでは、CSPについての説明が「Content-Security-Policyヘッダー」の項目にあり、 このnonceを自動で追加する機能の説明が「nonceを追加する」の項目にあります。
vscodeのdevcontainerでCodexを使うのを今は見送りにした理由
Codex(OpenAIのコーディング・エージェント)をdevcontainer(開発用コンテナ)の中に閉じ込めて動かすのは、 セキュリティの確保もできて、なかなか良いアイデアなのではと思いました。 ところが、vscodeで実際に試してみたところ、Codexのセキュリティの仕組みと絡んで、不都合な挙動があったので、 このやり方は公式にサポートされるまでは様子見が良いかなと今は思っています。
確認したこと
まずvscodeでdevcontainerを起動しました。 設定ファイル
.devcontainer/devcontainer.jsonの中身は以下の通りです。次に、Codex拡張をインストールしました。 その次に、Codexにソースファイルの一部を変更する指示を出したところ、
apply_patchが上手くいかないのでsedなどを代わりに使うという返答で、 変更前後のdiffが見づらい形になりました。なお、devcontainerの設定で指定するimageは以下の2つも試しましたが、 同じ現象に遭遇しましたので、特定のイメージでのみ発生する現象ではありません。
apply_patchが失敗する背景Codexが言うには、
apply_patchはbwrapという一種のコンテナの中で動かす仕組みらしく、 devcontainerというコンテナの中でbwrapというコンテナを動かす、 つまり、コンテナの中でコンテナを動かすのに失敗しているらしいです。 具体的には、devcontainerの中でbwrapのコンテナのために新しいnamespaceを作ろうとして、 permissionの問題に遭遇しているとのこと。Codexがbwrapを使うのはセキュリティを高めるためだと思いますので、 安易な設定変更などで
apply_patchを出来るようにするのは、 セキュリティ上のリスクがあると見ています。Rails 8.0からRails 8.1への移行(アップデート、アップグレード)で必要な作業
Rails 8.1におけるRails.configuration.action_view.remove_hidden_field_autocomplete
config.action_view.remove_hidden_field_autocompleteは、hiddenフィールドからautocomplete="off"属性を除去するかどうかの設定です。 (この機能のPRとこの機能のCommit)bin/rails app:updateコマンドが生成する config/initializers/new_framework_defaults_8_1.rbには、 以下のようにこの設定を有効にするコードがあります。この機能が導入された背景
この機能は、HTML標準へ より準拠したHTMLをRailsが生成するように追加されました。
具体的には、この機能を有効にしない場合、Railsは以下のような
autocomplete="off"属性を付けたhiddenフィールドを生成していました。このautocomplete属性付きのhiddenフィールドはHTML標準に沿っておらず、 Nu Html Checkerは 以下のメッセージとともに「エラー」として指摘していました。
Rails 8.0からRails 8.1への移行(アップデート、アップグレード)で必要な作業
Rails 8.1におけるconfig.action_dispatch.verbose_redirect_logs
config.action_dispatch.verbose_redirect_logsは、リダイレクトのソース位置を関連するログ行の下にログ出力するかどうかの設定です。rails newで生成されるconfig/environments/development.rbにおいて、 8.1からは以下のようにこの設定を有効にするコードが追加されました(この変更のPRとこの変更のCommit)。development環境でデバッグする際に使える情報が増える形になると思いますので、既存アプリでもこの設定を追加しても良いかもしれません。
Rails 8.0からRails 8.1への移行(アップデート、アップグレード)で必要な作業
基本的にはRailsガイドの手順に従えば良いと思います。
ガイドの手順にもありますが、ぜひ
bin/rails app:updateコマンドを活用しましょう。Rails 8.1への移行で対応が必要そうな個別の作業について、以下のコメントでそれぞれ取り上げますので、ご参考になれば幸いです。
Active Recordのgenerates_token_for:DBカラム不要で一時的なトークンを扱う機能
generates_token_forとは
generates_token_forは、特定の目的を持つトークンを生成し、そのトークンからレコードを検索・検証するための機能です。 Rails 7.1で標準機能として導入されました。特長
使いどころ:一時的に有効なURLの送付
以下のような「一時的で目的が限定されたトークン付きURL」を送付する場面に適しています。
なお、APIの認証トークンのような永続的な用途には向きません。 Railsで永続的なトークンを扱いたい場合は、
has_secure_tokenなどの利用を検討してください。注意:パスワードリセットには専用APIあり
Rails 8.0以降で
has_secure_passwordを利用している場合、パスワードリセット用トークンを扱う専用APIが自動的に提供されます。そのため、パスワードリセットの用途に限っては、自分でgenerates_token_forを定義する必要はありません。(詳しくは後述の補足を参照してください)使い方(メールアドレス確認の例)
ここでは「メールアドレス変更時の確認リンク」を題材に、基本的な使い方を説明します。
基本の流れ(定義・生成・検証)
まず、モデルに
generates_token_forを用いて、トークンの用途名(ここでは:email_verification)を定義します。 なお、用途名が異なっていれば複数定義することも可能です。トークンを生成する際は、対象のインスタンスに対して
generate_token_forを呼び出します。生成したトークンは、例えば以下のようにURLパラメータに載せてメールなどで送付するのが典型的な流れです。
受け取ったトークンからレコードを検索・検証するには、クラスメソッドの
find_by_token_forを使います。 有効なトークンならUserインスタンスが返り、無効なトークンや期限切れのトークンの場合はnilが返ります。有効期限による失効
定義時に
expires_inオプションを付与することで、トークンに有効期限(例:15分間)を設けることができます。モデルのデータ変化による失効
generates_token_forは、「一度状態が変わったら、古いトークンを使わせない」挙動を簡単に実装できます。 例えば、新しいメールアドレス確認用に生成されたトークンを、メールアドレスの変更が完了した後に無効化すれば、万が一流出しても悪用を防げます。無効化の仕組みは「定義時のブロックの戻り値をトークンに埋め込み、検証時にその値が変わっていれば無効とみなす」というものです。
注意:ブロックの戻り値に機密情報を含めない
ブロック内で返した値は、改ざん耐性はあるものの、暗号化されるわけではなく、デコードすれば読める形でトークンに埋め込まれます。 そのため、ブロックの戻り値には機密情報を含めてはなりません。
補足:パスワードリセット専用API
Rails 8.0以降では、モデルで
has_secure_passwordを利用している場合、パスワードリセットトークン用の以下のメソッドがデフォルトで追加されます。password_reset_token:トークン生成(インスタンスメソッド)find_by_password_reset_token:トークンからの検索と検証(クラスメソッド)find_by_password_reset_token!:同上(無効時に例外を発生させるバージョン)Rails 8.1で追加されたトークン有効期限の機能
さらにRails 8.1以降では、トークンの有効期限を柔軟に扱うための機能が追加されています。
has_secure_passwordの呼び出し時にreset_tokenオプションを通して有効期限を変更できるようになりました。また、以下のメソッドが追加されました。
password_reset_token_expires_in:設定されている有効期限の取得(インスタンスメソッド)参考情報
Bootstrap 5に由来するDart Sassの非推奨警告を抑制する:Railsアプリ(dartsass-rails)を例に
問題:Bootstrap 5に由来する大量の非推奨警告
Bootstrapは、 Sassの仕様変更に対して長期的に取り組みを進めている 最中であるため、Dart Sassでコンパイルすると以下のような非推奨(Deprecation)警告が大量に出力されます。
この大量の警告にまぎれてしまい、自分で書いたコードに対する警告を見つけにくくなるという問題があります。 その結果、自分のコードに警告が出ていないことを確認するだけでも、手間と時間がかかってしまいます。
なお、2024年にリリースされたDart Sass 1.80.0以降、
@importなどの非推奨警告がより積極的に出力されるようになり、この問題がさらに目立つようになりました。解決策:
--quiet-depsで依存ライブラリへの非推奨警告を抑制するこの問題の解決策は、
sassコマンドを実行する際に--quiet-depsオプションを付与することです。 これにより、Bootstrapを含む依存ライブラリ(厳密には、ロードパス経由でインポートされたコード)に対する非推奨警告が出力されなくなります。 なお、ロードパス経由でない自分のコードに対する警告は引き続き出力されます。Railsアプリ(dartsass-rails)で
--quiet-depsを付与する方法dartsass-rails gemを利用するRailsアプリでは、
config/initializers/dartsass.rbを開いて(なければ新規作成して)、 以下のコードを記述します。参考情報