From 9e37fce14280d0b0e77b330f442edfdb8747362d Mon Sep 17 00:00:00 2001 From: brookesargent Date: Wed, 27 Nov 2024 10:03:33 -0500 Subject: [PATCH] add some tests --- .../provider/webhook_recipient_resource.go | 39 ++++++++++ .../webhook_recipient_resource_test.go | 71 +++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/internal/provider/webhook_recipient_resource.go b/internal/provider/webhook_recipient_resource.go index f4074c0c..4038ff73 100644 --- a/internal/provider/webhook_recipient_resource.go +++ b/internal/provider/webhook_recipient_resource.go @@ -3,7 +3,9 @@ package provider import ( "context" "errors" + "fmt" "regexp" + "strings" "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" @@ -18,6 +20,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "golang.org/x/net/http/httpguts" "github.com/honeycombio/terraform-provider-honeycombio/client" "github.com/honeycombio/terraform-provider-honeycombio/internal/helper" @@ -34,6 +37,10 @@ var ( webhookTemplateTypes = []string{"trigger", "exhaustion_time", "budget_rate"} webhookTemplateNameRegex = regexp.MustCompile(`^[a-z](?:[a-zA-Z0-9]+$)?$`) + + defaultHeaderContentType = "Content-Type" + defaultHeaderUserAgent = "User-Agent" + defaultHeaderXHoneycombWebhookToken = "X-Honeycomb-Webhook-Token" ) type webhookRecipientResource struct { @@ -203,6 +210,9 @@ func (r *webhookRecipientResource) ValidateConfig(ctx context.Context, req resou var variables []models.TemplateVariableModel data.Variables.ElementsAs(ctx, &variables, false) + var headers []models.WebhookHeaderModel + data.Headers.ElementsAs(ctx, &headers, false) + triggerTmplExists := false budgetRateTmplExists := false exhaustionTimeTmplExists := false @@ -261,6 +271,35 @@ func (r *webhookRecipientResource) ValidateConfig(ctx context.Context, req resou } duplicateMap[name] = true } + + // webhook headers cannot used reserved keys and must be valid http headers + for i, h := range headers { + header := strings.ToLower(h.Name.ValueString()) + if header == strings.ToLower(defaultHeaderContentType) || + header == strings.ToLower(defaultHeaderUserAgent) || + header == strings.ToLower(defaultHeaderXHoneycombWebhookToken) { + resp.Diagnostics.AddAttributeError( + path.Root("header").AtListIndex(i).AtName("name"), + "Conflicting configuration arguments", + fmt.Sprintf("cannot match reserved \"name\": %s", h.Name.ValueString()), + ) + } + + if !httpguts.ValidHeaderFieldName(h.Name.ValueString()) { + resp.Diagnostics.AddAttributeError( + path.Root("header").AtListIndex(i).AtName("name"), + "Conflicting configuration arguments", + "invalid webhook header name", + ) + } + if !httpguts.ValidHeaderFieldValue(h.Value.ValueString()) { + resp.Diagnostics.AddAttributeError( + path.Root("header").AtListIndex(i).AtName("value"), + "Conflicting configuration arguments", + "invalid webhook header value", + ) + } + } } func (r *webhookRecipientResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/provider/webhook_recipient_resource_test.go b/internal/provider/webhook_recipient_resource_test.go index 9a42e022..f285e7f4 100644 --- a/internal/provider/webhook_recipient_resource_test.go +++ b/internal/provider/webhook_recipient_resource_test.go @@ -665,7 +665,78 @@ resource "honeycombio_webhook_recipient" "test" { }, }) }) +} + +func TestAcc_WebhookRecipientResource_validateReservedWebhookHeader(t *testing.T) { + name := test.RandomStringWithPrefix("test.", 20) + url := test.RandomURL() + + resource.Test(t, resource.TestCase{ + PreCheck: testAccPreCheck(t), + ProtoV5ProviderFactories: testAccProtoV5MuxServerFactory, + CheckDestroy: testAccEnsureRecipientDestroyed(t), + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(` +resource "honeycombio_webhook_recipient" "test" { + name = "%s" + url = "%s" + + template { + type = "trigger" + body = "body" + } + header { + name = "Content-Type" + value = "xml" + } + + variable { + name = "severity" + default_value = "warning" + } +}`, name, url), + ExpectError: regexp.MustCompile(`cannot match reserved "name": Content-Type`), + }, + }, + }) +} + +func TestAcc_WebhookRecipientResource_validateInvalidWebhookHeader(t *testing.T) { + name := test.RandomStringWithPrefix("test.", 20) + url := test.RandomURL() + + resource.Test(t, resource.TestCase{ + PreCheck: testAccPreCheck(t), + ProtoV5ProviderFactories: testAccProtoV5MuxServerFactory, + CheckDestroy: testAccEnsureRecipientDestroyed(t), + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(` +resource "honeycombio_webhook_recipient" "test" { + name = "%s" + url = "%s" + + template { + type = "trigger" + body = "body" + } + + header { + name = "é" + value = "test" + } + + variable { + name = "severity" + default_value = "warning" + } +}`, name, url), + ExpectError: regexp.MustCompile(`invalid webhook header name`), + }, + }, + }) } // TestAcc_WebhookRecipientResource_UpgradeFromVersion027 tests the migration case from the