dependabot-nuget 0.265.0 → 0.267.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/UpdateCommand.cs +6 -6
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +173 -0
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalysisResult.cs +1 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +92 -79
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +21 -8
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +36 -9
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/Requirement.cs +88 -45
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +33 -16
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +44 -25
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +1 -1
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +9 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/ProjectBuildFile.cs +2 -2
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/MissingFileException.cs +11 -0
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/NativeResult.cs +8 -0
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +45 -42
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +19 -1
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +2 -1
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationResult.cs +5 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +70 -22
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +29 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +6 -2
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +450 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/CompatibilityCheckerTests.cs +23 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/RequirementTests.cs +1 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +2 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +148 -0
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -1
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +17 -22
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestHttpServer.cs +81 -0
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +27 -7
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Mixed.cs +32 -0
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +447 -2
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +88 -0
  35. data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -0
  36. data/lib/dependabot/nuget/file_fetcher.rb +30 -11
  37. data/lib/dependabot/nuget/file_updater.rb +2 -0
  38. data/lib/dependabot/nuget/metadata_finder.rb +160 -2
  39. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +3 -0
  40. data/lib/dependabot/nuget/native_helpers.rb +36 -3
  41. data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +1 -0
  42. data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +3 -0
  43. metadata +12 -7
@@ -21,6 +21,8 @@ module Dependabot
21
21
  [
22
22
  %r{^[^/]*\.([a-z]{2})?proj$},
23
23
  /^packages\.config$/i,
24
+ /^app\.config$/i,
25
+ /^web\.config$/i,
24
26
  /^global\.json$/i,
25
27
  /^dotnet-tools\.json$/i,
26
28
  /^Directory\.Build\.props$/i,
@@ -12,16 +12,148 @@ module Dependabot
12
12
  class MetadataFinder < Dependabot::MetadataFinders::Base
13
13
  extend T::Sig
14
14
 
15
+ sig do
16
+ override
17
+ .params(
18
+ dependency: Dependabot::Dependency,
19
+ credentials: T::Array[Dependabot::Credential]
20
+ )
21
+ .void
22
+ end
23
+ def initialize(dependency:, credentials:)
24
+ @dependency_nuspec_file = T.let(nil, T.nilable(Nokogiri::XML::Document))
25
+
26
+ super
27
+ end
28
+
15
29
  private
16
30
 
17
31
  sig { override.returns(T.nilable(Dependabot::Source)) }
18
32
  def look_up_source
19
- source_url = dependency_source_url
20
- return Source.from_url(source_url) if source_url
33
+ return Source.from_url(dependency_source_url) if dependency_source_url
34
+
35
+ if dependency_nuspec_file
36
+ src_repo = look_up_source_in_nuspec(T.must(dependency_nuspec_file))
37
+ return src_repo if src_repo
38
+ end
39
+
40
+ # Fallback to getting source from the search result's projectUrl or licenseUrl.
41
+ # GitHub Packages doesn't support getting the `.nuspec`, switch to getting
42
+ # that instead once it is supported.
43
+ src_repo_from_project
44
+ rescue StandardError
45
+ # At this point in the process the PR is ready to be posted, we tried to gather commit
46
+ # and release notes, but have encountered an exception. So let's eat it since it's
47
+ # better to have a PR with no info than error out.
48
+ nil
49
+ end
50
+
51
+ sig { returns(T.nilable(Dependabot::Source)) }
52
+ def src_repo_from_project
53
+ source = dependency.requirements.find { |r| r.fetch(:source) }&.fetch(:source)
54
+ return unless source
55
+
56
+ # Query the service index e.g. https://nuget.pkg.github.com/ORG/index.json
57
+ response = Dependabot::RegistryClient.get(
58
+ url: source.fetch(:url),
59
+ headers: { **auth_header, "Accept" => "application/json" }
60
+ )
61
+ return unless response.status == 200
21
62
 
63
+ # Extract the query url e.g. https://nuget.pkg.github.com/ORG/query
64
+ search_base = extract_search_url(response.body)
65
+ return unless search_base
66
+
67
+ response = Dependabot::RegistryClient.get(
68
+ url: search_base + "?q=#{dependency.name.downcase}&prerelease=true&semVerLevel=2.0.0",
69
+ headers: { **auth_header, "Accept" => "application/json" }
70
+ )
71
+ return unless response.status == 200
72
+
73
+ # Find a projectUrl or licenseUrl that look like a source URL
74
+ extract_source_repo(response.body)
75
+ rescue JSON::ParserError
76
+ # Ignored, this is expected for some registries that don't handle these request.
77
+ end
78
+
79
+ sig { params(body: String).returns(T.nilable(String)) }
80
+ def extract_search_url(body)
81
+ JSON.parse(body)
82
+ .fetch("resources", [])
83
+ .find { |r| r.fetch("@type") == "SearchQueryService" }
84
+ &.fetch("@id")
85
+ end
86
+
87
+ sig { params(body: String).returns(T.nilable(Dependabot::Source)) }
88
+ def extract_source_repo(body)
89
+ JSON.parse(body).fetch("data", []).each do |search_result|
90
+ next unless search_result["id"].casecmp(dependency.name).zero?
91
+
92
+ if search_result.key?("projectUrl")
93
+ source = Source.from_url(search_result.fetch("projectUrl"))
94
+ return source if source
95
+ end
96
+ if search_result.key?("licenseUrl")
97
+ source = Source.from_url(search_result.fetch("licenseUrl"))
98
+ return source if source
99
+ end
100
+ end
101
+ # failed to find a source URL
22
102
  nil
23
103
  end
24
104
 
105
+ sig { params(nuspec: Nokogiri::XML::Document).returns(T.nilable(Dependabot::Source)) }
106
+ def look_up_source_in_nuspec(nuspec)
107
+ potential_source_urls = [
108
+ nuspec.at_css("package > metadata > repository")
109
+ &.attribute("url")&.value,
110
+ nuspec.at_css("package > metadata > repository > url")&.content,
111
+ nuspec.at_css("package > metadata > projectUrl")&.content,
112
+ nuspec.at_css("package > metadata > licenseUrl")&.content
113
+ ].compact
114
+
115
+ source_url = potential_source_urls.find { |url| Source.from_url(url) }
116
+ source_url ||= source_from_anywhere_in_nuspec(nuspec)
117
+
118
+ Source.from_url(source_url)
119
+ end
120
+
121
+ sig { params(nuspec: Nokogiri::XML::Document).returns(T.nilable(String)) }
122
+ def source_from_anywhere_in_nuspec(nuspec)
123
+ github_urls = []
124
+ nuspec.to_s.force_encoding(Encoding::UTF_8)
125
+ .scan(Source::SOURCE_REGEX) do
126
+ github_urls << Regexp.last_match.to_s
127
+ end
128
+
129
+ github_urls.find do |url|
130
+ repo = T.must(Source.from_url(url)).repo
131
+ repo.downcase.end_with?(dependency.name.downcase)
132
+ end
133
+ end
134
+
135
+ sig { returns(T.nilable(Nokogiri::XML::Document)) }
136
+ def dependency_nuspec_file
137
+ return @dependency_nuspec_file unless @dependency_nuspec_file.nil?
138
+
139
+ return if dependency_nuspec_url.nil?
140
+
141
+ response = Dependabot::RegistryClient.get(
142
+ url: T.must(dependency_nuspec_url),
143
+ headers: auth_header
144
+ )
145
+
146
+ @dependency_nuspec_file = Nokogiri::XML(response.body)
147
+ end
148
+
149
+ sig { returns(T.nilable(String)) }
150
+ def dependency_nuspec_url
151
+ source = dependency.requirements
152
+ .find { |r| r.fetch(:source) }&.fetch(:source)
153
+
154
+ source.fetch(:nuspec_url) if source&.key?(:nuspec_url)
155
+ end
156
+
25
157
  sig { returns(T.nilable(String)) }
26
158
  def dependency_source_url
27
159
  source = dependency.requirements
@@ -32,6 +164,32 @@ module Dependabot
32
164
 
33
165
  source.fetch("source_url")
34
166
  end
167
+
168
+ # rubocop:disable Metrics/PerceivedComplexity
169
+ sig { returns(T::Hash[String, String]) }
170
+ def auth_header
171
+ source = dependency.requirements
172
+ .find { |r| r.fetch(:source) }&.fetch(:source)
173
+ url = source&.fetch(:url, nil) || source&.fetch("url")
174
+
175
+ token = credentials
176
+ .select { |cred| cred["type"] == "nuget_feed" }
177
+ .find { |cred| cred["url"] == url }
178
+ &.fetch("token", nil)
179
+
180
+ return {} unless token
181
+
182
+ if token.include?(":")
183
+ encoded_token = Base64.encode64(token).delete("\n")
184
+ { "Authorization" => "Basic #{encoded_token}" }
185
+ elsif Base64.decode64(token).ascii_only? &&
186
+ Base64.decode64(token).include?(":")
187
+ { "Authorization" => "Basic #{token.delete("\n")}" }
188
+ else
189
+ { "Authorization" => "Bearer #{token}" }
190
+ end
191
+ end
192
+ # rubocop:enable Metrics/PerceivedComplexity
35
193
  end
36
194
  end
37
195
  end
@@ -4,6 +4,7 @@
4
4
  require "dependabot/nuget/native_discovery/native_dependency_file_discovery"
5
5
  require "dependabot/nuget/native_discovery/native_directory_packages_props_discovery"
6
6
  require "dependabot/nuget/native_discovery/native_project_discovery"
7
+ require "dependabot/nuget/native_helpers"
7
8
  require "sorbet-runtime"
8
9
 
9
10
  module Dependabot
@@ -13,6 +14,8 @@ module Dependabot
13
14
 
14
15
  sig { params(json: T::Hash[String, T.untyped]).returns(NativeWorkspaceDiscovery) }
15
16
  def self.from_json(json)
17
+ Dependabot::Nuget::NativeHelpers.ensure_no_errors(json)
18
+
16
19
  path = T.let(json.fetch("Path"), String)
17
20
  path = "/" + path unless path.start_with?("/")
18
21
  projects = T.let(json.fetch("Projects"), T::Array[T::Hash[String, T.untyped]]).filter_map do |project|
@@ -169,11 +169,12 @@ module Dependabot
169
169
  end
170
170
  end
171
171
 
172
+ # rubocop:disable Metrics/MethodLength
172
173
  sig do
173
174
  params(repo_root: String, proj_path: String, dependency: Dependency,
174
- is_transitive: T::Boolean).returns([String, String])
175
+ is_transitive: T::Boolean, result_output_path: String).returns([String, String])
175
176
  end
176
- def self.get_nuget_updater_tool_command(repo_root:, proj_path:, dependency:, is_transitive:)
177
+ def self.get_nuget_updater_tool_command(repo_root:, proj_path:, dependency:, is_transitive:, result_output_path:)
177
178
  exe_path = File.join(native_helpers_root, "NuGetUpdater", "NuGetUpdater.Cli")
178
179
  command_parts = [
179
180
  exe_path,
@@ -189,6 +190,8 @@ module Dependabot
189
190
  "--previous-version",
190
191
  dependency.previous_version,
191
192
  is_transitive ? "--transitive" : nil,
193
+ "--result-output-path",
194
+ result_output_path,
192
195
  "--verbose"
193
196
  ].compact
194
197
 
@@ -208,11 +211,19 @@ module Dependabot
208
211
  "--previous-version",
209
212
  "<previous-version>",
210
213
  is_transitive ? "--transitive" : nil,
214
+ "--result-output-path",
215
+ "<result-output-path>",
211
216
  "--verbose"
212
217
  ].compact.join(" ")
213
218
 
214
219
  [command, fingerprint]
215
220
  end
221
+ # rubocop:enable Metrics/MethodLength
222
+
223
+ sig { returns(String) }
224
+ def self.update_result_file_path
225
+ File.join(Dir.tmpdir, "update-result.json")
226
+ end
216
227
 
217
228
  sig do
218
229
  params(
@@ -225,13 +236,35 @@ module Dependabot
225
236
  end
226
237
  def self.run_nuget_updater_tool(repo_root:, proj_path:, dependency:, is_transitive:, credentials:)
227
238
  (command, fingerprint) = get_nuget_updater_tool_command(repo_root: repo_root, proj_path: proj_path,
228
- dependency: dependency, is_transitive: is_transitive)
239
+ dependency: dependency, is_transitive: is_transitive,
240
+ result_output_path: update_result_file_path)
229
241
 
230
242
  puts "running NuGet updater:\n" + command
231
243
 
232
244
  NuGetConfigCredentialHelpers.patch_nuget_config_for_action(credentials) do
233
245
  output = SharedHelpers.run_shell_command(command, allow_unsafe_shell_command: true, fingerprint: fingerprint)
234
246
  puts output
247
+
248
+ result_contents = File.read(update_result_file_path)
249
+ Dependabot.logger.info("update result: #{result_contents}")
250
+ result_json = T.let(JSON.parse(result_contents), T::Hash[String, T.untyped])
251
+ ensure_no_errors(result_json)
252
+ end
253
+ end
254
+
255
+ sig { params(json: T::Hash[String, T.untyped]).void }
256
+ def self.ensure_no_errors(json)
257
+ error_type = T.let(json.fetch("ErrorType", nil), T.nilable(String))
258
+ error_details = T.let(json.fetch("ErrorDetails", nil), T.nilable(String))
259
+ case error_type
260
+ when "None", nil
261
+ # no issue
262
+ when "AuthenticationFailure"
263
+ raise PrivateSourceAuthenticationFailure, error_details
264
+ when "MissingFile"
265
+ raise DependencyFileNotFound, error_details
266
+ else
267
+ raise "Unexpected error type from native tool: #{error_type}: #{error_details}"
235
268
  end
236
269
  end
237
270
  end
@@ -134,6 +134,7 @@ module Dependabot
134
134
  nil?
135
135
  end
136
136
 
137
+ Dependabot.logger.info("Writing dependency info: #{dependency_info}")
137
138
  File.write(dependency_file_path, dependency_info)
138
139
  end
139
140
 
@@ -68,6 +68,9 @@ module Dependabot
68
68
  add_credentials_to_nuget_config(credentials)
69
69
  begin
70
70
  yield
71
+ rescue DependabotError
72
+ # forward these
73
+ raise
71
74
  rescue StandardError => e
72
75
  log_message =
73
76
  <<~LOG_MESSAGE
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-nuget
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.265.0
4
+ version: 0.267.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-11 00:00:00.000000000 Z
11
+ date: 2024-07-25 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.265.0
19
+ version: 0.267.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.265.0
26
+ version: 0.267.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rubyzip
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -134,14 +134,14 @@ dependencies:
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 1.63.2
137
+ version: 1.65.0
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 1.63.2
144
+ version: 1.65.0
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: rubocop-performance
147
147
  requirement: !ruby/object:Gem::Requirement
@@ -328,6 +328,7 @@ files:
328
328
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs
329
329
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestBase.cs
330
330
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestExtensions.cs
331
+ - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestHttpServer.cs
331
332
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs
332
333
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs
333
334
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DirsProj.cs
@@ -369,6 +370,7 @@ files:
369
370
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs
370
371
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs
371
372
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs
373
+ - helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs
372
374
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/EvaluationResult.cs
373
375
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/EvaluationResultType.cs
374
376
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/BuildFile.cs
@@ -381,6 +383,8 @@ files:
381
383
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/CompatabilityChecker.cs
382
384
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/FrameworkCompatibilityService.cs
383
385
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/SupportedFrameworks.cs
386
+ - helpers/lib/NuGetUpdater/NuGetUpdater.Core/MissingFileException.cs
387
+ - helpers/lib/NuGetUpdater/NuGetUpdater.Core/NativeResult.cs
384
388
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/NuGetUpdater.Core.csproj
385
389
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Property.cs
386
390
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs
@@ -390,6 +394,7 @@ files:
390
394
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/GlobalJsonUpdater.cs
391
395
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs
392
396
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs
397
+ - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateOperationResult.cs
393
398
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdateResult.cs
394
399
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs
395
400
  - helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs
@@ -456,7 +461,7 @@ licenses:
456
461
  - MIT
457
462
  metadata:
458
463
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
459
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.265.0
464
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.267.0
460
465
  post_install_message:
461
466
  rdoc_options: []
462
467
  require_paths: