dependabot-nuget 0.288.0 → 0.290.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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/Directory.Packages.props +19 -17
  3. data/helpers/lib/NuGetUpdater/NuGetProjects/NuGet.Packaging/NuGet.Packaging.csproj +0 -1
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +7 -3
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +1 -1
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +29 -2
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +25 -4
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +0 -6
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +33 -16
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +25 -10
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +0 -13
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementArrayConverter.cs +39 -0
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/VersionFinder.cs +1 -1
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Clone/ShellGitCommandHandler.cs +1 -1
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +60 -66
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DotNetToolsJsonDiscovery.cs +2 -2
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/GlobalJsonDiscovery.cs +2 -2
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +11 -3
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscoveryResult.cs +1 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +2 -4
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +54 -11
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/WorkspaceDiscoveryResult.cs +0 -1
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +1 -2
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Files/JsonBuildFile.cs +1 -1
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/FrameworkChecker/CompatabilityChecker.cs +2 -2
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs +13 -0
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/AllowedUpdate.cs +18 -1
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CommitOptions.cs +8 -0
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Condition.cs +19 -0
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +8 -0
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/GroupPullRequest.cs +9 -0
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +13 -10
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequest.cs +11 -0
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/RequirementsUpdateStrategy.cs +15 -0
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +67 -58
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/VersionConverter.cs +19 -0
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +15 -44
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/DotNetToolsJsonUpdater.cs +4 -4
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/GlobalJsonUpdater.cs +5 -5
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +2 -10
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +38 -33
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +25 -23
  43. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +16 -12
  44. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ConsoleLogger.cs +1 -1
  45. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/DependencyConflictResolver.cs +19 -19
  46. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ILogger.cs +11 -1
  47. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +2 -0
  48. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +18 -17
  49. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +1 -17
  50. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +17 -9
  51. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProjectHelper.cs +96 -0
  52. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +5 -2
  53. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTests.cs +87 -5
  54. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTestBase.cs +2 -5
  55. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.DotNetToolsJson.cs +45 -1
  56. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs +35 -1
  57. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.PackagesConfig.cs +16 -0
  58. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Proj.cs +6 -0
  59. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +143 -36
  60. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +184 -48
  61. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +5 -5
  62. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +32 -10
  63. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +85 -0
  64. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +402 -102
  65. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +342 -2
  66. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/UpdatedDependencyListTests.cs +60 -2
  67. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs +18 -7
  68. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TestLogger.cs +1 -1
  69. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/BindingRedirectsTests.cs +1 -1
  70. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +24 -0
  71. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +4 -14
  72. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +84 -0
  73. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +66 -0
  74. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +95 -0
  75. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +1 -7
  76. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/AssertEx.cs +1 -1
  77. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/LinuxOnlyAttribute.cs +12 -0
  78. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +558 -711
  79. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +47 -2
  80. data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +4 -2
  81. data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -3
  82. data/lib/dependabot/nuget/discovery/dependency_details.rb +10 -3
  83. data/lib/dependabot/nuget/discovery/dependency_file_discovery.rb +8 -12
  84. data/lib/dependabot/nuget/discovery/discovery_json_reader.rb +214 -29
  85. data/lib/dependabot/nuget/discovery/project_discovery.rb +41 -8
  86. data/lib/dependabot/nuget/discovery/workspace_discovery.rb +14 -19
  87. data/lib/dependabot/nuget/file_fetcher.rb +11 -393
  88. data/lib/dependabot/nuget/file_parser.rb +23 -61
  89. data/lib/dependabot/nuget/file_updater.rb +28 -23
  90. data/lib/dependabot/nuget/native_helpers.rb +14 -5
  91. data/lib/dependabot/nuget/update_checker/requirements_updater.rb +23 -27
  92. data/lib/dependabot/nuget/update_checker.rb +116 -190
  93. metadata +20 -32
  94. data/helpers/lib/NuGetUpdater/NuGetProjects/Directory.Packages.props +0 -29
  95. data/lib/dependabot/nuget/discovery/directory_packages_props_discovery.rb +0 -43
  96. data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +0 -73
  97. data/lib/dependabot/nuget/file_fetcher/sln_project_paths_finder.rb +0 -60
  98. data/lib/dependabot/nuget/http_response_helpers.rb +0 -19
  99. data/lib/dependabot/nuget/native_discovery/native_dependency_details.rb +0 -102
  100. data/lib/dependabot/nuget/native_discovery/native_dependency_file_discovery.rb +0 -129
  101. data/lib/dependabot/nuget/native_discovery/native_discovery_json_reader.rb +0 -171
  102. data/lib/dependabot/nuget/native_discovery/native_evaluation_details.rb +0 -63
  103. data/lib/dependabot/nuget/native_discovery/native_project_discovery.rb +0 -82
  104. data/lib/dependabot/nuget/native_discovery/native_property_details.rb +0 -43
  105. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +0 -68
  106. data/lib/dependabot/nuget/native_update_checker/native_requirements_updater.rb +0 -105
  107. data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +0 -201
  108. data/lib/dependabot/nuget/nuget_client.rb +0 -223
  109. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +0 -116
  110. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +0 -297
  111. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +0 -221
  112. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +0 -110
  113. data/lib/dependabot/nuget/update_checker/property_updater.rb +0 -196
  114. data/lib/dependabot/nuget/update_checker/repository_finder.rb +0 -466
  115. data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +0 -34
  116. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +0 -30
  117. data/lib/dependabot/nuget/update_checker/version_finder.rb +0 -449
@@ -1,297 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "nokogiri"
5
- require "sorbet-runtime"
6
- require "stringio"
7
- require "zip"
8
-
9
- require "dependabot/update_checkers/base"
10
- require "dependabot/nuget/version"
11
-
12
- module Dependabot
13
- module Nuget
14
- class UpdateChecker < Dependabot::UpdateCheckers::Base
15
- class DependencyFinder
16
- extend T::Sig
17
-
18
- require_relative "requirements_updater"
19
- require_relative "nuspec_fetcher"
20
-
21
- sig { returns(T::Hash[String, T.untyped]) }
22
- def self.transitive_dependencies_cache
23
- CacheManager.cache("dependency_finder_transitive_dependencies")
24
- end
25
-
26
- sig { returns(T::Hash[String, T.untyped]) }
27
- def self.updated_peer_dependencies_cache
28
- CacheManager.cache("dependency_finder_updated_peer_dependencies")
29
- end
30
-
31
- sig { returns(T::Hash[String, T.untyped]) }
32
- def self.fetch_dependencies_cache
33
- CacheManager.cache("dependency_finder_fetch_dependencies")
34
- end
35
-
36
- sig do
37
- params(
38
- dependency: Dependabot::Dependency,
39
- dependency_files: T::Array[Dependabot::DependencyFile],
40
- ignored_versions: T::Array[String],
41
- credentials: T::Array[Dependabot::Credential],
42
- repo_contents_path: T.nilable(String)
43
- ).void
44
- end
45
- def initialize(dependency:, dependency_files:, ignored_versions:, credentials:, repo_contents_path:)
46
- @dependency = dependency
47
- @dependency_files = dependency_files
48
- @ignored_versions = ignored_versions
49
- @credentials = credentials
50
- @repo_contents_path = repo_contents_path
51
- end
52
-
53
- sig { returns(T::Array[Dependabot::Dependency]) }
54
- def transitive_dependencies
55
- key = "#{dependency.name.downcase}::#{dependency.version}"
56
- cache = DependencyFinder.transitive_dependencies_cache
57
-
58
- unless cache[key]
59
- begin
60
- # first do a quick sanity check on the version string; if it can't be parsed, an exception will be raised
61
- _ = Version.new(dependency.version)
62
-
63
- cache[key] = fetch_transitive_dependencies(
64
- @dependency.name,
65
- T.must(@dependency.version)
66
- ).map do |dependency_info|
67
- package_name = dependency_info["packageName"]
68
- target_version = dependency_info["version"]
69
-
70
- Dependency.new(
71
- name: package_name,
72
- version: target_version.to_s,
73
- requirements: [], # Empty requirements for transitive dependencies
74
- package_manager: @dependency.package_manager
75
- )
76
- end
77
- rescue StandardError
78
- # if anything happened above, there are no meaningful dependencies that can be derived
79
- cache[key] = []
80
- end
81
- end
82
-
83
- cache[key]
84
- end
85
-
86
- sig { returns(T::Array[Dependabot::Dependency]) }
87
- def updated_peer_dependencies
88
- key = "#{dependency.name.downcase}::#{dependency.version}"
89
- cache = DependencyFinder.updated_peer_dependencies_cache
90
-
91
- cache[key] ||= fetch_transitive_dependencies(
92
- @dependency.name,
93
- T.must(@dependency.version)
94
- ).filter_map do |dependency_info|
95
- package_name = dependency_info["packageName"]
96
- target_version = dependency_info["version"]
97
-
98
- # Find the Dependency object for the peer dependency. We will not return
99
- # dependencies that are not referenced from dependency files.
100
- peer_dependency = top_level_dependencies.find { |d| d.name == package_name }
101
- next unless peer_dependency
102
- next unless target_version > peer_dependency.numeric_version
103
-
104
- # Use version finder to determine the source details for the peer dependency.
105
- target_version_details = version_finder(peer_dependency).versions.find do |v|
106
- v.fetch(:version) == target_version
107
- end
108
- next unless target_version_details
109
-
110
- Dependency.new(
111
- name: peer_dependency.name,
112
- version: target_version_details.fetch(:version).to_s,
113
- requirements: updated_requirements(peer_dependency, target_version_details),
114
- previous_version: peer_dependency.version,
115
- previous_requirements: peer_dependency.requirements,
116
- package_manager: peer_dependency.package_manager,
117
- metadata: { information_only: true } # Instruct updater to not directly update this dependency
118
- )
119
- end
120
-
121
- cache[key]
122
- end
123
-
124
- private
125
-
126
- sig { returns(Dependabot::Dependency) }
127
- attr_reader :dependency
128
-
129
- sig { returns(T::Array[Dependabot::DependencyFile]) }
130
- attr_reader :dependency_files
131
-
132
- sig { returns(T::Array[String]) }
133
- attr_reader :ignored_versions
134
-
135
- sig { returns(T::Array[Dependabot::Credential]) }
136
- attr_reader :credentials
137
-
138
- sig { returns(T.nilable(String)) }
139
- attr_reader :repo_contents_path
140
-
141
- sig do
142
- params(
143
- dep: Dependabot::Dependency,
144
- target_version_details: T::Hash[Symbol, T.untyped]
145
- )
146
- .returns(T::Array[T::Hash[String, T.untyped]])
147
- end
148
- def updated_requirements(dep, target_version_details)
149
- @updated_requirements ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
150
- @updated_requirements[dep.name] ||=
151
- RequirementsUpdater.new(
152
- requirements: dep.requirements,
153
- latest_version: target_version_details.fetch(:version).to_s,
154
- source_details: target_version_details.slice(:nuspec_url, :repo_url, :source_url)
155
- ).updated_requirements
156
- end
157
-
158
- sig { returns(T::Array[Dependabot::Dependency]) }
159
- def top_level_dependencies
160
- @top_level_dependencies ||=
161
- T.let(
162
- Nuget::FileParser.new(
163
- dependency_files: dependency_files,
164
- repo_contents_path: repo_contents_path,
165
- source: nil
166
- ).parse.select(&:top_level?),
167
- T.nilable(T::Array[Dependabot::Dependency])
168
- )
169
- end
170
-
171
- sig { returns(T::Array[Dependabot::DependencyFile]) }
172
- def nuget_configs
173
- @nuget_configs ||=
174
- T.let(
175
- @dependency_files.select { |f| f.name.match?(/nuget\.config$/i) },
176
- T.nilable(T::Array[Dependabot::DependencyFile])
177
- )
178
- end
179
-
180
- sig { returns(T::Array[T::Hash[Symbol, String]]) }
181
- def dependency_urls
182
- @dependency_urls ||=
183
- T.let(
184
- RepositoryFinder.new(
185
- dependency: @dependency,
186
- credentials: @credentials,
187
- config_files: nuget_configs
188
- )
189
- .dependency_urls
190
- .select { |url| url.fetch(:repository_type) == "v3" },
191
- T.nilable(T::Array[T::Hash[Symbol, String]])
192
- )
193
- end
194
-
195
- sig { params(package_id: String, package_version: String).returns(T::Array[T::Hash[String, T.untyped]]) }
196
- def fetch_transitive_dependencies(package_id, package_version)
197
- all_dependencies = {}
198
- fetch_transitive_dependencies_impl(package_id, package_version, all_dependencies)
199
- all_dependencies.map { |_, dependency_info| dependency_info }
200
- end
201
-
202
- sig { params(package_id: String, package_version: String, all_dependencies: T::Hash[String, T.untyped]).void }
203
- def fetch_transitive_dependencies_impl(package_id, package_version, all_dependencies)
204
- dependencies = fetch_dependencies(package_id, package_version)
205
- return unless dependencies.any?
206
-
207
- dependencies.each do |dependency|
208
- next if dependency.nil?
209
-
210
- dependency_id = dependency["packageName"]
211
- dependency_version_range = dependency["versionRange"]
212
-
213
- nuget_version_range_regex = /[\[(](\d+(\.\d+)*(-\w+(\.\d+)*)?)/
214
- nuget_version_range_match_data = nuget_version_range_regex.match(dependency_version_range)
215
-
216
- dependency_version = if nuget_version_range_match_data.nil?
217
- dependency_version_range
218
- else
219
- nuget_version_range_match_data[1]
220
- end
221
-
222
- dependency["version"] = Version.new(dependency_version)
223
-
224
- current_dependency = all_dependencies[dependency_id.downcase]
225
- next unless current_dependency.nil? || current_dependency["version"] < dependency["version"]
226
-
227
- all_dependencies[dependency_id.downcase] = dependency
228
- fetch_transitive_dependencies_impl(dependency_id, dependency_version, all_dependencies)
229
- end
230
- end
231
-
232
- sig { params(package_id: String, package_version: String).returns(T::Array[T::Hash[String, T.untyped]]) }
233
- def fetch_dependencies(package_id, package_version)
234
- key = "#{package_id.downcase}::#{package_version}"
235
- cache = DependencyFinder.fetch_dependencies_cache
236
-
237
- cache[key] ||= begin
238
- nuspec_xml = NuspecFetcher.fetch_nuspec(dependency_urls, package_id, package_version)
239
- if nuspec_xml.nil?
240
- []
241
- else
242
- read_dependencies_from_nuspec(nuspec_xml)
243
- end
244
- end
245
-
246
- cache[key]
247
- end
248
-
249
- sig { params(nuspec_xml: Nokogiri::XML::Document).returns(T::Array[T::Hash[String, String]]) }
250
- def read_dependencies_from_nuspec(nuspec_xml) # rubocop:disable Metrics/PerceivedComplexity
251
- # we want to exclude development dependencies from the lookup
252
- allowed_attributes = %w(all compile native runtime)
253
-
254
- nuspec_xml_dependencies = nuspec_xml.xpath("//dependencies/child::node()/dependency").select do |dependency|
255
- include_attr = dependency.attribute("include")
256
- exclude_attr = dependency.attribute("exclude")
257
-
258
- if include_attr.nil? && exclude_attr.nil?
259
- true
260
- elsif include_attr
261
- include_values = include_attr.value.split(",").map(&:strip)
262
- include_values.any? { |element1| allowed_attributes.any? { |element2| element1.casecmp?(element2) } }
263
- else
264
- exclude_values = exclude_attr.value.split(",").map(&:strip)
265
- exclude_values.none? { |element1| allowed_attributes.any? { |element2| element1.casecmp?(element2) } }
266
- end
267
- end
268
-
269
- dependency_list = []
270
- nuspec_xml_dependencies.each do |dependency|
271
- next unless dependency.attribute("version")
272
-
273
- dependency_list << {
274
- "packageName" => dependency.attribute("id").value,
275
- "versionRange" => dependency.attribute("version").value
276
- }
277
- end
278
-
279
- dependency_list
280
- end
281
-
282
- sig { params(dep: Dependabot::Dependency).returns(Dependabot::Nuget::UpdateChecker::VersionFinder) }
283
- def version_finder(dep)
284
- VersionFinder.new(
285
- dependency: dep,
286
- dependency_files: dependency_files,
287
- credentials: credentials,
288
- ignored_versions: ignored_versions,
289
- raise_on_ignored: false,
290
- security_advisories: [],
291
- repo_contents_path: repo_contents_path
292
- )
293
- end
294
- end
295
- end
296
- end
297
- end
@@ -1,221 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "nokogiri"
5
- require "stringio"
6
- require "sorbet-runtime"
7
- require "zip"
8
-
9
- require "dependabot/nuget/http_response_helpers"
10
-
11
- module Dependabot
12
- module Nuget
13
- class NupkgFetcher
14
- extend T::Sig
15
-
16
- require_relative "repository_finder"
17
-
18
- sig do
19
- params(
20
- dependency_urls: T::Array[T::Hash[Symbol, String]],
21
- package_id: String,
22
- package_version: String
23
- )
24
- .returns(T.nilable(String))
25
- end
26
- def self.fetch_nupkg_buffer(dependency_urls, package_id, package_version)
27
- # check all repositories for the first one that has the nupkg
28
- dependency_urls.reduce(T.let(nil, T.nilable(String))) do |nupkg_buffer, repository_details|
29
- nupkg_buffer || fetch_nupkg_buffer_from_repository(repository_details, package_id, package_version)
30
- end
31
- end
32
-
33
- sig do
34
- params(
35
- repository_details: T::Hash[Symbol, T.untyped],
36
- package_id: T.nilable(String),
37
- package_version: T.nilable(String)
38
- )
39
- .returns(T.nilable(String))
40
- end
41
- def self.fetch_nupkg_url_from_repository(repository_details, package_id, package_version)
42
- return unless package_id && package_version && !package_version.empty?
43
-
44
- feed_url = repository_details[:repository_url]
45
- repository_type = repository_details[:repository_type]
46
-
47
- package_url = if repository_type == "v2"
48
- get_nuget_v2_package_url(repository_details, package_id, package_version)
49
- elsif repository_type == "v3"
50
- get_nuget_v3_package_url(repository_details, package_id, package_version)
51
- else
52
- raise Dependabot::DependencyFileNotResolvable, "Unexpected NuGet feed format: #{feed_url}"
53
- end
54
-
55
- package_url
56
- end
57
-
58
- sig do
59
- params(
60
- repository_details: T::Hash[Symbol, T.untyped],
61
- package_id: String,
62
- package_version: String
63
- )
64
- .returns(T.nilable(String))
65
- end
66
- def self.fetch_nupkg_buffer_from_repository(repository_details, package_id, package_version)
67
- package_url = fetch_nupkg_url_from_repository(repository_details, package_id, package_version)
68
- return unless package_url
69
-
70
- auth_header = repository_details[:auth_header]
71
- fetch_stream(package_url, auth_header)
72
- end
73
-
74
- sig do
75
- params(
76
- repository_details: T::Hash[Symbol, T.untyped],
77
- package_id: String,
78
- package_version: String
79
- )
80
- .returns(T.nilable(String))
81
- end
82
- def self.get_nuget_v3_package_url(repository_details, package_id, package_version)
83
- base_url = repository_details[:base_url]
84
- unless base_url
85
- return get_nuget_v3_package_url_from_search(repository_details, package_id,
86
- package_version)
87
- end
88
-
89
- base_url = base_url.delete_suffix("/")
90
- package_id_downcased = package_id.downcase
91
- "#{base_url}/#{package_id_downcased}/#{package_version}/#{package_id_downcased}.#{package_version}.nupkg"
92
- end
93
-
94
- # rubocop:disable Metrics/CyclomaticComplexity
95
- # rubocop:disable Metrics/PerceivedComplexity
96
- sig do
97
- params(
98
- repository_details: T::Hash[Symbol, T.untyped],
99
- package_id: String,
100
- package_version: String
101
- )
102
- .returns(T.nilable(String))
103
- end
104
- def self.get_nuget_v3_package_url_from_search(repository_details, package_id, package_version)
105
- search_url = repository_details[:search_url]
106
- return nil unless search_url
107
-
108
- # get search result
109
- search_result_response = fetch_url(search_url, repository_details)
110
- return nil unless search_result_response&.status == 200
111
-
112
- search_response_body = HttpResponseHelpers.remove_wrapping_zero_width_chars(T.must(search_result_response).body)
113
- search_results = JSON.parse(search_response_body)
114
-
115
- # find matching package and version
116
- package_search_result = search_results&.[]("data")&.find { |d| package_id.casecmp?(d&.[]("id")) }
117
- version_search_result = package_search_result&.[]("versions")&.find do |v|
118
- package_version.casecmp?(v&.[]("version"))
119
- end
120
- registration_leaf_url = version_search_result&.[]("@id")
121
- return nil unless registration_leaf_url
122
-
123
- registration_leaf_response = fetch_url(registration_leaf_url, repository_details)
124
- return nil unless registration_leaf_response
125
- return nil unless registration_leaf_response.status == 200
126
-
127
- registration_leaf_response_body =
128
- HttpResponseHelpers.remove_wrapping_zero_width_chars(registration_leaf_response.body)
129
- registration_leaf = JSON.parse(registration_leaf_response_body)
130
-
131
- # finally, get the .nupkg url
132
- registration_leaf&.[]("packageContent")
133
- end
134
- # rubocop:enable Metrics/PerceivedComplexity
135
- # rubocop:enable Metrics/CyclomaticComplexity
136
-
137
- sig do
138
- params(
139
- repository_details: T::Hash[Symbol, T.untyped],
140
- package_id: String,
141
- package_version: String
142
- )
143
- .returns(T.nilable(String))
144
- end
145
- def self.get_nuget_v2_package_url(repository_details, package_id, package_version)
146
- # get package XML
147
- base_url = repository_details[:base_url].delete_suffix("/")
148
- package_url = "#{base_url}/Packages(Id='#{package_id}',Version='#{package_version}')"
149
- response = fetch_url(package_url, repository_details)
150
- return nil unless response&.status == 200
151
-
152
- # find relevant element
153
- doc = Nokogiri::XML(T.must(response).body)
154
- doc.remove_namespaces!
155
-
156
- content_element = doc.xpath("/entry/content")
157
- nupkg_url = content_element&.attribute("src")&.value
158
- nupkg_url
159
- end
160
-
161
- sig do
162
- params(
163
- stream_url: String,
164
- auth_header: T::Hash[String, String],
165
- max_redirects: Integer
166
- )
167
- .returns(T.nilable(String))
168
- end
169
- def self.fetch_stream(stream_url, auth_header, max_redirects = 5)
170
- current_url = stream_url
171
- current_redirects = 0
172
-
173
- loop do
174
- # Directly download the stream without any additional settings _except_ for `omit_default_port: true` which
175
- # is necessary to not break the URL signing that some NuGet feeds use.
176
- response = Excon.get(
177
- current_url,
178
- headers: auth_header,
179
- omit_default_port: true
180
- )
181
-
182
- # redirect the HTTP response as appropriate based on documentation here:
183
- # https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
184
- case response.status
185
- when 200
186
- return response.body
187
- when 301, 302, 303, 307, 308
188
- current_redirects += 1
189
- return nil if current_redirects > max_redirects
190
-
191
- current_url = T.must(response.headers["Location"])
192
- else
193
- return nil
194
- end
195
- end
196
- end
197
-
198
- sig do
199
- params(
200
- url: String,
201
- repository_details: T::Hash[Symbol, T.untyped]
202
- )
203
- .returns(T.nilable(Excon::Response))
204
- end
205
- def self.fetch_url(url, repository_details)
206
- fetch_url_with_auth(url, repository_details.fetch(:auth_header))
207
- end
208
-
209
- sig { params(url: String, auth_header: T::Hash[T.any(String, Symbol), T.untyped]).returns(Excon::Response) }
210
- def self.fetch_url_with_auth(url, auth_header)
211
- cache = CacheManager.cache("nupkg_fetcher_cache")
212
- cache[url] ||= Dependabot::RegistryClient.get(
213
- url: url,
214
- headers: auth_header
215
- )
216
-
217
- cache[url]
218
- end
219
- end
220
- end
221
- end
@@ -1,110 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "nokogiri"
5
- require "stringio"
6
- require "sorbet-runtime"
7
- require "zip"
8
-
9
- module Dependabot
10
- module Nuget
11
- class NuspecFetcher
12
- extend T::Sig
13
-
14
- require_relative "nupkg_fetcher"
15
- require_relative "repository_finder"
16
-
17
- sig do
18
- params(
19
- dependency_urls: T::Array[T::Hash[Symbol, String]],
20
- package_id: String,
21
- package_version: T.nilable(String)
22
- )
23
- .returns(T.nilable(Nokogiri::XML::Document))
24
- end
25
- def self.fetch_nuspec(dependency_urls, package_id, package_version)
26
- # check all repositories for the first one that has the nuspec
27
- dependency_urls.reduce(T.let(nil, T.nilable(Nokogiri::XML::Document))) do |nuspec_xml, repository_details|
28
- nuspec_xml || fetch_nuspec_from_repository(repository_details, package_id, package_version)
29
- end
30
- end
31
-
32
- sig do
33
- params(
34
- repository_details: T::Hash[Symbol, T.untyped],
35
- package_id: T.nilable(String),
36
- package_version: T.nilable(String)
37
- )
38
- .returns(T.nilable(Nokogiri::XML::Document))
39
- end
40
- def self.fetch_nuspec_from_repository(repository_details, package_id, package_version)
41
- return unless package_id && package_version && !package_version.empty?
42
-
43
- feed_url = repository_details[:repository_url]
44
- auth_header = repository_details[:auth_header]
45
-
46
- nuspec_xml = nil
47
-
48
- if feed_supports_nuspec_download?(feed_url)
49
- # we can use the normal nuget apis to get the nuspec and list out the dependencies
50
- base_url = repository_details[:base_url].delete_suffix("/")
51
- package_id_downcased = package_id.downcase
52
- nuspec_url = "#{base_url}/#{package_id_downcased}/#{package_version}/#{package_id_downcased}.nuspec"
53
-
54
- nuspec_response = Dependabot::RegistryClient.get(
55
- url: nuspec_url,
56
- headers: auth_header
57
- )
58
-
59
- return unless nuspec_response.status == 200
60
-
61
- nuspec_response_body = remove_invalid_characters(nuspec_response.body)
62
- nuspec_xml = Nokogiri::XML(nuspec_response_body)
63
- else
64
- # no guarantee we can directly query the .nuspec; fall back to extracting it from the .nupkg
65
- package_data = NupkgFetcher.fetch_nupkg_buffer_from_repository(repository_details, package_id,
66
- package_version)
67
- return if package_data.nil?
68
-
69
- nuspec_string = extract_nuspec(package_data, package_id)
70
- nuspec_xml = Nokogiri::XML(nuspec_string)
71
- end
72
-
73
- nuspec_xml.remove_namespaces!
74
- nuspec_xml
75
- end
76
-
77
- sig { params(feed_url: String).returns(T::Boolean) }
78
- def self.feed_supports_nuspec_download?(feed_url)
79
- feed_regexs = [
80
- # nuget
81
- %r{https://api\.nuget\.org/v3/index\.json},
82
- # azure devops
83
- %r{https://pkgs\.dev\.azure\.com/(?<organization>[^/]+)/(?<project>[^/]+)/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json},
84
- %r{https://pkgs\.dev\.azure\.com/(?<organization>[^/]+)/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json(?<project>)},
85
- %r{https://(?<organization>[^\.\/]+)\.pkgs\.visualstudio\.com/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json(?<project>)}
86
- ]
87
- feed_regexs.any? { |reg| reg.match(feed_url) }
88
- end
89
-
90
- sig { params(zip_stream: String, package_id: String).returns(T.nilable(String)) }
91
- def self.extract_nuspec(zip_stream, package_id)
92
- Zip::File.open_buffer(zip_stream) do |zip|
93
- nuspec_entry = zip.find { |entry| entry.name == "#{package_id}.nuspec" }
94
- return nuspec_entry.get_input_stream.read if nuspec_entry
95
- end
96
- nil
97
- end
98
-
99
- sig { params(string: String).returns(String) }
100
- def self.remove_invalid_characters(string)
101
- string.dup
102
- .force_encoding(Encoding::UTF_8)
103
- .encode
104
- .scrub("")
105
- .gsub(/\A[\u200B-\u200D\uFEFF]/, "")
106
- .gsub(/[\u200B-\u200D\uFEFF]\Z/, "")
107
- end
108
- end
109
- end
110
- end