commands: read token from stdin in bridge configuration

Amine Hilaly created

bridge: improve bridge config validation

Change summary

bridge/github/config.go      | 12 +++++++++++-
bridge/gitlab/config.go      | 13 +++++++++++--
bridge/launchpad/config.go   |  8 +++++++-
commands/bridge_configure.go | 22 +++++++++++-----------
4 files changed, 40 insertions(+), 15 deletions(-)

Detailed changes

bridge/github/config.go 🔗

@@ -37,13 +37,18 @@ var (
 	ErrBadProjectURL = errors.New("bad project url")
 )
 
-func (*Github) Configure(repo repository.RepoCommon, params core.BridgeParams) (core.Configuration, error) {
+func (g *Github) Configure(repo repository.RepoCommon, params core.BridgeParams) (core.Configuration, error) {
 	conf := make(core.Configuration)
 	var err error
 	var token string
 	var owner string
 	var project string
 
+	if params.Token != "" &&
+		!(params.URL != "" || (params.Project != "" && params.Owner != "")) {
+		return nil, fmt.Errorf("you must provide a project URL or Owner/Name to configure this bridge with a token")
+	}
+
 	// getting owner and project name
 	if params.Owner != "" && params.Project != "" {
 		// first try to use params if both or project and owner are provided
@@ -106,6 +111,11 @@ func (*Github) Configure(repo repository.RepoCommon, params core.BridgeParams) (
 	conf[keyOwner] = owner
 	conf[keyProject] = project
 
+	err = g.ValidateConfig(conf)
+	if err != nil {
+		return nil, err
+	}
+
 	return conf, nil
 }
 

bridge/gitlab/config.go 🔗

@@ -20,7 +20,7 @@ var (
 	ErrBadProjectURL = errors.New("bad project url")
 )
 
-func (*Gitlab) Configure(repo repository.RepoCommon, params core.BridgeParams) (core.Configuration, error) {
+func (g *Gitlab) Configure(repo repository.RepoCommon, params core.BridgeParams) (core.Configuration, error) {
 	if params.Project != "" {
 		fmt.Println("warning: --project is ineffective for a gitlab bridge")
 	}
@@ -33,6 +33,10 @@ func (*Gitlab) Configure(repo repository.RepoCommon, params core.BridgeParams) (
 	var url string
 	var token string
 
+	if params.Token != "" && params.URL == "" {
+		return nil, fmt.Errorf("you must provide a project URL to configure this bridge with a token")
+	}
+
 	// get project url
 	if params.URL != "" {
 		url = params.URL
@@ -71,10 +75,15 @@ func (*Gitlab) Configure(repo repository.RepoCommon, params core.BridgeParams) (
 	conf[keyToken] = token
 	conf[core.KeyTarget] = target
 
+	err = g.ValidateConfig(conf)
+	if err != nil {
+		return nil, err
+	}
+
 	return conf, nil
 }
 
-func (*Gitlab) ValidateConfig(conf core.Configuration) error {
+func (g *Gitlab) ValidateConfig(conf core.Configuration) error {
 	if v, ok := conf[core.KeyTarget]; !ok {
 		return fmt.Errorf("missing %s key", core.KeyTarget)
 	} else if v != target {

bridge/launchpad/config.go 🔗

@@ -22,7 +22,7 @@ const (
 	defaultTimeout = 60 * time.Second
 )
 
-func (*Launchpad) Configure(repo repository.RepoCommon, params core.BridgeParams) (core.Configuration, error) {
+func (l *Launchpad) Configure(repo repository.RepoCommon, params core.BridgeParams) (core.Configuration, error) {
 	if params.Token != "" {
 		fmt.Println("warning: --token is ineffective for a Launchpad bridge")
 	}
@@ -63,6 +63,12 @@ func (*Launchpad) Configure(repo repository.RepoCommon, params core.BridgeParams
 
 	conf[keyProject] = project
 	conf[core.KeyTarget] = target
+
+	err = l.ValidateConfig(conf)
+	if err != nil {
+		return nil, err
+	}
+
 	return conf, nil
 }
 

commands/bridge_configure.go 🔗

@@ -6,10 +6,8 @@ import (
 	"os"
 	"strconv"
 	"strings"
-	"syscall"
 
 	"github.com/spf13/cobra"
-	"golang.org/x/crypto/ssh/terminal"
 
 	"github.com/MichaelMure/git-bug/bridge"
 	"github.com/MichaelMure/git-bug/bridge/core"
@@ -23,6 +21,7 @@ const (
 )
 
 var (
+	tokenStdin            bool
 	bridgeConfigureName   string
 	bridgeConfigureTarget string
 	bridgeParams          core.BridgeParams
@@ -36,15 +35,6 @@ func runBridgeConfigure(cmd *cobra.Command, args []string) error {
 	defer backend.Close()
 	interrupt.RegisterCleaner(backend.Close)
 
-	termState, err := terminal.GetState(int(syscall.Stdin))
-	if err != nil {
-		return err
-	}
-
-	interrupt.RegisterCleaner(func() error {
-		return terminal.Restore(int(syscall.Stdin), termState)
-	})
-
 	if bridgeConfigureTarget == "" {
 		bridgeConfigureTarget, err = promptTarget()
 		if err != nil {
@@ -64,6 +54,15 @@ func runBridgeConfigure(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
+	if tokenStdin {
+		reader := bufio.NewReader(os.Stdin)
+		token, err := reader.ReadString('\n')
+		if err != nil {
+			return fmt.Errorf("reading from stdin: %v", err)
+		}
+		bridgeParams.Token = strings.TrimSuffix(token, "\n")
+	}
+
 	err = b.Configure(bridgeParams)
 	if err != nil {
 		return err
@@ -192,6 +191,7 @@ func init() {
 	bridgeConfigureCmd.Flags().StringVarP(&bridgeParams.URL, "url", "u", "", "The URL of the target repository")
 	bridgeConfigureCmd.Flags().StringVarP(&bridgeParams.Owner, "owner", "o", "", "The owner of the target repository")
 	bridgeConfigureCmd.Flags().StringVarP(&bridgeParams.Token, "token", "T", "", "The authentication token for the API")
+	bridgeConfigureCmd.Flags().BoolVar(&tokenStdin, "token-stdin", false, "Expect to receive token from stdin and ignore token flag.")
 	bridgeConfigureCmd.Flags().StringVarP(&bridgeParams.Project, "project", "p", "", "The name of the target repository")
 	bridgeConfigureCmd.Flags().SortFlags = false
 }