@@ -24,6 +24,7 @@ import (
2424 "github.com/awslabs/soci-snapshotter/config"
2525 "github.com/awslabs/soci-snapshotter/util/dockershell"
2626 "github.com/awslabs/soci-snapshotter/util/testutil"
27+ "github.com/containerd/containerd/reference"
2728 "github.com/containerd/platforms"
2829)
2930
@@ -252,3 +253,93 @@ func testV1IsNotUsedWhenDisabled(t *testing.T, imgName string) {
252253 t .Fatalf ("expected no digest, got %s" , indexDigestUsed )
253254 }
254255}
256+
257+ func TestDanglingV2Annotation (t * testing.T ) {
258+ for _ , imgName := range pullModesImages {
259+ t .Run (imgName , func (t * testing.T ) {
260+ testDanglingV2Annotation (t , imgName )
261+ })
262+ }
263+ }
264+
265+ func testDanglingV2Annotation (t * testing.T , imgName string ) {
266+ regConfig := newRegistryConfig ()
267+ sh , done := newShellWithRegistry (t , regConfig )
268+ defer done ()
269+
270+ rebootContainerd (t , sh , "" , "" )
271+
272+ srcInfo := dockerhub (imgName )
273+ dstInfo := regConfig .mirror (imgName )
274+
275+ sh .X ("nerdctl" , "pull" , "--all-platforms" , srcInfo .ref )
276+ sh .X ("soci" , "convert" , "--min-layer-size" , "0" , srcInfo .ref , dstInfo .ref )
277+
278+ manifest , err := getManifestDigest (sh , dstInfo .ref , platforms .DefaultSpec ())
279+ if err != nil {
280+ t .Fatalf ("could not get manifest digest: %v" , err )
281+ }
282+
283+ v2IndexDigest , err := sh .OLog ("soci" ,
284+ "index" , "list" ,
285+ "-q" , "--ref" , srcInfo .ref ,
286+ "--platform" , platforms .Format (platforms .DefaultSpec ()),
287+ )
288+ if err != nil {
289+ t .Fatal (err )
290+ }
291+
292+ // Nither nerdctl nor ctr expose a way to "elevate" a platform-specific
293+ // manifest to a top level image directly, so we do a little registry dance:
294+ // push image:tag
295+ // pull image@sha256:... (the specific manifest we want to elevate)
296+ // tag image@sha256:... image/dangling:tag
297+ // push image/dangling:tag
298+ //
299+ // After this, image/dangling:tag refers to a single manifest that is platform specific.
300+ // We use this to separate an image manifest that contains a reference to a SOCI index
301+ // from the SOCI index itself to verify that it correctly pulls the image without lazy loading.
302+ platformManifestRef , err := reference .Parse (dstInfo .ref )
303+ if err != nil {
304+ t .Fatalf ("could not get parse destination ref: %v" , err )
305+ }
306+ danglingRef := platformManifestRef
307+ danglingRef .Locator += "/dangling" // image/dangling:tag
308+
309+ platformManifestRef .Object = "@" + manifest // image@sha256...
310+
311+ sh .X ("nerdctl" , "login" , "--username" , regConfig .user , "--password" , regConfig .pass , platformManifestRef .String ())
312+ sh .X ("nerdctl" , "push" , "--platform" , platforms .DefaultString (), dstInfo .ref )
313+ sh .X ("nerdctl" , "pull" , platformManifestRef .String ())
314+ sh .X ("nerdctl" , "image" , "tag" , platformManifestRef .String (), danglingRef .String ())
315+ // Push a v1 index as well to verify that we do not fall back if we don't find the SOCI v2 index
316+ sh .X ("nerdctl" , "push" , "--snapshotter" , "soci" , "--soci-min-layer-size" , "0" , danglingRef .String ())
317+
318+ m := rebootContainerd (t , sh , "" , getSnapshotterConfigToml (t , withPullModes (config .DefaultPullModes ())))
319+
320+ rsm , doneRsm := testutil .NewRemoteSnapshotMonitor (m )
321+ defer doneRsm ()
322+ var foundNoIndexMessage bool
323+ var indexDigestUsed string
324+ m .Add ("Look for digest" , func (s string ) {
325+ if strings .Contains (s , "no valid SOCI index found" ) {
326+ foundNoIndexMessage = true
327+ }
328+ structuredLog := make (map [string ]string )
329+ err := json .Unmarshal ([]byte (s ), & structuredLog )
330+ if err != nil {
331+ return
332+ }
333+ if structuredLog ["msg" ] == "fetching SOCI artifacts using index descriptor" {
334+ indexDigestUsed = structuredLog ["digest" ]
335+ }
336+ })
337+ sh .X ("nerdctl" , "pull" , "--snapshotter" , "soci" , danglingRef .String ())
338+ rsm .CheckAllLocalSnapshots (t )
339+ if ! foundNoIndexMessage {
340+ t .Fatalf ("did not find the message that no index was found" )
341+ }
342+ if strings .Trim (string (v2IndexDigest ), "\n " ) != indexDigestUsed {
343+ t .Fatalf ("expected v2 index digest %s, got %s" , v2IndexDigest , indexDigestUsed )
344+ }
345+ }
0 commit comments