dependabot-go_modules 0.117.7 → 0.118.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: 39ce7bcb4b1a8d66343e6a186c0deab95ce6f7c0a3e7f577e55dfcb127d73e99
4
- data.tar.gz: 4351710af1e7c33b4e597464d43725a976064a413c7d7f7acf5a55d0ec74af39
3
+ metadata.gz: 7799098c9d1777821ce42059f6a47702bb887af1179ab82c9266d65ad2ce73fc
4
+ data.tar.gz: 06c2fdfb2b91cd8e1d5ac93d027c6d25a6f744b17b333cd9fca392daa6176673
5
5
  SHA512:
6
- metadata.gz: 10761c29d848916a0447d5ead96ee3050c671667193fc05b6f142f221034fa368b19c6c28ccb2c57efb7d889709bf1532d1b7602cec6725746c07f416b469e32
7
- data.tar.gz: 0b201a3a611e0730a1b01db6b6a21af6f3fb10fd3de0d21586fb03f07ef0150194e3f6a9e063562acd0ebdd9266b20f8658cd753908f0076fc8b5b1b8ef87e8b
6
+ metadata.gz: aee189a098fc42fcdb31a2449f941c318e1a7a14bc1475eeec0dc6d0da4e97c05b764e9ff3ae6a3d1ab5e7084f75db7139243bacbe54386de5970067283a7ceb
7
+ data.tar.gz: a73d5d3884e68bd67ec2138c8c6a35009355da02d8a7a73c1993a0ef5a148ed6baf83711f32d2a3bc5405a19a5672b96b73b70d844bb97709b3036d79578581b
@@ -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.7
4
+ version: 0.118.0
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-20 00:00:00.000000000 Z
11
+ date: 2020-05-29 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.7
19
+ version: 0.118.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.117.7
26
+ version: 0.118.0
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.82.0
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.82.0
124
+ version: 0.83.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: vcr
127
127
  requirement: !ruby/object:Gem::Requirement