From efa09f64deb6b4d9706d872e9d50e362de8a50e0 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 21 Jan 2025 20:47:07 -0800 Subject: [PATCH 1/3] feat: allow token-login flag value as filepath to avoid leaking token into shell history --- cmd/auth.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/cmd/auth.go b/cmd/auth.go index e299ded18..f0ebdf244 100644 --- a/cmd/auth.go +++ b/cmd/auth.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" "io" + "os" astroplatformcore "github.com/astronomer/astro-cli/astro-client-platform-core" @@ -38,7 +39,7 @@ func newLoginCommand(coreClient astrocore.CoreClient, platformCoreClient astropl } cmd.Flags().BoolVarP(&shouldDisplayLoginLink, "login-link", "l", false, "Get login link to login on a separate device for cloud CLI login") - cmd.Flags().StringVarP(&token, "token-login", "t", "", "Login with a token for browserless cloud CLI login") + cmd.Flags().StringVarP(&token, "token-login", "t", "", "Login with a token for browserless cloud CLI login. It is recommended to pass a file containing the token to avoid leaking into shell history and environment") cmd.Flags().BoolVarP(&oAuth, "oauth", "o", false, "Do not prompt for local auth for software login") return cmd } @@ -56,10 +57,29 @@ func newLogoutCommand(out io.Writer) *cobra.Command { return cmd } +func isFilePath(path string) bool { + _, err := os.Stat(path) + if err == nil { + return true + } + if os.IsNotExist(err) { + return false + } + return false +} + func login(cmd *cobra.Command, args []string, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer) error { // Silence Usage as we have now validated command input cmd.SilenceUsage = true + if isFilePath(token) { + tok, err := os.ReadFile(token) + if err != nil { + return err + } + token = string(tok) + } + if len(args) == 1 { // check if user provided a valid cloud domain if !context.IsCloudDomain(args[0]) { From a981af7bb5cff58909aa2469e3992c2676922c8a Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Tue, 21 Jan 2025 20:47:13 -0800 Subject: [PATCH 2/3] filepath and direct token unit tests --- cmd/auth_test.go | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/cmd/auth_test.go b/cmd/auth_test.go index 54f272926..1fa278c91 100644 --- a/cmd/auth_test.go +++ b/cmd/auth_test.go @@ -21,13 +21,35 @@ func (s *CmdSuite) TestAuthRootCommand() { s.Contains(output, "Authenticate to Astro or Astronomer Software") } +func setupTokenFile(token string) string { + tmpFile, err := os.CreateTemp("", "testfile_") + if err != nil { + return "" + } + defer tmpFile.Close() + + _, err = tmpFile.Write([]byte(token)) + if err != nil { + return "" + } + return tmpFile.Name() +} + +func withTokenFlag(cmd *cobra.Command, token string) *cobra.Command{ + cmd.Flags().Set("token-login", token) + return cmd +} + func (s *CmdSuite) TestLogin() { buf := new(bytes.Buffer) cloudDomain := "astronomer.io" softwareDomain := "astronomer_dev.com" + token = "fake.jwt.claims" + tokenFilePath := setupTokenFile(token) - cloudLogin = func(domain, token string, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer, shouldDisplayLoginLink bool) error { + cloudLogin = func(domain, tok string, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer, shouldDisplayLoginLink bool) error { s.Equal(cloudDomain, domain) + s.Equal(tok, token) return nil } @@ -39,6 +61,12 @@ func (s *CmdSuite) TestLogin() { // cloud login success login(&cobra.Command{}, []string{cloudDomain}, nil, nil, buf) + // cloud login, token in flag value + login(withTokenFlag(&cobra.Command{}, token), []string{cloudDomain}, nil, nil, buf) + + // cloud login, token in file + login(withTokenFlag(&cobra.Command{}, tokenFilePath), []string{cloudDomain}, nil, nil, buf) + // software login success testUtil.InitTestConfig(testUtil.Initial) login(&cobra.Command{}, []string{softwareDomain}, nil, nil, buf) @@ -47,6 +75,12 @@ func (s *CmdSuite) TestLogin() { testUtil.InitTestConfig(testUtil.CloudPlatform) login(&cobra.Command{}, []string{}, nil, nil, buf) + // no domain, cloud login, token in flag value + login(withTokenFlag(&cobra.Command{}, token), []string{}, nil, nil, buf) + + // no domain, cloud login, token in file + login(withTokenFlag(&cobra.Command{}, tokenFilePath), []string{}, nil, nil, buf) + // no domain, software login testUtil.InitTestConfig(testUtil.SoftwarePlatform) login(&cobra.Command{}, []string{}, nil, nil, buf) From 96ac00891c38d3af9e7722b0015a35ec5335ecb7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 04:50:19 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cmd/auth_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/auth_test.go b/cmd/auth_test.go index 1fa278c91..c2cb0a11c 100644 --- a/cmd/auth_test.go +++ b/cmd/auth_test.go @@ -35,7 +35,7 @@ func setupTokenFile(token string) string { return tmpFile.Name() } -func withTokenFlag(cmd *cobra.Command, token string) *cobra.Command{ +func withTokenFlag(cmd *cobra.Command, token string) *cobra.Command { cmd.Flags().Set("token-login", token) return cmd }