Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix: deny empty positional arguments in all commands #312

Merged
merged 1 commit into from
Oct 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 69 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ var (
)

var rootCmd = &cobra.Command{
Use: "fioctl",
Short: "Manage Foundries Factories",
Use: "fioctl",
Short: "Manage Foundries Factories",
PersistentPreRunE: rootArgValidation,
}

func Execute() {
Expand Down Expand Up @@ -69,6 +70,7 @@ func Execute() {
}

func init() {
cobra.OnInitialize(func() { fixPersistentPreRuns(rootCmd) })
cobra.OnInitialize(initConfig)

rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.config/fioctl.yaml)")
Expand Down Expand Up @@ -100,6 +102,15 @@ func init() {
rootCmd.AddCommand(docsMdCmd)
}

func rootArgValidation(cmd *cobra.Command, args []string) error {
for pos, val := range args {
if len(strings.TrimSpace(val)) == 0 {
return fmt.Errorf("Empty values or values containing only white space are not allowed for positional argument at %d\n", pos)
}
}
return nil
}

func getConfigDir() string {
config, err := homedir.Expand("~/.config")
if err != nil {
Expand Down Expand Up @@ -202,3 +213,59 @@ $ fioctl completion fish > ~/.config/fish/completions/fioctl.fish
}
},
}

func fixPersistentPreRuns(cmd *cobra.Command) {
// See https://github.com/spf13/cobra/issues/216
parentPreRunE := cmd.PersistentPreRunE
parentPreRun := cmd.PersistentPreRun
// First, traverse up to find a parent defining the PersistentPreRun function.
for p := cmd.Parent(); p != nil && parentPreRunE == nil && parentPreRun == nil; p = p.Parent() {
// Cobra prefers PersistentPreRunE over PersistentPreRun if both are defined, so do we.
// Actually, no our code defines both functions (expected), so that assumption is safe.
if p.PersistentPreRunE != nil {
parentPreRunE = p.PersistentPreRunE
} else if p.PersistentPreRun != nil {
parentPreRun = p.PersistentPreRun
}
}

// Traverse children tree top-down, gradually fixing their PersistentPreRun functions to call into parents.
for _, child := range cmd.Commands() {
preRun := child.PersistentPreRun
preRunE := child.PersistentPreRunE
if preRunE != nil {
if parentPreRunE != nil {
child.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if err := parentPreRunE(cmd, args); err != nil {
return err
}
return preRunE(cmd, args)
}
} else if parentPreRun != nil {
child.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
parentPreRun(cmd, args)
return preRunE(cmd, args)
}
}
} else if preRun != nil {
if parentPreRunE != nil {
// Set the PersistentPreRunE, not PersistentPreRun, so that we can return the parent error into cmd.execute.
child.PersistentPreRun = nil
child.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if err := parentPreRunE(cmd, args); err != nil {
return err
}
preRun(cmd, args)
return nil
}
} else if parentPreRun != nil {
child.PersistentPreRun = func(cmd *cobra.Command, args []string) {
parentPreRun(cmd, args)
preRun(cmd, args)
}
}
}
// Now that this child command was fixed, we can run the magic recursion.
fixPersistentPreRuns(child)
}
}
Loading