概要
rspecでvcrというテストで投げたAPIリクエストを初回はymlにキャッシュしておいて、再実行した時はビデオデッキがカセット(cassete)を読み出すようにymlからレスポンスデータを再現してテストしてくれる便利な代物があるのですが、リクエストヘッダもそのまま残してくれているようでAuthorization
のトークンなどをそのまま残らないように設定できる方法をメモしました。
問題例
出力されたvcrのカセットファイル
http_interactions:
- request:
method: post
uri: https://example.com/api/v1/favorite
body:
encoding: UTF-8
string: '{"comment":"hello"}'
headers:
Content-Type:
- application/json
Authorization:
- Basic 000000_MySecretP@ssWordToken_000000
X-Http-Method-Override:
- POST
# 中略
※今回は仮に000000_MySecretP@ssWordToken_000000
をセキュリティ上、コミットに残したくない文字列とする。
specの設定ファイル
VCR.configure do |config|
config.cassette_library_dir = "vcr/vcr_cassettes"
config.hook_into :webmock
# パスワードトークン隠したかった。でもこれじゃ隠せてないw
# config.filter_sensitive_data("Basic *****") { 'Basic 000000_MySecretP@ssWordToken_000000' }
# ちょっと改善してみたが、これはトークンの生成ルールが透けて見えてるような気がする。
config.filter_sensitive_data("Basic *****") { "Basic #{Base64.strict_encode64([ENV.fetch("ID", nil), ENV.fetch("PW", nil)].join(":"))}" }
end
対応
config.filter_sensitive_dataメソッドをクロージャにすると第1引数にvcrの内容がそのままオブジェクトで取得できるみたいなので、それを利用することにした。
specの設定ファイル
VCR.configure do |config|
config.cassette_library_dir = "vcr/vcr_cassettes"
config.hook_into :webmock
# リクエストの`Authorization`の値がある場合は直に取得して秘匿するようにした。
config.filter_sensitive_data("Basic *****") { |interaction|
interaction.request.headers["Authorization"][0] if interaction.request.headers["Authorization"].present?
}
end
出力されたvcrのカセットファイル
http_interactions:
- request:
method: post
uri: https://example.com/api/v1/favorite
body:
encoding: UTF-8
string: '{"comment":"hello"}'
headers:
Content-Type:
- application/json
Authorization:
- Basic *****
X-Http-Method-Override:
- POST
# 中略
※Authorization
のトークンがBasic *****
に置換されている。
参考記事
https://qiita.com/kazuooooo/items/30971a40511ea48da4a2
https://qiita.com/gotchane/items/c2c29c0063bd44246510
https://stackoverflow.com/questions/60412825/hiding-sensitive-data-in-vcr#comment127692395_60415745