cmd: Prevent overwriting existing env vars with --envfile (#5803)

Co-authored-by: Francis Lavoie <lavofr@gmail.com>
This commit is contained in:
Evan Van Dam 2023-09-06 19:19:24 -07:00 committed by GitHub
parent 50cea4e263
commit f2ab7099db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 33 deletions

View file

@ -46,7 +46,14 @@ func cmdStart(fl Flags) (int, error) {
startCmdConfigAdapterFlag := fl.String("adapter") startCmdConfigAdapterFlag := fl.String("adapter")
startCmdPidfileFlag := fl.String("pidfile") startCmdPidfileFlag := fl.String("pidfile")
startCmdWatchFlag := fl.Bool("watch") startCmdWatchFlag := fl.Bool("watch")
startCmdEnvfileFlag := fl.String("envfile")
var err error
var startCmdEnvfileFlag []string
startCmdEnvfileFlag, err = fl.GetStringSlice("envfile")
if err != nil {
return caddy.ExitCodeFailedStartup,
fmt.Errorf("reading envfile flag: %v", err)
}
// open a listener to which the child process will connect when // open a listener to which the child process will connect when
// it is ready to confirm that it has successfully started // it is ready to confirm that it has successfully started
@ -70,8 +77,9 @@ func cmdStart(fl Flags) (int, error) {
if startCmdConfigFlag != "" { if startCmdConfigFlag != "" {
cmd.Args = append(cmd.Args, "--config", startCmdConfigFlag) cmd.Args = append(cmd.Args, "--config", startCmdConfigFlag)
} }
if startCmdEnvfileFlag != "" {
cmd.Args = append(cmd.Args, "--envfile", startCmdEnvfileFlag) for _, envFile := range startCmdEnvfileFlag {
cmd.Args = append(cmd.Args, "--envfile", envFile)
} }
if startCmdConfigAdapterFlag != "" { if startCmdConfigAdapterFlag != "" {
cmd.Args = append(cmd.Args, "--adapter", startCmdConfigAdapterFlag) cmd.Args = append(cmd.Args, "--adapter", startCmdConfigAdapterFlag)
@ -160,15 +168,22 @@ func cmdRun(fl Flags) (int, error) {
runCmdConfigFlag := fl.String("config") runCmdConfigFlag := fl.String("config")
runCmdConfigAdapterFlag := fl.String("adapter") runCmdConfigAdapterFlag := fl.String("adapter")
runCmdResumeFlag := fl.Bool("resume") runCmdResumeFlag := fl.Bool("resume")
runCmdLoadEnvfileFlag := fl.String("envfile")
runCmdPrintEnvFlag := fl.Bool("environ") runCmdPrintEnvFlag := fl.Bool("environ")
runCmdWatchFlag := fl.Bool("watch") runCmdWatchFlag := fl.Bool("watch")
runCmdPidfileFlag := fl.String("pidfile") runCmdPidfileFlag := fl.String("pidfile")
runCmdPingbackFlag := fl.String("pingback") runCmdPingbackFlag := fl.String("pingback")
var err error
var runCmdLoadEnvfileFlag []string
runCmdLoadEnvfileFlag, err = fl.GetStringSlice("envfile")
if err != nil {
return caddy.ExitCodeFailedStartup,
fmt.Errorf("reading envfile flag: %v", err)
}
// load all additional envs as soon as possible // load all additional envs as soon as possible
if runCmdLoadEnvfileFlag != "" { for _, envFile := range runCmdLoadEnvfileFlag {
if err := loadEnvFromFile(runCmdLoadEnvfileFlag); err != nil { if err := loadEnvFromFile(envFile); err != nil {
return caddy.ExitCodeFailedStartup, return caddy.ExitCodeFailedStartup,
fmt.Errorf("loading additional environment variables: %v", err) fmt.Errorf("loading additional environment variables: %v", err)
} }
@ -181,7 +196,6 @@ func cmdRun(fl Flags) (int, error) {
// load the config, depending on flags // load the config, depending on flags
var config []byte var config []byte
var err error
if runCmdResumeFlag { if runCmdResumeFlag {
config, err = os.ReadFile(caddy.ConfigAutosavePath) config, err = os.ReadFile(caddy.ConfigAutosavePath)
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -497,18 +511,24 @@ func cmdAdaptConfig(fl Flags) (int, error) {
func cmdValidateConfig(fl Flags) (int, error) { func cmdValidateConfig(fl Flags) (int, error) {
validateCmdConfigFlag := fl.String("config") validateCmdConfigFlag := fl.String("config")
validateCmdAdapterFlag := fl.String("adapter") validateCmdAdapterFlag := fl.String("adapter")
runCmdLoadEnvfileFlag := fl.String("envfile")
var err error
var runCmdLoadEnvfileFlag []string
runCmdLoadEnvfileFlag, err = fl.GetStringSlice("envfile")
if err != nil {
return caddy.ExitCodeFailedStartup,
fmt.Errorf("reading envfile flag: %v", err)
}
// load all additional envs as soon as possible // load all additional envs as soon as possible
if runCmdLoadEnvfileFlag != "" { for _, envFile := range runCmdLoadEnvfileFlag {
if err := loadEnvFromFile(runCmdLoadEnvfileFlag); err != nil { if err := loadEnvFromFile(envFile); err != nil {
return caddy.ExitCodeFailedStartup, return caddy.ExitCodeFailedStartup,
fmt.Errorf("loading additional environment variables: %v", err) fmt.Errorf("loading additional environment variables: %v", err)
} }
} }
// use default config and ensure a config file is specified // use default config and ensure a config file is specified
var err error
validateCmdConfigFlag, err = configFileWithRespectToDefault(caddy.Log(), validateCmdConfigFlag) validateCmdConfigFlag, err = configFileWithRespectToDefault(caddy.Log(), validateCmdConfigFlag)
if err != nil { if err != nil {
return caddy.ExitCodeFailedStartup, err return caddy.ExitCodeFailedStartup, err

View file

@ -104,7 +104,7 @@ using 'caddy run' instead to keep it in the foreground.
CobraFunc: func(cmd *cobra.Command) { CobraFunc: func(cmd *cobra.Command) {
cmd.Flags().StringP("config", "c", "", "Configuration file") cmd.Flags().StringP("config", "c", "", "Configuration file")
cmd.Flags().StringP("adapter", "a", "", "Name of config adapter to apply") cmd.Flags().StringP("adapter", "a", "", "Name of config adapter to apply")
cmd.Flags().StringP("envfile", "", "", "Environment file to load") cmd.Flags().StringSliceP("envfile", "", []string{}, "Environment file(s) to load")
cmd.Flags().BoolP("watch", "w", false, "Reload changed config file automatically") cmd.Flags().BoolP("watch", "w", false, "Reload changed config file automatically")
cmd.Flags().StringP("pidfile", "", "", "Path of file to which to write process ID") cmd.Flags().StringP("pidfile", "", "", "Path of file to which to write process ID")
cmd.RunE = WrapCommandFuncForCobra(cmdStart) cmd.RunE = WrapCommandFuncForCobra(cmdStart)
@ -150,7 +150,7 @@ option in a local development environment.
CobraFunc: func(cmd *cobra.Command) { CobraFunc: func(cmd *cobra.Command) {
cmd.Flags().StringP("config", "c", "", "Configuration file") cmd.Flags().StringP("config", "c", "", "Configuration file")
cmd.Flags().StringP("adapter", "a", "", "Name of config adapter to apply") cmd.Flags().StringP("adapter", "a", "", "Name of config adapter to apply")
cmd.Flags().StringP("envfile", "", "", "Environment file to load") cmd.Flags().StringSliceP("envfile", "", []string{}, "Environment file(s) to load")
cmd.Flags().BoolP("environ", "e", false, "Print environment") cmd.Flags().BoolP("environ", "e", false, "Print environment")
cmd.Flags().BoolP("resume", "r", false, "Use saved config, if any (and prefer over --config file)") cmd.Flags().BoolP("resume", "r", false, "Use saved config, if any (and prefer over --config file)")
cmd.Flags().BoolP("watch", "w", false, "Watch config file for changes and reload it automatically") cmd.Flags().BoolP("watch", "w", false, "Watch config file for changes and reload it automatically")
@ -301,7 +301,7 @@ the KEY=VALUE format will be loaded into the Caddy process.
CobraFunc: func(cmd *cobra.Command) { CobraFunc: func(cmd *cobra.Command) {
cmd.Flags().StringP("config", "c", "", "Input configuration file") cmd.Flags().StringP("config", "c", "", "Input configuration file")
cmd.Flags().StringP("adapter", "a", "", "Name of config adapter") cmd.Flags().StringP("adapter", "a", "", "Name of config adapter")
cmd.Flags().StringP("envfile", "", "", "Environment file to load") cmd.Flags().StringSliceP("envfile", "", []string{}, "Environment file(s) to load")
cmd.RunE = WrapCommandFuncForCobra(cmdValidateConfig) cmd.RunE = WrapCommandFuncForCobra(cmdValidateConfig)
}, },
}) })
@ -402,7 +402,7 @@ latest versions. EXPERIMENTAL: May be changed or removed.
Short: "Adds Caddy packages (EXPERIMENTAL)", Short: "Adds Caddy packages (EXPERIMENTAL)",
Long: ` Long: `
Downloads an updated Caddy binary with the specified packages (module/plugin) Downloads an updated Caddy binary with the specified packages (module/plugin)
added. Retains existing packages. Returns an error if the any of packages are added. Retains existing packages. Returns an error if the any of packages are
already included. EXPERIMENTAL: May be changed or removed. already included. EXPERIMENTAL: May be changed or removed.
`, `,
CobraFunc: func(cmd *cobra.Command) { CobraFunc: func(cmd *cobra.Command) {
@ -417,8 +417,8 @@ already included. EXPERIMENTAL: May be changed or removed.
Usage: "<packages...>", Usage: "<packages...>",
Short: "Removes Caddy packages (EXPERIMENTAL)", Short: "Removes Caddy packages (EXPERIMENTAL)",
Long: ` Long: `
Downloads an updated Caddy binaries without the specified packages (module/plugin). Downloads an updated Caddy binaries without the specified packages (module/plugin).
Returns an error if any of the packages are not included. Returns an error if any of the packages are not included.
EXPERIMENTAL: May be changed or removed. EXPERIMENTAL: May be changed or removed.
`, `,
CobraFunc: func(cmd *cobra.Command) { CobraFunc: func(cmd *cobra.Command) {
@ -464,40 +464,40 @@ argument of --directory. If the directory does not exist, it will be created.
Use: "completion [bash|zsh|fish|powershell]", Use: "completion [bash|zsh|fish|powershell]",
Short: "Generate completion script", Short: "Generate completion script",
Long: fmt.Sprintf(`To load completions: Long: fmt.Sprintf(`To load completions:
Bash: Bash:
$ source <(%[1]s completion bash) $ source <(%[1]s completion bash)
# To load completions for each session, execute once: # To load completions for each session, execute once:
# Linux: # Linux:
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s $ %[1]s completion bash > /etc/bash_completion.d/%[1]s
# macOS: # macOS:
$ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s $ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
Zsh: Zsh:
# If shell completion is not already enabled in your environment, # If shell completion is not already enabled in your environment,
# you will need to enable it. You can execute the following once: # you will need to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc $ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once: # To load completions for each session, execute once:
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s" $ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
# You will need to start a new shell for this setup to take effect. # You will need to start a new shell for this setup to take effect.
fish: fish:
$ %[1]s completion fish | source $ %[1]s completion fish | source
# To load completions for each session, execute once: # To load completions for each session, execute once:
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish $ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
PowerShell: PowerShell:
PS> %[1]s completion powershell | Out-String | Invoke-Expression PS> %[1]s completion powershell | Out-String | Invoke-Expression
# To load completions for every new session, run: # To load completions for every new session, run:
PS> %[1]s completion powershell > %[1]s.ps1 PS> %[1]s completion powershell > %[1]s.ps1
# and source this file from your PowerShell profile. # and source this file from your PowerShell profile.

View file

@ -300,8 +300,12 @@ func loadEnvFromFile(envFile string) error {
} }
for k, v := range envMap { for k, v := range envMap {
if err := os.Setenv(k, v); err != nil { // do not overwrite existing environment variables
return fmt.Errorf("setting environment variables: %v", err) _, exists := os.LookupEnv(k)
if !exists {
if err := os.Setenv(k, v); err != nil {
return fmt.Errorf("setting environment variables: %v", err)
}
} }
} }