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,43 +0,0 @@
1
- # typed: strong
2
- # frozen_string_literal: true
3
-
4
- require "sorbet-runtime"
5
-
6
- module Dependabot
7
- module Nuget
8
- class NativePropertyDetails
9
- extend T::Sig
10
-
11
- sig { params(json: T::Hash[String, T.untyped]).returns(NativePropertyDetails) }
12
- def self.from_json(json)
13
- name = T.let(json.fetch("Name"), String)
14
- value = T.let(json.fetch("Value"), String)
15
- source_file_path = T.let(json.fetch("SourceFilePath"), String)
16
-
17
- NativePropertyDetails.new(name: name,
18
- value: value,
19
- source_file_path: source_file_path)
20
- end
21
-
22
- sig do
23
- params(name: String,
24
- value: String,
25
- source_file_path: String).void
26
- end
27
- def initialize(name:, value:, source_file_path:)
28
- @name = name
29
- @value = value
30
- @source_file_path = source_file_path
31
- end
32
-
33
- sig { returns(String) }
34
- attr_reader :name
35
-
36
- sig { returns(String) }
37
- attr_reader :value
38
-
39
- sig { returns(String) }
40
- attr_reader :source_file_path
41
- end
42
- end
43
- end
@@ -1,61 +0,0 @@
1
- # typed: strong
2
- # frozen_string_literal: true
3
-
4
- require "dependabot/nuget/native_discovery/native_dependency_file_discovery"
5
- require "dependabot/nuget/native_discovery/native_project_discovery"
6
- require "dependabot/nuget/native_helpers"
7
- require "sorbet-runtime"
8
-
9
- module Dependabot
10
- module Nuget
11
- class NativeWorkspaceDiscovery
12
- extend T::Sig
13
-
14
- sig { params(json: T::Hash[String, T.untyped]).returns(NativeWorkspaceDiscovery) }
15
- def self.from_json(json)
16
- Dependabot::Nuget::NativeHelpers.ensure_no_errors(json)
17
-
18
- path = T.let(json.fetch("Path"), String)
19
- path = "/" + path unless path.start_with?("/")
20
- projects = T.let(json.fetch("Projects"), T::Array[T::Hash[String, T.untyped]]).filter_map do |project|
21
- NativeProjectDiscovery.from_json(project, path)
22
- end
23
- global_json = NativeDependencyFileDiscovery
24
- .from_json(T.let(json.fetch("GlobalJson"), T.nilable(T::Hash[String, T.untyped])), path)
25
- dotnet_tools_json = NativeDependencyFileDiscovery
26
- .from_json(T.let(json.fetch("DotNetToolsJson"),
27
- T.nilable(T::Hash[String, T.untyped])), path)
28
-
29
- NativeWorkspaceDiscovery.new(path: path,
30
- projects: projects,
31
- global_json: global_json,
32
- dotnet_tools_json: dotnet_tools_json)
33
- end
34
-
35
- sig do
36
- params(path: String,
37
- projects: T::Array[NativeProjectDiscovery],
38
- global_json: T.nilable(NativeDependencyFileDiscovery),
39
- dotnet_tools_json: T.nilable(NativeDependencyFileDiscovery)).void
40
- end
41
- def initialize(path:, projects:, global_json:, dotnet_tools_json:)
42
- @path = path
43
- @projects = projects
44
- @global_json = global_json
45
- @dotnet_tools_json = dotnet_tools_json
46
- end
47
-
48
- sig { returns(String) }
49
- attr_reader :path
50
-
51
- sig { returns(T::Array[NativeProjectDiscovery]) }
52
- attr_reader :projects
53
-
54
- sig { returns(T.nilable(NativeDependencyFileDiscovery)) }
55
- attr_reader :global_json
56
-
57
- sig { returns(T.nilable(NativeDependencyFileDiscovery)) }
58
- attr_reader :dotnet_tools_json
59
- end
60
- end
61
- end
@@ -1,105 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- #######################################################################
5
- # For more details on Dotnet version constraints, see: #
6
- # https://docs.microsoft.com/en-us/nuget/reference/package-versioning #
7
- #######################################################################
8
-
9
- require "sorbet-runtime"
10
-
11
- require "dependabot/update_checkers/base"
12
- require "dependabot/nuget/native_discovery/native_dependency_details"
13
- require "dependabot/nuget/version"
14
-
15
- module Dependabot
16
- module Nuget
17
- class NativeUpdateChecker < Dependabot::UpdateCheckers::Base
18
- class NativeRequirementsUpdater
19
- extend T::Sig
20
-
21
- sig do
22
- params(
23
- requirements: T::Array[T::Hash[Symbol, T.untyped]],
24
- dependency_details: T.nilable(Dependabot::Nuget::NativeDependencyDetails)
25
- )
26
- .void
27
- end
28
- def initialize(requirements:, dependency_details:)
29
- @requirements = requirements
30
- @dependency_details = dependency_details
31
- end
32
-
33
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
34
- def updated_requirements
35
- return requirements unless clean_version
36
-
37
- # NOTE: Order is important here. The FileUpdater needs the updated
38
- # requirement at index `i` to correspond to the previous requirement
39
- # at the same index.
40
- requirements.map do |req|
41
- next req if req.fetch(:requirement).nil?
42
- next req if req.fetch(:requirement).include?(",")
43
-
44
- new_req =
45
- if req.fetch(:requirement).include?("*")
46
- update_wildcard_requirement(req.fetch(:requirement))
47
- else
48
- # Since range requirements are excluded by the line above we can
49
- # replace anything that looks like a version with the new
50
- # version
51
- req[:requirement].sub(
52
- /#{Nuget::Version::VERSION_PATTERN}/o,
53
- clean_version.to_s
54
- )
55
- end
56
-
57
- next req if new_req == req.fetch(:requirement)
58
-
59
- new_source = req[:source]&.dup
60
- unless @dependency_details.nil?
61
- new_source = {
62
- type: "nuget_repo",
63
- source_url: @dependency_details.info_url
64
- }
65
- end
66
-
67
- req.merge({ requirement: new_req, source: new_source })
68
- end
69
- end
70
-
71
- private
72
-
73
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
74
- attr_reader :requirements
75
-
76
- sig { returns(T.class_of(Dependabot::Nuget::Version)) }
77
- def version_class
78
- Dependabot::Nuget::Version
79
- end
80
-
81
- sig { returns(T.nilable(Dependabot::Nuget::Version)) }
82
- def clean_version
83
- return unless @dependency_details&.version
84
-
85
- version_class.new(@dependency_details.version)
86
- end
87
-
88
- sig { params(req_string: String).returns(String) }
89
- def update_wildcard_requirement(req_string)
90
- return req_string if req_string == "*-*"
91
-
92
- return req_string if req_string == "*"
93
-
94
- precision = T.must(req_string.split("*").first).split(/\.|\-/).count
95
- wildcard_section = req_string.partition(/(?=[.\-]\*)/).last
96
-
97
- version_parts = T.must(clean_version).segments.first(precision)
98
- version = version_parts.join(".")
99
-
100
- version + wildcard_section
101
- end
102
- end
103
- end
104
- end
105
- end
@@ -1,214 +0,0 @@
1
- # typed: strong
2
- # frozen_string_literal: true
3
-
4
- require "dependabot/nuget/analysis/analysis_json_reader"
5
- require "dependabot/nuget/native_discovery/native_discovery_json_reader"
6
- require "dependabot/update_checkers"
7
- require "dependabot/update_checkers/base"
8
- require "sorbet-runtime"
9
-
10
- module Dependabot
11
- module Nuget
12
- class NativeUpdateChecker < Dependabot::UpdateCheckers::Base
13
- extend T::Sig
14
-
15
- require_relative "native_requirements_updater"
16
-
17
- sig { override.returns(T.nilable(String)) }
18
- def latest_version
19
- # No need to find latest version for transitive dependencies unless they have a vulnerability.
20
- return dependency.version if !dependency.top_level? && !vulnerable?
21
-
22
- # if no update sources have the requisite package, then we can only assume that the current version is correct
23
- @latest_version = T.let(
24
- update_analysis.dependency_analysis.updated_version,
25
- T.nilable(String)
26
- )
27
- end
28
-
29
- sig { override.returns(T.nilable(T.any(String, Gem::Version))) }
30
- def latest_resolvable_version
31
- # We always want a full unlock since any package update could update peer dependencies as well.
32
- # To force a full unlock instead of an own unlock, we return nil.
33
- nil
34
- end
35
-
36
- sig { override.returns(Dependabot::Nuget::Version) }
37
- def lowest_security_fix_version
38
- update_analysis.dependency_analysis.numeric_updated_version
39
- end
40
-
41
- sig { override.returns(T.nilable(Dependabot::Nuget::Version)) }
42
- def lowest_resolvable_security_fix_version
43
- return nil if version_comes_from_multi_dependency_property?
44
-
45
- update_analysis.dependency_analysis.numeric_updated_version
46
- end
47
-
48
- sig { override.returns(NilClass) }
49
- def latest_resolvable_version_with_no_unlock
50
- # Irrelevant, since Nuget has a single dependency file
51
- nil
52
- end
53
-
54
- sig { override.returns(T::Array[T::Hash[Symbol, T.untyped]]) }
55
- def updated_requirements
56
- dep_details = updated_dependency_details.find { |d| d.name.casecmp?(dependency.name) }
57
- NativeRequirementsUpdater.new(
58
- requirements: dependency.requirements,
59
- dependency_details: dep_details
60
- ).updated_requirements
61
- end
62
-
63
- sig { returns(T::Boolean) }
64
- def up_to_date?
65
- !update_analysis.dependency_analysis.can_update
66
- end
67
-
68
- sig { returns(T::Boolean) }
69
- def requirements_unlocked_or_can_be?
70
- update_analysis.dependency_analysis.can_update
71
- end
72
-
73
- sig { returns(T::Boolean) }
74
- def public_latest_version_resolvable_with_full_unlock?
75
- latest_version_resolvable_with_full_unlock?
76
- end
77
-
78
- sig { returns(T::Array[Dependabot::Dependency]) }
79
- def public_updated_dependencies_after_full_unlock
80
- updated_dependencies_after_full_unlock
81
- end
82
-
83
- private
84
-
85
- sig { returns(AnalysisJsonReader) }
86
- def update_analysis
87
- @update_analysis ||= T.let(request_analysis, T.nilable(AnalysisJsonReader))
88
- end
89
-
90
- sig { returns(String) }
91
- def dependency_file_path
92
- d = File.join(Dir.tmpdir, "dependency")
93
- FileUtils.mkdir_p(d)
94
- File.join(d, "#{dependency.name}.json")
95
- end
96
-
97
- sig { returns(T::Array[String]) }
98
- def dependency_file_paths
99
- dependency_files.map do |file|
100
- NativeDiscoveryJsonReader.dependency_file_path(
101
- repo_contents_path: T.must(repo_contents_path),
102
- dependency_file: file
103
- )
104
- end
105
- end
106
-
107
- sig { returns(AnalysisJsonReader) }
108
- def request_analysis
109
- discovery_file_path = NativeDiscoveryJsonReader.get_discovery_json_path_for_dependency_file_paths(
110
- dependency_file_paths
111
- )
112
- analysis_folder_path = AnalysisJsonReader.temp_directory
113
-
114
- write_dependency_info
115
-
116
- NativeHelpers.run_nuget_analyze_tool(repo_root: T.must(repo_contents_path),
117
- discovery_file_path: discovery_file_path,
118
- dependency_file_path: dependency_file_path,
119
- analysis_folder_path: analysis_folder_path,
120
- credentials: credentials)
121
-
122
- analysis_json = AnalysisJsonReader.analysis_json(dependency_name: dependency.name)
123
-
124
- AnalysisJsonReader.new(analysis_json: T.must(analysis_json))
125
- end
126
-
127
- sig { void }
128
- def write_dependency_info
129
- dependency_info = {
130
- Name: dependency.name,
131
- Version: dependency.version.to_s,
132
- IsVulnerable: vulnerable?,
133
- IgnoredVersions: ignored_versions,
134
- Vulnerabilities: security_advisories.map do |vulnerability|
135
- {
136
- DependencyName: vulnerability.dependency_name,
137
- PackageManager: vulnerability.package_manager,
138
- VulnerableVersions: vulnerability.vulnerable_versions.map(&:to_s),
139
- SafeVersions: vulnerability.safe_versions.map(&:to_s)
140
- }
141
- end
142
- }.to_json
143
- dependency_directory = File.dirname(dependency_file_path)
144
-
145
- begin
146
- Dir.mkdir(dependency_directory)
147
- rescue StandardError
148
- nil?
149
- end
150
-
151
- Dependabot.logger.info("Writing dependency info: #{dependency_info}")
152
- File.write(dependency_file_path, dependency_info)
153
- end
154
-
155
- sig { returns(Dependabot::FileParsers::Base::DependencySet) }
156
- def discovered_dependencies
157
- NativeDiscoveryJsonReader.load_discovery_for_dependency_file_paths(dependency_file_paths).dependency_set
158
- end
159
-
160
- sig { override.returns(T::Boolean) }
161
- def latest_version_resolvable_with_full_unlock?
162
- # We always want a full unlock since any package update could update peer dependencies as well.
163
- true
164
- end
165
-
166
- sig { override.returns(T::Array[Dependabot::Dependency]) }
167
- def updated_dependencies_after_full_unlock
168
- dependencies = discovered_dependencies.dependencies
169
- updated_dependency_details.filter_map do |dependency_details|
170
- dep = dependencies.find { |d| d.name.casecmp(dependency_details.name)&.zero? }
171
- next unless dep
172
-
173
- metadata = {}
174
- # For peer dependencies, instruct updater to not directly update this dependency
175
- metadata = { information_only: true } unless dependency.name.casecmp(dependency_details.name)&.zero?
176
-
177
- # rebuild the new requirements with the updated dependency details
178
- updated_reqs = dep.requirements.map do |r|
179
- r = r.clone
180
- r[:requirement] = dependency_details.version
181
- r[:source] = {
182
- type: "nuget_repo",
183
- source_url: dependency_details.info_url
184
- }
185
- r
186
- end
187
-
188
- Dependency.new(
189
- name: dep.name,
190
- version: dependency_details.version,
191
- requirements: updated_reqs,
192
- previous_version: dep.version,
193
- previous_requirements: dep.requirements,
194
- package_manager: dep.package_manager,
195
- metadata: metadata
196
- )
197
- end
198
- end
199
-
200
- sig { returns(T::Array[Dependabot::Nuget::NativeDependencyDetails]) }
201
- def updated_dependency_details
202
- @updated_dependency_details ||= T.let(update_analysis.dependency_analysis.updated_dependencies,
203
- T.nilable(T::Array[Dependabot::Nuget::NativeDependencyDetails]))
204
- end
205
-
206
- sig { returns(T::Boolean) }
207
- def version_comes_from_multi_dependency_property?
208
- update_analysis.dependency_analysis.version_comes_from_multi_dependency_property
209
- end
210
- end
211
- end
212
- end
213
-
214
- Dependabot::UpdateCheckers.register("nuget", Dependabot::Nuget::UpdateChecker)
@@ -1,223 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "dependabot/nuget/cache_manager"
5
- require "dependabot/nuget/http_response_helpers"
6
- require "dependabot/nuget/update_checker/repository_finder"
7
- require "sorbet-runtime"
8
-
9
- module Dependabot
10
- module Nuget
11
- class NugetClient
12
- extend T::Sig
13
-
14
- sig do
15
- params(dependency_name: String, repository_details: T::Hash[Symbol, String])
16
- .returns(T.nilable(T::Set[String]))
17
- end
18
- def self.get_package_versions(dependency_name, repository_details)
19
- repository_type = repository_details.fetch(:repository_type)
20
- if repository_type == "v3"
21
- get_package_versions_v3(dependency_name, repository_details)
22
- elsif repository_type == "v2"
23
- get_package_versions_v2(dependency_name, repository_details)
24
- elsif repository_type == "local"
25
- get_package_versions_local(dependency_name, repository_details)
26
- else
27
- raise "Unknown repository type: #{repository_type}"
28
- end
29
- end
30
-
31
- sig do
32
- params(dependency_name: String, repository_details: T::Hash[Symbol, String])
33
- .returns(T.nilable(T::Set[String]))
34
- end
35
- private_class_method def self.get_package_versions_local(dependency_name, repository_details)
36
- url = repository_details.fetch(:base_url)
37
- raise "Local repo #{url} doesn't exist or isn't a directory" unless File.exist?(url) && File.directory?(url)
38
-
39
- package_dir = File.join(url, dependency_name)
40
-
41
- versions = Set.new
42
- return versions unless File.exist?(package_dir) && File.directory?(package_dir)
43
-
44
- Dir.each_child(package_dir) do |child|
45
- versions.add(child) if File.directory?(File.join(package_dir, child))
46
- end
47
-
48
- versions
49
- end
50
-
51
- sig do
52
- params(dependency_name: String, repository_details: T::Hash[Symbol, String])
53
- .returns(T.nilable(T::Set[String]))
54
- end
55
- private_class_method def self.get_package_versions_v3(dependency_name, repository_details)
56
- # Use the registration URL if possible because it is fast and correct
57
- if repository_details[:registration_url]
58
- get_versions_from_registration_v3(repository_details)
59
- # use the search API if not because it is slow but correct
60
- elsif repository_details[:search_url]
61
- get_versions_from_search_url_v3(repository_details, dependency_name)
62
- # Otherwise, use the versions URL (fast but wrong because it includes unlisted versions)
63
- elsif repository_details[:versions_url]
64
- get_versions_from_versions_url_v3(repository_details)
65
- else
66
- raise "No version sources were available for #{dependency_name} in #{repository_details}"
67
- end
68
- end
69
-
70
- sig do
71
- params(dependency_name: String, repository_details: T::Hash[Symbol, String])
72
- .returns(T.nilable(T::Set[String]))
73
- end
74
- private_class_method def self.get_package_versions_v2(dependency_name, repository_details)
75
- doc = execute_xml_nuget_request(repository_details.fetch(:versions_url), repository_details)
76
- return unless doc
77
-
78
- # v2 APIs can differ, but all tested have this title value set to the name of the package
79
- title_nodes = doc.xpath("/feed/entry/title")
80
- matching_versions = Set.new
81
- title_nodes.each do |title_node|
82
- return nil unless title_node.text
83
-
84
- next unless title_node.text.casecmp?(dependency_name)
85
-
86
- version_node = title_node.parent.xpath("properties/Version")
87
- matching_versions << version_node.text if version_node && version_node.text
88
- end
89
-
90
- matching_versions
91
- end
92
-
93
- sig { params(repository_details: T::Hash[Symbol, String]).returns(T.nilable(T::Set[String])) }
94
- private_class_method def self.get_versions_from_versions_url_v3(repository_details)
95
- body = execute_json_nuget_request(repository_details.fetch(:versions_url), repository_details)
96
- ver_array = T.let(body&.fetch("versions"), T.nilable(T::Array[String]))
97
- ver_array&.to_set
98
- end
99
-
100
- sig { params(repository_details: T::Hash[Symbol, String]).returns(T.nilable(T::Set[String])) }
101
- private_class_method def self.get_versions_from_registration_v3(repository_details)
102
- url = repository_details.fetch(:registration_url)
103
- body = execute_json_nuget_request(url, repository_details)
104
-
105
- return unless body
106
-
107
- pages = body.fetch("items")
108
- versions = T.let(Set.new, T::Set[String])
109
- pages.each do |page|
110
- items = page["items"]
111
- if items
112
- # inlined entries
113
- get_versions_from_inline_page(items, versions)
114
- else
115
- # paged entries
116
- page_url = page["@id"]
117
- page_body = execute_json_nuget_request(page_url, repository_details)
118
- next unless page_body
119
-
120
- items = page_body.fetch("items")
121
- items.each do |item|
122
- catalog_entry = item.fetch("catalogEntry")
123
- versions << catalog_entry.fetch("version") if catalog_entry["listed"] == true
124
- end
125
- end
126
- end
127
-
128
- versions
129
- end
130
-
131
- sig { params(items: T::Array[T::Hash[String, T.untyped]], versions: T::Set[String]).void }
132
- private_class_method def self.get_versions_from_inline_page(items, versions)
133
- items.each do |item|
134
- catalog_entry = item["catalogEntry"]
135
-
136
- # a package is considered listed if the `listed` property is either `true` or missing
137
- listed_property = catalog_entry["listed"]
138
- is_listed = listed_property.nil? || listed_property == true
139
- if is_listed
140
- vers = catalog_entry["version"]
141
- versions << vers
142
- end
143
- end
144
- end
145
-
146
- sig do
147
- params(repository_details: T::Hash[Symbol, String], dependency_name: String)
148
- .returns(T.nilable(T::Set[String]))
149
- end
150
- private_class_method def self.get_versions_from_search_url_v3(repository_details, dependency_name)
151
- search_url = repository_details.fetch(:search_url)
152
- body = execute_json_nuget_request(search_url, repository_details)
153
-
154
- body&.fetch("data")
155
- &.find { |d| d.fetch("id").casecmp(dependency_name.downcase).zero? }
156
- &.fetch("versions")
157
- &.map { |d| d.fetch("version") }
158
- &.to_set
159
- end
160
-
161
- sig do
162
- params(url: String, repository_details: T::Hash[Symbol, T.untyped]).returns(T.nilable(Nokogiri::XML::Document))
163
- end
164
- private_class_method def self.execute_xml_nuget_request(url, repository_details)
165
- response = execute_nuget_request_internal(
166
- url: url,
167
- auth_header: repository_details.fetch(:auth_header),
168
- repository_url: repository_details.fetch(:repository_url)
169
- )
170
- return unless response.status == 200
171
-
172
- doc = Nokogiri::XML(response.body)
173
- doc.remove_namespaces!
174
- doc
175
- end
176
-
177
- sig do
178
- params(url: String,
179
- repository_details: T::Hash[Symbol, T.untyped])
180
- .returns(T.nilable(T::Hash[T.untyped, T.untyped]))
181
- end
182
- private_class_method def self.execute_json_nuget_request(url, repository_details)
183
- response = execute_nuget_request_internal(
184
- url: url,
185
- auth_header: repository_details.fetch(:auth_header),
186
- repository_url: repository_details.fetch(:repository_url)
187
- )
188
- return unless response.status == 200
189
-
190
- body = HttpResponseHelpers.remove_wrapping_zero_width_chars(response.body)
191
- JSON.parse(body)
192
- end
193
-
194
- sig do
195
- params(url: String, auth_header: T::Hash[Symbol, T.untyped], repository_url: String).returns(Excon::Response)
196
- end
197
- private_class_method def self.execute_nuget_request_internal(url:, auth_header:, repository_url:)
198
- cache = CacheManager.cache("dependency_url_search_cache")
199
- if cache[url].nil?
200
- response = Dependabot::RegistryClient.get(
201
- url: url,
202
- headers: auth_header
203
- )
204
-
205
- if [401, 402, 403].include?(response.status)
206
- raise Dependabot::PrivateSourceAuthenticationFailure, repository_url
207
- end
208
-
209
- cache[url] = response if !CacheManager.caching_disabled? && response.status == 200
210
- else
211
- response = cache[url]
212
- end
213
-
214
- response
215
- rescue Excon::Error::Timeout, Excon::Error::Socket
216
- repo_url = repository_url
217
- raise if repo_url == Dependabot::Nuget::RepositoryFinder::DEFAULT_REPOSITORY_URL
218
-
219
- raise PrivateSourceTimedOut, repo_url
220
- end
221
- end
222
- end
223
- end