Skip to content

Commit c3edec5

Browse files
committed
fix required requirements and control block
1 parent 9543595 commit c3edec5

9 files changed

+133
-280
lines changed

datadog/fwprovider/framework_provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ var Resources = []func() resource.Resource{
8383
NewWorkflowAutomationResource,
8484
NewAppBuilderAppResource,
8585
NewObservabilitPipelineResource,
86-
NewCustomFrameworkResource,
86+
NewComplianceCustomFrameworkResource,
8787
}
8888

8989
var Datasources = []func() datasource.DataSource{

datadog/fwprovider/resource_datadog_custom_framework.go renamed to datadog/fwprovider/resource_datadog_compliance_custom_framework.go

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
88
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
9+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
910
"github.com/hashicorp/terraform-plugin-framework/attr"
1011
"github.com/hashicorp/terraform-plugin-framework/resource"
1112
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
@@ -16,14 +17,14 @@ import (
1617
"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/validators"
1718
)
1819

19-
var _ resource.Resource = &customFrameworkResource{}
20+
var _ resource.Resource = &complianceCustomFrameworkResource{}
2021

21-
type customFrameworkResource struct {
22+
type complianceCustomFrameworkResource struct {
2223
Api *datadogV2.SecurityMonitoringApi
2324
Auth context.Context
2425
}
2526

26-
type customFrameworkModel struct {
27+
type complianceCustomFrameworkModel struct {
2728
ID types.String `tfsdk:"id"`
2829
Description types.String `tfsdk:"description"`
2930
Version types.String `tfsdk:"version"`
@@ -33,33 +34,42 @@ type customFrameworkModel struct {
3334
Requirements types.Set `tfsdk:"requirements"` // have to define requirements as a set to be unordered
3435
}
3536

36-
func NewCustomFrameworkResource() resource.Resource {
37-
return &customFrameworkResource{}
37+
func NewComplianceCustomFrameworkResource() resource.Resource {
38+
return &complianceCustomFrameworkResource{}
3839
}
3940

40-
func (r *customFrameworkResource) Metadata(_ context.Context, _ resource.MetadataRequest, response *resource.MetadataResponse) {
41-
response.TypeName = "custom_framework"
41+
func (r *complianceCustomFrameworkResource) Metadata(_ context.Context, _ resource.MetadataRequest, response *resource.MetadataResponse) {
42+
response.TypeName = "compliance_custom_framework"
4243
}
4344

44-
func (r *customFrameworkResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
45+
func (r *complianceCustomFrameworkResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
4546
response.Schema = schema.Schema{
46-
Description: "Manages custom framework in Datadog.",
47+
Description: "Provides a Datadog Compliance Custom Framework resource, which is used to create and manage compliance custom frameworks.",
4748
Attributes: map[string]schema.Attribute{
4849
"id": schema.StringAttribute{
49-
Description: "The ID of the custom framework resource.",
50+
Description: "The ID of the compliance custom framework resource.",
5051
Computed: true,
5152
},
5253
"version": schema.StringAttribute{
5354
Description: "The framework version.",
54-
Required: true,
55+
Validators: []validator.String{
56+
stringvalidator.LengthAtLeast(1),
57+
},
58+
Required: true,
5559
},
5660
"handle": schema.StringAttribute{
5761
Description: "The framework handle.",
58-
Required: true,
62+
Validators: []validator.String{
63+
stringvalidator.LengthAtLeast(1),
64+
},
65+
Required: true,
5966
},
6067
"name": schema.StringAttribute{
6168
Description: "The framework name.",
62-
Required: true,
69+
Validators: []validator.String{
70+
stringvalidator.LengthAtLeast(1),
71+
},
72+
Required: true,
6373
},
6474
"icon_url": schema.StringAttribute{
6575
Description: "The URL of the icon representing the framework.",
@@ -74,28 +84,34 @@ func (r *customFrameworkResource) Schema(_ context.Context, _ resource.SchemaReq
7484
"requirements": schema.SetNestedBlock{
7585
Description: "The requirements of the framework.",
7686
Validators: []validator.Set{
77-
setvalidator.SizeAtLeast(1),
87+
setvalidator.IsRequired(),
7888
validators.RequirementNameValidator(),
7989
},
8090
NestedObject: schema.NestedBlockObject{
8191
Attributes: map[string]schema.Attribute{
8292
"name": schema.StringAttribute{
8393
Description: "The name of the requirement.",
8494
Required: true,
95+
Validators: []validator.String{
96+
stringvalidator.LengthAtLeast(1),
97+
},
8598
},
8699
},
87100
Blocks: map[string]schema.Block{
88101
"controls": schema.SetNestedBlock{
89102
Description: "The controls of the requirement.",
90103
Validators: []validator.Set{
91-
setvalidator.SizeAtLeast(1),
104+
setvalidator.IsRequired(),
92105
validators.ControlNameValidator(),
93106
},
94107
NestedObject: schema.NestedBlockObject{
95108
Attributes: map[string]schema.Attribute{
96109
"name": schema.StringAttribute{
97110
Description: "The name of the control.",
98111
Required: true,
112+
Validators: []validator.String{
113+
stringvalidator.LengthAtLeast(1),
114+
},
99115
},
100116
"rules_id": schema.SetAttribute{
101117
Description: "The list of rules IDs for the control.",
@@ -112,14 +128,14 @@ func (r *customFrameworkResource) Schema(_ context.Context, _ resource.SchemaReq
112128
}
113129
}
114130

115-
func (r *customFrameworkResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
131+
func (r *complianceCustomFrameworkResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
116132
providerData, _ := request.ProviderData.(*FrameworkProvider)
117133
r.Api = providerData.DatadogApiInstances.GetSecurityMonitoringApiV2()
118134
r.Auth = providerData.Auth
119135
}
120136

121-
func (r *customFrameworkResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
122-
var state customFrameworkModel
137+
func (r *complianceCustomFrameworkResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
138+
var state complianceCustomFrameworkModel
123139
diags := request.Config.Get(ctx, &state)
124140
response.Diagnostics.Append(diags...)
125141
if response.Diagnostics.HasError() {
@@ -129,16 +145,16 @@ func (r *customFrameworkResource) Create(ctx context.Context, request resource.C
129145
_, _, err := r.Api.CreateCustomFramework(r.Auth, *buildCreateFrameworkRequest(state))
130146

131147
if err != nil {
132-
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating custom framework"))
148+
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating compliance custom framework"))
133149
return
134150
}
135151
state.ID = types.StringValue(state.Handle.ValueString() + string('-') + state.Version.ValueString())
136152
diags = response.State.Set(ctx, &state)
137153
response.Diagnostics.Append(diags...)
138154
}
139155

140-
func (r *customFrameworkResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
141-
var state customFrameworkModel
156+
func (r *complianceCustomFrameworkResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
157+
var state complianceCustomFrameworkModel
142158
diags := request.State.Get(ctx, &state)
143159
response.Diagnostics.Append(diags...)
144160
if response.Diagnostics.HasError() {
@@ -151,8 +167,8 @@ func (r *customFrameworkResource) Delete(ctx context.Context, request resource.D
151167
}
152168
}
153169

154-
func (r *customFrameworkResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
155-
var state customFrameworkModel
170+
func (r *complianceCustomFrameworkResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
171+
var state complianceCustomFrameworkModel
156172
diags := request.State.Get(ctx, &state)
157173
response.Diagnostics.Append(diags...)
158174
if response.Diagnostics.HasError() {
@@ -169,16 +185,16 @@ func (r *customFrameworkResource) Read(ctx context.Context, request resource.Rea
169185
}
170186
// this is for any other error
171187
if err != nil {
172-
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error reading custom framework"))
188+
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error reading compliance custom framework"))
173189
return
174190
}
175191
databaseState := readStateFromDatabase(data, state.Handle.ValueString(), state.Version.ValueString())
176192
diags = response.State.Set(ctx, &databaseState)
177193
response.Diagnostics.Append(diags...)
178194
}
179195

180-
func (r *customFrameworkResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
181-
var state customFrameworkModel
196+
func (r *complianceCustomFrameworkResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
197+
var state complianceCustomFrameworkModel
182198
diags := request.Config.Get(ctx, &state)
183199
response.Diagnostics.Append(diags...)
184200
if response.Diagnostics.HasError() {
@@ -187,7 +203,7 @@ func (r *customFrameworkResource) Update(ctx context.Context, request resource.U
187203

188204
_, _, err := r.Api.UpdateCustomFramework(r.Auth, state.Handle.ValueString(), state.Version.ValueString(), *buildUpdateFrameworkRequest(state))
189205
if err != nil {
190-
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating custom framework"))
206+
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating compliance custom framework"))
191207
return
192208
}
193209
diags = response.State.Set(ctx, &state)
@@ -238,9 +254,9 @@ func setRequirements(requirements []attr.Value) types.Set {
238254
requirements,
239255
)
240256
}
241-
func readStateFromDatabase(data datadogV2.GetCustomFrameworkResponse, handle string, version string) customFrameworkModel {
257+
func readStateFromDatabase(data datadogV2.GetCustomFrameworkResponse, handle string, version string) complianceCustomFrameworkModel {
242258
// Set the state
243-
var state customFrameworkModel
259+
var state complianceCustomFrameworkModel
244260
state.ID = types.StringValue(handle + "-" + version)
245261
state.Handle = types.StringValue(handle)
246262
state.Version = types.StringValue(version)
@@ -267,7 +283,7 @@ func readStateFromDatabase(data datadogV2.GetCustomFrameworkResponse, handle str
267283
}
268284

269285
// ImportState is used to import a resource from an existing framework so we can update it if it exists in the database and not in terraform
270-
func (r *customFrameworkResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
286+
func (r *complianceCustomFrameworkResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
271287
// Split the ID into handle and version
272288
// The last hyphen separates handle and version
273289
lastHyphenIndex := strings.LastIndex(request.ID, "-")
@@ -306,7 +322,7 @@ func convertStateRequirementsToFrameworkRequirements(requirements types.Set) []d
306322
return frameworkRequirements
307323
}
308324

309-
func buildCreateFrameworkRequest(state customFrameworkModel) *datadogV2.CreateCustomFrameworkRequest {
325+
func buildCreateFrameworkRequest(state complianceCustomFrameworkModel) *datadogV2.CreateCustomFrameworkRequest {
310326
createFrameworkRequest := datadogV2.NewCreateCustomFrameworkRequestWithDefaults()
311327
description := state.Description.ValueString()
312328
iconURL := state.IconURL.ValueString()
@@ -324,7 +340,7 @@ func buildCreateFrameworkRequest(state customFrameworkModel) *datadogV2.CreateCu
324340
return createFrameworkRequest
325341
}
326342

327-
func buildUpdateFrameworkRequest(state customFrameworkModel) *datadogV2.UpdateCustomFrameworkRequest {
343+
func buildUpdateFrameworkRequest(state complianceCustomFrameworkModel) *datadogV2.UpdateCustomFrameworkRequest {
328344
updateFrameworkRequest := datadogV2.NewUpdateCustomFrameworkRequestWithDefaults()
329345
description := state.Description.ValueString()
330346
iconURL := state.IconURL.ValueString()

datadog/internal/validators/duplicate_control_validator.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package validators
33
import (
44
"context"
55
"fmt"
6-
"log"
76

87
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
98
"github.com/hashicorp/terraform-plugin-framework/types"
@@ -24,26 +23,19 @@ func (v controlNameValidator) ValidateSet(ctx context.Context, req validator.Set
2423
return
2524
}
2625

27-
// Get all control names from the configuration
2826
var controlNames []string
2927
for _, control := range req.ConfigValue.Elements() {
3028
controlObj := control.(types.Object)
3129
name := controlObj.Attributes()["name"].(types.String).ValueString()
32-
log.Printf("Found control name in config: %s", name)
3330
controlNames = append(controlNames, name)
3431
}
3532

36-
log.Printf("Found %d control names in config", len(controlNames))
37-
38-
// Check for duplicates in the list
3933
seen := make(map[string]bool)
4034
for _, name := range controlNames {
41-
log.Printf("Checking control name: %s", name)
4235
if seen[name] {
43-
log.Printf("Found duplicate control name: %s", name)
4436
resp.Diagnostics.AddError(
45-
"400 Bad Request",
46-
fmt.Sprintf("Control name '%s' is used more than once. Each control must have a unique name.", name),
37+
"Each Control must have a unique name under the same requirement",
38+
fmt.Sprintf("Control name '%s' is used more than once under the same requirement", name),
4739
)
4840
return
4941
}

datadog/internal/validators/duplicate_requirement_validator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ func (v requirementNameValidator) ValidateSet(ctx context.Context, req validator
4242
if seen[name] {
4343
log.Printf("Found duplicate requirement name: %s", name)
4444
resp.Diagnostics.AddError(
45-
"400 Bad Request",
46-
fmt.Sprintf("Requirement name '%s' is used more than once. Each requirement must have a unique name.", name),
45+
"Each Requirement must have a unique name",
46+
fmt.Sprintf("Requirement name '%s' is used more than once.", name),
4747
)
4848
return
4949
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2025-05-01T16:08:14.218018-04:00
1+
2025-05-07T09:53:00.898171-04:00

0 commit comments

Comments
 (0)