diff --git a/env.go b/env.go index 19954d0..1bd8093 100644 --- a/env.go +++ b/env.go @@ -30,9 +30,9 @@ func (e *EnvMap) Add(key, value string) { e.env[key] = value } -// Environ returns the map in the format of "key=value", skipping any already set, +// Map returns the final map of environment variables, skipping any already set, // non-empty environment variables, and expanding variables -func (e *EnvMap) Environ() []string { +func (e *EnvMap) Map() map[string]string { // Remove anything already set as an env var env := lo.OmitBy(e.env, func(k, _ string) bool { return os.Getenv(k) != "" @@ -44,7 +44,7 @@ func (e *EnvMap) Environ() []string { }) // Expand variables - env = lo.MapValues(env, func(v string, _ string) string { + return lo.MapValues(env, func(v string, _ string) string { return os.Expand(v, func(s string) string { if l, ok := os.LookupEnv(s); ok { return l @@ -55,8 +55,14 @@ func (e *EnvMap) Environ() []string { return "$" + s }) }) +} - return lo.MapToSlice(env, func(k string, v string) string { +// Environ returns the map in the format of "key=value", skipping any already set, +// non-empty environment variables, and expanding variables +// +// Warning: this does not handle values with newlines +func (e *EnvMap) Environ() []string { + return lo.MapToSlice(e.Map(), func(k string, v string) string { return fmt.Sprintf("%s=%s", k, v) }) } diff --git a/env_test.go b/env_test.go index d548d30..e0247a1 100644 --- a/env_test.go +++ b/env_test.go @@ -34,4 +34,22 @@ func TestEnvMap(t *testing.T) { "DOCKER_CONSUL_BOOTSTRAP_EXPAND_ONE=foo-ignore-bar", "DOCKER_CONSUL_BOOTSTRAP_EXPAND_TWO=foo-bar-baz", }, e.Environ()) + + e.Add("DOCKER_CONSUL_BOOTSTRAP_NEWLINE_ESCAPED", "hello\nworld\n") + e.Add("DOCKER_CONSUL_BOOTSTRAP_NEWLINE", `foo +bar +baz + +test`) + + assert.Equal(t, map[string]string{ + "DOCKER_CONSUL_BOOTSTRAP_TEST_TEST": "testing", + "DOCKER_CONSUL_BOOTSTRAP_TEST_DOLLAR": "testing$a1^h", + "DOCKER_CONSUL_BOOTSTRAP_TEST_EXTRA": "abc^d$1234&567", + "DOCKER_CONSUL_BOOTSTRAP_TEST_BAZ": "bar", + "DOCKER_CONSUL_BOOTSTRAP_EXPAND_ONE": "foo-ignore-bar", + "DOCKER_CONSUL_BOOTSTRAP_EXPAND_TWO": "foo-bar-baz", + "DOCKER_CONSUL_BOOTSTRAP_NEWLINE": "foo\nbar\nbaz\n\ntest", + "DOCKER_CONSUL_BOOTSTRAP_NEWLINE_ESCAPED": "hello\nworld\n", + }, e.Map()) } diff --git a/main.go b/main.go index 8ff2e41..7f04950 100644 --- a/main.go +++ b/main.go @@ -66,7 +66,7 @@ func main() { } logger.DebugContext(ctx, "Running command", "command", cmd, "args", args) - if err := run(cmd, args, env.Environ()); err != nil { + if err := run(cmd, args, env); err != nil { logger.ErrorContext(ctx, "Could not run command", "error", err) os.Exit(1) } @@ -147,16 +147,23 @@ func loadVault(ctx context.Context, addr string, c *Config, l *slog.Logger) (Dic return values, err } -func run(name string, args, env []string) error { +func run(name string, args []string, env *EnvMap) error { bin, err := exec.LookPath(name) if err != nil { return fmt.Errorf("could not find %s: %w", name, err) } - env = append(os.Environ(), env...) - args = append([]string{name}, args...) + for k, v := range env.Map() { + if err := os.Setenv(k, v); err != nil { + return fmt.Errorf("could not set %s: %w", k, err) + } + } - if err := syscall.Exec(bin, args, env); err != nil { // #nosec + if err := syscall.Exec( // #nosec + bin, + append([]string{name}, args...), + os.Environ(), + ); err != nil { return fmt.Errorf("could not execute %s %s: %w", name, strings.Join(args, " "), err) } diff --git a/release-please-config.json b/release-please-config.json index 73f2b0b..995a628 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -7,23 +7,67 @@ "pull-request-header": ":robot: I detected a new release. Please review the changes below.", "pull-request-footer": "When you are ready to release these changes, merge this PR.", "changelog-sections": [ - { "type": "feat", "section": "Features" }, - { "type": "fix", "section": "Bug Fixes" }, - { "type": "perf", "section": "Performance Improvements" }, - { "type": "revert", "section": "Reverts" }, - { "type": "deps", "section": "Dependency Updates" }, - { "type": "docs", "section": "Documentation", "hidden": true }, - { "type": "style", "section": "Styles", "hidden": true }, - { "type": "chore", "section": "Miscellaneous", "hidden": true }, - { "type": "refactor", "section": "Refactors" }, - { "type": "test", "section": "Tests", "hidden": true }, - { "type": "build", "section": "Build", "hidden": true }, - { "type": "ci", "section": "Continuous Integration", "hidden": true } + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "deps", + "section": "Dependency Updates" + }, + { + "type": "docs", + "section": "Documentation", + "hidden": true + }, + { + "type": "style", + "section": "Styles", + "hidden": true + }, + { + "type": "chore", + "section": "Miscellaneous", + "hidden": true + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build", + "hidden": true + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } ], "packages": { ".": { "release-type": "go", - "draft": true + "draft": true, + "versioning": "prerelease", + "prerelease": true } } }