From 0d540d173973f73c615db5f60e76e1b766d2e79d Mon Sep 17 00:00:00 2001 From: Chris Dzombak Date: Mon, 11 Sep 2023 13:50:33 -0400 Subject: [PATCH] add environment privacy options --- README.md | 3 +++ envprivacy.go | 42 ++++++++++++++++++++++++++++++++++++++++++ runner.go | 16 ++++++++++++++-- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 envprivacy.go diff --git a/README.md b/README.md index 4ee3a9a..824038a 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,9 @@ If you plan to use the `RUNNER_OUTFD_PID` and `RUNNER_OUTFD_STD[OUT|ERR]` variab - `-version`: Print version and exit. - `-work-dir string`: Set the working directory for the program. +- `RUNNER_CENSOR_ENV` (environment variable only): Colon-separated list of environment variables whose values will be censored in output. +- `RUNNER_HIDE_ENV` (environment variable only): Colon-separated list of environment variables which will be entirely omitted from output. + #### Run as another user - `-gid int`: Run the program as the given GID. Ignored on Windows. (If provided, runner must be run as `root` or with `CAP_SETGID`.) diff --git a/envprivacy.go b/envprivacy.go new file mode 100644 index 0000000..5444152 --- /dev/null +++ b/envprivacy.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "os" + "strings" +) + +const ( + minLenForCensorHint = 5 +) + +func hiddenEnvVars() []string { + return strings.Split(os.Getenv(HideEnvVarsEnvVar), ":") +} + +func censoredEnvVars() []string { + return strings.Split(os.Getenv(CensorEnvVarsEnvVar), ":") +} + +func shouldHideEnvVar(varName string) bool { + return stringSliceContains(hiddenEnvVars(), varName) +} + +func censoredEnvVarValue(varName, value string) string { + if !stringSliceContains(censoredEnvVars(), varName) && varName != SMTPPassEnvVar { + return value + } + if len(value) < minLenForCensorHint { + return fmt.Sprintf("[%d chars]", len(value)) + } + return fmt.Sprintf("%c[%d chars]%c", value[0], len(value)-2, value[len(value)-1]) +} + +func stringSliceContains(slice []string, value string) bool { + for _, v := range slice { + if v == value { + return true + } + } + return false +} diff --git a/runner.go b/runner.go index db600fc..82ee152 100644 --- a/runner.go +++ b/runner.go @@ -34,6 +34,9 @@ const ( OutFdStderrEnvVar = "RUNNER_OUTFD_STDERR" LogDirEnvVar = "RUNNER_LOG_DIR" + + HideEnvVarsEnvVar = "RUNNER_HIDE_ENV" + CensorEnvVarsEnvVar = "RUNNER_CENSOR_ENV" ) func usage() { @@ -47,6 +50,10 @@ func usage() { "containerization situations. The container must be run with --cap-add CAP_SYS_PTRACE.\n", OutFdPidEnvVar) fmt.Printf("\nOptions:\n") flag.PrintDefaults() + fmt.Printf("\nEnvironment variable-only options:\n") + fmt.Printf(" %s\n \tColon-separated list of environment variables whose values will be censored in output."+ + "\n \tRUNNER_SMTP_PASS is always censored.\n", CensorEnvVarsEnvVar) + fmt.Printf(" %s\n \tColon-separated list of environment variables which will be entirely omitted from output.\n", HideEnvVarsEnvVar) fmt.Printf("\nVersion:\n runner %s\n", version) fmt.Printf("\nGitHub:\n https://github.com/cdzombak/runner\n") fmt.Printf("\nAuthor:\n Chris Dzombak \n") @@ -289,8 +296,13 @@ func main() { ) if !*hideEnv { output = output + "Environment:\n" - for _, v := range os.Environ() { - output = output + fmt.Sprintf("\t%s\n", v) + for _, envVar := range os.Environ() { + envVarPair := strings.SplitN(envVar, "=", 2) + envVarName := envVarPair[0] + if shouldHideEnvVar(envVarName) { + continue + } + output = output + fmt.Sprintf("\t%s=%s\n", envVarName, censoredEnvVarValue(envVarName, envVarPair[1])) } output = output + "\n" }