Skip to content

Commit cc540b7

Browse files
committed
centralize all key fetching logic
Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com>
1 parent 29ef30b commit cc540b7

12 files changed

Lines changed: 792 additions & 479 deletions

File tree

internal/cli/install-keys.go

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ package cli
22

33
import (
44
"fmt"
5-
"os"
6-
"path/filepath"
75

8-
"github.com/chainguard-dev/clog"
96
"github.com/spf13/cobra"
107

118
"chainguard.dev/apko/pkg/apk/apk"
9+
"chainguard.dev/apko/pkg/apk/apk/keyring"
1210
)
1311

1412
func installKeys() *cobra.Command {
@@ -19,7 +17,6 @@ func installKeys() *cobra.Command {
1917
Args: cobra.NoArgs,
2018
RunE: func(cmd *cobra.Command, args []string) error {
2119
ctx := cmd.Context()
22-
log := clog.FromContext(ctx)
2320

2421
a, err := apk.New(ctx)
2522
if err != nil {
@@ -29,24 +26,15 @@ func installKeys() *cobra.Command {
2926
if err != nil {
3027
return err
3128
}
32-
for _, repo := range repos {
33-
keys, err := a.DiscoverKeys(ctx, repo)
34-
if err != nil {
35-
return err
36-
}
3729

38-
if err := os.MkdirAll("/etc/apk/keys", 0755); err != nil {
39-
return err
40-
}
41-
for _, key := range keys {
42-
fn := filepath.Join("/etc/apk/keys", key.ID)
43-
if err := os.WriteFile(fn, key.Bytes, 0o644); err != nil { //nolint: gosec
44-
return fmt.Errorf("failed to write key %s: %w", key.ID, err)
45-
}
46-
log.With("repo", repo).Infof("wrote %s", fn)
47-
}
30+
keyRing, err := keyring.NewKeyRing(
31+
keyring.AddRepositories(repos...),
32+
)
33+
if err != nil {
34+
return fmt.Errorf("creating keyring: %w", err)
4835
}
49-
return nil
36+
37+
return a.DownloadAndStoreKeys(ctx, keyRing)
5038
},
5139
}
5240
}

internal/cli/lock.go

Lines changed: 23 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ import (
2424
"slices"
2525
"sort"
2626
"strings"
27-
"time"
2827

2928
"github.com/spf13/cobra"
3029

3130
"github.com/chainguard-dev/clog"
3231

3332
"chainguard.dev/apko/pkg/apk/apk"
33+
"chainguard.dev/apko/pkg/apk/apk/keyring"
3434
"chainguard.dev/apko/pkg/apk/auth"
3535
apkfs "chainguard.dev/apko/pkg/apk/fs"
3636
"chainguard.dev/apko/pkg/build"
@@ -281,87 +281,33 @@ func stripURLScheme(url string) string {
281281
func discoverKeysForLock(ctx context.Context, ic *types.ImageConfiguration, archs []types.Architecture) []pkglock.LockKeyring {
282282
log := clog.FromContext(ctx)
283283

284-
// Collect all unique repositories
285-
repoSet := make(map[string]struct{})
286-
for _, repo := range ic.Contents.BuildRepositories {
287-
repoSet[repo] = struct{}{}
288-
}
289-
for _, repo := range ic.Contents.RuntimeOnlyRepositories {
290-
repoSet[repo] = struct{}{}
291-
}
292-
for _, repo := range ic.Contents.Repositories {
293-
repoSet[repo] = struct{}{}
284+
keys, err := keyring.NewKeyRing(
285+
keyring.AddRepositories(ic.Contents.BuildRepositories...),
286+
keyring.AddRepositories(ic.Contents.RuntimeOnlyRepositories...),
287+
keyring.AddRepositories(ic.Contents.Repositories...),
288+
)
289+
if err != nil {
290+
log.Errorf("adding repositories for key discovery: %v", err)
291+
return nil
294292
}
295293

296-
// Map to track discovered keys by URL to avoid duplicates
297-
discoveredKeyMap := make(map[string]pkglock.LockKeyring)
298-
299-
// Fetch Alpine releases once (cached by HTTP client)
300-
client := &http.Client{}
301-
var alpineReleases *apk.Releases
302-
303-
// Discover keys for each repository and architecture
304-
for repo := range repoSet {
305-
// Try Alpine-style key discovery
306-
if ver, ok := apk.ParseAlpineVersion(repo); ok {
307-
// Fetch releases.json if not already fetched
308-
if alpineReleases == nil {
309-
releases, err := apk.FetchAlpineReleases(ctx, client)
310-
if err != nil {
311-
log.Warnf("Failed to fetch Alpine releases: %v", err)
312-
continue
313-
}
314-
alpineReleases = releases
315-
}
316-
317-
branch := alpineReleases.GetReleaseBranch(ver)
318-
if branch == nil {
319-
log.Debugf("Alpine version %s not found in releases", ver)
320-
continue
321-
}
322-
323-
// Get keys for each architecture
324-
for _, arch := range archs {
325-
log.Debugf("Discovering Alpine keys for %s (version %s, arch %s)", repo, ver, arch.ToAPK())
326-
urls := branch.KeysFor(arch.ToAPK(), time.Now())
327-
if len(urls) == 0 {
328-
log.Debugf("No keys found for arch %s and version %s", arch.ToAPK(), ver)
329-
continue
330-
}
331-
332-
// Add discovered key URLs to the map
333-
for _, u := range urls {
334-
discoveredKeyMap[u] = pkglock.LockKeyring{
335-
Name: stripURLScheme(u),
336-
URL: u,
337-
}
338-
}
339-
}
340-
}
294+
archStrs := make([]string, 0, len(archs))
295+
for _, arch := range archs {
296+
archStrs = append(archStrs, arch.ToAPK())
297+
}
341298

342-
// Try Chainguard-style key discovery
343-
log.Debugf("Attempting Chainguard-style key discovery for %s", repo)
344-
keys, err := apk.DiscoverKeys(ctx, client, auth.DefaultAuthenticators, repo)
345-
if err != nil {
346-
log.Debugf("Chainguard-style key discovery failed for %s: %v", repo, err)
347-
} else if len(keys) > 0 {
348-
log.Debugf("Discovered %d Chainguard-style keys for %s", len(keys), repo)
349-
// For each JWKS key, emit a URL: repository + "/" + KeyID
350-
repoBase := strings.TrimSuffix(repo, "/")
351-
for _, key := range keys {
352-
keyURL := repoBase + "/" + key.ID
353-
discoveredKeyMap[keyURL] = pkglock.LockKeyring{
354-
Name: stripURLScheme(keyURL),
355-
URL: keyURL,
356-
}
357-
}
358-
}
299+
fetchedKeys, err := keys.FetchKeys(ctx, keyring.NewFetcher(http.DefaultClient, auth.DefaultAuthenticators), archStrs)
300+
if err != nil {
301+
log.Errorf("downloading keys from repositories: %v", err)
302+
return nil
359303
}
360304

361-
// Convert map to slice
362-
discoveredKeys := make([]pkglock.LockKeyring, 0, len(discoveredKeyMap))
363-
for _, key := range discoveredKeyMap {
364-
discoveredKeys = append(discoveredKeys, key)
305+
discoveredKeys := make([]pkglock.LockKeyring, 0, len(fetchedKeys))
306+
for _, key := range fetchedKeys {
307+
discoveredKeys = append(discoveredKeys, pkglock.LockKeyring{
308+
Name: stripURLScheme(key.URL),
309+
URL: key.URL,
310+
})
365311
}
366312

367313
log.Infof("Discovered %d auto-discovered keys", len(discoveredKeys))

pkg/apk/apk/cache.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ type Cache struct {
8686
etagCache *sync.Map
8787
headFlight *singleflight.Group
8888
getFlight *singleflight.Group
89-
90-
discoverKeys *flightCache[string, []Key]
9189
}
9290

9391
// NewCache returns a new Cache, which allows us to persist the results of HEAD requests
@@ -103,9 +101,8 @@ type Cache struct {
103101
// requests for the same resource when passing etag=false.
104102
func NewCache(etag bool) *Cache {
105103
c := &Cache{
106-
headFlight: &singleflight.Group{},
107-
getFlight: &singleflight.Group{},
108-
discoverKeys: newFlightCache[string, []Key](),
104+
headFlight: &singleflight.Group{},
105+
getFlight: &singleflight.Group{},
109106
}
110107

111108
if etag {

pkg/apk/apk/const.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,5 @@ const (
3030
// which PAX record we use in the tar header
3131
paxRecordsChecksumKey = "APK-TOOLS.checksum.SHA1"
3232

33-
// for fetching the alpine keys
34-
alpineReleasesURL = "https://alpinelinux.org/releases.json"
35-
3633
xattrTarPAXRecordsPrefix = "SCHILY.xattr."
3734
)

0 commit comments

Comments
 (0)