Rails运行rails test:system报MessageEncryptor::InvalidMessage错误
问题复现表现
- 本地启动近期克隆的Rails项目,执行
rspec、rails test时所有测试用例可正常跑通 - 执行
rails test:system触发系统测试时,固定抛出ActiveSupport::MessageEncryptor::InvalidMessage、OpenSSL::Cipher::CipherError错误,错误栈指向ActiveSupport加密配置文件解密逻辑 - 手动删除
config/credentials.yml.enc、config/credentials/test.yml.enc,通过rails credentials:edit系列命令重建凭证文件后,异常会反转:系统测试可正常运行,普通测试触发完全一致的解密报错 - 直接复制同事正常运行环境下的
.env配置、master key、两份加密凭证文件覆盖本地文件,甚至重装对应版本Ruby、全量重装gem依赖、删除项目目录重新克隆,问题依旧存在 - 项目固定版本:
ruby 3.0.3p157、rails 7.0.2.3
核心排查方向
- 环境变量加载链路不一致:Rails 7中普通测试、系统测试的启动流程存在差异,系统测试会拉起独立的应用服务进程,二者加载环境变量、配置文件的优先级不同,很容易出现一边读取到正确key、一边读取到错误key的情况
- 多环境key优先级冲突:Rails 7会优先读取当前环境专属的key文件,测试环境下会优先查找
config/credentials/test.key,找不到才会读取全局config/master.key或RAILS_MASTER_KEY环境变量,只要某一处残留了旧的key文件,就会出现两类测试解密结果不一致的问题 - Spring预加载缓存污染:Rails默认集成的Spring进程会常驻内存缓存应用配置,修改凭证、key文件后如果没有彻底杀掉Spring进程,缓存的旧密钥会被部分测试进程读取,导致解密异常
- 配置覆盖问题:检查
.env、.env.test、config/environments/test.rb中是否存在硬编码的错误密钥、或者引用了生产/开发环境的加密配置项
修复步骤
按顺序操作,每步完成后可先验证是否恢复:
- 彻底清理缓存和冲突文件
# 杀掉所有常驻Spring进程 spring stop # 清空临时缓存、pid文件 rm -rf tmp/cache/* tmp/pids/* tmp/sockets/* # 删除所有可能存在优先级冲突的专属key文件 rm -f config/credentials/*.key config/master.key
- 统一密钥配置
- 将团队统一的master key内容写入
config/master.key,给文件设置600权限,不要只靠shell全局环境变量传值 - 确认
config/credentials/test.yml.enc、config/credentials.yml.enc均是用该master key加密生成,不要给test环境生成独立的key对 - 检查
.env、.env.test文件,删除其中写死的RAILS_MASTER_KEY配置,避免覆盖文件读取逻辑
- 验证解密一致性
依次执行以下命令验证两个测试链路的解密逻辑是否正常:
# 验证普通测试环境的凭证读取 rails runner -e test "pp Rails.application.credentials.config" # 验证系统测试启动链路的凭证读取 rails test:system -n 0
两个命令都正常输出凭证内容、无解密报错的话,再分别执行rails test、rails test:system跑全量用例即可。
4. 版本兼容补丁
如果以上操作后仍存在异常,是Rails 7.0.2.x版本的已知配置加载bug,在config/application.rb中添加如下配置,强制所有环境统一读取全局master key:
config.credentials.key_path = Rails.root.join('config/master.key')
内容的提问来源于stack exchange,提问作者cercxtrova
相关产品推荐
相关产品推荐

