Skip to content

Commit 1dbd83a

Browse files
authored
Fix handling encrypted string values for config properties
2 parents d49b98b + c7834b5 commit 1dbd83a

File tree

5 files changed

+121
-20
lines changed

5 files changed

+121
-20
lines changed

CHANGELOG.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## v0.2.2
2+
3+
BUG FIXES:
4+
5+
* resource/config_property: Fixed "Provider produced inconsistent result after apply" error when managing `ENCRYPTEDSTRING` type properties. The provider now correctly handles the API's `HiddenDecryptedPropertyPlaceholder` response and preserves the configured value in state
6+
7+
ENHANCEMENTS:
8+
9+
* tests: Added acceptance test `TestAccConfigPropertyResource_EncryptedString_APIKey` to verify encrypted config property handling
10+
* docs: Removed read-only fields `include_children` and `global` from `dependencytrack_policy` resource example
11+
112
## v0.2.1
213

314
BREAKING CHANGES:
@@ -26,13 +37,6 @@ ENHANCEMENTS:
2637
* resource/user_team_membership: Works with managed, LDAP, and OIDC users
2738
* tests: Added acceptance tests for `dependencytrack_user_team_membership` resource using API key authentication
2839

29-
BUG FIXES:
30-
31-
* build: Fixed artifact path in GitHub workflow to use correct binary name `terraform-provider-dependencytrack`
32-
* build: Updated .gitignore to reflect correct binary name
33-
* module: Renamed Go module from `terraform-provider-dependency-track` to `terraform-provider-dependencytrack` for consistency
34-
* docs: Fixed GitHub repository URLs in CHANGELOG.md to use correct repository name
35-
3640
## v0.1.0
3741

3842
FEATURES:

docs/resources/policy.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ Manages a Dependency-Track policy. Policies are used to automatically audit comp
1414

1515
```terraform
1616
resource "dependencytrack_policy" "example" {
17-
name = "Critical Vulnerabilities"
18-
operator = "ALL"
19-
violation_state = "FAIL"
20-
include_children = true
21-
global = true
17+
name = "Critical Vulnerabilities"
18+
operator = "ALL"
19+
violation_state = "FAIL"
2220
2321
conditions = [
2422
{

examples/resources/dependencytrack_policy/resource.tf

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
resource "dependencytrack_policy" "example" {
2-
name = "Critical Vulnerabilities"
3-
operator = "ALL"
4-
violation_state = "FAIL"
5-
include_children = true
6-
global = true
2+
name = "Critical Vulnerabilities"
3+
operator = "ALL"
4+
violation_state = "FAIL"
75

86
conditions = [
97
{

internal/provider/config_property_resource.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,16 @@ func (r *ConfigPropertyResource) Create(ctx context.Context, req resource.Create
153153

154154
// Set the ID and all attributes in state
155155
data.ID = types.StringValue(fmt.Sprintf("%s/%s", updatedProp.GroupName, updatedProp.Name))
156-
data.Value = types.StringValue(updatedProp.Value)
156+
157+
// For encrypted properties, the API returns a placeholder instead of the actual value
158+
// We need to preserve the configured value in state
159+
if updatedProp.Type == "ENCRYPTEDSTRING" && updatedProp.Value == "HiddenDecryptedPropertyPlaceholder" {
160+
// Keep the configured value that was set in data.Value
161+
// Don't update it with the placeholder from the API
162+
} else {
163+
data.Value = types.StringValue(updatedProp.Value)
164+
}
165+
157166
data.Type = types.StringValue(updatedProp.Type)
158167
data.Description = types.StringValue(updatedProp.Description)
159168

@@ -181,7 +190,15 @@ func (r *ConfigPropertyResource) Read(ctx context.Context, req resource.ReadRequ
181190
return
182191
}
183192

184-
data.Value = types.StringValue(prop.Value)
193+
// For encrypted properties, the API returns a placeholder instead of the actual value
194+
// We need to preserve the existing state value
195+
if prop.Type == "ENCRYPTEDSTRING" && prop.Value == "HiddenDecryptedPropertyPlaceholder" {
196+
// Keep the existing value from state (data.Value)
197+
// Don't update it with the placeholder from the API
198+
} else {
199+
data.Value = types.StringValue(prop.Value)
200+
}
201+
185202
data.Type = types.StringValue(prop.Type)
186203
data.Description = types.StringValue(prop.Description)
187204

@@ -217,7 +234,15 @@ func (r *ConfigPropertyResource) Update(ctx context.Context, req resource.Update
217234
return
218235
}
219236

220-
data.Value = types.StringValue(updatedProp.Value)
237+
// For encrypted properties, the API returns a placeholder instead of the actual value
238+
// We need to preserve the configured value in state
239+
if updatedProp.Type == "ENCRYPTEDSTRING" && updatedProp.Value == "HiddenDecryptedPropertyPlaceholder" {
240+
// Keep the configured value that was set in data.Value
241+
// Don't update it with the placeholder from the API
242+
} else {
243+
data.Value = types.StringValue(updatedProp.Value)
244+
}
245+
221246
data.Type = types.StringValue(updatedProp.Type)
222247
data.Description = types.StringValue(updatedProp.Description)
223248

internal/provider/config_property_resource_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,82 @@ func TestAccConfigPropertyResource_APIKey(t *testing.T) {
5959
})
6060
}
6161

62+
// TestAccConfigPropertyResource_EncryptedString_APIKey tests the config_property resource with an encrypted string property.
63+
// This test ensures that encrypted properties (ENCRYPTEDSTRING type) are handled correctly,
64+
// as the API returns "HiddenDecryptedPropertyPlaceholder" instead of the actual value.
65+
func TestAccConfigPropertyResource_EncryptedString_APIKey(t *testing.T) {
66+
resource.Test(t, resource.TestCase{
67+
PreCheck: func() { testAccPreCheckAPIKey(t) },
68+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
69+
Steps: []resource.TestStep{
70+
// Adopt and Update testing with encrypted property
71+
{
72+
Config: testAccConfigPropertyResourceConfigWithAPIKey("email", "smtp.password", "initial-password-123"),
73+
ConfigStateChecks: []statecheck.StateCheck{
74+
statecheck.ExpectKnownValue(
75+
"dependencytrack_config_property.test",
76+
tfjsonpath.New("group_name"),
77+
knownvalue.StringExact("email"),
78+
),
79+
statecheck.ExpectKnownValue(
80+
"dependencytrack_config_property.test",
81+
tfjsonpath.New("name"),
82+
knownvalue.StringExact("smtp.password"),
83+
),
84+
statecheck.ExpectKnownValue(
85+
"dependencytrack_config_property.test",
86+
tfjsonpath.New("value"),
87+
knownvalue.StringExact("initial-password-123"),
88+
),
89+
statecheck.ExpectKnownValue(
90+
"dependencytrack_config_property.test",
91+
tfjsonpath.New("type"),
92+
knownvalue.StringExact("ENCRYPTEDSTRING"),
93+
),
94+
},
95+
},
96+
// ImportState testing
97+
// Note: We cannot verify the value field for encrypted properties because
98+
// the API returns "HiddenDecryptedPropertyPlaceholder" instead of the actual value
99+
{
100+
ResourceName: "dependencytrack_config_property.test",
101+
ImportState: true,
102+
ImportStateVerify: true,
103+
ImportStateVerifyIgnore: []string{"value"},
104+
},
105+
// Update testing - this is critical for encrypted properties
106+
// Previously this would fail with "Provider produced inconsistent result after apply"
107+
{
108+
Config: testAccConfigPropertyResourceConfigWithAPIKey("email", "smtp.password", "updated-password-456"),
109+
ConfigStateChecks: []statecheck.StateCheck{
110+
statecheck.ExpectKnownValue(
111+
"dependencytrack_config_property.test",
112+
tfjsonpath.New("value"),
113+
knownvalue.StringExact("updated-password-456"),
114+
),
115+
statecheck.ExpectKnownValue(
116+
"dependencytrack_config_property.test",
117+
tfjsonpath.New("type"),
118+
knownvalue.StringExact("ENCRYPTEDSTRING"),
119+
),
120+
},
121+
},
122+
// Another update to ensure consistency is maintained
123+
{
124+
Config: testAccConfigPropertyResourceConfigWithAPIKey("email", "smtp.password", "final-password-789"),
125+
ConfigStateChecks: []statecheck.StateCheck{
126+
statecheck.ExpectKnownValue(
127+
"dependencytrack_config_property.test",
128+
tfjsonpath.New("value"),
129+
knownvalue.StringExact("final-password-789"),
130+
),
131+
},
132+
},
133+
// Delete testing automatically occurs in TestCase
134+
},
135+
})
136+
}
137+
62138
func testAccConfigPropertyResourceConfigWithAPIKey(groupName, name, value string) string {
63139
return testAccProviderConfigWithAPIKey() + fmt.Sprintf(`
64140
resource "dependencytrack_config_property" "test" {

0 commit comments

Comments
 (0)