From 1323abe664c753bd874167c3dc843780089c6dd4 Mon Sep 17 00:00:00 2001 From: raulbarreto-delivion <77453382+raulbarreto-delivion@users.noreply.github.com> Date: Wed, 15 Dec 2021 01:52:58 +0100 Subject: [PATCH] Fix update webhook and use secret for webhook authentication (#42) * Fix update repository webhooks and extend webhook tests * Use secret to authenticate the webhook payload and extend the tests with the secret Co-authored-by: Raul Barreto --- bitbucket/resource_repository_webhook.go | 42 ++++++++---- bitbucket/resource_repository_webhook_test.go | 66 +++++++++++++++++++ .../bitbucketserver_repository_webhook.md | 2 + 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/bitbucket/resource_repository_webhook.go b/bitbucket/resource_repository_webhook.go index 75b485f..61eed2b 100644 --- a/bitbucket/resource_repository_webhook.go +++ b/bitbucket/resource_repository_webhook.go @@ -9,14 +9,19 @@ import ( "strings" ) +type WebhookConfiguration struct { + Secret string `json:"secret,omitempty"` +} + type Webhook struct { - ID int `json:"id,omitempty"` - Name string `json:"name,omitempty"` - CreatedDate jsonTime `json:"createdDate,omitempty"` - UpdatedDate jsonTime `json:"updatedDate,omitempty"` - URL string `json:"url,omitempty"` - Active bool `json:"active,omitempty"` - Events []interface{} `json:"events"` + ID int `json:"id,omitempty"` + Name string `json:"name,omitempty"` + CreatedDate jsonTime `json:"createdDate,omitempty"` + UpdatedDate jsonTime `json:"updatedDate,omitempty"` + URL string `json:"url,omitempty"` + Active bool `json:"active,omitempty"` + Events []interface{} `json:"events"` + Configuration WebhookConfiguration `json:"configuration"` } type WebhookListResponse struct { @@ -64,6 +69,12 @@ func resourceRepositoryWebhook() *schema.Resource { ForceNew: false, Elem: &schema.Schema{Type: schema.TypeString}, }, + "secret": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Default: "", + }, "active": { Type: schema.TypeBool, Optional: true, @@ -101,7 +112,7 @@ func resourceRepositoryWebhookUpdate(d *schema.ResourceData, m interface{}) erro return err } - return resourceRepositoryHookRead(d, m) + return resourceRepositoryWebhookRead(d, m) } func resourceRepositoryWebhookCreate(d *schema.ResourceData, m interface{}) error { @@ -183,11 +194,16 @@ func resourceRepositoryWebhookDelete(d *schema.ResourceData, m interface{}) erro } func newWebhookFromResource(d *schema.ResourceData) (Hook *Webhook) { + configuration := &WebhookConfiguration{ + Secret: d.Get("secret").(string), + } + webhook := &Webhook{ - Name: d.Get("name").(string), - URL: d.Get("webhook_url").(string), - Active: d.Get("active").(bool), - Events: d.Get("events").([]interface{}), + Name: d.Get("name").(string), + URL: d.Get("webhook_url").(string), + Active: d.Get("active").(bool), + Events: d.Get("events").([]interface{}), + Configuration: *configuration, } return webhook @@ -224,6 +240,7 @@ func getRepositoryWebhookFromId(d *schema.ResourceData, m interface{}) error { _ = d.Set("webhook_url", webhook.URL) _ = d.Set("active", webhook.Active) _ = d.Set("events", webhook.Events) + _ = d.Set("secret", webhook.Configuration.Secret) return nil } @@ -260,6 +277,7 @@ func getRepositoryWebhookFromList(d *schema.ResourceData, m interface{}) error { _ = d.Set("webhook_url", webhook.URL) _ = d.Set("active", webhook.Active) _ = d.Set("events", webhook.Events) + _ = d.Set("secret", webhook.Configuration.Secret) return nil } } diff --git a/bitbucket/resource_repository_webhook_test.go b/bitbucket/resource_repository_webhook_test.go index 7666cf4..bd78e65 100644 --- a/bitbucket/resource_repository_webhook_test.go +++ b/bitbucket/resource_repository_webhook_test.go @@ -42,8 +42,74 @@ func TestAccBitbucketResourceRepositoryWebhook_simple(t *testing.T) { resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "project", projectKey), resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "repository", "repo"), resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "webhook_url", "https://www.google.com/"), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "secret", ""), ), }, + { + Config: config, + ExpectNonEmptyPlan: false, + }, + }, + }) +} + +func TestAccBitbucketResourceRepositoryWebhook_complete(t *testing.T) { + projectKey := fmt.Sprintf("TEST%v", rand.New(rand.NewSource(time.Now().UnixNano())).Int()) + + configString := ` + resource "bitbucketserver_project" "test" { + key = "%v" + name = "test-project-%v" + } + + resource "bitbucketserver_repository" "test" { + project = bitbucketserver_project.test.key + name = "repo" + } + + resource "bitbucketserver_repository_webhook" "test" { + project = bitbucketserver_project.test.key + repository = bitbucketserver_repository.test.slug + name = "%v" + webhook_url = "%v" + secret = "abc" + events = ["repo:refs_changed"] + active = true + } + ` + + config := fmt.Sprintf(configString, projectKey, projectKey, "test", "https://www.oldurl.com/") + newConfig := fmt.Sprintf(configString, projectKey, projectKey, "test2", "https://www.newurl.com/") + + // Create resource + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "project", projectKey), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "repository", "repo"), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "name", "test"), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "webhook_url", "https://www.oldurl.com/"), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "secret", "abc"), + ), + }, + { + Config: newConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "project", projectKey), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "repository", "repo"), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "name", "test2"), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "webhook_url", "https://www.newurl.com/"), + resource.TestCheckResourceAttr("bitbucketserver_repository_webhook.test", "secret", "abc"), + ), + }, + { + Config: newConfig, + Destroy: true, + }, }, }) } diff --git a/docs/resources/bitbucketserver_repository_webhook.md b/docs/resources/bitbucketserver_repository_webhook.md index 32fc68f..66e3bca 100644 --- a/docs/resources/bitbucketserver_repository_webhook.md +++ b/docs/resources/bitbucketserver_repository_webhook.md @@ -20,6 +20,7 @@ resource "bitbucketserver_repository_webhook" "main" { repository = bitbucketserver_repository.test.slug name = "google" webhook_url = "https://www.google.com/" + secret = "abc" events = ["repo:refs_changed"] active = true } @@ -31,6 +32,7 @@ resource "bitbucketserver_repository_webhook" "main" { * `repository` - Required. Repository slug to enable hook for. * `name` - Required. Name of the webhook. * `webhook_url` - Required. The URL of the webhook. +* `secret` - Optional. Secret used to authenticate the payload. * `events` - Required. A list of events to trigger the webhook url. * `active` - Optional. Enable or disable the webhook. Default: true