Skip to content

Commit

Permalink
Bugfix: deny empty positional arguments in all commands
Browse files Browse the repository at this point in the history
We expected this function to be provided by Cobra, but it does not make that check.
So, before the some commands accepting positional arguments allowed values like "" or ''.
These are affectively empty strings, that is equivalent to no value in all or commands.

As a matter of fact, some commands were panicking on this, some failing on API level with 400, 401, 404, 405, or 500 errors.
The exact error which happened seems quite random.
In the worst case this could lead to bad behavior, although I found no such use case.

This disallows erroneous (empty) positional arguments once and for all commands.
All (random) misbehaving commands I tried are now fixed.

Signed-off-by: Volodymyr Khoroz <[email protected]>
  • Loading branch information
vkhoroz committed Oct 18, 2023
1 parent cb36004 commit 398be14
Showing 1 changed file with 69 additions and 2 deletions.
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)
}
}

0 comments on commit 398be14

Please sign in to comment.