directory resolver should account for the proc cwd relative to the root path (#644)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2021-11-30 15:34:37 -05:00 committed by GitHub
parent 6af132e088
commit fe616acd98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 23 deletions

View File

@ -34,6 +34,7 @@ type pathFilterFn func(string) bool
// directoryResolver implements path and content access for the directory data source.
type directoryResolver struct {
path string
cwdRelativeToRoot string
cwd string
fileTree *filetree.FileTree
metadata map[file.ID]FileMetadata
@ -49,6 +50,14 @@ func newDirectoryResolver(root string, pathFilters ...pathFilterFn) (*directoryR
return nil, fmt.Errorf("could not create directory resolver: %w", err)
}
var cwdRelRoot string
if path.IsAbs(root) {
cwdRelRoot, err = filepath.Rel(cwd, root)
if err != nil {
return nil, fmt.Errorf("could not create directory resolver: %w", err)
}
}
if pathFilters == nil {
pathFilters = []pathFilterFn{isUnixSystemRuntimePath}
}
@ -56,6 +65,7 @@ func newDirectoryResolver(root string, pathFilters ...pathFilterFn) (*directoryR
resolver := directoryResolver{
path: root,
cwd: cwd,
cwdRelativeToRoot: cwdRelRoot,
fileTree: filetree.NewFileTree(),
metadata: make(map[file.ID]FileMetadata),
pathFilterFns: pathFilters,
@ -200,7 +210,11 @@ func (r directoryResolver) requestPath(userPath string) (string, error) {
if filepath.IsAbs(userPath) {
// don't allow input to potentially hop above root path
userPath = path.Join(r.path, userPath)
} else {
// ensure we take into account any relative difference between the root path and the CWD for relative requests
userPath = path.Join(r.cwdRelativeToRoot, userPath)
}
var err error
userPath, err = filepath.Abs(userPath)
if err != nil {
@ -212,7 +226,9 @@ func (r directoryResolver) requestPath(userPath string) (string, error) {
func (r directoryResolver) responsePath(path string) string {
// always return references relative to the request path (not absolute path)
if filepath.IsAbs(path) {
return strings.TrimPrefix(path, r.cwd+string(filepath.Separator))
// we need to account for the cwd relative to the running process and the given root for the directory resolver
prefix := filepath.Clean(filepath.Join(r.cwd, r.cwdRelativeToRoot))
return strings.TrimPrefix(path, prefix+string(filepath.Separator))
}
return path
}

View File

@ -10,6 +10,8 @@ import (
"syscall"
"testing"
"github.com/stretchr/testify/require"
"github.com/scylladb/go-set/strset"
"github.com/anchore/stereoscope/pkg/file"
@ -17,6 +19,60 @@ import (
"github.com/wagoodman/go-progress"
)
func TestDirectoryResolver_FilesByPath_absoluteRoot(t *testing.T) {
cases := []struct {
name string
relativeRoot string
input string
expected []string
}{
{
name: "should find a file from an absolute input",
relativeRoot: "./test-fixtures/",
input: "/image-symlinks/file-1.txt",
expected: []string{
"image-symlinks/file-1.txt",
},
},
{
name: "should find a file from a relative path",
relativeRoot: "./test-fixtures/",
input: "image-symlinks/file-1.txt",
expected: []string{
"image-symlinks/file-1.txt",
},
},
{
name: "should find a file from a relative path (root above cwd)",
relativeRoot: "../",
input: "sbom/sbom.go",
expected: []string{
"sbom/sbom.go",
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
// note: this test is all about asserting correct functionality when the given analysis path
// is an absolute path
absRoot, err := filepath.Abs(c.relativeRoot)
require.NoError(t, err)
resolver, err := newDirectoryResolver(absRoot)
assert.NoError(t, err)
refs, err := resolver.FilesByPath(c.input)
require.NoError(t, err)
assert.Len(t, refs, len(c.expected))
s := strset.New()
for _, actual := range refs {
s.Add(actual.RealPath)
}
assert.ElementsMatch(t, c.expected, s.List())
})
}
}
func TestDirectoryResolver_FilesByPath(t *testing.T) {
cases := []struct {
name string
@ -85,18 +141,10 @@ func TestDirectoryResolver_FilesByPath(t *testing.T) {
}
refs, err := resolver.FilesByPath(c.input)
if err != nil {
t.Fatalf("could not use resolver: %+v, %+v", err, refs)
}
if len(refs) != c.refCount {
t.Errorf("unexpected number of refs: %d != %d", len(refs), c.refCount)
}
require.NoError(t, err)
assert.Len(t, refs, c.refCount)
for _, actual := range refs {
if actual.RealPath != c.expected {
t.Errorf("bad resolve path: '%s'!='%s'", actual.RealPath, c.expected)
}
assert.Equal(t, c.expected, actual.RealPath)
}
})
}