@@ -121,19 +121,27 @@ func (g *AWSArtifactsRegistry) CopyImage(ctx context.Context, sourceRef string,
121121 return fmt .Errorf ("failed to parse source image reference '%s': %w" , sourceRef , err )
122122 }
123123
124- // 2. Get ECR auth
125- auth , err := g .getAuthToken (ctx )
126- if err != nil {
127- return fmt .Errorf ("failed to get ECR auth token: %w" , err )
128- }
129-
130- // 3. Fetch source image
131- img , err := remote .Image (src , remote .WithAuth (auth ))
132- if err != nil {
133- return fmt .Errorf ("failed to fetch source image '%s': %w" , sourceRef , err )
124+ // 2. Fetch source image — use auth only for private ECR, anonymous for public sources
125+ var img containerregistry.Image
126+ if isPrivateECR (sourceRef ) {
127+ auth , err := g .getAuthToken (ctx )
128+ if err != nil {
129+ return fmt .Errorf ("failed to get ECR auth token: %w" , err )
130+ }
131+ img , err = remote .Image (src , remote .WithAuth (auth ))
132+ if err != nil {
133+ return fmt .Errorf ("failed to fetch source image '%s': %w" , sourceRef , err )
134+ }
135+ } else {
136+ // Public images (Docker Hub, public.ecr.aws, etc.) — anonymous pull
137+ var fetchErr error
138+ img , fetchErr = remote .Image (src )
139+ if fetchErr != nil {
140+ return fmt .Errorf ("failed to fetch source image '%s': %w" , sourceRef , fetchErr )
141+ }
134142 }
135143
136- // 4 . Ensure target ECR repository exists
144+ // 3 . Ensure target ECR repository exists
137145 targetRepoName := fmt .Sprintf ("%s/%s" , g .repositoryName , templateId )
138146 if err := g .ensureRepository (ctx , targetRepoName ); err != nil {
139147 return fmt .Errorf ("failed to ensure target repository: %w" , err )
@@ -150,8 +158,12 @@ func (g *AWSArtifactsRegistry) CopyImage(ctx context.Context, sourceRef string,
150158 return fmt .Errorf ("failed to parse target reference '%s': %w" , targetTag , err )
151159 }
152160
153- // 6. Write image to target
154- if err := remote .Write (dst , img , remote .WithAuth (auth )); err != nil {
161+ // 6. Write image to target (always use ECR auth for the destination)
162+ pushAuth , err := g .getAuthToken (ctx )
163+ if err != nil {
164+ return fmt .Errorf ("failed to get ECR auth token for push: %w" , err )
165+ }
166+ if err := remote .Write (dst , img , remote .WithAuth (pushAuth )); err != nil {
155167 return fmt .Errorf ("failed to write image to '%s': %w" , targetTag , err )
156168 }
157169
@@ -177,30 +189,34 @@ func (g *AWSArtifactsRegistry) ensureRepository(ctx context.Context, repoName st
177189 return nil
178190}
179191
180- // resolveSourceRef resolves a short image name (e.g. "e2bdev/desktop") to a full
181- // ECR URI by prepending the registry domain. If the reference already contains a
192+ // resolveSourceRef resolves image references. If the reference already contains a
182193// registry domain (detected by a "." in the first path component), it is returned as-is.
194+ // Short names without a domain are treated as Docker Hub images.
183195func (g * AWSArtifactsRegistry ) resolveSourceRef (ctx context.Context , sourceRef string ) (string , error ) {
184196 parts := strings .SplitN (sourceRef , "/" , 2 )
185- if strings .Contains (parts [0 ], "." ) {
186- // Already has a registry domain
197+ // Strip tag/digest before checking for domain dots
198+ host := strings .SplitN (parts [0 ], ":" , 2 )[0 ]
199+ if strings .Contains (host , "." ) {
200+ // Already has a registry domain (e.g. public.ecr.aws/..., 918xxx.dkr.ecr.../...)
187201 return sourceRef , nil
188202 }
189203
190- // Get ECR registry URL from auth token
191- res , err := g .client .GetAuthorizationToken (ctx , & ecr.GetAuthorizationTokenInput {})
192- if err != nil {
193- return "" , fmt .Errorf ("failed to get ECR registry URL: %w" , err )
194- }
195- if len (res .AuthorizationData ) == 0 || res .AuthorizationData [0 ].ProxyEndpoint == nil {
196- return "" , fmt .Errorf ("no ECR proxy endpoint found" )
204+ // No domain → Docker Hub image
205+ if len (parts ) == 1 {
206+ // Official image like "ubuntu:22.04" → "docker.io/library/ubuntu:22.04"
207+ nameAndTag := strings .SplitN (sourceRef , ":" , 2 )
208+ if len (nameAndTag ) == 2 {
209+ return fmt .Sprintf ("docker.io/library/%s:%s" , nameAndTag [0 ], nameAndTag [1 ]), nil
210+ }
211+ return fmt .Sprintf ("docker.io/library/%s:latest" , sourceRef ), nil
197212 }
213+ // User image like "myuser/myrepo:tag" → "docker.io/myuser/myrepo:tag"
214+ return fmt .Sprintf ("docker.io/%s" , sourceRef ), nil
215+ }
198216
199- // ProxyEndpoint is "https://918380168589.dkr.ecr.us-west-2.amazonaws.com"
200- registryURL := strings .TrimPrefix (* res .AuthorizationData [0 ].ProxyEndpoint , "https://" )
201- registryURL = strings .TrimPrefix (registryURL , "http://" )
202-
203- return fmt .Sprintf ("%s/%s" , registryURL , sourceRef ), nil
217+ // isPrivateECR checks if the image reference points to a private ECR registry.
218+ func isPrivateECR (ref string ) bool {
219+ return strings .Contains (ref , ".dkr.ecr." ) && strings .Contains (ref , ".amazonaws.com" )
204220}
205221
206222func (g * AWSArtifactsRegistry ) getAuthToken (ctx context.Context ) (* authn.Basic , error ) {
@@ -232,4 +248,4 @@ func (g *AWSArtifactsRegistry) getAuthToken(ctx context.Context) (*authn.Basic,
232248 Username : username ,
233249 Password : password ,
234250 }, nil
235- }
251+ }
0 commit comments