Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docker/lib/dependabot/docker/update_checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,18 @@ def digest_up_to_date?
expected_digest =
if source_tag
latest_tag = latest_tag_from(source_tag)

# When digest-only updates are suppressed and the tag hasn't changed,
# treat the digest as up-to-date to avoid proposing a PR that only
# bumps the digest without a corresponding version change.
# Only apply to comparable (versioned) tags — non-comparable tags like
# "latest" or distro codenames should still get digest updates.
if Dependabot::Experiments.enabled?(:docker_digest_only_update_suppression) &&
Comment thread
markhallen marked this conversation as resolved.
Tag.new(source_tag).comparable? &&
latest_tag.name == source_tag
next true
end

digest_of(latest_tag.name)
else
updated_digest
Expand Down
137 changes: 137 additions & 0 deletions docker/spec/dependabot/docker/update_checker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ def stub_tag_with_no_digest(tag)
end

it { is_expected.to be_falsy }

context "when docker_digest_only_update_suppression experiment is enabled" do
before do
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_digest_only_update_suppression).and_return(true)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_created_timestamp_validation).and_return(false)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_pin_digests).and_return(false)
end

it { is_expected.to be_truthy }
end
end
end

Expand Down Expand Up @@ -3225,6 +3238,130 @@ def stub_tag_with_no_digest(tag)
end
end

describe "#digest_up_to_date? with docker_digest_only_update_suppression experiment" do
subject(:digest_up_to_date?) { checker.send(:digest_up_to_date?) }

let(:headers_response) do
fixture("docker", "registry_manifest_headers", "generic.json")
end
Comment thread
markhallen marked this conversation as resolved.

context "when experiment is enabled" do
before do
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_digest_only_update_suppression).and_return(true)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_created_timestamp_validation).and_return(false)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_pin_digests).and_return(false)
end

context "when the tag has not changed but the digest has" do
let(:version) { "17.10" }
let(:source) do
{
tag: "17.10",
digest: "old_digest_that_differs_from_registry"
}
end

before do
stub_request(:head, repo_url + "manifests/17.10")
.and_return(status: 200, headers: JSON.parse(headers_response))
end

it "treats the digest as up-to-date (suppresses digest-only update)" do
expect(digest_up_to_date?).to be true
end
end

context "when the tag has changed and the digest differs" do
let(:version) { "17.04" }
let(:source) do
{
tag: "17.04",
digest: "old_digest"
}
end

before do
stub_request(:head, repo_url + "manifests/17.10")
.and_return(status: 200, headers: JSON.parse(headers_response))
end

it "reports the digest as out of date" do
expect(digest_up_to_date?).to be false
end
end

context "when only a digest is present (no tag)" do
let(:version) { "latest" }
let(:source) do
{
digest: "old_digest"
}
end

before do
stub_request(:head, repo_url + "manifests/latest")
.and_return(status: 200, headers: JSON.parse(headers_response))
end

it "still detects digest changes (suppression only applies to tagged images)" do
expect(digest_up_to_date?).to be false
end
end

context "when the tag is non-comparable (e.g., 'latest' or distro codename) with digest" do
let(:version) { "artful" }
let(:source) do
{
tag: "artful",
digest: "old_digest_that_differs_from_registry"
}
end

before do
stub_request(:head, repo_url + "manifests/artful")
.and_return(status: 200, headers: JSON.parse(headers_response))
end

it "still detects digest changes (suppression only applies to versioned tags)" do
expect(digest_up_to_date?).to be false
end
end
end

context "when experiment is disabled" do
before do
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_digest_only_update_suppression).and_return(false)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_created_timestamp_validation).and_return(false)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:docker_pin_digests).and_return(false)
end

context "when the tag has not changed but the digest has" do
let(:version) { "17.10" }
let(:source) do
{
tag: "17.10",
digest: "old_digest_that_differs_from_registry"
}
end

before do
stub_request(:head, repo_url + "manifests/17.10")
.and_return(status: 200, headers: JSON.parse(headers_response))
end

it "reports the digest as out of date (existing behavior)" do
expect(digest_up_to_date?).to be false
end
end
end
end

private

def stub_same_sha_for(*tags)
Expand Down
Loading