65 lines
1.3 KiB
Go

package main
import (
"bufio"
"context"
"fmt"
"io"
"os/exec"
"regexp"
"strings"
"time"
)
// Run an external program
func RunProgram(program string, args []string, timeout time.Duration) {
// Flag if we are starting or stopping a container
managingContainer := program == "docker"
// Create context and command
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
cmd := exec.CommandContext(ctx, program, args...)
// Stringify and censor the program's arguments
strArgs := redactString(strings.Join(args, " "))
fmt.Printf(" [+] Running %s %s\n", program, strArgs)
// Setup pipes
stdout, err := cmd.StdoutPipe()
if err != nil {
panic(err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
panic(err)
}
// Start the command
if err := cmd.Start(); err != nil {
panic(err)
}
// Stream any messages to the terminal
for _, r := range []io.Reader{stdout, stderr} {
// Don't log stdout from the container
if managingContainer && r == stdout {
continue
}
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanRunes)
for scanner.Scan() {
fmt.Print(scanner.Text())
}
}
}
// Redacts sensitive command line arguments.
func redactString(raw string) string {
redactionRegex := regexp.MustCompilePOSIX(`-(user|pass|key) [^ ]+`)
return redactionRegex.ReplaceAllString(raw, "-$1 REDACTED")
}