Skip to content

Commit

Permalink
chore: disable processing private repos on repo register and webhook …
Browse files Browse the repository at this point in the history
…events

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
  • Loading branch information
rdimitrov committed Oct 10, 2023
1 parent a5f2a7c commit 0491147
Showing 1 changed file with 83 additions and 72 deletions.
155 changes: 83 additions & 72 deletions internal/controlplane/handlers_githubwebhooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ func (s *Server) HandleGitHubWebHook() http.HandlerFunc {
m.Metadata.Set("id", github.DeliveryID(r))
m.Metadata.Set("provider", string(db.ProviderTypeGithub))
m.Metadata.Set("source", "https://api.github.com/") // TODO: handle other sources

m.Metadata.Set("type", github.WebHookType(r))
// m.Metadata.Set("subject", ghEvent.GetRepo().GetFullName())
// m.Metadata.Set("time", ghEvent.GetCreatedAt().String())
Expand Down Expand Up @@ -179,7 +178,7 @@ func (s *Server) registerWebhookForRepository(
},
}

// Let's verify that the repository actually exists.
// let's verify that the repository actually exists.
repoGet, err := client.GetRepository(ctx, repo.Owner, repo.Name)
if err != nil {
errorStr := err.Error()
Expand All @@ -188,6 +187,14 @@ func (s *Server) registerWebhookForRepository(
continue
}

// skip if we try to register a private repository
if repoGet.GetPrivate() {
errorStr := "repository is private"
regResult.Status.Error = &errorStr
registerData = append(registerData, regResult)
continue
}

urlUUID := uuid.New().String()

webhookUrl := fmt.Sprintf("%s/%s", url, urlUUID)
Expand Down Expand Up @@ -276,18 +283,48 @@ func (s *Server) parseGithubEventForProcessing(
return fmt.Errorf("error unmarshalling payload: %w", err)
}

ctx := context.Background()

// get information about the repository from the payload
dbRepo, err := getRepoInformationFromPayload(ctx, s.store, payload)
if err != nil {
return fmt.Errorf("error getting repo information from payload: %w", err)
}
g := dbRepo.ProjectID

// get the provider for the repository
prov, err := s.store.GetProviderByName(ctx, db.GetProviderByNameParams{
Name: dbRepo.Provider,
ProjectID: dbRepo.ProjectID,
})
if err != nil {
return fmt.Errorf("error getting provider: %w", err)
}

provBuilder, err := providers.GetProviderBuilder(ctx, prov, g, s.store, s.cryptoEngine)
if err != nil {
return fmt.Errorf("error building client: %w", err)
}

// do not process events that are coming from a (now) private repository
err = isRepoPrivate(ctx, dbRepo, provBuilder)
if err != nil {
log.Printf("webhook events from private repos are not allowed. Skipping execution.")
return err
}

// determine if the payload is an artifact published event
// TODO: this needs to be managed via signals
hook_type := msg.Metadata.Get("type")
if hook_type == "package" {
if payload["action"] == "published" {
return s.parseArtifactPublishedEvent(
context.Background(), payload, msg)
ctx, payload, msg, dbRepo, provBuilder)
}
} else if hook_type == "pull_request" {
if payload["action"] == "opened" || payload["action"] == "synchronize" {
return s.parsePullRequestModEvent(
context.Background(), payload, msg)
return parsePullRequestModEvent(
ctx, payload, msg, dbRepo, provBuilder)
}
}

Expand All @@ -298,27 +335,14 @@ func (s *Server) parseGithubEventForProcessing(
return nil
}

return s.parseRepoEvent(context.Background(), payload, msg)
return parseRepoEvent(msg, dbRepo, provBuilder.GetName())
}

func (s *Server) parseRepoEvent(
ctx context.Context,
whPayload map[string]any,
func parseRepoEvent(
msg *message.Message,
dbrepo db.Repository,
providerName string,
) error {
dbrepo, err := getRepoInformationFromPayload(ctx, s.store, whPayload)
if err != nil {
return err
}

provider, err := s.store.GetProviderByName(ctx, db.GetProviderByNameParams{
Name: dbrepo.Provider,
ProjectID: dbrepo.ProjectID,
})
if err != nil {
return fmt.Errorf("error getting provider: %w", err)
}

// protobufs are our API, so we always execute on these instead of the DB directly.
repo := &pb.Repository{
Owner: dbrepo.RepoOwner,
Expand All @@ -332,7 +356,7 @@ func (s *Server) parseRepoEvent(
}

eiw := engine.NewEntityInfoWrapper().
WithProvider(provider.Name).
WithProvider(providerName).
WithRepository(repo).
WithProjectID(dbrepo.ProjectID).
WithRepositoryID(dbrepo.ID)
Expand All @@ -344,40 +368,22 @@ func (s *Server) parseArtifactPublishedEvent(
ctx context.Context,
whPayload map[string]any,
msg *message.Message,
dbrepo db.Repository,
prov *providers.ProviderBuilder,
) error {
// we need to have information about package and repository
if whPayload["package"] == nil || whPayload["repository"] == nil {
log.Printf("could not determine relevant entity for event. Skipping execution.")
return nil
}

// extract information about repository so we can identity the group and associated rules
dbrepo, err := getRepoInformationFromPayload(ctx, s.store, whPayload)
if err != nil {
return fmt.Errorf("error getting repo information from payload: %w", err)
}
g := dbrepo.ProjectID

prov, err := s.store.GetProviderByName(ctx, db.GetProviderByNameParams{
Name: dbrepo.Provider,
ProjectID: dbrepo.ProjectID,
})
if err != nil {
return fmt.Errorf("error getting provider: %w", err)
}

p, err := providers.GetProviderBuilder(ctx, prov, g, s.store, s.cryptoEngine)
if err != nil {
return fmt.Errorf("error building client: %w", err)
}

// NOTE(jaosorior): this webhook is very specific to github
if !p.Implements(db.ProviderTypeGithub) {
log.Printf("provider %s is not supported for github webhook", p.GetName())
if !prov.Implements(db.ProviderTypeGithub) {
log.Printf("provider %s is not supported for github webhook", prov.GetName())
return nil
}

cli, err := p.GetGitHub(ctx)
cli, err := prov.GetGitHub(ctx)
if err != nil {
log.Printf("error creating github provider: %v", err)
return nil
Expand All @@ -400,46 +406,28 @@ func (s *Server) parseArtifactPublishedEvent(

eiw := engine.NewEntityInfoWrapper().
WithArtifact(pbArtifact).
WithProvider(prov.Name).
WithProvider(prov.GetName()).
WithProjectID(dbrepo.ProjectID).
WithRepositoryID(dbrepo.ID).
WithArtifactID(dbArtifact.ID)

return eiw.ToMessage(msg)
}

func (s *Server) parsePullRequestModEvent(
func parsePullRequestModEvent(
ctx context.Context,
whPayload map[string]any,
msg *message.Message,
dbrepo db.Repository,
prov *providers.ProviderBuilder,
) error {
// extract information about repository so we can identify the group and associated rules
dbrepo, err := getRepoInformationFromPayload(ctx, s.store, whPayload)
if err != nil {
return fmt.Errorf("error getting repo information from payload: %w", err)
}
g := dbrepo.ProjectID

prov, err := s.store.GetProviderByName(ctx, db.GetProviderByNameParams{
Name: dbrepo.Provider,
ProjectID: dbrepo.ProjectID,
})
if err != nil {
return fmt.Errorf("error getting provider: %w", err)
}

p, err := providers.GetProviderBuilder(ctx, prov, g, s.store, s.cryptoEngine)
if err != nil {
return fmt.Errorf("error building client: %w", err)
}

// NOTE(jaosorior): this webhook is very specific to github
if !p.Implements(db.ProviderTypeGithub) {
log.Printf("provider %s is not supported for github webhook", p.GetName())
if !prov.Implements(db.ProviderTypeGithub) {
log.Printf("provider %s is not supported for github webhook", prov.GetName())
return nil
}

cli, err := p.GetGitHub(ctx)
cli, err := prov.GetGitHub(ctx)
if err != nil {
log.Printf("error creating github provider: %v", err)
return nil
Expand All @@ -460,7 +448,7 @@ func (s *Server) parsePullRequestModEvent(
eiw := engine.NewEntityInfoWrapper().
WithPullRequest(prEvalInfo).
WithPullRequestNumber(prEvalInfo.Number).
WithProvider(prov.Name).
WithProvider(prov.GetName()).
WithProjectID(dbrepo.ProjectID).
WithRepositoryID(dbrepo.ID)

Expand Down Expand Up @@ -916,3 +904,26 @@ func parseRepoID(repoID any) (int32, error) {
return 0, fmt.Errorf("unknown type for repoID: %T", v)
}
}

func isRepoPrivate(ctx context.Context, repo db.Repository, p *providers.ProviderBuilder) error {
// get the provider client
cli, err := p.GetGitHub(ctx)
if err != nil {
log.Printf("error creating github provider: %v", err)
return nil
}

// let's verify that the repository actually exists.
repoGet, err := cli.GetRepository(ctx, repo.RepoOwner, repo.RepoName)
if err != nil {
return fmt.Errorf("error getting %s/%s repository: %w", repo.RepoOwner, repo.RepoName, err)
}

// error out if we try to process a private repository
if repoGet.GetPrivate() {
return fmt.Errorf("repository %s/%s is private", repo.RepoOwner, repo.RepoName)
}

// all good
return nil
}

0 comments on commit 0491147

Please sign in to comment.