Skip to content
This repository was archived by the owner on Apr 17, 2023. It is now read-only.

Commit 8117995

Browse files
committed
Restrict deletes into the repository
Deletes of registry objects are referenced by their digest, but in some situations, we accidentally deleted objects from other places. For example, if we pushed the same image:tag into multiple namespaces, then a delete on one of them removed also the others from other namespaces. This commits restricts this into the given namespace/repository. Fixes #1125 Signed-off-by: Miquel Sabaté Solà <[email protected]>
1 parent d1bc09b commit 8117995

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

app/models/tag.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def delete_by_digest!(actor)
6363
dig = fetch_digest
6464
return false if dig.blank?
6565

66-
Tag.where(digest: dig).update_all(marked: true)
66+
Tag.where(repository: repository, digest: dig).update_all(marked: true)
6767

6868
begin
6969
Registry.get.client.delete(repository.full_name, dig, "manifests")
@@ -73,7 +73,11 @@ def delete_by_digest!(actor)
7373
return false
7474
end
7575

76-
Tag.where(digest: dig).map { |t| t.delete_by!(actor) }
76+
success = true
77+
Tag.where(repository: repository, digest: dig).find_each do |tag|
78+
success &&= tag&.delete_by!(actor)
79+
end
80+
success
7781
end
7882

7983
# Delete this tag and update its activity.

spec/models/tag_spec.rb

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ def fetch_digest_test
3434
end
3535

3636
describe Tag do
37-
let!(:registry) { create(:registry, hostname: "registry.test.lan") }
38-
let!(:user) { create(:admin) }
39-
let!(:repository) { create(:repository, namespace: registry.global_namespace, name: "repo") }
37+
let!(:registry) { create(:registry, hostname: "registry.test.lan") }
38+
let!(:user) { create(:admin) }
39+
let!(:repository) { create(:repository, namespace: registry.global_namespace, name: "repo") }
40+
let!(:repository1) { create(:repository, namespace: registry.global_namespace, name: "repo1") }
4041

4142
it { is_expected.to belong_to(:repository) }
4243
it { is_expected.to belong_to(:author) }
@@ -71,6 +72,7 @@ def fetch_digest_test
7172
describe "#delete_by_digest!" do
7273
let!(:tag) { create(:tag, name: "tag1", repository: repository, digest: "1") }
7374
let!(:tag2) { create(:tag, name: "tag2", repository: repository, digest: "2") }
75+
let!(:tag3) { create(:tag, name: "tag3", repository: repository1, digest: "2") }
7476

7577
it "returns false if there is no digest" do
7678
allow_any_instance_of(described_class).to receive(:fetch_digest).and_return(nil)
@@ -151,6 +153,20 @@ def fetch_digest_test
151153

152154
expect(described_class.find_by(name: "t")).to be_nil
153155
end
156+
157+
it "does not remove tags from other repositories" do
158+
allow_any_instance_of(Tag).to receive(:fetch_digest).and_return("2")
159+
allow_any_instance_of(Portus::RegistryClient).to(
160+
receive(:delete)
161+
.with(repository.full_name, "2", "manifests")
162+
.and_return(true)
163+
)
164+
165+
tag2.delete_by_digest!(user)
166+
167+
expect(repository.tags.count).to eq 1
168+
expect(repository1.tags.count).to eq 1
169+
end
154170
end
155171

156172
# NOTE: lots of cases are being left out on purpose because they are already

0 commit comments

Comments
 (0)