1 package packagelock
2
3 import (
4 "context"
5 "fmt"
6
7 "github.com/go-logr/logr"
8 "github.com/google/go-containerregistry/pkg/name"
9 "go.uber.org/multierr"
10
11 "github.com/google/go-containerregistry/pkg/authn"
12 "github.com/google/go-containerregistry/pkg/v1/google"
13 gremote "github.com/google/go-containerregistry/pkg/v1/remote"
14
15 "edge-infra.dev/pkg/f8n/warehouse"
16 "edge-infra.dev/pkg/f8n/warehouse/oci"
17 "edge-infra.dev/pkg/f8n/warehouse/oci/remote"
18 )
19
20 func InspectPackageLock(ctx context.Context, log logr.Logger, plf PackageLock, location string, project string, repository string) error {
21 var expectationErrs []error
22 keychain := authn.NewMultiKeychain(
23 google.Keychain,
24 authn.DefaultKeychain,
25 )
26 for _, pkg := range plf.Packages {
27 log.Info(fmt.Sprintf("validating %s", pkg.Name))
28 for _, ver := range pkg.Versions {
29 digestRef := fmt.Sprintf("%s-docker.pkg.dev/%s/%s/%s@%s", location, project, repository, pkg.Name, ver.Digest)
30 ref, err := name.ParseReference(digestRef)
31 if err != nil {
32 return err
33 }
34 digestArtifact, err := remote.Get(ref,
35 []remote.Option{
36 remote.WithContext(ctx),
37 gremote.WithAuthFromKeychain(keychain),
38 }...,
39 )
40 if err != nil {
41 return err
42 }
43 digestAnnos, err := oci.Annotations(digestArtifact)
44 if err != nil {
45 return err
46 }
47
48 expectedVersion, found := digestAnnos[warehouse.AnnotationVersion]
49 if !found {
50 err := fmt.Errorf("no version annotation found for pkg %s@%s", pkg.Name, ver.Digest)
51 expectationErrs = append(expectationErrs, err)
52 continue
53 }
54
55 if tagErrors := validateTagAnnotations(location, project, repository, pkg.Name, expectedVersion, ver.Tags); tagErrors != nil {
56 expectationErrs = append(expectationErrs, tagErrors)
57 continue
58 }
59 }
60 }
61 if err := multierr.Combine(expectationErrs...); err != nil {
62 return fmt.Errorf("all pkg versions must be the same. one or more differ: %+v", err)
63 }
64 return nil
65 }
66
67 func validateTagAnnotations(location string, project string, repository string, pkgName string, expectedVersion string, tags []string) error {
68 var tagErrors []error
69 for _, tag := range tags {
70 if tag == "latest" {
71 continue
72 }
73 tagRef := fmt.Sprintf("%s-docker.pkg.dev/%s/%s/%s:%s", location, project, repository, pkgName, tag)
74 ref, err := name.ParseReference(tagRef)
75 if err != nil {
76 tagErrors = append(tagErrors, err)
77 continue
78 }
79 tagArtifact, err := remote.Get(ref)
80 if err != nil {
81 tagErrors = append(tagErrors, err)
82 continue
83 }
84 tagAnnos, err := oci.Annotations(tagArtifact)
85 if err != nil {
86 tagErrors = append(tagErrors, err)
87 continue
88 }
89
90 tagVersion, found := tagAnnos[warehouse.AnnotationVersion]
91 if !found {
92 tagErrors = append(tagErrors, fmt.Errorf("tag %s did not contain a version annotation", tag))
93 continue
94 }
95
96 if tagVersion != expectedVersion {
97 tagErrors = append(tagErrors, fmt.Errorf("tag %s version annotation %s did not match expected version %s", tag, tagVersion, expectedVersion))
98 continue
99 }
100 }
101 if err := multierr.Combine(tagErrors...); err != nil {
102 return fmt.Errorf("one or more tag versions did not match digest annotation version: %w", err)
103 }
104 return nil
105 }
106
View as plain text