dependabot-vcpkg 0.389.0 → 0.390.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/lib/dependabot/vcpkg/file_parser.rb +83 -34
- data/lib/dependabot/vcpkg/file_updater.rb +127 -12
- data/lib/dependabot/vcpkg/manifest_baseline.rb +112 -0
- data/lib/dependabot/vcpkg/package/package_details_fetcher.rb +33 -91
- data/lib/dependabot/vcpkg/package/versions_database.rb +277 -0
- data/lib/dependabot/vcpkg/requirement.rb +42 -3
- data/lib/dependabot/vcpkg/update_checker/latest_version_finder.rb +49 -0
- data/lib/dependabot/vcpkg/update_checker/security_fix_resolver.rb +290 -0
- data/lib/dependabot/vcpkg/update_checker.rb +119 -17
- data/lib/dependabot/vcpkg/version.rb +304 -33
- data/lib/dependabot/vcpkg.rb +31 -0
- metadata +7 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bc65886cc56d34d9e32ca3dfe8a5ebcf25219d48b6c8276a62975974d1327bf8
|
|
4
|
+
data.tar.gz: ac856f5a7eaf627129324fd03ae4379eca0667370a63db31ed6f9e3073d3ea87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6ef838b9a47174b9fb9b664115d5688391446a7104533ec5e06ed894917b0c680bf0be1d6c35de8b99bbfd1a90eedcd7d92b43622b1db1011bae7fff8a3448c3
|
|
7
|
+
data.tar.gz: 6015c043d8bec0d168028712c3455195d40df263dd691eddcdf63b8c35e1a32ef13f6e8ac563cfac74eb53b6a1264ddc46a11d758d8bdc3415ce9513757768c7
|
|
@@ -10,7 +10,10 @@ require "dependabot/logger"
|
|
|
10
10
|
|
|
11
11
|
require "dependabot/vcpkg"
|
|
12
12
|
require "dependabot/vcpkg/language"
|
|
13
|
+
require "dependabot/vcpkg/manifest_baseline"
|
|
14
|
+
require "dependabot/vcpkg/package/versions_database"
|
|
13
15
|
require "dependabot/vcpkg/package_manager"
|
|
16
|
+
require "dependabot/vcpkg/version"
|
|
14
17
|
|
|
15
18
|
module Dependabot
|
|
16
19
|
module Vcpkg
|
|
@@ -124,7 +127,7 @@ module Dependabot
|
|
|
124
127
|
|
|
125
128
|
sig do
|
|
126
129
|
params(
|
|
127
|
-
dep:
|
|
130
|
+
dep: Object,
|
|
128
131
|
dependency_file: Dependabot::DependencyFile
|
|
129
132
|
)
|
|
130
133
|
.returns(T.nilable(Dependabot::Dependency))
|
|
@@ -132,40 +135,95 @@ module Dependabot
|
|
|
132
135
|
def parse_port_dependency(dep:, dependency_file:)
|
|
133
136
|
case dep
|
|
134
137
|
when String
|
|
135
|
-
|
|
136
|
-
Dependabot.logger.warn("Skipping vcpkg dependency '#{dep}' without version>= constraint")
|
|
137
|
-
nil
|
|
138
|
+
build_port_dependency(name: dep, constraint: nil, dependency_file:)
|
|
138
139
|
when Hash
|
|
139
140
|
name = dep["name"]
|
|
140
|
-
version_constraint = dep["version>="]
|
|
141
|
-
|
|
142
141
|
return nil unless name.is_a?(String)
|
|
143
142
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return nil
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Parse version and optional port-version
|
|
150
|
-
version, _port_version = parse_version_with_port(version_constraint)
|
|
151
|
-
|
|
152
|
-
Dependabot::Dependency.new(
|
|
153
|
-
name:,
|
|
154
|
-
version:,
|
|
155
|
-
package_manager: "vcpkg",
|
|
156
|
-
requirements: [{
|
|
157
|
-
requirement: ">=#{version_constraint}",
|
|
158
|
-
groups: [],
|
|
159
|
-
source: nil,
|
|
160
|
-
file: dependency_file.name
|
|
161
|
-
}]
|
|
162
|
-
)
|
|
143
|
+
constraint = dep[VCPKG_VERSION_CONSTRAINT_KEY]
|
|
144
|
+
build_port_dependency(name:, constraint: constraint.is_a?(String) ? constraint : nil, dependency_file:)
|
|
163
145
|
else
|
|
164
146
|
Dependabot.logger.warn("Skipping unknown vcpkg dependency format: #{dep.inspect}")
|
|
165
147
|
nil
|
|
166
148
|
end
|
|
167
149
|
end
|
|
168
150
|
|
|
151
|
+
# A port's version comes from its `version>=` constraint, the registry baseline, or both.
|
|
152
|
+
# vcpkg installs the lowest version satisfying every constraint, so where both are present
|
|
153
|
+
# the effective version is the higher of the two.
|
|
154
|
+
sig do
|
|
155
|
+
params(
|
|
156
|
+
name: String,
|
|
157
|
+
constraint: T.nilable(String),
|
|
158
|
+
dependency_file: Dependabot::DependencyFile
|
|
159
|
+
)
|
|
160
|
+
.returns(T.nilable(Dependabot::Dependency))
|
|
161
|
+
end
|
|
162
|
+
def build_port_dependency(name:, constraint:, dependency_file:)
|
|
163
|
+
version = effective_port_version(name:, constraint:)
|
|
164
|
+
|
|
165
|
+
unless version
|
|
166
|
+
Dependabot.logger.warn("Skipping vcpkg dependency '#{name}' without version>= constraint")
|
|
167
|
+
return nil
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
Dependabot::Dependency.new(
|
|
171
|
+
name:,
|
|
172
|
+
version: version.to_s,
|
|
173
|
+
package_manager: "vcpkg",
|
|
174
|
+
requirements: [{
|
|
175
|
+
requirement: constraint && ">=#{constraint}",
|
|
176
|
+
groups: [],
|
|
177
|
+
source: nil,
|
|
178
|
+
file: dependency_file.name
|
|
179
|
+
}]
|
|
180
|
+
)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
sig { params(name: String, constraint: T.nilable(String)).returns(T.nilable(Dependabot::Vcpkg::Version)) }
|
|
184
|
+
def effective_port_version(name:, constraint:)
|
|
185
|
+
constraint_version = constraint && Version.correct?(constraint) ? Version.new(constraint) : nil
|
|
186
|
+
baseline_version = baseline_port_version(name)
|
|
187
|
+
|
|
188
|
+
return constraint_version unless baseline_version
|
|
189
|
+
return baseline_version unless constraint_version
|
|
190
|
+
return constraint_version unless constraint_version.comparable_with?(baseline_version)
|
|
191
|
+
|
|
192
|
+
[constraint_version, baseline_version].max
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
sig { params(name: String).returns(T.nilable(Dependabot::Vcpkg::Version)) }
|
|
196
|
+
def baseline_port_version(name)
|
|
197
|
+
ref = builtin_baseline_ref
|
|
198
|
+
return nil unless ref
|
|
199
|
+
|
|
200
|
+
versions_database.baseline_version_for(port: name, ref:)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# The commit the manifest pins the built-in registry to. Ports resolved from any other
|
|
204
|
+
# registry are left alone, because the versions database shipped with the image only
|
|
205
|
+
# describes the built-in one.
|
|
206
|
+
sig { returns(T.nilable(String)) }
|
|
207
|
+
def builtin_baseline_ref
|
|
208
|
+
manifest_baseline.ref
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
sig { returns(Dependabot::Vcpkg::ManifestBaseline) }
|
|
212
|
+
def manifest_baseline
|
|
213
|
+
@manifest_baseline ||= T.let(
|
|
214
|
+
Dependabot::Vcpkg::ManifestBaseline.new(dependency_files:),
|
|
215
|
+
T.nilable(Dependabot::Vcpkg::ManifestBaseline)
|
|
216
|
+
)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
sig { returns(Dependabot::Vcpkg::Package::VersionsDatabase) }
|
|
220
|
+
def versions_database
|
|
221
|
+
@versions_database ||= T.let(
|
|
222
|
+
Dependabot::Vcpkg::Package::VersionsDatabase.new,
|
|
223
|
+
T.nilable(Dependabot::Vcpkg::Package::VersionsDatabase)
|
|
224
|
+
)
|
|
225
|
+
end
|
|
226
|
+
|
|
169
227
|
sig do
|
|
170
228
|
params(
|
|
171
229
|
registry: T::Hash[String, T.untyped],
|
|
@@ -230,15 +288,6 @@ module Dependabot
|
|
|
230
288
|
end
|
|
231
289
|
end
|
|
232
290
|
|
|
233
|
-
sig { params(version_string: String).returns([String, T.nilable(String)]) }
|
|
234
|
-
def parse_version_with_port(version_string)
|
|
235
|
-
if version_string.include?("#")
|
|
236
|
-
version_string.split("#", 2).then { |parts| [parts[0] || "", parts[1]] }
|
|
237
|
-
else
|
|
238
|
-
[version_string, nil]
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
|
|
242
291
|
# A project relying on a global vcpkg install has no baseline to update.
|
|
243
292
|
# Synthesize one so the updater adds it to the manifest; later runs keep it
|
|
244
293
|
# current. See https://github.com/dependabot/dependabot-core/issues/13051
|
|
@@ -7,6 +7,8 @@ require "sorbet-runtime"
|
|
|
7
7
|
require "dependabot/file_updaters"
|
|
8
8
|
require "dependabot/file_updaters/base"
|
|
9
9
|
require "dependabot/vcpkg"
|
|
10
|
+
require "dependabot/vcpkg/manifest_baseline"
|
|
11
|
+
require "dependabot/vcpkg/version"
|
|
10
12
|
|
|
11
13
|
module Dependabot
|
|
12
14
|
module Vcpkg
|
|
@@ -19,7 +21,7 @@ module Dependabot
|
|
|
19
21
|
|
|
20
22
|
# Handle vcpkg.json
|
|
21
23
|
vcpkg_json_file = get_original_file(VCPKG_JSON_FILENAME)
|
|
22
|
-
if vcpkg_json_file
|
|
24
|
+
if vcpkg_json_file && rewrite?(vcpkg_json_file)
|
|
23
25
|
updated_files << updated_file(
|
|
24
26
|
file: vcpkg_json_file,
|
|
25
27
|
content: updated_vcpkg_json_content(vcpkg_json_file)
|
|
@@ -28,7 +30,7 @@ module Dependabot
|
|
|
28
30
|
|
|
29
31
|
# Handle vcpkg-configuration.json
|
|
30
32
|
vcpkg_config_file = get_original_file(VCPKG_CONFIGURATION_JSON_FILENAME)
|
|
31
|
-
if vcpkg_config_file
|
|
33
|
+
if vcpkg_config_file && rewrite?(vcpkg_config_file)
|
|
32
34
|
updated_files << updated_file(
|
|
33
35
|
file: vcpkg_config_file,
|
|
34
36
|
content: updated_vcpkg_configuration_json_content(vcpkg_config_file)
|
|
@@ -40,6 +42,14 @@ module Dependabot
|
|
|
40
42
|
|
|
41
43
|
private
|
|
42
44
|
|
|
45
|
+
# A security fix can move the baseline in a file that none of the updated dependencies
|
|
46
|
+
# declare a requirement against, so that file needs rewriting even though `file_changed?`
|
|
47
|
+
# says otherwise.
|
|
48
|
+
sig { params(file: Dependabot::DependencyFile).returns(T::Boolean) }
|
|
49
|
+
def rewrite?(file)
|
|
50
|
+
file_changed?(file) || security_baseline&.fetch(:file) == file.name
|
|
51
|
+
end
|
|
52
|
+
|
|
43
53
|
sig { override.void }
|
|
44
54
|
def check_required_files
|
|
45
55
|
return if get_original_file(VCPKG_JSON_FILENAME) || get_original_file(VCPKG_CONFIGURATION_JSON_FILENAME)
|
|
@@ -57,6 +67,8 @@ module Dependabot
|
|
|
57
67
|
.select { |_, requirement| requirement }
|
|
58
68
|
.each { |dependency, _| update_dependency_in_content(parsed_content, dependency, file.name) }
|
|
59
69
|
|
|
70
|
+
apply_security_baseline(parsed_content, file.name)
|
|
71
|
+
|
|
60
72
|
JSON.pretty_generate(parsed_content)
|
|
61
73
|
rescue JSON::ParserError
|
|
62
74
|
raise Dependabot::DependencyFileNotParseable, file.path
|
|
@@ -72,6 +84,8 @@ module Dependabot
|
|
|
72
84
|
.select { |_, requirement| requirement }
|
|
73
85
|
.each { |dependency, _| update_registry_dependency_in_content(parsed_content, dependency, file.name) }
|
|
74
86
|
|
|
87
|
+
apply_security_baseline(parsed_content, file.name)
|
|
88
|
+
|
|
75
89
|
JSON.pretty_generate(parsed_content)
|
|
76
90
|
rescue JSON::ParserError
|
|
77
91
|
raise Dependabot::DependencyFileNotParseable, file.path
|
|
@@ -83,24 +97,125 @@ module Dependabot
|
|
|
83
97
|
when VCPKG_DEFAULT_BASELINE_DEPENDENCY_NAME
|
|
84
98
|
update_baseline_in_content(content, dependency, filename)
|
|
85
99
|
else
|
|
86
|
-
update_port_dependency_in_content(content, dependency)
|
|
100
|
+
update_port_dependency_in_content(content, dependency, filename)
|
|
87
101
|
end
|
|
88
102
|
end
|
|
89
103
|
|
|
90
104
|
sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency, filename: String).void }
|
|
91
105
|
def update_baseline_in_content(content, dependency, filename)
|
|
92
|
-
update_baseline_field(content, dependency, filename,
|
|
106
|
+
update_baseline_field(content, dependency, filename, VCPKG_BUILTIN_BASELINE_KEY)
|
|
93
107
|
end
|
|
94
108
|
|
|
109
|
+
sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency, filename: String).void }
|
|
110
|
+
def update_port_dependency_in_content(content, dependency, filename)
|
|
111
|
+
case remediation_for(dependency, filename)
|
|
112
|
+
when :override then apply_override(content, dependency)
|
|
113
|
+
# A baseline bump moves the port's version floor, so the port entry needs no change.
|
|
114
|
+
when :baseline then nil
|
|
115
|
+
else update_version_constraint(content, dependency)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
sig do
|
|
120
|
+
params(dependency: Dependabot::Dependency, filename: String).returns(T.nilable(Symbol))
|
|
121
|
+
end
|
|
122
|
+
def remediation_for(dependency, filename)
|
|
123
|
+
requirement = dependency.requirements.find { |r| r[:file] == filename }
|
|
124
|
+
metadata = requirement&.dig(:metadata)
|
|
125
|
+
return nil unless metadata.is_a?(Hash)
|
|
126
|
+
|
|
127
|
+
metadata[:security_remediation]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency).void }
|
|
131
|
+
def update_version_constraint(content, dependency)
|
|
132
|
+
entries = content[VCPKG_DEPENDENCIES_KEY]
|
|
133
|
+
return unless entries.is_a?(Array)
|
|
134
|
+
|
|
135
|
+
index = entries.index { |entry| port_entry_name(entry) == dependency.name }
|
|
136
|
+
return unless index
|
|
137
|
+
|
|
138
|
+
entry = entries[index]
|
|
139
|
+
# A port declared as a bare string has to become an object to carry a constraint.
|
|
140
|
+
entry = { "name" => entry } if entry.is_a?(String)
|
|
141
|
+
return unless entry.is_a?(Hash)
|
|
142
|
+
|
|
143
|
+
entry[VCPKG_VERSION_CONSTRAINT_KEY] = dependency.version
|
|
144
|
+
entries[index] = entry
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# vcpkg cannot compare versions across schemes, so when no safe version shares the current
|
|
148
|
+
# one's scheme, the only way to move the port is to pin it outright. `version` is the
|
|
149
|
+
# scheme-agnostic key, and the port version belongs in it as a `#N` suffix: the separate
|
|
150
|
+
# `port-version` key and the scheme-specific keys are both deprecated.
|
|
151
|
+
# See https://learn.microsoft.com/vcpkg/reference/vcpkg-json#overrides
|
|
95
152
|
sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency).void }
|
|
96
|
-
def
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
153
|
+
def apply_override(content, dependency)
|
|
154
|
+
entry = { "name" => dependency.name, "version" => dependency.version }
|
|
155
|
+
|
|
156
|
+
overrides = content[VCPKG_OVERRIDES_KEY]
|
|
157
|
+
unless overrides.is_a?(Array)
|
|
158
|
+
overrides = []
|
|
159
|
+
content[VCPKG_OVERRIDES_KEY] = overrides
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
index = overrides.index { |override| override.is_a?(Hash) && override["name"] == dependency.name }
|
|
163
|
+
index ? overrides[index] = entry : overrides << entry
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
sig { params(entry: T.untyped).returns(T.nilable(String)) }
|
|
167
|
+
def port_entry_name(entry)
|
|
168
|
+
return entry if entry.is_a?(String)
|
|
169
|
+
return nil unless entry.is_a?(Hash)
|
|
170
|
+
|
|
171
|
+
name = entry["name"]
|
|
172
|
+
name.is_a?(String) ? name : nil
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Where the fix wants the registry baseline moved to, if anywhere.
|
|
176
|
+
sig { returns(T.nilable(T::Hash[Symbol, String])) }
|
|
177
|
+
def security_baseline
|
|
178
|
+
return @security_baseline if @looked_up_security_baseline
|
|
179
|
+
|
|
180
|
+
@looked_up_security_baseline = T.let(true, T.nilable(T::Boolean))
|
|
181
|
+
@security_baseline = T.let(build_security_baseline, T.nilable(T::Hash[Symbol, String]))
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
sig { returns(T.nilable(T::Hash[Symbol, String])) }
|
|
185
|
+
def build_security_baseline
|
|
186
|
+
commit_sha = dependencies
|
|
187
|
+
.flat_map(&:requirements)
|
|
188
|
+
.filter_map { |requirement| requirement.dig(:metadata, :baseline_commit_sha) }
|
|
189
|
+
.first
|
|
190
|
+
return nil unless commit_sha.is_a?(String)
|
|
191
|
+
|
|
192
|
+
location = manifest_baseline.location
|
|
193
|
+
return nil unless location
|
|
194
|
+
|
|
195
|
+
{ file: location.first, commit_sha: }
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
sig { params(content: T::Hash[String, T.untyped], filename: String).void }
|
|
199
|
+
def apply_security_baseline(content, filename)
|
|
200
|
+
baseline = security_baseline
|
|
201
|
+
return unless baseline && baseline[:file] == filename
|
|
202
|
+
|
|
203
|
+
path = T.must(manifest_baseline.location).last
|
|
204
|
+
key = path.last
|
|
205
|
+
return unless key
|
|
206
|
+
|
|
207
|
+
target = T.must(path[0...-1]).reduce(content) { |node, segment| node.is_a?(Hash) ? node[segment] : nil }
|
|
208
|
+
return unless target.is_a?(Hash)
|
|
209
|
+
|
|
210
|
+
target[key] = baseline[:commit_sha]
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
sig { returns(Dependabot::Vcpkg::ManifestBaseline) }
|
|
214
|
+
def manifest_baseline
|
|
215
|
+
@manifest_baseline ||= T.let(
|
|
216
|
+
Dependabot::Vcpkg::ManifestBaseline.new(dependency_files:),
|
|
217
|
+
T.nilable(Dependabot::Vcpkg::ManifestBaseline)
|
|
218
|
+
)
|
|
104
219
|
end
|
|
105
220
|
|
|
106
221
|
sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency, filename: String).void }
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require "sorbet-runtime"
|
|
6
|
+
|
|
7
|
+
require "dependabot/dependency_file"
|
|
8
|
+
|
|
9
|
+
require "dependabot/vcpkg"
|
|
10
|
+
|
|
11
|
+
module Dependabot
|
|
12
|
+
module Vcpkg
|
|
13
|
+
# Finds the commit a manifest pins the built-in registry to.
|
|
14
|
+
#
|
|
15
|
+
# This ignores any other registry, because the versions database shipped with the updater image
|
|
16
|
+
# only describes the built-in one.
|
|
17
|
+
class ManifestBaseline
|
|
18
|
+
extend T::Sig
|
|
19
|
+
|
|
20
|
+
sig { params(dependency_files: T::Array[Dependabot::DependencyFile]).void }
|
|
21
|
+
def initialize(dependency_files:)
|
|
22
|
+
@dependency_files = dependency_files
|
|
23
|
+
@ref = T.let(nil, T.nilable(String))
|
|
24
|
+
@resolved = T.let(false, T::Boolean)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
28
|
+
attr_reader :dependency_files
|
|
29
|
+
|
|
30
|
+
sig { returns(T.nilable(String)) }
|
|
31
|
+
def ref
|
|
32
|
+
return @ref if @resolved
|
|
33
|
+
|
|
34
|
+
@resolved = true
|
|
35
|
+
@ref = manifest_builtin_baseline || default_registry_builtin_baseline
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The file the baseline lives in, and the JSON path to it, so an updater knows what to
|
|
39
|
+
# rewrite.
|
|
40
|
+
sig { returns(T.nilable([String, T::Array[String]])) }
|
|
41
|
+
def location
|
|
42
|
+
return [T.must(vcpkg_manifest_file).name, [VCPKG_BUILTIN_BASELINE_KEY]] if manifest_builtin_baseline
|
|
43
|
+
return nil unless default_registry_builtin_baseline
|
|
44
|
+
|
|
45
|
+
[T.must(vcpkg_configuration_file).name, %w(default-registry baseline)]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
sig { returns(T.nilable(String)) }
|
|
51
|
+
def manifest_builtin_baseline
|
|
52
|
+
manifest = vcpkg_manifest_file
|
|
53
|
+
return nil unless manifest
|
|
54
|
+
|
|
55
|
+
baseline = parsed_json(manifest)&.dig(VCPKG_BUILTIN_BASELINE_KEY)
|
|
56
|
+
baseline.is_a?(String) ? baseline : nil
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
sig { returns(T.nilable(String)) }
|
|
60
|
+
def default_registry_builtin_baseline
|
|
61
|
+
registry = default_registry
|
|
62
|
+
return nil unless registry
|
|
63
|
+
return nil unless builtin_registry?(registry)
|
|
64
|
+
|
|
65
|
+
baseline = registry["baseline"]
|
|
66
|
+
baseline.is_a?(String) ? baseline : nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
sig { returns(T.nilable(T::Hash[String, Object])) }
|
|
70
|
+
def default_registry
|
|
71
|
+
config = vcpkg_configuration_file
|
|
72
|
+
return nil unless config
|
|
73
|
+
|
|
74
|
+
registry = parsed_json(config)&.dig("default-registry")
|
|
75
|
+
registry.is_a?(Hash) ? registry : nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
sig { params(registry: T::Hash[String, Object]).returns(T::Boolean) }
|
|
79
|
+
def builtin_registry?(registry)
|
|
80
|
+
return true if registry["kind"] == "builtin"
|
|
81
|
+
return false unless registry["kind"] == "git"
|
|
82
|
+
|
|
83
|
+
repository = registry["repository"]
|
|
84
|
+
return false unless repository.is_a?(String)
|
|
85
|
+
|
|
86
|
+
official = [VCPKG_DEFAULT_REGISTRY_REPOSITORY, VCPKG_DEFAULT_BASELINE_URL]
|
|
87
|
+
official.include?(repository.delete_suffix("/"))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
91
|
+
def vcpkg_manifest_file
|
|
92
|
+
dependency_files.find { |file| file.name == VCPKG_JSON_FILENAME }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
96
|
+
def vcpkg_configuration_file
|
|
97
|
+
dependency_files.find { |file| file.name == VCPKG_CONFIGURATION_JSON_FILENAME }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
sig { params(file: Dependabot::DependencyFile).returns(T.nilable(T::Hash[String, Object])) }
|
|
101
|
+
def parsed_json(file)
|
|
102
|
+
content = file.content
|
|
103
|
+
return nil unless content
|
|
104
|
+
|
|
105
|
+
parsed = JSON.parse(content)
|
|
106
|
+
parsed.is_a?(Hash) ? parsed : nil
|
|
107
|
+
rescue JSON::ParserError
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -12,6 +12,7 @@ require "dependabot/shared_helpers"
|
|
|
12
12
|
require "dependabot/update_checkers/base"
|
|
13
13
|
|
|
14
14
|
require "dependabot/vcpkg"
|
|
15
|
+
require "dependabot/vcpkg/package/versions_database"
|
|
15
16
|
require "dependabot/vcpkg/version"
|
|
16
17
|
|
|
17
18
|
module Dependabot
|
|
@@ -22,16 +23,21 @@ module Dependabot
|
|
|
22
23
|
|
|
23
24
|
sig do
|
|
24
25
|
params(
|
|
25
|
-
dependency: Dependabot::Dependency
|
|
26
|
+
dependency: Dependabot::Dependency,
|
|
27
|
+
versions_database: Dependabot::Vcpkg::Package::VersionsDatabase
|
|
26
28
|
).void
|
|
27
29
|
end
|
|
28
|
-
def initialize(dependency:)
|
|
30
|
+
def initialize(dependency:, versions_database: Dependabot::Vcpkg::Package::VersionsDatabase.new)
|
|
29
31
|
@dependency = dependency
|
|
32
|
+
@versions_database = versions_database
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
sig { returns(Dependabot::Dependency) }
|
|
33
36
|
attr_reader :dependency
|
|
34
37
|
|
|
38
|
+
sig { returns(Dependabot::Vcpkg::Package::VersionsDatabase) }
|
|
39
|
+
attr_reader :versions_database
|
|
40
|
+
|
|
35
41
|
sig { returns(T.nilable(Dependabot::Package::PackageDetails)) }
|
|
36
42
|
def fetch
|
|
37
43
|
if registry_dependency?
|
|
@@ -75,88 +81,14 @@ module Dependabot
|
|
|
75
81
|
|
|
76
82
|
sig { returns(T.nilable(Dependabot::Package::PackageDetails)) }
|
|
77
83
|
def fetch_port_releases
|
|
78
|
-
|
|
79
|
-
.filter_map { |version_info| create_port_package_release(version_info) }
|
|
80
|
-
.reverse
|
|
81
|
-
.uniq(&:version)
|
|
82
|
-
.then do |releases|
|
|
83
|
-
Dependabot::Package::PackageDetails.new(
|
|
84
|
-
dependency: dependency,
|
|
85
|
-
releases: releases
|
|
86
|
-
)
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
|
91
|
-
def fetch_port_versions_from_git
|
|
92
|
-
port_path = "ports/#{dependency.name}/vcpkg.json"
|
|
93
|
-
vcpkg_repo_path = "/opt/vcpkg"
|
|
94
|
-
|
|
95
|
-
# Get each commit that modified the port's vcpkg.json
|
|
96
|
-
git_log_cmd = [
|
|
97
|
-
"git", "log", "--format=%H", "--follow", "--", port_path
|
|
98
|
-
]
|
|
84
|
+
release_dates = versions_database.release_dates_for(dependency.name)
|
|
99
85
|
|
|
100
|
-
|
|
101
|
-
|
|
86
|
+
releases = versions_database
|
|
87
|
+
.versions_for(dependency.name)
|
|
88
|
+
.map { |port_version| create_port_package_release(port_version, release_dates) }
|
|
89
|
+
.uniq(&:version)
|
|
102
90
|
|
|
103
|
-
|
|
104
|
-
next if line.empty?
|
|
105
|
-
|
|
106
|
-
commit_sha = line.strip
|
|
107
|
-
next unless commit_sha.match?(/\A[0-9a-f]{40}\z/) # Validate SHA format
|
|
108
|
-
|
|
109
|
-
# Get the vcpkg.json content for this commit
|
|
110
|
-
version_info = extract_version_from_commit(commit_sha, port_path)
|
|
111
|
-
version_info[:commit_sha] = commit_sha if version_info
|
|
112
|
-
version_info
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
|
|
116
|
-
Dependabot.logger.warn("Failed to fetch port versions for #{dependency.name}: #{e.message}")
|
|
117
|
-
[]
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
sig { params(commit_sha: String, file_path: String).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
|
121
|
-
def extract_version_from_commit(commit_sha, file_path)
|
|
122
|
-
show_cmd = ["git", "show", "#{commit_sha}:#{file_path}"]
|
|
123
|
-
|
|
124
|
-
file_content = Dependabot::SharedHelpers.run_shell_command(show_cmd.join(" "))
|
|
125
|
-
parsed_json = JSON.parse(file_content)
|
|
126
|
-
|
|
127
|
-
version = parsed_json["version"]
|
|
128
|
-
port_version = parsed_json["port-version"] || 0
|
|
129
|
-
|
|
130
|
-
return nil unless version
|
|
131
|
-
|
|
132
|
-
# Combine version and port-version
|
|
133
|
-
full_version = port_version.zero? ? version : "#{version}##{port_version}"
|
|
134
|
-
|
|
135
|
-
{
|
|
136
|
-
version: version,
|
|
137
|
-
port_version: port_version,
|
|
138
|
-
full_version: full_version,
|
|
139
|
-
commit_date: get_commit_date(commit_sha)
|
|
140
|
-
}
|
|
141
|
-
rescue JSON::ParserError => e
|
|
142
|
-
Dependabot.logger.warn("Failed to parse vcpkg.json for commit #{commit_sha}: #{e.message}")
|
|
143
|
-
nil
|
|
144
|
-
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
|
|
145
|
-
Dependabot.logger.warn("Failed to show file #{file_path} for commit #{commit_sha}: #{e.message}")
|
|
146
|
-
nil
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
sig { params(commit_sha: String).returns(T.nilable(Time)) }
|
|
150
|
-
def get_commit_date(commit_sha)
|
|
151
|
-
date_cmd = ["git", "show", "--no-patch", "--format=%ci", commit_sha]
|
|
152
|
-
date_output = Dependabot::SharedHelpers.run_shell_command(date_cmd.join(" "))
|
|
153
|
-
Time.parse(date_output.strip)
|
|
154
|
-
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
|
|
155
|
-
Dependabot.logger.warn("Failed to get commit date for #{commit_sha}: #{e.message}")
|
|
156
|
-
nil
|
|
157
|
-
rescue ArgumentError => e
|
|
158
|
-
Dependabot.logger.warn("Invalid date format for commit #{commit_sha}: #{e.message}")
|
|
159
|
-
nil
|
|
91
|
+
Dependabot::Package::PackageDetails.new(dependency: dependency, releases: releases)
|
|
160
92
|
end
|
|
161
93
|
|
|
162
94
|
sig { params(tag_info: T::Hash[Symbol, T.untyped]).returns(Dependabot::Package::PackageRelease) }
|
|
@@ -173,17 +105,27 @@ module Dependabot
|
|
|
173
105
|
)
|
|
174
106
|
end
|
|
175
107
|
|
|
176
|
-
sig
|
|
177
|
-
|
|
108
|
+
sig do
|
|
109
|
+
params(
|
|
110
|
+
port_version: Dependabot::Vcpkg::Package::VersionsDatabase::PortVersion,
|
|
111
|
+
release_dates: T::Hash[String, Time]
|
|
112
|
+
).returns(Dependabot::Package::PackageRelease)
|
|
113
|
+
end
|
|
114
|
+
def create_port_package_release(port_version, release_dates)
|
|
115
|
+
version = port_version.version
|
|
116
|
+
git_tree = port_version.git_tree
|
|
117
|
+
|
|
178
118
|
Dependabot::Package::PackageRelease.new(
|
|
179
|
-
version:
|
|
180
|
-
tag:
|
|
181
|
-
url: "#{Vcpkg::
|
|
182
|
-
|
|
119
|
+
version: version,
|
|
120
|
+
tag: version.to_s,
|
|
121
|
+
url: "#{Vcpkg::VCPKG_DEFAULT_REGISTRY_REPOSITORY}/tree/" \
|
|
122
|
+
"#{Vcpkg::VCPKG_DEFAULT_BASELINE_DEFAULT_BRANCH}/ports/#{dependency.name}",
|
|
123
|
+
released_at: git_tree && release_dates[git_tree],
|
|
183
124
|
details: {
|
|
184
|
-
"
|
|
185
|
-
"base_version" =>
|
|
186
|
-
"port_version" =>
|
|
125
|
+
"scheme" => port_version.scheme,
|
|
126
|
+
"base_version" => version.text,
|
|
127
|
+
"port_version" => version.port_version,
|
|
128
|
+
"git_tree" => git_tree
|
|
187
129
|
}
|
|
188
130
|
)
|
|
189
131
|
end
|