Skip to content

Commit 1fdf860

Browse files
Implementation of response policy support
Introduce `aquasec_response_policy` resource and `aquasec_response_policies`/`aquasec_response_policy_config` data sources with full client CRUD, utils, docs, and tests. - **Resource** - Add `aquasec_response_policy` with schema (`title`, `description`, `enabled`, `application_scopes`, `trigger`, `outputs`) and full CRUD in `aquasec/resource_response_policy.go`. - **Data Sources** - Add list data source `aquasec_response_policies` and config data source `aquasec_response_policy_config` in `aquasec/data_response_policy.go` (pagination/filtering + config fields). - **Provider Wiring** - Register new resource and data sources in `aquasec/provider.go`. - **Client API** - Implement `client/response_policy.go` with types and endpoints: get/list/create/update/delete, delete-all, status update, and config fetch. - **Utils** - Extend `aquasec/utils.go` with flatten/expand helpers for response policy schemas and config. - **Docs** - Add docs: `docs/resources/response_policy.md`, `docs/data-sources/response_policies.md`, `docs/data-sources/response_policy_config.md`. - **Tests** - Add acceptance tests for resource and data sources in `aquasec/resource_response_policy_test.go` and `aquasec/data_response_policy_test.go`.
1 parent f764ddd commit 1fdf860

File tree

12 files changed

+1825
-0
lines changed

12 files changed

+1825
-0
lines changed

aquasec/data_response_policy.go

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
package aquasec
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/aquasecurity/terraform-provider-aquasec/client"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
)
12+
13+
func dataResponsePolicy() *schema.Resource {
14+
return &schema.Resource{
15+
ReadContext: dataResponsePolicyRead,
16+
Schema: map[string]*schema.Schema{
17+
"page": {
18+
Type: schema.TypeInt,
19+
Optional: true,
20+
Default: 1,
21+
},
22+
"page_size": {
23+
Type: schema.TypeInt,
24+
Optional: true,
25+
Default: 10,
26+
},
27+
"scope": {
28+
Type: schema.TypeString,
29+
Optional: true,
30+
},
31+
"title": {
32+
Type: schema.TypeString,
33+
Optional: true,
34+
},
35+
"pagination_data": {
36+
Type: schema.TypeBool,
37+
Optional: true,
38+
Default: false,
39+
},
40+
"data": {
41+
Type: schema.TypeList,
42+
Computed: true,
43+
Elem: &schema.Resource{
44+
Schema: map[string]*schema.Schema{
45+
"id": {
46+
Type: schema.TypeInt,
47+
Computed: true,
48+
},
49+
"title": {
50+
Type: schema.TypeString,
51+
Computed: true,
52+
},
53+
"description": {
54+
Type: schema.TypeString,
55+
Computed: true,
56+
},
57+
"enabled": {
58+
Type: schema.TypeBool,
59+
Computed: true,
60+
},
61+
"application_scopes": {
62+
Type: schema.TypeSet,
63+
Elem: &schema.Schema{Type: schema.TypeString},
64+
Computed: true,
65+
},
66+
"last_updated_by": {
67+
Type: schema.TypeString,
68+
Computed: true,
69+
},
70+
"last_update": {
71+
Type: schema.TypeInt,
72+
Computed: true,
73+
},
74+
"created_at": {
75+
Type: schema.TypeInt,
76+
Computed: true,
77+
},
78+
"trigger": {
79+
Type: schema.TypeList,
80+
Computed: true,
81+
Elem: &schema.Resource{
82+
Schema: map[string]*schema.Schema{
83+
"predefined": {
84+
Type: schema.TypeString,
85+
Computed: true,
86+
},
87+
"input": {
88+
Type: schema.TypeList,
89+
Computed: true,
90+
Elem: &schema.Resource{
91+
Schema: map[string]*schema.Schema{
92+
"name": {
93+
Type: schema.TypeString,
94+
Computed: true,
95+
},
96+
"attributes": {
97+
Type: schema.TypeList,
98+
Computed: true,
99+
Elem: &schema.Resource{
100+
Schema: map[string]*schema.Schema{
101+
"name": {
102+
Type: schema.TypeString,
103+
Computed: true,
104+
},
105+
"value": {
106+
Type: schema.TypeString,
107+
Computed: true,
108+
},
109+
"operation": {
110+
Type: schema.TypeString,
111+
Computed: true,
112+
},
113+
},
114+
},
115+
},
116+
},
117+
},
118+
},
119+
"custom": {
120+
Type: schema.TypeList,
121+
Computed: true,
122+
Elem: &schema.Resource{
123+
Schema: map[string]*schema.Schema{
124+
"rego": {
125+
Type: schema.TypeString,
126+
Computed: true,
127+
},
128+
},
129+
},
130+
},
131+
},
132+
},
133+
},
134+
"outputs": {
135+
Type: schema.TypeList,
136+
Computed: true,
137+
Elem: &schema.Resource{
138+
Schema: map[string]*schema.Schema{
139+
"name": {
140+
Type: schema.TypeString,
141+
Computed: true,
142+
},
143+
"type": {
144+
Type: schema.TypeString,
145+
Computed: true,
146+
},
147+
},
148+
},
149+
},
150+
},
151+
},
152+
},
153+
},
154+
}
155+
}
156+
157+
func dataResponsePolicyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
158+
ac := m.(*client.Client)
159+
policyResp := client.ResponsePolicyResp{
160+
Page: d.Get("page").(int),
161+
PageSize: d.Get("page_size").(int),
162+
Scope: d.Get("scope").(string),
163+
Title: d.Get("title").(string),
164+
}
165+
166+
respPol, err := ac.GetResponsePolicies(policyResp)
167+
if err != nil {
168+
if strings.Contains(fmt.Sprintf("%s", err), "not found") {
169+
d.SetId("")
170+
return nil
171+
}
172+
return diag.FromErr(err)
173+
}
174+
175+
// If API returned no content (204) GetResponsePolicies may return nil
176+
if respPol == nil {
177+
// set empty data and a stable id
178+
if err := d.Set("data", []interface{}{}); err != nil {
179+
return diag.FromErr(err)
180+
}
181+
d.SetId("all")
182+
return nil
183+
}
184+
185+
// respPol.Data already contains ResponsePolicy objects; no need for JSON round-trip.
186+
polList := make([]client.ResponsePolicy, 0, len(respPol.Data))
187+
for _, polItem := range respPol.Data {
188+
polList = append(polList, polItem)
189+
}
190+
policy, _ := flattenResponsePolicies(&polList)
191+
192+
if err := d.Set("data", policy); err != nil {
193+
return diag.FromErr(err)
194+
}
195+
d.SetId("all")
196+
return nil
197+
}
198+
199+
func dataResponsePolicyConfig() *schema.Resource {
200+
return &schema.Resource{
201+
ReadContext: dataResponsePolicyConfigRead,
202+
Schema: map[string]*schema.Schema{
203+
"triggers": {
204+
Type: schema.TypeList,
205+
Computed: true,
206+
Elem: &schema.Resource{
207+
Schema: map[string]*schema.Schema{
208+
"name": {
209+
Type: schema.TypeString,
210+
Computed: true,
211+
},
212+
"type": {
213+
Type: schema.TypeString,
214+
Computed: true,
215+
},
216+
},
217+
},
218+
},
219+
"input": {
220+
Type: schema.TypeList,
221+
Computed: true,
222+
Elem: &schema.Resource{
223+
Schema: map[string]*schema.Schema{
224+
"asset_types": {
225+
Type: schema.TypeList,
226+
Computed: true,
227+
Elem: &schema.Resource{
228+
Schema: map[string]*schema.Schema{
229+
"display_name": {
230+
Type: schema.TypeString,
231+
Computed: true,
232+
},
233+
"field": {
234+
Type: schema.TypeString,
235+
Computed: true,
236+
},
237+
"value": {
238+
Type: schema.TypeString,
239+
Computed: true,
240+
},
241+
},
242+
},
243+
},
244+
"attributes": {
245+
Type: schema.TypeList,
246+
Computed: true,
247+
Elem: &schema.Resource{
248+
Schema: map[string]*schema.Schema{
249+
"name": {
250+
Type: schema.TypeString,
251+
Computed: true,
252+
},
253+
"type": {
254+
Type: schema.TypeString,
255+
Computed: true,
256+
},
257+
"input_type": {
258+
Type: schema.TypeString,
259+
Computed: true,
260+
},
261+
"asset_types": {
262+
Type: schema.TypeList,
263+
Elem: &schema.Schema{Type: schema.TypeString},
264+
Computed: true,
265+
},
266+
"display_name": {
267+
Type: schema.TypeString,
268+
Computed: true,
269+
},
270+
"enabled": {
271+
Type: schema.TypeBool,
272+
Computed: true,
273+
},
274+
"options": {
275+
Type: schema.TypeList,
276+
Computed: true,
277+
Elem: &schema.Resource{
278+
Schema: map[string]*schema.Schema{
279+
"display_name": {
280+
Type: schema.TypeString,
281+
Computed: true,
282+
},
283+
"value": {
284+
Type: schema.TypeString,
285+
Computed: true,
286+
},
287+
},
288+
},
289+
},
290+
},
291+
},
292+
},
293+
"operations": {
294+
Type: schema.TypeList,
295+
Computed: true,
296+
Elem: &schema.Resource{
297+
Schema: map[string]*schema.Schema{
298+
"name": {
299+
Type: schema.TypeString,
300+
Computed: true,
301+
},
302+
"type": {
303+
Type: schema.TypeString,
304+
Computed: true,
305+
},
306+
"display_name": {
307+
Type: schema.TypeString,
308+
Computed: true,
309+
},
310+
"enabled": {
311+
Type: schema.TypeBool,
312+
Computed: true,
313+
},
314+
},
315+
},
316+
},
317+
},
318+
},
319+
},
320+
},
321+
}
322+
}
323+
324+
func dataResponsePolicyConfigRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
325+
ac := m.(*client.Client)
326+
327+
respPolConfig, err := ac.GetResponsePolicyConfig()
328+
if err != nil {
329+
return diag.FromErr(err)
330+
}
331+
if respPolConfig == nil {
332+
// no config returned (204), treat as empty and set ID
333+
d.SetId("config")
334+
return nil
335+
}
336+
if err := d.Set("triggers", flattenResponsePolicyTriggerConfigs(respPolConfig.Triggers)); err != nil {
337+
return diag.FromErr(err)
338+
}
339+
if err := d.Set("input", flattenResponsePolicyInputsConfig(respPolConfig.Input)); err != nil {
340+
return diag.FromErr(err)
341+
}
342+
d.SetId("config")
343+
return nil
344+
}

0 commit comments

Comments
 (0)