Skip to content

Commit

Permalink
Add basic sudo support (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
wagoodman authored Feb 18, 2018
1 parent 5ec1d5c commit a17fbcd
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ $(TARGETS):

run:
go run main.go task.go config.go screen.go download.go log.go \
run example/13-single-line.yml
run example/14-sudo.yml

examples: clean build
./dist/bashful run example/00-demo.yml
Expand Down
3 changes: 3 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ type TaskConfig struct {
// StopOnFailure indicates to halt further program execution if a task command has a non-zero return code
StopOnFailure bool `yaml:"stop-on-failure"`

// Sudo indicates that the given command should be run with the given sudo credentials
Sudo bool `yaml:"sudo"`

// Tags is a list of strings that is used to filter down which task are run at runtime
Tags stringArray `yaml:"tags"`
TagSet mapset.Set
Expand Down
9 changes: 9 additions & 0 deletions example/14-sudo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
tasks:
# if a command shold be run with sudo, flag it as so...
- cmd: touch /bin/true
sudo: true

#... *don't* put sudo in your cmd
- cmd: sudo touch /bin/true
stop-on-failure: false

49 changes: 49 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io/ioutil"
"math/rand"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
Expand All @@ -16,6 +17,7 @@ import (
"text/template"
"time"

"github.com/howeyc/gopass"
color "github.com/mgutz/ansi"
"github.com/mholt/archiver"
"github.com/urfave/cli"
Expand All @@ -36,6 +38,7 @@ var (
ticker *time.Ticker
exitSignaled bool
startTime time.Time
sudoPassword string
purple = color.ColorFunc("magenta+h")
red = color.ColorFunc("red+h")
blue = color.ColorFunc("blue+h")
Expand Down Expand Up @@ -200,6 +203,51 @@ __BASHFUL_ARCHIVE__

}

func storeSudoPasswd() {
var sout bytes.Buffer

// check if there is a task that requires sudo
requireSudo := false
for _, task := range allTasks {
if task.Config.Sudo {
requireSudo = true
break
}
for _, subTask := range task.Children {
if subTask.Config.Sudo {
requireSudo = true
break
}
}
}

if !requireSudo {
return
}

// test if a password is even required for sudo
cmd := exec.Command("/bin/sh", "-c", "sudo -Sn /bin/true")
cmd.Stderr = &sout
err := cmd.Run()
requiresPassword := sout.String() == "sudo: a password is required\n"

if requiresPassword {
fmt.Print("[bashful] sudo password required: ")
sudoPassword, err := gopass.GetPasswd()
checkError(err, "Could get sudo password from user.")

// test the given password
cmdTest := exec.Command("/bin/sh", "-c", "sudo -S /bin/true")
cmdTest.Stdin = strings.NewReader(string(sudoPassword) + "\n")
err = cmdTest.Run()
if err != nil {
exitWithErrorMessage("Given sudo password did not work.")
}
} else {
checkError(err, "Could not determine sudo access for user.")
}
}

func run(yamlString []byte, environment map[string]string) []*Task {
var err error

Expand All @@ -208,6 +256,7 @@ func run(yamlString []byte, environment map[string]string) []*Task {

ParseConfig(yamlString)
allTasks = CreateTasks()
storeSudoPasswd()

DownloadAssets(allTasks)

Expand Down
7 changes: 6 additions & 1 deletion task.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,12 @@ func (task *Task) inflateCmd() {
readFd, writeFd, err := os.Pipe()
checkError(err, "Could not open env pipe for child shell")

task.Command.Cmd = exec.Command(shell, "-c", task.Config.CmdString+"; BASHFUL_RC=$?; env >&3; exit $BASHFUL_RC")
sudoCmd := ""
if task.Config.Sudo {
sudoCmd = "sudo -S "
}
task.Command.Cmd = exec.Command(shell, "-c", sudoCmd+task.Config.CmdString+"; BASHFUL_RC=$?; env >&3; exit $BASHFUL_RC")
task.Command.Cmd.Stdin = strings.NewReader(string(sudoPassword) + "\n")

// allow the child process to provide env vars via a pipe (FD3)
task.Command.Cmd.ExtraFiles = []*os.File{writeFd}
Expand Down

0 comments on commit a17fbcd

Please sign in to comment.