Skip to content

Commit 945f2d0

Browse files
committed
Merge remote-tracking branch 'origin/main' into replan
# Conflicts: # pkg/vcs/github_client/client.go
2 parents 2ae2b15 + c08c70b commit 945f2d0

File tree

10 files changed

+93
-43
lines changed

10 files changed

+93
-43
lines changed

.github/actions/build-image/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ runs:
4444

4545
- name: Build and push the Docker image
4646
shell: bash
47-
run: >-
47+
run: >-
4848
./earthly.sh
4949
${{ inputs.push == 'true' && '--push' || '' }}
5050
+docker-multiarch

cmd/root.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func init() {
4545
zerolog.LevelDebugValue,
4646
zerolog.LevelTraceValue,
4747
).
48-
withDefault("info").
48+
withDefault(zerolog.LevelInfoValue).
4949
withShortHand("l"),
5050
)
5151
boolFlag(flags, "persist-log-level", "Persists the set log level down to other module loggers.")
@@ -56,6 +56,11 @@ func init() {
5656
withChoices("github", "gitlab").
5757
withDefault("gitlab"))
5858
stringFlag(flags, "vcs-token", "VCS API token.")
59+
stringFlag(flags, "vcs-username", "VCS Username.")
60+
stringFlag(flags, "vcs-email", "VCS Email.")
61+
stringFlag(flags, "github-private-key", "Github App Private Key.")
62+
int64Flag(flags, "github-app-id", "Github App ID.")
63+
int64Flag(flags, "github-installation-id", "Github Installation ID.")
5964
stringFlag(flags, "argocd-api-token", "ArgoCD API token.")
6065
stringFlag(flags, "argocd-api-server-addr", "ArgoCD API Server Address.",
6166
newStringOpts().
@@ -124,7 +129,10 @@ func setupLogOutput() {
124129

125130
// Default level is info, unless debug flag is present
126131
levelFlag := viper.GetString("log-level")
127-
level, _ := zerolog.ParseLevel(levelFlag)
132+
level, err := zerolog.ParseLevel(levelFlag)
133+
if err != nil {
134+
log.Error().Err(err).Msg("Invalid log level")
135+
}
128136

129137
zerolog.SetGlobalLevel(level)
130138
log.Debug().Msg("Debug level logging enabled.")

docs/usage.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ The full list of supported environment variables is described below:
4747
|`KUBECHECKS_ENABLE_PREUPGRADE`|Enable preupgrade checks.|`true`|
4848
|`KUBECHECKS_ENSURE_WEBHOOKS`|Ensure that webhooks are created in repositories referenced by argo.|`false`|
4949
|`KUBECHECKS_FALLBACK_K8S_VERSION`|Fallback target Kubernetes version for schema / upgrade checks.|`1.23.0`|
50+
|`KUBECHECKS_GITHUB_APP_ID`|Github App ID.|`0`|
51+
|`KUBECHECKS_GITHUB_INSTALLATION_ID`|Github Installation ID.|`0`|
52+
|`KUBECHECKS_GITHUB_PRIVATE_KEY`|Github App Private Key.||
5053
|`KUBECHECKS_KUBERNETES_CLUSTERID`|Kubernetes Cluster ID, must be specified if kubernetes-type is eks.||
5154
|`KUBECHECKS_KUBERNETES_CONFIG`|Path to your kubernetes config file, used to monitor applications.||
5255
|`KUBECHECKS_KUBERNETES_TYPE`|Kubernetes Type One of eks, or local.|`local`|
@@ -67,9 +70,11 @@ The full list of supported environment variables is described below:
6770
|`KUBECHECKS_SHOW_DEBUG_INFO`|Set to true to print debug info to the footer of MR comments.|`false`|
6871
|`KUBECHECKS_TIDY_OUTDATED_COMMENTS_MODE`|Sets the mode to use when tidying outdated comments. One of hide, delete.|`hide`|
6972
|`KUBECHECKS_VCS_BASE_URL`|VCS base url, useful if self hosting gitlab, enterprise github, etc.||
73+
|`KUBECHECKS_VCS_EMAIL`|VCS Email.||
7074
|`KUBECHECKS_VCS_TOKEN`|VCS API token.||
7175
|`KUBECHECKS_VCS_TYPE`|VCS type. One of gitlab or github.|`gitlab`|
7276
|`KUBECHECKS_VCS_UPLOAD_URL`|VCS upload url, required for enterprise github.||
77+
|`KUBECHECKS_VCS_USERNAME`|VCS Username.||
7378
|`KUBECHECKS_WEBHOOK_SECRET`|Optional secret key for validating the source of incoming webhooks.||
7479
|`KUBECHECKS_WEBHOOK_URL_BASE`|The endpoint to listen on for incoming PR/MR event webhooks. For example, 'https://checker.mycompany.com'.||
7580
|`KUBECHECKS_WEBHOOK_URL_PREFIX`|If your application is running behind a proxy that uses path based routing, set this value to match the path prefix. For example, '/hello/world'.||

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/aws/aws-sdk-go-v2/service/eks v1.46.0
1313
github.com/aws/aws-sdk-go-v2/service/sts v1.30.1
1414
github.com/aws/smithy-go v1.20.3
15+
github.com/bradleyfalzon/ghinstallation/v2 v2.6.0
1516
github.com/cenkalti/backoff/v4 v4.3.0
1617
github.com/chainguard-dev/git-urls v1.0.2
1718
github.com/creasty/defaults v1.7.0
@@ -105,7 +106,6 @@ require (
105106
github.com/blang/semver/v4 v4.0.0 // indirect
106107
github.com/bmatcuk/doublestar/v4 v4.6.0 // indirect
107108
github.com/bombsimon/logrusr/v2 v2.0.1 // indirect
108-
github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 // indirect
109109
github.com/bufbuild/protocompile v0.6.0 // indirect
110110
github.com/cespare/xxhash/v2 v2.3.0 // indirect
111111
github.com/chai2010/gettext-go v1.0.2 // indirect

pkg/config/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,18 @@ type ServerConfig struct {
3333
OtelCollectorPort string `mapstructure:"otel-collector-port"`
3434

3535
// vcs
36+
VcsUsername string `mapstructure:"vcs-username"`
37+
VcsEmail string `mapstructure:"vcs-email"`
3638
VcsBaseUrl string `mapstructure:"vcs-base-url"`
3739
VcsUploadUrl string `mapstructure:"vcs-upload-url"` // github enterprise upload URL
3840
VcsToken string `mapstructure:"vcs-token"`
3941
VcsType string `mapstructure:"vcs-type"`
4042

43+
//github
44+
GithubPrivateKey string `mapstructure:"github-private-key"`
45+
GithubAppID int64 `mapstructure:"github-app-id"`
46+
GithubInstallationID int64 `mapstructure:"github-installation-id"`
47+
4148
// webhooks
4249
EnsureWebhooks bool `mapstructure:"ensure-webhooks"`
4350
WebhookSecret string `mapstructure:"webhook-secret"`

pkg/events/check.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ func (ce *CheckEvent) getRepo(ctx context.Context, vcsClient hasUsername, cloneU
201201
ce.clonedRepos[reposKey] = repo
202202

203203
// if we cloned 'HEAD', figure out its original branch and store a copy of the repo there
204-
if branchName == "" || branchName == "HEAD" {
204+
if branchName == "HEAD" {
205205
remoteHeadBranchName, err := repo.GetRemoteHead()
206206
if err != nil {
207207
return repo, errors.Wrap(err, "failed to determine remote head")
@@ -260,12 +260,17 @@ func (ce *CheckEvent) Process(ctx context.Context) error {
260260

261261
if len(ce.affectedItems.Applications) <= 0 && len(ce.affectedItems.ApplicationSets) <= 0 {
262262
ce.logger.Info().Msg("No affected apps or appsets, skipping")
263-
ce.ctr.VcsClient.PostMessage(ctx, ce.pullRequest, "No changes")
263+
if _, err := ce.ctr.VcsClient.PostMessage(ctx, ce.pullRequest, "No changes"); err != nil {
264+
return errors.Wrap(err, "failed to post changes")
265+
}
264266
return nil
265267
}
266268

267269
// We make one comment per run, containing output for all the apps
268-
ce.vcsNote = ce.createNote(ctx)
270+
ce.vcsNote, err = ce.createNote(ctx)
271+
if err != nil {
272+
return errors.Wrap(err, "failed to create note")
273+
}
269274

270275
for num := 0; num <= ce.ctr.Config.MaxConcurrenctChecks; num++ {
271276

@@ -375,8 +380,8 @@ Check kubechecks application logs for more information.
375380
`
376381
)
377382

378-
// Creates a generic Note struct that we can write into across all worker threads
379-
func (ce *CheckEvent) createNote(ctx context.Context) *msg.Message {
383+
// createNote creates a generic Note struct that we can write into across all worker threads
384+
func (ce *CheckEvent) createNote(ctx context.Context) (*msg.Message, error) {
380385
ctx, span := otel.Tracer("check").Start(ctx, "createNote")
381386
defer span.End()
382387

pkg/vcs/github_client/client.go

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strconv"
1010
"strings"
1111

12+
"github.com/bradleyfalzon/ghinstallation/v2"
1213
giturls "github.com/chainguard-dev/git-urls"
1314
"github.com/google/go-github/v62/github"
1415
"github.com/pkg/errors"
@@ -48,37 +49,26 @@ func CreateGithubClient(cfg config.ServerConfig) (*Client, error) {
4849
shurcoolClient *githubv4.Client
4950
)
5051

51-
// Initialize the GitLab client with access token
52-
t := cfg.VcsToken
53-
if t == "" {
54-
log.Fatal().Msg("github token needs to be set")
55-
}
56-
log.Debug().Msgf("Token Length - %d", len(t))
5752
ctx := context.Background()
58-
ts := oauth2.StaticTokenSource(
59-
&oauth2.Token{AccessToken: t},
60-
)
61-
tc := oauth2.NewClient(ctx, ts)
53+
54+
githubClient, err := createHttpClient(ctx, cfg)
55+
if err != nil {
56+
return nil, errors.Wrap(err, "failed to create github http client")
57+
}
6258

6359
githubUrl := cfg.VcsBaseUrl
6460
githubUploadUrl := cfg.VcsUploadUrl
6561
// we need both urls to be set for github enterprise
6662
if githubUrl == "" || githubUploadUrl == "" {
67-
googleClient = github.NewClient(tc) // If this has failed, we'll catch it on first call
63+
googleClient = github.NewClient(githubClient) // If this has failed, we'll catch it on first call
6864

69-
// Use the client from shurcooL's githubv4 library for queries.
70-
shurcoolClient = githubv4.NewClient(tc)
65+
shurcoolClient = githubv4.NewClient(githubClient)
7166
} else {
72-
googleClient, err = github.NewClient(tc).WithEnterpriseURLs(githubUrl, githubUploadUrl)
67+
googleClient, err = github.NewClient(githubClient).WithEnterpriseURLs(githubUrl, githubUploadUrl)
7368
if err != nil {
7469
log.Fatal().Err(err).Msg("failed to create github enterprise client")
7570
}
76-
shurcoolClient = githubv4.NewEnterpriseClient(githubUrl, tc)
77-
}
78-
79-
user, _, err := googleClient.Users.Get(ctx, "")
80-
if err != nil {
81-
return nil, errors.Wrap(err, "failed to get user")
71+
shurcoolClient = githubv4.NewEnterpriseClient(githubUrl, githubClient)
8272
}
8373

8474
client := &Client{
@@ -89,13 +79,20 @@ func CreateGithubClient(cfg config.ServerConfig) (*Client, error) {
8979
Issues: IssuesService{googleClient.Issues},
9080
},
9181
shurcoolClient: shurcoolClient,
82+
username: cfg.VcsUsername,
83+
email: cfg.VcsEmail,
9284
}
93-
if user != nil {
94-
if user.Login != nil {
95-
client.username = *user.Login
96-
}
97-
if user.Email != nil {
98-
client.email = *user.Email
85+
86+
if client.username == "" || client.email == "" {
87+
user, _, err := googleClient.Users.Get(ctx, "")
88+
if err == nil {
89+
if user.Login != nil {
90+
client.username = *user.Login
91+
}
92+
93+
if user.Email != nil {
94+
client.email = *user.Email
95+
}
9996
}
10097
}
10198

@@ -108,6 +105,32 @@ func CreateGithubClient(cfg config.ServerConfig) (*Client, error) {
108105
return client, nil
109106
}
110107

108+
func createHttpClient(ctx context.Context, cfg config.ServerConfig) (*http.Client, error) {
109+
// Initialize the GitHub client with app key if provided
110+
if cfg.GithubAppID != 0 && cfg.GithubInstallationID != 0 && cfg.GithubPrivateKey != "" {
111+
appTransport, err := ghinstallation.New(
112+
http.DefaultTransport, cfg.GithubAppID, cfg.GithubInstallationID, []byte(cfg.GithubPrivateKey),
113+
)
114+
if err != nil {
115+
return nil, errors.Wrap(err, "failed to create github app transport")
116+
}
117+
118+
return &http.Client{Transport: appTransport}, nil
119+
}
120+
121+
// Initialize the GitHub client with access token if app key is not provided
122+
vcsToken := cfg.VcsToken
123+
if vcsToken != "" {
124+
log.Debug().Msgf("Token Length - %d", len(vcsToken))
125+
ts := oauth2.StaticTokenSource(
126+
&oauth2.Token{AccessToken: vcsToken},
127+
)
128+
return oauth2.NewClient(ctx, ts), nil
129+
}
130+
131+
return nil, errors.New("Either GitHub token or GitHub App credentials (App ID, Installation ID, Private Key) must be set")
132+
}
133+
111134
func (c *Client) Username() string { return c.username }
112135
func (c *Client) Email() string { return c.email }
113136
func (c *Client) GetName() string {

pkg/vcs/github_client/message.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strings"
77

88
"github.com/google/go-github/v62/github"
9+
"github.com/pkg/errors"
910
"github.com/rs/zerolog/log"
1011
"github.com/shurcooL/githubv4"
1112

@@ -17,7 +18,7 @@ import (
1718

1819
const MaxCommentLength = 64 * 1024
1920

20-
func (c *Client) PostMessage(ctx context.Context, pr vcs.PullRequest, message string) *msg.Message {
21+
func (c *Client) PostMessage(ctx context.Context, pr vcs.PullRequest, message string) (*msg.Message, error) {
2122
_, span := tracer.Start(ctx, "PostMessageToMergeRequest")
2223
defer span.End()
2324

@@ -37,10 +38,10 @@ func (c *Client) PostMessage(ctx context.Context, pr vcs.PullRequest, message st
3738

3839
if err != nil {
3940
telemetry.SetError(span, err, "Create Pull Request comment")
40-
log.Error().Err(err).Msg("could not post message to PR")
41+
return nil, errors.Wrap(err, "could not post message to PR")
4142
}
4243

43-
return msg.NewMessage(pr.FullName, pr.CheckID, int(*comment.ID), c)
44+
return msg.NewMessage(pr.FullName, pr.CheckID, int(*comment.ID), c), nil
4445
}
4546

4647
func (c *Client) UpdateMessage(ctx context.Context, m *msg.Message, msg string) error {

pkg/vcs/gitlab_client/message.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"strings"
77

8+
"github.com/pkg/errors"
89
"github.com/rs/zerolog/log"
910
"github.com/xanzy/go-gitlab"
1011

@@ -16,8 +17,8 @@ import (
1617

1718
const MaxCommentLength = 1_000_000
1819

19-
func (c *Client) PostMessage(ctx context.Context, pr vcs.PullRequest, message string) *msg.Message {
20-
_, span := tracer.Start(ctx, "PostMessageToMergeRequest")
20+
func (c *Client) PostMessage(ctx context.Context, pr vcs.PullRequest, message string) (*msg.Message, error) {
21+
_, span := tracer.Start(ctx, "PostMessage")
2122
defer span.End()
2223

2324
if len(message) > MaxCommentLength {
@@ -32,10 +33,10 @@ func (c *Client) PostMessage(ctx context.Context, pr vcs.PullRequest, message st
3233
})
3334
if err != nil {
3435
telemetry.SetError(span, err, "Create Merge Request Note")
35-
log.Error().Err(err).Msg("could not post message to MR")
36+
return nil, errors.Wrap(err, "could not post message to MR")
3637
}
3738

38-
return msg.NewMessage(pr.FullName, pr.CheckID, n.ID, c)
39+
return msg.NewMessage(pr.FullName, pr.CheckID, n.ID, c), nil
3940
}
4041

4142
func (c *Client) hideOutdatedMessages(ctx context.Context, projectName string, mergeRequestID int, notes []*gitlab.Note) error {

pkg/vcs/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type WebHookConfig struct {
1717
// Client represents a VCS client
1818
type Client interface {
1919
// PostMessage takes in project name in form "owner/repo" (ie zapier/kubechecks), the PR/MR id, and the actual message
20-
PostMessage(context.Context, PullRequest, string) *msg.Message
20+
PostMessage(context.Context, PullRequest, string) (*msg.Message, error)
2121
// UpdateMessage update a message with new content
2222
UpdateMessage(context.Context, *msg.Message, string) error
2323
// VerifyHook validates a webhook secret and return the body; must be called even if no secret

0 commit comments

Comments
 (0)