// Copyright IBM Corp. 2014, 2026 // SPDX-License-Identifier: BUSL-1.1 package json import ( "encoding/json" "sort" "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/configs/configschema" "github.com/hashicorp/terraform/internal/genconfig" "github.com/hashicorp/terraform/internal/lang/format" "github.com/hashicorp/terraform/internal/lang/marks" "github.com/zclconf/go-cty/cty" ctyjson "github.com/zclconf/go-cty/cty/json" ) type QueryStart struct { Address string `json:"address"` ResourceType string `json:"resource_type"` InputConfig map[string]json.RawMessage `json:"input_config,omitempty"` SensitiveAttributePaths []string `json:"sensitive_attribute_paths,omitempty"` } type QueryResult struct { Address string `json:"address"` DisplayName string `json:"display_name"` Identity map[string]json.RawMessage `json:"identity"` IdentityVersion int64 `json:"identity_version"` ResourceType string `json:"resource_type"` ResourceObject map[string]json.RawMessage `json:"resource_object,omitempty"` Config string `json:"config,omitempty"` ImportConfig string `json:"import_config,omitempty"` } type QueryComplete struct { Address string `json:"address"` ResourceType string `json:"resource_type"` Total int `json:"total"` } func NewQueryStart(addr addrs.AbsResourceInstance, inputConfig cty.Value, configSchema *configschema.Block) QueryStart { unmarkVal, valPaths := inputConfig.UnmarkDeepWithPaths() // We only want a unique set of attribute paths. A path // can either be defined as sensitive by the provider or // marked by configuration. uniquePaths := make(map[string]struct{}) // Search for any marked sensitive paths, irrespective // of the schema for _, pvm := range valPaths { if _, ok := pvm.Marks[marks.Sensitive]; ok { uniquePaths[format.CtyPath(pvm.Path)] = struct{}{} } } // Now let's loop through the resource schema defined by // the provider schemaPaths := configSchema.SensitivePaths(inputConfig, nil) for _, path := range schemaPaths { uniquePaths[format.CtyPath(path)] = struct{}{} } sensitiveAttributePaths := make([]string, 0, len(uniquePaths)) for p := range uniquePaths { sensitiveAttributePaths = append(sensitiveAttributePaths, p) } sort.Strings(sensitiveAttributePaths) return QueryStart{ Address: addr.String(), ResourceType: addr.Resource.Resource.Type, InputConfig: marshalValues(unmarkVal), SensitiveAttributePaths: sensitiveAttributePaths, } } func NewQueryResult(listAddr addrs.AbsResourceInstance, value cty.Value, identityVersion int64, generated *genconfig.ResourceImport) QueryResult { result := QueryResult{ Address: listAddr.String(), DisplayName: value.GetAttr("display_name").AsString(), Identity: marshalValues(value.GetAttr("identity")), IdentityVersion: identityVersion, ResourceType: listAddr.Resource.Resource.Type, ResourceObject: marshalValues(value.GetAttr("state")), } if generated != nil { result.Config = generated.Resource.String() result.ImportConfig = string(generated.ImportBody) } return result } func NewQueryComplete(addr addrs.AbsResourceInstance, total int) QueryComplete { return QueryComplete{ Address: addr.String(), ResourceType: addr.Resource.Resource.Type, Total: total, } } func marshalValues(value cty.Value) map[string]json.RawMessage { if value == cty.NilVal || value.IsNull() { return nil } ret := make(map[string]json.RawMessage) it := value.ElementIterator() for it.Next() { k, v := it.Element() vJSON, _ := ctyjson.Marshal(v, v.Type()) ret[k.AsString()] = json.RawMessage(vJSON) } return ret }