Skip to content

`gitlab-backup-cli` omnibus package bin command lacks privilege/system user handling

Summary

In #8273 (closed), we added the initial bin command gitlab-backup-cli as part of the project to replace existing gitlab-backup with a newer unified backup tool. Testing with @nwestbury and @sranasinghe, it seems the command gitlab-backup-cli when run as root on a production install from the omnibus package is failing:

root@br-1k-main-gitlab-rails-1:~# gitlab-backup-cli backup all
[2024-05-09 15:41:15 UTC] ℹ️  Initializing environment...
/opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/execjs-2.8.1/lib/execjs/runtimes.rb:58:in `autodetect': Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/execjs-2.8.1/lib/execjs.rb:5:in `<module:ExecJS>'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/execjs-2.8.1/lib/execjs.rb:4:in `<main>'
	from <internal:/opt/gitlab/embedded/lib/ruby/site_ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/opt/gitlab/embedded/lib/ruby/site_ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bootsnap-1.18.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/terser-1.0.2/lib/terser.rb:6:in `<main>'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bundler-2.5.8/lib/bundler/runtime.rb:60:in `require'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bundler-2.5.8/lib/bundler/runtime.rb:60:in `block (2 levels) in require'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bundler-2.5.8/lib/bundler/runtime.rb:55:in `each'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bundler-2.5.8/lib/bundler/runtime.rb:55:in `block in require'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bundler-2.5.8/lib/bundler/runtime.rb:44:in `each'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bundler-2.5.8/lib/bundler/runtime.rb:44:in `require'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bundler-2.5.8/lib/bundler.rb:187:in `require'
	from /opt/gitlab/embedded/service/gitlab-rails/config/application.rb:18:in `<main>'
	from <internal:/opt/gitlab/embedded/lib/ruby/site_ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/opt/gitlab/embedded/lib/ruby/site_ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/bootsnap-1.18.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	from /opt/gitlab/embedded/service/gitlab-rails/gems/gitlab-backup-cli/lib/gitlab/backup/cli.rb:23:in `rails_environment!'
	from /opt/gitlab/embedded/service/gitlab-rails/gems/gitlab-backup-cli/lib/gitlab/backup/cli/commands/backup_subcommand.rb:14:in `block in all'
	from /opt/gitlab/embedded/service/gitlab-rails/gems/gitlab-backup-cli/lib/gitlab/backup/cli/commands/backup_subcommand.rb:45:in `measure_duration'
	from /opt/gitlab/embedded/service/gitlab-rails/gems/gitlab-backup-cli/lib/gitlab/backup/cli/commands/backup_subcommand.rb:12:in `all'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor.rb:527:in `dispatch'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor/invocation.rb:116:in `invoke'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor.rb:338:in `block in subcommand'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor.rb:527:in `dispatch'
	from /opt/gitlab/embedded/lib/ruby/gems/3.1.0/gems/thor-1.3.1/lib/thor/base.rb:584:in `start'
	from /opt/gitlab/embedded/service/gitlab-rails/bin/gitlab-backup-cli:14:in `<main>'

Steps to reproduce

  1. Set up a sandbox gitlab install -- any architecture will work. Install the latest gitlab production build omnibus package
  2. ssh into the rails instance, change to root, and attempt to run a backup:
sudo su - # change to root shell
gitlab-backup-ctl backup all
# you will see the error output shown further up in this issue

What is the current bug behavior?

  • It fails because it can't identify a JS execution environment while loading the Rails environment

What is the expected correct behavior?

  • It should run without error and create a backup

Troubleshooting / Fix Notes

  • Reviewing the other omnibus package bin scripts (e.g. gitlab-rake gitlab-rails etc...), they go through great lengths to cd into the rails source directory and then change to the gitlab user with more restricted permissions
  • The gitlab-backup-cli script we added in !7328 (merged) does not do anything to set up the environment before delegating to the inner $RAILS_ROOT/bin/gitlab-backup-cli ruby script
  • As root, the backup command works when I run it as:
/opt/gitlab/embedded/bin/chpst -e /opt/gitlab/etc/gitlab-rails/env -u git:git -U git:git /usr/bin/env RUBYOPT=-W:no-experimental /opt/gitlab/embedded/bin/bundle exec gitlab-backup-cli
  • Thus, to resolve this bug, I propose updating the omnibus gitlab-backup-cli bin script to factor in the same environment setup and user/privilege switching that the other omnibus bin wrappers appear to do before calling the inner packaged gitlab-backup-cli ruby script.