diff --git a/cmd/beacon-chain/main.go b/cmd/beacon-chain/main.go index 34ddac4a89..bfe3032aaa 100644 --- a/cmd/beacon-chain/main.go +++ b/cmd/beacon-chain/main.go @@ -177,7 +177,10 @@ func main() { runtimeDebug.SetGCPercent(ctx.Int(flags.SetGCPercent.Name)) } runtime.GOMAXPROCS(runtime.NumCPU()) - return debug.Setup(ctx) + if err := debug.Setup(ctx); err != nil { + return err + } + return cmd.ValidateNoArgs(ctx) } defer func() { diff --git a/cmd/client-stats/main.go b/cmd/client-stats/main.go index 3905fe99f5..5bf2ac023c 100644 --- a/cmd/client-stats/main.go +++ b/cmd/client-stats/main.go @@ -84,7 +84,7 @@ func main() { log.WithError(err).Error("Failed to configuring logging to disk.") } } - return nil + return cmd.ValidateNoArgs(ctx) } defer func() { diff --git a/cmd/slasher/main.go b/cmd/slasher/main.go index af59d54338..fa8c7330d1 100644 --- a/cmd/slasher/main.go +++ b/cmd/slasher/main.go @@ -132,7 +132,10 @@ func main() { } runtime.GOMAXPROCS(runtime.NumCPU()) - return debug.Setup(ctx) + if err := debug.Setup(ctx); err != nil { + return err + } + return cmd.ValidateNoArgs(ctx) } app.After = func(ctx *cli.Context) error { diff --git a/cmd/validator/main.go b/cmd/validator/main.go index 4b81e20564..9c3d0e797d 100644 --- a/cmd/validator/main.go +++ b/cmd/validator/main.go @@ -168,7 +168,10 @@ func main() { } runtime.GOMAXPROCS(runtime.NumCPU()) - return debug.Setup(ctx) + if err := debug.Setup(ctx); err != nil { + return err + } + return cmd.ValidateNoArgs(ctx) } app.After = func(ctx *cli.Context) error { diff --git a/shared/cmd/flags.go b/shared/cmd/flags.go index 14eb7d59c9..7aef06561d 100644 --- a/shared/cmd/flags.go +++ b/shared/cmd/flags.go @@ -2,6 +2,9 @@ package cmd import ( + "fmt" + "strings" + "github.com/prysmaticlabs/prysm/shared/params" "github.com/urfave/cli/v2" "github.com/urfave/cli/v2/altsrc" @@ -250,3 +253,17 @@ func LoadFlagsFromConfig(cliCtx *cli.Context, flags []cli.Flag) error { } return nil } + +// ValidateNoArgs insures that the application is not run with erroneous arguments or flags. +// This function should be used in the app.Before, whenever the application supports a default command. +func ValidateNoArgs(ctx *cli.Context) error { + for _, a := range ctx.Args().Slice() { + if strings.HasPrefix(a, "-") { + continue + } + if c := ctx.App.Command(a); c == nil { + return fmt.Errorf("unrecognized argument: %s", a) + } + } + return nil +} diff --git a/shared/cmd/flags_test.go b/shared/cmd/flags_test.go index 3e4869f840..a4af7dde8d 100644 --- a/shared/cmd/flags_test.go +++ b/shared/cmd/flags_test.go @@ -40,3 +40,35 @@ func TestLoadFlagsFromConfig(t *testing.T) { require.NoError(t, command.Run(context)) require.NoError(t, os.Remove("flags_test.yaml")) } + +func TestValidateNoArgs(t *testing.T) { + app := &cli.App{ + Before: ValidateNoArgs, + Action: func(c *cli.Context) error { + return nil + }, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "foo", + }, + }, + Commands: []*cli.Command{ + { + Name: "bar", + }, + }, + } + + // It should not work with a bogus argument + err := app.Run([]string{"command", "foo"}) + require.ErrorContains(t, "unrecognized argument: foo", err) + // It should work with registered flags + err = app.Run([]string{"command", "--foo=bar"}) + require.NoError(t, err) + // It should work with subcommands. + err = app.Run([]string{"command", "bar"}) + require.NoError(t, err) + // It should fail on unregistered flag (default logic in urfave/cli). + err = app.Run([]string{"command", "bar", "--baz"}) + require.ErrorContains(t, "flag provided but not defined", err) +}