Skip to content

Commit cc12e68

Browse files
authored
refactor to support dynamic github app tokens (#428)
1 parent 6e1c50a commit cc12e68

File tree

8 files changed

+210
-289
lines changed

8 files changed

+210
-289
lines changed

cmd/controller.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"github.com/zapier/kubechecks/pkg/config"
1919
"github.com/zapier/kubechecks/pkg/container"
2020
"github.com/zapier/kubechecks/pkg/events"
21-
"github.com/zapier/kubechecks/pkg/git"
2221
"github.com/zapier/kubechecks/pkg/server"
2322
"github.com/zapier/kubechecks/telemetry"
2423
)
@@ -64,11 +63,6 @@ var ControllerCmd = &cobra.Command{
6463
log.Info().Msgf("not monitoring applications, MonitorAllApplications: %+v", cfg.MonitorAllApplications)
6564
}
6665

67-
log.Info().Msg("initializing git settings")
68-
if err = initializeGit(ctr); err != nil {
69-
log.Fatal().Err(err).Msg("failed to initialize git settings")
70-
}
71-
7266
log.Info().Strs("locations", cfg.PoliciesLocation).Msg("processing policies locations")
7367
if err = processLocations(ctx, ctr, cfg.PoliciesLocation); err != nil {
7468
log.Fatal().Err(err).Msg("failed to process policy locations")
@@ -113,14 +107,6 @@ func startWebserver(ctx context.Context, ctr container.Container, processors []c
113107
go srv.Start(ctx)
114108
}
115109

116-
func initializeGit(ctr container.Container) error {
117-
if err := git.SetCredentials(ctr.Config, ctr.VcsClient); err != nil {
118-
return err
119-
}
120-
121-
return nil
122-
}
123-
124110
func waitForPendingRequest() {
125111
for events.GetInFlight() > 0 {
126112
log.Info().Int("count", events.GetInFlight()).Msg("waiting for in-flight requests to complete")

cmd/process.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,6 @@ var processCmd = &cobra.Command{
5757
log.Fatal().Err(err).Msg("failed to create clients")
5858
}
5959

60-
log.Info().Msg("initializing git settings")
61-
if err = initializeGit(ctr); err != nil {
62-
log.Fatal().Err(err).Msg("failed to initialize git settings")
63-
}
64-
6560
repo, err := ctr.VcsClient.LoadHook(ctx, args[0])
6661
if err != nil {
6762
log.Fatal().Err(err).Msg("failed to load hook")

pkg/config/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"fmt"
45
"reflect"
56
"strings"
67
"time"
@@ -126,6 +127,10 @@ func NewWithViper(v *viper.Viper) (ServerConfig, error) {
126127
return cfg, errors.Wrap(err, "failed to read configuration")
127128
}
128129

130+
if cfg.VcsBaseUrl == "" {
131+
cfg.VcsBaseUrl = fmt.Sprintf("https://%s.com", cfg.VcsType)
132+
}
133+
129134
log.Info().Msg("Server Configuration: ")
130135
log.Info().Msgf("Webhook URL Base: %s", cfg.WebhookUrlBase)
131136
log.Info().Msgf("Webhook URL Prefix: %s", cfg.UrlPrefix)

pkg/container/main.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
client "github.com/zapier/kubechecks/pkg/kubernetes"
1010
"github.com/zapier/kubechecks/pkg/vcs/github_client"
1111
"github.com/zapier/kubechecks/pkg/vcs/gitlab_client"
12+
"go.opentelemetry.io/otel"
1213

1314
"github.com/zapier/kubechecks/pkg/appdir"
1415
"github.com/zapier/kubechecks/pkg/argo_client"
@@ -17,6 +18,8 @@ import (
1718
"github.com/zapier/kubechecks/pkg/vcs"
1819
)
1920

21+
var tracer = otel.Tracer("pkg/container")
22+
2023
type Container struct {
2124
ArgoClient *argo_client.ArgoClient
2225

@@ -36,6 +39,9 @@ type ReposCache interface {
3639
}
3740

3841
func New(ctx context.Context, cfg config.ServerConfig) (Container, error) {
42+
ctx, span := tracer.Start(ctx, "New")
43+
defer span.End()
44+
3945
var err error
4046

4147
var ctr = Container{
@@ -46,9 +52,9 @@ func New(ctx context.Context, cfg config.ServerConfig) (Container, error) {
4652
// create vcs client
4753
switch cfg.VcsType {
4854
case "gitlab":
49-
ctr.VcsClient, err = gitlab_client.CreateGitlabClient(cfg)
55+
ctr.VcsClient, err = gitlab_client.CreateGitlabClient(ctx, cfg)
5056
case "github":
51-
ctr.VcsClient, err = github_client.CreateGithubClient(cfg)
57+
ctr.VcsClient, err = github_client.CreateGithubClient(ctx, cfg)
5258
default:
5359
err = fmt.Errorf("unknown vcs-type: %q", cfg.VcsType)
5460
}

pkg/git/repo.go

Lines changed: 13 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package git
33
import (
44
"bufio"
55
"context"
6-
"encoding/json"
76
"fmt"
8-
"io"
97
"io/fs"
108
"net/http"
119
"net/url"
@@ -14,7 +12,6 @@ import (
1412
"path/filepath"
1513
"strings"
1614
"sync"
17-
"time"
1815

1916
"github.com/pkg/errors"
2017
"github.com/rs/zerolog/log"
@@ -23,7 +20,6 @@ import (
2320

2421
"github.com/zapier/kubechecks/pkg"
2522
"github.com/zapier/kubechecks/pkg/config"
26-
"github.com/zapier/kubechecks/pkg/vcs"
2723
"github.com/zapier/kubechecks/telemetry"
2824
)
2925

@@ -213,7 +209,7 @@ func (r *Repo) MergeIntoTarget(ctx context.Context, ref string) error {
213209
attribute.String("sha", ref),
214210
))
215211
defer span.End()
216-
merge_command := []string{"merge", ref}
212+
mergeCommand := []string{"merge", ref}
217213
// For shallow clones, we need to pull the ref into the repo
218214
if r.Shallow {
219215
ref = strings.TrimPrefix(ref, "origin/")
@@ -227,10 +223,10 @@ func (r *Repo) MergeIntoTarget(ctx context.Context, ref string) error {
227223
// When merging shallow clones, we need to allow unrelated histories
228224
// and use the "theirs" strategy to avoid conflicts
229225
// cons of this is that it may not be entirely accurate and may overwrite changes in the target branch
230-
merge_command = []string{"merge", ref, "--allow-unrelated-histories", "-X", "theirs"}
226+
mergeCommand = []string{"merge", ref, "--allow-unrelated-histories", "-X", "theirs"}
231227
}
232228

233-
cmd := r.execGitCommand(merge_command...)
229+
cmd := r.execGitCommand(mergeCommand...)
234230
out, err := cmd.CombinedOutput()
235231
if err != nil {
236232
telemetry.SetError(span, err, "merge commit into branch")
@@ -298,10 +294,9 @@ func censorVcsToken(cfg config.ServerConfig, args []string) []string {
298294
}
299295

300296
// SetCredentials ensures Git auth is set up for cloning
301-
func SetCredentials(cfg config.ServerConfig, vcsClient vcs.Client) error {
302-
email := vcsClient.Email()
303-
username := vcsClient.Username()
304-
cloneUsername := vcsClient.CloneUsername()
297+
func SetCredentials(ctx context.Context, cfg config.ServerConfig, email, username, cloneUrl string) error {
298+
_, span := tracer.Start(ctx, "SetCredentials")
299+
defer span.End()
305300

306301
cmd := execCommand(cfg, "git", "config", "--global", "user.email", email)
307302
err := cmd.Run()
@@ -315,14 +310,6 @@ func SetCredentials(cfg config.ServerConfig, vcsClient vcs.Client) error {
315310
return errors.Wrap(err, "failed to set git user name")
316311
}
317312

318-
httpClient := &http.Client{
319-
Timeout: 30 * time.Second,
320-
}
321-
cloneUrl, err := getCloneUrl(cloneUsername, cfg, httpClient)
322-
if err != nil {
323-
return errors.Wrap(err, "failed to get clone url")
324-
}
325-
326313
homedir, err := os.UserHomeDir()
327314
if err != nil {
328315
return errors.Wrap(err, "unable to get home directory")
@@ -350,73 +337,17 @@ func SetCredentials(cfg config.ServerConfig, vcsClient vcs.Client) error {
350337
return nil
351338
}
352339

353-
func getCloneUrl(user string, cfg config.ServerConfig, httpClient HTTPClient) (string, error) {
354-
vcsBaseUrl := cfg.VcsBaseUrl
355-
vcsType := cfg.VcsType
356-
vcsToken := cfg.VcsToken
357-
340+
func BuildCloneURL(baseURL, user, password string) (string, error) {
358341
var hostname, scheme string
359342

360-
if vcsBaseUrl == "" {
361-
// hack: but it does happen to work for now
362-
hostname = fmt.Sprintf("%s.com", vcsType)
363-
scheme = "https"
364-
} else {
365-
parts, err := url.Parse(vcsBaseUrl)
366-
if err != nil {
367-
return "", errors.Wrapf(err, "failed to parse %q", vcsBaseUrl)
368-
}
369-
hostname = parts.Host
370-
scheme = parts.Scheme
371-
}
372-
373-
if cfg.IsGithubApp() {
374-
stringAppId := fmt.Sprintf("%d", cfg.GithubAppID)
375-
jwt, err := pkg.CreateJWT(cfg.GithubPrivateKey, stringAppId)
376-
if err != nil {
377-
return "", errors.Wrapf(err, "failed to create jwt")
378-
}
379-
url := fmt.Sprintf("https://api.github.com/app/installations/%d/access_tokens", cfg.GithubInstallationID)
380-
381-
req, err := http.NewRequest(http.MethodPost, url, nil)
382-
if err != nil {
383-
return "", errors.Wrapf(err, "failed to create request")
384-
}
385-
req.Header.Add("Accept", "application/vnd.github.v3+json")
386-
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", jwt))
387-
388-
resp, err := httpClient.Do(req)
389-
if err != nil {
390-
return "", errors.Wrapf(err, "failed to get response")
391-
}
392-
defer func() {
393-
if closeErr := resp.Body.Close(); closeErr != nil {
394-
log.Warn().Err(closeErr).Msg("failed to close response body")
395-
}
396-
}()
397-
398-
body, err := io.ReadAll(resp.Body)
399-
if err != nil {
400-
return "", errors.Wrapf(err, "failed to read response")
401-
}
402-
403-
var result interface{}
404-
err = json.Unmarshal(body, &result)
405-
if err != nil {
406-
return "", errors.Wrapf(err, "failed to unmarshal response")
407-
}
408-
409-
data, ok := result.(map[string]interface{})
410-
if !ok {
411-
return "", errors.New("failed to convert response to map")
412-
}
413-
414-
if token, ok := data["token"].(string); ok {
415-
vcsToken = token
416-
}
343+
parts, err := url.Parse(baseURL)
344+
if err != nil {
345+
return "", errors.Wrapf(err, "failed to parse %q", baseURL)
417346
}
347+
hostname = parts.Host
348+
scheme = parts.Scheme
418349

419-
return fmt.Sprintf("%s://%s:%s@%s", scheme, user, vcsToken, hostname), nil
350+
return fmt.Sprintf("%s://%s:%s@%s", scheme, user, password, hostname), nil
420351
}
421352

422353
// GetListOfChangedFiles returns a list of files that have changed between the current branch and the target branch

0 commit comments

Comments
 (0)