dependabot-terraform 0.148.6 → 0.149.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae4366dea7cdc8902be7fc60c702dd4880f3eb061779da6b0dafee4ec81b0a30
4
- data.tar.gz: 27006c4842926165444aba49096aae361c6dd8b84639546cb0fb800f9ac51f18
3
+ metadata.gz: 36c78f6a28ee4ff879140720e2ab9fa49a11fcec5d7c5312c18147051264e826
4
+ data.tar.gz: f7a0be0a203afd35b77a5e51b10bea90df77457caf15757640bc4e80d8bf108b
5
5
  SHA512:
6
- metadata.gz: bf9ec46421f129b6c566bb489f0c0da2f6a95cb760f429f2f03e6be456356746bc538e17fce65f12b3da331451b7346600744888d36d0919e0a1b43a65d74d7c
7
- data.tar.gz: 7a4c1512faf5c2f2be193fd71bacffbf598cd87418c8c9f00d8ae6b39b226f04782ae46c5a06dabcc7941f67b6dcba302247de9e59e52370df95f3edb3a0a938
6
+ metadata.gz: dad9fdb36c1eb15daf45f6a972c005a918f90e146c9349c191051ed83a469b7b92cf8e93b7418e93b4ed74aa19f6a2844bbdbc99cdd8f28bdc406902e3fb1ffc
7
+ data.tar.gz: 19601275314f1221d25009a6b732ec3a1b61f24c24579d1ad95fc5d83a5e8f2a3b54d6990c7b310e439364a9a68a45a3503329e9217eb5b0fa732d73c36dac1e
@@ -20,6 +20,10 @@ module Dependabot
20
20
  include FileSelector
21
21
 
22
22
  ARCHIVE_EXTENSIONS = %w(.zip .tbz2 .tgz .txz).freeze
23
+ DEFAULT_REGISTRY = "registry.terraform.io"
24
+ DEFAULT_NAMESPACE = "hashicorp"
25
+ # https://www.terraform.io/docs/language/providers/requirements.html#source-addresses
26
+ PROVIDER_SOURCE_ADDRESS = %r{\A((?<hostname>.+)/)?(?<namespace>.+)/(?<name>.+)\z}.freeze
23
27
 
24
28
  def parse
25
29
  dependency_set = DependencySet.new
@@ -27,14 +31,14 @@ module Dependabot
27
31
  terraform_files.each do |file|
28
32
  modules = parsed_file(file).fetch("module", {})
29
33
  modules.each do |name, details|
30
- dependency_set << build_terraform_dependency(file, name, details, false)
34
+ dependency_set << build_terraform_dependency(file, name, details)
31
35
  end
32
36
 
33
37
  parsed_file(file).fetch("terraform", []).each do |terraform|
34
38
  required_providers = terraform.fetch("required_providers", {})
35
39
  required_providers.each do |provider|
36
40
  provider.each do |name, details|
37
- dependency_set << build_terraform_dependency(file, name, details, true)
41
+ dependency_set << build_provider_dependency(file, name, details)
38
42
  end
39
43
  end
40
44
  end
@@ -54,10 +58,10 @@ module Dependabot
54
58
 
55
59
  private
56
60
 
57
- def build_terraform_dependency(file, name, details, provider)
58
- details = details.is_a?(Array) ? details.first : details
61
+ def build_terraform_dependency(file, name, details)
62
+ details = details.first
59
63
 
60
- source = source_from(details, provider)
64
+ source = source_from(details)
61
65
  dep_name = case source[:type]
62
66
  when "registry" then source[:module_identifier]
63
67
  when "provider" then details["source"]
@@ -82,8 +86,31 @@ module Dependabot
82
86
  )
83
87
  end
84
88
 
89
+ def build_provider_dependency(file, name, details = {})
90
+ source_address = details.fetch("source", nil)
91
+ version_req = details["version"]&.strip
92
+ hostname, namespace, name = provider_source_from(source_address, name)
93
+ dependency_name = source_address ? "#{namespace}/#{name}" : name
94
+
95
+ Dependency.new(
96
+ name: dependency_name,
97
+ version: determine_version_for(hostname, namespace, name, version_req),
98
+ package_manager: "terraform",
99
+ requirements: [
100
+ requirement: version_req,
101
+ groups: [],
102
+ file: file.name,
103
+ source: {
104
+ type: "provider",
105
+ registry_hostname: hostname,
106
+ module_identifier: "#{namespace}/#{name}"
107
+ }
108
+ ]
109
+ )
110
+ end
111
+
85
112
  def build_terragrunt_dependency(file, details)
86
- source = source_from(details, false)
113
+ source = source_from(details)
87
114
  dep_name =
88
115
  if Source.from_url(source[:url])
89
116
  Source.from_url(source[:url]).repo
@@ -107,7 +134,7 @@ module Dependabot
107
134
  end
108
135
 
109
136
  # Full docs at https://www.terraform.io/docs/modules/sources.html
110
- def source_from(details_hash, provider)
137
+ def source_from(details_hash)
111
138
  raw_source = details_hash.fetch("source")
112
139
  bare_source = get_proxied_source(raw_source)
113
140
 
@@ -118,23 +145,28 @@ module Dependabot
118
145
  when :github, :bitbucket, :git
119
146
  git_source_details_from(bare_source)
120
147
  when :registry
121
- registry_source_details_from(bare_source, provider)
148
+ registry_source_details_from(bare_source)
122
149
  end
123
150
 
124
151
  source_details[:proxy_url] = raw_source if raw_source != bare_source
125
152
  source_details
126
153
  end
127
154
 
128
- def registry_source_details_from(source_string, provider)
155
+ def provider_source_from(source_address, name)
156
+ return [DEFAULT_REGISTRY, DEFAULT_NAMESPACE, name] unless source_address
157
+
158
+ matches = source_address.match(PROVIDER_SOURCE_ADDRESS)
159
+ [
160
+ matches[:hostname] || DEFAULT_REGISTRY,
161
+ matches[:namespace],
162
+ matches[:name] || name
163
+ ]
164
+ end
165
+
166
+ def registry_source_details_from(source_string)
129
167
  parts = source_string.split("//").first.split("/")
130
168
 
131
- if provider && parts.count == 2
132
- {
133
- "type": "provider",
134
- "registry_hostname": "registry.terraform.io",
135
- "module_identifier": source_string
136
- }
137
- elsif parts.count == 3
169
+ if parts.count == 3
138
170
  {
139
171
  type: "registry",
140
172
  registry_hostname: "registry.terraform.io",
@@ -300,6 +332,23 @@ module Dependabot
300
332
 
301
333
  raise "No Terraform configuration file!"
302
334
  end
335
+
336
+ def determine_version_for(hostname, namespace, name, constraint)
337
+ return constraint if constraint&.match?(/\A\d/)
338
+
339
+ lock_file_content.
340
+ dig("provider", "#{hostname}/#{namespace}/#{name}", 0, "version")
341
+ end
342
+
343
+ def lock_file_content
344
+ @lock_file_content ||=
345
+ begin
346
+ lock_file = dependency_files.find do |file|
347
+ file.name == ".terraform.lock.hcl"
348
+ end
349
+ lock_file ? parsed_file(lock_file) : {}
350
+ end
351
+ end
303
352
  end
304
353
  end
305
354
  end
@@ -98,9 +98,9 @@ module Dependabot
98
98
  end
99
99
 
100
100
  def provider_declaration_regex
101
+ name = Regexp.escape(dependency.name)
101
102
  /
102
- (?:required_providers\s\{)*
103
- (source\s*=\s*["']#{Regexp.escape(dependency.name)}["']
103
+ ((source\s*=\s*["']#{name}["']|\s*#{name}\s*=\s*\{.*)
104
104
  (?:(?!^\}).)+)
105
105
  /mx
106
106
  end
@@ -4,6 +4,7 @@ require "excon"
4
4
  require "json"
5
5
  require "dependabot/metadata_finders"
6
6
  require "dependabot/metadata_finders/base"
7
+ require "dependabot/terraform/registry_client"
7
8
  require "dependabot/shared_helpers"
8
9
 
9
10
  module Dependabot
@@ -40,7 +41,9 @@ module Dependabot
40
41
  info = dependency.requirements.map { |r| r[:source] }.compact.first
41
42
  hostname = info[:registry_hostname] || info["registry_hostname"]
42
43
 
43
- RegistryClient.new(hostname: hostname).source(dependency: dependency)
44
+ RegistryClient.
45
+ new(hostname: hostname, credentials: credentials).
46
+ source(dependency: dependency)
44
47
  end
45
48
  end
46
49
  end
@@ -11,8 +11,11 @@ module Dependabot
11
11
  class RegistryClient
12
12
  PUBLIC_HOSTNAME = "registry.terraform.io"
13
13
 
14
- def initialize(hostname:)
14
+ def initialize(hostname: PUBLIC_HOSTNAME, credentials: [])
15
15
  @hostname = hostname
16
+ @tokens = credentials.each_with_object({}) do |item, memo|
17
+ memo[item["host"]] = item["token"] if item["type"] == "terraform_registry"
18
+ end
16
19
  end
17
20
 
18
21
  # Fetch all the versions of a provider, and return a Version
@@ -23,9 +26,6 @@ module Dependabot
23
26
  # @return [Array<Dependabot::Terraform::Version>]
24
27
  # @raise [RuntimeError] when the versions cannot be retrieved
25
28
  def all_provider_versions(identifier:)
26
- # TODO: Implement service discovery for custom registries
27
- return [] unless hostname == PUBLIC_HOSTNAME
28
-
29
29
  response = get(endpoint: "providers/#{identifier}/versions")
30
30
 
31
31
  JSON.parse(response).
@@ -41,9 +41,6 @@ module Dependabot
41
41
  # @return [Array<Dependabot::Terraform::Version>]
42
42
  # @raise [RuntimeError] when the versions cannot be retrieved
43
43
  def all_module_versions(identifier:)
44
- # TODO: Implement service discovery for custom registries
45
- return [] unless hostname == PUBLIC_HOSTNAME
46
-
47
44
  response = get(endpoint: "modules/#{identifier}/versions")
48
45
 
49
46
  JSON.parse(response).
@@ -61,9 +58,6 @@ module Dependabot
61
58
  # @return Dependabot::Source
62
59
  # @raise [RuntimeError] when the source cannot be retrieved
63
60
  def source(dependency:)
64
- # TODO: Implement service discovery for custom registries
65
- return unless hostname == PUBLIC_HOSTNAME
66
-
67
61
  type = dependency.requirements.first[:source][:type]
68
62
  endpoint = if type == "registry"
69
63
  "modules/#{dependency.name}/#{dependency.version}"
@@ -80,7 +74,7 @@ module Dependabot
80
74
 
81
75
  private
82
76
 
83
- attr_reader :hostname
77
+ attr_reader :hostname, :tokens
84
78
 
85
79
  def get(endpoint:)
86
80
  url = "https://#{hostname}/v1/#{endpoint}"
@@ -88,7 +82,7 @@ module Dependabot
88
82
  response = Excon.get(
89
83
  url,
90
84
  idempotent: true,
91
- **SharedHelpers.excon_defaults
85
+ **SharedHelpers.excon_defaults(headers: headers_for(hostname))
92
86
  )
93
87
 
94
88
  raise "Response from registry was #{response.status}" unless response.status == 200
@@ -99,6 +93,11 @@ module Dependabot
99
93
  def version_class
100
94
  Version
101
95
  end
96
+
97
+ def headers_for(hostname)
98
+ token = tokens[hostname]
99
+ token ? { "Authorization" => "Bearer #{token}" } : {}
100
+ end
102
101
  end
103
102
  end
104
103
  end
@@ -87,7 +87,7 @@ module Dependabot
87
87
  def registry_client
88
88
  @registry_client ||= begin
89
89
  hostname = dependency_source_details.fetch(:registry_hostname)
90
- RegistryClient.new(hostname: hostname)
90
+ RegistryClient.new(hostname: hostname, credentials: credentials)
91
91
  end
92
92
  end
93
93
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-terraform
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.148.6
4
+ version: 0.149.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-21 00:00:00.000000000 Z
11
+ date: 2021-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.148.6
19
+ version: 0.149.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.148.6
26
+ version: 0.149.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement