Skip to content

Commit 827b54e

Browse files
authored
Do not copy referrers in CopyBaseImages (#2073)
1 parent 05d94f7 commit 827b54e

9 files changed

Lines changed: 90 additions & 13 deletions

src/ImageBuilder.Tests/BuildCommandTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3704,6 +3704,7 @@ private static void VerifyImportImage(Mock<ICopyImageService> copyImageServiceMo
37043704
destTagNames,
37053705
destRegistryName,
37063706
srcTagName,
3707+
true,
37073708
srcRegistryName,
37083709
It.IsAny<ContainerRegistryImportSourceCredentials>(),
37093710
false));

src/ImageBuilder.Tests/CopyAcrImagesCommandTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public async Task CopyAcrImagesCommand_CustomDockerfileName()
104104
new string[] { expectedTag },
105105
manifest.Registry,
106106
expectedTag,
107+
true,
107108
SourceRegistry,
108109
null,
109110
false));
@@ -205,6 +206,7 @@ public async Task CopyAcrImagesCommand_SharedDockerfile()
205206
new string[] { expectedTag },
206207
manifest.Registry,
207208
expectedTag,
209+
true,
208210
SourceRegistry,
209211
null,
210212
false));
@@ -318,6 +320,7 @@ public async Task CopyAcrImagesCommand_RuntimeDepsSharing()
318320
new string[] { expectedTag },
319321
manifest.Registry,
320322
expectedTag,
323+
true,
321324
SourceRegistry,
322325
null,
323326
false));
@@ -431,6 +434,7 @@ public async Task SyndicatedTags()
431434
new string[] { expectedTag },
432435
manifest.Registry,
433436
It.IsAny<string>(),
437+
true,
434438
SourceRegistry,
435439
null,
436440
false));
@@ -516,6 +520,7 @@ public async Task CopyAcrImagesCommand_CopiesManifestListTags()
516520
new string[] { $"test/runtime:tag1" },
517521
DestinationRegistry,
518522
"test/runtime:tag1",
523+
true,
519524
SourceRegistry,
520525
null,
521526
false));
@@ -526,6 +531,7 @@ public async Task CopyAcrImagesCommand_CopiesManifestListTags()
526531
new string[] { $"test/runtime:shared1" },
527532
DestinationRegistry,
528533
"test/runtime:shared1",
534+
true,
529535
SourceRegistry,
530536
null,
531537
false));
@@ -535,6 +541,7 @@ public async Task CopyAcrImagesCommand_CopiesManifestListTags()
535541
new string[] { $"test/runtime:shared2" },
536542
DestinationRegistry,
537543
"test/runtime:shared2",
544+
true,
538545
SourceRegistry,
539546
null,
540547
false));
@@ -628,6 +635,7 @@ public async Task CopyAcrImagesCommand_CopiesSyndicatedManifestListTags()
628635
new string[] { $"test/runtime:tag1" },
629636
DestinationRegistry,
630637
"test/runtime:tag1",
638+
true,
631639
SourceRegistry,
632640
null,
633641
false));
@@ -638,6 +646,7 @@ public async Task CopyAcrImagesCommand_CopiesSyndicatedManifestListTags()
638646
new string[] { $"test/runtime:shared1" },
639647
DestinationRegistry,
640648
"test/runtime:shared1",
649+
true,
641650
SourceRegistry,
642651
null,
643652
false));
@@ -648,6 +657,7 @@ public async Task CopyAcrImagesCommand_CopiesSyndicatedManifestListTags()
648657
new string[] { $"test/runtime2:syn-shared1" },
649658
DestinationRegistry,
650659
"test/runtime2:syn-shared1",
660+
true,
651661
SourceRegistry,
652662
null,
653663
false));
@@ -721,6 +731,7 @@ public async Task CopyAcrImagesCommand_SkipsManifestListsWithNoManifestData()
721731
new string[] { $"test/runtime:tag1" },
722732
DestinationRegistry,
723733
It.IsAny<string>(),
734+
true,
724735
SourceRegistry,
725736
null,
726737
false));

src/ImageBuilder.Tests/CopyBaseImagesCommandTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public async Task MultipleBaseTags()
9393
new string[] { expectedTagInfo.TargetTag },
9494
manifest.Registry,
9595
expectedTagInfo.SourceImage,
96+
false,
9697
expectedTagInfo.Registry,
9798
It.Is<ContainerRegistryImportSourceCredentials>(creds => creds.Username == expectedTagInfo.Username && creds.Password == expectedTagInfo.Password),
9899
false));
@@ -167,6 +168,7 @@ public async Task OverridenBaseTag()
167168
new string[] { expectedTagInfo.TargetTag },
168169
manifest.Registry,
169170
expectedTagInfo.SourceImage,
171+
false,
170172
expectedTagInfo.Registry,
171173
It.Is<ContainerRegistryImportSourceCredentials>(creds => (creds == null && expectedTagInfo.Username == null) || (creds.Username == expectedTagInfo.Username && creds.Password == expectedTagInfo.Password)),
172174
false));

src/ImageBuilder.Tests/CopyImageServiceTests.cs

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ await Should.NotThrowAsync(() =>
4646
destAcrName: "myacr.azurecr.io",
4747
srcTagName: "repo:tag",
4848
srcRegistryName: "docker.io",
49-
isDryRun: true));
49+
sourceCredentials: null,
50+
isDryRun: true,
51+
copyReferrers: true));
5052
}
5153

5254
/// <summary>
@@ -94,7 +96,9 @@ await service.ImportImageAsync(
9496
destAcrName: "myacr.azurecr.io",
9597
srcTagName: "repo:tag",
9698
srcRegistryName: "docker.io",
97-
isDryRun: false);
99+
sourceCredentials: null,
100+
isDryRun: false,
101+
copyReferrers: true);
98102

99103
// Verify the importer was called, proving execution reached the import step
100104
// (past the external registry lookup that previously threw)
@@ -137,7 +141,9 @@ await service.ImportImageAsync(
137141
destAcrName: "myacr.azurecr.io",
138142
srcTagName: "repo:tag",
139143
srcRegistryName: "myacr.azurecr.io",
140-
isDryRun: false);
144+
sourceCredentials: null,
145+
isDryRun: false,
146+
copyReferrers: true);
141147

142148
// Main image import with TargetTags
143149
mockImporter.Verify(
@@ -203,7 +209,9 @@ await service.ImportImageAsync(
203209
destAcrName: "myacr.azurecr.io",
204210
srcTagName: "repo:tag",
205211
srcRegistryName: "myacr.azurecr.io",
206-
isDryRun: false);
212+
sourceCredentials: null,
213+
isDryRun: false,
214+
copyReferrers: true);
207215

208216
mockImporter.Verify(
209217
x => x.ImportImageAsync(
@@ -213,6 +221,47 @@ await service.ImportImageAsync(
213221
Times.Once);
214222
}
215223

224+
/// <summary>
225+
/// When copyReferrers is false, referrer discovery and referrer imports are
226+
/// both skipped. Only the main image is imported.
227+
/// </summary>
228+
[Fact]
229+
public async Task ImportImageAsync_CopyReferrersFalse_SkipsReferrerDiscoveryAndImport()
230+
{
231+
PublishConfiguration publishConfig = CreateAcrPublishConfig("myacr.azurecr.io");
232+
233+
var mockImporter = new Mock<IAcrImageImporter>();
234+
var mockOras = new Mock<IOrasService>();
235+
236+
var service = new CopyImageService(
237+
Mock.Of<ILogger<CopyImageService>>(),
238+
mockImporter.Object,
239+
mockOras.Object,
240+
ConfigurationHelper.CreateOptionsMock(publishConfig));
241+
242+
await service.ImportImageAsync(
243+
destTagNames: ["mirror/repo:tag"],
244+
destAcrName: "myacr.azurecr.io",
245+
srcTagName: "repo:tag",
246+
srcRegistryName: "myacr.azurecr.io",
247+
sourceCredentials: null,
248+
isDryRun: false,
249+
copyReferrers: false);
250+
251+
// GetReferrersAsync should never be called when copyReferrers is false
252+
mockOras.Verify(
253+
o => o.GetReferrersAsync(It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()),
254+
Times.Never);
255+
256+
// Only the main image should be imported (no referrers)
257+
mockImporter.Verify(
258+
x => x.ImportImageAsync(
259+
It.IsAny<string>(),
260+
It.IsAny<ResourceIdentifier>(),
261+
It.IsAny<ContainerRegistryImportImageContent>()),
262+
Times.Once);
263+
}
264+
216265
/// <summary>
217266
/// In dry-run mode, referrer discovery and ACR imports are both skipped.
218267
/// The ORAS service receives the dry-run flag and returns an empty list
@@ -239,7 +288,9 @@ await service.ImportImageAsync(
239288
destAcrName: "myacr.azurecr.io",
240289
srcTagName: "repo:tag",
241290
srcRegistryName: "myacr.azurecr.io",
242-
isDryRun: true);
291+
sourceCredentials: null,
292+
isDryRun: true,
293+
copyReferrers: true);
243294

244295
mockOras.Verify(
245296
o => o.GetReferrersAsync(It.IsAny<string>(), true, It.IsAny<CancellationToken>()),

src/ImageBuilder/Commands/BuildCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ await _copyImageService.ImportImageAsync(
624624
destTagNames: destTags,
625625
destAcrName: Manifest.Registry,
626626
srcTagName: DockerHelper.TrimRegistry(sourceDigest, srcRegistry),
627+
copyReferrers: true,
627628
srcRegistryName: srcRegistry);
628629

629630
// Redefine the source digest to be from the destination of the copy, not the source. The canonical scenario

src/ImageBuilder/Commands/CopyAcrImagesCommand.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public override async Task ExecuteAsync()
5959
DockerHelper.TrimRegistry(tagInfo.DestinationTag, Manifest.Registry),
6060
Manifest.Registry,
6161
DockerHelper.TrimRegistry(tagInfo.SourceTag, Options.SourceRegistry),
62+
copyReferrers: true,
6263
srcRegistryName: Options.SourceRegistry)))
6364
.SelectMany(tasks => tasks);
6465

@@ -68,6 +69,7 @@ public override async Task ExecuteAsync()
6869
DockerHelper.TrimRegistry(tagInfo.DestinationTag, Manifest.Registry),
6970
Manifest.Registry,
7071
DockerHelper.TrimRegistry(tagInfo.SourceTag, Options.SourceRegistry),
72+
copyReferrers: true,
7173
srcRegistryName: Options.SourceRegistry));
7274

7375
await Task.WhenAll(platformImportTasks.Concat(manifestListImportTasks));

src/ImageBuilder/Commands/CopyBaseImagesCommand.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,13 @@ private Task CopyImageAsync(string fromImage, string destinationRegistryName)
9595
};
9696
}
9797

98-
return ImportImageAsync($"{Options.RepoPrefix}{fromImage}", destinationRegistryName, srcImage,
99-
srcRegistryName: registry, sourceCredentials: importSourceCreds);
98+
return ImportImageAsync(
99+
destTagName: $"{Options.RepoPrefix}{fromImage}",
100+
destRegistryName: destinationRegistryName,
101+
srcTagName: srcImage,
102+
srcRegistryName: registry,
103+
sourceCredentials: importSourceCreds,
104+
copyReferrers: false);
100105
}
101106
}
102107
}

src/ImageBuilder/Commands/CopyImagesCommand.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ protected Task ImportImageAsync(
2222
string destTagName,
2323
string destRegistryName,
2424
string srcTagName,
25+
bool copyReferrers,
2526
string? srcRegistryName = null,
2627
ContainerRegistryImportSourceCredentials? sourceCredentials = null) =>
2728
_copyImageService.ImportImageAsync(
@@ -30,5 +31,6 @@ protected Task ImportImageAsync(
3031
srcTagName: srcTagName,
3132
srcRegistryName: srcRegistryName,
3233
sourceCredentials: sourceCredentials,
33-
isDryRun: Options.IsDryRun);
34+
isDryRun: Options.IsDryRun,
35+
copyReferrers: copyReferrers);
3436
}

src/ImageBuilder/CopyImageService.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Task ImportImageAsync(
2020
string[] destTagNames,
2121
string destAcrName,
2222
string srcTagName,
23+
bool copyReferrers,
2324
string? srcRegistryName = null,
2425
ContainerRegistryImportSourceCredentials? sourceCredentials = null,
2526
bool isDryRun = false);
@@ -48,6 +49,7 @@ public async Task ImportImageAsync(
4849
string[] destTagNames,
4950
string destAcrName,
5051
string srcTagName,
52+
bool copyReferrers,
5153
string? srcRegistryName = null,
5254
ContainerRegistryImportSourceCredentials? sourceCredentials = null,
5355
bool isDryRun = false)
@@ -57,17 +59,17 @@ public async Task ImportImageAsync(
5759
string sourceImageName = DockerHelper.GetImageName(srcRegistryName, srcTagName);
5860
string destRepo = destTagNames.First().Split(':')[0].Split('@')[0];
5961

60-
// Discover referrers (signatures, SBOMs, etc.) for the source image.
61-
IReadOnlyList<ReferrerInfo> referrers =
62-
await _orasService.GetReferrersAsync(reference: sourceImageName, isDryRun: isDryRun);
62+
IReadOnlyList<ReferrerInfo> referrers = copyReferrers
63+
? await _orasService.GetReferrersAsync(reference: sourceImageName, isDryRun: isDryRun)
64+
: [];
6365

6466
var destinationImageNames =
6567
destTagNames.Select(tag => $"'{DockerHelper.GetImageName(destAcr.Server, tag)}'").ToList();
6668
string formattedDestinationImages = string.Join(", ", destinationImageNames);
6769

6870
_logger.LogInformation(
69-
"Importing {DestinationImages} and {ReferrerCount} referrer(s) from '{SourceImage}' (DryRun={DryRun})",
70-
formattedDestinationImages, referrers.Count, sourceImageName, isDryRun);
71+
"Importing {DestinationImages} and {ReferrerCount} referrer(s) from '{SourceImage}' (DryRun={DryRun}, CopyReferrers={CopyReferrers})",
72+
formattedDestinationImages, referrers.Count, sourceImageName, isDryRun, copyReferrers);
7173

7274
if (isDryRun)
7375
{

0 commit comments

Comments
 (0)