ensure resolvers ignore directories for "FilesBy*" methods

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2020-11-06 07:21:38 -05:00
parent 8095cd9980
commit 0205e72be9
No known key found for this signature in database
GPG Key ID: 5CB45AE22BAB7EA7
7 changed files with 129 additions and 8 deletions

View File

@ -67,12 +67,26 @@ func (r *AllLayersResolver) FilesByPath(paths ...file.Path) ([]file.Reference, e
for _, path := range paths { for _, path := range paths {
for idx, layerIdx := range r.layers { for idx, layerIdx := range r.layers {
ref := r.img.Layers[layerIdx].Tree.File(path) tree := r.img.Layers[layerIdx].Tree
ref := tree.File(path)
if ref == nil { if ref == nil {
// no file found, keep looking through layers // no file found, keep looking through layers
continue continue
} }
// don't consider directories (special case: there is no path information for /)
if ref.Path == "/" {
continue
} else if r.img.FileCatalog.Exists(*ref) {
metadata, err := r.img.FileCatalog.Get(*ref)
if err != nil {
return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", ref.Path, err)
}
if metadata.Metadata.IsDir {
continue
}
}
results, err := r.fileByRef(*ref, uniqueFileIDs, idx) results, err := r.fileByRef(*ref, uniqueFileIDs, idx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -97,6 +111,20 @@ func (r *AllLayersResolver) FilesByGlob(patterns ...string) ([]file.Reference, e
} }
for _, ref := range refs { for _, ref := range refs {
// don't consider directories (special case: there is no path information for /)
if ref.Path == "/" {
continue
} else if r.img.FileCatalog.Exists(ref) {
metadata, err := r.img.FileCatalog.Get(ref)
if err != nil {
return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", ref.Path, err)
}
if metadata.Metadata.IsDir {
continue
}
}
results, err := r.fileByRef(ref, uniqueFileIDs, idx) results, err := r.fileByRef(ref, uniqueFileIDs, idx)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,9 +1,10 @@
package resolvers package resolvers
import ( import (
"github.com/anchore/stereoscope/pkg/imagetest"
"testing" "testing"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/stereoscope/pkg/file" "github.com/anchore/stereoscope/pkg/file"
) )
@ -80,6 +81,11 @@ func TestAllLayersResolver_FilesByPath(t *testing.T) {
}, },
}, },
}, },
{
name: "ignore directories",
linkPath: "/bin",
resolutions: []resolution{},
},
} }
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
@ -188,6 +194,11 @@ func TestAllLayersResolver_FilesByGlob(t *testing.T) {
}, },
}, },
}, },
{
name: "ignore directories",
glob: "**/bin",
resolutions: []resolution{},
},
} }
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {

View File

@ -33,12 +33,18 @@ func (s DirectoryResolver) FilesByPath(userPaths ...file.Path) ([]file.Reference
// a path relative to root should be prefixed with the resolvers directory path, otherwise it should be left as is // a path relative to root should be prefixed with the resolvers directory path, otherwise it should be left as is
userStrPath = path.Join(s.Path, userStrPath) userStrPath = path.Join(s.Path, userStrPath)
} }
_, err := os.Stat(userStrPath) fileMeta, err := os.Stat(userStrPath)
if os.IsNotExist(err) { if os.IsNotExist(err) {
continue continue
} else if err != nil { } else if err != nil {
log.Errorf("path (%s) is not valid: %v", userStrPath, err) log.Errorf("path (%s) is not valid: %v", userStrPath, err)
} }
// don't consider directories
if fileMeta.IsDir() {
continue
}
references = append(references, file.NewFileReference(file.Path(userStrPath))) references = append(references, file.NewFileReference(file.Path(userStrPath)))
} }
@ -69,9 +75,12 @@ func (s DirectoryResolver) FilesByGlob(patterns ...string) ([]file.Reference, er
if err != nil { if err != nil {
continue continue
} }
// don't consider directories
if fileMeta.IsDir() { if fileMeta.IsDir() {
continue continue
} }
matchedPath := file.Path(match) matchedPath := file.Path(match)
result = append(result, file.NewFileReference(matchedPath)) result = append(result, file.NewFileReference(matchedPath))
} }

View File

@ -48,6 +48,12 @@ func TestDirectoryResolver_FilesByPath(t *testing.T) {
expected: "test-fixtures/image-symlinks/file-1.txt", expected: "test-fixtures/image-symlinks/file-1.txt",
refCount: 1, refCount: 1,
}, },
{
name: "directories ignored",
root: "./test-fixtures/",
input: "/image-symlinks",
refCount: 0,
},
} }
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {

View File

@ -26,16 +26,32 @@ func (r *ImageSquashResolver) FilesByPath(paths ...file.Path) ([]file.Reference,
uniqueFiles := make([]file.Reference, 0) uniqueFiles := make([]file.Reference, 0)
for _, path := range paths { for _, path := range paths {
ref := r.img.SquashedTree().File(path) tree := r.img.SquashedTree()
ref := tree.File(path)
if ref == nil { if ref == nil {
// no file found, keep looking through layers // no file found, keep looking through layers
continue continue
} }
// don't consider directories (special case: there is no path information for /)
if ref.Path == "/" {
continue
} else if r.img.FileCatalog.Exists(*ref) {
metadata, err := r.img.FileCatalog.Get(*ref)
if err != nil {
return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", ref.Path, err)
}
if metadata.Metadata.IsDir {
continue
}
}
// a file may be a symlink, process it as such and resolve it
resolvedRef, err := r.img.ResolveLinkByImageSquash(*ref) resolvedRef, err := r.img.ResolveLinkByImageSquash(*ref)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to resolve link from img (ref=%+v): %w", ref, err) return nil, fmt.Errorf("failed to resolve link from img (ref=%+v): %w", ref, err)
} }
if resolvedRef != nil && !uniqueFileIDs.Contains(*resolvedRef) { if resolvedRef != nil && !uniqueFileIDs.Contains(*resolvedRef) {
uniqueFileIDs.Add(*resolvedRef) uniqueFileIDs.Add(*resolvedRef)
uniqueFiles = append(uniqueFiles, *resolvedRef) uniqueFiles = append(uniqueFiles, *resolvedRef)
@ -57,6 +73,20 @@ func (r *ImageSquashResolver) FilesByGlob(patterns ...string) ([]file.Reference,
} }
for _, ref := range refs { for _, ref := range refs {
// don't consider directories (special case: there is no path information for /)
if ref.Path == "/" {
continue
} else if r.img.FileCatalog.Exists(ref) {
metadata, err := r.img.FileCatalog.Get(ref)
if err != nil {
return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", ref.Path, err)
}
if metadata.Metadata.IsDir {
continue
}
}
resolvedRefs, err := r.FilesByPath(ref.Path) resolvedRefs, err := r.FilesByPath(ref.Path)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to find files by path (ref=%+v): %w", ref, err) return nil, fmt.Errorf("failed to find files by path (ref=%+v): %w", ref, err)

View File

@ -1,9 +1,10 @@
package resolvers package resolvers
import ( import (
"github.com/anchore/stereoscope/pkg/imagetest"
"testing" "testing"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/stereoscope/pkg/file" "github.com/anchore/stereoscope/pkg/file"
) )
@ -44,6 +45,11 @@ func TestImageSquashResolver_FilesByPath(t *testing.T) {
resolveLayer: 8, resolveLayer: 8,
resolvePath: "/link-dead", resolvePath: "/link-dead",
}, },
{
name: "ignore directories",
linkPath: "/bin",
resolvePath: "",
},
} }
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
@ -60,10 +66,20 @@ func TestImageSquashResolver_FilesByPath(t *testing.T) {
t.Fatalf("could not use resolver: %+v", err) t.Fatalf("could not use resolver: %+v", err)
} }
if len(refs) != 1 { expectedRefs := 1
if c.resolvePath == "" {
expectedRefs = 0
}
if len(refs) != expectedRefs {
t.Fatalf("unexpected number of resolutions: %d", len(refs)) t.Fatalf("unexpected number of resolutions: %d", len(refs))
} }
if expectedRefs == 0 {
// nothing else to assert
return
}
actual := refs[0] actual := refs[0]
if actual.Path != file.Path(c.resolvePath) { if actual.Path != file.Path(c.resolvePath) {
@ -119,6 +135,11 @@ func TestImageSquashResolver_FilesByGlob(t *testing.T) {
resolveLayer: 8, resolveLayer: 8,
resolvePath: "/link-dead", resolvePath: "/link-dead",
}, },
{
name: "ignore directories",
glob: "**/bin",
resolvePath: "",
},
} }
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
@ -135,10 +156,20 @@ func TestImageSquashResolver_FilesByGlob(t *testing.T) {
t.Fatalf("could not use resolver: %+v", err) t.Fatalf("could not use resolver: %+v", err)
} }
if len(refs) != 1 { expectedRefs := 1
if c.resolvePath == "" {
expectedRefs = 0
}
if len(refs) != expectedRefs {
t.Fatalf("unexpected number of resolutions: %d", len(refs)) t.Fatalf("unexpected number of resolutions: %d", len(refs))
} }
if expectedRefs == 0 {
// nothing else to assert
return
}
actual := refs[0] actual := refs[0]
if actual.Path != file.Path(c.resolvePath) { if actual.Path != file.Path(c.resolvePath) {

View File

@ -61,9 +61,15 @@ func TestDirectoryScope(t *testing.T) {
{ {
desc: "path detected", desc: "path detected",
input: "test-fixtures", input: "test-fixtures",
inputPaths: []file.Path{file.Path("test-fixtures/path-detected")}, inputPaths: []file.Path{file.Path("test-fixtures/path-detected/.vimrc")},
expRefs: 1, expRefs: 1,
}, },
{
desc: "directory ignored",
input: "test-fixtures",
inputPaths: []file.Path{file.Path("test-fixtures/path-detected")},
expRefs: 0,
},
{ {
desc: "no files-by-path detected", desc: "no files-by-path detected",
input: "test-fixtures", input: "test-fixtures",