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.
- checksums.yaml +4 -4
- data/helpers/lib/NuGetUpdater/Directory.Packages.props +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +7 -3
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +26 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +0 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +6 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +24 -9
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +0 -13
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementConverter.cs +17 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +44 -5
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +19 -11
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs +13 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/AllowedUpdate.cs +18 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CommitOptions.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Condition.cs +19 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +8 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/GroupPullRequest.cs +9 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +13 -10
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequest.cs +11 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/RequirementsUpdateStrategy.cs +15 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +24 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/VersionConverter.cs +19 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +3 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +43 -18
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +13 -12
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +2 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +40 -14
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +45 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProjectHelper.cs +2 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +5 -2
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.DotNetToolsJson.cs +45 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs +35 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +0 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +41 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +2 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +85 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +7 -31
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +340 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs +18 -7
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +24 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +0 -12
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +84 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +66 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +55 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +0 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +785 -755
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +2 -2
- data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +1 -1
- data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -3
- data/lib/dependabot/nuget/discovery/dependency_details.rb +10 -3
- data/lib/dependabot/nuget/discovery/dependency_file_discovery.rb +8 -12
- data/lib/dependabot/nuget/discovery/discovery_json_reader.rb +214 -29
- data/lib/dependabot/nuget/discovery/project_discovery.rb +41 -8
- data/lib/dependabot/nuget/discovery/workspace_discovery.rb +14 -19
- data/lib/dependabot/nuget/file_fetcher.rb +3 -3
- data/lib/dependabot/nuget/file_parser.rb +92 -3
- data/lib/dependabot/nuget/file_updater.rb +13 -13
- data/lib/dependabot/nuget/language.rb +82 -0
- data/lib/dependabot/nuget/native_helpers.rb +37 -5
- data/lib/dependabot/nuget/package_manager.rb +51 -0
- data/lib/dependabot/nuget/update_checker/requirements_updater.rb +23 -27
- data/lib/dependabot/nuget/update_checker.rb +116 -190
- metadata +20 -29
- data/lib/dependabot/nuget/discovery/directory_packages_props_discovery.rb +0 -43
- data/lib/dependabot/nuget/http_response_helpers.rb +0 -19
- data/lib/dependabot/nuget/native_discovery/native_dependency_details.rb +0 -102
- data/lib/dependabot/nuget/native_discovery/native_dependency_file_discovery.rb +0 -122
- data/lib/dependabot/nuget/native_discovery/native_discovery_json_reader.rb +0 -277
- data/lib/dependabot/nuget/native_discovery/native_evaluation_details.rb +0 -63
- data/lib/dependabot/nuget/native_discovery/native_project_discovery.rb +0 -104
- data/lib/dependabot/nuget/native_discovery/native_property_details.rb +0 -43
- data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +0 -61
- data/lib/dependabot/nuget/native_update_checker/native_requirements_updater.rb +0 -105
- data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +0 -214
- data/lib/dependabot/nuget/nuget_client.rb +0 -223
- data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +0 -116
- data/lib/dependabot/nuget/update_checker/dependency_finder.rb +0 -297
- data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +0 -221
- data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +0 -110
- data/lib/dependabot/nuget/update_checker/property_updater.rb +0 -196
- data/lib/dependabot/nuget/update_checker/repository_finder.rb +0 -466
- data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +0 -34
- data/lib/dependabot/nuget/update_checker/tfm_finder.rb +0 -30
- data/lib/dependabot/nuget/update_checker/version_finder.rb +0 -449
@@ -1,116 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "sorbet-runtime"
|
5
|
-
|
6
|
-
require "dependabot/update_checkers/base"
|
7
|
-
|
8
|
-
module Dependabot
|
9
|
-
module Nuget
|
10
|
-
class CompatibilityChecker
|
11
|
-
extend T::Sig
|
12
|
-
|
13
|
-
require_relative "nuspec_fetcher"
|
14
|
-
require_relative "nupkg_fetcher"
|
15
|
-
require_relative "tfm_finder"
|
16
|
-
require_relative "tfm_comparer"
|
17
|
-
|
18
|
-
sig do
|
19
|
-
params(
|
20
|
-
dependency_urls: T::Array[T::Hash[Symbol, String]],
|
21
|
-
dependency: Dependabot::Dependency
|
22
|
-
).void
|
23
|
-
end
|
24
|
-
def initialize(dependency_urls:, dependency:)
|
25
|
-
@dependency_urls = dependency_urls
|
26
|
-
@dependency = dependency
|
27
|
-
end
|
28
|
-
|
29
|
-
sig { params(version: String).returns(T::Boolean) }
|
30
|
-
def compatible?(version)
|
31
|
-
nuspec_xml = NuspecFetcher.fetch_nuspec(dependency_urls, dependency.name, version)
|
32
|
-
return false unless nuspec_xml
|
33
|
-
|
34
|
-
# development dependencies are packages such as analyzers which need to be compatible with the compiler not the
|
35
|
-
# project itself, but some packages that report themselves as development dependencies still contain target
|
36
|
-
# framework dependencies and should be checked for compatibility through the regular means
|
37
|
-
return true if pure_development_dependency?(nuspec_xml)
|
38
|
-
|
39
|
-
package_tfms = parse_package_tfms(nuspec_xml)
|
40
|
-
package_tfms = fetch_package_tfms(version) if package_tfms.empty?
|
41
|
-
# nil is a special return value that indicates that the package is likely a development dependency
|
42
|
-
return true if package_tfms.nil?
|
43
|
-
return false if package_tfms.empty?
|
44
|
-
|
45
|
-
return false if project_tfms.nil? || project_tfms&.empty?
|
46
|
-
|
47
|
-
TfmComparer.are_frameworks_compatible?(T.must(project_tfms), package_tfms)
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
sig { returns(T::Array[T::Hash[Symbol, String]]) }
|
53
|
-
attr_reader :dependency_urls
|
54
|
-
|
55
|
-
sig { returns(Dependabot::Dependency) }
|
56
|
-
attr_reader :dependency
|
57
|
-
|
58
|
-
sig { params(nuspec_xml: Nokogiri::XML::Document).returns(T::Boolean) }
|
59
|
-
def pure_development_dependency?(nuspec_xml)
|
60
|
-
contents = nuspec_xml.at_xpath("package/metadata/developmentDependency")&.content&.strip
|
61
|
-
return false unless contents # no `developmentDependency` element
|
62
|
-
|
63
|
-
self_reports_as_development_dependency = contents.casecmp?("true")
|
64
|
-
return false unless self_reports_as_development_dependency
|
65
|
-
|
66
|
-
# even though a package self-reports as a development dependency, it might not be if it has dependency groups
|
67
|
-
# with a target framework
|
68
|
-
dependency_groups_with_target_framework =
|
69
|
-
nuspec_xml.at_xpath("/package/metadata/dependencies/group[@targetFramework]")
|
70
|
-
dependency_groups_with_target_framework.to_a.empty?
|
71
|
-
end
|
72
|
-
|
73
|
-
sig { params(nuspec_xml: Nokogiri::XML::Document).returns(T::Array[String]) }
|
74
|
-
def parse_package_tfms(nuspec_xml)
|
75
|
-
nuspec_xml.xpath("//dependencies/group").filter_map { |group| group.attribute("targetFramework") }
|
76
|
-
end
|
77
|
-
|
78
|
-
sig { returns(T.nilable(T::Array[String])) }
|
79
|
-
def project_tfms
|
80
|
-
@project_tfms ||= T.let(TfmFinder.frameworks(dependency), T.nilable(T::Array[String]))
|
81
|
-
end
|
82
|
-
|
83
|
-
sig { params(dependency_version: String).returns(T.nilable(T::Array[String])) }
|
84
|
-
def fetch_package_tfms(dependency_version)
|
85
|
-
cache = CacheManager.cache("compatibility_checker_tfms_cache")
|
86
|
-
key = "#{dependency.name}::#{dependency_version}"
|
87
|
-
|
88
|
-
cache[key] ||= begin
|
89
|
-
nupkg_buffer = NupkgFetcher.fetch_nupkg_buffer(dependency_urls, dependency.name, dependency_version)
|
90
|
-
return [] unless nupkg_buffer
|
91
|
-
|
92
|
-
# Parse tfms from the folders beneath the lib folder
|
93
|
-
folder_name = "lib/"
|
94
|
-
tfms = Set.new
|
95
|
-
Zip::File.open_buffer(nupkg_buffer) do |zip|
|
96
|
-
lib_file_entries = zip.select { |entry| entry.name.start_with?(folder_name) }
|
97
|
-
# If there is no lib folder in this package, assume it is a development dependency
|
98
|
-
return nil if lib_file_entries.empty?
|
99
|
-
|
100
|
-
lib_file_entries.each do |entry|
|
101
|
-
_, tfm = entry.name.split("/").first(2)
|
102
|
-
|
103
|
-
# some zip compressors create empty directory entries (in this case `lib/`) which can cause the string
|
104
|
-
# split to return `nil`, so we have to explicitly guard against that
|
105
|
-
tfms << tfm if tfm
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
tfms.to_a
|
110
|
-
end
|
111
|
-
|
112
|
-
cache[key]
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
@@ -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
|