@@ -10,9 +10,8 @@ import (
1010 "strings"
1111
1212 "github.com/apparentlymart/go-versions/versions"
13- "github.com/apparentlymart/go-versions/versions/constraints"
1413 "github.com/hashicorp/terraform/addrs"
15- "github.com/hashicorp/terraform/configs"
14+ hclConfigs "github.com/hashicorp/terraform/configs"
1615 httputils "github.com/tenable/terrascan/pkg/utils/http"
1716 "go.uber.org/zap"
1817)
@@ -22,11 +21,7 @@ const (
2221 terraformVersionHeader = "X-Terraform-Version"
2322)
2423
25- // VersionConstraints ...
26- type VersionConstraints = constraints.IntersectionSpec
27-
28- // Requirements ...
29- type Requirements map [addrs.Provider ]VersionConstraints
24+ var versionCache = make (map [string ]string )
3025
3126// ProviderVersions ...
3227type ProviderVersions struct {
@@ -37,14 +32,10 @@ type ProviderVersions struct {
3732 Warnings []string `json:"warnings"`
3833}
3934
40- // ProviderVersionList fetches all the versions of terraform providers
41- func ProviderVersionList (ctx context.Context , addr addrs.Provider , terraformVersion string ) (versions.List , []string , error ) {
35+ // providerVersionList fetches all the versions of terraform providers
36+ func providerVersionList (ctx context.Context , addr addrs.Provider , terraformVersion string ) (versions.List , []string , error ) {
4237 zap .S ().Debugf ("fetching list of providers metadata, hostname: %q, type: %q, namespace: %q, " , addr .Hostname .String (), addr .Namespace , addr .Type )
4338
44- if addr .Hostname .String () == "" {
45- return nil , nil , fmt .Errorf ("error preparing the providers list endpoint, error: hostname can't be empty" )
46- }
47-
4839 endpointURL , err := url .Parse (path .Join (apiVersion , "providers" , addr .Namespace , addr .Type , "versions" ))
4940 if err != nil {
5041 return nil , nil , fmt .Errorf ("error preparing the providers list endpoint, error: %s" , err .Error ())
@@ -92,76 +83,108 @@ func ProviderVersionList(ctx context.Context, addr addrs.Provider, terraformVers
9283 }
9384 versionList = append (versionList , ver )
9485 }
95- // versionList.Newest()
96-
9786 return versionList , body .Warnings , nil
9887}
9988
100- var versionCache = make (map [string ]string )
101-
102- // LatestProviderVersion returns the latest published version for the asked provider.
89+ // latestProviderVersion returns the latest published version for the asked provider.
10390// It returns "0.0.0" in case its not available
104- func LatestProviderVersion (addr addrs.Provider , terraformVersion string ) string {
91+ func latestProviderVersion (addr addrs.Provider , terraformVersion string ) string {
10592
10693 // check if the cache has the version info
10794 if v , found := versionCache [fmt .Sprintf ("%s-%s" , addr .Type , terraformVersion )]; found {
10895 return v
10996 }
110- versionList , _ , err := ProviderVersionList (context .TODO (), addr , terraformVersion )
97+ versionList , _ , err := providerVersionList (context .TODO (), addr , terraformVersion )
11198 if err != nil {
112- zap .S ().Errorf ("failed to fetch latest version for terraform provider, error: %s" , err .Error ())
99+ zap .S ().Warnf ("failed to fetch latest version for terraform provider, error: %s" , err .Error ())
100+ return versionList .Newest ().String ()
113101 }
114102 // update cache
115103 versionCache [fmt .Sprintf ("%s-%s" , addr .Type , terraformVersion )] = versionList .Newest ().String ()
116104 return versionList .Newest ().String ()
117105}
118106
119- // ParseVersionConstraints parses a "Ruby-like" version constraint string
120- // into a VersionConstraints value.
121- func ParseVersionConstraints (str string ) (VersionConstraints , error ) {
122- return constraints .ParseRubyStyleMulti (str )
107+ // GetProviderVersion identifies the version constraints for file resources.
108+ func GetProviderVersion (f * hclConfigs.File , addr addrs.Provider , terraformVersion string ) string {
109+ version := ""
110+
111+ for _ , rps := range f .RequiredProviders {
112+ if rp , exist := rps .RequiredProviders [addr .Type ]; exist {
113+ version = trimVersionConstraints (rp .Requirement .Required .String ())
114+ break
115+ }
116+ }
117+
118+ // older version of terraform (terraform version < 1.x) may have version in provider block
119+ if len (version ) == 0 {
120+ for _ , pc := range f .ProviderConfigs {
121+ if pc .Name == addr .Type {
122+ version = trimVersionConstraints (pc .Version .Required .String ())
123+ break
124+ }
125+ }
126+ }
127+
128+ // fetch latest version
129+ if len (version ) == 0 {
130+ version = latestProviderVersion (addr , terraformVersion )
131+ }
132+ v , err := versions .ParseVersion (version )
133+ if err != nil {
134+ zap .S ().Warnf ("failed to parse provider version: %s" , err .Error ())
135+ return ""
136+ }
137+ return v .String ()
123138}
124139
125- // GetModuleProviderVersion gets the provider version form the 'required_providers' block for module.
126- // if the 'required_providers' is not defined, it returns empty string
127- func GetModuleProviderVersion (m * configs.Module ) string {
140+ // GetModuleProviderVersion identifies the version constraints for module resources.
141+ func GetModuleProviderVersion (module * hclConfigs.Module , addr addrs.Provider , terraformVersion string ) string {
128142 version := ""
129- if m == nil || m .ProviderRequirements == nil {
130- return version
143+
144+ if rp , exist := module .ProviderRequirements .RequiredProviders [addr .Type ]; exist {
145+ version = trimVersionConstraints (rp .Requirement .Required .String ())
131146 }
132- for _ , requiredProvider := range m .ProviderRequirements .RequiredProviders {
133- if requiredProvider != nil && len (requiredProvider .Requirement .Required ) > 0 {
134- version = requiredProvider .Requirement .Required [0 ].String ()
147+
148+ // older version of terraform (terraform version < 1.x) may have version in provider block
149+ if len (version ) == 0 {
150+ if pc , exist := module .ProviderConfigs [addr .Type ]; exist {
151+ version = trimVersionConstraints (pc .Version .Required .String ())
135152 }
136153 }
137154
138- // trim version string
139- s := strings .Split (version , " " )
140- if len (s ) > 1 {
141- version = s [1 ]
155+ // fetch latest version
156+ if len (version ) == 0 {
157+ version = latestProviderVersion (addr , terraformVersion )
142158 }
143-
144- return version
159+ v , err := versions .ParseVersion (version )
160+ if err != nil {
161+ zap .S ().Warnf ("failed to parse provider version: %s" , err .Error ())
162+ return ""
163+ }
164+ return v .String ()
145165}
146166
147- // GetFileProviderVersion gets the provider version form the 'required_providers' block for the file.
148- // if the 'required_providers' is not defined, it returns empty string
149- func GetFileProviderVersion ( f * configs. File ) string {
150- version := ""
151- if f == nil || f . RequiredProviders == nil || len ( f . RequiredProviders ) == 0 {
152- return version
167+ // ResolveProvider resolves provider addr
168+ func ResolveProvider ( resource * hclConfigs. Resource , requiredProviders [] * hclConfigs. RequiredProviders ) addrs. Provider {
169+ implied , err := addrs . ParseProviderPart ( resource . Addr (). ImpliedProvider ())
170+ if err != nil {
171+ zap . S (). Warnf ( "failed to parse provider namespace or type: %s" , err . Error ())
172+ return addrs . NewDefaultProvider ( "aws" )
153173 }
154- for _ , requiredProvider := range f . RequiredProviders [ 0 ]. RequiredProviders {
155- if requiredProvider != nil && len ( requiredProvider . Requirement . Required ) > 0 {
156- version = requiredProvider . Requirement . Required [ 0 ]. String ()
174+ for _ , rp := range requiredProviders {
175+ if provider , exists := rp . RequiredProviders [ implied ]; exists {
176+ return provider . Type
157177 }
158178 }
179+ return addrs .ImpliedProviderForUnqualifiedType (implied )
180+ }
159181
160- // trim version string
161- s := strings .Split (version , " " )
182+ // trimVersionConstraints trim version constraints from string.
183+ // e.g. "~> 3.0.2" will become "3.0.2"
184+ func trimVersionConstraints (v string ) string {
185+ s := strings .Split (v , " " )
162186 if len (s ) > 1 {
163- version = s [1 ]
187+ v = s [1 ]
164188 }
165-
166- return version
189+ return v
167190}
0 commit comments