Skip to content

Commit cb7a524

Browse files
committed
resources: use sets for properties where order has no significance
1 parent a85a0e5 commit cb7a524

11 files changed

+89
-50
lines changed

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
run: go mod download
2424

2525
- name: Run tests
26-
run: go test -v -cover ./internal/provider/...
26+
run: make test
2727

2828
- name: Run acceptance tests
2929
run: |

Makefile

+6
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,10 @@ build:
1212

1313
.PHONY: docs
1414
docs:
15+
@echo "@==> $@"
1516
go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@latest generate --provider-dir . -provider-name pomerium
17+
18+
.PHONY: test
19+
test:
20+
@echo "@==> $@"
21+
@go test ./internal/provider/...

example/main.tf

+19-1
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,30 @@ resource "pomerium_policy" "test_policy" {
7676
})
7777
}
7878

79+
resource "pomerium_policy" "test_policy_group" {
80+
name = "group test policy"
81+
namespace_id = pomerium_namespace.test_namespace.id
82+
ppl = yamlencode({
83+
allow = {
84+
and = [
85+
{
86+
groups = {
87+
has = "gid-123456"
88+
}
89+
}
90+
]
91+
}
92+
})
93+
}
7994
resource "pomerium_route" "test_route" {
8095
name = "test-route"
8196
namespace_id = pomerium_namespace.test_namespace.id
8297
from = "https://verify-tf.localhost.pomerium.io"
8398
to = ["https://verify.pomerium.com"]
84-
policies = [pomerium_policy.test_policy.id]
99+
policies = [
100+
pomerium_policy.test_policy_group.id,
101+
pomerium_policy.test_policy.id,
102+
]
85103
}
86104

87105
resource "pomerium_key_pair" "test_key_pair" {

internal/provider/convert.go

+32-10
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,18 @@ import (
1717
"google.golang.org/protobuf/types/known/structpb"
1818
)
1919

20-
func FromStringSlice(slice []string) types.List {
20+
func FromStringSliceToSet(slice []string) types.Set {
21+
if slice == nil {
22+
return types.SetNull(types.StringType)
23+
}
24+
fields := make([]attr.Value, 0)
25+
for _, v := range slice {
26+
fields = append(fields, types.StringValue(v))
27+
}
28+
return types.SetValueMust(types.StringType, fields)
29+
}
30+
31+
func FromStringSliceToList(slice []string) types.List {
2132
if slice == nil {
2233
return types.ListNull(types.StringType)
2334
}
@@ -28,12 +39,12 @@ func FromStringSlice(slice []string) types.List {
2839
return types.ListValueMust(types.StringType, fields)
2940
}
3041

31-
// FromStringList converts a Settings_StringList to a types.List
32-
func FromStringList(sl *pb.Settings_StringList) types.List {
42+
// FromStringListToSet converts a Settings_StringList to a types.List
43+
func FromStringListToSet(sl *pb.Settings_StringList) types.Set {
3344
if sl == nil {
34-
return types.ListNull(types.StringType)
45+
return types.SetNull(types.StringType)
3546
}
36-
return FromStringSlice(sl.Values)
47+
return FromStringSliceToSet(sl.Values)
3748
}
3849

3950
// FromStringMap converts a map[string]string to a types.Map
@@ -49,14 +60,14 @@ func FromStringMap(m map[string]string) types.Map {
4960
}
5061

5162
// ToStringList converts a types.List to Settings_StringList and handles diagnostics internally
52-
func ToStringList(ctx context.Context, dst **pb.Settings_StringList, list types.List, diagnostics *diag.Diagnostics) {
53-
if list.IsNull() {
63+
func ToStringListFromSet(ctx context.Context, dst **pb.Settings_StringList, set types.Set, diagnostics *diag.Diagnostics) {
64+
if set.IsNull() {
5465
*dst = nil
5566
return
5667
}
5768

5869
var values []string
59-
diagnostics.Append(list.ElementsAs(ctx, &values, false)...)
70+
diagnostics.Append(set.ElementsAs(ctx, &values, false)...)
6071
if !diagnostics.HasError() {
6172
*dst = &pb.Settings_StringList{Values: values}
6273
}
@@ -76,8 +87,19 @@ func ToStringMap(ctx context.Context, dst *map[string]string, m types.Map, diagn
7687
}
7788
}
7889

79-
// ToStringSlice converts a types.List to string slice and handles diagnostics internally
80-
func ToStringSlice(ctx context.Context, dst *[]string, list types.List, diagnostics *diag.Diagnostics) {
90+
func ToStringSliceFromSet(ctx context.Context, dst *[]string, set types.Set, diagnostics *diag.Diagnostics) {
91+
*dst = make([]string, 0)
92+
if !set.IsNull() {
93+
var values []string
94+
diagnostics.Append(set.ElementsAs(ctx, &values, false)...)
95+
if !diagnostics.HasError() {
96+
*dst = values
97+
}
98+
}
99+
}
100+
101+
// ToStringSliceFromList converts a types.List to string slice and handles diagnostics internally
102+
func ToStringSliceFromList(ctx context.Context, dst *[]string, list types.List, diagnostics *diag.Diagnostics) {
81103
*dst = make([]string, 0)
82104
if !list.IsNull() {
83105
var values []string

internal/provider/convert_test.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func TestFromStringSlice(t *testing.T) {
4949

5050
for _, tt := range tests {
5151
t.Run(tt.name, func(t *testing.T) {
52-
result := provider.FromStringSlice(tt.input)
52+
result := provider.FromStringSliceToList(tt.input)
5353
assert.Equal(t, tt.expected, result)
5454
})
5555
}
@@ -136,32 +136,32 @@ func TestToDuration(t *testing.T) {
136136
}
137137
}
138138

139-
func TestToStringList(t *testing.T) {
139+
func TestToStringListFromSet(t *testing.T) {
140140
ctx := context.Background()
141141
tests := []struct {
142142
name string
143-
input types.List
143+
input types.Set
144144
expectError bool
145145
validate func(*testing.T, *pb.Settings_StringList)
146146
}{
147147
{
148148
name: "null list",
149-
input: types.ListNull(types.StringType),
149+
input: types.SetNull(types.StringType),
150150
validate: func(t *testing.T, s *pb.Settings_StringList) {
151151
assert.Nil(t, s)
152152
},
153153
},
154154
{
155155
name: "empty list",
156-
input: types.ListValueMust(types.StringType, []attr.Value{}),
156+
input: types.SetValueMust(types.StringType, []attr.Value{}),
157157
validate: func(t *testing.T, s *pb.Settings_StringList) {
158158
require.NotNil(t, s)
159159
assert.Empty(t, s.Values)
160160
},
161161
},
162162
{
163163
name: "valid list",
164-
input: types.ListValueMust(types.StringType, []attr.Value{
164+
input: types.SetValueMust(types.StringType, []attr.Value{
165165
types.StringValue("value1"),
166166
types.StringValue("value2"),
167167
}),
@@ -176,7 +176,7 @@ func TestToStringList(t *testing.T) {
176176
t.Run(tt.name, func(t *testing.T) {
177177
var result *pb.Settings_StringList
178178
diagnostics := diag.Diagnostics{}
179-
provider.ToStringList(ctx, &result, tt.input, &diagnostics)
179+
provider.ToStringListFromSet(ctx, &result, tt.input, &diagnostics)
180180

181181
if tt.expectError {
182182
assert.True(t, diagnostics.HasError())

internal/provider/policy_model.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func ConvertPolicyFromPB(dst *PolicyResourceModel, src *pb.Policy) diag.Diagnost
4949
dst.Enforced = types.BoolValue(src.Enforced)
5050
dst.Explanation = types.StringValue(src.Explanation)
5151
dst.Remediation = types.StringValue(src.Remediation)
52-
dst.Rego = FromStringSlice(src.Rego)
52+
dst.Rego = FromStringSliceToList(src.Rego)
5353
ppl, err := PolicyLanguageType{}.Parse(types.StringValue(src.Ppl))
5454
if err != nil {
5555
diagnostics.AddError("converting PPL", err.Error())

internal/provider/route.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func (r *RouteResource) Schema(_ context.Context, _ resource.SchemaRequest, resp
5959
Description: "From URL.",
6060
Required: true,
6161
},
62-
"to": schema.ListAttribute{
62+
"to": schema.SetAttribute{
6363
ElementType: types.StringType,
6464
Description: "To URLs.",
6565
Required: true,
@@ -68,7 +68,7 @@ func (r *RouteResource) Schema(_ context.Context, _ resource.SchemaRequest, resp
6868
Description: "ID of the namespace the route belongs to.",
6969
Required: true,
7070
},
71-
"policies": schema.ListAttribute{
71+
"policies": schema.SetAttribute{
7272
ElementType: types.StringType,
7373
Description: "List of policy IDs associated with the route.",
7474
Optional: true,
@@ -163,7 +163,7 @@ func (r *RouteResource) Schema(_ context.Context, _ resource.SchemaRequest, resp
163163
Description: "Set request headers.",
164164
Optional: true,
165165
},
166-
"remove_request_headers": schema.ListAttribute{
166+
"remove_request_headers": schema.SetAttribute{
167167
ElementType: types.StringType,
168168
Description: "Remove request headers.",
169169
Optional: true,

internal/provider/route_model.go

+7-14
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55

66
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
7-
"github.com/hashicorp/terraform-plugin-framework/attr"
87
"github.com/hashicorp/terraform-plugin-framework/diag"
98
"github.com/hashicorp/terraform-plugin-framework/types"
109
"github.com/pomerium/enterprise-client-go/pb"
@@ -15,9 +14,9 @@ type RouteModel struct {
1514
ID types.String `tfsdk:"id"`
1615
Name types.String `tfsdk:"name"`
1716
From types.String `tfsdk:"from"`
18-
To types.List `tfsdk:"to"`
17+
To types.Set `tfsdk:"to"`
1918
NamespaceID types.String `tfsdk:"namespace_id"`
20-
Policies types.List `tfsdk:"policies"`
19+
Policies types.Set `tfsdk:"policies"`
2120
StatName types.String `tfsdk:"stat_name"`
2221
Prefix types.String `tfsdk:"prefix"`
2322
Path types.String `tfsdk:"path"`
@@ -39,7 +38,7 @@ type RouteModel struct {
3938
TLSDownstreamServerName types.String `tfsdk:"tls_downstream_server_name"`
4039
TLSUpstreamAllowRenegotiation types.Bool `tfsdk:"tls_upstream_allow_renegotiation"`
4140
SetRequestHeaders types.Map `tfsdk:"set_request_headers"`
42-
RemoveRequestHeaders types.List `tfsdk:"remove_request_headers"`
41+
RemoveRequestHeaders types.Set `tfsdk:"remove_request_headers"`
4342
SetResponseHeaders types.Map `tfsdk:"set_response_headers"`
4443
PreserveHostHeader types.Bool `tfsdk:"preserve_host_header"`
4544
PassIdentityHeaders types.Bool `tfsdk:"pass_identity_headers"`
@@ -81,7 +80,7 @@ func ConvertRouteToPB(
8180
pbRoute.TlsDownstreamServerName = src.TLSDownstreamServerName.ValueStringPointer()
8281
pbRoute.TlsUpstreamAllowRenegotiation = src.TLSUpstreamAllowRenegotiation.ValueBoolPointer()
8382
ToStringMap(ctx, &pbRoute.SetRequestHeaders, src.SetRequestHeaders, &diagnostics)
84-
ToStringSlice(ctx, &pbRoute.RemoveRequestHeaders, src.RemoveRequestHeaders, &diagnostics)
83+
ToStringSliceFromSet(ctx, &pbRoute.RemoveRequestHeaders, src.RemoveRequestHeaders, &diagnostics)
8584
ToStringMap(ctx, &pbRoute.SetResponseHeaders, src.SetResponseHeaders, &diagnostics)
8685
pbRoute.PreserveHostHeader = src.PreserveHostHeader.ValueBoolPointer()
8786
pbRoute.PassIdentityHeaders = src.PassIdentityHeaders.ValueBoolPointer()
@@ -110,14 +109,8 @@ func ConvertRouteFromPB(
110109
dst.Name = types.StringValue(src.Name)
111110
dst.From = types.StringValue(src.From)
112111
dst.NamespaceID = types.StringValue(src.NamespaceId)
113-
114-
toList := make([]attr.Value, len(src.To))
115-
for i, v := range src.To {
116-
toList[i] = types.StringValue(v)
117-
}
118-
dst.To = types.ListValueMust(types.StringType, toList)
119-
120-
dst.Policies = FromStringSlice(StringSliceExclude(src.PolicyIds, src.EnforcedPolicyIds))
112+
dst.To = FromStringSliceToSet(src.To)
113+
dst.Policies = FromStringSliceToSet(StringSliceExclude(src.PolicyIds, src.EnforcedPolicyIds))
121114
dst.StatName = types.StringValue(src.StatName)
122115
dst.Prefix = types.StringPointerValue(src.Prefix)
123116
dst.Path = types.StringPointerValue(src.Path)
@@ -139,7 +132,7 @@ func ConvertRouteFromPB(
139132
dst.TLSDownstreamServerName = types.StringPointerValue(src.TlsDownstreamServerName)
140133
dst.TLSUpstreamAllowRenegotiation = types.BoolPointerValue(src.TlsUpstreamAllowRenegotiation)
141134
dst.SetRequestHeaders = FromStringMap(src.SetRequestHeaders)
142-
dst.RemoveRequestHeaders = FromStringSlice(src.RemoveRequestHeaders)
135+
dst.RemoveRequestHeaders = FromStringSliceToSet(src.RemoveRequestHeaders)
143136
dst.SetResponseHeaders = FromStringMap(src.SetResponseHeaders)
144137
dst.PreserveHostHeader = types.BoolPointerValue(src.PreserveHostHeader)
145138
dst.PassIdentityHeaders = types.BoolPointerValue(src.PassIdentityHeaders)

internal/provider/route_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestConvertRoute(t *testing.T) {
3737
// Test conversion from model to pb
3838
plan := provider.RouteResourceModel{
3939
From: types.StringValue("from"),
40-
To: types.ListValueMust(types.StringType, []attr.Value{types.StringValue("to")}),
40+
To: types.SetValueMust(types.StringType, []attr.Value{types.StringValue("to")}),
4141
Name: types.StringValue("route-name"),
4242
ID: types.StringValue("route-id"),
4343
}

internal/provider/settings_model.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import (
1010
)
1111

1212
type SettingsModel struct {
13-
AccessLogFields types.List `tfsdk:"access_log_fields"`
13+
AccessLogFields types.Set `tfsdk:"access_log_fields"`
1414
Address types.String `tfsdk:"address"`
1515
AuthenticateCallbackPath types.String `tfsdk:"authenticate_callback_path"`
1616
AuthenticateServiceURL types.String `tfsdk:"authenticate_service_url"`
17-
AuthorizeLogFields types.List `tfsdk:"authorize_log_fields"`
17+
AuthorizeLogFields types.Set `tfsdk:"authorize_log_fields"`
1818
AuthorizeServiceURL types.String `tfsdk:"authorize_service_url"`
1919
Autocert types.Bool `tfsdk:"autocert"`
2020
AutocertDir types.String `tfsdk:"autocert_dir"`
@@ -73,7 +73,7 @@ type SettingsModel struct {
7373
PrimaryColor types.String `tfsdk:"primary_color"`
7474
ProxyLogLevel types.String `tfsdk:"proxy_log_level"`
7575
RequestParams types.Map `tfsdk:"request_params"`
76-
Scopes types.List `tfsdk:"scopes"`
76+
Scopes types.Set `tfsdk:"scopes"`
7777
SecondaryColor types.String `tfsdk:"secondary_color"`
7878
SetResponseHeaders types.Map `tfsdk:"set_response_headers"`
7979
SkipXFFAppend types.Bool `tfsdk:"skip_xff_append"`
@@ -89,11 +89,11 @@ func ConvertSettingsToPB(
8989
var diagnostics diag.Diagnostics
9090
pbSettings := &pb.Settings{}
9191

92-
ToStringList(ctx, &pbSettings.AccessLogFields, src.AccessLogFields, &diagnostics)
92+
ToStringListFromSet(ctx, &pbSettings.AccessLogFields, src.AccessLogFields, &diagnostics)
9393
pbSettings.Address = src.Address.ValueStringPointer()
9494
pbSettings.AuthenticateCallbackPath = src.AuthenticateCallbackPath.ValueStringPointer()
9595
pbSettings.AuthenticateServiceUrl = src.AuthenticateServiceURL.ValueStringPointer()
96-
ToStringList(ctx, &pbSettings.AuthorizeLogFields, src.AuthorizeLogFields, &diagnostics)
96+
ToStringListFromSet(ctx, &pbSettings.AuthorizeLogFields, src.AuthorizeLogFields, &diagnostics)
9797
pbSettings.AuthorizeServiceUrl = src.AuthorizeServiceURL.ValueStringPointer()
9898
pbSettings.Autocert = src.Autocert.ValueBoolPointer()
9999
pbSettings.AutocertDir = src.AutocertDir.ValueStringPointer()
@@ -144,7 +144,7 @@ func ConvertSettingsToPB(
144144
pbSettings.PrimaryColor = src.PrimaryColor.ValueStringPointer()
145145
pbSettings.ProxyLogLevel = src.ProxyLogLevel.ValueStringPointer()
146146
ToStringMap(ctx, &pbSettings.RequestParams, src.RequestParams, &diagnostics)
147-
ToStringSlice(ctx, &pbSettings.Scopes, src.Scopes, &diagnostics)
147+
ToStringSliceFromSet(ctx, &pbSettings.Scopes, src.Scopes, &diagnostics)
148148
pbSettings.SecondaryColor = src.SecondaryColor.ValueStringPointer()
149149
ToStringMap(ctx, &pbSettings.SetResponseHeaders, src.SetResponseHeaders, &diagnostics)
150150
pbSettings.SkipXffAppend = src.SkipXFFAppend.ValueBoolPointer()
@@ -161,11 +161,11 @@ func ConvertSettingsFromPB(
161161
) diag.Diagnostics {
162162
var diagnostics diag.Diagnostics
163163

164-
dst.AccessLogFields = FromStringList(src.AccessLogFields)
164+
dst.AccessLogFields = FromStringListToSet(src.AccessLogFields)
165165
dst.Address = types.StringPointerValue(src.Address)
166166
dst.AuthenticateCallbackPath = types.StringPointerValue(src.AuthenticateCallbackPath)
167167
dst.AuthenticateServiceURL = types.StringPointerValue(src.AuthenticateServiceUrl)
168-
dst.AuthorizeLogFields = FromStringList(src.AuthorizeLogFields)
168+
dst.AuthorizeLogFields = FromStringListToSet(src.AuthorizeLogFields)
169169
dst.AuthorizeServiceURL = types.StringPointerValue(src.AuthorizeServiceUrl)
170170
dst.Autocert = types.BoolPointerValue(src.Autocert)
171171
dst.AutocertDir = types.StringPointerValue(src.AutocertDir)
@@ -216,7 +216,7 @@ func ConvertSettingsFromPB(
216216
dst.PrimaryColor = types.StringPointerValue(src.PrimaryColor)
217217
dst.ProxyLogLevel = types.StringPointerValue(src.ProxyLogLevel)
218218
dst.RequestParams = FromStringMap(src.RequestParams)
219-
dst.Scopes = FromStringSlice(src.Scopes)
219+
dst.Scopes = FromStringSliceToSet(src.Scopes)
220220
dst.SecondaryColor = types.StringPointerValue(src.SecondaryColor)
221221
dst.SetResponseHeaders = FromStringMap(src.SetResponseHeaders)
222222
dst.SkipXFFAppend = types.BoolPointerValue(src.SkipXffAppend)

internal/provider/settings_schema.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ var SettingsResourceSchema = schema.Schema{
139139
Optional: true,
140140
Description: "IDP provider URL",
141141
},
142-
"scopes": schema.ListAttribute{
142+
"scopes": schema.SetAttribute{
143143
Optional: true,
144144
ElementType: types.StringType,
145145
Description: "Scopes",
@@ -434,12 +434,12 @@ var SettingsResourceSchema = schema.Schema{
434434
Description: "Identity provider refresh timeout",
435435
CustomType: timetypes.GoDurationType{},
436436
},
437-
"access_log_fields": schema.ListAttribute{
437+
"access_log_fields": schema.SetAttribute{
438438
Optional: true,
439439
ElementType: types.StringType,
440440
Description: "Access log fields",
441441
},
442-
"authorize_log_fields": schema.ListAttribute{
442+
"authorize_log_fields": schema.SetAttribute{
443443
Optional: true,
444444
ElementType: types.StringType,
445445
Description: "Authorize log fields",

0 commit comments

Comments
 (0)