Skip to content

Commit 19d09e0

Browse files
authored
image-copy-ecr: support nested repositories (#275)
Previously we would have copied `charts/external-secrets` to `external-secrets`, potentially mixing images and charts in the same ECR repo.
1 parent 5405f3b commit 19d09e0

1 file changed

Lines changed: 48 additions & 12 deletions

File tree

image-copy-ecr/main.go

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"chainguard.dev/sdk/auth/aws"
1818
cgevents "chainguard.dev/sdk/events"
1919
"chainguard.dev/sdk/events/registry"
20+
iam "chainguard.dev/sdk/proto/platform/iam/v1"
2021
v1 "chainguard.dev/sdk/proto/platform/registry/v1"
2122
"chainguard.dev/sdk/sts"
2223
"github.com/aws/aws-lambda-go/events"
@@ -176,24 +177,59 @@ func resolveRepositoryName(ctx context.Context, repoID string) (string, error) {
176177
return "", fmt.Errorf("getting token: %w", err)
177178
}
178179

179-
// Create client that uses the token
180-
client, err := v1.NewClients(ctx, env.APIEndpoint, tok.AccessToken)
180+
// Create clients that uses the token
181+
regc, err := v1.NewClients(ctx, env.APIEndpoint, tok.AccessToken)
181182
if err != nil {
182-
return "", fmt.Errorf("creating clients: %w", err)
183+
return "", fmt.Errorf("creating registry clients: %w", err)
183184
}
184-
185-
// Lookup the repository name from the ID
186-
repoList, err := client.Registry().ListRepos(ctx, &v1.RepoFilter{
187-
Id: repoID,
188-
})
185+
iamc, err := iam.NewClients(ctx, env.APIEndpoint, tok.AccessToken)
189186
if err != nil {
190-
return "", fmt.Errorf("listing repositories: %w", err)
187+
return "", fmt.Errorf("creating group clients: %w", err)
188+
}
189+
190+
// Look up the name for each subrepository. This supports nested repos
191+
// like charts/cert-manager.
192+
var path []string
193+
parts := strings.Split(repoID, "/")
194+
for i := 1; i < len(parts); i++ {
195+
id := strings.Join(parts[:i+1], "/")
196+
197+
// Each element in the path may be a 'repo' or a 'group', so we
198+
// need to try both.
199+
var name string
200+
groupList, err := iamc.Groups().List(ctx, &iam.GroupFilter{
201+
Id: id,
202+
})
203+
if err != nil {
204+
return "", fmt.Errorf("listing groups for %s: %w", id, err)
205+
}
206+
for _, group := range groupList.Items {
207+
name = group.Name
208+
break
209+
}
210+
if name == "" {
211+
repoList, err := regc.Registry().ListRepos(ctx, &v1.RepoFilter{
212+
Id: id,
213+
})
214+
if err != nil {
215+
return "", fmt.Errorf("listing repositories for %s: %w", id, err)
216+
}
217+
for _, repo := range repoList.Items {
218+
name = repo.Name
219+
break
220+
}
221+
}
222+
if name == "" {
223+
return "", fmt.Errorf("couldn't find repository or group name for id: %s", id)
224+
}
225+
path = append(path, name)
191226
}
192-
for _, repo := range repoList.Items {
193-
return repo.Name, nil
227+
228+
if len(path) == 0 {
229+
return "", fmt.Errorf("couldn't find full repository name for id: %s", repoID)
194230
}
195231

196-
return "", fmt.Errorf("couldn't find repository name for id: %s", repoID)
232+
return strings.Join(path, "/"), nil
197233
}
198234

199235
// newToken generates a token using the AWS identity of the Lambda function.

0 commit comments

Comments
 (0)