Skip to content

Commit

Permalink
Run chef with additional permissions
Browse files Browse the repository at this point in the history
In order to install homebrew, the script needs to
be run as the current user, but it also requires
sudo rights to change the ownership of
/usr/local/bin amongst other things.

Chef is being run in a subprocess and as a result,
there’s no TTY associated with the shell. This
means Homebrew can’t ask for a password when it
runs sudo and the process fails.

This workaround temporarily grants the user the
right to run sudo commands without a password for
the duration of the chef run. It revokes them at
the end, even if chef fails.

There’s some discussion about this here:
sous-chefs/homebrew#105
  • Loading branch information
tuzz committed Sep 10, 2017
1 parent 9e88770 commit 343ed25
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 2 deletions.
4 changes: 4 additions & 0 deletions lib/zz/commands/provision.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ module Provision
class << self
def execute(args)
Exec.install_chef unless Exec.chef_installed?

Exec.grant_permissions
Exec.run_chef
ensure
Exec.revoke_permissions
end

def name
Expand Down
14 changes: 14 additions & 0 deletions lib/zz/exec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ def chef_installed?
def run_chef
execute("chef-solo --config #{Path.chef_config}")
end

def grant_permissions(u = ENV["USER"])
execute(
"echo '#{u} ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/#{u}"
)
end

def revoke_permissions(u = ENV["USER"])
execute("sudo rm -f /etc/sudoers.d/#{u}")
end

def homebrew_installed?
execute("which brew")
end
end
end
end
8 changes: 8 additions & 0 deletions lib/zz/path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ def chef_config
def chef_installer
"https://www.opscode.com/chef/install.sh"
end

def homebrew_remote_installer
"https://raw.githubusercontent.com/Homebrew/install/master/install"
end

def homebrew_local_installer
to("tmp/hombrew_installer")
end
end
end
end
14 changes: 12 additions & 2 deletions spec/zz/commands/provision_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,20 @@
subject.execute([])
end

it "runs chef" do
expect(ZZ::Exec).to receive(:run_chef)
it "grants permissions, then runs chef, then revokes permissions" do
expect(ZZ::Exec).to receive(:grant_permissions).ordered
expect(ZZ::Exec).to receive(:run_chef).ordered
expect(ZZ::Exec).to receive(:revoke_permissions).ordered

subject.execute([])
end

it "ensures permissions are revoked if something goes wrong" do
allow(ZZ::Exec).to receive(:run_chef).and_raise("test")
expect(ZZ::Exec).to receive(:revoke_permissions)

expect { subject.execute([]) }.to raise_error("test")
end

pending "--list option the prints the run_list"
end
32 changes: 32 additions & 0 deletions spec/zz/exec_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,36 @@
subject.run_chef
end
end

describe ".grant_permissions" do
it "grants the permission to run sudo without a password" do
expect(subject).to receive(:execute)
.with("echo 'foo ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/foo")

subject.grant_permissions("foo")
end

it "defaults to the current user" do
allow(ENV).to receive(:[]).and_return("bar")

expect(subject).to receive(:execute)
.with("echo 'bar ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/bar")

subject.grant_permissions
end
end

describe ".revoke_permissions" do
it "revokes the permission to run sudo without a password" do
expect(subject).to receive(:execute).with("sudo rm -f /etc/sudoers.d/foo")
subject.revoke_permissions("foo")
end

it "defaults to the current user" do
allow(ENV).to receive(:[]).and_return("bar")

expect(subject).to receive(:execute).with("sudo rm -f /etc/sudoers.d/bar")
subject.revoke_permissions
end
end
end

0 comments on commit 343ed25

Please sign in to comment.