ソースを参照

update repo methods and handlers to ensure safety

Alexander Belanger 4 年 前
コミット
f41546877c

+ 11 - 1
api/server/handlers/environment/create.go

@@ -15,6 +15,7 @@ import (
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/auth/token"
+	"github.com/porter-dev/porter/internal/encryption"
 	"github.com/porter-dev/porter/internal/integrations/ci/actions"
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/models/integrations"
@@ -53,6 +54,14 @@ func (c *CreateEnvironmentHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
 		return
 	}
 
+	// create a random webhook id
+	webhookUID, err := encryption.GenerateRandomBytes(32)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
 	env, err := c.Repo().Environment().CreateEnvironment(&models.Environment{
 		ProjectID:         project.ID,
 		ClusterID:         cluster.ID,
@@ -61,6 +70,7 @@ func (c *CreateEnvironmentHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
 		GitRepoOwner:      owner,
 		GitRepoName:       name,
 		Mode:              request.Mode,
+		WebhookID:         string(webhookUID),
 	})
 
 	if err != nil {
@@ -76,7 +86,7 @@ func (c *CreateEnvironmentHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
 		return
 	}
 
-	webhookURL := fmt.Sprintf("%s/api/github/incoming_webhook", c.Config().ServerConf.ServerURL)
+	webhookURL := fmt.Sprintf("%s/api/github/incoming_webhook/%s", c.Config().ServerConf.ServerURL, string(webhookUID))
 
 	// create incoming webhook
 	_, _, err = client.Repositories.CreateHook(

+ 2 - 1
api/server/handlers/environment/enable_pull_request.go

@@ -34,6 +34,7 @@ func NewEnablePullRequestHandler(
 }
 
 func (c *EnablePullRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	project, _ := r.Context().Value(types.ProjectScope).(*models.Project)
 	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
 	request := &types.PullRequest{}
 
@@ -41,7 +42,7 @@ func (c *EnablePullRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
 		return
 	}
 
-	env, err := c.Repo().Environment().ReadEnvironmentByOwnerRepoName(request.RepoOwner, request.RepoName)
+	env, err := c.Repo().Environment().ReadEnvironmentByOwnerRepoName(project.ID, cluster.ID, request.RepoOwner, request.RepoName)
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))

+ 9 - 1
api/server/handlers/webhook/github_incoming.go

@@ -12,6 +12,7 @@ import (
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
 	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/server/shared/requestutils"
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/models"
 )
@@ -57,10 +58,17 @@ func (c *GithubIncomingWebhookHandler) ServeHTTP(w http.ResponseWriter, r *http.
 }
 
 func (c *GithubIncomingWebhookHandler) processPullRequestEvent(event *github.PullRequestEvent, r *http.Request) error {
+	// get the webhook id from the request
+	webhookID, reqErr := requestutils.GetURLParamString(r, types.URLParamIncomingWebhookID)
+
+	if reqErr != nil {
+		return fmt.Errorf(reqErr.Error())
+	}
+
 	owner := event.GetRepo().GetOwner().GetLogin()
 	repo := event.GetRepo().GetName()
 
-	env, err := c.Repo().Environment().ReadEnvironmentByOwnerRepoName(owner, repo)
+	env, err := c.Repo().Environment().ReadEnvironmentByWebhookIDOwnerRepoName(webhookID, owner, repo)
 
 	if err != nil {
 		return err

+ 3 - 3
api/server/router/base.go

@@ -1,6 +1,8 @@
 package router
 
 import (
+	"fmt"
+
 	"github.com/go-chi/chi"
 	"github.com/porter-dev/porter/api/server/handlers/billing"
 	"github.com/porter-dev/porter/api/server/handlers/credentials"
@@ -538,7 +540,6 @@ func GetBaseRoutes(
 	})
 
 	if config.ServerConf.GithubIncomingWebhookSecret != "" {
-
 		// POST /api/github/incoming_webhook -> webhook.NewGithubIncomingWebhook
 		githubIncomingWebhookEndpoint := factory.NewAPIEndpoint(
 			&types.APIRequestMetadata{
@@ -546,7 +547,7 @@ func GetBaseRoutes(
 				Method: types.HTTPVerbPost,
 				Path: &types.Path{
 					Parent:       basePath,
-					RelativePath: "/github/incoming_webhook",
+					RelativePath: fmt.Sprintf("/github/incoming_webhook/{%s}", types.URLParamIncomingWebhookID),
 				},
 				Scopes: []types.PermissionScope{},
 			},
@@ -563,7 +564,6 @@ func GetBaseRoutes(
 			Handler:  githubIncomingWebhookHandler,
 			Router:   r,
 		})
-
 	}
 
 	return routes

+ 5 - 4
api/types/git_installation.go

@@ -23,10 +23,11 @@ type Repo struct {
 type ListReposResponse []Repo
 
 const (
-	URLParamGitKind      URLParam = "kind"
-	URLParamGitRepoOwner URLParam = "owner"
-	URLParamGitRepoName  URLParam = "name"
-	URLParamGitBranch    URLParam = "branch"
+	URLParamGitKind           URLParam = "kind"
+	URLParamGitRepoOwner      URLParam = "owner"
+	URLParamGitRepoName       URLParam = "name"
+	URLParamGitBranch         URLParam = "branch"
+	URLParamIncomingWebhookID URLParam = "webhook_id"
 )
 
 type ListRepoBranchesResponse []string

+ 4 - 0
internal/models/environment.go

@@ -18,6 +18,10 @@ type Environment struct {
 
 	Name string
 	Mode string
+
+	// WebhookID uniquely identifies the environment when other fields (project, cluster)
+	// aren't present
+	WebhookID string
 }
 
 func (e *Environment) ToEnvironmentType() *types.Environment {

+ 2 - 1
internal/repository/environment.go

@@ -6,7 +6,8 @@ type EnvironmentRepository interface {
 	CreateEnvironment(env *models.Environment) (*models.Environment, error)
 	ReadEnvironment(projectID, clusterID, gitInstallationID uint, gitRepoOwner, gitRepoName string) (*models.Environment, error)
 	ReadEnvironmentByID(projectID, clusterID, envID uint) (*models.Environment, error)
-	ReadEnvironmentByOwnerRepoName(owner, repo string) (*models.Environment, error)
+	ReadEnvironmentByOwnerRepoName(projectID, clusterID uint, owner, repo string) (*models.Environment, error)
+	ReadEnvironmentByWebhookIDOwnerRepoName(webhookID, owner, repo string) (*models.Environment, error)
 	ListEnvironments(projectID, clusterID uint) ([]*models.Environment, error)
 	DeleteEnvironment(env *models.Environment) (*models.Environment, error)
 	CreateDeployment(deployment *models.Deployment) (*models.Deployment, error)

+ 15 - 2
internal/repository/gorm/environment.go

@@ -52,11 +52,24 @@ func (repo *EnvironmentRepository) ReadEnvironmentByID(projectID, clusterID, env
 }
 
 func (repo *EnvironmentRepository) ReadEnvironmentByOwnerRepoName(
+	projectID, clusterID uint,
 	gitRepoOwner, gitRepoName string,
 ) (*models.Environment, error) {
 	env := &models.Environment{}
-	if err := repo.db.Order("id desc").Where("git_repo_owner = ? AND git_repo_name = ?",
-		gitRepoOwner, gitRepoName,
+	if err := repo.db.Order("id desc").Where("project_id = ? AND cluster_id = ? AND git_repo_owner = ? AND git_repo_name = ?",
+		projectID, clusterID, gitRepoOwner, gitRepoName,
+	).First(&env).Error; err != nil {
+		return nil, err
+	}
+	return env, nil
+}
+
+func (repo *EnvironmentRepository) ReadEnvironmentByWebhookIDOwnerRepoName(
+	webhookID, gitRepoOwner, gitRepoName string,
+) (*models.Environment, error) {
+	env := &models.Environment{}
+	if err := repo.db.Order("id desc").Where("webhook_id = ? AND git_repo_owner = ? AND git_repo_name = ?",
+		webhookID, gitRepoOwner, gitRepoName,
 	).First(&env).Error; err != nil {
 		return nil, err
 	}

+ 8 - 1
internal/repository/test/environment.go

@@ -27,7 +27,14 @@ func (repo *EnvironmentRepository) ReadEnvironmentByID(projectID, clusterID, env
 	panic("unimplemented")
 }
 
-func (repo *EnvironmentRepository) ReadEnvironmentByOwnerRepoName(owner, repoName string) (*models.Environment, error) {
+func (repo *EnvironmentRepository) ReadEnvironmentByOwnerRepoName(
+	projectID, clusterID uint,
+	gitRepoOwner, gitRepoName string,
+) (*models.Environment, error) {
+	panic("unimplemented")
+}
+
+func (repo *EnvironmentRepository) ReadEnvironmentByWebhookIDOwnerRepoName(webhookID, owner, repoName string) (*models.Environment, error) {
 	panic("unimplemented")
 }