From cc3c4300f012bc03af29edd918ad51000e956df3 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Tue, 30 Apr 2024 14:49:54 -0700 Subject: [PATCH 01/18] Initial commit of github apps poc --- cmd/example/main.go | 41 +++++++++++++++++------ go.mod | 9 +++++ go.sum | 22 ++++++++++++ pkg/authentication/request.go | 8 +++-- pkg/authentication/token_provider.go | 12 +++++-- pkg/authentication/token_provider_test.go | 18 +++++----- pkg/client.go | 35 +++++++++++++++++-- 7 files changed, 117 insertions(+), 28 deletions(-) diff --git a/cmd/example/main.go b/cmd/example/main.go index 18281bed..fbb31657 100644 --- a/cmd/example/main.go +++ b/cmd/example/main.go @@ -2,13 +2,13 @@ package main import ( "context" - "fmt" "log" - "os" "time" - abs "github.com/microsoft/kiota-abstractions-go" + abstractions "github.com/microsoft/kiota-abstractions-go" "github.com/octokit/go-sdk/pkg" + "github.com/octokit/go-sdk/pkg/github/user" + "github.com/octokit/go-sdk/pkg/github/user/repos" ) func main() { @@ -16,7 +16,8 @@ func main() { pkg.WithUserAgent("my-user-agent"), pkg.WithRequestTimeout(5*time.Second), pkg.WithBaseUrl("https://api.github.com"), - pkg.WithAuthorizationToken(os.Getenv("GITHUB_TOKEN")), + // pkg.WithAuthorizationToken(os.Getenv("GITHUB_TOKEN")), + pkg.WithGitHubAppAuthentication("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", 131977, 20570954), ) // equally valid: @@ -25,14 +26,34 @@ func main() { log.Fatalf("error creating client: %v", err) } - queryParams := &abs.DefaultQueryParameters{} - requestConfig := &abs.RequestConfiguration[abs.DefaultQueryParameters]{ + viz := repos.ALL_GETVISIBILITYQUERYPARAMETERTYPE + queryParams := &user.ReposRequestBuilderGetQueryParameters{ + Visibility: &viz, + } + requestConfig := &abstractions.RequestConfiguration[user.ReposRequestBuilderGetQueryParameters]{ QueryParameters: queryParams, } - zen, err := client.Zen().Get(context.Background(), requestConfig) + repos, err := client.User().Repos().Get(context.Background(), requestConfig) if err != nil { - fmt.Printf("error getting Zen: %v\n", err) - return + log.Fatalf("error getting repositories: %v", err) + // return err + } + + if len(repos) > 0 { + log.Printf("Repositories:\n") + for _, repo := range repos { + log.Printf("%v\n", *repo.GetFullName()) + } } - fmt.Printf("%v\n", *zen) + + // queryParams := &abs.DefaultQueryParameters{} + // requestConfig := &abs.RequestConfiguration[abs.DefaultQueryParameters]{ + // QueryParameters: queryParams, + // } + // zen, err := client.Zen().Get(context.Background(), requestConfig) + // if err != nil { + // fmt.Printf("error getting Zen: %v\n", err) + // return + // } + // fmt.Printf("%v\n", *zen) } diff --git a/go.mod b/go.mod index 87784957..0804202c 100644 --- a/go.mod +++ b/go.mod @@ -9,13 +9,22 @@ require ( github.com/microsoft/kiota-serialization-json-go v1.0.7 github.com/microsoft/kiota-serialization-multipart-go v1.0.0 github.com/microsoft/kiota-serialization-text-go v1.0.0 + golang.org/x/sync v0.7.0 ) require ( + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/google/go-github/v29 v29.0.2 // indirect + golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 // indirect +) + +require ( + github.com/bradleyfalzon/ghinstallation v1.1.1 github.com/cjlapao/common-go v0.0.39 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/std-uritemplate/std-uritemplate/go v0.0.55 // indirect diff --git a/go.sum b/go.sum index 296304ad..7d4954bd 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,26 @@ +github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I= +github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug= github.com/cjlapao/common-go v0.0.39 h1:bAAUrj2B9v0kMzbAOhzjSmiyDy+rd56r2sy7oEiQLlA= github.com/cjlapao/common-go v0.0.39/go.mod h1:M3dzazLjTjEtZJbbxoA5ZDiGCiHmpwqW9l4UWaddwOA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts= +github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -39,6 +51,16 @@ go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGX go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/authentication/request.go b/pkg/authentication/request.go index 7c3d0cb5..eb553cf6 100644 --- a/pkg/authentication/request.go +++ b/pkg/authentication/request.go @@ -12,15 +12,19 @@ type Request struct { *abs.RequestInformation } -// WithAuthorization sets the Authorization header to the given token, +// WithTokenAuthentication sets the Authorization header to the given token, // prepended by the AuthType -func (r *Request) WithAuthorization(token string) { +func (r *Request) WithTokenAuthentication(token string) { if r.Headers.ContainsKey(headers.AuthorizationKey) { r.Headers.Remove(headers.AuthorizationKey) } r.Headers.Add(headers.AuthorizationKey, fmt.Sprintf("%v %v", headers.AuthType, token)) } +func (r *Request) WithGitHubAppAuthentication(pemFile []byte, appID string) { + // TODO(kfcampbell): do something useful here +} + // WithUserAgent allows the caller to set the User-Agent string for each request func (r *Request) WithUserAgent(userAgent string) { if r.Headers.ContainsKey(headers.UserAgentKey) { diff --git a/pkg/authentication/token_provider.go b/pkg/authentication/token_provider.go index bc558853..9e91762d 100644 --- a/pkg/authentication/token_provider.go +++ b/pkg/authentication/token_provider.go @@ -12,10 +12,16 @@ type TokenProvider struct { type TokenProviderOption func(*TokenProvider, *Request) -// WithAuthorizationToken sets the AuthorizationToken for each request to the given token. -func WithAuthorizationToken(token string) TokenProviderOption { +// WithTokenAuthentication sets the AuthorizationToken for each request to the given token. +func WithTokenAuthentication(token string) TokenProviderOption { return func(t *TokenProvider, r *Request) { - r.WithAuthorization(token) + r.WithTokenAuthentication(token) + } +} + +func WithGitHubApp(pemFile []byte, appID string) TokenProviderOption { + return func(t *TokenProvider, r *Request) { + r.WithGitHubAppAuthentication(pemFile, appID) } } diff --git a/pkg/authentication/token_provider_test.go b/pkg/authentication/token_provider_test.go index 9e4179bc..cfeaa286 100644 --- a/pkg/authentication/token_provider_test.go +++ b/pkg/authentication/token_provider_test.go @@ -18,7 +18,7 @@ import ( func TestTokenIsSetInAuthenticatedRequest(t *testing.T) { token := "help i'm trapped in a Go binary" - provider := authentication.NewTokenProvider(authentication.WithAuthorizationToken(token)) + provider := authentication.NewTokenProvider(authentication.WithTokenAuthentication(token)) reqInfo := abstractions.NewRequestInformation() addtlContext := make(map[string]interface{}) @@ -41,7 +41,7 @@ func TestTokenIsSetInAuthenticatedRequest(t *testing.T) { // TODO(kfcampbell): this code could be refactored to use table-based tests func TestDefaultRequestOptions(t *testing.T) { token := "this is not the token you're looking for" - provider := authentication.NewTokenProvider(authentication.WithAuthorizationToken(token)) + provider := authentication.NewTokenProvider(authentication.WithTokenAuthentication(token)) reqInfo := abstractions.NewRequestInformation() addtlContext := make(map[string]interface{}) @@ -74,7 +74,7 @@ func TestOverwritingDefaultRequestOptions(t *testing.T) { apiVersion := "i'm totally a real API version" userAgent := "i'm totally a real user agent" provider := authentication.NewTokenProvider( - authentication.WithAuthorizationToken(token), + authentication.WithTokenAuthentication(token), authentication.WithAPIVersion(apiVersion), authentication.WithUserAgent(userAgent)) @@ -125,7 +125,7 @@ func TestAnonymousAuthIsAllowed(t *testing.T) { func TestTokenSetInRequestIsNotOverwritten(t *testing.T) { providerToken := "dit dit dit / dat dat dat / dit dit dit" provider := authentication.NewTokenProvider( - authentication.WithAuthorizationToken(providerToken), + authentication.WithTokenAuthentication(providerToken), ) requestToken := "dit dit dit dit / dit / dit dat dit dit / dit dat dat dit" @@ -156,7 +156,7 @@ func TestHappyPathIntegration(t *testing.T) { } provider := authentication.NewTokenProvider( - authentication.WithAuthorizationToken(token), + authentication.WithTokenAuthentication(token), ) adapter, err := http.NewNetHttpRequestAdapter(provider) @@ -170,17 +170,15 @@ func TestHappyPathIntegration(t *testing.T) { // Create a new instance of abstractions.RequestConfiguration requestConfig := &abstractions.RequestConfiguration[user.EmailsRequestBuilderGetQueryParameters]{ - Headers: headers, + Headers: headers, } - - userEmails, err := client.User().Emails().Get(context.Background(), requestConfig) if err != nil { - log.Fatalf("%v\n", err) + log.Fatalf("%v\n", err) } for _, v := range userEmails { - fmt.Printf("%v\n", *v.GetEmail()) + fmt.Printf("%v\n", *v.GetEmail()) } } diff --git a/pkg/client.go b/pkg/client.go index 853d273b..e7be3ba2 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/bradleyfalzon/ghinstallation" kiotaHttp "github.com/microsoft/kiota-http-go" auth "github.com/octokit/go-sdk/pkg/authentication" "github.com/octokit/go-sdk/pkg/github" @@ -23,16 +24,27 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { middlewares := options.Middleware middlewares = append(middlewares, rateLimitHandler) netHttpClient := kiotaHttp.GetDefaultClient(middlewares...) + if options.RequestTimeout != 0 { netHttpClient.Timeout = options.RequestTimeout } + if options.GitHubAppID != 0 && options.GitHubAppInstallationID != 0 && options.GitHubAppPemFilePath != "" { + existingTransport := netHttpClient.Transport + appTransport, err := ghinstallation.NewKeyFromFile(existingTransport, options.GitHubAppID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) + if err != nil { + return nil, fmt.Errorf("failed to create transport from GitHub App: %v", err) + } + netHttpClient.Transport = appTransport + } + tokenProviderOptions := []auth.TokenProviderOption{ auth.WithAPIVersion(options.APIVersion), auth.WithUserAgent(options.UserAgent), } - if options.Token != "" { - tokenProviderOptions = append(tokenProviderOptions, auth.WithAuthorizationToken(options.Token)) + + if options.Token != "" && (options.GitHubAppID == 0 && options.GitHubAppInstallationID == 0 && options.GitHubAppPemFilePath == "") { + tokenProviderOptions = append(tokenProviderOptions, auth.WithTokenAuthentication(options.Token)) } tokenProvider := auth.NewTokenProvider(tokenProviderOptions...) @@ -70,7 +82,16 @@ type ClientOptions struct { RequestTimeout time.Duration Middleware []kiotaHttp.Middleware BaseURL string - Token string + + // Token should be left blank if GitHub App auth or an unauthenticated client is desired. + Token string + + // GitHubAppPemFilePath should be left blank if token auth or an unauthenticated client is desired. + GitHubAppPemFilePath string + // GitHubAppID should be left blank if token auth or an unauthenticated client is desired. + GitHubAppID int64 + // GitHubAppInstallationID should be left blank if token auth or an unauthenticated client is desired. + GitHubAppInstallationID int64 } // GetDefaultClientOptions returns a new instance of ClientOptions with default values. @@ -121,3 +142,11 @@ func WithAPIVersion(version string) ClientOptionFunc { c.APIVersion = version } } + +func WithGitHubAppAuthentication(GitHubAppPemFilePath string, GitHubAppID int64, GitHubAppInstallationID int64) ClientOptionFunc { + return func(c *ClientOptions) { + c.GitHubAppPemFilePath = GitHubAppPemFilePath + c.GitHubAppID = GitHubAppID + c.GitHubAppInstallationID = GitHubAppInstallationID + } +} From d810a54ec8712f14be791ad19078e2f33d1e9d29 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 2 May 2024 14:06:12 -0700 Subject: [PATCH 02/18] Demo of GitHub Apps auth working in go-sdk --- cmd/example/main.go | 28 ++++++---------------------- go.mod | 7 +++---- go.sum | 22 ++++++---------------- pkg/authentication/request.go | 2 +- pkg/client.go | 13 +++++++++++-- 5 files changed, 27 insertions(+), 45 deletions(-) diff --git a/cmd/example/main.go b/cmd/example/main.go index fbb31657..62f13f3e 100644 --- a/cmd/example/main.go +++ b/cmd/example/main.go @@ -7,8 +7,7 @@ import ( abstractions "github.com/microsoft/kiota-abstractions-go" "github.com/octokit/go-sdk/pkg" - "github.com/octokit/go-sdk/pkg/github/user" - "github.com/octokit/go-sdk/pkg/github/user/repos" + "github.com/octokit/go-sdk/pkg/github/installation" ) func main() { @@ -26,34 +25,19 @@ func main() { log.Fatalf("error creating client: %v", err) } - viz := repos.ALL_GETVISIBILITYQUERYPARAMETERTYPE - queryParams := &user.ReposRequestBuilderGetQueryParameters{ - Visibility: &viz, - } - requestConfig := &abstractions.RequestConfiguration[user.ReposRequestBuilderGetQueryParameters]{ + queryParams := &installation.RepositoriesRequestBuilderGetQueryParameters{} + requestConfig := &abstractions.RequestConfiguration[installation.RepositoriesRequestBuilderGetQueryParameters]{ QueryParameters: queryParams, } - repos, err := client.User().Repos().Get(context.Background(), requestConfig) + repos, err := client.Installation().Repositories().Get(context.Background(), requestConfig) if err != nil { log.Fatalf("error getting repositories: %v", err) - // return err } - if len(repos) > 0 { + if len(repos.GetRepositories()) > 0 { log.Printf("Repositories:\n") - for _, repo := range repos { + for _, repo := range repos.GetRepositories() { log.Printf("%v\n", *repo.GetFullName()) } } - - // queryParams := &abs.DefaultQueryParameters{} - // requestConfig := &abs.RequestConfiguration[abs.DefaultQueryParameters]{ - // QueryParameters: queryParams, - // } - // zen, err := client.Zen().Get(context.Background(), requestConfig) - // if err != nil { - // fmt.Printf("error getting Zen: %v\n", err) - // return - // } - // fmt.Printf("%v\n", *zen) } diff --git a/go.mod b/go.mod index 0804202c..507647fd 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/octokit/go-sdk go 1.21.5 require ( + github.com/bradleyfalzon/ghinstallation/v2 v2.10.0 github.com/microsoft/kiota-abstractions-go v1.6.0 github.com/microsoft/kiota-http-go v1.3.3 github.com/microsoft/kiota-serialization-form-go v1.0.0 @@ -13,13 +14,11 @@ require ( ) require ( - github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect - github.com/google/go-github/v29 v29.0.2 // indirect - golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/google/go-github/v60 v60.0.0 // indirect ) require ( - github.com/bradleyfalzon/ghinstallation v1.1.1 github.com/cjlapao/common-go v0.0.39 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.1 // indirect diff --git a/go.sum b/go.sum index 7d4954bd..cba0db9b 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,21 @@ -github.com/bradleyfalzon/ghinstallation v1.1.1 h1:pmBXkxgM1WeF8QYvDLT5kuQiHMcmf+X015GI0KM/E3I= -github.com/bradleyfalzon/ghinstallation v1.1.1/go.mod h1:vyCmHTciHx/uuyN82Zc3rXN3X2KTK8nUTCrTMwAhcug= +github.com/bradleyfalzon/ghinstallation/v2 v2.10.0 h1:XWuWBRFEpqVrHepQob9yPS3Xg4K3Wr9QCx4fu8HbUNg= +github.com/bradleyfalzon/ghinstallation/v2 v2.10.0/go.mod h1:qoGA4DxWPaYTgVCrmEspVSjlTu4WYAiSxMIhorMRXXc= github.com/cjlapao/common-go v0.0.39 h1:bAAUrj2B9v0kMzbAOhzjSmiyDy+rd56r2sy7oEiQLlA= github.com/cjlapao/common-go v0.0.39/go.mod h1:M3dzazLjTjEtZJbbxoA5ZDiGCiHmpwqW9l4UWaddwOA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v29 v29.0.2 h1:opYN6Wc7DOz7Ku3Oh4l7prmkOMwEcQxpFtxdU8N8Pts= -github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-github/v60 v60.0.0 h1:oLG98PsLauFvvu4D/YPxq374jhSxFYdzQGNCyONLfn8= +github.com/google/go-github/v60 v60.0.0/go.mod h1:ByhX2dP9XT9o/ll2yXAu2VD8l5eNVg8hD4Cr0S/LmQk= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -51,16 +48,9 @@ go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGX go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/authentication/request.go b/pkg/authentication/request.go index eb553cf6..1173c3bf 100644 --- a/pkg/authentication/request.go +++ b/pkg/authentication/request.go @@ -22,7 +22,7 @@ func (r *Request) WithTokenAuthentication(token string) { } func (r *Request) WithGitHubAppAuthentication(pemFile []byte, appID string) { - // TODO(kfcampbell): do something useful here + // TODO(kfcampbell): can we do something useful here? otherwise possibly remove } // WithUserAgent allows the caller to set the User-Agent string for each request diff --git a/pkg/client.go b/pkg/client.go index e7be3ba2..5490ad5e 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -2,9 +2,10 @@ package pkg import ( "fmt" + "net/http" "time" - "github.com/bradleyfalzon/ghinstallation" + "github.com/bradleyfalzon/ghinstallation/v2" kiotaHttp "github.com/microsoft/kiota-http-go" auth "github.com/octokit/go-sdk/pkg/authentication" "github.com/octokit/go-sdk/pkg/github" @@ -23,7 +24,10 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { rateLimitHandler := handlers.NewRateLimitHandler() middlewares := options.Middleware middlewares = append(middlewares, rateLimitHandler) - netHttpClient := kiotaHttp.GetDefaultClient(middlewares...) + defaultTransport := kiotaHttp.GetDefaultTransport() + netHttpClient := &http.Client{ + Transport: defaultTransport, + } if options.RequestTimeout != 0 { netHttpClient.Timeout = options.RequestTimeout @@ -38,6 +42,11 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { netHttpClient.Transport = appTransport } + // middleware must be applied after App transport is set, otherwise App token will + // fail to be renewed + finalTransport := kiotaHttp.NewCustomTransportWithParentTransport(netHttpClient.Transport, middlewares...) + netHttpClient.Transport = finalTransport + tokenProviderOptions := []auth.TokenProviderOption{ auth.WithAPIVersion(options.APIVersion), auth.WithUserAgent(options.UserAgent), From 5dbbe406b0a7488a2d3c63ea9e170a1c0950bdef Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 2 May 2024 14:10:48 -0700 Subject: [PATCH 03/18] Remove unnecessary auth configuration functions --- pkg/authentication/request.go | 4 ---- pkg/authentication/token_provider.go | 6 ------ 2 files changed, 10 deletions(-) diff --git a/pkg/authentication/request.go b/pkg/authentication/request.go index 1173c3bf..fcfefb71 100644 --- a/pkg/authentication/request.go +++ b/pkg/authentication/request.go @@ -21,10 +21,6 @@ func (r *Request) WithTokenAuthentication(token string) { r.Headers.Add(headers.AuthorizationKey, fmt.Sprintf("%v %v", headers.AuthType, token)) } -func (r *Request) WithGitHubAppAuthentication(pemFile []byte, appID string) { - // TODO(kfcampbell): can we do something useful here? otherwise possibly remove -} - // WithUserAgent allows the caller to set the User-Agent string for each request func (r *Request) WithUserAgent(userAgent string) { if r.Headers.ContainsKey(headers.UserAgentKey) { diff --git a/pkg/authentication/token_provider.go b/pkg/authentication/token_provider.go index 9e91762d..d306992b 100644 --- a/pkg/authentication/token_provider.go +++ b/pkg/authentication/token_provider.go @@ -19,12 +19,6 @@ func WithTokenAuthentication(token string) TokenProviderOption { } } -func WithGitHubApp(pemFile []byte, appID string) TokenProviderOption { - return func(t *TokenProvider, r *Request) { - r.WithGitHubAppAuthentication(pemFile, appID) - } -} - // WithDefaultUserAgent sets the User-Agent string sent for requests to the default // for this SDK. func WithDefaultUserAgent() TokenProviderOption { From c7a0760fe8ad1b660b892c4365f6fd04d4bb4c51 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 2 May 2024 14:19:55 -0700 Subject: [PATCH 04/18] Docs comments cleanup --- cmd/example/main.go | 4 ++-- pkg/authentication/token_provider.go | 8 ++++++-- pkg/client.go | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cmd/example/main.go b/cmd/example/main.go index 62f13f3e..e7c4ef53 100644 --- a/cmd/example/main.go +++ b/cmd/example/main.go @@ -5,7 +5,7 @@ import ( "log" "time" - abstractions "github.com/microsoft/kiota-abstractions-go" + abs "github.com/microsoft/kiota-abstractions-go" "github.com/octokit/go-sdk/pkg" "github.com/octokit/go-sdk/pkg/github/installation" ) @@ -26,7 +26,7 @@ func main() { } queryParams := &installation.RepositoriesRequestBuilderGetQueryParameters{} - requestConfig := &abstractions.RequestConfiguration[installation.RepositoriesRequestBuilderGetQueryParameters]{ + requestConfig := &abs.RequestConfiguration[installation.RepositoriesRequestBuilderGetQueryParameters]{ QueryParameters: queryParams, } repos, err := client.Installation().Repositories().Get(context.Background(), requestConfig) diff --git a/pkg/authentication/token_provider.go b/pkg/authentication/token_provider.go index d306992b..d610c8db 100644 --- a/pkg/authentication/token_provider.go +++ b/pkg/authentication/token_provider.go @@ -6,10 +6,16 @@ import ( abs "github.com/microsoft/kiota-abstractions-go" ) +// TokenProvider may use a token to authenticate each request. It also can be +// used to configure UserAgent strings, API Versions, and other request configuration. +// Note that GitHub App authentication is set at the client transport level. See the +// docs for pkg.NewApiClient for more. type TokenProvider struct { options []TokenProviderOption } +// TokenProviderOption provides a functional option +// for configuring a TokenProvider. type TokenProviderOption func(*TokenProvider, *Request) // WithTokenAuthentication sets the AuthorizationToken for each request to the given token. @@ -55,7 +61,6 @@ func NewTokenProvider(options ...TokenProviderOption) *TokenProvider { provider := &TokenProvider{ options: options, } - return provider } @@ -80,6 +85,5 @@ func (t *TokenProvider) AuthenticateRequest(context context.Context, request *ab for _, option := range t.options { option(t, reqWrapper) } - return nil } diff --git a/pkg/client.go b/pkg/client.go index 5490ad5e..b0e1e2a7 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -33,6 +33,7 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { netHttpClient.Timeout = options.RequestTimeout } + // Configure GitHub App authentication if required fields are provided if options.GitHubAppID != 0 && options.GitHubAppInstallationID != 0 && options.GitHubAppPemFilePath != "" { existingTransport := netHttpClient.Transport appTransport, err := ghinstallation.NewKeyFromFile(existingTransport, options.GitHubAppID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) @@ -42,8 +43,8 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { netHttpClient.Transport = appTransport } - // middleware must be applied after App transport is set, otherwise App token will - // fail to be renewed + // Middleware must be applied after App transport is set, otherwise App token will fail to be + // renewed with a 400 Bad Request error (even though the request is identical to a successful one.) finalTransport := kiotaHttp.NewCustomTransportWithParentTransport(netHttpClient.Transport, middlewares...) netHttpClient.Transport = finalTransport @@ -52,6 +53,7 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { auth.WithUserAgent(options.UserAgent), } + // If a PAT is provided and GitHub App information is not, configure token authentication if options.Token != "" && (options.GitHubAppID == 0 && options.GitHubAppInstallationID == 0 && options.GitHubAppPemFilePath == "") { tokenProviderOptions = append(tokenProviderOptions, auth.WithTokenAuthentication(options.Token)) } From 89748f0b79b7514d4fe35c341a6a4a4b67653291 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 2 May 2024 14:26:21 -0700 Subject: [PATCH 05/18] Differentiate App and token auth examples --- cmd/{example => app-example}/main.go | 0 cmd/token-example/main.go | 37 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) rename cmd/{example => app-example}/main.go (100%) create mode 100644 cmd/token-example/main.go diff --git a/cmd/example/main.go b/cmd/app-example/main.go similarity index 100% rename from cmd/example/main.go rename to cmd/app-example/main.go diff --git a/cmd/token-example/main.go b/cmd/token-example/main.go new file mode 100644 index 00000000..5cff4014 --- /dev/null +++ b/cmd/token-example/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + "time" + + abs "github.com/microsoft/kiota-abstractions-go" + "github.com/octokit/go-sdk/pkg" +) + +func main() { + client, err := pkg.NewApiClient( + pkg.WithUserAgent("my-user-agent"), + pkg.WithRequestTimeout(5*time.Second), + pkg.WithBaseUrl("https://api.github.com"), + pkg.WithAuthorizationToken(os.Getenv("GITHUB_TOKEN")), + ) + + // equally valid: + //client, err := pkg.NewApiClient() + if err != nil { + log.Fatalf("error creating client: %v", err) + } + + queryParams := &abs.DefaultQueryParameters{} + requestConfig := &abs.RequestConfiguration[abs.DefaultQueryParameters]{ + QueryParameters: queryParams, + } + zen, err := client.Zen().Get(context.Background(), requestConfig) + if err != nil { + log.Fatalf("error getting repositories: %v", err) + } + fmt.Printf("GitHub Zen principle: %v\n", *zen) +} From ac183c04a6ce393a5c2f3f9fd2d65cea8e5c8cc6 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Tue, 21 May 2024 15:00:13 -0700 Subject: [PATCH 06/18] Switch to using fork of ghinstallation --- go.mod | 8 +++----- go.sum | 8 ++++---- pkg/client.go | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 507647fd..bc2100e7 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/octokit/go-sdk go 1.21.5 require ( - github.com/bradleyfalzon/ghinstallation/v2 v2.10.0 + github.com/kfcampbell/ghinstallation v0.0.2 github.com/microsoft/kiota-abstractions-go v1.6.0 github.com/microsoft/kiota-http-go v1.3.3 github.com/microsoft/kiota-serialization-form-go v1.0.0 @@ -13,16 +13,14 @@ require ( golang.org/x/sync v0.7.0 ) -require ( - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/google/go-github/v60 v60.0.0 // indirect -) +require github.com/golang-jwt/jwt/v4 v4.5.0 // indirect require ( github.com/cjlapao/common-go v0.0.39 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/go-github/v61 v61.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index cba0db9b..e0df28a8 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/bradleyfalzon/ghinstallation/v2 v2.10.0 h1:XWuWBRFEpqVrHepQob9yPS3Xg4K3Wr9QCx4fu8HbUNg= -github.com/bradleyfalzon/ghinstallation/v2 v2.10.0/go.mod h1:qoGA4DxWPaYTgVCrmEspVSjlTu4WYAiSxMIhorMRXXc= github.com/cjlapao/common-go v0.0.39 h1:bAAUrj2B9v0kMzbAOhzjSmiyDy+rd56r2sy7oEiQLlA= github.com/cjlapao/common-go v0.0.39/go.mod h1:M3dzazLjTjEtZJbbxoA5ZDiGCiHmpwqW9l4UWaddwOA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -14,12 +12,14 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v60 v60.0.0 h1:oLG98PsLauFvvu4D/YPxq374jhSxFYdzQGNCyONLfn8= -github.com/google/go-github/v60 v60.0.0/go.mod h1:ByhX2dP9XT9o/ll2yXAu2VD8l5eNVg8hD4Cr0S/LmQk= +github.com/google/go-github/v61 v61.0.0 h1:VwQCBwhyE9JclCI+22/7mLB1PuU9eowCXKY5pNlu1go= +github.com/google/go-github/v61 v61.0.0/go.mod h1:0WR+KmsWX75G2EbpyGsGmradjo3IiciuI4BmdVCobQY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kfcampbell/ghinstallation v0.0.2 h1:o4XFT/h6/a8vf5DVDF+2m3cxxGuxNmcQ+H4pv1nuKwE= +github.com/kfcampbell/ghinstallation v0.0.2/go.mod h1:6ctykoYqeAYdnsMFA52ziGlsxNW9CC3fdPLG7eoGOmY= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= diff --git a/pkg/client.go b/pkg/client.go index b0e1e2a7..340c764a 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - "github.com/bradleyfalzon/ghinstallation/v2" + "github.com/kfcampbell/ghinstallation" kiotaHttp "github.com/microsoft/kiota-http-go" auth "github.com/octokit/go-sdk/pkg/authentication" "github.com/octokit/go-sdk/pkg/github" From 6e4307a004c92c9271f5aedd1366215b0cca604a Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Wed, 22 May 2024 16:34:27 -0700 Subject: [PATCH 07/18] Bump to latest ghinstallation fork version --- go.mod | 4 +--- go.sum | 10 ++-------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index bc2100e7..45201083 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/octokit/go-sdk go 1.21.5 require ( - github.com/kfcampbell/ghinstallation v0.0.2 + github.com/kfcampbell/ghinstallation v0.0.4 github.com/microsoft/kiota-abstractions-go v1.6.0 github.com/microsoft/kiota-http-go v1.3.3 github.com/microsoft/kiota-serialization-form-go v1.0.0 @@ -20,8 +20,6 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/google/go-github/v61 v61.0.0 // indirect - github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/std-uritemplate/std-uritemplate/go v0.0.55 // indirect diff --git a/go.sum b/go.sum index e0df28a8..49221c81 100644 --- a/go.sum +++ b/go.sum @@ -9,17 +9,12 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github/v61 v61.0.0 h1:VwQCBwhyE9JclCI+22/7mLB1PuU9eowCXKY5pNlu1go= -github.com/google/go-github/v61 v61.0.0/go.mod h1:0WR+KmsWX75G2EbpyGsGmradjo3IiciuI4BmdVCobQY= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/kfcampbell/ghinstallation v0.0.2 h1:o4XFT/h6/a8vf5DVDF+2m3cxxGuxNmcQ+H4pv1nuKwE= -github.com/kfcampbell/ghinstallation v0.0.2/go.mod h1:6ctykoYqeAYdnsMFA52ziGlsxNW9CC3fdPLG7eoGOmY= +github.com/kfcampbell/ghinstallation v0.0.4 h1:gxleHOByehQfEzkUbP6LyKKqgXvUQFxEg7ReAh/VvH0= +github.com/kfcampbell/ghinstallation v0.0.4/go.mod h1:LWoIPrgnl/HA+3Be890KTLm378+LZuABjBLKlF/Lq8M= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -50,7 +45,6 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From fce8ecc977dc693cc6dcf71b67dba0145e266a0c Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Wed, 22 May 2024 16:35:10 -0700 Subject: [PATCH 08/18] Allow authorizing with clientID --- cmd/app-example/main.go | 4 +++- pkg/client.go | 30 +++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/cmd/app-example/main.go b/cmd/app-example/main.go index e7c4ef53..f1eb4c90 100644 --- a/cmd/app-example/main.go +++ b/cmd/app-example/main.go @@ -16,7 +16,9 @@ func main() { pkg.WithRequestTimeout(5*time.Second), pkg.WithBaseUrl("https://api.github.com"), // pkg.WithAuthorizationToken(os.Getenv("GITHUB_TOKEN")), - pkg.WithGitHubAppAuthentication("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", 131977, 20570954), + // client ID: "Iv1.97d45f3f6f63859f" + // pkg.WithGitHubAppAuthentication("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", 131977, 20570954), + pkg.WithGitHubAppAuthenticationClientID("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", "Iv1.97d45f3f6f63859f", 20570954), ) // equally valid: diff --git a/pkg/client.go b/pkg/client.go index 340c764a..84c543db 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -34,13 +34,22 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { } // Configure GitHub App authentication if required fields are provided - if options.GitHubAppID != 0 && options.GitHubAppInstallationID != 0 && options.GitHubAppPemFilePath != "" { + if (options.GitHubAppID != 0 || options.GitHubAppClientID != "") && options.GitHubAppInstallationID != 0 && options.GitHubAppPemFilePath != "" { existingTransport := netHttpClient.Transport - appTransport, err := ghinstallation.NewKeyFromFile(existingTransport, options.GitHubAppID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) - if err != nil { - return nil, fmt.Errorf("failed to create transport from GitHub App: %v", err) + + if options.GitHubAppClientID != "" { + appTransport, err := ghinstallation.NewKeyFromFile(existingTransport, options.GitHubAppClientID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) + if err != nil { + return nil, fmt.Errorf("failed to create transport from GitHub App using clientID: %v", err) + } + netHttpClient.Transport = appTransport + } else { + appTransport, err := ghinstallation.NewKeyFromFileWithAppID(existingTransport, options.GitHubAppID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) + if err != nil { + return nil, fmt.Errorf("failed to create transport from GitHub App using appID: %v", err) + } + netHttpClient.Transport = appTransport } - netHttpClient.Transport = appTransport } // Middleware must be applied after App transport is set, otherwise App token will fail to be @@ -100,7 +109,10 @@ type ClientOptions struct { // GitHubAppPemFilePath should be left blank if token auth or an unauthenticated client is desired. GitHubAppPemFilePath string // GitHubAppID should be left blank if token auth or an unauthenticated client is desired. + // Deprecated: Use GitHubAppClientID instead. GitHubAppID int64 + // GitHubAppClientID should be left blank if token auth or an unauthenticated client is desired. + GitHubAppClientID string // GitHubAppInstallationID should be left blank if token auth or an unauthenticated client is desired. GitHubAppInstallationID int64 } @@ -161,3 +173,11 @@ func WithGitHubAppAuthentication(GitHubAppPemFilePath string, GitHubAppID int64, c.GitHubAppInstallationID = GitHubAppInstallationID } } + +func WithGitHubAppAuthenticationClientID(GitHubAppPemFilePath string, GitHubAppClientID string, GitHubAppInstallationID int64) ClientOptionFunc { + return func(c *ClientOptions) { + c.GitHubAppPemFilePath = GitHubAppPemFilePath + c.GitHubAppClientID = GitHubAppClientID + c.GitHubAppInstallationID = GitHubAppInstallationID + } +} From 17193b74166484920b1a8b8fb9a9e39edeea1423 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 23 May 2024 13:47:10 -0700 Subject: [PATCH 09/18] Refactor naming to default to clientID for App auth --- cmd/app-example/main.go | 4 ++-- pkg/client.go | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/cmd/app-example/main.go b/cmd/app-example/main.go index f1eb4c90..2faca24c 100644 --- a/cmd/app-example/main.go +++ b/cmd/app-example/main.go @@ -17,8 +17,8 @@ func main() { pkg.WithBaseUrl("https://api.github.com"), // pkg.WithAuthorizationToken(os.Getenv("GITHUB_TOKEN")), // client ID: "Iv1.97d45f3f6f63859f" - // pkg.WithGitHubAppAuthentication("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", 131977, 20570954), - pkg.WithGitHubAppAuthenticationClientID("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", "Iv1.97d45f3f6f63859f", 20570954), + // pkg.WithGitHubAppAuthenticationUsingAppID("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", 131977, 20570954), + pkg.WithGitHubAppAuthentication("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", "Iv1.97d45f3f6f63859f", 20570954), ) // equally valid: diff --git a/pkg/client.go b/pkg/client.go index 84c543db..5d518d79 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -166,18 +166,22 @@ func WithAPIVersion(version string) ClientOptionFunc { } } -func WithGitHubAppAuthentication(GitHubAppPemFilePath string, GitHubAppID int64, GitHubAppInstallationID int64) ClientOptionFunc { +// WithGitHubAppAuthenticationUsingAppID configures the client with the given GitHub App +// auth. Deprecated: Use WithGitHubAppAuthentication instead, which takes in a clientID +// string instead of an appID integer. +func WithGitHubAppAuthenticationUsingAppID(pemFilePath string, appID int64, installationID int64) ClientOptionFunc { return func(c *ClientOptions) { - c.GitHubAppPemFilePath = GitHubAppPemFilePath - c.GitHubAppID = GitHubAppID - c.GitHubAppInstallationID = GitHubAppInstallationID + c.GitHubAppPemFilePath = pemFilePath + c.GitHubAppID = appID + c.GitHubAppInstallationID = installationID } } -func WithGitHubAppAuthenticationClientID(GitHubAppPemFilePath string, GitHubAppClientID string, GitHubAppInstallationID int64) ClientOptionFunc { +// WithGitHubAppAuthentication configures the client with the given GitHub App auth. +func WithGitHubAppAuthentication(pemFilePath string, clientID string, installationID int64) ClientOptionFunc { return func(c *ClientOptions) { - c.GitHubAppPemFilePath = GitHubAppPemFilePath - c.GitHubAppClientID = GitHubAppClientID - c.GitHubAppInstallationID = GitHubAppInstallationID + c.GitHubAppPemFilePath = pemFilePath + c.GitHubAppClientID = clientID + c.GitHubAppInstallationID = installationID } } From 916a677f9b064d7cdcb7473b28438fbc39371635 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 23 May 2024 14:33:35 -0700 Subject: [PATCH 10/18] Bump kfcampbell/ghinstallation version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 45201083..87985c60 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/octokit/go-sdk go 1.21.5 require ( - github.com/kfcampbell/ghinstallation v0.0.4 + github.com/kfcampbell/ghinstallation v0.0.5 github.com/microsoft/kiota-abstractions-go v1.6.0 github.com/microsoft/kiota-http-go v1.3.3 github.com/microsoft/kiota-serialization-form-go v1.0.0 diff --git a/go.sum b/go.sum index 49221c81..12c8ab19 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/kfcampbell/ghinstallation v0.0.4 h1:gxleHOByehQfEzkUbP6LyKKqgXvUQFxEg7ReAh/VvH0= -github.com/kfcampbell/ghinstallation v0.0.4/go.mod h1:LWoIPrgnl/HA+3Be890KTLm378+LZuABjBLKlF/Lq8M= +github.com/kfcampbell/ghinstallation v0.0.5 h1:1ND+f5GrrEsBZeDQhe9HLVQ9du4GLu26WdCBjPjzhYc= +github.com/kfcampbell/ghinstallation v0.0.5/go.mod h1:LWoIPrgnl/HA+3Be890KTLm378+LZuABjBLKlF/Lq8M= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= From e405d53320f8f872aba7493b831d7f1aa675c835 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 23 May 2024 15:06:53 -0700 Subject: [PATCH 11/18] Rename WithAuthorizationToken to WithTokenAuthentication --- cmd/app-example/main.go | 2 +- cmd/token-example/main.go | 2 +- pkg/client.go | 4 ++-- pkg/example_test.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/app-example/main.go b/cmd/app-example/main.go index 2faca24c..8d0f55d6 100644 --- a/cmd/app-example/main.go +++ b/cmd/app-example/main.go @@ -15,7 +15,7 @@ func main() { pkg.WithUserAgent("my-user-agent"), pkg.WithRequestTimeout(5*time.Second), pkg.WithBaseUrl("https://api.github.com"), - // pkg.WithAuthorizationToken(os.Getenv("GITHUB_TOKEN")), + // pkg.WithTokenAuthentication(os.Getenv("GITHUB_TOKEN")), // client ID: "Iv1.97d45f3f6f63859f" // pkg.WithGitHubAppAuthenticationUsingAppID("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", 131977, 20570954), pkg.WithGitHubAppAuthentication("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", "Iv1.97d45f3f6f63859f", 20570954), diff --git a/cmd/token-example/main.go b/cmd/token-example/main.go index 5cff4014..fcb7075a 100644 --- a/cmd/token-example/main.go +++ b/cmd/token-example/main.go @@ -16,7 +16,7 @@ func main() { pkg.WithUserAgent("my-user-agent"), pkg.WithRequestTimeout(5*time.Second), pkg.WithBaseUrl("https://api.github.com"), - pkg.WithAuthorizationToken(os.Getenv("GITHUB_TOKEN")), + pkg.WithTokenAuthentication(os.Getenv("GITHUB_TOKEN")), ) // equally valid: diff --git a/pkg/client.go b/pkg/client.go index 5d518d79..c0eafbc4 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -151,9 +151,9 @@ func WithBaseUrl(baseURL string) ClientOptionFunc { } } -// WithAuthorizationToken configures the client with the given +// WithTokenAuthentication configures the client with the given // Personal Authorization Token. -func WithAuthorizationToken(token string) ClientOptionFunc { +func WithTokenAuthentication(token string) ClientOptionFunc { return func(c *ClientOptions) { c.Token = token } diff --git a/pkg/example_test.go b/pkg/example_test.go index 776a1b50..77c7ad6d 100644 --- a/pkg/example_test.go +++ b/pkg/example_test.go @@ -22,7 +22,7 @@ func ExampleApiClient_Octocat() { pkg.WithUserAgent("octokit/go-sdk.example-functions"), pkg.WithRequestTimeout(5*time.Second), pkg.WithBaseUrl("https://api.github.com"), - pkg.WithAuthorizationToken(os.Getenv("GITHUB_TOKEN")), + pkg.WithTokenAuthentication(os.Getenv("GITHUB_TOKEN")), ) // equally valid: @@ -80,7 +80,7 @@ func ExampleApiClient_Octocat() { func ExampleApiClient_Octocat_withoutConvenienceConstructor() { tokenProvider := auth.NewTokenProvider( // to create an authenticated provider, uncomment the below line and pass in your token - // auth.WithAuthorizationToken("ghp_your_token"), + // auth.WithTokenAuthentication("ghp_your_token"), auth.WithUserAgent("octokit/go-sdk.example-functions"), ) adapter, err := kiotaHttp.NewNetHttpRequestAdapter(tokenProvider) From 7d369b29e6d080034aa7cc541ba3fa2226e65e36 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 23 May 2024 15:09:22 -0700 Subject: [PATCH 12/18] Add README note about different types of App auth --- README.md | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4998f0c9..85d71de6 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,48 @@ An "alpha" version of a generated Go SDK from [GitHub's OpenAPI spec](https://gi ## How do I use it? -See example client instantiations and requests in [example_test.go](pkg/example_test.go). +See example client instantiations and requests in [example_test.go](pkg/example_test.go) or in the [cmd/ directory](cmd/). ⚠️ **Note**: This SDK is not yet stable. Breaking changes may occur at any time. ### Authentication -Currently, this SDK supports both [Personal Access Tokens (classic)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#personal-access-tokens-classic) and [fine-grained Personal Access Tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#fine-grained-personal-access-tokens). +This SDK supports [Personal Access Tokens (classic)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#personal-access-tokens-classic), [fine-grained Personal Access Tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#fine-grained-personal-access-tokens), and [GitHub Apps](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app) authentication. -Future work is planned for the SDK to support [GitHub Apps](https://docs.github.com/en/apps/overview) authentication as well. +In order to use either type of Personal Access token, you can use the `WithTokenAuthentication("YOUR_TOKEN_HERE")` functional option when constructing a client, like so: + +```go +client, err := pkg.NewApiClient( + pkg.WithTokenAuthentication(os.Getenv("GITHUB_TOKEN")), +) +if err != nil { + log.Fatalf("error creating client: %v", err) +} +``` + +In order to authenticate as a GitHub App, you can use the `WithGitHubAppAuthentication` functional option: + +```go +client, err := pkg.NewApiClient( + pkg.WithGitHubAppAuthentication("/path/to/your/pem/file.pem", "your-client-ID", yourInstallationIDInt), +) +if err != nil { + log.Fatalf("error creating client: %v", err) +} +``` + +To see more detailed examples, view [the cmd/ directory in this repo](cmd/). + +⚠️ **Note**: There are [three types](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app) of GitHub App authentication: +1. [As the App itself (meta endpoints)](https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28) +1. [As an App installation](https://docs.github.com/en/rest/authentication/endpoints-available-for-github-app-installation-access-tokens?apiVersion=2022-11-28) +1. On behalf of a user + +Authenticating on behalf of a user is not supported in an SDK, as it requires a UI authentication flow with redirects. This SDK supports authenticating as the App itself and as an App installation. + +Note that the SDK **does not yet** support authenticating as the App itself and as an App installation using the same client transparently to the user. Authenticating as the App itself requires [creating a JSON Web Token (JWT)](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app) and using that as token authentication. For helpers to create and sign a JWT in Go, you may use the [golang-jwt/jwt](https://github.com/golang-jwt/jwt) library. + +Authenticating as an App installation can be done using the `WithGitHubAppAuthentication` functional option. Future work is planned to make the App meta endpoints vs. App installation endpoints auth schemes transparent to the user and only require one client setup. ## Why a generated SDK? From 115596244e21cd38f67117aa75c0e90c3022c9f7 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 23 May 2024 15:18:53 -0700 Subject: [PATCH 13/18] Simplify token initialization client --- pkg/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/client.go b/pkg/client.go index c0eafbc4..0dd51772 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -63,7 +63,7 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { } // If a PAT is provided and GitHub App information is not, configure token authentication - if options.Token != "" && (options.GitHubAppID == 0 && options.GitHubAppInstallationID == 0 && options.GitHubAppPemFilePath == "") { + if options.Token != "" && (options.GitHubAppInstallationID == 0 && options.GitHubAppPemFilePath == "") { tokenProviderOptions = append(tokenProviderOptions, auth.WithTokenAuthentication(options.Token)) } From 0b56dbff00a1a6b9f8b5efdfa9b2d703974e78ce Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 23 May 2024 15:21:21 -0700 Subject: [PATCH 14/18] Another ghinstallation version bump --- go.mod | 5 ++--- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 87985c60..b94a3972 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/octokit/go-sdk go 1.21.5 require ( - github.com/kfcampbell/ghinstallation v0.0.5 + github.com/kfcampbell/ghinstallation v0.0.6 github.com/microsoft/kiota-abstractions-go v1.6.0 github.com/microsoft/kiota-http-go v1.3.3 github.com/microsoft/kiota-serialization-form-go v1.0.0 @@ -13,13 +13,12 @@ require ( golang.org/x/sync v0.7.0 ) -require github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - require ( github.com/cjlapao/common-go v0.0.39 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/std-uritemplate/std-uritemplate/go v0.0.55 // indirect diff --git a/go.sum b/go.sum index 12c8ab19..8ebb0fdc 100644 --- a/go.sum +++ b/go.sum @@ -7,14 +7,14 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/kfcampbell/ghinstallation v0.0.5 h1:1ND+f5GrrEsBZeDQhe9HLVQ9du4GLu26WdCBjPjzhYc= -github.com/kfcampbell/ghinstallation v0.0.5/go.mod h1:LWoIPrgnl/HA+3Be890KTLm378+LZuABjBLKlF/Lq8M= +github.com/kfcampbell/ghinstallation v0.0.6 h1:L4QkjRqNosJ6Kyetymq7FswY1wUxMQO+fyYXJAWl0WY= +github.com/kfcampbell/ghinstallation v0.0.6/go.mod h1:UXWfCKaLwF+AiyCo8gxE5oA0VMQsAmCdRXgTyyRdUnA= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= From b15e87db1f098bc3125525de5f1690fd5f4e1ad8 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 30 May 2024 14:11:46 -0700 Subject: [PATCH 15/18] Use env vars for App auth example --- cmd/app-example/main.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmd/app-example/main.go b/cmd/app-example/main.go index 8d0f55d6..81336ca9 100644 --- a/cmd/app-example/main.go +++ b/cmd/app-example/main.go @@ -3,6 +3,8 @@ package main import ( "context" "log" + "os" + "strconv" "time" abs "github.com/microsoft/kiota-abstractions-go" @@ -11,14 +13,16 @@ import ( ) func main() { + installationID, err := strconv.ParseInt(os.Getenv("INSTALLATION_ID"), 10, 64) + if err != nil { + log.Fatalf("error parsing installation ID from string to int64: %v", err) + } + client, err := pkg.NewApiClient( pkg.WithUserAgent("my-user-agent"), pkg.WithRequestTimeout(5*time.Second), pkg.WithBaseUrl("https://api.github.com"), - // pkg.WithTokenAuthentication(os.Getenv("GITHUB_TOKEN")), - // client ID: "Iv1.97d45f3f6f63859f" - // pkg.WithGitHubAppAuthenticationUsingAppID("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", 131977, 20570954), - pkg.WithGitHubAppAuthentication("/home/kfcampbell/github/dev/go-sdk/kfcampbell-terraform-provider.2024-04-30.private-key.pem", "Iv1.97d45f3f6f63859f", 20570954), + pkg.WithGitHubAppAuthentication(os.Getenv("PATH_TO_PEM_FILE"), os.Getenv("CLIENT_ID"), installationID), ) // equally valid: From a604459b1765b136d76b956b07ad30851cec2eb2 Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Thu, 30 May 2024 14:35:31 -0700 Subject: [PATCH 16/18] Test coverage for Apps auth --- pkg/client_test.go | 135 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 pkg/client_test.go diff --git a/pkg/client_test.go b/pkg/client_test.go new file mode 100644 index 00000000..abb3f138 --- /dev/null +++ b/pkg/client_test.go @@ -0,0 +1,135 @@ +package pkg + +import ( + "os" + "testing" + + "github.com/octokit/go-sdk/pkg/headers" +) + +const ( + installationID = 1234 + clientID = "testClientID" + pemFileName = "testPemFile" + token = "testToken" + appID = 123 +) + +// test key taken from Go source code at +// https://go.dev/src/crypto/rsa/rsa_test.go +var key = []byte(`-----BEGIN TESTING KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDNoyFUYeDuqw+k +iyv47iBy/udbWmQdpbUZ8JobHv8uQrvL7sQN6l83teHgNJsXqtiLF3MC+K+XI6Dq +hxUWfQwLip8WEnv7Jx/+53S8yp/CS4Jw86Q1bQHbZjFDpcoqSuwAxlegw18HNZCY +fpipYnA1lYCm+MTjtgXJQbjA0dwUGCf4BDMqt+76Jk3XZF5975rftbkGoT9eu8Jt +Xs5F5Xkwd8q3fkQz+fpLW4u9jrfFyQ61RRFkYrCjlhtGjYIzBHGgQM4n/sNXhiy5 +h0tA7Xa6NyYrN/OXe/Y1K8Rz/tzlvbMoxgZgtBuKo1N3m8ckFi7hUVK2eNv7GoAb +teTTPrg/AgMBAAECggEAAnfsVpmsL3R0Bh4gXRpPeM63H6e1a8B8kyVwiO9o0cXX +gKp9+P39izfB0Kt6lyCj/Wg+wOQT7rg5qy1yIw7fBHGmcjquxh3uN0s3YZ+Vcym6 +SAY5f0vh/OyJN9r3Uv8+Pc4jtb7So7QDzdWeZurssBmUB0avAMRdGNFGP5SyILcz +l3Q59hTxQ4czRHKjZ06L1/sA+tFVbO1j39FN8nMOU/ovLF4lAmZTkQ6AP6n6XPHP +B8Nq7jSYz6RDO200jzp6UsdrnjjkJRbzOxN/fn+ckCP+WYuq+y/d05ET9PdVa4qI +Jyr80D9QgHmfztcecvYwoskGnkb2F4Tmp0WnAj/xVQKBgQD4TrMLyyHdbAr5hoSi +p+r7qBQxnHxPe2FKO7aqagi4iPEHauEDgwPIcsOYota1ACiSs3BaESdJAClbqPYd +HDI4c2DZ6opux6WYkSju+tVXYW6qarR3fzrP3fUCdz2c2NfruWOqq8YmjzAhTNPm +YzvtzTdwheNYV0Vi71t1SfZmfQKBgQDUAgSUcrgXdGDnSbaNe6KwjY5oZWOQfZe2 +DUhqfN/JRFZj+EMfIIh6OQXnZqkp0FeRdfRAFl8Yz8ESHEs4j+TikLJEeOdfmYLS +TWxlMPDTUGbUvSf4g358NJ8TlfYA7dYpSTNPXMRSLtsz1palmaDBTE/V2xKtTH6p +VglRNRUKawKBgCPqBh2TkN9czC2RFkgMb4FcqycN0jEQ0F6TSnVVhtNiAzKmc8s1 +POvWJZJDIzjkv/mP+JUeXAdD/bdjNc26EU126rA6KzGgsMPjYv9FymusDPybGGUc +Qt5j5RcpNgEkn/5ZPyAlXjCfjz+RxChTfAyGHRmqU9qoLMIFir3pJ7llAoGBAMNH +sIxENwlzqyafoUUlEq/pU7kZWuJmrO2FwqRDraYoCiM/NCRhxRQ/ng6NY1gejepw +abD2alXiV4alBSxubne6rFmhvA00y2mG40c6Ezmxn2ZpbX3dMQ6bMcPKp7QnXtLc +mCSL4FGK02ImUNDsd0RVVFw51DRId4rmsuJYMK9NAoGAKlYdc4784ixTD2ZICIOC +ZWPxPAyQUEA7EkuUhAX1bVNG6UJTYA8kmGcUCG4jPTgWzi00IyUUr8jK7efyU/zs +qiJuVs1bia+flYIQpysMl1VzZh8gW1nkB4SVPm5l2wBvVJDIr9Mc6rueC/oVNkh2 +fLVGuFoTVIu2bF0cWAjNNMg= +-----END TESTING KEY-----`) + +func TestNewApiClientUnauthenticatedHappyPath(t *testing.T) { + client, err := NewApiClient( + WithAPIVersion(headers.APIVersionValue), + ) + if err != nil { + t.Fatalf("error creating client: %v", err) + } + if client == nil { + t.Fatalf("client is nil") + } +} + +func TestNewApiClientTokenAuthHappyPath(t *testing.T) { + client, err := NewApiClient(WithTokenAuthentication(token)) + if err != nil { + t.Fatalf("error creating client: %v", err) + } + if client == nil { + t.Fatalf("client is nil") + } +} + +func TestNewApiClientAppAuthHappyPath(t *testing.T) { + tmpfile, err := os.CreateTemp("", pemFileName) + if err != nil { + t.Fatal(err) + } + defer os.Remove(tmpfile.Name()) + + if _, err := tmpfile.Write(key); err != nil { + t.Fatal(err) + } + if err := tmpfile.Close(); err != nil { + t.Fatal(err) + } + + client, err := NewApiClient(WithGitHubAppAuthentication(tmpfile.Name(), clientID, installationID)) + if err != nil { + t.Fatalf("error creating client: %v", err) + } + if client == nil { + t.Fatalf("client is nil") + } +} + +func TestNewApiClientAppAuthErrorGettingKeyFromFile(t *testing.T) { + client, err := NewApiClient(WithGitHubAppAuthentication("pem/file/does/not/exist.pem", clientID, installationID)) + if err == nil { + t.Fatalf("expected error creating client") + } + if client != nil { + t.Fatalf("client is not nil") + } +} + +func TestNewApiClientAppAuthWithAppIDHappyPath(t *testing.T) { + tmpfile, err := os.CreateTemp("", pemFileName) + if err != nil { + t.Fatal(err) + } + defer os.Remove(tmpfile.Name()) + + if _, err := tmpfile.Write(key); err != nil { + t.Fatal(err) + } + if err := tmpfile.Close(); err != nil { + t.Fatal(err) + } + + client, err := NewApiClient(WithGitHubAppAuthenticationUsingAppID(tmpfile.Name(), appID, installationID)) + if err != nil { + t.Fatalf("error creating client: %v", err) + } + if client == nil { + t.Fatalf("client is nil") + } +} + +func TestNewApiClientAppAuthWithAppIDErrorGettingKeyFromFile(t *testing.T) { + client, err := NewApiClient(WithGitHubAppAuthenticationUsingAppID("pem/file/does/not/exist.pem", appID, installationID)) + if err == nil { + t.Fatalf("expected error creating client") + } + if client != nil { + t.Fatalf("client is not nil") + } +} From 1a4d9fc213267b57ccb10c8c5bc7824fb65e92fc Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Mon, 3 Jun 2024 14:40:52 -0700 Subject: [PATCH 17/18] Update pkg/client.go Co-authored-by: Nick Floyd <139819+nickfloyd@users.noreply.github.com> --- pkg/client.go | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/pkg/client.go b/pkg/client.go index 0dd51772..544df41c 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -33,24 +33,23 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { netHttpClient.Timeout = options.RequestTimeout } - // Configure GitHub App authentication if required fields are provided - if (options.GitHubAppID != 0 || options.GitHubAppClientID != "") && options.GitHubAppInstallationID != 0 && options.GitHubAppPemFilePath != "" { - existingTransport := netHttpClient.Transport - - if options.GitHubAppClientID != "" { - appTransport, err := ghinstallation.NewKeyFromFile(existingTransport, options.GitHubAppClientID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) - if err != nil { - return nil, fmt.Errorf("failed to create transport from GitHub App using clientID: %v", err) - } - netHttpClient.Transport = appTransport - } else { - appTransport, err := ghinstallation.NewKeyFromFileWithAppID(existingTransport, options.GitHubAppID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) - if err != nil { - return nil, fmt.Errorf("failed to create transport from GitHub App using appID: %v", err) - } - netHttpClient.Transport = appTransport - } - } + if (options.GitHubAppID != 0 || options.GitHubAppClientID != "") && options.GitHubAppInstallationID != 0 && options.GitHubAppPemFilePath != "" { + existingTransport := netHttpClient.Transport + var appTransport ghinstallation.Transport + var err error + + if options.GitHubAppClientID != "" { + appTransport, err = ghinstallation.NewKeyFromFile(existingTransport, options.GitHubAppClientID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) + } else { + appTransport, err = ghinstallation.NewKeyFromFileWithAppID(existingTransport, options.GitHubAppID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) + } + + if err != nil { + return nil, fmt.Errorf("failed to create transport from GitHub App: %v", err) + } + + netHttpClient.Transport = appTransport + } // Middleware must be applied after App transport is set, otherwise App token will fail to be // renewed with a 400 Bad Request error (even though the request is identical to a successful one.) From 9bf71d21d0f6d0e6428e72944822a7516f45919d Mon Sep 17 00:00:00 2001 From: Keegan Campbell Date: Mon, 3 Jun 2024 14:43:30 -0700 Subject: [PATCH 18/18] Fix build error from code suggestion --- pkg/client.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pkg/client.go b/pkg/client.go index 544df41c..9538d96d 100644 --- a/pkg/client.go +++ b/pkg/client.go @@ -33,23 +33,23 @@ func NewApiClient(optionFuncs ...ClientOptionFunc) (*Client, error) { netHttpClient.Timeout = options.RequestTimeout } - if (options.GitHubAppID != 0 || options.GitHubAppClientID != "") && options.GitHubAppInstallationID != 0 && options.GitHubAppPemFilePath != "" { - existingTransport := netHttpClient.Transport - var appTransport ghinstallation.Transport - var err error - - if options.GitHubAppClientID != "" { - appTransport, err = ghinstallation.NewKeyFromFile(existingTransport, options.GitHubAppClientID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) - } else { - appTransport, err = ghinstallation.NewKeyFromFileWithAppID(existingTransport, options.GitHubAppID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) - } - - if err != nil { - return nil, fmt.Errorf("failed to create transport from GitHub App: %v", err) - } - - netHttpClient.Transport = appTransport - } + if (options.GitHubAppID != 0 || options.GitHubAppClientID != "") && options.GitHubAppInstallationID != 0 && options.GitHubAppPemFilePath != "" { + existingTransport := netHttpClient.Transport + var appTransport *ghinstallation.Transport + var err error + + if options.GitHubAppClientID != "" { + appTransport, err = ghinstallation.NewKeyFromFile(existingTransport, options.GitHubAppClientID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) + } else { + appTransport, err = ghinstallation.NewKeyFromFileWithAppID(existingTransport, options.GitHubAppID, options.GitHubAppInstallationID, options.GitHubAppPemFilePath) + } + + if err != nil { + return nil, fmt.Errorf("failed to create transport from GitHub App: %v", err) + } + + netHttpClient.Transport = appTransport + } // Middleware must be applied after App transport is set, otherwise App token will fail to be // renewed with a 400 Bad Request error (even though the request is identical to a successful one.)