dependabot-go_modules 0.117.6 → 0.117.11

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: f7372dd4c4672d221065b7fa54cc53cb5f0430f9987942d06defb0dbe429140a
4
- data.tar.gz: cae04c71ebcf2588dc2c5c919a8c1a4561df683c25a3d52a4c007b34ea1e80dc
3
+ metadata.gz: dd8c69512adb380e04e618dd8aee5babf1cb2c9ecce5db883d75cbe4f6e5da8d
4
+ data.tar.gz: d8f0ac8addff60780b4a2c0f8c0511a22927b707a56ed36e57621db867065a7a
5
5
  SHA512:
6
- metadata.gz: 3b121dd8bb6e9863ac9270535540c91f2c52b4469f39acb2c8f3d5a8d243eac41598356c86b628a0ffdc8db6fbcfa6897714609c3860cfc3ab598bea5cf2c55f
7
- data.tar.gz: '0881fa05874b7f704207d12ba344fe4f5c032b339795d28133aa0482427b6ad3e64650ea563308bcbb7db3ad3bb258a110a1a2fee2a35bfa237fce6c4687c322'
6
+ metadata.gz: 451e6577853ff04a4533020294c3dbd9bca7a1ad2bcc61900d68af7b76fcc4af3b3ac5930c5b01b7d9da6dce9227b1f7ef5a7c80c814bd06c3366f9eebca16f3
7
+ data.tar.gz: 851ef0e19e28d029fdcda001b25b51b4255e34f4ebe8ccc480bd9285ab0f54d618fbc411ffdc9d144858425119a1e4ca508e294f41cc3a4f7ba2ff4f53f2cec7
@@ -135,16 +135,16 @@ module Dependabot
135
135
  end
136
136
  end
137
137
 
138
- GIT_ERROR_REGEX = /go: .*: git fetch .*: exit status 128/.freeze
138
+ GIT_ERROR_REGEX = /go: .*: git fetch .*: exit status 128/m.freeze
139
139
  def handle_parser_error(path, stderr)
140
140
  case stderr
141
- when /go: .*: unknown revision/
141
+ when /go: .*: unknown revision/m
142
142
  line = stderr.lines.grep(/unknown revision/).first
143
143
  raise Dependabot::DependencyFileNotResolvable, line.strip
144
- when /go: .*: unrecognized import path/
144
+ when /go: .*: unrecognized import path/m
145
145
  line = stderr.lines.grep(/unrecognized import/).first
146
146
  raise Dependabot::DependencyFileNotResolvable, line.strip
147
- when /go: errors parsing go.mod/
147
+ when /go: errors parsing go.mod/m
148
148
  msg = stderr.gsub(path.to_s, "").strip
149
149
  raise Dependabot::DependencyFileNotParseable.new(go_mod.path, msg)
150
150
  when GIT_ERROR_REGEX
@@ -9,6 +9,22 @@ module Dependabot
9
9
  module GoModules
10
10
  class FileUpdater
11
11
  class GoModUpdater
12
+ # Turn off the module proxy for now, as it's causing issues with
13
+ # private git dependencies
14
+ ENVIRONMENT = { "GOPRIVATE" => "*" }.freeze
15
+
16
+ RESOLVABILITY_ERROR_REGEXES = [
17
+ /go: .*: git fetch .*: exit status 128/.freeze,
18
+ /verifying .*: checksum mismatch/.freeze,
19
+ /build .*: cannot find module providing package/.freeze
20
+ ].freeze
21
+
22
+ MODULE_PATH_MISMATCH_REGEXES = [
23
+ /go: ([^@\s]+)(?:@[^\s]+)?: .* has non-.* module path "(.*)" at/,
24
+ /go: ([^@\s]+)(?:@[^\s]+)?: .* unexpected module path "(.*)"/,
25
+ /go: ([^@\s]+)(?:@[^\s]+)?: .* declares its path as: ([\S]*)/m
26
+ ].freeze
27
+
12
28
  def initialize(dependencies:, go_mod:, go_sum:, credentials:)
13
29
  @dependencies = dependencies
14
30
  @go_mod = go_mod
@@ -17,96 +33,171 @@ module Dependabot
17
33
  end
18
34
 
19
35
  def updated_go_mod_content
20
- # Turn off the module proxy for now, as it's causing issues with
21
- # private git dependencies
22
- env = { "GOPRIVATE" => "*" }
23
-
24
- @updated_go_mod_content ||=
25
- SharedHelpers.in_a_temporary_directory do
26
- SharedHelpers.with_git_configured(credentials: credentials) do
27
- File.write("go.mod", go_mod.content)
28
-
29
- deps = dependencies.map do |dep|
30
- {
31
- name: dep.name,
32
- version: "v" + dep.version.sub(/^v/i, ""),
33
- indirect: dep.requirements.empty?
34
- }
35
- end
36
-
37
- SharedHelpers.run_helper_subprocess(
38
- command: NativeHelpers.helper_path,
39
- env: env,
40
- function: "updateDependencyFile",
41
- args: { dependencies: deps }
42
- )
43
- end
44
- end
36
+ updated_files[:go_mod]
45
37
  end
46
38
 
47
39
  def updated_go_sum_content
48
- return nil unless go_sum
49
-
50
- # This needs to be run separately so we don't nest subprocess calls
51
- prepared_go_mod_content
52
-
53
- @updated_go_sum_content ||=
54
- SharedHelpers.in_a_temporary_directory do
55
- SharedHelpers.with_git_configured(credentials: credentials) do
56
- # Create a fake empty module for each local module so that
57
- # `go get -d` works, even if some modules have been `replace`d
58
- # with a local module that we don't have access to.
59
- local_replacements.each do |_, stub_path|
60
- Dir.mkdir(stub_path) unless Dir.exist?(stub_path)
61
- FileUtils.touch(File.join(stub_path, "go.mod"))
62
- end
63
-
64
- File.write("go.mod", prepared_go_mod_content)
65
- File.write("go.sum", go_sum.content)
66
- File.write("main.go", dummy_main_go)
67
-
68
- # Turn off the module proxy for now, as it's causing issues
69
- # with private git dependencies
70
- env = { "GOPRIVATE" => "*" }
71
-
72
- _, stderr, status = Open3.capture3(env, "go get -d")
73
- unless status.success?
74
- handle_subprocess_error(go_sum.path, stderr)
75
- end
76
-
77
- File.read("go.sum")
78
- end
79
- end
40
+ updated_files[:go_sum]
80
41
  end
81
42
 
82
43
  private
83
44
 
84
- RESOLVABILITY_ERROR_REGEXES = [
85
- /go: .*: git fetch .*: exit status 128/.freeze,
86
- /verifying .*: checksum mismatch/.freeze,
87
- /build .*: cannot find module providing package/.freeze
88
- ].freeze
89
- MODULE_PATH_MISMATCH_REGEXES = [
90
- /go: ([^@\s]+)(?:@[^\s]+)?: .* has non-.* module path "(.*)" at/,
91
- /go: ([^@\s]+)(?:@[^\s]+)?: .* unexpected module path "(.*)"/,
92
- /go: ([^@\s]+)(?:@[^\s]+)?: .* declares its path as: ([\S]*)/m
93
- ].freeze
45
+ attr_reader :dependencies, :go_mod, :go_sum, :credentials
46
+
47
+ def updated_files
48
+ @updated_files ||= update_files
49
+ end
50
+
51
+ # rubocop:disable Metrics/AbcSize
52
+ def update_files
53
+ # Map paths in local replace directives to path hashes
54
+ substitutions = replace_directive_substitutions(go_mod.content)
55
+ stub_dirs = substitutions.values
56
+
57
+ # Replace full paths with path hashes in the go.mod
58
+ clean_go_mod = substitute_all(go_mod.content, substitutions)
59
+
60
+ # Set the new dependency versions in the go.mod
61
+ updated_go_mod = in_temp_dir(stub_dirs) do
62
+ update_go_mod(clean_go_mod, dependencies)
63
+ end
64
+
65
+ # Then run `go get` to pick up other changes to the file caused by
66
+ # the upgrade
67
+ regenerated_files = in_temp_dir(stub_dirs) do
68
+ run_go_get(updated_go_mod, go_sum)
69
+ end
70
+
71
+ # At this point, the go.mod returned from run_go_get contains the
72
+ # correct set of modules, but running `go get` can change the file in
73
+ # undesirable ways (such as injecting the current Go version), so we
74
+ # need to update the original go.mod with the updated set of
75
+ # requirements rather than using the regenerated file directly
76
+ original_reqs = in_temp_dir(stub_dirs) do
77
+ parse_manifest_requirements(go_mod.content)
78
+ end
79
+ updated_reqs = in_temp_dir(stub_dirs) do
80
+ parse_manifest_requirements(regenerated_files[:go_mod])
81
+ end
82
+
83
+ original_paths = original_reqs.map { |r| r["Path"] }
84
+ updated_paths = updated_reqs.map { |r| r["Path"] }
85
+ req_paths_to_remove = original_paths - updated_paths
94
86
 
95
- def local_replacements
96
- @local_replacements ||=
87
+ output_go_mod = in_temp_dir(stub_dirs) do
88
+ remove_requirements(go_mod.content, req_paths_to_remove)
89
+ end
90
+
91
+ output_go_mod = in_temp_dir(stub_dirs) do
92
+ deps = updated_reqs.map { |r| requirement_to_dependency_obj(r) }
93
+ update_go_mod(output_go_mod, deps)
94
+ end
95
+
96
+ { go_mod: output_go_mod, go_sum: regenerated_files[:go_sum] }
97
+ end
98
+ # rubocop:enable Metrics/AbcSize
99
+
100
+ def update_go_mod(go_mod_content, dependencies)
101
+ File.write("go.mod", go_mod_content)
102
+
103
+ deps = dependencies.map do |dep|
104
+ {
105
+ name: dep.name,
106
+ version: "v" + dep.version.sub(/^v/i, ""),
107
+ indirect: dep.requirements.empty?
108
+ }
109
+ end
110
+
111
+ SharedHelpers.run_helper_subprocess(
112
+ command: NativeHelpers.helper_path,
113
+ env: ENVIRONMENT,
114
+ function: "updateDependencyFile",
115
+ args: { dependencies: deps }
116
+ )
117
+ end
118
+
119
+ def run_go_get(go_mod_content, go_sum)
120
+ File.write("go.mod", go_mod_content)
121
+ File.write("go.sum", go_sum.content) if go_sum
122
+ File.write("main.go", dummy_main_go)
123
+
124
+ _, stderr, status = Open3.capture3(ENVIRONMENT, "go get -d")
125
+ handle_subprocess_error(stderr) unless status.success?
126
+
127
+ updated_go_sum = go_sum ? File.read("go.sum") : nil
128
+ { go_mod: File.read("go.mod"), go_sum: updated_go_sum }
129
+ end
130
+
131
+ def parse_manifest_requirements(go_mod_content)
132
+ File.write("go.mod", go_mod_content)
133
+
134
+ command = "go mod edit -json"
135
+ stdout, stderr, status = Open3.capture3(ENVIRONMENT, command)
136
+ handle_subprocess_error(stderr) unless status.success?
137
+
138
+ JSON.parse(stdout)["Require"] || []
139
+ end
140
+
141
+ def remove_requirements(go_mod_content, requirement_paths)
142
+ File.write("go.mod", go_mod_content)
143
+
144
+ requirement_paths.each do |path|
145
+ escaped_path = Shellwords.escape(path)
146
+ command = "go mod edit -droprequire #{escaped_path}"
147
+ _, stderr, status = Open3.capture3(ENVIRONMENT, command)
148
+ handle_subprocess_error(stderr) unless status.success?
149
+ end
150
+
151
+ File.read("go.mod")
152
+ end
153
+
154
+ def add_requirements(go_mod_content, requirements)
155
+ File.write("go.mod", go_mod_content)
156
+
157
+ requirements.each do |r|
158
+ escaped_req = Shellwords.escape("#{r['Path']}@#{r['Version']}")
159
+ command = "go mod edit -require #{escaped_req}"
160
+ _, stderr, status = Open3.capture3(ENVIRONMENT, command)
161
+ handle_subprocess_error(stderr) unless status.success?
162
+ end
163
+
164
+ File.read("go.mod")
165
+ end
166
+
167
+ def in_temp_dir(stub_paths, &block)
168
+ SharedHelpers.in_a_temporary_directory do
169
+ SharedHelpers.with_git_configured(credentials: credentials) do
170
+ # Create a fake empty module for each local module so that
171
+ # `go get -d` works, even if some modules have been `replace`d
172
+ # with a local module that we don't have access to.
173
+ stub_paths.each do |stub_path|
174
+ Dir.mkdir(stub_path) unless Dir.exist?(stub_path)
175
+ FileUtils.touch(File.join(stub_path, "go.mod"))
176
+ end
177
+
178
+ block.call
179
+ end
180
+ end
181
+ end
182
+
183
+ # Given a go.mod file, find all `replace` directives pointing to a path
184
+ # on the local filesystem, and return an array of pairs mapping the
185
+ # original path to a hash of the path.
186
+ #
187
+ # This lets us substitute all parts of the go.mod that are dependent on
188
+ # the layout of the filesystem with a structure we can reproduce (i.e.
189
+ # no paths such as ../../../foo), run the Go tooling, then reverse the
190
+ # process afterwards.
191
+ def replace_directive_substitutions(go_mod_content)
192
+ @replace_directive_substitutions ||=
97
193
  SharedHelpers.in_a_temporary_directory do |path|
98
- File.write("go.mod", go_mod.content)
194
+ File.write("go.mod", go_mod_content)
99
195
 
100
196
  # Parse the go.mod to get a JSON representation of the replace
101
197
  # directives
102
198
  command = "go mod edit -json"
103
-
104
- # Turn off the module proxy for now, as it's causing issues with
105
- # private git dependencies
106
- env = { "GOPRIVATE" => "*" }
107
-
108
- stdout, stderr, status = Open3.capture3(env, command)
109
- handle_parser_error(path, stderr) unless status.success?
199
+ stdout, stderr, status = Open3.capture3(ENVIRONMENT, command)
200
+ handle_subprocess_error(path, stderr) unless status.success?
110
201
 
111
202
  # Find all the local replacements, and return them with a stub
112
203
  # path we can use in their place. Using generated paths is safer
@@ -116,18 +207,20 @@ module Dependabot
116
207
  map { |r| r["New"]["Path"] }.
117
208
  compact.
118
209
  select { |p| p.start_with?(".") || p.start_with?("/") }.
119
- map { |p| [p, "./" + Digest::SHA2.hexdigest(p)] }
210
+ map { |p| [p, "./" + Digest::SHA2.hexdigest(p)] }.
211
+ to_h
120
212
  end
121
213
  end
122
214
 
123
- def prepared_go_mod_content
124
- content = updated_go_mod_content
125
- local_replacements.reduce(content) do |body, (path, stub_path)|
126
- body.sub(path, stub_path)
215
+ def substitute_all(file, substitutions)
216
+ substitutions.reduce(file) do |text, (a, b)|
217
+ text.sub(a, b)
127
218
  end
128
219
  end
129
220
 
130
- def handle_subprocess_error(path, stderr)
221
+ def handle_subprocess_error(stderr)
222
+ stderr = stderr.gsub(Dir.getwd, "")
223
+
131
224
  error_regex = RESOLVABILITY_ERROR_REGEXES.find { |r| stderr =~ r }
132
225
  if error_regex
133
226
  lines = stderr.lines.drop_while { |l| error_regex !~ l }
@@ -141,7 +234,7 @@ module Dependabot
141
234
  new(go_mod.path, match[1], match[2])
142
235
  end
143
236
 
144
- msg = stderr.gsub(path.to_s, "").lines.last(10).join.strip
237
+ msg = stderr.lines.last(10).join.strip
145
238
  raise Dependabot::DependencyFileNotParseable.new(go_mod.path, msg)
146
239
  end
147
240
 
@@ -156,13 +249,29 @@ module Dependabot
156
249
  # good to switch back to `main` so we can surface more errors.
157
250
  lines = ["package dummypkg", "import ("]
158
251
  dependencies.each do |dep|
159
- lines << "_ \"#{dep.name}\""
252
+ lines << "_ \"#{dep.name}\"" unless dep.requirements.empty?
160
253
  end
161
254
  lines << ")"
162
255
  lines.join("\n")
163
256
  end
164
257
 
165
- attr_reader :dependencies, :go_mod, :go_sum, :credentials
258
+ def requirement_to_dependency_obj(req)
259
+ # This is an approximation - we're not correctly populating `source`
260
+ # for instance, but it's only to plug the requirement into the
261
+ # `update_go_mod` method so this mapping doesn't need to be perfect
262
+ dep_req = {
263
+ file: "go.mod",
264
+ requirement: req["Version"],
265
+ groups: [],
266
+ source: nil
267
+ }
268
+ Dependency.new(
269
+ name: req["Path"],
270
+ version: req["Version"],
271
+ requirements: req["Indirect"] ? [] : [dep_req],
272
+ package_manager: "go_modules"
273
+ )
274
+ end
166
275
  end
167
276
  end
168
277
  end
@@ -125,7 +125,8 @@ module Dependabot
125
125
  GitCommitChecker.new(
126
126
  dependency: dependency,
127
127
  credentials: credentials,
128
- ignored_versions: ignored_versions
128
+ ignored_versions: ignored_versions,
129
+ raise_on_ignored: raise_on_ignored
129
130
  )
130
131
  end
131
132
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-go_modules
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.117.6
4
+ version: 0.117.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-09 00:00:00.000000000 Z
11
+ date: 2020-05-28 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.117.6
19
+ version: 0.117.11
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.117.6
26
+ version: 0.117.11
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.80.1
117
+ version: 0.83.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 0.80.1
124
+ version: 0.83.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: vcr
127
127
  requirement: !ruby/object:Gem::Requirement