dependabot-core 0.84.1 → 0.85.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.
@@ -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