From ffcd7d8059dfdd4d0f0c337f897de50fc20d747e Mon Sep 17 00:00:00 2001 From: Max Jonas Werner Date: Tue, 2 Nov 2021 09:42:28 +0100 Subject: [PATCH 1/3] feat: prompt for access tokens in 'bootstrap' command This change adds functionality to both, `bootstrap github` and `bootstrap gitlab` to prompt the user for the personal access tokens if those can't be derived from the shell environment. Echoing is turned off for better privacy. Instead of having to interactively type the token or manually paste it from the clipboard, users can also pipe it to Flux which comes in handy e.g. when executing Flux remotely over an SSH connection: ``` $ echo 'asdf' | flux bootstrap github ``` Otherwise, Flux will prompt the user: ``` $ flux bootstrap github Please type your GitHub personal access token: ``` closes #2011 Signed-off-by: Max Jonas Werner --- cmd/flux/bootstrap_github.go | 6 +++++- cmd/flux/bootstrap_gitlab.go | 6 +++++- cmd/flux/main.go | 22 ++++++++++++++++++++++ go.mod | 1 + 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/cmd/flux/bootstrap_github.go b/cmd/flux/bootstrap_github.go index 54b9694f..34f60f6d 100644 --- a/cmd/flux/bootstrap_github.go +++ b/cmd/flux/bootstrap_github.go @@ -111,7 +111,11 @@ func init() { func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error { ghToken := os.Getenv(ghTokenEnvVar) if ghToken == "" { - return fmt.Errorf("%s environment variable not found", ghTokenEnvVar) + var err error + ghToken, err = readPasswordFromStdin("Please type your GitHub personal access token: ") + if err != nil { + return fmt.Errorf("could not read token: %w", err) + } } if err := bootstrapValidate(); err != nil { diff --git a/cmd/flux/bootstrap_gitlab.go b/cmd/flux/bootstrap_gitlab.go index 09bde7f3..24baa03a 100644 --- a/cmd/flux/bootstrap_gitlab.go +++ b/cmd/flux/bootstrap_gitlab.go @@ -108,7 +108,11 @@ func init() { func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error { glToken := os.Getenv(glTokenEnvVar) if glToken == "" { - return fmt.Errorf("%s environment variable not found", glTokenEnvVar) + var err error + glToken, err = readPasswordFromStdin("Please type your GitLab personal access token: ") + if err != nil { + return fmt.Errorf("could not read token: %w", err) + } } if projectNameIsValid, err := regexp.MatchString(gitlabProjectRegex, gitlabArgs.repository); err != nil || !projectNameIsValid { diff --git a/cmd/flux/main.go b/cmd/flux/main.go index 916c4940..86cfba76 100644 --- a/cmd/flux/main.go +++ b/cmd/flux/main.go @@ -17,12 +17,15 @@ limitations under the License. package main import ( + "bufio" + "fmt" "log" "os" "path/filepath" "time" "github.com/spf13/cobra" + "golang.org/x/term" corev1 "k8s.io/api/core/v1" _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -167,3 +170,22 @@ func homeDir() string { } return os.Getenv("USERPROFILE") // windows } + +func readPasswordFromStdin(prompt string) (string, error) { + var out string + var err error + fmt.Fprint(os.Stdout, prompt) + stdinFD := int(os.Stdin.Fd()) + if term.IsTerminal(stdinFD) { + var inBytes []byte + inBytes, err = term.ReadPassword(int(os.Stdin.Fd())) + out = string(inBytes) + } else { + out, err = bufio.NewReader(os.Stdin).ReadString('\n') + } + if err != nil { + return "", fmt.Errorf("could not read from stdin: %w", err) + } + fmt.Println() + return out, nil +} diff --git a/go.mod b/go.mod index d12d1795..ca48bb4d 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/spf13/cobra v1.1.3 github.com/spf13/pflag v1.0.5 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d k8s.io/api v0.22.2 k8s.io/apiextensions-apiserver v0.22.2 k8s.io/apimachinery v0.22.2 From 31771f3575aa5390e35350ddccff01bb7fc55e5d Mon Sep 17 00:00:00 2001 From: Max Jonas Werner Date: Tue, 2 Nov 2021 14:46:15 +0100 Subject: [PATCH 2/3] fix: improve wording Signed-off-by: Max Jonas Werner --- cmd/flux/bootstrap_github.go | 2 +- cmd/flux/bootstrap_gitlab.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/flux/bootstrap_github.go b/cmd/flux/bootstrap_github.go index 34f60f6d..162a85bc 100644 --- a/cmd/flux/bootstrap_github.go +++ b/cmd/flux/bootstrap_github.go @@ -112,7 +112,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error { ghToken := os.Getenv(ghTokenEnvVar) if ghToken == "" { var err error - ghToken, err = readPasswordFromStdin("Please type your GitHub personal access token: ") + ghToken, err = readPasswordFromStdin("Please enter your GitHub personal access token (PAT): ") if err != nil { return fmt.Errorf("could not read token: %w", err) } diff --git a/cmd/flux/bootstrap_gitlab.go b/cmd/flux/bootstrap_gitlab.go index 24baa03a..77557ea0 100644 --- a/cmd/flux/bootstrap_gitlab.go +++ b/cmd/flux/bootstrap_gitlab.go @@ -109,7 +109,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error { glToken := os.Getenv(glTokenEnvVar) if glToken == "" { var err error - glToken, err = readPasswordFromStdin("Please type your GitLab personal access token: ") + glToken, err = readPasswordFromStdin("Please enter your GitLab personal access token (PAT): ") if err != nil { return fmt.Errorf("could not read token: %w", err) } From be1ce74dc528d8b7aa51346e6d1eca6d1ad974b1 Mon Sep 17 00:00:00 2001 From: Max Jonas Werner Date: Sun, 7 Nov 2021 15:06:30 +0100 Subject: [PATCH 3/3] fix: trim CRLF from password read from stdin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bufio's reader.ReadString includes any CRLF characters and we don't want these in the resulting token because this leads to errors in the authentication like this: ``` ✗ failed to get Git repository "https://github.com/kingdon-ci/jenkins-infra": Get "https://api.github.com/repos/kingdon-ci/jenkins-infra": net/http: invalid header field value "Bearer gho_NNNNNsecrettokenMMMMM\n" for key Authorization ``` Signed-off-by: Max Jonas Werner --- cmd/flux/main.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/flux/main.go b/cmd/flux/main.go index 86cfba76..6b00e4b0 100644 --- a/cmd/flux/main.go +++ b/cmd/flux/main.go @@ -22,6 +22,7 @@ import ( "log" "os" "path/filepath" + "strings" "time" "github.com/spf13/cobra" @@ -171,6 +172,9 @@ func homeDir() string { return os.Getenv("USERPROFILE") // windows } +// readPasswordFromStdin reads a password from stdin and returns the input +// with trailing newline and/or carriage return removed. It also makes sure that terminal +// echoing is turned off if stdin is a terminal. func readPasswordFromStdin(prompt string) (string, error) { var out string var err error @@ -187,5 +191,5 @@ func readPasswordFromStdin(prompt string) (string, error) { return "", fmt.Errorf("could not read from stdin: %w", err) } fmt.Println() - return out, nil + return strings.TrimRight(out, "\r\n"), nil }