Проблемы с добавлением гема vault-rails в плагин

Я пытаюсь добавить vault-rails в плагин для шифрования ключей, которые являются частью добавленной мной модели, следуя примеру здесь: Plugin with custom gems - #4 by Falco

(Есть ли уже какой-то способ сделать это в Discourse, который я не нашел? Я вижу только плагин encrypt. . .)

Если я добавлю эту строку в свой plugin.rb, я получаю ошибку: Could not find 'rails' (>= 5.0) among 348 total gem(s). Добавление той же строки в Gemfile самого Discourse работает нормально.

gem "vault-rails", "0.7.0", { require: false }
 (master *) pfaffman@shinytim:~/src/discourse-repos/discourse$ ./bin/rails c
Traceback (most recent call last):
	43: from ./bin/rails:17:in `<main>'
	42: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/dependencies.rb:324:in `require'
	41: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/dependencies.rb:291:in `load_dependency'
	40: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/dependencies.rb:324:in `block in require'
	39: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	38: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	37: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	36: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	35: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	34: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/railties-6.0.3.3/lib/rails/commands.rb:18:in `<main>'
	33: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/railties-6.0.3.3/lib/rails/command.rb:46:in `invoke'
	32: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/railties-6.0.3.3/lib/rails/command/base.rb:69:in `perform'
	31: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
	30: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
	29: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
	28: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/railties-6.0.3.3/lib/rails/commands/console/console_command.rb:101:in `perform'
	27: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/railties-6.0.3.3/lib/rails/command/actions.rb:14:in `require_application_and_environment!'
	26: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/railties-6.0.3.3/lib/rails/command/actions.rb:22:in `require_application!'
	25: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/dependencies.rb:324:in `require'
	24: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/dependencies.rb:291:in `load_dependency'
	23: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-6.0.3.3/lib/active_support/dependencies.rb:324:in `block in require'
	22: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	21: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	20: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	19: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	18: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.5.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	17: from /home/pfaffman/src/discourse-repos/discourse/config/application.rb:70:in `<main>'
	16: from /home/pfaffman/src/discourse-repos/discourse/config/application.rb:71:in `<module:Discourse>'
	15: from /home/pfaffman/src/discourse-repos/discourse/config/application.rb:304:in `<class:Application>'
	14: from /home/pfaffman/src/discourse-repos/discourse/lib/plugin_initialization_guard.rb:5:in `plugin_initialization_guard'
	13: from /home/pfaffman/src/discourse-repos/discourse/config/application.rb:305:in `block in <class:Application>'
	12: from lib/discourse.rb:225:in `activate_plugins!'
	11: from lib/discourse.rb:225:in `each'
	10: from lib/discourse.rb:228:in `block in activate_plugins!'
	 9: from /home/pfaffman/src/discourse-repos/discourse/lib/plugin/instance.rb:611:in `activate!'
	 8: from /home/pfaffman/src/discourse-repos/discourse/lib/plugin/instance.rb:611:in `instance_eval'
	 7: from /home/pfaffman/src/discourse-repos/discourse/plugins/discourse-pfaffmanager/plugin.rb:13:in `activate!'
	 6: from /home/pfaffman/src/discourse-repos/discourse/lib/plugin/instance.rb:705:in `gem'
	 5: from /home/pfaffman/src/discourse-repos/discourse/lib/plugin_gem.rb:22:in `load'
	 4: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1371:in `activate'
	 3: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1389:in `activate_dependencies'
	 2: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1389:in `each'
	 1: from /home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/rubygems/specification.rb:1400:in `block in activate_dependencies'
/home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/rubygems/dependency.rb:311:in `to_specs': Could not find 'rails' (>= 5.0) among 348 total gem(s) (Gem::MissingSpecError)
Checked in 'GEM_PATH=/home/pfaffman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0:/home/pfaffman/Dropbox/home/bin/dotfiles/.gem/ruby/2.7.0', execute `gem env` for more information

В опубликованной вами ссылке сказано:

Вы пробовали это сделать?

Discourse не имеет зависимости от гема Rails, мы импортируем только необходимые нам модули. Указанный вами гем зависит от полного гема Rails, поэтому вам нужно будет рекурсивно добавить каждую зависимость, которой нет в стандартной поставке Discourse.

Боюсь, это будет довольно объёмная работа, но хотя бы вы точно узнаете, чего вам не хватает.

О, я и не подумал бы, что rails не загружен.

всё дерево зависимостей! Понятно.

Это действительно кажется довольно объёмным.

Я буду хранить в базе данных такие вещи, как ключ API от DigitalOcean и SSH-ключ. Знаете ли вы на вскидку какой-то другой простой способ сделать это безопасно? Думаю, я мог бы просто вызвать внешнюю команду и запустить vault или что-то подобное через exec. Это не будет происходить часто.

Может быть, использовать только gem vault, который зависит лишь от aws-sigv4 и aws-eventstream?

Что вы имеете в виду под «безопасно» в данном контексте? Какая у вас Threat model - Wikipedia? Вы пытаетесь защитить это от администраторов с доступом к Data Explorer? В таком случае использование простой переменной окружения (ENV) должно быть проще.

«Безопасно» означает достаточно безопасно, чтобы вы были готовы предоставить свой ключ API Digital Ocean и ключ API Mailgun, чтобы мой небольшой плагин создал Droplet, установил на него Discourse, а затем использовал SSH-ключ для выполнения обновлений и других задач.

Думаю, единственное улучшение для продакшена, которое я добавлю, — это то, что если кто-то украдёт базу данных, у него не будет этих ключей. Конечно, если они взломают сервер, то все гарантии теряются.

Возможно, мне придётся найти более лёгкий способ зашифровать эти несколько полей.

РЕДАКТИРОВАНИЕ: https://pawelurbanek.com/rails-secure-encrypt-decrypt выглядит достаточно просто и использует ActiveSupport::MessageEncryptor, который, кажется, уже доступен.