Procházet zdrojové kódy

api endpoint changes

Ivan Galakhov před 4 roky
rodič
revize
e065e9c33c

+ 1 - 0
docker-compose.dev.yaml

@@ -26,6 +26,7 @@ services:
       - ./server:/porter/server
       - ./api:/porter/api
       - ./docker/kubeconfig.yaml:/porter/kubeconfig.yaml
+      - ./docker/github_app_private_key.pem:/porter/docker/github_app_private_key.pem
   postgres:
     image: postgres:latest
     container_name: postgres

+ 4 - 1
go.mod

@@ -7,6 +7,7 @@ require (
 	github.com/AlecAivazis/survey/v2 v2.2.9
 	github.com/DATA-DOG/go-sqlmock v1.5.0
 	github.com/aws/aws-sdk-go v1.35.4
+	github.com/bradleyfalzon/ghinstallation v1.1.1 // indirect
 	github.com/buildpacks/pack v0.19.0
 	github.com/cli/cli v1.11.0
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
@@ -24,7 +25,9 @@ require (
 	github.com/go-redis/redis/v8 v8.3.1
 	github.com/go-test/deep v1.0.7
 	github.com/google/go-github v17.0.0+incompatible
+	github.com/google/go-github/v29 v29.0.3 // indirect
 	github.com/google/go-github/v33 v33.0.0
+	github.com/google/go-querystring v1.1.0 // indirect
 	github.com/gorilla/schema v1.2.0
 	github.com/gorilla/securecookie v1.1.1
 	github.com/gorilla/sessions v1.2.1
@@ -50,7 +53,7 @@ require (
 	github.com/spf13/viper v1.7.0
 	github.com/stretchr/testify v1.7.0
 	github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
-	golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
+	golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
 	golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
 	google.golang.org/api v0.30.0
 	google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a

+ 11 - 0
go.sum

@@ -177,6 +177,8 @@ github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
+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/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
 github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA=
 github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
@@ -540,11 +542,16 @@ github.com/google/go-containerregistry v0.5.1 h1:/+mFTs4AlwsJ/mJe8NDtKb7BxLtbZFp
 github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
 github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
+github.com/google/go-github/v29 v29.0.2/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
+github.com/google/go-github/v29 v29.0.3 h1:IktKCTwU//aFHnpA+2SLIi7Oo9uhAzgsdZNbcAqhgdc=
+github.com/google/go-github/v29 v29.0.3/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E=
 github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
 github.com/google/go-github/v33 v33.0.0 h1:qAf9yP0qc54ufQxzwv+u9H0tiVOnPJxo0lI/JXqw3ZM=
 github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg=
 github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
 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/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
@@ -1283,6 +1290,8 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1366,6 +1375,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
 golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
@@ -1468,6 +1478,7 @@ golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=

+ 2 - 0
internal/config/config.go

@@ -45,6 +45,8 @@ type ServerConf struct {
 	GithubAppClientSecret  string `env:"GITHUB_APP_CLIENT_SECRET"`
 	GithubAppName          string `env:"GITHUB_APP_NAME"`
 	GithubAppWebhookSecret string `env:"GITHUB_APP_WEBHOOK_SECRET"`
+	GithubAppID            string `env:"GITHUB_APP_ID"`
+	GithubAppSecretPath    string `env:"GITHUB_APP_SECRET_PATH"`
 
 	GoogleClientID         string `env:"GOOGLE_CLIENT_ID"`
 	GoogleClientSecret     string `env:"GOOGLE_CLIENT_SECRET"`

+ 5 - 1
internal/oauth/config.go

@@ -22,6 +22,8 @@ type Config struct {
 type GithubAppConf struct {
 	AppName       string
 	WebhookSecret string
+	SecretPath    string
+	AppID         int64
 	oauth2.Config
 }
 
@@ -38,10 +40,12 @@ func NewGithubClient(cfg *Config) *oauth2.Config {
 	}
 }
 
-func NewGithubAppClient(cfg *Config, name string, secret string) *GithubAppConf {
+func NewGithubAppClient(cfg *Config, name string, secret string, secretPath string, appID int64) *GithubAppConf {
 	return &GithubAppConf{
 		AppName:       name,
 		WebhookSecret: secret,
+		SecretPath:    secretPath,
+		AppID:         appID,
 		Config: oauth2.Config{
 			ClientID:     cfg.ClientID,
 			ClientSecret: cfg.ClientSecret,

+ 15 - 7
server/api/api.go

@@ -3,6 +3,7 @@ package api
 import (
 	"fmt"
 	"net/http"
+	"strconv"
 	"strings"
 
 	"github.com/go-playground/locales/en"
@@ -170,13 +171,20 @@ func New(conf *AppConfig) (*App, error) {
 		app.Capabilities.GithubLogin = sc.GithubLoginEnabled
 	}
 
-	if sc.GithubAppClientID != "" && sc.GithubAppClientSecret != "" && sc.GithubAppName != "" && sc.GithubAppWebhookSecret != "" {
-		app.GithubAppConf = oauth.NewGithubAppClient(&oauth.Config{
-			ClientID:     sc.GithubAppClientID,
-			ClientSecret: sc.GithubAppClientSecret,
-			Scopes:       []string{"read:user"},
-			BaseURL:      sc.ServerURL,
-		}, sc.GithubAppName, sc.GithubAppWebhookSecret)
+	if sc.GithubAppClientID != "" &&
+		sc.GithubAppClientSecret != "" &&
+		sc.GithubAppName != "" &&
+		sc.GithubAppWebhookSecret != "" &&
+		sc.GithubAppSecretPath != "" &&
+		sc.GithubAppID != "" {
+		if AppID, err := strconv.ParseInt(sc.GithubAppID, 10, 64); err == nil {
+			app.GithubAppConf = oauth.NewGithubAppClient(&oauth.Config{
+				ClientID:     sc.GithubAppClientID,
+				ClientSecret: sc.GithubAppClientSecret,
+				Scopes:       []string{"read:user"},
+				BaseURL:      sc.ServerURL,
+			}, sc.GithubAppName, sc.GithubAppWebhookSecret, sc.GithubAppSecretPath, AppID)
+		}
 	}
 
 	if sc.GoogleClientID != "" && sc.GoogleClientSecret != "" {

+ 32 - 4
server/api/git_repo_handler.go

@@ -13,6 +13,7 @@ import (
 	"strings"
 	"sync"
 
+	"github.com/bradleyfalzon/ghinstallation"
 	"github.com/go-chi/chi"
 	"github.com/google/go-github/github"
 )
@@ -20,7 +21,7 @@ import (
 // HandleListProjectGitRepos returns a list of git repos for a project
 func (app *App) HandleListProjectGitRepos(w http.ResponseWriter, r *http.Request) {
 
-	tok, err := app.getGithubAppTokenFromRequest(r)
+	tok, err := app.getGithubAppOauthTokenFromRequest(r)
 
 	if err != nil {
 		json.NewEncoder(w).Encode(make([]*models.GitRepoExternal, 0))
@@ -101,15 +102,14 @@ type AutoBuildpack struct {
 
 // HandleListRepos retrieves a list of repo names
 func (app *App) HandleListRepos(w http.ResponseWriter, r *http.Request) {
-	tok, err := app.githubTokenFromRequest(r)
+
+	client, err := app.githubAppClientFromRequest(r)
 
 	if err != nil {
 		app.handleErrorInternal(err, w)
 		return
 	}
 
-	client := github.NewClient(app.GithubProjectConf.Client(oauth2.NoContext, tok))
-
 	// figure out number of repositories
 	opt := &github.RepositoryListOptions{
 		ListOptions: github.ListOptions{
@@ -118,6 +118,8 @@ func (app *App) HandleListRepos(w http.ResponseWriter, r *http.Request) {
 		Sort: "updated",
 	}
 
+	//client.Apps.ListRepos()
+
 	allRepos, resp, err := client.Repositories.List(context.Background(), "", opt)
 
 	if err != nil {
@@ -521,6 +523,32 @@ func (app *App) HandleGetRepoZIPDownloadURL(w http.ResponseWriter, r *http.Reque
 	json.NewEncoder(w).Encode(apiResp)
 }
 
+// githubAppClientFromRequest gets the github app installation id from the request and authenticates
+// using it and a private key file
+func (app *App) githubAppClientFromRequest(r *http.Request) (*github.Client, error) {
+
+	installationID, err := strconv.ParseUint(chi.URLParam(r, "installation_id"), 0, 64)
+
+	if err != nil || installationID == 0 {
+		return nil, fmt.Errorf("could not read installation id")
+	}
+
+	fmt.Println(app.GithubAppConf.AppID)
+
+	itr, err := ghinstallation.NewKeyFromFile(
+		http.DefaultTransport,
+		app.GithubAppConf.AppID,
+		int64(installationID),
+		"/porter/docker/github_app_private_key.pem")
+
+	if err != nil {
+		fmt.Println(err)
+		return nil, err
+	}
+
+	return github.NewClient(&http.Client{Transport: itr}), nil
+}
+
 // finds the github token given the git repo id and the project id
 func (app *App) githubTokenFromRequest(
 	r *http.Request,

+ 4 - 3
server/api/integration_handler.go

@@ -494,7 +494,7 @@ type HandleListGithubAppAccessResp struct {
 // HandleListGithubAppAccess provides basic info on if the current user is authenticated through the GitHub app
 // and what accounts/organizations their authentication has access to
 func (app *App) HandleListGithubAppAccess(w http.ResponseWriter, r *http.Request) {
-	tok, err := app.getGithubAppTokenFromRequest(r)
+	tok, err := app.getGithubAppOauthTokenFromRequest(r)
 
 	if err != nil {
 		res := HandleListGithubAppAccessResp{
@@ -561,8 +561,9 @@ func (app *App) HandleListGithubAppAccess(w http.ResponseWriter, r *http.Request
 	json.NewEncoder(w).Encode(res)
 }
 
-// getGithubAppTokenFromRequest
-func (app *App) getGithubAppTokenFromRequest(r *http.Request) (*oauth2.Token, error) {
+// getGithubAppOauthTokenFromRequest gets the oauth token from the request based on the currently
+// logged in user. Note that this authenticates as the user, rather than the installation.
+func (app *App) getGithubAppOauthTokenFromRequest(r *http.Request) (*oauth2.Token, error) {
 	userID, err := app.getUserIDFromRequest(r)
 
 	if err != nil {

+ 42 - 38
server/middleware/auth.go

@@ -403,44 +403,48 @@ func (auth *Auth) DoesUserHaveGitRepoAccess(
 	gitRepoLoc IDLocation,
 ) http.Handler {
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		grID, err := findGitRepoIDInRequest(r, gitRepoLoc)
-
-		if err != nil {
-			http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-			return
-		}
-
-		projID, err := findProjIDInRequest(r, projLoc)
-
-		if err != nil {
-			http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-			return
-		}
-
-		// get the service accounts belonging to the project
-		grs, err := auth.repo.GitRepo.ListGitReposByProjectID(uint(projID))
-
-		if err != nil {
-			http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
-			return
-		}
-
-		doesExist := false
-
-		for _, gr := range grs {
-			if gr.ID == uint(grID) {
-				doesExist = true
-				break
-			}
-		}
-
-		if doesExist {
-			next.ServeHTTP(w, r)
-			return
-		}
-
-		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-		return
+		// TODO: needs to use new github integration implementation
+
+		next.ServeHTTP(w, r)
+
+		//grID, err := findGitRepoIDInRequest(r, gitRepoLoc)
+		//
+		//if err != nil {
+		//	http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+		//	return
+		//}
+		//
+		//projID, err := findProjIDInRequest(r, projLoc)
+		//
+		//if err != nil {
+		//	http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+		//	return
+		//}
+		//
+		//// get the service accounts belonging to the project
+		//grs, err := auth.repo.GitRepo.ListGitReposByProjectID(uint(projID))
+		//
+		//if err != nil {
+		//	http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+		//	return
+		//}
+		//
+		//doesExist := false
+		//
+		//for _, gr := range grs {
+		//	if gr.ID == uint(grID) {
+		//		doesExist = true
+		//		break
+		//	}
+		//}
+		//
+		//if doesExist {
+		//	next.ServeHTTP(w, r)
+		//	return
+		//}
+		//
+		//http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
+		//return
 	})
 }
 

+ 1 - 1
server/router/router.go

@@ -1145,7 +1145,7 @@ func New(a *api.App) *chi.Mux {
 
 			r.Method(
 				"GET",
-				"/projects/{project_id}/gitrepos/{git_repo_id}/repos",
+				"/projects/{project_id}/gitrepos/{installation_id}/repos",
 				auth.DoesUserHaveProjectAccess(
 					auth.DoesUserHaveGitRepoAccess(
 						requestlog.NewHandler(a.HandleListRepos, l),