github.com/aquasecurity/trivy-iac@v0.8.1-0.20240127024015-3d8e412cf0ab/pkg/scanners/cloudformation/parser/parameter.go (about)

     1  package parser
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/liamg/jfather"
    11  	"gopkg.in/yaml.v3"
    12  
    13  	"github.com/aquasecurity/trivy-iac/pkg/scanners/cloudformation/cftypes"
    14  )
    15  
    16  type Parameter struct {
    17  	inner parameterInner
    18  }
    19  
    20  type parameterInner struct {
    21  	Type    string      `yaml:"Type"`
    22  	Default interface{} `yaml:"Default"`
    23  }
    24  
    25  func (p *Parameter) UnmarshalYAML(node *yaml.Node) error {
    26  	return node.Decode(&p.inner)
    27  }
    28  
    29  func (p *Parameter) UnmarshalJSONWithMetadata(node jfather.Node) error {
    30  	return node.Decode(&p.inner)
    31  }
    32  
    33  func (p *Parameter) Type() cftypes.CfType {
    34  	switch p.inner.Type {
    35  	case "Boolean":
    36  		return cftypes.Bool
    37  	case "String":
    38  		return cftypes.String
    39  	case "Integer":
    40  		return cftypes.Int
    41  	default:
    42  		return cftypes.String
    43  	}
    44  }
    45  
    46  func (p *Parameter) Default() interface{} {
    47  	return p.inner.Default
    48  }
    49  
    50  func (p *Parameter) UpdateDefault(inVal interface{}) {
    51  	passedVal := inVal.(string)
    52  
    53  	switch p.inner.Type {
    54  	case "Boolean":
    55  		p.inner.Default, _ = strconv.ParseBool(passedVal)
    56  	case "String":
    57  		p.inner.Default = passedVal
    58  	case "Integer":
    59  		p.inner.Default, _ = strconv.Atoi(passedVal)
    60  	default:
    61  		p.inner.Default = passedVal
    62  	}
    63  }
    64  
    65  type Parameters map[string]any
    66  
    67  func (p *Parameters) Merge(other Parameters) {
    68  	for k, v := range other {
    69  		(*p)[k] = v
    70  	}
    71  }
    72  
    73  func (p *Parameters) UnmarshalJSON(data []byte) error {
    74  	(*p) = make(Parameters)
    75  
    76  	if len(data) == 0 {
    77  		return nil
    78  	}
    79  
    80  	switch {
    81  	case data[0] == '{' && data[len(data)-1] == '}': // object
    82  		// CodePipeline like format
    83  		var params struct {
    84  			Params map[string]any `json:"Parameters"`
    85  		}
    86  
    87  		if err := json.Unmarshal(data, &params); err != nil {
    88  			return err
    89  		}
    90  
    91  		(*p) = params.Params
    92  	case data[0] == '[' && data[len(data)-1] == ']': // array
    93  		{
    94  			// Original format
    95  			var params []string
    96  
    97  			if err := json.Unmarshal(data, &params); err == nil {
    98  				for _, param := range params {
    99  					parts := strings.Split(param, "=")
   100  					if len(parts) != 2 {
   101  						return fmt.Errorf("invalid key-value parameter: %q", param)
   102  					}
   103  					(*p)[parts[0]] = parts[1]
   104  				}
   105  				return nil
   106  			}
   107  
   108  			// CloudFormation like format
   109  			var cfparams []struct {
   110  				ParameterKey   string `json:"ParameterKey"`
   111  				ParameterValue string `json:"ParameterValue"`
   112  			}
   113  
   114  			d := json.NewDecoder(bytes.NewReader(data))
   115  			d.DisallowUnknownFields()
   116  			if err := d.Decode(&cfparams); err != nil {
   117  				return err
   118  			}
   119  
   120  			for _, param := range cfparams {
   121  				(*p)[param.ParameterKey] = param.ParameterValue
   122  			}
   123  		}
   124  	default:
   125  		return fmt.Errorf("unsupported parameters format")
   126  	}
   127  
   128  	return nil
   129  }