Fix directory resolver to consider CWD and root path input correctly (#1840)

* [wip] put in initial fix

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* capture expected behavior of dir resolver in tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update tests + comments to reflect current dir resolver behavior

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add additional test cases

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix linting

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix additional tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix bad merge conflict resolution

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

---------

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2023-05-25 09:41:18 -04:00 committed by GitHub
parent 07e76907f6
commit 6afbffce28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1177 additions and 29 deletions

View File

@ -13,7 +13,6 @@ import (
"github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom" "github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
) )
// TODO: Add ToFormatModel tests // TODO: Add ToFormatModel tests
@ -505,14 +504,14 @@ func Test_toSPDXID(t *testing.T) {
}{ }{
{ {
name: "short filename", name: "short filename",
it: source.Coordinates{ it: file.Coordinates{
RealPath: "/short/path/file.txt", RealPath: "/short/path/file.txt",
}, },
expected: "File-short-path-file.txt", expected: "File-short-path-file.txt",
}, },
{ {
name: "long filename", name: "long filename",
it: source.Coordinates{ it: file.Coordinates{
RealPath: "/some/long/path/with/a/lot/of-text/that-contains-a/file.txt", RealPath: "/some/long/path/with/a/lot/of-text/that-contains-a/file.txt",
}, },
expected: "File-...a-lot-of-text-that-contains-a-file.txt", expected: "File-...a-lot-of-text-that-contains-a-file.txt",

View File

@ -54,12 +54,6 @@ func newFromDirectoryWithoutIndex(root string, base string, pathFilters ...PathI
if err != nil { if err != nil {
return nil, fmt.Errorf("could not get CWD: %w", err) return nil, fmt.Errorf("could not get CWD: %w", err)
} }
// we have to account for the root being accessed through a symlink path and always resolve the real path. Otherwise
// we will not be able to normalize given paths that fall under the resolver
cleanCWD, err := filepath.EvalSymlinks(currentWD)
if err != nil {
return nil, fmt.Errorf("could not evaluate CWD symlinks: %w", err)
}
cleanRoot, err := filepath.EvalSymlinks(root) cleanRoot, err := filepath.EvalSymlinks(root)
if err != nil { if err != nil {
@ -80,7 +74,7 @@ func newFromDirectoryWithoutIndex(root string, base string, pathFilters ...PathI
var currentWdRelRoot string var currentWdRelRoot string
if path.IsAbs(cleanRoot) { if path.IsAbs(cleanRoot) {
currentWdRelRoot, err = filepath.Rel(cleanCWD, cleanRoot) currentWdRelRoot, err = filepath.Rel(currentWD, cleanRoot)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not determine given root path to CWD: %w", err) return nil, fmt.Errorf("could not determine given root path to CWD: %w", err)
} }
@ -91,7 +85,7 @@ func newFromDirectoryWithoutIndex(root string, base string, pathFilters ...PathI
return &Directory{ return &Directory{
path: cleanRoot, path: cleanRoot,
base: cleanBase, base: cleanBase,
currentWd: cleanCWD, currentWd: currentWD,
currentWdRelativeToRoot: currentWdRelRoot, currentWdRelativeToRoot: currentWdRelRoot,
tree: filetree.New(), tree: filetree.New(),
index: filetree.NewIndex(), index: filetree.NewIndex(),
@ -132,6 +126,7 @@ func (r Directory) requestPath(userPath string) (string, error) {
return userPath, nil return userPath, nil
} }
// responsePath takes a path from the underlying fs domain and converts it to a path that is relative to the root of the directory resolver.
func (r Directory) responsePath(path string) string { func (r Directory) responsePath(path string) string {
// check to see if we need to encode back to Windows from posix // check to see if we need to encode back to Windows from posix
if runtime.GOOS == WindowsOS { if runtime.GOOS == WindowsOS {

View File

@ -8,6 +8,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings"
"github.com/wagoodman/go-partybus" "github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress" "github.com/wagoodman/go-progress"
@ -119,6 +120,22 @@ func (r *directoryIndexer) indexTree(root string, stager *progress.Stage) ([]str
return roots, nil return roots, nil
} }
shouldIndexFullTree, err := isRealPath(root)
if err != nil {
return nil, err
}
if !shouldIndexFullTree {
newRoots, err := r.indexBranch(root, stager)
if err != nil {
return nil, fmt.Errorf("unable to index branch=%q: %w", root, err)
}
roots = append(roots, newRoots...)
return roots, nil
}
err = filepath.Walk(root, err = filepath.Walk(root,
func(path string, info os.FileInfo, err error) error { func(path string, info os.FileInfo, err error) error {
stager.Current = path stager.Current = path
@ -143,6 +160,85 @@ func (r *directoryIndexer) indexTree(root string, stager *progress.Stage) ([]str
return roots, nil return roots, nil
} }
func isRealPath(root string) (bool, error) {
rootParent := filepath.Clean(filepath.Dir(root))
realRootParent, err := filepath.EvalSymlinks(rootParent)
if err != nil {
return false, err
}
realRootParent = filepath.Clean(realRootParent)
return rootParent == realRootParent, nil
}
func (r *directoryIndexer) indexBranch(root string, stager *progress.Stage) ([]string, error) {
rootRealPath, err := filepath.EvalSymlinks(root)
if err != nil {
return nil, err
}
// there is a symlink within the path to the root, we need to index the real root parent first
// then capture the symlinks to the root path
roots, err := r.indexTree(rootRealPath, stager)
if err != nil {
return nil, fmt.Errorf("unable to index real root=%q: %w", rootRealPath, err)
}
// walk down all ancestor paths and shallow-add non-existing elements to the tree
for idx, p := range allContainedPaths(root) {
var targetPath string
if idx != 0 {
parent := path.Dir(p)
cleanParent, err := filepath.EvalSymlinks(parent)
if err != nil {
return nil, fmt.Errorf("unable to evaluate symlink for contained path parent=%q: %w", parent, err)
}
targetPath = filepath.Join(cleanParent, filepath.Base(p))
} else {
targetPath = p
}
stager.Current = targetPath
lstat, err := os.Lstat(targetPath)
newRoot, err := r.indexPath(targetPath, lstat, err)
if err != nil && !errors.Is(err, ErrSkipPath) && !errors.Is(err, fs.SkipDir) {
return nil, fmt.Errorf("unable to index ancestor path=%q: %w", targetPath, err)
}
if newRoot != "" {
roots = append(roots, newRoot)
}
}
return roots, nil
}
func allContainedPaths(p string) []string {
var all []string
var currentPath string
cleanPath := strings.TrimSpace(p)
if cleanPath == "" {
return nil
}
// iterate through all parts of the path, replacing path elements with link resolutions where possible.
for idx, part := range strings.Split(filepath.Clean(cleanPath), file.DirSeparator) {
if idx == 0 && part == "" {
currentPath = file.DirSeparator
continue
}
// cumulatively gather where we are currently at and provide a rich object
currentPath = path.Join(currentPath, part)
all = append(all, currentPath)
}
return all
}
func (r *directoryIndexer) indexPath(path string, info os.FileInfo, err error) (string, error) { func (r *directoryIndexer) indexPath(path string, info os.FileInfo, err error) (string, error) {
// ignore any path which a filter function returns true // ignore any path which a filter function returns true
for _, filterFn := range r.pathIndexVisitors { for _, filterFn := range r.pathIndexVisitors {

View File

@ -226,8 +226,8 @@ func TestDirectoryIndexer_SkipsAlreadyVisitedLinkDestinations(t *testing.T) {
var observedPaths []string var observedPaths []string
pathObserver := func(p string, _ os.FileInfo, _ error) error { pathObserver := func(p string, _ os.FileInfo, _ error) error {
fields := strings.Split(p, "test-fixtures/symlinks-prune-indexing") fields := strings.Split(p, "test-fixtures/symlinks-prune-indexing")
if len(fields) != 2 { if len(fields) < 2 {
t.Fatalf("unable to parse path: %s", p) return nil
} }
clean := strings.TrimLeft(fields[1], "/") clean := strings.TrimLeft(fields[1], "/")
if clean != "" { if clean != "" {
@ -261,9 +261,11 @@ func TestDirectoryIndexer_SkipsAlreadyVisitedLinkDestinations(t *testing.T) {
"path/5/6/7/8/dont-index-me-twice-either.txt", "path/5/6/7/8/dont-index-me-twice-either.txt",
"path/file.txt", "path/file.txt",
// everything below is after the original tree is indexed, and we are now indexing additional roots from symlinks // everything below is after the original tree is indexed, and we are now indexing additional roots from symlinks
"path", // considered from symlink before-path, but pruned "path", // considered from symlink before-path, but pruned
"before-path/file.txt", // considered from symlink c-file.txt, but pruned "path/file.txt", // leaf
"before-path", // considered from symlink c-path, but pruned "before-path", // considered from symlink c-path, but pruned
"path/file.txt", // leaf
"before-path", // considered from symlink c-path, but pruned
} }
assert.Equal(t, expected, observedPaths, "visited paths differ \n %s", cmp.Diff(expected, observedPaths)) assert.Equal(t, expected, observedPaths, "visited paths differ \n %s", cmp.Diff(expected, observedPaths))
@ -282,7 +284,7 @@ func TestDirectoryIndexer_IndexesAllTypes(t *testing.T) {
for _, ref := range allRefs { for _, ref := range allRefs {
fields := strings.Split(string(ref.RealPath), "test-fixtures/symlinks-prune-indexing") fields := strings.Split(string(ref.RealPath), "test-fixtures/symlinks-prune-indexing")
if len(fields) != 2 { if len(fields) != 2 {
t.Fatalf("unable to parse path: %s", ref.RealPath) continue
} }
clean := strings.TrimLeft(fields[1], "/") clean := strings.TrimLeft(fields[1], "/")
if clean == "" { if clean == "" {
@ -326,3 +328,58 @@ func TestDirectoryIndexer_IndexesAllTypes(t *testing.T) {
} }
} }
func Test_allContainedPaths(t *testing.T) {
tests := []struct {
name string
path string
want []string
}{
{
name: "empty",
path: "",
want: nil,
},
{
name: "single relative",
path: "a",
want: []string{"a"},
},
{
name: "single absolute",
path: "/a",
want: []string{"/a"},
},
{
name: "multiple relative",
path: "a/b/c",
want: []string{"a", "a/b", "a/b/c"},
},
{
name: "multiple absolute",
path: "/a/b/c",
want: []string{"/a", "/a/b", "/a/b/c"},
},
{
name: "multiple absolute with extra slashs",
path: "///a/b//c/",
want: []string{"/a", "/a/b", "/a/b/c"},
},
{
name: "relative with single dot",
path: "a/./b",
want: []string{"a", "a/b"},
},
{
name: "relative with double single dot",
path: "a/../b",
want: []string{"b"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, allContainedPaths(tt.path))
})
}
}

View File

@ -22,6 +22,501 @@ import (
"github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/file"
) )
func TestDirectoryResolver_FilesByPath_request_response(t *testing.T) {
// /
// somewhere/
// outside.txt
// root-link -> ./
// path/
// to/
// abs-inside.txt -> /path/to/the/file.txt # absolute link to somewhere inside of the root
// rel-inside.txt -> ./the/file.txt # relative link to somewhere inside of the root
// the/
// file.txt
// abs-outside.txt -> /somewhere/outside.txt # absolute link to outside of the root
// rel-outside -> ../../../somewhere/outside.txt # relative link to outside of the root
//
testDir, err := os.Getwd()
require.NoError(t, err)
relative := filepath.Join("test-fixtures", "req-resp")
absolute := filepath.Join(testDir, relative)
absInsidePath := filepath.Join(absolute, "path", "to", "abs-inside.txt")
absOutsidePath := filepath.Join(absolute, "path", "to", "the", "abs-outside.txt")
relativeViaLink := filepath.Join(relative, "root-link")
absoluteViaLink := filepath.Join(absolute, "root-link")
relativeViaDoubleLink := filepath.Join(relative, "root-link", "root-link")
absoluteViaDoubleLink := filepath.Join(absolute, "root-link", "root-link")
cleanup := func() {
_ = os.Remove(absInsidePath)
_ = os.Remove(absOutsidePath)
}
// ensure the absolute symlinks are cleaned up from any previous runs
cleanup()
require.NoError(t, os.Symlink(filepath.Join(absolute, "path", "to", "the", "file.txt"), absInsidePath))
require.NoError(t, os.Symlink(filepath.Join(absolute, "somewhere", "outside.txt"), absOutsidePath))
t.Cleanup(cleanup)
cases := []struct {
name string
cwd string
root string
base string
input string
expectedRealPath string
expectedVirtualPath string
}{
{
name: "relative root, relative request, direct",
root: relative,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, relative request, direct",
root: absolute,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "relative root, abs request, direct",
root: relative,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, abs request, direct",
root: absolute,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
// cwd within root...
{
name: "relative root, relative request, direct, cwd within root",
cwd: filepath.Join(relative, "path/to"),
root: "../../",
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, relative request, direct, cwd within root",
cwd: filepath.Join(relative, "path/to"),
root: absolute,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "relative root, abs request, direct, cwd within root",
cwd: filepath.Join(relative, "path/to"),
root: "../../",
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, abs request, direct, cwd within root",
cwd: filepath.Join(relative, "path/to"),
root: absolute,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
// cwd within symlink root...
{
name: "relative root, relative request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: "./",
input: "path/to/the/file.txt",
// note: why not expect "path/to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "path/to/the/file.txt",
expectedVirtualPath: "path/to/the/file.txt",
},
{
name: "abs root, relative request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: absoluteViaLink,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "relative root, abs request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: "./",
input: "/path/to/the/file.txt",
// note: why not expect "path/to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "path/to/the/file.txt",
expectedVirtualPath: "path/to/the/file.txt",
},
{
name: "abs root, abs request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: absoluteViaLink,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
// cwd within symlink root, request nested within...
{
name: "relative root, relative nested request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: "./path",
input: "to/the/file.txt",
// note: why not expect "to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "to/the/file.txt",
expectedVirtualPath: "to/the/file.txt",
},
{
name: "abs root, relative nested request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absoluteViaLink, "path"),
input: "to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
{
name: "relative root, abs nested request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: "./path",
input: "/to/the/file.txt",
// note: why not expect "to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "to/the/file.txt",
expectedVirtualPath: "to/the/file.txt",
},
{
name: "abs root, abs nested request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absoluteViaLink, "path"),
input: "/to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
// cwd within DOUBLE symlink root...
{
name: "relative root, relative request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: "./",
input: "path/to/the/file.txt",
// note: why not expect "path/to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "path/to/the/file.txt",
expectedVirtualPath: "path/to/the/file.txt",
},
{
name: "abs root, relative request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: absoluteViaDoubleLink,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "relative root, abs request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: "./",
input: "/path/to/the/file.txt",
// note: why not expect "path/to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "path/to/the/file.txt",
expectedVirtualPath: "path/to/the/file.txt",
},
{
name: "abs root, abs request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: absoluteViaDoubleLink,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
// cwd within DOUBLE symlink root, request nested within...
{
name: "relative root, relative nested request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: "./path",
input: "to/the/file.txt",
// note: why not expect "path/to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "to/the/file.txt",
expectedVirtualPath: "to/the/file.txt",
},
{
name: "abs root, relative nested request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: filepath.Join(absoluteViaDoubleLink, "path"),
input: "to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
{
name: "relative root, abs nested request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: "./path",
input: "/to/the/file.txt",
// note: why not expect "path/to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "to/the/file.txt",
expectedVirtualPath: "to/the/file.txt",
},
{
name: "abs root, abs nested request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: filepath.Join(absoluteViaDoubleLink, "path"),
input: "/to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
// cwd within DOUBLE symlink root, request nested DEEP within...
{
name: "relative root, relative nested request, direct, cwd deep within (double) symlink root",
cwd: filepath.Join(relativeViaDoubleLink, "path", "to"),
root: "../",
input: "to/the/file.txt",
// note: why not expect "path/to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "to/the/file.txt",
expectedVirtualPath: "to/the/file.txt",
},
{
name: "abs root, relative nested request, direct, cwd deep within (double) symlink root",
cwd: filepath.Join(relativeViaDoubleLink, "path", "to"),
root: filepath.Join(absoluteViaDoubleLink, "path"),
input: "to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
{
name: "relative root, abs nested request, direct, cwd deep within (double) symlink root",
cwd: filepath.Join(relativeViaDoubleLink, "path", "to"),
root: "../",
input: "/to/the/file.txt",
// note: why not expect "path/to/the/file.txt" here?
// this is because we don't know that the path used to access this path (which is a link within
// the root) resides within the root. Without this information it appears as if this file resides
// outside the root.
expectedRealPath: filepath.Join(absolute, "path/to/the/file.txt"),
//expectedRealPath: "to/the/file.txt",
expectedVirtualPath: "to/the/file.txt",
},
{
name: "abs root, abs nested request, direct, cwd deep within (double) symlink root",
cwd: filepath.Join(relativeViaDoubleLink, "path", "to"),
root: filepath.Join(absoluteViaDoubleLink, "path"),
input: "/to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
// link to outside of root cases...
{
name: "relative root, relative request, abs indirect (outside of root)",
root: filepath.Join(relative, "path"),
input: "to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "abs root, relative request, abs indirect (outside of root)",
root: filepath.Join(absolute, "path"),
input: "to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "relative root, abs request, abs indirect (outside of root)",
root: filepath.Join(relative, "path"),
input: "/to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "abs root, abs request, abs indirect (outside of root)",
root: filepath.Join(absolute, "path"),
input: "/to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "relative root, relative request, relative indirect (outside of root)",
root: filepath.Join(relative, "path"),
input: "to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, relative request, relative indirect (outside of root)",
root: filepath.Join(absolute, "path"),
input: "to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "relative root, abs request, relative indirect (outside of root)",
root: filepath.Join(relative, "path"),
input: "/to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, abs request, relative indirect (outside of root)",
root: filepath.Join(absolute, "path"),
input: "/to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
// link to outside of root cases... cwd within symlink root
{
name: "relative root, relative request, abs indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: "path",
input: "to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "abs root, relative request, abs indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absolute, "path"),
input: "to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "relative root, abs request, abs indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: "path",
input: "/to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "abs root, abs request, abs indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absolute, "path"),
input: "/to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "relative root, relative request, relative indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: "path",
input: "to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, relative request, relative indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absolute, "path"),
input: "to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "relative root, abs request, relative indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: "path",
input: "/to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, abs request, relative indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absolute, "path"),
input: "/to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "relative root, relative request, relative indirect (outside of root), cwd within DOUBLE symlink root",
cwd: relativeViaDoubleLink,
root: "path",
input: "to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, relative request, relative indirect (outside of root), cwd within DOUBLE symlink root",
cwd: relativeViaDoubleLink,
root: filepath.Join(absolute, "path"),
input: "to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "relative root, abs request, relative indirect (outside of root), cwd within DOUBLE symlink root",
cwd: relativeViaDoubleLink,
root: "path",
input: "/to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, abs request, relative indirect (outside of root), cwd within DOUBLE symlink root",
cwd: relativeViaDoubleLink,
root: filepath.Join(absolute, "path"),
input: "/to/the/rel-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/rel-outside.txt",
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
// we need to mimic a shell, otherwise we won't get a path within a symlink
targetPath := filepath.Join(testDir, c.cwd)
t.Setenv("PWD", filepath.Clean(targetPath))
require.NoError(t, err)
require.NoError(t, os.Chdir(targetPath))
t.Cleanup(func() {
require.NoError(t, os.Chdir(testDir))
})
resolver, err := NewFromDirectory(c.root, c.base)
require.NoError(t, err)
require.NotNil(t, resolver)
refs, err := resolver.FilesByPath(c.input)
require.NoError(t, err)
if c.expectedRealPath == "" {
require.Empty(t, refs)
return
}
require.Len(t, refs, 1)
assert.Equal(t, c.expectedRealPath, refs[0].RealPath, "real path different")
assert.Equal(t, c.expectedVirtualPath, refs[0].VirtualPath, "virtual path different")
})
}
}
func TestDirectoryResolver_FilesByPath_relativeRoot(t *testing.T) { func TestDirectoryResolver_FilesByPath_relativeRoot(t *testing.T) {
cases := []struct { cases := []struct {
name string name string

View File

@ -0,0 +1 @@
./the/file.txt

View File

@ -0,0 +1 @@
file-1

View File

@ -0,0 +1 @@
../../../somewhere/outside.txt

View File

@ -0,0 +1 @@
./

View File

@ -23,6 +23,509 @@ import (
"github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/file"
) )
func Test_UnindexDirectoryResolver_RequestRelativePathWithinSymlink(t *testing.T) {
pwd, err := os.Getwd()
// we need to mimic a shell, otherwise we won't get a path within a symlink
targetPath := filepath.Join(pwd, "./test-fixtures/symlinked-root/nested/link-root/nested")
t.Setenv("PWD", targetPath)
require.NoError(t, err)
require.NoError(t, os.Chdir(targetPath))
t.Cleanup(func() {
require.NoError(t, os.Chdir(pwd))
})
resolver := NewFromUnindexedDirectory("./")
require.NoError(t, err)
locations, err := resolver.FilesByPath("file2.txt")
require.NoError(t, err)
require.Len(t, locations, 1)
// TODO: this is technically not correct behavior since this is reporting the symlink path (virtual path) and
// not the real path.
require.False(t, filepath.IsAbs(locations[0].RealPath), "should be relative path")
}
func Test_UnindexDirectoryResolver_FilesByPath_request_response(t *testing.T) {
// /
// somewhere/
// outside.txt
// root-link -> ./
// path/
// to/
// abs-inside.txt -> /path/to/the/file.txt # absolute link to somewhere inside of the root
// rel-inside.txt -> ./the/file.txt # relative link to somewhere inside of the root
// the/
// file.txt
// abs-outside.txt -> /somewhere/outside.txt # absolute link to outside of the root
// rel-outside -> ../../../somewhere/outside.txt # relative link to outside of the root
//
testDir, err := os.Getwd()
require.NoError(t, err)
relative := filepath.Join("test-fixtures", "req-resp")
absolute := filepath.Join(testDir, relative)
absInsidePath := filepath.Join(absolute, "path", "to", "abs-inside.txt")
absOutsidePath := filepath.Join(absolute, "path", "to", "the", "abs-outside.txt")
relativeViaLink := filepath.Join(relative, "root-link")
absoluteViaLink := filepath.Join(absolute, "root-link")
relativeViaDoubleLink := filepath.Join(relative, "root-link", "root-link")
absoluteViaDoubleLink := filepath.Join(absolute, "root-link", "root-link")
cleanup := func() {
_ = os.Remove(absInsidePath)
_ = os.Remove(absOutsidePath)
}
// ensure the absolute symlinks are cleaned up from any previous runs
cleanup()
require.NoError(t, os.Symlink(filepath.Join(absolute, "path", "to", "the", "file.txt"), absInsidePath))
require.NoError(t, os.Symlink(filepath.Join(absolute, "somewhere", "outside.txt"), absOutsidePath))
t.Cleanup(cleanup)
cases := []struct {
name string
cwd string
root string
base string
input string
expectedRealPath string
expectedVirtualPath string
}{
{
name: "relative root, relative request, direct",
root: relative,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, relative request, direct",
root: absolute,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "relative root, abs request, direct",
root: relative,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, abs request, direct",
root: absolute,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
// cwd within root...
{
name: "relative root, relative request, direct, cwd within root",
cwd: filepath.Join(relative, "path/to"),
root: "../../",
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, relative request, direct, cwd within root",
cwd: filepath.Join(relative, "path/to"),
root: absolute,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "relative root, abs request, direct, cwd within root",
cwd: filepath.Join(relative, "path/to"),
root: "../../",
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, abs request, direct, cwd within root",
cwd: filepath.Join(relative, "path/to"),
root: absolute,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
// cwd within symlink root...
{
name: "relative root, relative request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: "./",
input: "path/to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, relative request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: absoluteViaLink,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "relative root, abs request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: "./",
input: "/path/to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, abs request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: absoluteViaLink,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
// cwd within symlink root, request nested within...
{
name: "relative root, relative nested request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: "./path",
input: "to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "to/the/file.txt",
},
{
name: "abs root, relative nested request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absoluteViaLink, "path"),
input: "to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
{
name: "relative root, abs nested request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: "./path",
input: "/to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "to/the/file.txt",
},
{
name: "abs root, abs nested request, direct, cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absoluteViaLink, "path"),
input: "/to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
// cwd within DOUBLE symlink root...
{
name: "relative root, relative request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: "./",
input: "path/to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, relative request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: absoluteViaDoubleLink,
input: "path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
{
name: "relative root, abs request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: "./",
input: "/path/to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "path/to/the/file.txt",
},
{
name: "abs root, abs request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: absoluteViaDoubleLink,
input: "/path/to/the/file.txt",
expectedRealPath: "path/to/the/file.txt",
},
// cwd within DOUBLE symlink root, request nested within...
{
name: "relative root, relative nested request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: "./path",
input: "to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "to/the/file.txt",
},
{
name: "abs root, relative nested request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: filepath.Join(absoluteViaDoubleLink, "path"),
input: "to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
{
name: "relative root, abs nested request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: "./path",
input: "/to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "to/the/file.txt",
},
{
name: "abs root, abs nested request, direct, cwd within (double) symlink root",
cwd: relativeViaDoubleLink,
root: filepath.Join(absoluteViaDoubleLink, "path"),
input: "/to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
// cwd within DOUBLE symlink root, request nested DEEP within...
{
name: "relative root, relative nested request, direct, cwd deep within (double) symlink root",
cwd: filepath.Join(relativeViaDoubleLink, "path", "to"),
root: "../",
input: "to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "to/the/file.txt",
},
{
name: "abs root, relative nested request, direct, cwd deep within (double) symlink root",
cwd: filepath.Join(relativeViaDoubleLink, "path", "to"),
root: filepath.Join(absoluteViaDoubleLink, "path"),
input: "to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
{
name: "relative root, abs nested request, direct, cwd deep within (double) symlink root",
cwd: filepath.Join(relativeViaDoubleLink, "path", "to"),
root: "../",
input: "/to/the/file.txt",
// note: this is inconsistent with the directory resolver. The real path is essentially the virtual path
// in this case for the unindexed resolver, which is not correct.
expectedRealPath: "to/the/file.txt",
},
{
name: "abs root, abs nested request, direct, cwd deep within (double) symlink root",
cwd: filepath.Join(relativeViaDoubleLink, "path", "to"),
root: filepath.Join(absoluteViaDoubleLink, "path"),
input: "/to/the/file.txt",
expectedRealPath: "to/the/file.txt",
},
// link to outside of root cases...
{
name: "relative root, relative request, abs indirect (outside of root)",
root: filepath.Join(relative, "path"),
input: "to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "abs root, relative request, abs indirect (outside of root)",
root: filepath.Join(absolute, "path"),
input: "to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "relative root, abs request, abs indirect (outside of root)",
root: filepath.Join(relative, "path"),
input: "/to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "abs root, abs request, abs indirect (outside of root)",
root: filepath.Join(absolute, "path"),
input: "/to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "relative root, relative request, relative indirect (outside of root)",
root: filepath.Join(relative, "path"),
input: "to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, relative request, relative indirect (outside of root)",
root: filepath.Join(absolute, "path"),
input: "to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "relative root, abs request, relative indirect (outside of root)",
root: filepath.Join(relative, "path"),
input: "/to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, abs request, relative indirect (outside of root)",
root: filepath.Join(absolute, "path"),
input: "/to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
// link to outside of root cases... cwd within symlink root
{
name: "relative root, relative request, abs indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: "path",
input: "to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "abs root, relative request, abs indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absolute, "path"),
input: "to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "relative root, abs request, abs indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: "path",
input: "/to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "abs root, abs request, abs indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absolute, "path"),
input: "/to/the/abs-outside.txt",
expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
expectedVirtualPath: "to/the/abs-outside.txt",
},
{
name: "relative root, relative request, relative indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: "path",
input: "to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, relative request, relative indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absolute, "path"),
input: "to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "relative root, abs request, relative indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: "path",
input: "/to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, abs request, relative indirect (outside of root), cwd within symlink root",
cwd: relativeViaLink,
root: filepath.Join(absolute, "path"),
input: "/to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "relative root, relative request, relative indirect (outside of root), cwd within DOUBLE symlink root",
cwd: relativeViaDoubleLink,
root: "path",
input: "to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, relative request, relative indirect (outside of root), cwd within DOUBLE symlink root",
cwd: relativeViaDoubleLink,
root: filepath.Join(absolute, "path"),
input: "to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "relative root, abs request, relative indirect (outside of root), cwd within DOUBLE symlink root",
cwd: relativeViaDoubleLink,
root: "path",
input: "/to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
{
name: "abs root, abs request, relative indirect (outside of root), cwd within DOUBLE symlink root",
cwd: relativeViaDoubleLink,
root: filepath.Join(absolute, "path"),
input: "/to/the/rel-outside.txt",
//expectedRealPath: filepath.Join(absolute, "/somewhere/outside.txt"),
// TODO: the real path is not correct
expectedRealPath: "../somewhere/outside.txt",
expectedVirtualPath: "to/the/rel-outside.txt",
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
// we need to mimic a shell, otherwise we won't get a path within a symlink
targetPath := filepath.Join(testDir, c.cwd)
t.Setenv("PWD", filepath.Clean(targetPath))
require.NoError(t, err)
require.NoError(t, os.Chdir(targetPath))
t.Cleanup(func() {
require.NoError(t, os.Chdir(testDir))
})
resolver := NewFromUnindexedDirectory(c.root)
require.NotNil(t, resolver)
refs, err := resolver.FilesByPath(c.input)
require.NoError(t, err)
if c.expectedRealPath == "" {
require.Empty(t, refs)
return
}
require.Len(t, refs, 1)
assert.Equal(t, c.expectedRealPath, refs[0].RealPath, "real path different")
assert.Equal(t, c.expectedVirtualPath, refs[0].VirtualPath, "virtual path different")
})
}
}
func Test_UnindexedDirectoryResolver_Basic(t *testing.T) { func Test_UnindexedDirectoryResolver_Basic(t *testing.T) {
wd, err := os.Getwd() wd, err := os.Getwd()
require.NoError(t, err) require.NoError(t, err)

View File

@ -7,7 +7,6 @@ import (
"github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
"github.com/anchore/syft/syft/source"
) )
func Test_KernelCataloger(t *testing.T) { func Test_KernelCataloger(t *testing.T) {
@ -50,7 +49,7 @@ func Test_KernelCataloger(t *testing.T) {
), ),
Licenses: pkg.NewLicenseSet( Licenses: pkg.NewLicenseSet(
pkg.NewLicenseFromLocations("GPL v2", pkg.NewLicenseFromLocations("GPL v2",
source.NewVirtualLocation( file.NewVirtualLocation(
"/lib/modules/6.0.7-301.fc37.x86_64/kernel/drivers/tty/ttynull.ko", "/lib/modules/6.0.7-301.fc37.x86_64/kernel/drivers/tty/ttynull.ko",
"/lib/modules/6.0.7-301.fc37.x86_64/kernel/drivers/tty/ttynull.ko", "/lib/modules/6.0.7-301.fc37.x86_64/kernel/drivers/tty/ttynull.ko",
), ),

View File

@ -8,7 +8,6 @@ import (
"github.com/anchore/syft/internal" "github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/license" "github.com/anchore/syft/syft/license"
"github.com/anchore/syft/syft/source"
) )
func TestLicenseSet_Add(t *testing.T) { func TestLicenseSet_Add(t *testing.T) {
@ -59,15 +58,15 @@ func TestLicenseSet_Add(t *testing.T) {
{ {
name: "deduplicate licenses with locations", name: "deduplicate licenses with locations",
licenses: []License{ licenses: []License{
NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "1"})), NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "1"})),
NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "1"})), NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "1"})),
NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "2"})), NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "2"})),
}, },
want: []License{ want: []License{
NewLicenseFromLocations( NewLicenseFromLocations(
"MIT", "MIT",
file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "1"}), file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "1"}),
file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "2"}), file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "2"}),
), ),
}, },
}, },
@ -75,14 +74,14 @@ func TestLicenseSet_Add(t *testing.T) {
name: "same licenses with different locations", name: "same licenses with different locations",
licenses: []License{ licenses: []License{
NewLicense("MIT"), NewLicense("MIT"),
NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "2"})), NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "2"})),
NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "1"})), NewLicenseFromLocations("MIT", file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "1"})),
}, },
want: []License{ want: []License{
NewLicenseFromLocations( NewLicenseFromLocations(
"MIT", "MIT",
file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "1"}), file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "1"}),
file.NewLocationFromCoordinates(source.Coordinates{RealPath: "/place", FileSystemID: "2"}), file.NewLocationFromCoordinates(file.Coordinates{RealPath: "/place", FileSystemID: "2"}),
), ),
}, },
}, },