From a826ecc8a49c2f7de8011800b2a80d0c04ceb579 Mon Sep 17 00:00:00 2001 From: dee-see Date: Tue, 1 Sep 2026 11:08:01 +0100 Subject: [PATCH] Fix CLI flag confusion breaking H1 auth `poll h1` ignores `--user`/`--token` due to a viper binding collision with `reports h1`, this causes auth to fail unless using environment variables (which is preferred, to be fair). --- cmd/poll_bc.go | 10 +++++++--- cmd/poll_h1.go | 8 ++++++-- cmd/poll_it.go | 4 +++- cmd/poll_ywh.go | 10 +++++++--- cmd/reports_h1.go | 8 ++++++-- cmd/root.go | 11 +++++++++++ 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/cmd/poll_bc.go b/cmd/poll_bc.go index bd4bc4a..a40205c 100644 --- a/cmd/poll_bc.go +++ b/cmd/poll_bc.go @@ -13,6 +13,13 @@ import ( var pollBcCmd = &cobra.Command{ Use: "bc", Short: "Poll Bugcrowd programs", + PreRunE: func(cmd *cobra.Command, _ []string) error { + return bindViperFlags(cmd, map[string]string{ + "bugcrowd.email": "email", + "bugcrowd.password": "password", + "bugcrowd.otpsecret": "otp-secret", + }) + }, RunE: func(cmd *cobra.Command, _ []string) error { publicOnly, _ := cmd.Flags().GetBool("public-only") token, _ := cmd.Flags().GetString("token") // Token is CLI-only, not from config @@ -49,7 +56,4 @@ func init() { pollBcCmd.Flags().StringP("email", "E", "", "Bugcrowd login email") pollBcCmd.Flags().StringP("password", "P", "", "Bugcrowd login password") pollBcCmd.Flags().StringP("otp-secret", "O", "", "Bugcrowd TOTP secret (base32)") - viper.BindPFlag("bugcrowd.email", pollBcCmd.Flags().Lookup("email")) - viper.BindPFlag("bugcrowd.password", pollBcCmd.Flags().Lookup("password")) - viper.BindPFlag("bugcrowd.otpsecret", pollBcCmd.Flags().Lookup("otp-secret")) } diff --git a/cmd/poll_h1.go b/cmd/poll_h1.go index 22e07bb..651f7aa 100644 --- a/cmd/poll_h1.go +++ b/cmd/poll_h1.go @@ -13,6 +13,12 @@ import ( var pollH1Cmd = &cobra.Command{ Use: "h1", Short: "Poll HackerOne programs", + PreRunE: func(cmd *cobra.Command, _ []string) error { + return bindViperFlags(cmd, map[string]string{ + "hackerone.username": "user", + "hackerone.token": "token", + }) + }, RunE: func(cmd *cobra.Command, _ []string) error { user := viper.GetString("hackerone.username") token := viper.GetString("hackerone.token") @@ -34,7 +40,5 @@ func init() { pollCmd.AddCommand(pollH1Cmd) pollH1Cmd.Flags().StringP("user", "u", "", "HackerOne username") pollH1Cmd.Flags().StringP("token", "t", "", "HackerOne API token") - viper.BindPFlag("hackerone.username", pollH1Cmd.Flags().Lookup("user")) - viper.BindPFlag("hackerone.token", pollH1Cmd.Flags().Lookup("token")) // Reuse common flags from parent via cobra's flag inheritance } diff --git a/cmd/poll_it.go b/cmd/poll_it.go index 8439525..2e25498 100644 --- a/cmd/poll_it.go +++ b/cmd/poll_it.go @@ -13,6 +13,9 @@ import ( var pollItCmd = &cobra.Command{ Use: "it", Short: "Poll Intigriti programs", + PreRunE: func(cmd *cobra.Command, _ []string) error { + return bindViperFlags(cmd, map[string]string{"intigriti.token": "token"}) + }, RunE: func(cmd *cobra.Command, _ []string) error { token := viper.GetString("intigriti.token") if token == "" { @@ -37,5 +40,4 @@ var pollItCmd = &cobra.Command{ func init() { pollCmd.AddCommand(pollItCmd) pollItCmd.Flags().StringP("token", "t", "", "Intigriti authorization token (Bearer)") - viper.BindPFlag("intigriti.token", pollItCmd.Flags().Lookup("token")) } diff --git a/cmd/poll_ywh.go b/cmd/poll_ywh.go index 723f72f..226ffc0 100644 --- a/cmd/poll_ywh.go +++ b/cmd/poll_ywh.go @@ -13,6 +13,13 @@ import ( var pollYwhCmd = &cobra.Command{ Use: "ywh", Short: "Poll YesWeHack programs", + PreRunE: func(cmd *cobra.Command, _ []string) error { + return bindViperFlags(cmd, map[string]string{ + "yeswehack.email": "email", + "yeswehack.password": "password", + "yeswehack.otpsecret": "otp-secret", + }) + }, RunE: func(cmd *cobra.Command, _ []string) error { token, _ := cmd.Flags().GetString("token") // Token is CLI-only, not from config email := viper.GetString("yeswehack.email") @@ -42,7 +49,4 @@ func init() { pollYwhCmd.Flags().StringP("email", "E", "", "YesWeHack login email") pollYwhCmd.Flags().StringP("password", "P", "", "YesWeHack login password") pollYwhCmd.Flags().StringP("otp-secret", "O", "", "YesWeHack TOTP secret (base32)") - viper.BindPFlag("yeswehack.email", pollYwhCmd.Flags().Lookup("email")) - viper.BindPFlag("yeswehack.password", pollYwhCmd.Flags().Lookup("password")) - viper.BindPFlag("yeswehack.otpsecret", pollYwhCmd.Flags().Lookup("otp-secret")) } diff --git a/cmd/reports_h1.go b/cmd/reports_h1.go index 9d8dde2..23f1f7c 100644 --- a/cmd/reports_h1.go +++ b/cmd/reports_h1.go @@ -18,6 +18,12 @@ import ( var reportsH1Cmd = &cobra.Command{ Use: "h1", Short: "Download reports from HackerOne", + PreRunE: func(cmd *cobra.Command, _ []string) error { + return bindViperFlags(cmd, map[string]string{ + "hackerone.username": "user", + "hackerone.token": "token", + }) + }, RunE: func(cmd *cobra.Command, _ []string) error { user := viper.GetString("hackerone.username") token := viper.GetString("hackerone.token") @@ -59,8 +65,6 @@ func init() { reportsCmd.AddCommand(reportsH1Cmd) reportsH1Cmd.Flags().StringP("user", "u", "", "HackerOne username") reportsH1Cmd.Flags().StringP("token", "t", "", "HackerOne API token") - viper.BindPFlag("hackerone.username", reportsH1Cmd.Flags().Lookup("user")) - viper.BindPFlag("hackerone.token", reportsH1Cmd.Flags().Lookup("token")) } func runReportsH1(ctx context.Context, fetcher *reports.H1Fetcher, opts reports.FetchOptions) error { diff --git a/cmd/root.go b/cmd/root.go index ce455db..86703b0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -135,6 +135,17 @@ func initConfig() { } +// bindViperFlags binds flags to viper keys for the command being run. Binding in +// init() instead would let commands sharing a viper key clobber each other. +func bindViperFlags(cmd *cobra.Command, bindings map[string]string) error { + for key, name := range bindings { + if err := viper.BindPFlag(key, cmd.Flags().Lookup(name)); err != nil { + return err + } + } + return nil +} + func GetDBConnectionString() (string, error) { url := viper.GetString("db_url") if url == "" {