diff --git a/docs/data-sources/named_webhook.md b/docs/data-sources/named_webhook.md index 2ed74880..caaf0404 100644 --- a/docs/data-sources/named_webhook.md +++ b/docs/data-sources/named_webhook.md @@ -26,6 +26,5 @@ description: |- - `id` (String) The ID of this resource. - `labels` (Set of String) labels for the webhook to use when referring in policies or filtering them - `name` (String) the name for the webhook which will also be used to generate the id -- `secret` (String, Sensitive) secret used to sign each request so you're able to verify that the request comes from us. - `secret_header_keys` (Set of String) secret header keys which are currently set for this webhook - `space_id` (String) ID of the space the webhook is in diff --git a/docs/data-sources/webhook.md b/docs/data-sources/webhook.md index da2490b9..9a4b3618 100644 --- a/docs/data-sources/webhook.md +++ b/docs/data-sources/webhook.md @@ -35,4 +35,3 @@ data "spacelift_webhook" "webhook" { - `enabled` (Boolean) enables or disables sending webhooks - `endpoint` (String) endpoint to send the POST request to - `id` (String) The ID of this resource. -- `secret` (String) secret used to sign each POST request so you're able to verify that the request comes from us diff --git a/docs/resources/audit_trail_webhook.md b/docs/resources/audit_trail_webhook.md index b64c991a..1199f274 100644 --- a/docs/resources/audit_trail_webhook.md +++ b/docs/resources/audit_trail_webhook.md @@ -27,7 +27,7 @@ resource "spacelift_audit_trail_webhook" "example" { - `enabled` (Boolean) `enabled` determines whether the webhook is enabled. If it is not, Spacelift will not send any requests to the endpoint. - `endpoint` (String) `endpoint` is the URL to which Spacelift will send POST requests about audit events. -- `secret` (String, Sensitive) `secret` is a secret that Spacelift will send with the request. +- `secret` (String, Sensitive) `secret` is a secret that Spacelift will send with the request. Note that once it's created, it will be just an empty string in the state due to security reasons. ### Optional diff --git a/docs/resources/named_webhook.md b/docs/resources/named_webhook.md index 5a293501..bedfeb03 100644 --- a/docs/resources/named_webhook.md +++ b/docs/resources/named_webhook.md @@ -25,7 +25,7 @@ description: |- ### Optional - `labels` (Set of String) labels for the webhook to use when referring in policies or filtering them -- `secret` (String, Sensitive) secret used to sign each request so you're able to verify that the request comes from us. Defaults to an empty value. +- `secret` (String, Sensitive) secret used to sign each request so you're able to verify that the request comes from us. Defaults to an empty value. Note that once it's created, it will be just an empty string in the state due to security reasons. ### Read-Only diff --git a/docs/resources/webhook.md b/docs/resources/webhook.md index 80258852..6e78e280 100644 --- a/docs/resources/webhook.md +++ b/docs/resources/webhook.md @@ -30,7 +30,7 @@ resource "spacelift_webhook" "webhook" { - `enabled` (Boolean) enables or disables sending webhooks. Defaults to `true`. - `module_id` (String) ID of the module which triggers the webhooks -- `secret` (String, Sensitive) secret used to sign each POST request so you're able to verify that the request comes from us. Defaults to an empty value. +- `secret` (String, Sensitive) secret used to sign each POST request so you're able to verify that the request comes from us. Defaults to an empty value. Note that once it's created, it will be just an empty string in the state due to security reasons. - `stack_id` (String) ID of the stack which triggers the webhooks ### Read-Only diff --git a/spacelift/data_named_webhook.go b/spacelift/data_named_webhook.go index 9fc2cd95..6172d459 100644 --- a/spacelift/data_named_webhook.go +++ b/spacelift/data_named_webhook.go @@ -48,12 +48,6 @@ func dataNamedWebhook() *schema.Resource { }, Computed: true, }, - "secret": { - Type: schema.TypeString, - Description: "secret used to sign each request so you're able to verify that the request comes from us.", - Computed: true, - Sensitive: true, - }, "secret_header_keys": { Type: schema.TypeSet, Elem: &schema.Schema{ @@ -92,7 +86,6 @@ func dataNamedWebhookRead(ctx context.Context, d *schema.ResourceData, meta inte d.SetId(wh.ID) d.Set("name", wh.Name) d.Set("endpoint", wh.Endpoint) - d.Set("secret", wh.Secret) d.Set("enabled", wh.Enabled) d.Set("space_id", wh.Space.ID) diff --git a/spacelift/data_named_webhook_test.go b/spacelift/data_named_webhook_test.go index 02287c78..0401cde8 100644 --- a/spacelift/data_named_webhook_test.go +++ b/spacelift/data_named_webhook_test.go @@ -41,7 +41,6 @@ func TestNamedWebhookData(t *testing.T) { Attribute("webhook_id", IsNotEmpty()), Attribute("endpoint", Equals("https://bacon.org")), Attribute("enabled", Equals("true")), - Attribute("secret", Equals("super-secret")), SetContains("secret_header_keys", "thisisakey"), ), }}) diff --git a/spacelift/data_webhook.go b/spacelift/data_webhook.go index d5d9de5a..94688691 100644 --- a/spacelift/data_webhook.go +++ b/spacelift/data_webhook.go @@ -36,11 +36,6 @@ func dataWebhook() *schema.Resource { Optional: true, ExactlyOneOf: []string{"module_id", "stack_id"}, }, - "secret": { - Type: schema.TypeString, - Description: "secret used to sign each POST request so you're able to verify that the request comes from us", - Computed: true, - }, "stack_id": { Type: schema.TypeString, Description: "ID of the stack which triggers the webhooks", @@ -96,7 +91,6 @@ func dataModuleWebhookRead(ctx context.Context, d *schema.ResourceData, meta int d.SetId(webhookID) d.Set("enabled", module.Integrations.Webhooks[webhookIndex].Enabled) d.Set("endpoint", module.Integrations.Webhooks[webhookIndex].Endpoint) - d.Set("secret", module.Integrations.Webhooks[webhookIndex].Secret) return nil } @@ -132,7 +126,6 @@ func dataStackWebhookRead(ctx context.Context, d *schema.ResourceData, meta inte d.SetId(webhookID) d.Set("enabled", stack.Integrations.Webhooks[webhookIndex].Enabled) d.Set("endpoint", stack.Integrations.Webhooks[webhookIndex].Endpoint) - d.Set("secret", stack.Integrations.Webhooks[webhookIndex].Secret) return nil } diff --git a/spacelift/data_webhook_test.go b/spacelift/data_webhook_test.go index 28317584..78795a32 100644 --- a/spacelift/data_webhook_test.go +++ b/spacelift/data_webhook_test.go @@ -38,7 +38,6 @@ func TestWebhookData(t *testing.T) { Attribute("id", IsNotEmpty()), Attribute("endpoint", Equals("https://bacon.org")), Attribute("enabled", Equals("true")), - Attribute("secret", Equals("very-very-secret")), Attribute("stack_id", StartsWith("test-stack-")), AttributeNotPresent("module_id"), ), @@ -72,7 +71,6 @@ func TestWebhookData(t *testing.T) { Attribute("id", IsNotEmpty()), Attribute("endpoint", Equals("https://bacon.org")), Attribute("enabled", Equals("true")), - Attribute("secret", Equals("very-very-secret")), Attribute("module_id", Equals(fmt.Sprintf("terraform-default-test-module-%s", randomID))), AttributeNotPresent("stack_id"), ), diff --git a/spacelift/internal/structs/named_webhook_input.go b/spacelift/internal/structs/named_webhook_input.go index 7b231e33..18a4a991 100644 --- a/spacelift/internal/structs/named_webhook_input.go +++ b/spacelift/internal/structs/named_webhook_input.go @@ -9,7 +9,7 @@ type NamedWebhooksIntegration struct { Endpoint string `graphql:"endpoint" json:"endpoint"` Space Space `graphql:"space" json:"space"` Name string `graphql:"name" json:"name"` - Secret string `graphql:"secret" json:"secret"` + Secret *string `graphql:"secret" json:"secret"` SecretHeaders []string `graphql:"secretHeaders" json:"secretHeaders"` Labels []string `graphql:"labels" json:"labels"` } @@ -20,7 +20,7 @@ type NamedWebhooksIntegrationInput struct { Endpoint graphql.String `json:"endpoint"` Space graphql.ID `json:"space"` Name graphql.String `json:"name"` - Secret graphql.String `json:"secret"` + Secret *graphql.String `json:"secret"` Labels []graphql.String `json:"labels"` } diff --git a/spacelift/resource_audit_trail_webhook.go b/spacelift/resource_audit_trail_webhook.go index 834e6faf..a102e37a 100644 --- a/spacelift/resource_audit_trail_webhook.go +++ b/spacelift/resource_audit_trail_webhook.go @@ -44,10 +44,12 @@ func resourceAuditTrailWebhook() *schema.Resource { "information about the run that triggered the event.", }, "secret": { - Type: schema.TypeString, - Required: true, - Sensitive: true, - Description: "`secret` is a secret that Spacelift will send with the request.", + Type: schema.TypeString, + Required: true, + Sensitive: true, + ForceNew: true, + Description: "`secret` is a secret that Spacelift will send with the request. Note that once it's created, it will be just an empty string in the state due to security reasons.", + DiffSuppressFunc: ignoreOnceCreated, }, "custom_headers": { Type: schema.TypeMap, @@ -96,7 +98,7 @@ func resourceAuditTrailWebhookRead(ctx context.Context, data *schema.ResourceDat data.Set("enabled", query.AuditTrailWebhook.Enabled) data.Set("endpoint", query.AuditTrailWebhook.Endpoint) data.Set("include_runs", query.AuditTrailWebhook.IncludeRuns) - data.Set("secret", query.AuditTrailWebhook.Secret) + data.Set("secret", "") return nil } @@ -110,7 +112,6 @@ func resourceAuditTrailWebhookUpdate(ctx context.Context, data *schema.ResourceD Enabled: toBool(data.Get("enabled")), Endpoint: toString(data.Get("endpoint")), IncludeRuns: toBool(data.Get("include_runs")), - Secret: toString(data.Get("secret")), CustomHeaders: toOptionalStringMap(data.Get("custom_headers")), }, } diff --git a/spacelift/resource_audit_trail_webhook_test.go b/spacelift/resource_audit_trail_webhook_test.go index c6d48850..081c4426 100644 --- a/spacelift/resource_audit_trail_webhook_test.go +++ b/spacelift/resource_audit_trail_webhook_test.go @@ -44,7 +44,7 @@ func Test_resourceAuditTrailWebhook(t *testing.T) { Attribute("enabled", Equals("false")), Attribute("endpoint", Equals("https://example.com")), Attribute("include_runs", Equals("true")), - Attribute("secret", Equals("secret")), + Attribute("secret", Equals("")), ), }, { @@ -59,7 +59,7 @@ func Test_resourceAuditTrailWebhook(t *testing.T) { Attribute("enabled", Equals("false")), Attribute("endpoint", Equals("https://example.com")), Attribute("include_runs", Equals("true")), - Attribute("secret", Equals("secret")), + Attribute("secret", Equals("")), Attribute("custom_headers.%", Equals("2")), Attribute("custom_headers.X-Some-Header", Equals("some-value")), Attribute("custom_headers.X-Some-Header-2", Equals("some-value-2")), diff --git a/spacelift/resource_named_webhook.go b/spacelift/resource_named_webhook.go index 214425cb..e86b82d3 100644 --- a/spacelift/resource_named_webhook.go +++ b/spacelift/resource_named_webhook.go @@ -61,10 +61,12 @@ func resourceNamedWebhook() *schema.Resource { Optional: true, }, "secret": { - Type: schema.TypeString, - Description: "secret used to sign each request so you're able to verify that the request comes from us. Defaults to an empty value.", - Optional: true, - Sensitive: true, + Type: schema.TypeString, + Description: "secret used to sign each request so you're able to verify that the request comes from us. Defaults to an empty value. Note that once it's created, it will be just an empty string in the state due to security reasons.", + Optional: true, + Sensitive: true, + ForceNew: true, + DiffSuppressFunc: ignoreOnceCreated, }, }, } @@ -82,7 +84,7 @@ func resourceNamedWebhookCreate(ctx context.Context, d *schema.ResourceData, met Endpoint: graphql.String(d.Get("endpoint").(string)), Space: graphql.ID(d.Get("space_id").(string)), Name: graphql.String(d.Get("name").(string)), - Secret: graphql.String(d.Get("secret").(string)), + Secret: toOptionalString(d.Get("secret").(string)), Labels: []graphql.String{}, } @@ -121,9 +123,9 @@ func resourceNamedWebhookRead(ctx context.Context, d *schema.ResourceData, meta d.SetId(wh.ID) d.Set("name", wh.Name) d.Set("endpoint", wh.Endpoint) - d.Set("secret", wh.Secret) d.Set("enabled", wh.Enabled) d.Set("space_id", wh.Space.ID) + d.Set("secret", "") labels := schema.NewSet(schema.HashString, []interface{}{}) for _, label := range wh.Labels { @@ -159,7 +161,7 @@ func resourceNamedWebhookUpdate(ctx context.Context, d *schema.ResourceData, met "input": structs.NamedWebhooksIntegrationInput{ Enabled: graphql.Boolean(enabled), Endpoint: graphql.String(endpoint), - Secret: graphql.String(secret), + Secret: toOptionalString(secret), Name: graphql.String(name), Space: graphql.String(spaceID), Labels: labels, diff --git a/spacelift/resource_named_webhook_test.go b/spacelift/resource_named_webhook_test.go index 71a6b158..76ff1ef8 100644 --- a/spacelift/resource_named_webhook_test.go +++ b/spacelift/resource_named_webhook_test.go @@ -36,7 +36,7 @@ func TestNamedWebhookResource(t *testing.T) { resourceName, Attribute("id", IsNotEmpty()), Attribute("endpoint", Equals("https://bacon.net")), - Attribute("secret", Equals("super-secret")), + Attribute("secret", Equals("")), Attribute("space_id", Equals("root")), Attribute("name", Equals(fmt.Sprintf("testing-named-%s", randomID))), Attribute("enabled", Equals("true")), diff --git a/spacelift/resource_webhook.go b/spacelift/resource_webhook.go index 26d1de5f..945ff2a6 100644 --- a/spacelift/resource_webhook.go +++ b/spacelift/resource_webhook.go @@ -72,11 +72,13 @@ func resourceWebhook() *schema.Resource { ExactlyOneOf: []string{"module_id", "stack_id"}, }, "secret": { - Type: schema.TypeString, - Description: "secret used to sign each POST request so you're able to verify that the request comes from us. Defaults to an empty value.", - Optional: true, - Sensitive: true, - Default: "", + Type: schema.TypeString, + Description: "secret used to sign each POST request so you're able to verify that the request comes from us. Defaults to an empty value. Note that once it's created, it will be just an empty string in the state due to security reasons.", + Optional: true, + Sensitive: true, + ForceNew: true, + Default: "", + DiffSuppressFunc: ignoreOnceCreated, }, "stack_id": { Type: schema.TypeString, @@ -128,7 +130,7 @@ func resourceWebhookCreate(ctx context.Context, d *schema.ResourceData, meta int d.SetId(mutation.WebhooksIntegration.ID) - return nil + return resourceWebhookRead(ctx, d, meta) } func resourceWebhookRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -175,7 +177,7 @@ func resourceModuleWebhookRead(ctx context.Context, d *schema.ResourceData, meta d.SetId(webhookID) d.Set("enabled", module.Integrations.Webhooks[webhookIndex].Enabled) d.Set("endpoint", module.Integrations.Webhooks[webhookIndex].Endpoint) - d.Set("secret", module.Integrations.Webhooks[webhookIndex].Secret) + d.Set("secret", "") return nil } @@ -216,7 +218,7 @@ func resourceStackWebhookRead(ctx context.Context, d *schema.ResourceData, meta d.SetId(webhookID) d.Set("enabled", stack.Integrations.Webhooks[webhookIndex].Enabled) d.Set("endpoint", stack.Integrations.Webhooks[webhookIndex].Endpoint) - d.Set("secret", stack.Integrations.Webhooks[webhookIndex].Secret) + d.Set("secret", "") return nil } @@ -224,7 +226,6 @@ func resourceStackWebhookRead(ctx context.Context, d *schema.ResourceData, meta func resourceWebhookUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { enabled := d.Get("enabled").(bool) endpoint := d.Get("endpoint").(string) - secret := d.Get("secret").(string) webhookID := d.Id() var mutation struct { @@ -239,7 +240,6 @@ func resourceWebhookUpdate(ctx context.Context, d *schema.ResourceData, meta int "input": structs.WebhooksIntegrationInput{ Enabled: graphql.Boolean(enabled), Endpoint: graphql.String(endpoint), - Secret: graphql.String(secret), }, } diff --git a/spacelift/resource_webhook_test.go b/spacelift/resource_webhook_test.go index 51178958..1eb70bcf 100644 --- a/spacelift/resource_webhook_test.go +++ b/spacelift/resource_webhook_test.go @@ -39,7 +39,7 @@ func TestWebhookResource(t *testing.T) { resourceName, Attribute("id", IsNotEmpty()), Attribute("endpoint", Equals("https://bacon.org")), - Attribute("secret", Equals("very-very-secret")), + Attribute("secret", Equals("")), ), }, { @@ -77,7 +77,7 @@ func TestWebhookResource(t *testing.T) { resourceName, Attribute("id", IsNotEmpty()), Attribute("endpoint", Equals("https://bacon.org")), - Attribute("secret", Equals("very-very-secret")), + Attribute("secret", Equals("")), ), }, {