package main import ( "context" "errors" "fmt" "net/url" "os" "os/exec" "strings" "time" ) type commandRunner func(context.Context, string, ...string) ([]byte, error) func resolveToken(endpoint string) (string, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() return resolveTokenWith(ctx, endpoint, os.Getenv, runCommand) } func resolveTokenWith(ctx context.Context, endpoint string, getenv func(string) string, run commandRunner) (string, error) { if token := firstNonEmpty( getenv("GH_TOKEN"), getenv("GITHUB_TOKEN"), getenv("GH_ENTERPRISE_TOKEN"), getenv("GITHUB_ENTERPRISE_TOKEN"), ); token != "" { return token, nil } host, err := githubHost(endpoint) if err != nil { return "", err } output, err := run(ctx, "gh", "auth", "token", "--hostname", host) if err != nil { if errors.Is(err, exec.ErrNotFound) { return "", errors.New("no environment token found and gh is not installed; install gh and run `gh auth login`, or set GH_TOKEN") } if ctx.Err() != nil { return "", fmt.Errorf("read authentication from gh: %w", ctx.Err()) } return "", fmt.Errorf("no usable authentication for %s; run `gh auth login --hostname %s`, or set GH_TOKEN: %w", host, host, err) } token := strings.TrimSpace(string(output)) if token == "" { return "", fmt.Errorf("gh returned an empty token for %s; run `gh auth login --hostname %s`", host, host) } return token, nil } func githubHost(endpoint string) (string, error) { parsed, err := url.Parse(endpoint) if err != nil || parsed.Scheme == "" || parsed.Hostname() == "" { return "", fmt.Errorf("invalid GitHub GraphQL endpoint %q", endpoint) } if parsed.Hostname() == "api.github.com" { return "github.com", nil } return parsed.Hostname(), nil } func runCommand(ctx context.Context, name string, args ...string) ([]byte, error) { return exec.CommandContext(ctx, name, args...).Output() }