Skip to content

Commit a06e930

Browse files
jhrozekJAORMX
andauthored
Revert "Add webhook secret bootstrap and verification for Gitlab (#4492)" (#4504)
This reverts commit 052daf1. Co-authored-by: Juan Antonio Osorio <[email protected]>
1 parent f1f7b18 commit a06e930

File tree

10 files changed

+26
-315
lines changed

10 files changed

+26
-315
lines changed

cmd/dev/app/rule_type/rttst.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ func getProvider(pstr string, token string, providerConfigFile string) (provifv1
438438
}
439439

440440
// We may pass a "fake" webhook URL here as it is not used in the test
441-
client, err := gitlab.New(credentials.NewGitLabTokenCredential(token), cfg, "fake", "fake")
441+
client, err := gitlab.New(credentials.NewGitLabTokenCredential(token), cfg, "fake")
442442
if err != nil {
443443
return nil, fmt.Errorf("error instantiating gitlab provider: %w", err)
444444
}

internal/config/server/gitlab.go

-6
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,6 @@ package server
1919
type GitLabConfig struct {
2020
OAuthClientConfig `mapstructure:",squash"`
2121

22-
// WebhookSecrets is the configuration for the GitLab webhook secrets
23-
// setup and verification. This is used to verify incoming webhook requests
24-
// from GitLab, as well as to generate the webhook URL for GitLab to send
25-
// events to.
26-
WebhookSecrets `mapstructure:",squash"`
27-
2822
// Scopes is the list of scopes to request from the GitLab OAuth provider
2923
Scopes []string `mapstructure:"scopes"`
3024
}

internal/config/server/webhook.go

+2-12
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,10 @@ import (
2323

2424
// WebhookConfig is the configuration for our webhook capabilities
2525
type WebhookConfig struct {
26-
// WebhookSecrets is the configuration for the webhook secrets.
27-
// This is embedded in the WebhookConfig so that the secrets can be
28-
// used in the WebhookConfig, as the GitHub provider needs for now.
29-
WebhookSecrets `mapstructure:",squash"`
3026
// ExternalWebhookURL is the URL that we will send our webhook to
3127
ExternalWebhookURL string `mapstructure:"external_webhook_url"`
3228
// ExternalPingURL is the URL that we will send our ping to
3329
ExternalPingURL string `mapstructure:"external_ping_url"`
34-
}
35-
36-
// WebhookSecrets is the configuration for the webhook secrets. this is useful
37-
// to import in whatever provider configuration that needs to use some webhook
38-
// secrets.
39-
type WebhookSecrets struct {
4030
// WebhookSecret is the secret that we will use to sign our webhook
4131
WebhookSecret string `mapstructure:"webhook_secret"`
4232
// WebhookSecretFile is the location of the file containing the webhook secret
@@ -49,7 +39,7 @@ type WebhookSecrets struct {
4939

5040
// GetPreviousWebhookSecrets retrieves the previous webhook secrets from a file specified in the WebhookConfig.
5141
// It reads the contents of the file, splits the data by whitespace, and returns it as a slice of strings.
52-
func (wc *WebhookSecrets) GetPreviousWebhookSecrets() ([]string, error) {
42+
func (wc *WebhookConfig) GetPreviousWebhookSecrets() ([]string, error) {
5343
data, err := os.ReadFile(wc.PreviousWebhookSecretFile)
5444
if err != nil {
5545
return nil, fmt.Errorf("failed to read previous webhook secrets from file: %w", err)
@@ -61,6 +51,6 @@ func (wc *WebhookSecrets) GetPreviousWebhookSecrets() ([]string, error) {
6151
}
6252

6353
// GetWebhookSecret returns the GitHub App's webhook secret
64-
func (wc *WebhookSecrets) GetWebhookSecret() (string, error) {
54+
func (wc *WebhookConfig) GetWebhookSecret() (string, error) {
6555
return fileOrArg(wc.WebhookSecretFile, wc.WebhookSecret, "webhook secret")
6656
}

internal/controlplane/fuzz_test.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,7 @@ func FuzzGitHubEventParsers(f *testing.F) {
118118
}
119119
defer os.Remove(whSecretFile.Name())
120120

121-
whConfig := &server.WebhookConfig{
122-
WebhookSecrets: server.WebhookSecrets{
123-
WebhookSecretFile: whSecretFile.Name(),
124-
},
125-
}
121+
whConfig := &server.WebhookConfig{WebhookSecretFile: whSecretFile.Name()}
126122

127123
s := &Server{}
128124
ctx := context.Background()

internal/providers/gitlab/gitlab.go

+5-15
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,11 @@ type gitlabClient struct {
5757
glcfg *minderv1.GitLabProviderConfig
5858
webhookURL string
5959
gitConfig config.GitConfig
60-
61-
// secret for the webhook. This is stored in the
62-
// structure to allow efficient fetching.
63-
currentWebhookSecret string
6460
}
6561

6662
// New creates a new GitLab provider
6763
// Note that the webhook URL should already contain the provider class in the path
68-
func New(
69-
cred provifv1.GitLabCredential,
70-
cfg *minderv1.GitLabProviderConfig,
71-
webhookURL string,
72-
currentWebhookSecret string,
73-
) (*gitlabClient, error) {
64+
func New(cred provifv1.GitLabCredential, cfg *minderv1.GitLabProviderConfig, webhookURL string) (*gitlabClient, error) {
7465
// TODO: We need a context here.
7566
cli := oauth2.NewClient(context.Background(), cred.GetAsOAuth2TokenSource())
7667

@@ -83,11 +74,10 @@ func New(
8374
}
8475

8576
return &gitlabClient{
86-
cred: cred,
87-
cli: cli,
88-
glcfg: cfg,
89-
webhookURL: webhookURL,
90-
currentWebhookSecret: currentWebhookSecret,
77+
cred: cred,
78+
cli: cli,
79+
glcfg: cfg,
80+
webhookURL: webhookURL,
9181
// TODO: Add git config
9282
}, nil
9383
}

internal/providers/gitlab/manager/manager.go

+6-30
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ import (
2424
"net/url"
2525
"slices"
2626

27-
"github.com/rs/zerolog"
28-
2927
"github.com/stacklok/minder/internal/config/server"
3028
"github.com/stacklok/minder/internal/crypto"
3129
"github.com/stacklok/minder/internal/db"
@@ -41,12 +39,6 @@ type providerClassManager struct {
4139
glpcfg *server.GitLabConfig
4240
webhookURL string
4341
parentContext context.Context
44-
45-
// secrets for the webhook. These are stored in the
46-
// structure to allow efficient fetching. Rotation
47-
// requires a process restart.
48-
currentWebhookSecret string
49-
previousWebhookSecrets []string
5042
}
5143

5244
// NewGitLabProviderClassManager creates a new provider class manager for the dockerhub provider
@@ -58,33 +50,17 @@ func NewGitLabProviderClassManager(
5850
return nil, errors.New("webhook URL is required")
5951
}
6052

61-
if cfg == nil {
62-
return nil, errors.New("gitlab config is required")
63-
}
64-
6553
webhookURL, err := url.JoinPath(webhookURLBase, url.PathEscape(string(db.ProviderClassGitlab)))
6654
if err != nil {
6755
return nil, fmt.Errorf("error joining webhook URL: %w", err)
6856
}
6957

70-
whSecret, err := cfg.GetWebhookSecret()
71-
if err != nil {
72-
return nil, fmt.Errorf("error getting webhook secret: %w", err)
73-
}
74-
75-
previousSecrets, err := cfg.GetPreviousWebhookSecrets()
76-
if err != nil {
77-
zerolog.Ctx(ctx).Error().Err(err).Msg("previous secrets not loaded")
78-
}
79-
8058
return &providerClassManager{
81-
store: store,
82-
crypteng: crypteng,
83-
glpcfg: cfg,
84-
webhookURL: webhookURL,
85-
parentContext: ctx,
86-
currentWebhookSecret: whSecret,
87-
previousWebhookSecrets: previousSecrets,
59+
store: store,
60+
crypteng: crypteng,
61+
glpcfg: cfg,
62+
webhookURL: webhookURL,
63+
parentContext: ctx,
8864
}, nil
8965
}
9066

@@ -115,7 +91,7 @@ func (g *providerClassManager) Build(ctx context.Context, config *db.Provider) (
11591
return nil, fmt.Errorf("error parsing gitlab config: %w", err)
11692
}
11793

118-
cli, err := gitlab.New(creds, cfg, g.webhookURL, g.currentWebhookSecret)
94+
cli, err := gitlab.New(creds, cfg, g.webhookURL)
11995
if err != nil {
12096
return nil, fmt.Errorf("error creating gitlab client: %w", err)
12197
}

internal/providers/gitlab/manager/webhook.go

+2-57
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,16 @@
1515
package manager
1616

1717
import (
18-
"errors"
19-
"fmt"
2018
"net/http"
21-
"strings"
2219

23-
"github.com/google/uuid"
2420
"github.com/rs/zerolog"
25-
26-
"github.com/stacklok/minder/internal/providers/gitlab/webhooksecret"
2721
)
2822

2923
// GetWebhookHandler implements the ProviderManager interface
3024
// Note that this is where the whole webhook handler is defined and
3125
// will live.
3226
func (m *providerClassManager) GetWebhookHandler() http.Handler {
33-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
27+
return http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
3428
l := zerolog.Ctx(m.parentContext).With().
3529
Str("webhook", "gitlab").
3630
Str("method", r.Method).
@@ -40,57 +34,8 @@ func (m *providerClassManager) GetWebhookHandler() http.Handler {
4034
Str("content-type", r.Header.Get("Content-Type")).
4135
Logger()
4236

43-
// Validate the webhook secret
44-
if err := m.validateRequest(r); err != nil {
45-
l.Error().Err(err).Msg("invalid webhook request")
46-
http.Error(w, "invalid webhook request", http.StatusUnauthorized)
47-
return
48-
}
37+
// TODO: Implement webhook handler
4938

5039
l.Debug().Msg("received webhook")
5140
})
5241
}
53-
54-
func (m *providerClassManager) validateRequest(r *http.Request) error {
55-
// Validate the webhook secret
56-
gltok := r.Header.Get("X-Gitlab-Token")
57-
if gltok == "" {
58-
return errors.New("missing X-Gitlab-Token header")
59-
}
60-
61-
if err := m.validateToken(gltok, r); err != nil {
62-
return fmt.Errorf("invalid X-Gitlab-Token header: %w", err)
63-
}
64-
65-
return nil
66-
}
67-
68-
// validateToken validates the incoming GitLab webhook token
69-
// Validation takes the secret from the GitLab webhook configuration
70-
// appens the last element of the path to the URL (which is unique per entity)
71-
func (m *providerClassManager) validateToken(token string, req *http.Request) error {
72-
// Extract the unique ID from the URL path
73-
path := req.URL.Path
74-
uniq := path[strings.LastIndex(path, "/")+1:]
75-
76-
// uniq must be a valid UUID
77-
_, err := uuid.Parse(uniq)
78-
if err != nil {
79-
return errors.New("invalid unique ID")
80-
}
81-
82-
// Generate the expected secret
83-
if valid := webhooksecret.Verify(m.currentWebhookSecret, uniq, token); valid {
84-
// If the secret is valid, we can return
85-
return nil
86-
}
87-
88-
// Check the previous secrets
89-
for _, prev := range m.previousWebhookSecrets {
90-
if valid := webhooksecret.Verify(prev, uniq, token); valid {
91-
return nil
92-
}
93-
}
94-
95-
return errors.New("invalid webhook token")
96-
}

internal/providers/gitlab/registration.go

+9-18
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import (
2929
"github.com/xanzy/go-gitlab"
3030

3131
"github.com/stacklok/minder/internal/entities/properties"
32-
"github.com/stacklok/minder/internal/providers/gitlab/webhooksecret"
3332
"github.com/stacklok/minder/internal/util/ptr"
3433
minderv1 "github.com/stacklok/minder/pkg/api/protobuf/go/minder/v1"
3534
)
@@ -58,11 +57,8 @@ func (c *gitlabClient) RegisterEntity(
5857

5958
whprops, err := c.createWebhook(ctx, upstreamID)
6059
if err != nil {
61-
zerolog.Ctx(ctx).Error().
62-
Str("upstreamID", upstreamID).
63-
Str("provider-class", Class).
64-
Err(err).Msg("failed to create webhook")
65-
return nil, errors.New("failed to create webhook")
60+
// There is already enough context in the error message
61+
return nil, err
6662
}
6763

6864
return props.Merge(whprops), nil
@@ -106,20 +102,15 @@ func (c *gitlabClient) createWebhook(ctx context.Context, upstreamID string) (*p
106102
return nil, fmt.Errorf("failed to join URL path for webhook: %w", err)
107103
}
108104

109-
sec, err := webhooksecret.New(c.currentWebhookSecret, hookUUID.String())
110-
if err != nil {
111-
return nil, fmt.Errorf("failed to create webhook secret: %w", err)
112-
}
113-
114105
trve := ptr.Ptr(true)
115106
hreq := &gitlab.AddProjectHookOptions{
116-
URL: &webhookUniqueURL,
117-
Token: &sec,
118-
PushEvents: trve,
119-
TagPushEvents: trve,
120-
MergeRequestsEvents: trve,
121-
ReleasesEvents: trve,
122-
EnableSSLVerification: trve,
107+
URL: &webhookUniqueURL,
108+
// TODO: Add secret
109+
PushEvents: trve,
110+
TagPushEvents: trve,
111+
MergeRequestsEvents: trve,
112+
ReleasesEvents: trve,
113+
// TODO: Enable SSL verification
123114
}
124115

125116
hook, err := c.doCreateWebhook(ctx, createHookPath, hreq)

internal/providers/gitlab/webhooksecret/whsecret.go

-57
This file was deleted.

0 commit comments

Comments
 (0)