mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-20 14:22:50 -08:00
Support for scanning of an OCI image given a tag. (fanal#130)
Condition:- Specify an image name and tag ":" separated. If correct image name and tag is specified ":" separated, image with given tag will be return otherwise first one will be return
This commit is contained in:
2
go.mod
2
go.mod
@@ -21,7 +21,7 @@ require (
|
||||
github.com/knqyf263/nested v0.0.1
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
|
||||
github.com/saracen/walker v0.0.0-20191201085201-324a081bae7e
|
||||
github.com/sosedoff/gitkit v0.2.0
|
||||
github.com/stretchr/testify v1.5.1
|
||||
|
||||
@@ -9,12 +9,14 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/fanal/image/token"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
"github.com/google/go-containerregistry/pkg/authn"
|
||||
"github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1"
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/google/go-containerregistry/pkg/v1/layout"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
@@ -186,7 +188,19 @@ func fileOpener(fileName string) func() (io.ReadCloser, error) {
|
||||
}
|
||||
|
||||
func tryOCI(fileName string) (v1.Image, error) {
|
||||
lp, err := layout.FromPath(fileName)
|
||||
var inputTag, inputFileName string
|
||||
|
||||
// Check if tag is specified in input
|
||||
if strings.Contains(fileName, ":") {
|
||||
splitFileName := strings.Split(fileName, ":")
|
||||
inputFileName = splitFileName[0]
|
||||
inputTag = splitFileName[1]
|
||||
} else {
|
||||
inputFileName = fileName
|
||||
inputTag = ""
|
||||
}
|
||||
|
||||
lp, err := layout.FromPath(inputFileName)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("unable to open %s as an OCI Image: %w", fileName, err)
|
||||
}
|
||||
@@ -205,12 +219,38 @@ func tryOCI(fileName string) (v1.Image, error) {
|
||||
return nil, xerrors.New("no valid manifest")
|
||||
}
|
||||
|
||||
// Support only first image
|
||||
h := m.Manifests[0].Digest
|
||||
img, err := index.Image(h)
|
||||
if err != nil {
|
||||
return nil, xerrors.New("invalid OCI image")
|
||||
// Support image having tag separated by : , otherwise support first image
|
||||
|
||||
if inputTag != "" {
|
||||
return getOCIImage(m, index, inputTag)
|
||||
} else {
|
||||
h := m.Manifests[0].Digest
|
||||
|
||||
img, err := index.Image(h)
|
||||
if err != nil {
|
||||
return nil, xerrors.New("invalid OCI image")
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getOCIImage(m *v1.IndexManifest, index v1.ImageIndex, inputTag string) (v1.Image, error) {
|
||||
for _, manifest := range m.Manifests {
|
||||
annotation := manifest.Annotations
|
||||
|
||||
tag := annotation[ispec.AnnotationRefName]
|
||||
if tag == inputTag {
|
||||
h := manifest.Digest
|
||||
|
||||
img, err := index.Image(h)
|
||||
if err != nil {
|
||||
return nil, xerrors.New("invalid OCI image")
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
}
|
||||
|
||||
return img, nil
|
||||
return nil, xerrors.New("invalid OCI image tag")
|
||||
}
|
||||
|
||||
@@ -226,6 +226,25 @@ func TestNewArchiveImage(t *testing.T) {
|
||||
fileName: "../test/testdata/test.oci",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with OCI Image and tag Format",
|
||||
args: args{
|
||||
fileName: "../test/testdata/test_image_tag.oci:0.0.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with OCI Image only",
|
||||
args: args{
|
||||
fileName: "../test/testdata/test_image_tag.oci",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad path with OCI Image and invalid tagFormat",
|
||||
args: args{
|
||||
fileName: "../test/testdata/test_image_tag.oci:0.0.0",
|
||||
},
|
||||
wantErr: "invalid OCI image tag",
|
||||
},
|
||||
{
|
||||
name: "sad path, oci image not found",
|
||||
args: args{
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":2,"config":{"mediaType":"application/vnd.oci.image.config.v1+json","digest":"sha256:b23a8f6569ae9ae331226205fa72f480ce5310707d0bc97e611f83fbbbde4604","size":584},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:cdd16bd695eda2819e7637648f573c2ca64896c4f7bff9732ac9db734ca3bc2c","size":2610}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"created":"2020-01-03T01:21:37.263809283Z","architecture":"amd64","os":"linux","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"]},"rootfs":{"type":"layers","diff_ids":["sha256:9c27e219663c25e0f28493790cc0b88bc973ba3b1686355f221c38a36978ac63"]},"history":[{"created":"2020-01-03T01:21:37.132606296Z","created_by":"/bin/sh -c #(nop) COPY file:7bf12aab75c3867a023fe3b8bd6d113d43a4fcc415f3cc27cbcf0fff37b65a02 in / "},{"created":"2020-01-03T01:21:37.263809283Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}]}
|
||||
Binary file not shown.
13
test/testdata/test_image_tag.oci/index.json
vendored
Normal file
13
test/testdata/test_image_tag.oci/index.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"manifests": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"digest": "sha256:afb744871f99e0ff8e6f253244836ed34c5d805fdb096d3a205ffaf5e9073cab",
|
||||
"size": 345,
|
||||
"annotations": {
|
||||
"org.opencontainers.image.ref.name": "0.0.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
1
test/testdata/test_image_tag.oci/oci-layout
vendored
Normal file
1
test/testdata/test_image_tag.oci/oci-layout
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"imageLayoutVersion": "1.0.0"}
|
||||
Reference in New Issue
Block a user