From 83b4b06ed2148196a8c709a8bf46baa9e6f2fab0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 29 Sep 2025 10:29:06 -0500 Subject: [PATCH 1/6] New action: aws_events_put_events --- internal/service/events/service_package_gen.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/service/events/service_package_gen.go b/internal/service/events/service_package_gen.go index 926a7e2ffea2..082a8622fb80 100644 --- a/internal/service/events/service_package_gen.go +++ b/internal/service/events/service_package_gen.go @@ -17,6 +17,17 @@ import ( type servicePackage struct{} +func (p *servicePackage) Actions(ctx context.Context) []*inttypes.ServicePackageAction { + return []*inttypes.ServicePackageAction{ + { + Factory: newPutEventsAction, + TypeName: "aws_events_put_events", + Name: "Put Events", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, + } +} + func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.ServicePackageFrameworkDataSource { return []*inttypes.ServicePackageFrameworkDataSource{ { From 3ca19a3283ba83700e2a2271d83e15d20ad74776 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 29 Sep 2025 10:30:30 -0500 Subject: [PATCH 2/6] Add changelog --- .changelog/44487.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/44487.txt diff --git a/.changelog/44487.txt b/.changelog/44487.txt new file mode 100644 index 000000000000..98eb0eca07a4 --- /dev/null +++ b/.changelog/44487.txt @@ -0,0 +1,3 @@ +```release-note:new-action +aws_events_put_events +``` \ No newline at end of file From b918ee62e742ab3a81b4717ad90327fcfb8fb4a8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 29 Sep 2025 10:30:44 -0500 Subject: [PATCH 3/6] Add user docs --- .../actions/events_put_events.html.markdown | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 website/docs/actions/events_put_events.html.markdown diff --git a/website/docs/actions/events_put_events.html.markdown b/website/docs/actions/events_put_events.html.markdown new file mode 100644 index 000000000000..9a111e3ae24f --- /dev/null +++ b/website/docs/actions/events_put_events.html.markdown @@ -0,0 +1,146 @@ +--- +subcategory: "EventBridge" +layout: "aws" +page_title: "AWS: aws_events_put_events" +description: |- + Sends custom events to Amazon EventBridge so that they can be matched to rules. +--- + +# Action: aws_events_put_events + +~> **Note:** `aws_events_put_events` is in beta. Its interface and behavior may change as the feature evolves, and breaking changes are possible. It is offered as a technical preview without compatibility guarantees until Terraform 1.14 is generally available. + +Sends custom events to Amazon EventBridge so that they can be matched to rules. This action provides an imperative way to emit events from Terraform plans (e.g., deployment notifications) while still allowing Terraform to manage when the emission occurs through `action_trigger` lifecycle events. + +## Example Usage + +### Basic Event + +```terraform +action "aws_events_put_events" "example" { + config { + entry { + source = "mycompany.myapp" + detail_type = "User Action" + detail = jsonencode({ + user_id = "12345" + action = "login" + }) + } + } +} +``` + +### Multiple Events + +```terraform +action "aws_events_put_events" "batch" { + config { + entry { + source = "mycompany.orders" + detail_type = "Order Created" + detail = jsonencode({ + order_id = "order-123" + amount = 99.99 + }) + } + + entry { + source = "mycompany.orders" + detail_type = "Order Updated" + detail = jsonencode({ + order_id = "order-456" + status = "shipped" + }) + } + } +} +``` + +### Custom Event Bus + +```terraform +resource "aws_cloudwatch_event_bus" "example" { + name = "custom-bus" +} + +action "aws_events_put_events" "custom_bus" { + config { + entry { + source = "mycompany.analytics" + detail_type = "Page View" + event_bus_name = aws_cloudwatch_event_bus.example.name + detail = jsonencode({ + page = "/home" + user = "anonymous" + }) + } + } +} +``` + +### Event with Resources and Timestamp + +```terraform +action "aws_events_put_events" "detailed" { + config { + entry { + source = "aws.ec2" + detail_type = "EC2 Instance State-change Notification" + time = "2023-01-01T12:00:00Z" # RFC3339 + resources = ["arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0"] + detail = jsonencode({ + instance_id = "i-1234567890abcdef0" + state = "running" + }) + } + } +} +``` + +### Triggered by Terraform Data + +```terraform +resource "terraform_data" "deploy" { + input = var.deployment_id + + lifecycle { + action_trigger { + events = [before_create, before_update] + actions = [action.aws_events_put_events.deployment] + } + } +} + +action "aws_events_put_events" "deployment" { + config { + entry { + source = "mycompany.deployments" + detail_type = "Deployment Complete" + detail = jsonencode({ + deployment_id = var.deployment_id + environment = var.environment + timestamp = timestamp() + }) + } + } +} +``` + +## Argument Reference + +This action supports the following arguments: + +* `entry` - (Required) One or more `entry` blocks defining events to send. Multiple blocks may be specified. See [below](#entry-block). +* `region` - (Optional) AWS region override. Defaults to the provider region if omitted. + +### `entry` Block + +Each `entry` block supports: + +* `source` - (Required) The source identifier for the event (e.g., `mycompany.myapp`). +* `detail_type` - (Optional) Free-form string used to decide what fields to expect in the event detail. +* `detail` - (Optional) JSON string (use `jsonencode()`) representing the event detail payload. +* `event_bus_name` - (Optional) Name or ARN of the event bus. Defaults to the account's default bus. +* `resources` - (Optional) List of ARNs the event primarily concerns. +* `time` - (Optional) RFC3339 timestamp for the event. If omitted, the receive time is used. From b9b4893c21e2fce4efc48d3fe5c9229680321211 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 29 Sep 2025 10:31:01 -0500 Subject: [PATCH 4/6] Add new action --- internal/service/events/put_events_action.go | 140 +++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 internal/service/events/put_events_action.go diff --git a/internal/service/events/put_events_action.go b/internal/service/events/put_events_action.go new file mode 100644 index 000000000000..aefc90cfc5dc --- /dev/null +++ b/internal/service/events/put_events_action.go @@ -0,0 +1,140 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package events + +import ( + "context" + "strconv" + + "github.com/aws/aws-sdk-go-v2/service/eventbridge" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/action" + "github.com/hashicorp/terraform-plugin-framework/action/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @Action(aws_events_put_events, name="Put Events") +// nosemgrep: ci.events-in-func-name -- "PutEvents" matches AWS API operation name (PutEvents). Required for consistent generated/action naming; safe to ignore. +func newPutEventsAction(_ context.Context) (action.ActionWithConfigure, error) { + return &putEventsAction{}, nil +} + +var ( + _ action.Action = (*putEventsAction)(nil) +) + +type putEventsAction struct { + framework.ActionWithModel[putEventsActionModel] +} + +type putEventsActionModel struct { + framework.WithRegionModel + Entry fwtypes.ListNestedObjectValueOf[putEventEntryModel] `tfsdk:"entry"` +} + +type putEventEntryModel struct { + Detail types.String `tfsdk:"detail"` + DetailType types.String `tfsdk:"detail_type"` + EventBusName types.String `tfsdk:"event_bus_name"` + Resources fwtypes.ListValueOf[types.String] `tfsdk:"resources"` + Source types.String `tfsdk:"source"` + Time timetypes.RFC3339 `tfsdk:"time"` +} + +func (a *putEventsAction) Schema(ctx context.Context, req action.SchemaRequest, resp *action.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Sends custom events to Amazon EventBridge so that they can be matched to rules.", + Blocks: map[string]schema.Block{ + "entry": schema.ListNestedBlock{ + Description: "The entry that defines an event in your system.", + CustomType: fwtypes.NewListNestedObjectTypeOf[putEventEntryModel](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "detail": schema.StringAttribute{ + Description: "A valid JSON string. There is no other schema imposed.", + Optional: true, + }, + "detail_type": schema.StringAttribute{ + Description: "Free-form string used to decide what fields to expect in the event detail.", + Optional: true, + }, + "event_bus_name": schema.StringAttribute{ + Description: "The name or ARN of the event bus to receive the event.", + Optional: true, + }, + names.AttrResources: schema.ListAttribute{ + Description: "AWS resources, identified by Amazon Resource Name (ARN), which the event primarily concerns.", + CustomType: fwtypes.ListOfStringType, + Optional: true, + }, + names.AttrSource: schema.StringAttribute{ + Description: "The source of the event.", + Required: true, + }, + "time": schema.StringAttribute{ + Description: "The time stamp of the event, per RFC3339.", + Optional: true, + CustomType: timetypes.RFC3339Type{}, + }, + }, + }, + }, + }, + } +} + +func (a *putEventsAction) Invoke(ctx context.Context, req action.InvokeRequest, resp *action.InvokeResponse) { + var model putEventsActionModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &model)...) + if resp.Diagnostics.HasError() { + return + } + + conn := a.Meta().EventsClient(ctx) + + tflog.Info(ctx, "Putting events", map[string]any{ + "entry_count": len(model.Entry.Elements()), + }) + + resp.SendProgress(action.InvokeProgressEvent{ + Message: "Putting events to EventBridge...", + }) + + var input eventbridge.PutEventsInput + resp.Diagnostics.Append(fwflex.Expand(ctx, model, &input)...) + if resp.Diagnostics.HasError() { + return + } + + output, err := conn.PutEvents(ctx, &input) + if err != nil { + resp.Diagnostics.AddError( + "Putting Events", + "Could not put events: "+err.Error(), + ) + return + } + + if output.FailedEntryCount > 0 { + resp.Diagnostics.AddError( + "Putting Events", + strconv.Itoa(int(output.FailedEntryCount))+" entries failed to be processed", + ) + return + } + + resp.SendProgress(action.InvokeProgressEvent{ + Message: "Events put successfully", + }) + + tflog.Info(ctx, "Put events completed", map[string]any{ + "successful_entries": len(output.Entries), + }) +} From d91b54e961f4d205bf8e907917ec0c17b4a1be44 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 29 Sep 2025 10:31:10 -0500 Subject: [PATCH 5/6] Add tests --- .../service/events/put_events_action_test.go | 384 ++++++++++++++++++ 1 file changed, 384 insertions(+) create mode 100644 internal/service/events/put_events_action_test.go diff --git a/internal/service/events/put_events_action_test.go b/internal/service/events/put_events_action_test.go new file mode 100644 index 000000000000..072c0ac9a917 --- /dev/null +++ b/internal/service/events/put_events_action_test.go @@ -0,0 +1,384 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package events_test + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/eventbridge" + "github.com/aws/aws-sdk-go-v2/service/sqs" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccEventsPutEventsAction_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EventsServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_14_0), + }, + CheckDestroy: testAccCheckBusDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccPutEventsActionConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckPutEventsDelivered(ctx, rName, 1), + ), + }, + }, + }) +} + +func TestAccEventsPutEventsAction_multipleEntries(t *testing.T) { + ctx := acctest.Context(t) + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EventsServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_14_0), + }, + CheckDestroy: testAccCheckBusDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccPutEventsActionConfig_multipleEntries(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckPutEventsDelivered(ctx, rName, 2), + ), + }, + }, + }) +} + +func TestAccEventsPutEventsAction_customBus(t *testing.T) { + ctx := acctest.Context(t) + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EventsServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_14_0), + }, + CheckDestroy: testAccCheckBusDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccPutEventsActionConfig_customBus(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckPutEventsDelivered(ctx, rName, 1), + ), + }, + }, + }) +} + +// nosemgrep: ci.events-in-func-name -- Verification helper for PutEvents delivery +func testAccCheckPutEventsDelivered(ctx context.Context, rName string, expected int) resource.TestCheckFunc { + return func(s *terraform.State) error { + meta := acctest.Provider.Meta().(*conns.AWSClient) + evConn := meta.EventsClient(ctx) + sqsConn := meta.SQSClient(ctx) + + // Ensure bus exists (sanity) + if _, err := evConn.DescribeEventBus(ctx, &eventbridge.DescribeEventBusInput{Name: &rName}); err != nil { + return fmt.Errorf("event bus %s not found: %w", rName, err) + } + + // Discover queue URL via name convention + queueName := rName + "-events-test" + getOut, err := sqsConn.GetQueueUrl(ctx, &sqs.GetQueueUrlInput{QueueName: &queueName}) + if err != nil { + return fmt.Errorf("getting queue url: %w", err) + } + + deadline := time.Now().Add(2 * time.Minute) + received := 0 + marker := rName + for time.Now().Before(deadline) && received < expected { + // Long poll + msgOut, err := sqsConn.ReceiveMessage(ctx, &sqs.ReceiveMessageInput{ + QueueUrl: getOut.QueueUrl, + MaxNumberOfMessages: 10, + WaitTimeSeconds: 10, + }) + if err != nil { + // transient network errors: retry + continue + } + for _, m := range msgOut.Messages { + if m.Body == nil { + continue + } + // EventBridge SQS target wraps the event as JSON; look for marker inside detail + if strings.Contains(*m.Body, marker) { + // Optionally parse to verify structure + var parsed map[string]any + _ = json.Unmarshal([]byte(*m.Body), &parsed) + received++ + } + } + } + + if received < expected { + return fmt.Errorf("expected %d events delivered to SQS, received %d", expected, received) + } + return nil + } +} + +// nosemgrep: ci.events-in-func-name -- Function reflects PutEvents operation naming for consistency. +func testAccPutEventsActionConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q +} + +resource "aws_cloudwatch_event_rule" "test" { + name = %[1]q + event_bus_name = aws_cloudwatch_event_bus.test.name + event_pattern = jsonencode({ + source = ["test.application"] + }) +} + +resource "aws_sqs_queue" "events_target" { + name = "%[1]s-events-test" +} + +resource "aws_sqs_queue_policy" "events_target" { + queue_url = aws_sqs_queue.events_target.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowEventBridgeSendMessage" + Effect = "Allow" + Principal = { Service = "events.amazonaws.com" } + Action = "sqs:SendMessage" + Resource = aws_sqs_queue.events_target.arn + Condition = { + ArnEquals = { "aws:SourceArn" = aws_cloudwatch_event_rule.test.arn } + } + } + ] + }) +} + +resource "aws_cloudwatch_event_target" "test" { + rule = aws_cloudwatch_event_rule.test.name + event_bus_name = aws_cloudwatch_event_bus.test.name + target_id = "sqs" + arn = aws_sqs_queue.events_target.arn +} + +action "aws_events_put_events" "test" { + config { + entry { + source = "test.application" + detail_type = "Test Event" + event_bus_name = aws_cloudwatch_event_bus.test.name + detail = jsonencode({ + marker = %[1]q + action = "test" + }) + } + } +} + +resource "terraform_data" "trigger" { + input = "trigger" + lifecycle { + action_trigger { + events = [after_create, before_update] + actions = [action.aws_events_put_events.test] + } + } + depends_on = [ + aws_cloudwatch_event_target.test, + aws_sqs_queue_policy.events_target + ] +} +`, rName) +} + +// nosemgrep: ci.events-in-func-name -- Function reflects PutEvents operation naming for consistency. +func testAccPutEventsActionConfig_multipleEntries(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q +} + +resource "aws_cloudwatch_event_rule" "test" { + name = %[1]q + event_bus_name = aws_cloudwatch_event_bus.test.name + event_pattern = jsonencode({ + source = ["test.application", "test.orders"] + }) +} + +resource "aws_sqs_queue" "events_target" { + name = "%[1]s-events-test" +} + +resource "aws_sqs_queue_policy" "events_target" { + queue_url = aws_sqs_queue.events_target.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowEventBridgeSendMessage" + Effect = "Allow" + Principal = { Service = "events.amazonaws.com" } + Action = "sqs:SendMessage" + Resource = aws_sqs_queue.events_target.arn + Condition = { + ArnEquals = { "aws:SourceArn" = aws_cloudwatch_event_rule.test.arn } + } + } + ] + }) +} + +resource "aws_cloudwatch_event_target" "test" { + rule = aws_cloudwatch_event_rule.test.name + event_bus_name = aws_cloudwatch_event_bus.test.name + target_id = "sqs" + arn = aws_sqs_queue.events_target.arn +} + +action "aws_events_put_events" "test" { + config { + entry { + source = "test.application" + detail_type = "User Action" + event_bus_name = aws_cloudwatch_event_bus.test.name + detail = jsonencode({ + marker = %[1]q + action = "login" + }) + } + + entry { + source = "test.orders" + detail_type = "Order Created" + event_bus_name = aws_cloudwatch_event_bus.test.name + detail = jsonencode({ + marker = %[1]q + amount = 99.99 + }) + } + } +} + +resource "terraform_data" "trigger" { + input = "trigger" + lifecycle { + action_trigger { + events = [after_create, before_update] + actions = [action.aws_events_put_events.test] + } + } + depends_on = [ + aws_cloudwatch_event_target.test, + aws_sqs_queue_policy.events_target + ] +} +`, rName) +} + +// nosemgrep: ci.events-in-func-name -- Function reflects PutEvents operation naming for consistency. +func testAccPutEventsActionConfig_customBus(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_event_bus" "test" { + name = %[1]q +} + +resource "aws_cloudwatch_event_rule" "test" { + name = %[1]q + event_bus_name = aws_cloudwatch_event_bus.test.name + event_pattern = jsonencode({ + source = ["custom.source"] + detail-type = ["Custom Event"] + }) +} + +resource "aws_sqs_queue" "events_target" { + name = "%[1]s-events-test" +} + +resource "aws_sqs_queue_policy" "events_target" { + queue_url = aws_sqs_queue.events_target.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowEventBridgeSendMessage" + Effect = "Allow" + Principal = { Service = "events.amazonaws.com" } + Action = "sqs:SendMessage" + Resource = aws_sqs_queue.events_target.arn + Condition = { + ArnEquals = { "aws:SourceArn" = aws_cloudwatch_event_rule.test.arn } + } + } + ] + }) +} + +resource "aws_cloudwatch_event_target" "test" { + rule = aws_cloudwatch_event_rule.test.name + event_bus_name = aws_cloudwatch_event_bus.test.name + target_id = "sqs" + arn = aws_sqs_queue.events_target.arn +} + +action "aws_events_put_events" "test" { + config { + entry { + source = "custom.source" + detail_type = "Custom Event" + event_bus_name = aws_cloudwatch_event_bus.test.name + time = "2023-01-01T12:00:00Z" + resources = ["arn:aws:s3:::example-bucket"] + detail = jsonencode({ + custom_field = "custom_value" + marker = %[1]q + timestamp = "2023-01-01T12:00:00Z" + }) + } + } +} + +resource "terraform_data" "trigger" { + input = "trigger" + lifecycle { + action_trigger { + events = [after_create, before_update] + actions = [action.aws_events_put_events.test] + } + } + depends_on = [ + aws_cloudwatch_event_target.test, + aws_sqs_queue_policy.events_target + ] +} +`, rName) +} From 2c35b495d48d2036d6c5169e098ba9a7cccbba13 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 29 Sep 2025 16:56:55 -0400 Subject: [PATCH 6/6] Fix hardocded partitions --- internal/service/events/put_events_action_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/service/events/put_events_action_test.go b/internal/service/events/put_events_action_test.go index 072c0ac9a917..3c51187378d2 100644 --- a/internal/service/events/put_events_action_test.go +++ b/internal/service/events/put_events_action_test.go @@ -307,6 +307,8 @@ resource "terraform_data" "trigger" { // nosemgrep: ci.events-in-func-name -- Function reflects PutEvents operation naming for consistency. func testAccPutEventsActionConfig_customBus(rName string) string { return fmt.Sprintf(` +data "aws_partition" "current" {} + resource "aws_cloudwatch_event_bus" "test" { name = %[1]q } @@ -357,7 +359,7 @@ action "aws_events_put_events" "test" { detail_type = "Custom Event" event_bus_name = aws_cloudwatch_event_bus.test.name time = "2023-01-01T12:00:00Z" - resources = ["arn:aws:s3:::example-bucket"] + resources = ["arn:${data.aws_partition.current.partition}:s3:::example-bucket"] detail = jsonencode({ custom_field = "custom_value" marker = %[1]q