Skip to content

Commit f66c0ff

Browse files
committed
docker: add metadata finding support for org.opencontainers.image.version and org.opencontainers.image.revision
1 parent 24f1357 commit f66c0ff

File tree

2 files changed

+107
-7
lines changed

2 files changed

+107
-7
lines changed

docker/lib/dependabot/docker/metadata_finder.rb

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,73 @@ def look_up_source
1818
return if dependency.requirements.empty?
1919

2020
new_source = dependency.requirements.first&.fetch(:source)
21-
return unless new_source && new_source[:registry] && new_source[:tag]
21+
return unless new_source && new_source[:registry] && (new_source[:tag] || new_source[:digest])
2222

23-
image_ref = "#{new_source[:registry]}/#{dependency.name}:#{new_source[:tag]}"
24-
image_details_output = SharedHelpers.run_shell_command("regctl image inspect #{image_ref}")
25-
image_details = JSON.parse(image_details_output)
26-
image_source = image_details.dig("config", "Labels", "org.opencontainers.image.source")
23+
details = image_details(new_source)
24+
image_source = details.dig("config", "Labels", "org.opencontainers.image.source")
2725
return unless image_source
2826

29-
Dependabot::Source.from_url(image_source)
27+
return Dependabot::Source.from_url(image_source) if new_source[:tag]
28+
29+
build_source_from_image_version(image_source, details)
3030
rescue StandardError => e
3131
Dependabot.logger.warn("Error looking up Docker source: #{e.message}")
3232
nil
3333
end
34+
35+
sig do
36+
params(
37+
source: T::Hash[Symbol, T.untyped]
38+
).returns(
39+
T::Hash[String, T.untyped]
40+
)
41+
end
42+
def image_details(source)
43+
registry = source[:registry]
44+
tag = source[:tag]
45+
digest = source[:digest]
46+
47+
image_ref =
48+
# If both tag and digest are present, use the digest as docker ignores the tag when a digest is present
49+
if digest
50+
"#{registry}/#{dependency.name}@sha256:#{digest}"
51+
else
52+
"#{registry}/#{dependency.name}:#{tag}"
53+
end
54+
55+
Dependabot.logger.info("Looking up Docker source #{image_ref}")
56+
output = SharedHelpers.run_shell_command("regctl image inspect #{image_ref}")
57+
JSON.parse(output)
58+
end
59+
60+
sig do
61+
params(
62+
image_source: String,
63+
details: T::Hash[String, T.untyped]
64+
).returns(T.nilable(Dependabot::Source))
65+
end
66+
def build_source_from_image_version(image_source, details)
67+
image_version = details.dig("config", "Labels", "org.opencontainers.image.version")
68+
revision = details.dig("config", "Labels", "org.opencontainers.image.revision")
69+
# Sometimes the versions are not tags (e.g., "24.04")
70+
# We only want to build a source if the version looks like a tag (starts with "v")
71+
is_tag = image_version&.start_with?("v")
72+
73+
return unless is_tag || revision
74+
75+
parsed_source = Dependabot::Source.from_url(image_source)
76+
return unless parsed_source
77+
78+
Dependabot.logger.info "Building source with branch '#{image_version}' and commit '#{revision}'"
79+
80+
Dependabot::Source.new(
81+
provider: parsed_source.provider,
82+
repo: parsed_source.repo,
83+
directory: parsed_source.directory,
84+
branch: image_version,
85+
commit: revision
86+
)
87+
end
3488
end
3589
end
3690
end

docker/spec/dependabot/docker/metadata_finder_spec.rb

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,53 @@
7373
requirement: nil,
7474
groups: [],
7575
source: { registry: "ghcr.io",
76-
digest: "sha256:389a5a9a5457ed237b05d623ddc31a42fa97811051dcd02d7ca4ad46bd3edd3e" }
76+
digest: "389a5a9a5457ed237b05d623ddc31a42fa97811051dcd02d7ca4ad46bd3edd3e" }
77+
}],
78+
package_manager: "docker"
79+
)
80+
end
81+
82+
it "doesn't find the repository" do
83+
expect(finder.source_url).to be_nil
84+
end
85+
end
86+
87+
context "with a docker image without a tag but with org.opencontainers.image.version populated" do
88+
let(:dependency) do
89+
Dependabot::Dependency.new(
90+
name: "regclient/regctl",
91+
version: "",
92+
requirements: [{
93+
file: "Dockerfile",
94+
requirement: nil,
95+
groups: [],
96+
source: { registry: "ghcr.io",
97+
digest: "a734f285c0962e46557bff24489fa0b0521455733f72d9eb30c4f7a5027aeed6" }
98+
}],
99+
package_manager: "docker"
100+
)
101+
end
102+
103+
it "finds the repository" do
104+
expect(finder.source_url).to eq "https://github.com/regclient/regclient"
105+
expect(finder.send(:source).branch).to eq "v0.11.1"
106+
expect(finder.send(:source).commit).to eq "bf3bcfc47173b49ee8000d1d3a1ac15036e83cf0"
107+
end
108+
end
109+
110+
context "with a docker image without a tag but without a proper tag format or revision" do
111+
# The image used here has org.opencontainers.image.version set to "24.04"
112+
# which refers to the Ubuntu version rather than a tag
113+
let(:dependency) do
114+
Dependabot::Dependency.new(
115+
name: "maven",
116+
version: "",
117+
requirements: [{
118+
file: "Dockerfile",
119+
requirement: nil,
120+
groups: [],
121+
source: { registry: "docker.io",
122+
digest: "800a33a4cb190082c47abcd57944c852e1dece834f92c0aef65bea6336c52a72" }
77123
}],
78124
package_manager: "docker"
79125
)

0 commit comments

Comments
 (0)