[Provisioning] Add mutation hook to generate webhook URL and secret (#96742)

Add mutation hook to generate webhook URL and secret
This commit is contained in:
Roberto Jiménez Sánchez authored and GitHub committed 2024-11-20 10:45:24 +01:00
1 parent 8fda03d3d5
commit a9931ff283
2 files changed
+56 -10

No files matched your search

+4 -8
View File
@@ -56,6 +56,9 @@ func (r *githubRepository) Validate() (list field.ErrorList) {
if gh.Repository == "" {
list = append(list, field.Required(field.NewPath("spec", "github", "repository"), "a github repo name is required"))
}
if gh.Branch == "" {
list = append(list, field.Required(field.NewPath("spec", "github", "branch"), "a github branch is required"))
}
if gh.Token == "" {
list = append(list, field.Required(field.NewPath("spec", "github", "token"), "a github access token is required"))
}
@@ -181,16 +184,9 @@ func (r *githubRepository) onPushEvent(ctx context.Context, event *github.PushEv
return fmt.Errorf("repository mismatch")
}
branch := r.config.Spec.GitHub.Branch
if branch == "" {
// Default to main if no branch is specified
// TODO: should this be a mutation hook instead?
branch = "main"
}
// Skip silently if the event is not for the main/master branch
// as we cannot configure the webhook to only publish events for the main branch
if event.GetRef() != fmt.Sprintf("refs/heads/%s", branch) {
if event.GetRef() != fmt.Sprintf("refs/heads/%s", r.config.Spec.GitHub.Branch) {
return nil
}
+52 -2
View File
@@ -2,6 +2,9 @@ package provisioning
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"log/slog"
"path/filepath"
@@ -39,13 +42,15 @@ var (
// This is used just so wire has something unique to return
type ProvisioningAPIBuilder struct {
cfg *setting.Cfg
getter rest.Getter
localFileResolver *LocalFolderResolver
logger *slog.Logger
}
func NewProvisioningAPIBuilder(local *LocalFolderResolver) *ProvisioningAPIBuilder {
func NewProvisioningAPIBuilder(cfg *setting.Cfg, local *LocalFolderResolver) *ProvisioningAPIBuilder {
return &ProvisioningAPIBuilder{
cfg: cfg,
localFileResolver: local,
logger: slog.Default().With("logger", "provisioning-api-builder"),
}
@@ -60,7 +65,7 @@ func RegisterAPIService(
if !features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) {
return nil // skip registration unless opting into experimental apis
}
builder := NewProvisioningAPIBuilder(&LocalFolderResolver{
builder := NewProvisioningAPIBuilder(cfg, &LocalFolderResolver{
ProvisioningPath: cfg.ProvisioningPath,
DevenvPath: filepath.Join(cfg.HomePath, "devenv"),
})
@@ -237,6 +242,38 @@ func (b *ProvisioningAPIBuilder) afterDelete(obj runtime.Object, opts *metav1.De
return
}
}
func (b *ProvisioningAPIBuilder) Mutate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
obj := a.GetObject()
if obj == nil || a.GetOperation() == admission.Connect {
return nil // This is normal for sub-resource
}
r, ok := obj.(*provisioning.Repository)
if !ok {
return fmt.Errorf("expected repository configuration")
}
if r.Spec.Type == provisioning.GithubRepositoryType {
if r.Spec.GitHub == nil {
return fmt.Errorf("github configuration is required")
}
if r.Spec.GitHub.Branch == "" {
r.Spec.GitHub.Branch = "main"
}
if r.Spec.GitHub.WebhookURL == "" {
r.Spec.GitHub.WebhookURL = fmt.Sprintf("%sapi/provisioning/v0alpha1/namespaces/%s/repositories/%s/webhook", b.cfg.AppURL, a.GetNamespace(), a.GetName())
}
if r.Spec.GitHub.WebhookSecret == "" {
r.Spec.GitHub.WebhookSecret = b.generateWebhookSecret(r.Spec.GitHub.Token)
}
}
return nil
}
func (b *ProvisioningAPIBuilder) Validate(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) (err error) {
obj := a.GetObject()
@@ -449,3 +486,16 @@ spec:
return oas, nil
}
// generateWebhookSecret generates a webhook secret from a token
// using the configured secret key. The generated secret is consistent.
// TODO: this must be replaced by a app platform secrets once we have that.
func (b *ProvisioningAPIBuilder) generateWebhookSecret(token string) string {
secretKey := []byte(b.cfg.SecretKey)
h := hmac.New(sha256.New, secretKey)
h.Write([]byte(token))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}