2

I'm wrote a workflow to install some tool dependencies on a Linux self-hosted GitHub runner VM. I'm using homebrew to do the tool installs. Using homebrew requires that it not be run on the root user which is what the GitHub Runner logs in as. I'm wondering why when I create a step that switches the user from root to my test user things break but when I sudo to that user in every step things work fine, I think I explained this poorly so see below:

Failing Workflow (you can see the first step switches the user to testUser):

 installHomebrew:
    name: Install Homebrew
    runs-on: [self-hosted]
        
    steps:
      - name: Switch to etpAdmin user
        run: sudo -u testUser -i

      - name: Install Homebrew silently
        run: sudo apt install linuxbrew-wrapper -y
        
      - name: Run brew for the first time to create the .linuxbrew directory
        run: brew -h

This will fail on the last step claiming homebrew shouldn't be run on root while the following workflow works just fine.

 installHomebrew:
    name: Install Homebrew
    runs-on: [self-hosted]
        
    steps:
      - name: Install Homebrew silently
        run: sudo apt install linuxbrew-wrapper -y
        
      - name: Run brew for the first time to create the .linuxbrew directory
        run: sudo -u testUser -i brew -h

My Linux is a little rusty but I was under the impression using sudo -u (username) -i will log the terminal into the specified user until logout/switching user again, am I wrong or is there a better way to accomplish this?

Tommy
  • 350
  • 3
  • 11

1 Answers1

3

Disclaimer; I'm not familiar with the platform you are running on or the tool you are using, but I do have an educated guess.. and I hope this also how the -i flag behaves.

As most provisioners work, they usually run each step (mostly) independently from other steps. Which (again, usually) means that environment from one step is not carried over to the next one. So in this case, running sudo -i in one step will not have any effect on subsequent steps. You can try this to see how the provisioner in your case operates:

testUserChange:
    name: Test active user
    runs-on: [self-hosted]
        
    steps:
      - name: Default user
        run: whoami
        
      - name: Sudo user
        run: sudo -u testUser -i whoami

      - name: Should be default user again
        run: whoami

      - name: Maybe interactive shell like in first attempt
        run: sudo -u testUser -i

      - name: Who am I now
        run: whoami

Now as for the -i, the manual states:

This means that login-specific resource files such as .profile or .login will be read by the shell. If a command is specified, it is passed to the shell for execution via the shell's -c option. If no command is specified, an interactive shell is executed.

While this may be a bit confusing, as most provisioners don't expect user interactive input at runtime, they would usually close the STDIN handle (the input to the process). If we have two users, user0ne and usertw0, I hope I can demonstrate the behavior;

$ export PS1="This is user0ne env \$ " # just to show when environment variables are re-set due to loading the login scripts
This is user0ne env $
This is user0ne env $ whoami
user0ne
This is user0ne env $ sudo -u usertw0 /bin/sh
This is user0ne env $ whoami
usertw0
This is user0ne env $ exit
This is user0ne env $ whoami
user0ne
This is user0ne env $

In the above example, you can see that while the effective user is tw0, the environment is still set to what 0ne has set. Let's try with -i:

This is user0ne env $ sudo -u usertw0 -i /bin/sh
$ whoami
usertw0
$ exit
This is user0ne env $

So by now, looks like -i sets the environment (and login) to tw0's. Now, while the documentation does state that without any argument an interactive shell is opened:

This is user0ne env $ sudo -u usertw0 -i
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

usertw0@ubuntu:~$ logout
This is user0ne env $

Let's see what happens if we close the input handler (or more accurately, input nothing):

This is user0ne env $ sudo -u usertw0 -i < /dev/null
This is user0ne env $ whoami
user0ne
This is user0ne env $

And the same will happen even if you provide /bin/sh as the command to run, like shown in a snippet above:

This is user0ne env $ sudo -u usertw0 -i /bin/sh < /dev/null
This is user0ne env $ whoami
user0ne
This is user0ne env $

So even though the documentation does state it will open an interactive shell, the shell closes once there is no input to be read, and the state returns to the previous user.

Cheers! :)

Dharman
  • 30,962
  • 25
  • 85
  • 135
micromoses
  • 6,747
  • 2
  • 20
  • 29
  • That makes sense to me and that's really what I thought was happening but I wanted some sort of confirmation. Thanks very much! – Tommy Mar 18 '21 at 18:48