dependabot-nuget 0.289.0 → 0.291.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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/Directory.Packages.props +1 -1
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +7 -3
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +1 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +26 -1
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +2 -1
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +0 -6
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +1 -1
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +6 -1
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +24 -9
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +2 -0
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +0 -13
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementConverter.cs +17 -0
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +44 -5
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +2 -2
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +2 -0
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +19 -11
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +1 -0
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs +13 -0
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/AllowedUpdate.cs +18 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CommitOptions.cs +8 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Condition.cs +19 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +8 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/GroupPullRequest.cs +9 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +13 -10
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequest.cs +11 -0
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/RequirementsUpdateStrategy.cs +15 -0
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +24 -4
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/VersionConverter.cs +19 -0
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +2 -1
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +3 -2
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +43 -18
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +13 -12
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +1 -1
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +2 -0
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +40 -14
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +2 -2
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +45 -7
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProjectHelper.cs +2 -2
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +5 -2
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.DotNetToolsJson.cs +45 -1
  43. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs +35 -1
  44. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +0 -4
  45. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +41 -0
  46. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -0
  47. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +1 -1
  48. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +2 -1
  49. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +85 -0
  50. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +7 -31
  51. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +340 -0
  52. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs +18 -7
  53. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +24 -0
  54. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +0 -12
  55. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +84 -0
  56. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +66 -0
  57. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +55 -0
  58. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +0 -6
  59. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +785 -755
  60. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +2 -2
  61. data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +1 -1
  62. data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -3
  63. data/lib/dependabot/nuget/discovery/dependency_details.rb +10 -3
  64. data/lib/dependabot/nuget/discovery/dependency_file_discovery.rb +8 -12
  65. data/lib/dependabot/nuget/discovery/discovery_json_reader.rb +214 -29
  66. data/lib/dependabot/nuget/discovery/project_discovery.rb +41 -8
  67. data/lib/dependabot/nuget/discovery/workspace_discovery.rb +14 -19
  68. data/lib/dependabot/nuget/file_fetcher.rb +3 -3
  69. data/lib/dependabot/nuget/file_parser.rb +92 -3
  70. data/lib/dependabot/nuget/file_updater.rb +13 -13
  71. data/lib/dependabot/nuget/language.rb +82 -0
  72. data/lib/dependabot/nuget/native_helpers.rb +37 -5
  73. data/lib/dependabot/nuget/package_manager.rb +51 -0
  74. data/lib/dependabot/nuget/update_checker/requirements_updater.rb +23 -27
  75. data/lib/dependabot/nuget/update_checker.rb +116 -190
  76. metadata +20 -29
  77. data/lib/dependabot/nuget/discovery/directory_packages_props_discovery.rb +0 -43
  78. data/lib/dependabot/nuget/http_response_helpers.rb +0 -19
  79. data/lib/dependabot/nuget/native_discovery/native_dependency_details.rb +0 -102
  80. data/lib/dependabot/nuget/native_discovery/native_dependency_file_discovery.rb +0 -122
  81. data/lib/dependabot/nuget/native_discovery/native_discovery_json_reader.rb +0 -277
  82. data/lib/dependabot/nuget/native_discovery/native_evaluation_details.rb +0 -63
  83. data/lib/dependabot/nuget/native_discovery/native_project_discovery.rb +0 -104
  84. data/lib/dependabot/nuget/native_discovery/native_property_details.rb +0 -43
  85. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +0 -61
  86. data/lib/dependabot/nuget/native_update_checker/native_requirements_updater.rb +0 -105
  87. data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +0 -214
  88. data/lib/dependabot/nuget/nuget_client.rb +0 -223
  89. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +0 -116
  90. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +0 -297
  91. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +0 -221
  92. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +0 -110
  93. data/lib/dependabot/nuget/update_checker/property_updater.rb +0 -196
  94. data/lib/dependabot/nuget/update_checker/repository_finder.rb +0 -466
  95. data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +0 -34
  96. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +0 -30
  97. data/lib/dependabot/nuget/update_checker/version_finder.rb +0 -449
@@ -1,466 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "excon"
5
- require "nokogiri"
6
- require "sorbet-runtime"
7
-
8
- require "dependabot/errors"
9
- require "dependabot/update_checkers/base"
10
- require "dependabot/registry_client"
11
- require "dependabot/nuget/cache_manager"
12
- require "dependabot/nuget/http_response_helpers"
13
-
14
- module Dependabot
15
- module Nuget
16
- # rubocop:disable Metrics/ClassLength
17
- class RepositoryFinder
18
- extend T::Sig
19
-
20
- DEFAULT_REPOSITORY_URL = "https://api.nuget.org/v3/index.json"
21
- DEFAULT_REPOSITORY_API_KEY = "nuget.org"
22
-
23
- sig do
24
- params(
25
- dependency: Dependabot::Dependency,
26
- credentials: T::Array[Dependabot::Credential],
27
- config_files: T::Array[Dependabot::DependencyFile]
28
- ).void
29
- end
30
- def initialize(dependency:, credentials:, config_files: [])
31
- @dependency = dependency
32
- @credentials = credentials
33
- @config_files = config_files
34
- end
35
-
36
- sig { returns(T::Array[T::Hash[Symbol, String]]) }
37
- def dependency_urls
38
- find_dependency_urls
39
- end
40
-
41
- sig { returns(T::Array[T::Hash[Symbol, String]]) }
42
- def known_repositories
43
- return @known_repositories if @known_repositories
44
-
45
- @known_repositories ||= T.let([], T.nilable(T::Array[T::Hash[Symbol, String]]))
46
- @known_repositories += credential_repositories
47
- @known_repositories += config_file_repositories
48
-
49
- @known_repositories << { url: DEFAULT_REPOSITORY_URL, token: nil } if @known_repositories.empty?
50
-
51
- @known_repositories = @known_repositories.map do |repo|
52
- url = repo[:url]
53
- begin
54
- url = URI::DEFAULT_PARSER.parse(url).to_s
55
- rescue URI::InvalidURIError
56
- # e.g., the url has spaces or unacceptable symbols
57
- url = URI::DEFAULT_PARSER.escape(url)
58
- end
59
-
60
- { url: url, token: repo[:token] }
61
- end
62
- @known_repositories.uniq
63
- end
64
-
65
- sig { params(dependency_name: String).returns(T::Hash[Symbol, T.untyped]) }
66
- def self.get_default_repository_details(dependency_name)
67
- {
68
- base_url: "https://api.nuget.org/v3-flatcontainer/",
69
- registration_url: "https://api.nuget.org/v3/registration5-gz-semver2/#{dependency_name.downcase}/index.json",
70
- repository_url: DEFAULT_REPOSITORY_URL,
71
- versions_url: "https://api.nuget.org/v3-flatcontainer/" \
72
- "#{dependency_name.downcase}/index.json",
73
- search_url: "https://azuresearch-usnc.nuget.org/query" \
74
- "?q=#{dependency_name.downcase}&prerelease=true&semVerLevel=2.0.0",
75
- auth_header: {},
76
- repository_type: "v3"
77
- }
78
- end
79
-
80
- sig { params(source_name: String).returns(String) }
81
- def self.escape_source_name_to_element_name(source_name)
82
- source_name.chars.map do |c|
83
- case c
84
- when /[A-Za-z0-9\-_.]/
85
- # letters, digits, hyphens, underscores, and periods are all directly allowed
86
- c
87
- else
88
- # otherwise it needs to be escaped as a 4 digit hex value
89
- "_x#{c.ord.to_s(16).rjust(4, '0')}_"
90
- end
91
- end.join
92
- end
93
-
94
- private
95
-
96
- sig { returns(Dependabot::Dependency) }
97
- attr_reader :dependency
98
-
99
- sig { returns(T::Array[Dependabot::Credential]) }
100
- attr_reader :credentials
101
-
102
- sig { returns(T::Array[Dependabot::DependencyFile]) }
103
- attr_reader :config_files
104
-
105
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
106
- def find_dependency_urls
107
- @find_dependency_urls ||=
108
- T.let(
109
- known_repositories.flat_map do |details|
110
- if details.fetch(:url) == DEFAULT_REPOSITORY_URL
111
- # Save a request for the default URL, since we already know how
112
- # it addresses packages
113
- next default_repository_details
114
- end
115
-
116
- build_url_for_details(details)
117
- end.compact.uniq,
118
- T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
119
- )
120
- end
121
-
122
- sig { params(repo_details: T::Hash[Symbol, T.untyped]).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
123
- def build_url_for_details(repo_details)
124
- url = repo_details.fetch(:url)
125
- url_obj = URI.parse(url)
126
- if url_obj.is_a?(URI::HTTP)
127
- details = build_url_for_details_remote(repo_details)
128
- elsif url_obj.is_a?(URI::File)
129
- details = {
130
- base_url: url,
131
- repository_type: "local"
132
- }
133
- end
134
-
135
- details
136
- end
137
-
138
- sig { params(repo_details: T::Hash[Symbol, T.untyped]).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
139
- def build_url_for_details_remote(repo_details)
140
- response = get_repo_metadata(repo_details)
141
- check_repo_response(response, repo_details)
142
- return unless response.status == 200
143
-
144
- body = HttpResponseHelpers.remove_wrapping_zero_width_chars(response.body)
145
- parsed_json = JSON.parse(body)
146
- base_url = base_url_from_v3_metadata(parsed_json)
147
- search_url = search_url_from_v3_metadata(parsed_json)
148
- registration_url = registration_url_from_v3_metadata(parsed_json)
149
-
150
- details = {
151
- base_url: base_url,
152
- repository_url: repo_details.fetch(:url),
153
- auth_header: auth_header_for_token(repo_details.fetch(:token)),
154
- repository_type: "v3"
155
- }
156
- if base_url
157
- details[:versions_url] =
158
- File.join(base_url, dependency.name.downcase, "index.json")
159
- end
160
- if search_url
161
- details[:search_url] =
162
- search_url + "?q=#{dependency.name.downcase}&prerelease=true&semVerLevel=2.0.0"
163
- end
164
-
165
- if registration_url
166
- details[:registration_url] = File.join(registration_url, dependency.name.downcase, "index.json")
167
- end
168
-
169
- details
170
- rescue JSON::ParserError
171
- build_v2_url(T.must(response), repo_details)
172
- rescue Excon::Error::Timeout, Excon::Error::Socket
173
- handle_timeout(repo_metadata_url: repo_details.fetch(:url))
174
- end
175
-
176
- sig { params(repo_details: T::Hash[Symbol, T.untyped]).returns(Excon::Response) }
177
- def get_repo_metadata(repo_details)
178
- url = repo_details.fetch(:url)
179
- cache = CacheManager.cache("repo_finder_metadatacache")
180
- if cache[url]
181
- cache[url]
182
- else
183
- result = Dependabot::RegistryClient.get(
184
- url: url,
185
- headers: auth_header_for_token(repo_details.fetch(:token))
186
- )
187
- cache[url] = result
188
- result
189
- end
190
- end
191
-
192
- sig { params(metadata: T::Hash[String, T::Array[T::Hash[String, T.untyped]]]).returns(T.nilable(String)) }
193
- def base_url_from_v3_metadata(metadata)
194
- metadata
195
- .fetch("resources", [])
196
- .find { |r| r.fetch("@type") == "PackageBaseAddress/3.0.0" }
197
- &.fetch("@id")
198
- end
199
-
200
- sig { params(metadata: T::Hash[String, T::Array[T::Hash[String, T.untyped]]]).returns(T.nilable(String)) }
201
- def registration_url_from_v3_metadata(metadata)
202
- allowed_registration_types = %w(
203
- RegistrationsBaseUrl
204
- RegistrationsBaseUrl/3.0.0-beta
205
- RegistrationsBaseUrl/3.0.0-rc
206
- RegistrationsBaseUrl/3.4.0
207
- RegistrationsBaseUrl/3.6.0
208
- )
209
- metadata
210
- .fetch("resources", [])
211
- .find { |r| allowed_registration_types.find { |s| r.fetch("@type") == s } }
212
- &.fetch("@id")
213
- end
214
-
215
- sig { params(metadata: T::Hash[String, T::Array[T::Hash[String, T.untyped]]]).returns(T.nilable(String)) }
216
- def search_url_from_v3_metadata(metadata)
217
- # allowable values from here: https://learn.microsoft.com/en-us/nuget/api/search-query-service-resource#versioning
218
- allowed_search_types = %w(
219
- SearchQueryService
220
- SearchQueryService/3.0.0-beta
221
- SearchQueryService/3.0.0-rc
222
- SearchQueryService/3.5.0
223
- )
224
- metadata
225
- .fetch("resources", [])
226
- .find { |r| allowed_search_types.find { |s| r.fetch("@type") == s } }
227
- &.fetch("@id")
228
- end
229
-
230
- sig do
231
- params(
232
- response: Excon::Response,
233
- repo_details: T::Hash[Symbol, T.untyped]
234
- )
235
- .returns(T::Hash[Symbol, T.untyped])
236
- end
237
- def build_v2_url(response, repo_details)
238
- doc = Nokogiri::XML(response.body)
239
-
240
- doc.remove_namespaces!
241
- base_url = doc.at_xpath("service")&.attributes
242
- &.fetch("base", nil)&.value
243
-
244
- base_url ||= repo_details.fetch(:url)
245
-
246
- {
247
- base_url: base_url,
248
- repository_url: base_url,
249
- versions_url: File.join(
250
- base_url.delete_suffix("/"),
251
- "FindPackagesById()?id='#{dependency.name}'"
252
- ),
253
- auth_header: auth_header_for_token(repo_details.fetch(:token)),
254
- repository_type: "v2"
255
- }
256
- end
257
-
258
- sig { params(response: Excon::Response, details: T::Hash[Symbol, T.untyped]).void }
259
- def check_repo_response(response, details)
260
- return unless [401, 402, 403].include?(response.status)
261
- raise if details.fetch(:url) == DEFAULT_REPOSITORY_URL
262
-
263
- raise PrivateSourceAuthenticationFailure, details.fetch(:url)
264
- end
265
-
266
- sig { params(repo_metadata_url: String).returns(T.noreturn) }
267
- def handle_timeout(repo_metadata_url:)
268
- raise if repo_metadata_url == DEFAULT_REPOSITORY_URL
269
-
270
- raise PrivateSourceTimedOut, repo_metadata_url
271
- end
272
-
273
- sig { returns(T::Array[T::Hash[Symbol, String]]) }
274
- def credential_repositories
275
- @credential_repositories ||=
276
- T.let(
277
- credentials
278
- .select { |cred| cred["type"] == "nuget_feed" && cred["url"] }
279
- .map { |c| { url: c.fetch("url"), token: c["token"] } },
280
- T.nilable(T::Array[T::Hash[Symbol, String]])
281
- )
282
- end
283
-
284
- sig { returns(T::Array[T::Hash[Symbol, String]]) }
285
- def config_file_repositories
286
- config_files.flat_map { |file| repos_from_config_file(file) }
287
- end
288
-
289
- # rubocop:disable Metrics/CyclomaticComplexity
290
- # rubocop:disable Metrics/PerceivedComplexity
291
- # rubocop:disable Metrics/MethodLength
292
- # rubocop:disable Metrics/AbcSize
293
- sig { params(config_file: Dependabot::DependencyFile).returns(T::Array[T::Hash[Symbol, String]]) }
294
- def repos_from_config_file(config_file)
295
- doc = Nokogiri::XML(config_file.content)
296
- doc.remove_namespaces!
297
- # analogous to having a root config with the default repository
298
- base_sources = [{ url: DEFAULT_REPOSITORY_URL, key: "nuget.org" }]
299
-
300
- sources = T.let([], T::Array[T::Hash[Symbol, String]])
301
-
302
- # regular package sources
303
- doc.css("configuration > packageSources").children.each do |node|
304
- if node.name == "clear"
305
- sources.clear
306
- base_sources.clear
307
- else
308
- key = node.attribute("key")&.value&.strip || node.at_xpath("./key")&.content&.strip
309
- url = node.attribute("value")&.value&.strip || node.at_xpath("./value")&.content&.strip
310
- url = expand_windows_style_environment_variables(url) if url
311
-
312
- # if the path isn't absolute it's relative to the nuget.config file
313
- if url
314
- unless url.include?("://") || Pathname.new(url).absolute?
315
- url = Pathname(config_file.directory).join(url).to_path
316
- end
317
- sources << { url: url, key: key }
318
- end
319
- end
320
- end
321
-
322
- # signed package sources
323
- # https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file#trustedsigners-section
324
- doc.xpath("/configuration/trustedSigners/repository").each do |node|
325
- name = node.attribute("name")&.value&.strip
326
- service_index = node.attribute("serviceIndex")&.value&.strip
327
- sources << { url: service_index, key: name }
328
- end
329
-
330
- sources += base_sources # TODO: quirky overwrite behavior
331
- disabled_sources = disabled_sources(doc)
332
- sources.reject! do |s|
333
- disabled_sources.include?(s[:key])
334
- end
335
-
336
- sources.reject! do |s|
337
- known_urls = credential_repositories.map { |cr| cr.fetch(:url) }
338
- known_urls.include?(s.fetch(:url))
339
- end
340
-
341
- # filter out based on packageSourceMapping
342
- package_mapping_elements = doc.xpath("/configuration/packageSourceMapping/packageSource/package[@pattern]")
343
- matching_package_elements = package_mapping_elements.select do |package_element|
344
- pattern = package_element.attribute("pattern").value
345
-
346
- # reusing this function for a case insensitive GLOB pattern patch (e.g., "Microsoft.Azure.*")
347
- File.fnmatch(pattern, @dependency.name, File::FNM_CASEFOLD)
348
- end
349
- longest_matching_package_element = matching_package_elements.max_by do |package_element|
350
- package_element.attribute("pattern").value.length
351
- end
352
- matching_key = longest_matching_package_element&.parent&.attribute("key")&.value
353
- if matching_key
354
- # found a matching source, only keep that one
355
- sources.select! { |s| s.fetch(:key) == matching_key }
356
- end
357
-
358
- add_config_file_credentials(sources: sources, doc: doc)
359
- sources.each { |details| details.delete(:key) }
360
-
361
- sources
362
- end
363
- # rubocop:enable Metrics/AbcSize
364
- # rubocop:enable Metrics/MethodLength
365
- # rubocop:enable Metrics/PerceivedComplexity
366
- # rubocop:enable Metrics/CyclomaticComplexity
367
-
368
- sig { returns(T::Hash[Symbol, T.untyped]) }
369
- def default_repository_details
370
- RepositoryFinder.get_default_repository_details(dependency.name)
371
- end
372
-
373
- # rubocop:disable Metrics/PerceivedComplexity
374
- sig { params(doc: Nokogiri::XML::Document).returns(T::Array[String]) }
375
- def disabled_sources(doc)
376
- doc.css("configuration > disabledPackageSources > add").filter_map do |node|
377
- value = node.attribute("value")&.value ||
378
- node.at_xpath("./value")&.content
379
-
380
- if value&.strip&.downcase == "true"
381
- node.attribute("key")&.value&.strip ||
382
- node.at_xpath("./key")&.content&.strip
383
- end
384
- end
385
- end
386
- # rubocop:enable Metrics/PerceivedComplexity
387
-
388
- # rubocop:disable Metrics/PerceivedComplexity
389
- sig do
390
- params(
391
- sources: T::Array[T::Hash[Symbol, T.nilable(String)]],
392
- doc: Nokogiri::XML::Document
393
- )
394
- .void
395
- end
396
- def add_config_file_credentials(sources:, doc:)
397
- sources.each do |source_details|
398
- key = source_details.fetch(:key)
399
- next source_details[:token] = nil unless key
400
- next source_details[:token] = nil if key.match?(/^\d/)
401
-
402
- tag = RepositoryFinder.escape_source_name_to_element_name(key)
403
- creds_nodes = doc.css("configuration > packageSourceCredentials " \
404
- "> #{tag} > add")
405
-
406
- username =
407
- creds_nodes
408
- .find { |n| n.attribute("key")&.value == "Username" }
409
- &.attribute("value")&.value
410
- password =
411
- creds_nodes
412
- .find { |n| n.attribute("key")&.value == "ClearTextPassword" }
413
- &.attribute("value")&.value
414
-
415
- # NOTE: We have to look for plain text passwords, as we have no
416
- # way of decrypting encrypted passwords. For the same reason we
417
- # don't fetch API keys from the nuget.config at all.
418
- next source_details[:token] = nil unless username && password
419
-
420
- expanded_username = expand_windows_style_environment_variables(username)
421
- expanded_password = expand_windows_style_environment_variables(password)
422
- source_details[:token] = "#{expanded_username}:#{expanded_password}"
423
- rescue Nokogiri::XML::XPath::SyntaxError
424
- # Any non-ascii characters in the tag with cause a syntax error
425
- next source_details[:token] = nil
426
- end
427
- end
428
- # rubocop:enable Metrics/PerceivedComplexity
429
-
430
- sig { params(string: String).returns(String) }
431
- def expand_windows_style_environment_variables(string)
432
- # NuGet.Config files can have Windows-style environment variables that need to be replaced
433
- # https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file#using-environment-variables
434
- string.gsub(/%([^%]+)%/) do
435
- environment_variable_name = T.must(::Regexp.last_match(1))
436
- environment_variable_value = ENV.fetch(environment_variable_name, nil)
437
- if environment_variable_value
438
- environment_variable_value
439
- else
440
- # report that the variable couldn't be expanded, then replace it as-is
441
- Dependabot.logger.warn <<~WARN
442
- The variable '%#{environment_variable_name}%' could not be expanded in NuGet.Config
443
- WARN
444
- "%#{environment_variable_name}%"
445
- end
446
- end
447
- end
448
-
449
- sig { params(token: T.nilable(String)).returns(T::Hash[String, String]) }
450
- def auth_header_for_token(token)
451
- return {} unless token
452
-
453
- if token.include?(":")
454
- encoded_token = Base64.encode64(token).delete("\n")
455
- { "Authorization" => "Basic #{encoded_token}" }
456
- elsif Base64.decode64(token).ascii_only? &&
457
- Base64.decode64(token).include?(":")
458
- { "Authorization" => "Basic #{token.delete("\n")}" }
459
- else
460
- { "Authorization" => "Bearer #{token}" }
461
- end
462
- end
463
- end
464
- # rubocop:enable Metrics/ClassLength
465
- end
466
- end
@@ -1,34 +0,0 @@
1
- # typed: strong
2
- # frozen_string_literal: true
3
-
4
- require "sorbet-runtime"
5
-
6
- require "dependabot/update_checkers/base"
7
- require "dependabot/nuget/version"
8
- require "dependabot/nuget/requirement"
9
- require "dependabot/nuget/native_helpers"
10
- require "dependabot/shared_helpers"
11
-
12
- module Dependabot
13
- module Nuget
14
- class TfmComparer
15
- extend T::Sig
16
-
17
- sig { params(project_tfms: T::Array[String], package_tfms: T::Array[String]).returns(T::Boolean) }
18
- def self.are_frameworks_compatible?(project_tfms, package_tfms)
19
- return false if package_tfms.empty?
20
- return false if project_tfms.empty?
21
-
22
- key = "project_ftms:#{project_tfms.sort.join(',')}:package_tfms:#{package_tfms.sort.join(',')}".downcase
23
-
24
- @cached_framework_check ||= T.let({}, T.nilable(T::Hash[String, T::Boolean]))
25
- unless @cached_framework_check.key?(key)
26
- @cached_framework_check[key] =
27
- NativeHelpers.run_nuget_framework_check(project_tfms,
28
- package_tfms)
29
- end
30
- T.must(@cached_framework_check[key])
31
- end
32
- end
33
- end
34
- end
@@ -1,30 +0,0 @@
1
- # typed: strong
2
- # frozen_string_literal: true
3
-
4
- require "dependabot/nuget/discovery/discovery_json_reader"
5
-
6
- module Dependabot
7
- module Nuget
8
- class TfmFinder
9
- extend T::Sig
10
-
11
- sig { params(dependency: Dependency).returns(T::Array[String]) }
12
- def self.frameworks(dependency)
13
- discovery_json = DiscoveryJsonReader.discovery_json
14
- return [] unless discovery_json
15
-
16
- workspace = DiscoveryJsonReader.new(
17
- discovery_json: discovery_json
18
- ).workspace_discovery
19
- return [] unless workspace
20
-
21
- workspace.projects.select do |project|
22
- all_dependencies = project.dependencies + project.referenced_project_paths.flat_map do |ref|
23
- workspace.projects.find { |p| p.file_path == ref }&.dependencies || []
24
- end
25
- all_dependencies.any? { |d| d.name.casecmp?(dependency.name) }
26
- end.flat_map(&:target_frameworks).uniq
27
- end
28
- end
29
- end
30
- end