[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:
1 parent
8fda03d3d5
commit
a9931ff283
2 files changed
+56
-10
No files matched your search
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
Reference in new issue
Block a user