add file contents cataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman
2021-04-12 17:30:57 -04:00
parent 9ad786d608
commit c1551a03c5
10 changed files with 261 additions and 2 deletions
+68
View File
@@ -0,0 +1,68 @@
package file
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/source"
)
type ContentsCataloger struct {
globs []string
skipFilesAboveSize int64
}
func NewContentsCataloger(globs []string, skipFilesAboveSize int64) (*ContentsCataloger, error) {
return &ContentsCataloger{
globs: globs,
skipFilesAboveSize: skipFilesAboveSize,
}, nil
}
func (i *ContentsCataloger) Catalog(resolver source.FileResolver) (map[source.Location]string, error) {
results := make(map[source.Location]string)
var locations []source.Location
locations, err := resolver.FilesByGlob(i.globs...)
if err != nil {
return nil, err
}
for _, location := range locations {
metadata, err := resolver.FileMetadataByLocation(location)
if err != nil {
return nil, err
}
if i.skipFilesAboveSize > 0 && metadata.Size > i.skipFilesAboveSize {
continue
}
result, err := i.catalogLocation(resolver, location)
if err != nil {
return nil, err
}
results[location] = result
}
log.Debugf("file contents cataloger processed %d files", len(results))
return results, nil
}
func (i *ContentsCataloger) catalogLocation(resolver source.FileResolver, location source.Location) (string, error) {
contentReader, err := resolver.FileContentsByLocation(location)
if err != nil {
return "", err
}
defer contentReader.Close()
buf := &bytes.Buffer{}
if _, err = io.Copy(base64.NewEncoder(base64.StdEncoding, buf), contentReader); err != nil {
return "", fmt.Errorf("unable to observe contents of %+v: %+v", location.RealPath, err)
}
return buf.String(), nil
}
+89
View File
@@ -0,0 +1,89 @@
package file
import (
"testing"
"github.com/anchore/syft/syft/source"
"github.com/stretchr/testify/assert"
)
func TestContentsCataloger(t *testing.T) {
allFiles := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt"}
tests := []struct {
name string
globs []string
maxSize int64
files []string
expected map[source.Location]string
catalogErr bool
}{
{
name: "multi-pattern",
globs: []string{"test-fixtures/last/*.txt", "test-fixtures/*.txt"},
files: allFiles,
expected: map[source.Location]string{
source.NewLocation("test-fixtures/last/path.txt"): "dGVzdC1maXh0dXJlcy9sYXN0L3BhdGgudHh0IGZpbGUgY29udGVudHMh",
source.NewLocation("test-fixtures/another-path.txt"): "dGVzdC1maXh0dXJlcy9hbm90aGVyLXBhdGgudHh0IGZpbGUgY29udGVudHMh",
source.NewLocation("test-fixtures/a-path.txt"): "dGVzdC1maXh0dXJlcy9hLXBhdGgudHh0IGZpbGUgY29udGVudHMh",
},
},
{
name: "no-patterns",
globs: []string{},
files: []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt"},
expected: map[source.Location]string{},
},
{
name: "all-txt",
globs: []string{"**/*.txt"},
files: allFiles,
expected: map[source.Location]string{
source.NewLocation("test-fixtures/last/path.txt"): "dGVzdC1maXh0dXJlcy9sYXN0L3BhdGgudHh0IGZpbGUgY29udGVudHMh",
source.NewLocation("test-fixtures/another-path.txt"): "dGVzdC1maXh0dXJlcy9hbm90aGVyLXBhdGgudHh0IGZpbGUgY29udGVudHMh",
source.NewLocation("test-fixtures/a-path.txt"): "dGVzdC1maXh0dXJlcy9hLXBhdGgudHh0IGZpbGUgY29udGVudHMh",
},
},
{
name: "subpath",
globs: []string{"test-fixtures/*.txt"},
files: allFiles,
expected: map[source.Location]string{
source.NewLocation("test-fixtures/another-path.txt"): "dGVzdC1maXh0dXJlcy9hbm90aGVyLXBhdGgudHh0IGZpbGUgY29udGVudHMh",
source.NewLocation("test-fixtures/a-path.txt"): "dGVzdC1maXh0dXJlcy9hLXBhdGgudHh0IGZpbGUgY29udGVudHMh",
},
},
{
name: "size-filter",
maxSize: 42,
globs: []string{"**/*.txt"},
files: allFiles,
expected: map[source.Location]string{
source.NewLocation("test-fixtures/last/path.txt"): "dGVzdC1maXh0dXJlcy9sYXN0L3BhdGgudHh0IGZpbGUgY29udGVudHMh",
source.NewLocation("test-fixtures/a-path.txt"): "dGVzdC1maXh0dXJlcy9hLXBhdGgudHh0IGZpbGUgY29udGVudHMh",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
c, err := NewContentsCataloger(test.globs, test.maxSize)
if err != nil {
t.Fatalf("could not create cataloger: %+v", err)
}
resolver := source.NewMockResolverForPaths(test.files...)
actual, err := c.Catalog(resolver)
if err != nil && !test.catalogErr {
t.Fatalf("could not catalog (but should have been able to): %+v", err)
} else if err == nil && test.catalogErr {
t.Fatalf("expected catalog error but did not get one")
} else if test.catalogErr && err != nil {
return
}
assert.Equal(t, test.expected, actual, "mismatched contents")
})
}
}
+6 -2
View File
@@ -5,7 +5,7 @@ import (
"io"
"os"
"github.com/anchore/syft/internal/file"
"github.com/bmatcuk/doublestar/v2"
)
var _ FileResolver = (*MockResolver)(nil)
@@ -84,7 +84,11 @@ func (r MockResolver) FilesByGlob(patterns ...string) ([]Location, error) {
var results []Location
for _, pattern := range patterns {
for _, location := range r.Locations {
if file.GlobMatch(pattern, location.RealPath) {
matches, err := doublestar.Match(pattern, location.RealPath)
if err != nil {
return nil, err
}
if matches {
results = append(results, location)
}
}