Skip to content

Commit

Permalink
Docker scanning by digest (#1615)
Browse files Browse the repository at this point in the history
* added functionality to scan docker images with digests instead of tags

* cleaned import statement

* added unit test for baseAndTag parsing + remote digest scan
  • Loading branch information
joeleonjr authored Aug 11, 2023
1 parent e894540 commit fa9469c
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 8 deletions.
32 changes: 26 additions & 6 deletions pkg/sources/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) err
var img v1.Image
var err error
var base, tag string
var hasDigest bool
var imageName name.Reference

if strings.HasPrefix(image, "file://") {
image = strings.TrimPrefix(image, "file://")
Expand All @@ -93,10 +95,18 @@ func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) err
return err
}
} else {
base, tag = baseAndTagFromImage(image)
imageName, err := name.NewTag(image)
if err != nil {
return err
base, tag, hasDigest = baseAndTagFromImage(image)

if hasDigest {
imageName, err = name.NewDigest(image)
if err != nil {
return err
}
} else {
imageName, err = name.NewTag(image)
if err != nil {
return err
}
}

img, err = remote.Image(imageName, remoteOpts...)
Expand Down Expand Up @@ -194,10 +204,20 @@ func (s *Source) Chunks(ctx context.Context, chunksChan chan *sources.Chunk) err
return nil
}

func baseAndTagFromImage(image string) (base, tag string) {
func baseAndTagFromImage(image string) (base, tag string, hasDigest bool) {
regRepoDelimiter := "/"
tagDelim := ":"
parts := strings.Split(image, tagDelim)
digestDelim := "@"

// Split on digest first, if present.
parts := strings.SplitN(image, digestDelim, 2)
if len(parts) > 1 {
base = parts[0]
tag = parts[1]
hasDigest = true
return
}
parts = strings.Split(image, tagDelim)
// Verify that we aren't confusing a tag for a hostname w/ port for the purposes of weak validation.
if len(parts) > 1 && !strings.Contains(parts[len(parts)-1], regRepoDelimiter) {
base = strings.Join(parts[:len(parts)-1], tagDelim)
Expand Down
63 changes: 61 additions & 2 deletions pkg/sources/docker/docker_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build integration

package docker

import (
Expand Down Expand Up @@ -51,3 +49,64 @@ func TestDockerImageScan(t *testing.T) {

assert.Equal(t, 1, chunkCounter)
}

func TestDockerImageScanWithDigest(t *testing.T) {
dockerConn := &sourcespb.Docker{
Credential: &sourcespb.Docker_Unauthenticated{
Unauthenticated: &credentialspb.Unauthenticated{},
},
Images: []string{"trufflesecurity/secrets@sha256:864f6d41209462d8e37fc302ba1532656e265f7c361f11e29fed6ca1f4208e11"},
}

conn := &anypb.Any{}
err := conn.MarshalFrom(dockerConn)
assert.NoError(t, err)

s := &Source{}
err = s.Init(context.TODO(), "test source", 0, 0, false, conn, 1)
assert.NoError(t, err)

var wg sync.WaitGroup
chunksChan := make(chan *sources.Chunk, 1)
chunkCounter := 0
wg.Add(1)
go func() {
defer wg.Done()
for chunk := range chunksChan {
assert.NotEmpty(t, chunk)
chunkCounter++
}
}()

err = s.Chunks(context.TODO(), chunksChan)
assert.NoError(t, err)

close(chunksChan)
wg.Wait()

assert.Equal(t, 1, chunkCounter)
}

func TestBaseAndTagFromImage(t *testing.T) {
tests := []struct {
image string
wantBase string
wantTag string
wantDigest bool
}{
{"golang:1.16", "golang", "1.16", false},
{"golang@sha256:abcdef", "golang", "sha256:abcdef", true},
{"ghcr.io/golang:1.16", "ghcr.io/golang", "1.16", false},
{"ghcr.io/golang:nightly", "ghcr.io/golang", "nightly", false},
{"ghcr.io/golang", "ghcr.io/golang", "latest", false},
{"ghcr.io/trufflesecurity/secrets", "ghcr.io/trufflesecurity/secrets", "latest", false},
}

for _, tt := range tests {
gotBase, gotTag, gotDigest := baseAndTagFromImage(tt.image)
if gotBase != tt.wantBase || gotTag != tt.wantTag || gotDigest != tt.wantDigest {
t.Errorf("baseAndTagFromImage(%q) = (%q, %q, %v), want (%q, %q, %v)",
tt.image, gotBase, gotTag, gotDigest, tt.wantBase, tt.wantTag, tt.wantDigest)
}
}
}

0 comments on commit fa9469c

Please sign in to comment.