Skip to content

Commit

Permalink
cmd/cueckoo: start using git credential for github auth
Browse files Browse the repository at this point in the history
We want this for Gerrit, but for consistency and to test it out first,
do it with GitHub first.

Note that we still support the env vars as a fallback for now,
in case anyone struggles with the git credential helper setup.
However, we would recommend to avoid the env vars after this change,
as many git credential helpers like libsecret are safer than env vars.

Once again, verified that runtrybot still works with a dummy CL.

Signed-off-by: Daniel Martí <[email protected]>
Change-Id: Idc188d2168c168c36afd080bed6349e2d042b463
Dispatch-Trailer: {"type":"trybot","CL":557234,"patchset":4,"ref":"refs/changes/34/557234/4","targetBranch":"master"}
  • Loading branch information
mvdan authored and cueckoo committed Aug 3, 2023
1 parent f64378b commit a71db09
Showing 1 changed file with 65 additions and 14 deletions.
79 changes: 65 additions & 14 deletions cmd/cueckoo/cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import (
"encoding/json"
"fmt"
"io"
"net/url"
"os"
"os/exec"
"strings"

"github.com/andygrunwald/go-gerrit"
Expand Down Expand Up @@ -119,16 +121,18 @@ func loadConfig(ctx context.Context) (*config, error) {
}
}

var auth github.BasicAuthTransport
auth.Username, err = mustGetEnv("GITHUB_USER")
if err != nil {
return nil, err
}
auth.Password, err = mustGetEnv("GITHUB_PAT")
if err != nil {
return nil, err
githubUser, githubPassword, err := gitCredentials(ctx, githubURL)
if githubUser == "" || githubPassword == "" || err != nil {
// Fall back to the manual env vars.
githubUser = os.Getenv("GITHUB_USER")
githubPassword = os.Getenv("GITHUB_PAT")
if githubUser == "" || githubPassword == "" {
return nil, fmt.Errorf("configure a git credential helper or set GITHUB_USER and GITHUB_PAT")
}
}
res.githubClient = github.NewClient(auth.Client())
githubAuth := github.BasicAuthTransport{Username: githubUser, Password: githubPassword}
res.githubClient = github.NewClient(githubAuth.Client())

res.gerritClient, err = gerrit.NewClient(res.gerritURL, nil)
if err != nil {
return nil, err
Expand All @@ -137,12 +141,59 @@ func loadConfig(ctx context.Context) (*config, error) {
return &res, nil
}

func mustGetEnv(name string) (string, error) {
val := os.Getenv(name)
if val == "" {
return "", fmt.Errorf("%s is required", name)
func gitCredentials(ctx context.Context, repoURL string) (username, password string, _ error) {
// For example:
//
// $ git credential fill
// protocol=https
// host=example.com
// path=foo.git
// ^D
// protocol=https
// host=example.com
// username=bob
// password=secr3t

u, err := url.Parse(repoURL)
if err != nil {
return "", "", err
}
input := strings.Join([]string{
"protocol=" + u.Scheme,
"host=" + u.Host,
"path=" + u.Path,
}, "\n") + "\n" // `git credential` wants a trailing newline
cmd := exec.CommandContext(ctx, "git", "credential", "fill")
cmd.Stdin = strings.NewReader(input)
outputBytes, err := cmd.Output()
if err != nil {
if err, _ := err.(*exec.ExitError); err != nil {
// stderr was captured by Output
return "", "", fmt.Errorf("failed to run %q: %v:\n%s", cmd.Args, err, err.Stderr)
}
return "", "", fmt.Errorf("failed to run %q: %v", cmd.Args, err)
}
for _, line := range strings.Split(string(outputBytes), "\n") {
if line == "" {
continue // ignore the trailing empty line
}
key, val, ok := strings.Cut(line, "=")
if !ok {
return "", "", fmt.Errorf("invalid output line: %q", line)
}
switch key {
case "protocol", "host", "path":
// input keys are repeated; ignore them.
case "username":
username = val
case "password":
password = val
default:
// Could happen if the user configured an auth mechanism we don't support, like oauth.
return "", "", fmt.Errorf("unknown output line key: %q", line)
}
}
return val, nil
return username, password, nil
}

func (c *config) triggerRepositoryDispatch(owner, repo string, payload github.DispatchRequestOptions) error {
Expand Down

0 comments on commit a71db09

Please sign in to comment.