Rails7 RSpec测试加密属性首次CI报key_derivation_salt未配置错误
问题现象
基于Rails 7.0.3框架开发的应用中,某模型配置了encrypted attribute(加密属性),本地验证RSpec用例时行为正常,配置GitHub Actions工作流自动执行测试时出现稳定复现的异常:同一提交的首次CI运行必然失败,手动触发重新运行后全部执行成功。
报错信息如下:
ActiveRecord::Encryption::Errors::Configuration: key_derivation_salt is not configured. Please configure it via credential active_record_encryption.key_derivation_salt or by setting config.active_record.encryption.key_derivation_salt
现有配置说明
- 已在GitHub仓库Secrets中配置了对应的
RAILS_MASTER_KEY - ActiveRecord加密所需的配置项均存储在加密凭据文件中,配置结构如下:
active_record_encryption: primary_key: u▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ deterministic_key: 4▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ key_derivation_salt: R▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉
- 原有GitHub Actions工作流精简配置如下:
name: CI on: [push] jobs: rspec: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ".ruby-version" - name: Bundle Install run: | gem install bundler -v $(grep 'BUNDLED WITH' -A1 Gemfile.lock | tail -n 1 ) bundle config set --local path 'vendor/bundle' bundle install --jobs 4 --retry 3 - env: RAILS_MASTER_KEY: "${{ secrets.RAILS_MASTER_KEY }}" run: RAILS_ENV=test bundle exec rspec
- 诉求:不通过引入RSpec重试/重跑类gem临时规避问题,定位根本原因并彻底修复。
根本原因
该问题是CI环境变量作用域配置错误+冷启动时序竞态叠加老版本checkout动作缺陷导致的,和业务代码逻辑无关:
- 原配置中
RAILS_MASTER_KEY只绑定在最后执行rspec的单条run指令上,工作流前面的所有步骤(包括bundle安装、Rails预加载、缓存生成流程)都无法读取到该密钥。首次在全新Runner上运行时,Rails冷启动过程中ActiveRecord加密组件的初始化时点早于凭据解密流程,读不到加密配置就会直接抛出salt缺失的错误。 - 首次运行失败后手动重跑时,GitHub Actions会复用首次运行生成的工作区缓存、bundle缓存,此时Rails不需要走完整的冷启动初始化流程,加载时序发生变化,加密配置可以正常读取,因此测试会全部通过,是非常典型的首跑必败、重跑必过的时序问题特征。
- 原配置使用的
actions/checkout@v1是多年前的老旧版本,存在加密凭据文件权限设置错误、代码拉取不完整的已知问题,会进一步放大首次加载的时序异常。
修复方案
按优先级执行以下调整即可彻底解决问题:
- 修正环境变量作用域,将
RAILS_MASTER_KEY和RAILS_ENV配置到job层级,确保整个job生命周期内所有流程都能读取到正确的环境变量;同时升级checkout版本到稳定版,替换冗余的bundle安装逻辑为setup-ruby自带的缓存能力,修改后的工作流配置参考:
name: CI on: [push] jobs: rspec: runs-on: ubuntu-latest env: RAILS_ENV: test RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }} steps: - uses: actions/checkout@v3 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ".ruby-version" bundler-cache: true - name: Verify Encryption Config run: bundle exec rails runner "puts ActiveRecord::Encryption.config.key_derivation_salt" - name: Run RSpec run: bundle exec rspec
- 校验test环境加密配置的加载时机,打开
config/environments/test.rb,确认ActiveRecord加密配置在Rails凭据加载完成后才初始化,可显式指定配置读取逻辑避免提前初始化:
# config/environments/test.rb Rails.application.configure do # 其余原有test环境配置保持不变 config.active_record.encryption.primary_key = Rails.application.credentials.active_record_encryption[:primary_key] config.active_record.encryption.deterministic_key = Rails.application.credentials.active_record_encryption[:deterministic_key] config.active_record.encryption.key_derivation_salt = Rails.application.credentials.active_record_encryption[:key_derivation_salt] end
- 调整完成后手动清理一次GitHub Actions的历史工作流缓存,避免旧的错误缓存干扰验证结果。
内容的提问来源于stack exchange,提问作者user1065745
相关产品推荐
相关产品推荐

