github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/image/oci.go (about) 1 package image 2 3 import ( 4 "strings" 5 6 v1 "github.com/google/go-containerregistry/pkg/v1" 7 "github.com/google/go-containerregistry/pkg/v1/layout" 8 ispec "github.com/opencontainers/image-spec/specs-go/v1" 9 "golang.org/x/xerrors" 10 ) 11 12 func tryOCI(fileName string) (v1.Image, error) { 13 var inputRef, inputFileName string 14 15 // Check if tag is specified in input 16 // e.g. /path/to/oci:0.0.1 17 18 inputFileName, inputRef, found := strings.Cut(fileName, "@") 19 20 if !found { 21 inputFileName, inputRef, found = strings.Cut(fileName, ":") 22 } 23 24 if !found { 25 inputFileName = fileName 26 inputRef = "" 27 } 28 29 lp, err := layout.FromPath(inputFileName) 30 if err != nil { 31 return nil, xerrors.Errorf("unable to open %s as an OCI Image: %w", fileName, err) 32 } 33 34 index, err := lp.ImageIndex() 35 if err != nil { 36 return nil, xerrors.Errorf("unable to retrieve index.json: %w", err) 37 } 38 39 m, err := index.IndexManifest() 40 if err != nil { 41 return nil, xerrors.Errorf("invalid index.json: %w", err) 42 } 43 44 if len(m.Manifests) == 0 { 45 return nil, xerrors.New("no valid manifest") 46 } 47 48 // Support image having tag separated by : , otherwise support first image 49 return getOCIImage(m, index, inputRef) 50 } 51 52 func getOCIImage(m *v1.IndexManifest, index v1.ImageIndex, inputRef string) (v1.Image, error) { 53 for _, manifest := range m.Manifests { 54 annotation := manifest.Annotations 55 tag := annotation[ispec.AnnotationRefName] 56 if inputRef == "" || // always select the first digest 57 tag == inputRef || 58 manifest.Digest.String() == inputRef { 59 h := manifest.Digest 60 if manifest.MediaType.IsIndex() { 61 childIndex, err := index.ImageIndex(h) 62 if err != nil { 63 return nil, xerrors.Errorf("unable to retrieve a child image %q: %w", h.String(), err) 64 } 65 childManifest, err := childIndex.IndexManifest() 66 if err != nil { 67 return nil, xerrors.Errorf("invalid a child manifest for %q: %w", h.String(), err) 68 } 69 return getOCIImage(childManifest, childIndex, "") 70 } 71 72 img, err := index.Image(h) 73 if err != nil { 74 return nil, xerrors.Errorf("invalid OCI image: %w", err) 75 } 76 77 return img, nil 78 } 79 } 80 81 return nil, xerrors.New("invalid OCI image ref") 82 }