mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
* feat: Validate Git tokens before consuming them This works the exact same way that the Git credential manager does. It ensures the user token is valid before returning it to the client. It's been manually tested on GitHub, GitLab, and BitBucket. * Fix requested changes
84 lines
2.1 KiB
Go
84 lines
2.1 KiB
Go
package cli
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"os/signal"
|
|
"time"
|
|
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/cli/cliui"
|
|
"github.com/coder/coder/coderd/gitauth"
|
|
"github.com/coder/coder/codersdk"
|
|
"github.com/coder/retry"
|
|
)
|
|
|
|
// gitAskpass is used by the Coder agent to automatically authenticate
|
|
// with Git providers based on a hostname.
|
|
func gitAskpass() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "gitaskpass",
|
|
Hidden: true,
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
ctx := cmd.Context()
|
|
|
|
ctx, stop := signal.NotifyContext(ctx, InterruptSignals...)
|
|
defer stop()
|
|
|
|
user, host, err := gitauth.ParseAskpass(args[0])
|
|
if err != nil {
|
|
return xerrors.Errorf("parse host: %w", err)
|
|
}
|
|
|
|
client, err := createAgentClient(cmd)
|
|
if err != nil {
|
|
return xerrors.Errorf("create agent client: %w", err)
|
|
}
|
|
|
|
token, err := client.WorkspaceAgentGitAuth(ctx, host, false)
|
|
if err != nil {
|
|
var apiError *codersdk.Error
|
|
if errors.As(err, &apiError) && apiError.StatusCode() == http.StatusNotFound {
|
|
// This prevents the "Run 'coder --help' for usage"
|
|
// message from occurring.
|
|
cmd.Printf("%s\n", apiError.Message)
|
|
return cliui.Canceled
|
|
}
|
|
return xerrors.Errorf("get git token: %w", err)
|
|
}
|
|
if token.URL != "" {
|
|
if err := openURL(cmd, token.URL); err == nil {
|
|
cmd.Printf("Your browser has been opened to authenticate with Git:\n\n\t%s\n\n", token.URL)
|
|
} else {
|
|
cmd.Printf("Open the following URL to authenticate with Git:\n\n\t%s\n\n", token.URL)
|
|
}
|
|
|
|
for r := retry.New(250*time.Millisecond, 10*time.Second); r.Wait(ctx); {
|
|
token, err = client.WorkspaceAgentGitAuth(ctx, host, true)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
cmd.Printf("You've been authenticated with Git!\n")
|
|
break
|
|
}
|
|
}
|
|
|
|
if token.Password != "" {
|
|
if user == "" {
|
|
fmt.Fprintln(cmd.OutOrStdout(), token.Username)
|
|
} else {
|
|
fmt.Fprintln(cmd.OutOrStdout(), token.Password)
|
|
}
|
|
} else {
|
|
fmt.Fprintln(cmd.OutOrStdout(), token.Username)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
}
|