Skip to content

Commit 59c0dba

Browse files
Secret Manager: Fix panic in SecretVersion flatten when AccessSecretVersion API call fails (#15082)
1 parent 0cce7b6 commit 59c0dba

File tree

1 file changed

+63
-25
lines changed

1 file changed

+63
-25
lines changed

mmv1/templates/terraform/custom_flatten/secret_version_access.go.tmpl

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,50 +11,88 @@
1111
limitations under the License.
1212
*/ -}}
1313
func flatten{{$.GetPrefix}}{{$.TitlelizeProperty}}(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
14-
transformed := make(map[string]interface{})
15-
// write-only attributes are null on reads, secret_data_wo_version is used instead to return empty transformed that resolves a diff.
14+
// helper: always return []interface{}{map} with the safest value
15+
safeTransformed := func(val interface{}) []interface{} {
16+
m := make(map[string]interface{})
17+
if val != nil {
18+
m["secret_data"] = val
19+
}
20+
return []interface{}{m}
21+
}
22+
23+
// write-only: during read, resolve diff with empty object
1624
if _, ok := d.GetOkExists("secret_data_wo_version"); ok {
17-
return []interface{}{transformed}
25+
return safeTransformed(nil)
1826
}
1927

20-
// if this secret version is disabled, the api will return an error, as the value cannot be accessed, return what we have
21-
if d.Get("enabled").(bool) == false {
22-
transformed["secret_data"] = d.Get("secret_data")
23-
return []interface{}{transformed}
28+
// if "enabled" does not exist or is false, preserve what we already have in the state
29+
enabledVal, exists := d.GetOk("enabled")
30+
if !exists {
31+
return safeTransformed(d.Get("secret_data"))
32+
}
33+
if enabled, _ := enabledVal.(bool); !enabled {
34+
return safeTransformed(d.Get("secret_data"))
2435
}
2536

37+
// build access URL; if it fails, preserve state
2638
url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}SecretManagerBasePath{{"}}"}}{{"{{"}}name{{"}}"}}:access")
2739
if err != nil {
28-
return err
40+
log.Printf("[ERROR] Failed to build secret access URL: %v", err)
41+
return safeTransformed(d.Get("secret_data"))
2942
}
3043

31-
parts := strings.Split(d.Get("name").(string), "/")
44+
// safely extract project
45+
nameStr, _ := d.Get("name").(string)
46+
parts := strings.Split(nameStr, "/")
47+
if len(parts) < 2 {
48+
log.Printf("[WARN] Unexpected secret name format %q, preserving state", nameStr)
49+
return safeTransformed(d.Get("secret_data"))
50+
}
3251
project := parts[1]
3352

34-
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
53+
ua, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
3554
if err != nil {
36-
return err
55+
log.Printf("[ERROR] Failed to generate user agent string: %v", err)
56+
return safeTransformed(d.Get("secret_data"))
3757
}
3858

3959
accessRes, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
40-
Config: config,
41-
Method: "GET",
42-
Project: project,
43-
RawURL: url,
44-
UserAgent: userAgent,
60+
Config: config,
61+
Method: "GET",
62+
Project: project,
63+
RawURL: url,
64+
UserAgent: ua,
4565
})
4666
if err != nil {
47-
return err
67+
// per review: add explicit log to diagnose underlying url/transport error
68+
log.Printf("[ERROR] Failed to access secret version at %q: %v", url, err)
69+
return safeTransformed(d.Get("secret_data"))
4870
}
4971

50-
if d.Get("is_secret_data_base64").(bool) {
51-
transformed["secret_data"] = accessRes["payload"].(map[string]interface{})["data"].(string)
52-
} else {
53-
data, err := base64.StdEncoding.DecodeString(accessRes["payload"].(map[string]interface{})["data"].(string))
54-
if err != nil {
55-
return err
72+
// safely fetch payload.data
73+
var dataB64 string
74+
if payloadAny, ok := accessRes["payload"]; ok {
75+
if payloadMap, ok := payloadAny.(map[string]interface{}); ok {
76+
if s, ok := payloadMap["data"].(string); ok {
77+
dataB64 = s
78+
}
5679
}
57-
transformed["secret_data"] = string(data)
5880
}
59-
return []interface{}{transformed}
81+
if dataB64 == "" {
82+
log.Printf("[WARN] No payload.data found in secret access response for %q, preserving state", nameStr)
83+
return safeTransformed(d.Get("secret_data"))
84+
}
85+
86+
// decide whether to keep pure base64 or decode it
87+
isB64, _ := d.Get("is_secret_data_base64").(bool)
88+
if isB64 {
89+
return safeTransformed(dataB64)
90+
}
91+
92+
decoded, decErr := base64.StdEncoding.DecodeString(dataB64)
93+
if decErr != nil {
94+
log.Printf("[ERROR] Failed to decode base64 secret payload for %q: %v", nameStr, decErr)
95+
return safeTransformed(d.Get("secret_data"))
96+
}
97+
return safeTransformed(string(decoded))
6098
}

0 commit comments

Comments
 (0)