@@ -20,6 +20,7 @@ import (
2020 ggcrv1 "github.com/google/go-containerregistry/pkg/v1"
2121 "github.com/sylabs/singularity/v4/internal/pkg/cache"
2222 "github.com/sylabs/singularity/v4/internal/pkg/client/progress"
23+ "github.com/sylabs/singularity/v4/internal/pkg/ociplatform"
2324 "github.com/sylabs/singularity/v4/pkg/sylog"
2425)
2526
@@ -56,7 +57,8 @@ func cachedImage(ctx context.Context, imgCache *cache.Handle, srcImg ggcrv1.Imag
5657// docker daemon, it will be pulled into the local cache - which is a
5758// multi-image OCI layout. If the cache is disabled, the image will be fetched
5859// into a subdirectory of the provided tmpDir. The caller is responsible for
59- // cleaning up tmpDir.
60+ // cleaning up tmpDir. The platform of the image will be checked against
61+ // tOpts.Platform.
6062func LocalImage (ctx context.Context , tOpts * TransportOptions , imgCache * cache.Handle , imageURI , tmpDir string ) (ggcrv1.Image , error ) {
6163 // oci-archive tarball is a local file, but current ggcr cannot read
6264 // directly. Must always extract to a layoutdir .
@@ -70,7 +72,16 @@ func LocalImage(ctx context.Context, tOpts *TransportOptions, imgCache *cache.Ha
7072 }
7173 // Docker tarballs and OCI layouts are already local
7274 if srcType == TarballSourceSink || srcType == OCISourceSink {
73- return srcType .Image (ctx , srcRef , tOpts , nil )
75+ img , err := srcType .Image (ctx , srcRef , tOpts , nil )
76+ if err != nil {
77+ return nil , err
78+ }
79+ // Verify against requested platform - ggcr doesn't filter on platform
80+ // when pulling a manifest directly, only on pulling from an image index.
81+ if err := ociplatform .CheckImagePlatform (tOpts .Platform , img ); err != nil {
82+ return nil , fmt .Errorf ("while checking OCI image: %w" , err )
83+ }
84+ return img , nil
7485 }
7586
7687 return LocalImageLayout (ctx , tOpts , imgCache , imageURI , tmpDir )
@@ -82,7 +93,8 @@ func LocalImage(ctx context.Context, tOpts *TransportOptions, imgCache *cache.Ha
8293// docker daemon, it will be pulled into the local cache - which is a
8394// multi-image OCI layout. If the cache is disabled, the image will be fetched
8495// into a subdirectory of the provided tmpDir. The caller is responsible for
85- // cleaning up tmpDir.
96+ // cleaning up tmpDir. The platform of the image will be checked against
97+ // tOpts.Platform.
8698func LocalImageLayout (ctx context.Context , tOpts * TransportOptions , imgCache * cache.Handle , imageURI , tmpDir string ) (ggcrv1.Image , error ) {
8799 if strings .HasPrefix (imageURI , "oci-archive:" ) {
88100 // oci-archive is a straight tar of an OCI layout, so extract to a tempDir
@@ -98,19 +110,27 @@ func LocalImageLayout(ctx context.Context, tOpts *TransportOptions, imgCache *ca
98110 return nil , err
99111 }
100112
101- // We might already have an OCI layout at this point
102- if srcType == OCISourceSink {
103- return srcType .Image (ctx , srcRef , tOpts , nil )
104- }
105-
106- // Registry / Docker Daemon images need to be fetched
107113 rt := progress .NewRoundTripper (ctx , nil )
108114 srcImg , err := srcType .Image (ctx , srcRef , tOpts , rt )
109115 if err != nil {
110116 rt .ProgressShutdown ()
111117 return nil , err
112118 }
113119
120+ // Verify against requested platform - ggcr doesn't filter on platform when
121+ // pulling a manifest directly, only on pulling from an image index.
122+ if err := ociplatform .CheckImagePlatform (tOpts .Platform , srcImg ); err != nil {
123+ return nil , fmt .Errorf ("while checking OCI image: %w" , err )
124+ }
125+
126+ // We might already have an OCI layout at this point - which is local.
127+ if srcType == OCISourceSink {
128+ rt .ProgressShutdown ()
129+ return srcImg , nil
130+ }
131+
132+ // Registry / Docker Daemon images need to be fetched
133+
114134 if imgCache != nil && ! imgCache .IsDisabled () {
115135 // Ensure the image is cached, and return reference to the cached image.
116136 cachedImg , err := cachedImage (ctx , imgCache , srcImg )
0 commit comments