dependabot-core 0.84.1 → 0.85.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,148 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "nokogiri"
4
- require "dependabot/file_updaters/java/maven"
5
- require "dependabot/file_parsers/java/maven"
6
- require "dependabot/file_parsers/java/maven/property_value_finder"
7
-
8
- module Dependabot
9
- module FileUpdaters
10
- module Java
11
- class Maven
12
- class DeclarationFinder
13
- DECLARATION_REGEX =
14
- %r{<parent>.*?</parent>|<dependency>.*?</dependency>|
15
- <plugin>.*?</plugin>|<extension>.*?</extension>}mx.freeze
16
-
17
- attr_reader :dependency, :declaring_requirement, :dependency_files
18
-
19
- def initialize(dependency:, dependency_files:, declaring_requirement:)
20
- @dependency = dependency
21
- @dependency_files = dependency_files
22
- @declaring_requirement = declaring_requirement
23
- end
24
-
25
- def declaration_strings
26
- @declaration_strings ||= fetch_pom_declaration_strings
27
- end
28
-
29
- def declaration_nodes
30
- declaration_strings.map do |declaration_string|
31
- Nokogiri::XML(declaration_string)
32
- end
33
- end
34
-
35
- private
36
-
37
- def declaring_pom
38
- filename = declaring_requirement.fetch(:file)
39
- declaring_pom = dependency_files.find { |f| f.name == filename }
40
- return declaring_pom if declaring_pom
41
-
42
- raise "No pom found with name #{filename}!"
43
- end
44
-
45
- def dependency_name
46
- dependency.name
47
- end
48
-
49
- def fetch_pom_declaration_strings
50
- deep_find_declarations(declaring_pom.content).select do |nd|
51
- node = Nokogiri::XML(nd)
52
- node.remove_namespaces!
53
- next false unless node_group_id(node)
54
- next false unless node.at_xpath("./*/artifactId")
55
-
56
- node_name = [
57
- node_group_id(node),
58
- evaluated_value(node.at_xpath("./*/artifactId").content.strip)
59
- ].compact.join(":")
60
-
61
- next false unless node_name == dependency_name
62
- next false unless packaging_type_matches?(node)
63
-
64
- declaring_requirement_matches?(node)
65
- end
66
- end
67
-
68
- def node_group_id(node)
69
- unless node.at_xpath("./*/groupId") || node.at_xpath("./plugin")
70
- return
71
- end
72
- unless node.at_xpath("./*/groupId")
73
- return "org.apache.maven.plugins"
74
- end
75
-
76
- evaluated_value(node.at_xpath("./*/groupId").content.strip)
77
- end
78
-
79
- def deep_find_declarations(string)
80
- string.scan(DECLARATION_REGEX).flat_map do |matching_node|
81
- [matching_node, *deep_find_declarations(matching_node[1..-1])]
82
- end
83
- end
84
-
85
- def declaring_requirement_matches?(node)
86
- node_requirement = node.at_css("version")&.content&.strip
87
-
88
- if declaring_requirement.dig(:metadata, :property_name)
89
- return false unless node_requirement
90
-
91
- property_name =
92
- node_requirement.
93
- match(FileParsers::Java::Maven::PROPERTY_REGEX)&.
94
- named_captures&.
95
- fetch("property")
96
-
97
- property_name == declaring_requirement[:metadata][:property_name]
98
- else
99
- node_requirement == declaring_requirement.fetch(:requirement)
100
- end
101
- end
102
-
103
- def packaging_type_matches?(node)
104
- type = declaring_requirement.dig(:metadata, :packaging_type)
105
- type == packaging_type(node)
106
- end
107
-
108
- def packaging_type(dependency_node)
109
- return "pom" if dependency_node.child.node_name == "parent"
110
- return "jar" unless dependency_node.at_xpath("./*/type")
111
-
112
- packaging_type_content = dependency_node.at_xpath("./*/type").
113
- content.strip
114
-
115
- evaluated_value(packaging_type_content)
116
- end
117
-
118
- def evaluated_value(value)
119
- unless value.match?(FileParsers::Java::Maven::PROPERTY_REGEX)
120
- return value
121
- end
122
-
123
- property_name =
124
- value.match(FileParsers::Java::Maven::PROPERTY_REGEX).
125
- named_captures.fetch("property")
126
-
127
- property_value =
128
- property_value_finder.
129
- property_details(
130
- property_name: property_name,
131
- callsite_pom: declaring_pom
132
- )&.fetch(:value)
133
-
134
- return value unless property_value
135
-
136
- value.gsub(FileParsers::Java::Maven::PROPERTY_REGEX, property_value)
137
- end
138
-
139
- def property_value_finder
140
- @property_value_finder ||=
141
- FileParsers::Java::Maven::PropertyValueFinder.
142
- new(dependency_files: dependency_files)
143
- end
144
- end
145
- end
146
- end
147
- end
148
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "nokogiri"
4
-
5
- require "dependabot/dependency_file"
6
- require "dependabot/file_updaters/java/maven"
7
- require "dependabot/file_parsers/java/maven/property_value_finder"
8
-
9
- module Dependabot
10
- module FileUpdaters
11
- module Java
12
- class Maven
13
- class PropertyValueUpdater
14
- def initialize(dependency_files:)
15
- @dependency_files = dependency_files
16
- end
17
-
18
- def update_pomfiles_for_property_change(property_name:, callsite_pom:,
19
- updated_value:)
20
- declaration_details = property_value_finder.property_details(
21
- property_name: property_name,
22
- callsite_pom: callsite_pom
23
- )
24
- node = declaration_details.fetch(:node)
25
- filename = declaration_details.fetch(:file)
26
-
27
- pom_to_update = dependency_files.find { |f| f.name == filename }
28
- updated_content = pom_to_update.content.sub(
29
- %r{<#{Regexp.quote(node.name)}>
30
- \s*#{Regexp.quote(node.content)}\s*
31
- </#{Regexp.quote(node.name)}>}xm,
32
- "<#{node.name}>#{updated_value}</#{node.name}>"
33
- )
34
-
35
- updated_pomfiles = dependency_files.dup
36
- updated_pomfiles[updated_pomfiles.index(pom_to_update)] =
37
- update_file(file: pom_to_update, content: updated_content)
38
-
39
- updated_pomfiles
40
- end
41
-
42
- private
43
-
44
- attr_reader :dependency_files
45
-
46
- def property_value_finder
47
- @property_value_finder ||=
48
- FileParsers::Java::Maven::PropertyValueFinder.
49
- new(dependency_files: dependency_files)
50
- end
51
-
52
- def update_file(file:, content:)
53
- updated_file = file.dup
54
- updated_file.content = content
55
- updated_file
56
- end
57
- end
58
- end
59
- end
60
- end
61
- end
@@ -1,173 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "nokogiri"
4
- require "dependabot/metadata_finders/base"
5
- require "dependabot/file_fetchers/base"
6
- require "dependabot/file_parsers/java/maven"
7
- require "dependabot/file_parsers/java/maven/repositories_finder"
8
-
9
- module Dependabot
10
- module MetadataFinders
11
- module Java
12
- class Maven < Dependabot::MetadataFinders::Base
13
- DOT_SEPARATOR_REGEX = %r{\.(?:(?!\d+[.\/])+)}.freeze
14
-
15
- private
16
-
17
- def look_up_source
18
- tmp_source = look_up_source_in_pom(dependency_pom_file)
19
- return tmp_source if tmp_source
20
-
21
- return unless (parent = parent_pom_file(dependency_pom_file))
22
-
23
- tmp_source = look_up_source_in_pom(parent)
24
- return unless tmp_source
25
-
26
- artifact = dependency.name.split(":").last
27
- return tmp_source if tmp_source.repo.end_with?(artifact)
28
- return tmp_source if repo_has_subdir_for_dep?(tmp_source)
29
- end
30
-
31
- def repo_has_subdir_for_dep?(tmp_source)
32
- @repo_has_subdir_for_dep ||= {}
33
- if @repo_has_subdir_for_dep.key?(tmp_source)
34
- return @repo_has_subdir_for_dep[tmp_source]
35
- end
36
-
37
- artifact = dependency.name.split(":").last
38
- fetcher =
39
- FileFetchers::Base.new(source: tmp_source, credentials: credentials)
40
-
41
- @repo_has_subdir_for_dep[tmp_source] =
42
- fetcher.send(:repo_contents, raise_errors: false).
43
- select { |f| f.type == "dir" }.
44
- any? { |f| artifact.end_with?(f.name) }
45
- rescue Dependabot::RepoNotFound
46
- @repo_has_subdir_for_dep[tmp_source] = false
47
- end
48
-
49
- def look_up_source_in_pom(pom)
50
- potential_source_urls = [
51
- pom.at_css("project > url")&.content,
52
- pom.at_css("project > scm > url")&.content,
53
- pom.at_css("project > issueManagement > url")&.content
54
- ].compact
55
-
56
- source_url = potential_source_urls.find { |url| Source.from_url(url) }
57
- source_url ||= source_from_anywhere_in_pom(pom)
58
- source_url = substitute_property_in_source_url(source_url, pom)
59
-
60
- Source.from_url(source_url)
61
- end
62
-
63
- def substitute_property_in_source_url(source_url, pom)
64
- return unless source_url
65
- return source_url unless source_url.include?("${")
66
-
67
- regex = FileParsers::Java::Maven::PROPERTY_REGEX
68
- property_name = source_url.match(regex).named_captures["property"]
69
- doc = pom.dup
70
- doc.remove_namespaces!
71
- nm = property_name.sub(/^pom\./, "").sub(/^project\./, "")
72
- property_value =
73
- loop do
74
- candidate_node =
75
- doc.at_xpath("/project/#{nm}") ||
76
- doc.at_xpath("/project/properties/#{nm}") ||
77
- doc.at_xpath("/project/profiles/profile/properties/#{nm}")
78
- break candidate_node.content if candidate_node
79
- break unless nm.match?(DOT_SEPARATOR_REGEX)
80
-
81
- nm = nm.sub(DOT_SEPARATOR_REGEX, "/")
82
- end
83
-
84
- source_url.gsub("${#{property_name}}", property_value)
85
- end
86
-
87
- def source_from_anywhere_in_pom(pom)
88
- github_urls = []
89
- pom.to_s.scan(Source::SOURCE_REGEX) do
90
- github_urls << Regexp.last_match.to_s
91
- end
92
-
93
- github_urls.find do |url|
94
- repo = Source.from_url(url).repo
95
- repo.end_with?(dependency.name.split(":").last)
96
- end
97
- end
98
-
99
- def dependency_pom_file
100
- return @dependency_pom_file unless @dependency_pom_file.nil?
101
-
102
- artifact_id = dependency.name.split(":").last
103
- response = Excon.get(
104
- "#{maven_repo_dependency_url}/"\
105
- "#{dependency.version}/"\
106
- "#{artifact_id}-#{dependency.version}.pom",
107
- headers: auth_details,
108
- idempotent: true,
109
- **SharedHelpers.excon_defaults
110
- )
111
-
112
- @dependency_pom_file = Nokogiri::XML(response.body)
113
- rescue Excon::Error::Timeout
114
- @dependency_pom_file = Nokogiri::XML("")
115
- end
116
-
117
- def parent_pom_file(pom)
118
- doc = pom.dup
119
- doc.remove_namespaces!
120
- group_id = doc.at_xpath("/project/parent/groupId")&.content&.strip
121
- artifact_id =
122
- doc.at_xpath("/project/parent/artifactId")&.content&.strip
123
- version = doc.at_xpath("/project/parent/version")&.content&.strip
124
-
125
- return unless artifact_id && group_id && version
126
-
127
- response = Excon.get(
128
- "#{maven_repo_url}/#{group_id.tr('.', '/')}/#{artifact_id}/"\
129
- "#{version}/"\
130
- "#{artifact_id}-#{version}.pom",
131
- headers: auth_details,
132
- idempotent: true,
133
- **SharedHelpers.excon_defaults
134
- )
135
-
136
- Nokogiri::XML(response.body)
137
- end
138
-
139
- def maven_repo_url
140
- source = dependency.requirements.
141
- find { |r| r&.fetch(:source) }&.fetch(:source)
142
-
143
- source&.fetch(:url, nil) ||
144
- source&.fetch("url") ||
145
- FileParsers::Java::Maven::RepositoriesFinder::CENTRAL_REPO_URL
146
- end
147
-
148
- def maven_repo_dependency_url
149
- group_id, artifact_id = dependency.name.split(":")
150
-
151
- "#{maven_repo_url}/#{group_id.tr('.', '/')}/#{artifact_id}"
152
- end
153
-
154
- def auth_details
155
- cred =
156
- credentials.select { |c| c["type"] == "maven_repository" }.
157
- find do |c|
158
- cred_url = c.fetch("url").gsub(%r{/+$}, "")
159
- next false unless cred_url == maven_repo_url
160
-
161
- c.fetch("username", nil)
162
- end
163
-
164
- return {} unless cred
165
-
166
- token = cred.fetch("username") + ":" + cred.fetch("password")
167
- encoded_token = Base64.encode64(token).delete("\n")
168
- { "Authorization" => "Basic #{encoded_token}" }
169
- end
170
- end
171
- end
172
- end
173
- end
@@ -1,159 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/update_checkers/base"
4
- require "dependabot/file_parsers/java/maven/property_value_finder"
5
-
6
- module Dependabot
7
- module UpdateCheckers
8
- module Java
9
- class Maven < Dependabot::UpdateCheckers::Base
10
- require_relative "maven/requirements_updater"
11
- require_relative "maven/version_finder"
12
- require_relative "maven/property_updater"
13
-
14
- def latest_version
15
- latest_version_details&.fetch(:version)
16
- end
17
-
18
- def latest_resolvable_version
19
- # Maven's version resolution algorithm is very simple: it just uses
20
- # the version defined "closest", with the first declaration winning
21
- # if two declarations are equally close. As a result, we can just
22
- # return that latest version unless dealing with a property dep.
23
- # https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Transitive_Dependencies
24
- return nil if version_comes_from_multi_dependency_property?
25
-
26
- latest_version
27
- end
28
-
29
- def latest_resolvable_version_with_no_unlock
30
- # Irrelevant, since Maven has a single dependency file (the pom.xml).
31
- #
32
- # For completeness we ought to resolve the pom.xml and return the
33
- # latest version that satisfies the current constraint AND any
34
- # constraints placed on it by other dependencies. Seeing as we're
35
- # never going to take any action as a result, though, we just return
36
- # nil.
37
- nil
38
- end
39
-
40
- def updated_requirements
41
- property_names =
42
- declarations_using_a_property.
43
- map { |req| req.dig(:metadata, :property_name) }
44
-
45
- RequirementsUpdater.new(
46
- requirements: dependency.requirements,
47
- latest_version: latest_version&.to_s,
48
- source_url: latest_version_details&.fetch(:source_url),
49
- properties_to_update: property_names
50
- ).updated_requirements
51
- end
52
-
53
- def requirements_unlocked_or_can_be?
54
- declarations_using_a_property.none? do |requirement|
55
- prop_name = requirement.dig(:metadata, :property_name)
56
- pom = dependency_files.find { |f| f.name == requirement[:file] }
57
-
58
- declaration_pom_name =
59
- property_value_finder.
60
- property_details(property_name: prop_name, callsite_pom: pom)&.
61
- fetch(:file)
62
-
63
- declaration_pom_name == "remote_pom.xml" ||
64
- declaration_pom_name.end_with?("pom_parent.xml")
65
- end
66
- end
67
-
68
- private
69
-
70
- def latest_version_resolvable_with_full_unlock?
71
- return false unless version_comes_from_multi_dependency_property?
72
-
73
- property_updater.update_possible?
74
- end
75
-
76
- def updated_dependencies_after_full_unlock
77
- property_updater.updated_dependencies
78
- end
79
-
80
- def numeric_version_up_to_date?
81
- return false unless version_class.correct?(dependency.version)
82
-
83
- super
84
- end
85
-
86
- def numeric_version_can_update?(requirements_to_unlock:)
87
- return false unless version_class.correct?(dependency.version)
88
-
89
- super
90
- end
91
-
92
- def latest_version_details
93
- @latest_version_details ||= version_finder.latest_version_details
94
- end
95
-
96
- def version_finder
97
- @version_finder ||=
98
- VersionFinder.new(
99
- dependency: dependency,
100
- dependency_files: dependency_files,
101
- credentials: credentials,
102
- ignored_versions: ignored_versions
103
- )
104
- end
105
-
106
- def property_updater
107
- @property_updater ||=
108
- PropertyUpdater.new(
109
- dependency: dependency,
110
- dependency_files: dependency_files,
111
- target_version_details: latest_version_details,
112
- credentials: credentials,
113
- ignored_versions: ignored_versions
114
- )
115
- end
116
-
117
- def property_value_finder
118
- @property_value_finder ||=
119
- FileParsers::Java::Maven::PropertyValueFinder.
120
- new(dependency_files: dependency_files)
121
- end
122
-
123
- def version_comes_from_multi_dependency_property?
124
- declarations_using_a_property.any? do |requirement|
125
- property_name = requirement.fetch(:metadata).fetch(:property_name)
126
- property_source = requirement.fetch(:metadata).
127
- fetch(:property_source)
128
-
129
- all_property_based_dependencies.any? do |dep|
130
- next false if dep.name == dependency.name
131
-
132
- dep.requirements.any? do |req|
133
- next unless req.dig(:metadata, :property_name) == property_name
134
-
135
- req.dig(:metadata, :property_source) == property_source
136
- end
137
- end
138
- end
139
- end
140
-
141
- def declarations_using_a_property
142
- @declarations_using_a_property ||=
143
- dependency.requirements.
144
- select { |req| req.dig(:metadata, :property_name) }
145
- end
146
-
147
- def all_property_based_dependencies
148
- @all_property_based_dependencies ||=
149
- FileParsers::Java::Maven.new(
150
- dependency_files: dependency_files,
151
- source: nil
152
- ).parse.select do |dep|
153
- dep.requirements.any? { |req| req.dig(:metadata, :property_name) }
154
- end
155
- end
156
- end
157
- end
158
- end
159
- end