initial_root_password erroneously containing newline

Summary

I just tried to setup a fresh instance of GitLab on Docker (Swarm Mode in my case) using the Docs at https://docs.gitlab.com/ee/install/docker.html But whatever I tried, gitlab_rails['initial_root_password'] = File.read('/run/secrets/gitlab_root_password') just didn't seem to work. After the setup was complete (when the actual application logs appear in the docker logs) login with the defined password didn't work.

As I read somewhere the root user could be locked due to the failed login attempt I got into the Rails console and looked at the user via User.where(id: 1).first.locked_at? which resulted in false. So that wasn't the issue.

Setting the password via the following was successful and I could login afterwards:

user = User.where(id: 1).first
user.password = 'mypassword'
user.password_confirmation = 'mypassword'
user.save!

When beginning from scratch and using gitlab_rails['initial_root_password'] = 'mypassword' everything worked as expected.

Then I thought, maybe File.read() doesn't work as expected. So again in the Rails console I tested it:

irb(main):001:0> File.read('/run/secrets/gitlab_root_password')
=> "mypassword\n"

Aha! It seems the password gets set, but to a password that cannot be entered in the login (obviously), due to the line break at the end of the file (Unix line endings).

Again, beginning from scratch, I then changed to gitlab_rails['initial_root_password'] = File.read('/run/secrets/gitlab_root_password').strip in my gitlab.rb file. And voilà - I could login as expected!

Steps to reproduce

docker-compose.yml:

version: '3.8'

services:
  gitlab:
    image: gitlab/gitlab-ce:14.2.3-ce.0
    ports:
      - 22:22
      - 80:80
      - 443:443
    volumes:
      - /srv/staging-gfs/gitlab/config:/etc/gitlab
      - /srv/staging-gfs/gitlab/data:/var/opt/gitlab
      - /srv/staging-gfs/gitlab/logs:/var/log/gitlab
    environment:
      GITLAB_OMNIBUS_CONFIG: "from_file('/omnibus_config.rb')"
    configs:
      - source: gitlab
        target: /omnibus_config.rb
    secrets:
      - gitlab_root_password
    # I had to disable the healthcheck while doing initial setup,
    # because it took longer than the healthcheck's first check,
    # so Docker killed the container and started a new one
    healthcheck:
      disable: true

configs:
  gitlab:
    file: ./gitlab.rb

secrets:
  gitlab_root_password:
    file: ./root_password.txt

gitlab.rb:

external_url 'http://gitlab.example.com'
gitlab_rails['initial_root_password'] = File.read('/run/secrets/gitlab_root_password')

root_password.txt:

mypassword

And then docker stack deploy -c docker-compose.yml gitlab (or docker-compose up -d).

What is the current bug behavior?

Login with the password defined in the secret file doesn't work when using gitlab_rails['initial_root_password'] = File.read('/run/secrets/gitlab_root_password').

What is the expected correct behavior?

Login with user root and the password specified in the secret file succeeds.

Possible fixes

As mentioned in the summary File.read('/run/secrets/gitlab_root_password').strip does work for me in this case.
But if the password contains spaces at the beginning or end this would again break.

After a quick internet search I found a (hopefully) more robust solution:
File.read('/run/secrets/gitlab_root_password').gsub("\n", "")

This should work as the following examples show. It is important to note that it MUST be gsub("\n", ...) and not gsub('\n', ...).

irb(main):001:0> "foo\n".gsub("\n", "")
=> "foo"
irb(main):002:0> "foo \n".gsub("\n", "")
=> "foo "
irb(main):003:0> " foo\n".gsub("\n", "")
=> " foo"
irb(main):004:0> "foo bar\n".gsub("\n", "")
=> "foo bar"
irb(main):005:0> " foo bar \n".gsub("\n", "")
=> " foo bar "

But this is merely a workaround. The actual fix should be applied where the gitlab_rails['initial_root_password'] variable is read (maybe the gsub(...) method could be applied there).

Edited by Kevin Köllmann