diff --git a/datadog/data_source_datadog_cloud_workload_security_agent_rules.go b/datadog/data_source_datadog_cloud_workload_security_agent_rules.go
deleted file mode 100644
index 45f942b0f3..0000000000
--- a/datadog/data_source_datadog_cloud_workload_security_agent_rules.go
+++ /dev/null
@@ -1,100 +0,0 @@
-package datadog
-
-import (
- "context"
- "fmt"
-
- "github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func dataSourceDatadogCloudWorkloadSecurityAgentRules() *schema.Resource {
- return &schema.Resource{
- Description: "Use this data source to retrieve information about existing Cloud Workload Security Agent Rules for use in other resources. Deprecated, use datadog_csm_threats_agent_rules data source instead: https://registry.terraform.io/providers/DataDog/datadog/latest/docs/data-sources/csm_threats_agent_rules",
- DeprecationMessage: "This data source is deprecated — use the datadog_csm_threats_agent_rules data source instead: https://registry.terraform.io/providers/DataDog/datadog/latest/docs/data-sources/csm_threats_agent_rules",
- ReadContext: dataSourceDatadogCloudWorkloadSecurityAgentRulesRead,
-
- SchemaFunc: func() map[string]*schema.Schema {
- return map[string]*schema.Schema{
- // Computed
- "agent_rules": {
- Description: "List of Agent rules.",
- Type: schema.TypeList,
- Computed: true,
- Elem: &schema.Resource{
- Schema: map[string]*schema.Schema{
- "id": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The id of the Agent rule.",
- },
- "description": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The description of the Agent rule.",
- },
- "enabled": {
- Type: schema.TypeBool,
- Computed: true,
- Description: "Whether the Agent rule is enabled.",
- },
- "expression": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The SECL expression of the Agent rule.",
- },
- "name": {
- Type: schema.TypeString,
- Computed: true,
- Description: "The name of the Agent rule.",
- },
- },
- },
- },
- }
- },
- }
-}
-
-func dataSourceDatadogCloudWorkloadSecurityAgentRulesRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
- providerConf := meta.(*ProviderConfiguration)
- apiInstances := providerConf.DatadogApiInstances
- auth := providerConf.Auth
-
- agentRules := make([]map[string]interface{}, 0)
- response, httpresp, err := apiInstances.GetCSMThreatsApiV2().ListCloudWorkloadSecurityAgentRules(auth)
- if err != nil {
- return utils.TranslateClientErrorDiag(err, httpresp, "error listing agent rules")
- }
-
- diags := diag.Diagnostics{}
- for _, agentRule := range response.GetData() {
- if err := utils.CheckForUnparsed(agentRule); err != nil {
- diags = append(diags, diag.Diagnostic{
- Severity: diag.Warning,
- Summary: fmt.Sprintf("skipping agent rule with id: %s", agentRule.GetId()),
- Detail: fmt.Sprintf("rule contains unparsed object: %v", err),
- })
- continue
- }
-
- // extract agent rule
- agentRuleTF := make(map[string]interface{})
- attributes := agentRule.GetAttributes()
-
- agentRuleTF["id"] = agentRule.GetId()
- agentRuleTF["name"] = attributes.GetName()
- agentRuleTF["description"] = attributes.GetDescription()
- agentRuleTF["expression"] = attributes.GetExpression()
- agentRuleTF["enabled"] = attributes.GetEnabled()
-
- agentRules = append(agentRules, agentRuleTF)
- }
-
- d.SetId("cloud-workload-security-agent-rules")
- d.Set("agent_rules", agentRules)
-
- return diags
-}
diff --git a/datadog/fwprovider/data_source_datadog_csm_threats_multi_policy_agent_rules.go b/datadog/fwprovider/data_source_datadog_csm_threats_multi_policy_agent_rules.go
new file mode 100644
index 0000000000..1f8d11b101
--- /dev/null
+++ b/datadog/fwprovider/data_source_datadog_csm_threats_multi_policy_agent_rules.go
@@ -0,0 +1,178 @@
+package fwprovider
+
+import (
+ "context"
+ "crypto/sha256"
+ "fmt"
+ "strings"
+
+ "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+
+ "github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+var (
+ _ datasource.DataSourceWithConfigure = &csmThreatsMultiPolicyAgentRulesDataSource{}
+)
+
+type csmThreatsMultiPolicyAgentRulesDataSource struct {
+ api *datadogV2.CSMThreatsApi
+ auth context.Context
+}
+
+type csmThreatsMultiPolicyAgentRulesDataSourceModel struct {
+ PolicyId types.String `tfsdk:"policy_id"`
+ Id types.String `tfsdk:"id"`
+ AgentRulesIds types.List `tfsdk:"agent_rules_ids"`
+ AgentRules []csmThreatsMultiPolicyAgentRuleDataSourceModel `tfsdk:"agent_rules"`
+}
+
+type csmThreatsMultiPolicyAgentRuleDataSourceModel struct {
+ Id types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ Enabled types.Bool `tfsdk:"enabled"`
+ Expression types.String `tfsdk:"expression"`
+ ProductTags types.Set `tfsdk:"product_tags"`
+}
+
+func NewCSMThreatsMultiPolicyAgentRulesDataSource() datasource.DataSource {
+ return &csmThreatsMultiPolicyAgentRulesDataSource{}
+}
+
+func (r *csmThreatsMultiPolicyAgentRulesDataSource) Configure(_ context.Context, request datasource.ConfigureRequest, response *datasource.ConfigureResponse) {
+ if request.ProviderData == nil {
+ return
+ }
+
+ providerData, ok := request.ProviderData.(*FrameworkProvider)
+ if !ok {
+ response.Diagnostics.AddError(
+ "Unexpected Resource Configure Type",
+ fmt.Sprintf("Expected *FrameworkProvider, got: %T. Please report this issue to the provider developers.", request.ProviderData),
+ )
+ return
+ }
+
+ r.api = providerData.DatadogApiInstances.GetCSMThreatsApiV2()
+ r.auth = providerData.Auth
+}
+
+func (r *csmThreatsMultiPolicyAgentRulesDataSource) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) {
+ response.TypeName = "csm_threats_multi_policy_agent_rules"
+}
+
+func (r *csmThreatsMultiPolicyAgentRulesDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) {
+ var state csmThreatsMultiPolicyAgentRulesDataSourceModel
+ response.Diagnostics.Append(request.Config.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ params := datadogV2.NewListCSMThreatsAgentRulesOptionalParameters()
+ if !state.PolicyId.IsNull() && !state.PolicyId.IsUnknown() {
+ policyId := state.PolicyId.ValueString()
+ params.WithPolicyId(policyId)
+ }
+
+ res, _, err := r.api.ListCSMThreatsAgentRules(r.auth, *params)
+ if err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error while fetching agent rules"))
+ return
+ }
+
+ data := res.GetData()
+ agentRuleIds := make([]string, len(data))
+ agentRules := make([]csmThreatsMultiPolicyAgentRuleDataSourceModel, len(data))
+
+ for idx, agentRule := range res.GetData() {
+ var agentRuleModel csmThreatsMultiPolicyAgentRuleDataSourceModel
+ agentRuleModel.Id = types.StringValue(agentRule.GetId())
+ attributes := agentRule.Attributes
+ agentRuleModel.Name = types.StringValue(attributes.GetName())
+ agentRuleModel.Description = types.StringValue(attributes.GetDescription())
+ agentRuleModel.Enabled = types.BoolValue(attributes.GetEnabled())
+ agentRuleModel.Expression = types.StringValue(*attributes.Expression)
+ tags := attributes.GetProductTags()
+ tagSet := make(map[string]struct{})
+ for _, tag := range tags {
+ tagSet[tag] = struct{}{}
+ }
+ uniqueTags := make([]string, 0, len(tagSet))
+ for tag := range tagSet {
+ uniqueTags = append(uniqueTags, tag)
+ }
+
+ productTags, diags := types.SetValueFrom(ctx, types.StringType, uniqueTags)
+ if diags.HasError() {
+ response.Diagnostics.Append(diags...)
+ continue
+ }
+ agentRuleModel.ProductTags = productTags
+ agentRuleIds[idx] = agentRule.GetId()
+ agentRules[idx] = agentRuleModel
+ }
+
+ stateId := strings.Join(agentRuleIds, "--")
+ state.Id = types.StringValue(computeDataSourceID(&stateId))
+ tfAgentRuleIds, diags := types.ListValueFrom(ctx, types.StringType, agentRuleIds)
+ response.Diagnostics.Append(diags...)
+ state.AgentRulesIds = tfAgentRuleIds
+ state.AgentRules = agentRules
+
+ response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (*csmThreatsMultiPolicyAgentRulesDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, response *datasource.SchemaResponse) {
+ response.Schema = schema.Schema{
+ Description: "Use this data source to retrieve information about existing Agent rules.",
+ Attributes: map[string]schema.Attribute{
+ // Input
+ "policy_id": schema.StringAttribute{
+ Description: "Listing only the rules in the policy with this field as the ID",
+ Optional: true,
+ },
+ // Output
+ "id": schema.StringAttribute{
+ Description: "The ID of the data source",
+ Computed: true,
+ },
+ "agent_rules_ids": schema.ListAttribute{
+ Computed: true,
+ Description: "List of IDs for the Agent rules.",
+ ElementType: types.StringType,
+ },
+ "agent_rules": schema.ListAttribute{
+ Computed: true,
+ Description: "List of Agent rules",
+ ElementType: types.ObjectType{
+ AttrTypes: map[string]attr.Type{
+ "id": types.StringType,
+ "name": types.StringType,
+ "description": types.StringType,
+ "enabled": types.BoolType,
+ "expression": types.StringType,
+ "product_tags": types.SetType{ElemType: types.StringType},
+ },
+ },
+ },
+ },
+ }
+}
+
+func computeDataSourceID(ids *string) string {
+ // Key for hashing
+ var b strings.Builder
+ if ids != nil {
+ b.WriteString(*ids)
+ }
+ keyStr := b.String()
+ h := sha256.New()
+ h.Write([]byte(keyStr))
+
+ return fmt.Sprintf("%x", h.Sum(nil))
+}
diff --git a/datadog/fwprovider/data_source_datadog_csm_threats_policy.go b/datadog/fwprovider/data_source_datadog_csm_threats_policy.go
new file mode 100644
index 0000000000..c8a3455b06
--- /dev/null
+++ b/datadog/fwprovider/data_source_datadog_csm_threats_policy.go
@@ -0,0 +1,109 @@
+package fwprovider
+
+import (
+ "context"
+ "strings"
+
+ "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+
+ "github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+var (
+ _ datasource.DataSourceWithConfigure = &csmThreatsPoliciesDataSource{}
+)
+
+type csmThreatsPoliciesDataSource struct {
+ api *datadogV2.CSMThreatsApi
+ auth context.Context
+}
+
+type csmThreatsPoliciesDataSourceModel struct {
+ Id types.String `tfsdk:"id"`
+ PolicyIds types.List `tfsdk:"policy_ids"`
+ Policies []csmThreatsPolicyModel `tfsdk:"policies"`
+}
+
+func NewCSMThreatsPoliciesDataSource() datasource.DataSource {
+ return &csmThreatsPoliciesDataSource{}
+}
+
+func (r *csmThreatsPoliciesDataSource) Configure(_ context.Context, request datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
+ providerData := request.ProviderData.(*FrameworkProvider)
+ r.api = providerData.DatadogApiInstances.GetCSMThreatsApiV2()
+ r.auth = providerData.Auth
+}
+
+func (*csmThreatsPoliciesDataSource) Metadata(_ context.Context, _ datasource.MetadataRequest, response *datasource.MetadataResponse) {
+ response.TypeName = "csm_threats_policies"
+}
+
+func (r *csmThreatsPoliciesDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) {
+ var state csmThreatsPoliciesDataSourceModel
+ response.Diagnostics.Append(request.Config.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ res, _, err := r.api.ListCSMThreatsAgentPolicies(r.auth)
+ if err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error while fetching agent rules"))
+ return
+ }
+
+ data := res.GetData()
+ policyIds := make([]string, len(data))
+ policies := make([]csmThreatsPolicyModel, len(data))
+
+ for idx, policy := range res.GetData() {
+ var policyModel csmThreatsPolicyModel
+ policyModel.Id = types.StringValue(policy.GetId())
+ attributes := policy.Attributes
+ policyModel.Name = types.StringValue(attributes.GetName())
+ policyModel.Description = types.StringValue(attributes.GetDescription())
+ policyModel.Enabled = types.BoolValue(attributes.GetEnabled())
+ policyModel.Tags, _ = types.SetValueFrom(ctx, types.StringType, attributes.GetHostTags())
+ policyIds[idx] = policy.GetId()
+ policies[idx] = policyModel
+ }
+
+ stateId := strings.Join(policyIds, "--")
+ state.Id = types.StringValue(computeDataSourceID(&stateId))
+ tfAgentRuleIds, diags := types.ListValueFrom(ctx, types.StringType, policyIds)
+ response.Diagnostics.Append(diags...)
+ state.PolicyIds = tfAgentRuleIds
+ state.Policies = policies
+
+ response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (*csmThreatsPoliciesDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, response *datasource.SchemaResponse) {
+ response.Schema = schema.Schema{
+ Description: "Use this data source to retrieve information about existing policies.",
+ Attributes: map[string]schema.Attribute{
+ "id": utils.ResourceIDAttribute(),
+ "policy_ids": schema.ListAttribute{
+ Computed: true,
+ Description: "List of IDs for the policies.",
+ ElementType: types.StringType,
+ },
+ "policies": schema.ListAttribute{
+ Computed: true,
+ Description: "List of policies",
+ ElementType: types.ObjectType{
+ AttrTypes: map[string]attr.Type{
+ "id": types.StringType,
+ "tags": types.SetType{ElemType: types.StringType},
+ "name": types.StringType,
+ "description": types.StringType,
+ "enabled": types.BoolType,
+ },
+ },
+ },
+ },
+ }
+}
diff --git a/datadog/fwprovider/framework_provider.go b/datadog/fwprovider/framework_provider.go
index 15da535fb1..9fd49eaf68 100644
--- a/datadog/fwprovider/framework_provider.go
+++ b/datadog/fwprovider/framework_provider.go
@@ -68,7 +68,6 @@ var Resources = []func() resource.Resource{
NewTeamResource,
NewUserRoleResource,
NewSecurityMonitoringSuppressionResource,
- NewCSMThreatsAgentRuleResource,
NewServiceAccountResource,
NewWebhookResource,
NewWebhookCustomVariableResource,
@@ -80,6 +79,9 @@ var Resources = []func() resource.Resource{
NewActionConnectionResource,
NewWorkflowAutomationResource,
NewAppBuilderAppResource,
+ NewCSMThreatsAgentRuleResource,
+ NewCSMThreatsPolicyResource,
+ NewCSMThreatsMultiPolicyAgentRuleResource,
}
var Datasources = []func() datasource.DataSource{
@@ -101,13 +103,15 @@ var Datasources = []func() datasource.DataSource{
NewDatadogUsersDataSource,
NewDatadogRoleUsersDataSource,
NewSecurityMonitoringSuppressionDataSource,
- NewCSMThreatsAgentRulesDataSource,
+ NewCSMThreatsMultiPolicyAgentRulesDataSource,
NewLogsPipelinesOrderDataSource,
NewDatadogTeamsDataSource,
NewDatadogActionConnectionDataSource,
NewDatadogSyntheticsGlobalVariableDataSource,
NewWorkflowAutomationDataSource,
NewDatadogAppBuilderAppDataSource,
+ NewCSMThreatsAgentRulesDataSource,
+ NewCSMThreatsPoliciesDataSource,
}
// FrameworkProvider struct
diff --git a/datadog/fwprovider/resource_datadog_csm_threats_agent_rule.go b/datadog/fwprovider/resource_datadog_csm_threats_agent_rule.go
index f04ada2d7f..73274922a0 100644
--- a/datadog/fwprovider/resource_datadog_csm_threats_agent_rule.go
+++ b/datadog/fwprovider/resource_datadog_csm_threats_agent_rule.go
@@ -2,7 +2,6 @@ package fwprovider
import (
"context"
- "sync"
"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
"github.com/hashicorp/terraform-plugin-framework/path"
@@ -17,9 +16,8 @@ import (
)
var (
- csmThreatsMutex sync.Mutex
- _ resource.ResourceWithConfigure = &csmThreatsAgentRuleResource{}
- _ resource.ResourceWithImportState = &csmThreatsAgentRuleResource{}
+ _ resource.ResourceWithConfigure = &csmThreatsAgentRuleResource{}
+ _ resource.ResourceWithImportState = &csmThreatsAgentRuleResource{}
)
type csmThreatsAgentRuleModel struct {
diff --git a/datadog/fwprovider/resource_datadog_csm_threats_multi_policy_agent_rule.go b/datadog/fwprovider/resource_datadog_csm_threats_multi_policy_agent_rule.go
new file mode 100644
index 0000000000..4e724823d9
--- /dev/null
+++ b/datadog/fwprovider/resource_datadog_csm_threats_multi_policy_agent_rule.go
@@ -0,0 +1,272 @@
+package fwprovider
+
+import (
+ "context"
+ "strings"
+ "sync"
+
+ "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+
+ "github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+var (
+ csmThreatsMutex sync.Mutex
+ _ resource.ResourceWithConfigure = &csmThreatsMultiPolicyAgentRuleResource{}
+ _ resource.ResourceWithImportState = &csmThreatsMultiPolicyAgentRuleResource{}
+)
+
+type csmThreatsMultiPolicyAgentRuleResource struct {
+ api *datadogV2.CSMThreatsApi
+ auth context.Context
+}
+
+type csmThreatsMultiPolicyAgentRuleModel struct {
+ Id types.String `tfsdk:"id"`
+ PolicyId types.String `tfsdk:"policy_id"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ Enabled types.Bool `tfsdk:"enabled"`
+ Expression types.String `tfsdk:"expression"`
+ ProductTags types.Set `tfsdk:"product_tags"`
+}
+
+func NewCSMThreatsMultiPolicyAgentRuleResource() resource.Resource {
+ return &csmThreatsMultiPolicyAgentRuleResource{}
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+ response.TypeName = "csm_threats_multi_policy_agent_rule"
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+ providerData := request.ProviderData.(*FrameworkProvider)
+ r.api = providerData.DatadogApiInstances.GetCSMThreatsApiV2()
+ r.auth = providerData.Auth
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+ response.Schema = schema.Schema{
+ Description: "Provides a Datadog CSM Threats Agent Rule API resource.",
+ Attributes: map[string]schema.Attribute{
+ "id": utils.ResourceIDAttribute(),
+ "policy_id": schema.StringAttribute{
+ Required: true,
+ Description: "The ID of the agent policy in which the rule is saved",
+ },
+ "name": schema.StringAttribute{
+ Required: true,
+ Description: "The name of the Agent rule.",
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.RequiresReplace(),
+ },
+ },
+ "description": schema.StringAttribute{
+ Optional: true,
+ Description: "A description for the Agent rule.",
+ Computed: true,
+ },
+ "enabled": schema.BoolAttribute{
+ Required: true,
+ Description: "Indicates Whether the Agent rule is enabled.",
+ },
+ "expression": schema.StringAttribute{
+ Required: true,
+ Description: "The SECL expression of the Agent rule",
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.RequiresReplace(),
+ },
+ },
+ "product_tags": schema.SetAttribute{
+ Optional: true,
+ ElementType: types.StringType,
+ Description: "The list of product tags associated with the rule",
+ Computed: true,
+ },
+ },
+ }
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
+ result := strings.SplitN(request.ID, ":", 2)
+ if len(result) != 2 {
+ response.Diagnostics.AddError("error retrieving policy_id or rule_id from given ID", "")
+ return
+ }
+
+ response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root("policy_id"), result[0])...)
+ response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root("id"), result[1])...)
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
+ var state csmThreatsMultiPolicyAgentRuleModel
+ response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ agentRulePayload, err := r.buildCreateCSMThreatsAgentRulePayload(&state)
+ if err != nil {
+ response.Diagnostics.AddError("error while parsing resource", err.Error())
+ }
+
+ res, _, err := r.api.CreateCSMThreatsAgentRule(r.auth, *agentRulePayload)
+ if err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating agent rule"))
+ return
+ }
+ if err := utils.CheckForUnparsed(response); err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "response contains unparsed object"))
+ return
+ }
+
+ r.updateStateFromResponse(ctx, &state, &res)
+ response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
+ var state csmThreatsMultiPolicyAgentRuleModel
+ response.Diagnostics.Append(request.State.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ agentRuleId := state.Id.ValueString()
+ policyId := state.PolicyId.ValueString()
+ res, httpResponse, err := r.api.GetCSMThreatsAgentRule(r.auth, agentRuleId, *datadogV2.NewGetCSMThreatsAgentRuleOptionalParameters().WithPolicyId(policyId))
+ if err != nil {
+ if httpResponse != nil && httpResponse.StatusCode == 404 {
+ response.State.RemoveResource(ctx)
+ return
+ }
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error fetching agent rule"))
+ return
+ }
+ if err := utils.CheckForUnparsed(response); err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "response contains unparsed object"))
+ return
+ }
+
+ r.updateStateFromResponse(ctx, &state, &res)
+ response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
+ var state csmThreatsMultiPolicyAgentRuleModel
+ response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ agentRulePayload, err := r.buildUpdateCSMThreatsAgentRulePayload(&state)
+ if err != nil {
+ response.Diagnostics.AddError("error while parsing resource", err.Error())
+ }
+
+ res, _, err := r.api.UpdateCSMThreatsAgentRule(r.auth, state.Id.ValueString(), *agentRulePayload)
+ if err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating agent rule"))
+ return
+ }
+ if err := utils.CheckForUnparsed(response); err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "response contains unparsed object"))
+ return
+ }
+
+ r.updateStateFromResponse(ctx, &state, &res)
+ response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
+ var state csmThreatsMultiPolicyAgentRuleModel
+ response.Diagnostics.Append(request.State.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ id := state.Id.ValueString()
+ policyId := state.PolicyId.ValueString()
+ httpResp, err := r.api.DeleteCSMThreatsAgentRule(r.auth, id, *datadogV2.NewDeleteCSMThreatsAgentRuleOptionalParameters().WithPolicyId(policyId))
+ if err != nil {
+ if httpResp != nil && httpResp.StatusCode == 404 {
+ return
+ }
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error deleting agent rule"))
+ return
+ }
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) buildCreateCSMThreatsAgentRulePayload(state *csmThreatsMultiPolicyAgentRuleModel) (*datadogV2.CloudWorkloadSecurityAgentRuleCreateRequest, error) {
+ _, policyId, name, description, enabled, expression, productTags := r.extractAgentRuleAttributesFromResource(state)
+
+ attributes := datadogV2.CloudWorkloadSecurityAgentRuleCreateAttributes{}
+ attributes.Expression = expression
+ attributes.Name = name
+ attributes.Description = description
+ attributes.Enabled = &enabled
+ attributes.PolicyId = &policyId
+ attributes.ProductTags = productTags
+
+ data := datadogV2.NewCloudWorkloadSecurityAgentRuleCreateData(attributes, datadogV2.CLOUDWORKLOADSECURITYAGENTRULETYPE_AGENT_RULE)
+ return datadogV2.NewCloudWorkloadSecurityAgentRuleCreateRequest(*data), nil
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) buildUpdateCSMThreatsAgentRulePayload(state *csmThreatsMultiPolicyAgentRuleModel) (*datadogV2.CloudWorkloadSecurityAgentRuleUpdateRequest, error) {
+ agentRuleId, policyId, _, description, enabled, _, productTags := r.extractAgentRuleAttributesFromResource(state)
+
+ attributes := datadogV2.CloudWorkloadSecurityAgentRuleUpdateAttributes{}
+ attributes.Description = description
+ attributes.Enabled = &enabled
+ attributes.PolicyId = &policyId
+ attributes.ProductTags = productTags
+
+ data := datadogV2.NewCloudWorkloadSecurityAgentRuleUpdateData(attributes, datadogV2.CLOUDWORKLOADSECURITYAGENTRULETYPE_AGENT_RULE)
+ data.Id = &agentRuleId
+ return datadogV2.NewCloudWorkloadSecurityAgentRuleUpdateRequest(*data), nil
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) extractAgentRuleAttributesFromResource(state *csmThreatsMultiPolicyAgentRuleModel) (string, string, string, *string, bool, string, []string) {
+ // Mandatory fields
+ id := state.Id.ValueString()
+ policyId := state.PolicyId.ValueString()
+ name := state.Name.ValueString()
+ enabled := state.Enabled.ValueBool()
+ expression := state.Expression.ValueString()
+ description := state.Description.ValueStringPointer()
+ var productTags []string
+ if !state.ProductTags.IsNull() && !state.ProductTags.IsUnknown() {
+ for _, tag := range state.ProductTags.Elements() {
+ tagStr, ok := tag.(types.String)
+ if !ok {
+ return "", "", "", nil, false, "", nil
+ }
+ productTags = append(productTags, tagStr.ValueString())
+ }
+ }
+
+ return id, policyId, name, description, enabled, expression, productTags
+}
+
+func (r *csmThreatsMultiPolicyAgentRuleResource) updateStateFromResponse(ctx context.Context, state *csmThreatsMultiPolicyAgentRuleModel, res *datadogV2.CloudWorkloadSecurityAgentRuleResponse) {
+ state.Id = types.StringValue(res.Data.GetId())
+
+ attributes := res.Data.Attributes
+
+ state.Name = types.StringValue(attributes.GetName())
+ state.Description = types.StringValue(attributes.GetDescription())
+ state.Enabled = types.BoolValue(attributes.GetEnabled())
+ state.Expression = types.StringValue(attributes.GetExpression())
+ tags := attributes.GetProductTags()
+ if len(tags) == 0 && state.ProductTags.IsNull() {
+ state.ProductTags = types.SetNull(types.StringType)
+ } else {
+ state.ProductTags, _ = types.SetValueFrom(ctx, types.StringType, tags)
+ }
+
+}
diff --git a/datadog/fwprovider/resource_datadog_csm_threats_policy.go b/datadog/fwprovider/resource_datadog_csm_threats_policy.go
new file mode 100644
index 0000000000..8ca301d792
--- /dev/null
+++ b/datadog/fwprovider/resource_datadog_csm_threats_policy.go
@@ -0,0 +1,277 @@
+package fwprovider
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+
+ "github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
+)
+
+type csmThreatsPolicyModel struct {
+ Id types.String `tfsdk:"id"`
+ Tags types.Set `tfsdk:"tags"`
+ HostTagsLists types.Set `tfsdk:"host_tags_lists"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ Enabled types.Bool `tfsdk:"enabled"`
+}
+
+type csmThreatsPolicyResource struct {
+ api *datadogV2.CSMThreatsApi
+ auth context.Context
+}
+
+func NewCSMThreatsPolicyResource() resource.Resource {
+ return &csmThreatsPolicyResource{}
+}
+
+func (r *csmThreatsPolicyResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
+ response.TypeName = "csm_threats_policy"
+}
+
+func (r *csmThreatsPolicyResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
+ providerData := request.ProviderData.(*FrameworkProvider)
+ r.api = providerData.DatadogApiInstances.GetCSMThreatsApiV2()
+ r.auth = providerData.Auth
+}
+
+func (r *csmThreatsPolicyResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
+ response.Schema = schema.Schema{
+ Description: "Provides a Datadog CSM Threats policy API resource.",
+ Attributes: map[string]schema.Attribute{
+ "id": utils.ResourceIDAttribute(),
+ "name": schema.StringAttribute{
+ Required: true,
+ Description: "The name of the policy.",
+ },
+ "description": schema.StringAttribute{
+ Optional: true,
+ Description: "A description for the policy.",
+ Computed: true,
+ },
+ "enabled": schema.BoolAttribute{
+ Optional: true,
+ Default: booldefault.StaticBool(false),
+ Description: "Indicates whether the policy is enabled.",
+ Computed: true,
+ },
+ "tags": schema.SetAttribute{
+ Optional: true,
+ Description: "Host tags that define where the policy is deployed. Deprecated, use host_tags_lists instead.",
+ ElementType: types.StringType,
+ Computed: true,
+ },
+ "host_tags_lists": schema.SetAttribute{
+ Optional: true,
+ Description: "Host tags that define where the policy is deployed. Inner values are ANDed, outer arrays are ORed.",
+ ElementType: types.ListType{
+ ElemType: types.StringType,
+ },
+ },
+ },
+ }
+}
+
+func (r *csmThreatsPolicyResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
+ resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response)
+}
+
+func (r *csmThreatsPolicyResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
+ var state csmThreatsPolicyModel
+ response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ csmThreatsMutex.Lock()
+ defer csmThreatsMutex.Unlock()
+
+ policyPayload, err := r.buildCreateCSMThreatsPolicyPayload(&state)
+ if err != nil {
+ response.Diagnostics.AddError("error while parsing resource", err.Error())
+ }
+
+ res, _, err := r.api.CreateCSMThreatsAgentPolicy(r.auth, *policyPayload)
+ if err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating policy"))
+ return
+ }
+ if err := utils.CheckForUnparsed(response); err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "response contains unparsed object"))
+ return
+ }
+
+ r.updateStateFromResponse(ctx, &state, &res)
+ response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *csmThreatsPolicyResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
+ var state csmThreatsPolicyModel
+ response.Diagnostics.Append(request.State.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ policyId := state.Id.ValueString()
+ res, httpResponse, err := r.api.GetCSMThreatsAgentPolicy(r.auth, policyId)
+ if err != nil {
+ if httpResponse != nil && httpResponse.StatusCode == 404 {
+ response.State.RemoveResource(ctx)
+ return
+ }
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error fetching agent policy"))
+ return
+ }
+ if err := utils.CheckForUnparsed(response); err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "response contains unparsed object"))
+ return
+ }
+
+ r.updateStateFromResponse(ctx, &state, &res)
+ response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *csmThreatsPolicyResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
+ var state csmThreatsPolicyModel
+ response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ csmThreatsMutex.Lock()
+ defer csmThreatsMutex.Unlock()
+
+ policyPayload, err := r.buildUpdateCSMThreatsPolicyPayload(&state)
+ if err != nil {
+ response.Diagnostics.AddError("error while parsing resource", err.Error())
+ }
+
+ res, _, err := r.api.UpdateCSMThreatsAgentPolicy(r.auth, state.Id.ValueString(), *policyPayload)
+ if err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating agent rule"))
+ return
+ }
+ if err := utils.CheckForUnparsed(response); err != nil {
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "response contains unparsed object"))
+ return
+ }
+
+ r.updateStateFromResponse(ctx, &state, &res)
+ response.Diagnostics.Append(response.State.Set(ctx, &state)...)
+}
+
+func (r *csmThreatsPolicyResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
+ var state csmThreatsPolicyModel
+ response.Diagnostics.Append(request.State.Get(ctx, &state)...)
+ if response.Diagnostics.HasError() {
+ return
+ }
+
+ csmThreatsMutex.Lock()
+ defer csmThreatsMutex.Unlock()
+
+ id := state.Id.ValueString()
+
+ httpResp, err := r.api.DeleteCSMThreatsAgentPolicy(r.auth, id)
+ if err != nil {
+ if httpResp != nil && httpResp.StatusCode == 404 {
+ return
+ }
+ response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error deleting agent rule"))
+ return
+ }
+}
+
+func (r *csmThreatsPolicyResource) buildCreateCSMThreatsPolicyPayload(state *csmThreatsPolicyModel) (*datadogV2.CloudWorkloadSecurityAgentPolicyCreateRequest, error) {
+ _, name, description, enabled, tags, hostTagsLists, err := r.extractPolicyAttributesFromResource(state)
+ if err != nil {
+ return nil, err
+ }
+
+ attributes := datadogV2.CloudWorkloadSecurityAgentPolicyCreateAttributes{}
+ attributes.Name = name
+ attributes.Description = description
+ attributes.Enabled = enabled
+ attributes.HostTags = tags
+ attributes.HostTagsLists = hostTagsLists
+
+ data := datadogV2.NewCloudWorkloadSecurityAgentPolicyCreateData(attributes, datadogV2.CLOUDWORKLOADSECURITYAGENTPOLICYTYPE_POLICY)
+ return datadogV2.NewCloudWorkloadSecurityAgentPolicyCreateRequest(*data), nil
+}
+
+func (r *csmThreatsPolicyResource) buildUpdateCSMThreatsPolicyPayload(state *csmThreatsPolicyModel) (*datadogV2.CloudWorkloadSecurityAgentPolicyUpdateRequest, error) {
+ policyId, name, description, enabled, tags, hostTagsLists, err := r.extractPolicyAttributesFromResource(state)
+ if err != nil {
+ return nil, err
+ }
+ attributes := datadogV2.CloudWorkloadSecurityAgentPolicyUpdateAttributes{}
+ attributes.Name = &name
+ attributes.Description = description
+ attributes.Enabled = enabled
+ attributes.HostTags = tags
+ attributes.HostTagsLists = hostTagsLists
+
+ data := datadogV2.NewCloudWorkloadSecurityAgentPolicyUpdateData(attributes, datadogV2.CLOUDWORKLOADSECURITYAGENTPOLICYTYPE_POLICY)
+ data.Id = &policyId
+ return datadogV2.NewCloudWorkloadSecurityAgentPolicyUpdateRequest(*data), nil
+}
+
+func (r *csmThreatsPolicyResource) extractPolicyAttributesFromResource(state *csmThreatsPolicyModel) (string, string, *string, *bool, []string, [][]string, error) {
+ // Mandatory fields
+ id := state.Id.ValueString()
+ name := state.Name.ValueString()
+ enabled := state.Enabled.ValueBoolPointer()
+ description := state.Description.ValueStringPointer()
+ var tags []string
+ if !state.Tags.IsNull() && !state.Tags.IsUnknown() {
+ for _, tag := range state.Tags.Elements() {
+ tagStr, ok := tag.(types.String)
+ if !ok {
+ return "", "", nil, nil, nil, nil, fmt.Errorf("expected item to be of type types.String, got %T", tag)
+ }
+ tags = append(tags, tagStr.ValueString())
+ }
+ }
+ var hostTagsLists [][]string
+ if !state.HostTagsLists.IsNull() && !state.HostTagsLists.IsUnknown() {
+ for _, hostTagList := range state.HostTagsLists.Elements() {
+ hostTagListStr, ok := hostTagList.(types.List)
+ if !ok {
+ return "", "", nil, nil, nil, nil, fmt.Errorf("expected item to be of type types.List, got %T", hostTagList)
+ }
+ var tags []string
+ for _, hostTag := range hostTagListStr.Elements() {
+ hostTagStr, ok := hostTag.(types.String)
+ if !ok {
+ return "", "", nil, nil, nil, nil, fmt.Errorf("expected item to be of type types.String, got %T", hostTag)
+ }
+ tags = append(tags, hostTagStr.ValueString())
+ }
+ hostTagsLists = append(hostTagsLists, tags)
+ }
+ }
+ return id, name, description, enabled, tags, hostTagsLists, nil
+}
+
+func (r *csmThreatsPolicyResource) updateStateFromResponse(ctx context.Context, state *csmThreatsPolicyModel, res *datadogV2.CloudWorkloadSecurityAgentPolicyResponse) {
+ state.Id = types.StringValue(res.Data.GetId())
+
+ attributes := res.Data.Attributes
+
+ state.Name = types.StringValue(attributes.GetName())
+ state.Description = types.StringValue(attributes.GetDescription())
+ state.Enabled = types.BoolValue(attributes.GetEnabled())
+ state.Tags, _ = types.SetValueFrom(ctx, types.StringType, attributes.GetHostTags())
+ state.HostTagsLists, _ = types.SetValueFrom(ctx, types.ListType{
+ ElemType: types.ListType{
+ ElemType: types.StringType,
+ },
+ }, attributes.GetHostTagsLists())
+}
diff --git a/datadog/provider.go b/datadog/provider.go
index 37839ef108..e0d30cfa02 100644
--- a/datadog/provider.go
+++ b/datadog/provider.go
@@ -222,7 +222,6 @@ func Provider() *schema.Provider {
// NEW DATA SOURCES ARE NOT ALLOWED TO BE ADDED HERE
// New data sources must be implemented using the `terraform-plugin-framework`, and added to the `datadog/fwprovider` directory.
DataSourcesMap: map[string]*schema.Resource{
- "datadog_cloud_workload_security_agent_rules": dataSourceDatadogCloudWorkloadSecurityAgentRules(),
"datadog_dashboard": dataSourceDatadogDashboard(),
"datadog_integration_aws_logs_services": dataSourceDatadogIntegrationAWSLogsServices(),
"datadog_logs_archives_order": dataSourceDatadogLogsArchivesOrder(),
diff --git a/datadog/tests/data_source_datadog_cloud_workload_security_agent_rules_test.go b/datadog/tests/data_source_datadog_cloud_workload_security_agent_rules_test.go
deleted file mode 100644
index 1e0a6a1fe0..0000000000
--- a/datadog/tests/data_source_datadog_cloud_workload_security_agent_rules_test.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package test
-
-import (
- "context"
- "fmt"
- "strconv"
- "testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/hashicorp/terraform-plugin-testing/helper/resource"
- "github.com/hashicorp/terraform-plugin-testing/terraform"
-
- "github.com/terraform-providers/terraform-provider-datadog/datadog"
-)
-
-const tfAgentRulesSource = "data.datadog_cloud_workload_security_agent_rules.acceptance_test"
-
-func TestAccDatadogCloudWorkloadSecurityAgentRulesDatasource(t *testing.T) {
- t.Parallel()
- _, accProviders := testAccProviders(context.Background(), t)
- accProvider := testAccProvider(t, accProviders)
-
- resource.Test(t, resource.TestCase{
- PreCheck: func() { testAccPreCheck(t) },
- ProviderFactories: accProviders,
- Steps: []resource.TestStep{
- {
- Config: testAccDataSourceCloudWorkloadSecurityAgentRules(),
- Check: resource.ComposeTestCheckFunc(
- cloudWorkloadSecurityCheckAgentRulesCount(accProvider),
- ),
- },
- },
- })
-}
-
-func cloudWorkloadSecurityCheckAgentRulesCount(accProvider func() (*schema.Provider, error)) func(state *terraform.State) error {
- return func(state *terraform.State) error {
- provider, _ := accProvider()
- providerConf := provider.Meta().(*datadog.ProviderConfiguration)
- auth := providerConf.Auth
- apiInstances := providerConf.DatadogApiInstances
-
- agentRulesResponse, _, err := apiInstances.GetCSMThreatsApiV2().ListCloudWorkloadSecurityAgentRules(auth)
- if err != nil {
- return err
- }
- return cloudWorkloadSecurityAgentRulesCount(state, len(agentRulesResponse.Data))
- }
-}
-
-func cloudWorkloadSecurityAgentRulesCount(state *terraform.State, responseCount int) error {
- resourceAttributes := state.RootModule().Resources[tfAgentRulesSource].Primary.Attributes
- agentRulesCount, _ := strconv.Atoi(resourceAttributes["agent_rules.#"])
-
- if agentRulesCount != responseCount {
- return fmt.Errorf("expected %d agent rules got %d agent rules",
- responseCount, agentRulesCount)
- }
- return nil
-}
-
-func testAccDataSourceCloudWorkloadSecurityAgentRules() string {
- return `
-data "datadog_cloud_workload_security_agent_rules" "acceptance_test" {
-}
-`
-}
diff --git a/datadog/tests/data_source_datadog_csm_threats_agent_rules_test.go b/datadog/tests/data_source_datadog_csm_threats_agent_rule_test.go
similarity index 100%
rename from datadog/tests/data_source_datadog_csm_threats_agent_rules_test.go
rename to datadog/tests/data_source_datadog_csm_threats_agent_rule_test.go
diff --git a/datadog/tests/data_source_datadog_csm_threats_multi_policy_agent_rules_test.go b/datadog/tests/data_source_datadog_csm_threats_multi_policy_agent_rules_test.go
new file mode 100644
index 0000000000..16cc6d08f3
--- /dev/null
+++ b/datadog/tests/data_source_datadog_csm_threats_multi_policy_agent_rules_test.go
@@ -0,0 +1,153 @@
+package test
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "testing"
+
+ "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+
+ "github.com/terraform-providers/terraform-provider-datadog/datadog/fwprovider"
+)
+
+func TestAccCSMThreatsMultiPolicyAgentRulesDataSource(t *testing.T) {
+ t.Parallel()
+ ctx, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t)
+
+ policyName := uniqueAgentRuleName(ctx)
+ policyConfig := fmt.Sprintf(`
+ resource "datadog_csm_threats_policy" "policy_for_test" {
+ name = "%s"
+ enabled = true
+ description = "im a policy"
+ tags = ["host_name:test_host"]
+ }
+ `, policyName)
+
+ agentRuleName := uniqueAgentRuleName(ctx)
+ agentRuleConfig := fmt.Sprintf(`
+ %s
+ resource "datadog_csm_threats_multi_policy_agent_rule" "agent_rule_for_data_source_test" {
+ name = "%s"
+ policy_id = datadog_csm_threats_policy.policy_for_test.id
+ enabled = true
+ description = "im a rule"
+ expression = "open.file.name == \"etc/shadow/password\""
+ product_tags = ["compliance_framework:PCI-DSS"]
+ }
+ `, policyConfig, agentRuleName)
+ dataSourceName := "data.datadog_csm_threats_multi_policy_agent_rules.my_data_source"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV5ProviderFactories: accProviders,
+ CheckDestroy: testAccCheckCSMThreatsMultiPolicyAgentRuleDestroy(providers.frameworkProvider),
+ Steps: []resource.TestStep{
+ {
+ // Create an agent rule to have at least one
+ Config: agentRuleConfig,
+ Check: testAccCheckCSMThreatsMultiPolicyAgentRuleExists(providers.frameworkProvider, "datadog_csm_threats_multi_policy_agent_rule.agent_rule_for_data_source_test"),
+ },
+ {
+ Config: fmt.Sprintf(`
+ %s
+ data "datadog_csm_threats_multi_policy_agent_rules" "my_data_source" {
+ policy_id = datadog_csm_threats_policy.policy_for_test.id
+ }
+ `, agentRuleConfig),
+ Check: checkCSMThreatsMultiPolicyAgentRulesDataSourceContent(providers.frameworkProvider, dataSourceName, agentRuleName),
+ },
+ },
+ })
+}
+
+func testAccCheckDatadogCSMThreatsMultiPolicyAgentRulesDataSourceConfig(policyName, agentRuleName string) string {
+ return fmt.Sprintf(`
+data "datadog_csm_threats_multi_policy_agent_rules" "my_data_source" {
+ policy_id = datadog_csm_threats_policy.policy.id
+}
+
+resource "datadog_csm_threats_policy" "policy" {
+ name = "%s"
+ enabled = true
+ description = "Test description"
+ tags = ["host_name:test_host"]
+}
+
+resource "datadog_csm_threats_multi_policy_agent_rule" "agent_rule" {
+ name = "%s"
+ description = "Test description"
+ enabled = true
+ expression = "open.file.name == \"etc/shadow/password\""
+ policy_id = datadog_csm_threats_policy.policy.id
+ product_tags = ["compliance_framework:PCI-DSS"]
+}
+`, policyName, agentRuleName)
+}
+
+func checkCSMThreatsMultiPolicyAgentRulesDataSourceContent(accProvider *fwprovider.FrameworkProvider, dataSourceName string, agentRuleName string) resource.TestCheckFunc {
+ return func(state *terraform.State) error {
+ res, ok := state.RootModule().Resources[dataSourceName]
+ if !ok {
+ return fmt.Errorf("resource missing from state: %s", dataSourceName)
+ }
+
+ auth := accProvider.Auth
+ apiInstances := accProvider.DatadogApiInstances
+
+ policyId := res.Primary.Attributes["policy_id"]
+ allAgentRulesResponse, _, err := apiInstances.GetCSMThreatsApiV2().ListCSMThreatsAgentRules(auth, *datadogV2.NewListCSMThreatsAgentRulesOptionalParameters().WithPolicyId(policyId))
+ if err != nil {
+ return err
+ }
+
+ // Check the agentRule we created is in the API response
+ agentRuleId := ""
+ ruleName := ""
+ for _, rule := range allAgentRulesResponse.GetData() {
+ if rule.Attributes.GetName() == agentRuleName {
+ agentRuleId = rule.GetId()
+ ruleName = rule.Attributes.GetName()
+ break
+ }
+ }
+ if agentRuleId == "" {
+ return fmt.Errorf("agent rule with name '%s' not found in API responses", agentRuleName)
+ }
+
+ // Check that the data_source fetched is correct
+ resourceAttributes := res.Primary.Attributes
+ agentRulesIdsCount, err := strconv.Atoi(resourceAttributes["agent_rules_ids.#"])
+ if err != nil {
+ return err
+ }
+ agentRulesCount, err := strconv.Atoi(resourceAttributes["agent_rules.#"])
+ if err != nil {
+ return err
+ }
+ if agentRulesCount != agentRulesIdsCount {
+ return fmt.Errorf("the data source contains %d agent rules IDs but %d agent rules", agentRulesIdsCount, agentRulesCount)
+ }
+
+ // Find in which position is the agent rule we created, and check its values
+ idx := 0
+ for idx < agentRulesIdsCount && resourceAttributes[fmt.Sprintf("agent_rules_ids.%d", idx)] != agentRuleId {
+ idx++
+ }
+ if idx == len(resourceAttributes) {
+ return fmt.Errorf("agent rule with ID '%s' not found in data source", agentRuleId)
+ }
+
+ return resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("agent_rules.%d.name", idx), ruleName),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("agent_rules.%d.enabled", idx), "true"),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("agent_rules.%d.description", idx), "im a rule"),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("agent_rules.%d.expression", idx), "open.file.name == \"etc/shadow/password\""),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("agent_rules.%d.product_tags.#", idx), "1"),
+ resource.TestCheckTypeSetElemAttr(dataSourceName, fmt.Sprintf("agent_rules.%d.product_tags.*", idx), "compliance_framework:PCI-DSS"),
+ )(state)
+ }
+}
diff --git a/datadog/tests/data_source_datadog_csm_threats_policies_test.go b/datadog/tests/data_source_datadog_csm_threats_policies_test.go
new file mode 100644
index 0000000000..f9bed4ab41
--- /dev/null
+++ b/datadog/tests/data_source_datadog_csm_threats_policies_test.go
@@ -0,0 +1,112 @@
+package test
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+
+ "github.com/terraform-providers/terraform-provider-datadog/datadog/fwprovider"
+)
+
+func TestAccCSMThreatsPoliciesDataSource(t *testing.T) {
+ ctx, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t)
+
+ policyName := uniqueAgentRuleName(ctx)
+ dataSourceName := "data.datadog_csm_threats_policies.my_data_source"
+ policyConfig := fmt.Sprintf(`
+ resource "datadog_csm_threats_policy" "policy_for_data_source_test" {
+ name = "%s"
+ enabled = true
+ description = "im a policy"
+ tags = ["host_name:test_host"]
+ host_tags_lists = [["host_name:test_host", "env:prod"], ["host_name:test_host2", "env:staging"]]
+ }
+ `, policyName)
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV5ProviderFactories: accProviders,
+ CheckDestroy: testAccCheckCSMThreatsPolicyDestroy(providers.frameworkProvider),
+ Steps: []resource.TestStep{
+ {
+ // Create a policy to have at least one
+ Config: policyConfig,
+ Check: testAccCheckCSMThreatsPolicyExists(providers.frameworkProvider, "datadog_csm_threats_policy.policy_for_data_source_test"),
+ },
+ {
+ Config: fmt.Sprintf(`
+ %s
+ data "datadog_csm_threats_policies" "my_data_source" {}
+ `, policyConfig),
+ Check: checkCSMThreatsPoliciesDataSourceContent(providers.frameworkProvider, dataSourceName, policyName),
+ },
+ },
+ })
+}
+
+func checkCSMThreatsPoliciesDataSourceContent(accProvider *fwprovider.FrameworkProvider, dataSourceName string, policyName string) resource.TestCheckFunc {
+ return func(state *terraform.State) error {
+ res, ok := state.RootModule().Resources[dataSourceName]
+ if !ok {
+ return fmt.Errorf("resource missing from state: %s", dataSourceName)
+ }
+
+ auth := accProvider.Auth
+ apiInstances := accProvider.DatadogApiInstances
+
+ allPoliciesResponse, _, err := apiInstances.GetCSMThreatsApiV2().ListCSMThreatsAgentPolicies(auth)
+ if err != nil {
+ return err
+ }
+
+ // Check the policy we created is in the API response
+ resPolicyId := ""
+ for _, policy := range allPoliciesResponse.GetData() {
+ if policy.Attributes.GetName() == policyName {
+ resPolicyId = policy.GetId()
+ break
+ }
+ }
+ if resPolicyId == "" {
+ return fmt.Errorf("policy with name '%s' not found in API responses", policyName)
+ }
+
+ // Check that the data_source fetched is correct
+ resourceAttributes := res.Primary.Attributes
+ policyIdsCount, err := strconv.Atoi(resourceAttributes["policy_ids.#"])
+ if err != nil {
+ return err
+ }
+ policiesCount, err := strconv.Atoi(resourceAttributes["policies.#"])
+ if err != nil {
+ return err
+ }
+ if policiesCount != policyIdsCount {
+ return fmt.Errorf("the data source contains %d policy IDs but %d policies", policyIdsCount, policiesCount)
+ }
+
+ // Find in which position is the policy we created, and check its values
+ idx := 0
+ for idx < policyIdsCount && resourceAttributes[fmt.Sprintf("policy_ids.%d", idx)] != resPolicyId {
+ idx++
+ }
+ if idx == len(resourceAttributes) {
+ return fmt.Errorf("policy with ID '%s' not found in data source", resPolicyId)
+ }
+
+ return resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("policies.%d.name", idx), policyName),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("policies.%d.enabled", idx), "true"),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("policies.%d.tags.0", idx), "host_name:test_host"),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("policies.%d.host_tags_lists.0.0", idx), "host_name:test_host"),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("policies.%d.host_tags_lists.0.1", idx), "env:prod"),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("policies.%d.host_tags_lists.1.0", idx), "host_name:test_host2"),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("policies.%d.host_tags_lists.1.1", idx), "env:staging"),
+ resource.TestCheckResourceAttr(dataSourceName, fmt.Sprintf("policies.%d.description", idx), "im a policy"),
+ )(state)
+ }
+}
diff --git a/datadog/tests/provider_test.go b/datadog/tests/provider_test.go
index b334d9a20a..1abbec9977 100644
--- a/datadog/tests/provider_test.go
+++ b/datadog/tests/provider_test.go
@@ -58,7 +58,10 @@ var testFiles2EndpointTags = map[string]string{
"tests/data_source_datadog_application_key_test": "application_keys",
"tests/data_source_datadog_cloud_workload_security_agent_rules_test": "cloud-workload-security",
"tests/data_source_datadog_action_connection_test": "action_connection",
+ "tests/data_source_datadog_csm_threats_agent_rule_test": "cloud-workload-security",
"tests/data_source_datadog_csm_threats_agent_rules_test": "cloud-workload-security",
+ "tests/data_source_datadog_csm_threats_multi_policy_agent_rules_test": "cloud-workload-security",
+ "tests/data_source_datadog_csm_threats_policies_test": "cloud-workload-security",
"tests/data_source_datadog_dashboard_list_test": "dashboard-lists",
"tests/data_source_datadog_dashboard_test": "dashboard",
"tests/data_source_datadog_hosts_test": "hosts",
@@ -119,6 +122,9 @@ var testFiles2EndpointTags = map[string]string{
"tests/resource_datadog_cloud_workload_security_agent_rule_test": "cloud_workload_security",
"tests/resource_datadog_action_connection_test": "action_connection",
"tests/resource_datadog_csm_threats_agent_rule_test": "cloud-workload-security",
+ "tests/resource_datadog_csm_threats_multi_policy_agent_rule_test": "cloud-workload-security",
+ "tests/resource_datadog_csm_threats_policy_test": "cloud-workload-security",
+ "tests/resource_datadog_csm_threats_policies_list_test": "cloud-workload-security",
"tests/resource_datadog_dashboard_alert_graph_test": "dashboards",
"tests/resource_datadog_dashboard_alert_value_test": "dashboards",
"tests/resource_datadog_dashboard_change_test": "dashboards",
diff --git a/datadog/tests/resource_datadog_cloud_workload_security_agent_rule_test.go b/datadog/tests/resource_datadog_cloud_workload_security_agent_rule_test.go
deleted file mode 100644
index 9ac3ce0b7c..0000000000
--- a/datadog/tests/resource_datadog_cloud_workload_security_agent_rule_test.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package test
-
-import (
- "context"
- "fmt"
- "strings"
- "testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/hashicorp/terraform-plugin-testing/helper/resource"
- "github.com/hashicorp/terraform-plugin-testing/terraform"
-
- "github.com/terraform-providers/terraform-provider-datadog/datadog"
-)
-
-const tfAgentRuleName = "datadog_cloud_workload_security_agent_rule.acceptance_test"
-
-func TestAccDatadogCloudWorkloadSecurityAgentRule(t *testing.T) {
- t.Parallel()
- ctx, accProviders := testAccProviders(context.Background(), t)
- agentRuleName := strings.Replace(uniqueEntityName(ctx, t), "-", "_", -1)
- accProvider := testAccProvider(t, accProviders)
-
- resource.Test(t, resource.TestCase{
- PreCheck: func() { testAccPreCheck(t) },
- ProviderFactories: accProviders,
- CheckDestroy: testAccCheckDatadogCloudWorkloadSecurityAgentRuleDestroy(accProvider),
- Steps: []resource.TestStep{
- {
- Config: testAccCheckDatadogCloudWorkloadSecurityAgentRuleCreated(agentRuleName),
- Check: testAccCheckDatadogCloudWorkloadSecurityAgentRuleCreatedCheck(accProvider, agentRuleName),
- },
- {
- Config: testAccCheckDatadogCloudWorkloadSecurityAgentRuleUpdated(agentRuleName),
- Check: testAccCheckDatadogCloudWorkloadSecurityAgentRuleUpdatedCheck(accProvider, agentRuleName),
- },
- },
- })
-}
-
-func testAccCheckDatadogCloudWorkloadSecurityAgentRuleCreated(name string) string {
- return fmt.Sprintf(`
-resource "datadog_cloud_workload_security_agent_rule" "acceptance_test" {
- name = "%s"
- description = "an agent rule"
- enabled = "true"
- expression = "exec.file.name == \"java\""
-}
-`, name)
-}
-
-func testAccCheckDatadogCloudWorkloadSecurityAgentRuleCreatedCheck(accProvider func() (*schema.Provider, error), agentRuleName string) resource.TestCheckFunc {
- return resource.ComposeTestCheckFunc(
- testAccCheckDatadogCloudWorkloadSecurityAgentRuleExists(accProvider),
- resource.TestCheckResourceAttr(
- tfAgentRuleName, "name", agentRuleName),
- resource.TestCheckResourceAttr(
- tfAgentRuleName, "description", "an agent rule"),
- resource.TestCheckResourceAttr(
- tfAgentRuleName, "enabled", "true"),
- resource.TestCheckResourceAttr(
- tfAgentRuleName, "expression", "exec.file.name == \"java\""),
- )
-}
-
-func testAccCheckDatadogCloudWorkloadSecurityAgentRuleUpdated(name string) string {
- return fmt.Sprintf(`
-resource "datadog_cloud_workload_security_agent_rule" "acceptance_test" {
- name = "%s"
- description = "a new agent rule"
- enabled = "false"
- expression = "exec.file.name == \"go\""
-}
-`, name)
-}
-
-func testAccCheckDatadogCloudWorkloadSecurityAgentRuleUpdatedCheck(accProvider func() (*schema.Provider, error), agentRuleName string) resource.TestCheckFunc {
- return resource.ComposeTestCheckFunc(
- testAccCheckDatadogCloudWorkloadSecurityAgentRuleExists(accProvider),
- resource.TestCheckResourceAttr(
- tfAgentRuleName, "name", agentRuleName),
- resource.TestCheckResourceAttr(
- tfAgentRuleName, "description", "a new agent rule"),
- resource.TestCheckResourceAttr(
- tfAgentRuleName, "enabled", "false"),
- resource.TestCheckResourceAttr(
- tfAgentRuleName, "expression", "exec.file.name == \"go\""),
- )
-}
-
-func testAccCheckDatadogCloudWorkloadSecurityAgentRuleExists(accProvider func() (*schema.Provider, error)) resource.TestCheckFunc {
- return func(s *terraform.State) error {
- provider, _ := accProvider()
- providerConf := provider.Meta().(*datadog.ProviderConfiguration)
- auth := providerConf.Auth
- apiInstances := providerConf.DatadogApiInstances
-
- for _, agentRule := range s.RootModule().Resources {
- _, _, err := apiInstances.GetCSMThreatsApiV2().GetCloudWorkloadSecurityAgentRule(auth, agentRule.Primary.ID)
- if err != nil {
- return fmt.Errorf("received an error retrieving cloud workload security agent rule: %s", err)
- }
- }
- return nil
- }
-}
-
-func testAccCheckDatadogCloudWorkloadSecurityAgentRuleDestroy(accProvider func() (*schema.Provider, error)) resource.TestCheckFunc {
- return func(s *terraform.State) error {
- provider, _ := accProvider()
- providerConf := provider.Meta().(*datadog.ProviderConfiguration)
- auth := providerConf.Auth
- apiInstances := providerConf.DatadogApiInstances
-
- for _, resource := range s.RootModule().Resources {
- if resource.Type == "datadog_cloud_workload_security_agent_rule" {
- _, httpResponse, err := apiInstances.GetCSMThreatsApiV2().GetCloudWorkloadSecurityAgentRule(auth, resource.Primary.ID)
- if err != nil {
- if httpResponse != nil && httpResponse.StatusCode == 404 {
- continue
- }
- return fmt.Errorf("received an error deleting cloud workload security agent rule: %s", err)
- }
- return fmt.Errorf("cloud workload security agent rule still exists")
- }
- }
- return nil
- }
-
-}
diff --git a/datadog/tests/resource_datadog_csm_threats_multi_policy_agent_rule_test.go b/datadog/tests/resource_datadog_csm_threats_multi_policy_agent_rule_test.go
new file mode 100644
index 0000000000..120c2fc667
--- /dev/null
+++ b/datadog/tests/resource_datadog_csm_threats_multi_policy_agent_rule_test.go
@@ -0,0 +1,149 @@
+package test
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "testing"
+
+ "github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+
+ "github.com/terraform-providers/terraform-provider-datadog/datadog/fwprovider"
+)
+
+// Create an agent rule and update its description
+func TestAccCSMThreatsMultiPolicyAgentRule_CreateAndUpdate(t *testing.T) {
+ ctx, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t)
+
+ agentRuleName := uniqueAgentRuleName(ctx)
+ resourceName := "datadog_csm_threats_multi_policy_agent_rule.agent_rule_test"
+
+ policyName := uniqueAgentRuleName(ctx)
+ policyConfig := fmt.Sprintf(`
+ resource "datadog_csm_threats_policy" "policy_for_test" {
+ name = "%s"
+ enabled = true
+ description = "im a policy"
+ tags = ["host_name:test_host"]
+ }
+ `, policyName)
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV5ProviderFactories: accProviders,
+ CheckDestroy: testAccCheckCSMThreatsMultiPolicyAgentRuleDestroy(providers.frameworkProvider),
+ Steps: []resource.TestStep{
+ {
+ // Create a policy to have at least one
+ Config: policyConfig,
+ Check: testAccCheckCSMThreatsPolicyExists(providers.frameworkProvider, "datadog_csm_threats_policy.policy_for_test"),
+ },
+ {
+ Config: fmt.Sprintf(`
+ %s
+ resource "datadog_csm_threats_multi_policy_agent_rule" "agent_rule_test" {
+ name = "%s"
+ policy_id = datadog_csm_threats_policy.policy_for_test.id
+ enabled = true
+ description = "im a rule"
+ expression = "open.file.name == \"etc/shadow/password\""
+ product_tags = ["compliance_framework:PCI-DSS"]
+ }
+ `, policyConfig, agentRuleName),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCSMThreatsMultiPolicyAgentRuleExists(providers.frameworkProvider, resourceName),
+ checkCSMThreatsAgentRuleContentMultiPolicy(
+ resourceName,
+ agentRuleName,
+ "im a rule",
+ "open.file.name == \"etc/shadow/password\"",
+ "compliance_framework:PCI-DSS",
+ ),
+ ),
+ },
+ // Update description
+ {
+ Config: fmt.Sprintf(`
+ %s
+ resource "datadog_csm_threats_multi_policy_agent_rule" "agent_rule_test" {
+ name = "%s"
+ policy_id = datadog_csm_threats_policy.policy_for_test.id
+ enabled = true
+ description = "updated agent rule for terraform provider test"
+ expression = "open.file.name == \"etc/shadow/password\""
+ product_tags = ["compliance_framework:ISO-27799"]
+ }
+ `, policyConfig, agentRuleName),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCSMThreatsMultiPolicyAgentRuleExists(providers.frameworkProvider, resourceName),
+ checkCSMThreatsAgentRuleContentMultiPolicy(
+ resourceName,
+ agentRuleName,
+ "updated agent rule for terraform provider test",
+ "open.file.name == \"etc/shadow/password\"",
+ "compliance_framework:ISO-27799",
+ ),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckCSMThreatsMultiPolicyAgentRuleExists(accProvider *fwprovider.FrameworkProvider, resourceName string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ resource, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return fmt.Errorf("resource '%s' not found in the state %s", resourceName, s.RootModule().Resources)
+ }
+
+ if resource.Type != "datadog_csm_threats_multi_policy_agent_rule" {
+ return fmt.Errorf("resource %s is not of type datadog_csm_threats_multi_policy_agent_rule, found %s instead", resourceName, resource.Type)
+ }
+
+ auth := accProvider.Auth
+ apiInstances := accProvider.DatadogApiInstances
+
+ policyId := resource.Primary.Attributes["policy_id"]
+ _, _, err := apiInstances.GetCSMThreatsApiV2().GetCSMThreatsAgentRule(auth, resource.Primary.ID, *datadogV2.NewGetCSMThreatsAgentRuleOptionalParameters().WithPolicyId(policyId))
+ if err != nil {
+ return fmt.Errorf("received an error retrieving agent rule: %s", err)
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckCSMThreatsMultiPolicyAgentRuleDestroy(accProvider *fwprovider.FrameworkProvider) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ auth := accProvider.Auth
+ apiInstances := accProvider.DatadogApiInstances
+
+ for _, resource := range s.RootModule().Resources {
+ if resource.Type == "datadog_csm_threats_multi_policy_agent_rule" {
+ policyId := resource.Primary.Attributes["policy_id"]
+ _, httpResponse, err := apiInstances.GetCSMThreatsApiV2().GetCSMThreatsAgentRule(auth, resource.Primary.ID, *datadogV2.NewGetCSMThreatsAgentRuleOptionalParameters().WithPolicyId(policyId))
+ if err == nil {
+ return errors.New("agent rule still exists")
+ }
+ if httpResponse == nil || httpResponse.StatusCode != 404 {
+ return fmt.Errorf("received an error while getting the agent rule: %s", err)
+ }
+ }
+ }
+
+ return nil
+ }
+}
+
+func checkCSMThreatsAgentRuleContentMultiPolicy(resourceName string, name string, description string, expression string, product_tags string) resource.TestCheckFunc {
+ return resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "name", name),
+ resource.TestCheckResourceAttr(resourceName, "description", description),
+ resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
+ resource.TestCheckResourceAttr(resourceName, "expression", expression),
+ resource.TestCheckResourceAttr(resourceName, "product_tags.#", "1"),
+ resource.TestCheckTypeSetElemAttr(resourceName, "product_tags.*", product_tags),
+ )
+}
diff --git a/datadog/tests/resource_datadog_csm_threats_policy_test.go b/datadog/tests/resource_datadog_csm_threats_policy_test.go
new file mode 100644
index 0000000000..4eca2fdd0f
--- /dev/null
+++ b/datadog/tests/resource_datadog_csm_threats_policy_test.go
@@ -0,0 +1,204 @@
+package test
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+
+ "github.com/terraform-providers/terraform-provider-datadog/datadog/fwprovider"
+)
+
+// Create an agent policy and update its description
+func TestAccCSMThreatsPolicy_CreateAndUpdate(t *testing.T) {
+ ctx, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t)
+
+ policyName := uniqueAgentRuleName(ctx)
+ resourceName := "datadog_csm_threats_policy.policy_test"
+ tags := []string{"host_name:test_host"}
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV5ProviderFactories: accProviders,
+ CheckDestroy: testAccCheckCSMThreatsPolicyDestroy(providers.frameworkProvider),
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+ resource "datadog_csm_threats_policy" "policy_test" {
+ name = "%s"
+ enabled = true
+ description = "im a policy"
+ tags = ["host_name:test_host"]
+ }
+ `, policyName),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCSMThreatsPolicyExists(providers.frameworkProvider, "datadog_csm_threats_policy.policy_test"),
+ checkCSMThreatsPolicyContent(
+ resourceName,
+ policyName,
+ "im a policy",
+ tags,
+ ),
+ ),
+ },
+ // Update description
+ {
+ Config: fmt.Sprintf(`
+ resource "datadog_csm_threats_policy" "policy_test" {
+ name = "%s"
+ enabled = true
+ description = "updated policy for terraform provider test"
+ tags = ["host_name:test_host"]
+ }
+ `, policyName),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCSMThreatsPolicyExists(providers.frameworkProvider, resourceName),
+ checkCSMThreatsPolicyContent(
+ resourceName,
+ policyName,
+ "updated policy for terraform provider test",
+ tags,
+ ),
+ ),
+ },
+ },
+ })
+}
+
+// Create an agent policy with host_tags_lists and update its description
+func TestAccCSMThreatsPolicy_CreateAndUpdateWithHostTagsLists(t *testing.T) {
+ ctx, providers, accProviders := testAccFrameworkMuxProviders(context.Background(), t)
+
+ policyName := uniqueAgentRuleName(ctx)
+ resourceName := "datadog_csm_threats_policy.policy_test"
+ hostTagsLists := [][]string{
+ {"host_name:test_host", "env:prod"},
+ {"host_name:test_host2", "env:staging"},
+ }
+ updatedHostTagsLists := [][]string{
+ {"host_name:test", "env:prod"},
+ {"host_name:test_host2", "env:test"},
+ }
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV5ProviderFactories: accProviders,
+ CheckDestroy: testAccCheckCSMThreatsPolicyDestroy(providers.frameworkProvider),
+ Steps: []resource.TestStep{
+ {
+ Config: fmt.Sprintf(`
+ resource "datadog_csm_threats_policy" "policy_test" {
+ name = "%s"
+ enabled = true
+ description = "im a policy"
+ host_tags_lists = [["host_name:test_host", "env:prod"], ["host_name:test_host2", "env:staging"]]
+ }
+ `, policyName),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCSMThreatsPolicyExists(providers.frameworkProvider, "datadog_csm_threats_policy.policy_test"),
+ checkCSMThreatsPolicyContentWithHostTagsLists(
+ resourceName,
+ policyName,
+ "im a policy",
+ hostTagsLists,
+ ),
+ ),
+ },
+ // Update description and tags
+ {
+ Config: fmt.Sprintf(`
+ resource "datadog_csm_threats_policy" "policy_test" {
+ name = "%s"
+ enabled = true
+ description = "updated policy for terraform provider test"
+ host_tags_lists = [["host_name:test", "env:prod"], ["host_name:test_host2", "env:test"]]
+ }
+ `, policyName),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCSMThreatsPolicyExists(providers.frameworkProvider, resourceName),
+ checkCSMThreatsPolicyContentWithHostTagsLists(
+ resourceName,
+ policyName,
+ "updated policy for terraform provider test",
+ updatedHostTagsLists,
+ ),
+ ),
+ },
+ },
+ })
+}
+
+func checkCSMThreatsPolicyContent(resourceName string, name string, description string, tags []string) resource.TestCheckFunc {
+ return resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "name", name),
+ resource.TestCheckResourceAttr(resourceName, "description", description),
+ resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
+ resource.TestCheckResourceAttr(resourceName, "tags.0", tags[0]),
+ )
+}
+
+func checkCSMThreatsPolicyContentWithHostTagsLists(resourceName string, name string, description string, hostTagsLists [][]string) resource.TestCheckFunc {
+ checks := []resource.TestCheckFunc{
+ resource.TestCheckResourceAttr(resourceName, "name", name),
+ resource.TestCheckResourceAttr(resourceName, "description", description),
+ resource.TestCheckResourceAttr(resourceName, "enabled", "true"),
+ }
+
+ // Add checks for each host tags list
+ for i, tagList := range hostTagsLists {
+ for j, tag := range tagList {
+ checks = append(checks, resource.TestCheckResourceAttr(
+ resourceName,
+ fmt.Sprintf("host_tags_lists.%d.%d", i, j),
+ tag,
+ ))
+ }
+ }
+
+ return resource.ComposeTestCheckFunc(checks...)
+}
+
+func testAccCheckCSMThreatsPolicyExists(accProvider *fwprovider.FrameworkProvider, resourceName string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ resource, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return fmt.Errorf("resource '%s' not found in the state %s", resourceName, s.RootModule().Resources)
+ }
+
+ if resource.Type != "datadog_csm_threats_policy" {
+ return fmt.Errorf("resource %s is not of type datadog_csm_threats_policy, found %s instead", resourceName, resource.Type)
+ }
+
+ auth := accProvider.Auth
+ apiInstances := accProvider.DatadogApiInstances
+
+ _, _, err := apiInstances.GetCSMThreatsApiV2().GetCSMThreatsAgentPolicy(auth, resource.Primary.ID)
+ if err != nil {
+ return fmt.Errorf("received an error retrieving policy: %s", err)
+ }
+
+ return nil
+ }
+}
+
+func testAccCheckCSMThreatsPolicyDestroy(accProvider *fwprovider.FrameworkProvider) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ auth := accProvider.Auth
+ apiInstances := accProvider.DatadogApiInstances
+
+ for _, resource := range s.RootModule().Resources {
+ if resource.Type == "datadog_csm_threats_policy" {
+ _, httpResponse, err := apiInstances.GetCSMThreatsApiV2().GetCSMThreatsAgentPolicy(auth, resource.Primary.ID)
+ if err == nil {
+ return errors.New("policy still exists")
+ }
+ if httpResponse == nil || httpResponse.StatusCode != 404 {
+ return fmt.Errorf("received an error while getting the policy: %s", err)
+ }
+ }
+ }
+
+ return nil
+ }
+}
diff --git a/docs/data-sources/cloud_workload_security_agent_rules.md b/docs/data-sources/cloud_workload_security_agent_rules.md
deleted file mode 100644
index 6bfafbe24b..0000000000
--- a/docs/data-sources/cloud_workload_security_agent_rules.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "datadog_cloud_workload_security_agent_rules Data Source - terraform-provider-datadog"
-subcategory: ""
-description: |-
- Use this data source to retrieve information about existing Cloud Workload Security Agent Rules for use in other resources. Deprecated, use datadog_csm_threats_agent_rules data source instead: https://registry.terraform.io/providers/DataDog/datadog/latest/docs/data-sources/csm_threats_agent_rules
----
-
-# datadog_cloud_workload_security_agent_rules (Data Source)
-
-Use this data source to retrieve information about existing Cloud Workload Security Agent Rules for use in other resources. Deprecated, use datadog_csm_threats_agent_rules data source instead: https://registry.terraform.io/providers/DataDog/datadog/latest/docs/data-sources/csm_threats_agent_rules
-
-## Example Usage
-
-```terraform
-data "datadog_cloud_workload_security_agent_rules" "test" {
-}
-```
-
-
-## Schema
-
-### Read-Only
-
-- `agent_rules` (List of Object) List of Agent rules. (see [below for nested schema](#nestedatt--agent_rules))
-- `id` (String) The ID of this resource.
-
-
-### Nested Schema for `agent_rules`
-
-Read-Only:
-
-- `description` (String)
-- `enabled` (Boolean)
-- `expression` (String)
-- `id` (String)
-- `name` (String)
diff --git a/docs/data-sources/csm_threats_multi_policy_agent_rules.md b/docs/data-sources/csm_threats_multi_policy_agent_rules.md
new file mode 100644
index 0000000000..db71337c99
--- /dev/null
+++ b/docs/data-sources/csm_threats_multi_policy_agent_rules.md
@@ -0,0 +1,38 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "datadog_csm_threats_multi_policy_agent_rules Data Source - terraform-provider-datadog"
+subcategory: ""
+description: |-
+ Use this data source to retrieve information about existing Agent rules.
+---
+
+# datadog_csm_threats_multi_policy_agent_rules (Data Source)
+
+Use this data source to retrieve information about existing Agent rules.
+
+
+
+
+## Schema
+
+### Optional
+
+- `policy_id` (String) Listing only the rules in the policy with this field as the ID
+
+### Read-Only
+
+- `agent_rules` (List of Object) List of Agent rules (see [below for nested schema](#nestedatt--agent_rules))
+- `agent_rules_ids` (List of String) List of IDs for the Agent rules.
+- `id` (String) The ID of the data source
+
+
+### Nested Schema for `agent_rules`
+
+Read-Only:
+
+- `description` (String)
+- `enabled` (Boolean)
+- `expression` (String)
+- `id` (String)
+- `name` (String)
+- `product_tags` (Set of String)
diff --git a/docs/data-sources/csm_threats_policies.md b/docs/data-sources/csm_threats_policies.md
new file mode 100644
index 0000000000..46ae797871
--- /dev/null
+++ b/docs/data-sources/csm_threats_policies.md
@@ -0,0 +1,33 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "datadog_csm_threats_policies Data Source - terraform-provider-datadog"
+subcategory: ""
+description: |-
+ Use this data source to retrieve information about existing policies.
+---
+
+# datadog_csm_threats_policies (Data Source)
+
+Use this data source to retrieve information about existing policies.
+
+
+
+
+## Schema
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+- `policies` (List of Object) List of policies (see [below for nested schema](#nestedatt--policies))
+- `policy_ids` (List of String) List of IDs for the policies.
+
+
+### Nested Schema for `policies`
+
+Read-Only:
+
+- `description` (String)
+- `enabled` (Boolean)
+- `id` (String)
+- `name` (String)
+- `tags` (Set of String)
diff --git a/docs/resources/csm_threats_multi_policy_agent_rule.md b/docs/resources/csm_threats_multi_policy_agent_rule.md
new file mode 100644
index 0000000000..67f4e6c52b
--- /dev/null
+++ b/docs/resources/csm_threats_multi_policy_agent_rule.md
@@ -0,0 +1,32 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "datadog_csm_threats_multi_policy_agent_rule Resource - terraform-provider-datadog"
+subcategory: ""
+description: |-
+ Provides a Datadog CSM Threats Agent Rule API resource.
+---
+
+# datadog_csm_threats_multi_policy_agent_rule (Resource)
+
+Provides a Datadog CSM Threats Agent Rule API resource.
+
+
+
+
+## Schema
+
+### Required
+
+- `enabled` (Boolean) Indicates Whether the Agent rule is enabled.
+- `expression` (String) The SECL expression of the Agent rule
+- `name` (String) The name of the Agent rule.
+- `policy_id` (String) The ID of the agent policy in which the rule is saved
+
+### Optional
+
+- `description` (String) A description for the Agent rule.
+- `product_tags` (Set of String) The list of product tags associated with the rule
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
diff --git a/docs/resources/csm_threats_policy.md b/docs/resources/csm_threats_policy.md
new file mode 100644
index 0000000000..61039b47f7
--- /dev/null
+++ b/docs/resources/csm_threats_policy.md
@@ -0,0 +1,31 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "datadog_csm_threats_policy Resource - terraform-provider-datadog"
+subcategory: ""
+description: |-
+ Provides a Datadog CSM Threats policy API resource.
+---
+
+# datadog_csm_threats_policy (Resource)
+
+Provides a Datadog CSM Threats policy API resource.
+
+
+
+
+## Schema
+
+### Required
+
+- `name` (String) The name of the policy.
+
+### Optional
+
+- `description` (String) A description for the policy.
+- `enabled` (Boolean) Indicates whether the policy is enabled. Defaults to `false`.
+- `host_tags_lists` (Set of List of String) Host tags that define where the policy is deployed. Inner values are ANDed, outer arrays are ORed.
+- `tags` (Set of String) Host tags that define where the policy is deployed. Deprecated, use host_tags_lists instead.
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
diff --git a/go.mod b/go.mod
index a02074fa79..053540190b 100644
--- a/go.mod
+++ b/go.mod
@@ -101,4 +101,9 @@ require (
google.golang.org/protobuf v1.36.3 // indirect
)
+<<<<<<< Updated upstream
go 1.23.0
+=======
+go 1.23.0
+replace github.com/DataDog/datadog-api-client-go/v2 v2.31.0 => ../datadog-api-client-go
+>>>>>>> Stashed changes