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:
Shivam Mishra
2020-08-30 05:56:55 -07:00
committed by GitHub
parent 3f64bd6b32
commit fa1f12776b
8 changed files with 84 additions and 9 deletions

2
go.mod
View File

@@ -21,7 +21,7 @@ require (
github.com/knqyf263/nested v0.0.1 github.com/knqyf263/nested v0.0.1
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
github.com/opencontainers/go-digest v1.0.0-rc1 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/saracen/walker v0.0.0-20191201085201-324a081bae7e
github.com/sosedoff/gitkit v0.2.0 github.com/sosedoff/gitkit v0.2.0
github.com/stretchr/testify v1.5.1 github.com/stretchr/testify v1.5.1

View File

@@ -9,12 +9,14 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os" "os"
"strings"
"github.com/aquasecurity/fanal/image/token" "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/authn"
"github.com/google/go-containerregistry/pkg/name" "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/layout"
"github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-containerregistry/pkg/v1/tarball" "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) { 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 { if err != nil {
return nil, xerrors.Errorf("unable to open %s as an OCI Image: %w", fileName, err) 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") return nil, xerrors.New("no valid manifest")
} }
// Support only first image // Support image having tag separated by : , otherwise support first image
h := m.Manifests[0].Digest
img, err := index.Image(h) if inputTag != "" {
if err != nil { return getOCIImage(m, index, inputTag)
return nil, xerrors.New("invalid OCI image") } 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")
} }

View File

@@ -226,6 +226,25 @@ func TestNewArchiveImage(t *testing.T) {
fileName: "../test/testdata/test.oci", 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", name: "sad path, oci image not found",
args: args{ args: args{

View File

@@ -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}]}

View File

@@ -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}]}

View 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"
}
}
]
}

View File

@@ -0,0 +1 @@
{"imageLayoutVersion": "1.0.0"}