From 7e93766d0e19e8155651fe8c99211b4980e30ea3 Mon Sep 17 00:00:00 2001 From: William Murphy Date: Tue, 28 Nov 2023 09:41:28 -0500 Subject: [PATCH] fix: index file itself when file scan path has symlink (#2359) Previously, building the index of the filesystem when source was file would fail if part of the path syft was passed to the file included a symlinked directory, resulting in cataloging misses. --------- Signed-off-by: Will Murphy --- syft/source/file_source.go | 17 ++++++++++++++--- syft/source/file_source_test.go | 16 ++++++++++++++++ syft/source/test-fixtures/actual-path/empty | 0 syft/source/test-fixtures/symlink | 1 + test/cli/symlink_test.go | 13 +++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 syft/source/test-fixtures/actual-path/empty create mode 120000 syft/source/test-fixtures/symlink create mode 100644 test/cli/symlink_test.go diff --git a/syft/source/file_source.go b/syft/source/file_source.go index 481a015e154..fcccd592914 100644 --- a/syft/source/file_source.go +++ b/syft/source/file_source.go @@ -159,11 +159,10 @@ func (s FileSource) FileResolver(_ Scope) (file.Resolver, error) { } isArchiveAnalysis := fi.IsDir() - absAnalysisPath, err := filepath.Abs(s.analysisPath) + absParentDir, err := absoluteSymlinkFreePathToParent(s.analysisPath) if err != nil { - return nil, fmt.Errorf("unable to get absolute path for analysis path=%q: %w", s.analysisPath, err) + return nil, err } - absParentDir := filepath.Dir(absAnalysisPath) var res *fileresolver.Directory if isArchiveAnalysis { @@ -210,6 +209,18 @@ func (s FileSource) FileResolver(_ Scope) (file.Resolver, error) { return s.resolver, nil } +func absoluteSymlinkFreePathToParent(path string) (string, error) { + absAnalysisPath, err := filepath.Abs(path) + if err != nil { + return "", fmt.Errorf("unable to get absolute path for analysis path=%q: %w", path, err) + } + dereferencedAbsAnalysisPath, err := filepath.EvalSymlinks(absAnalysisPath) + if err != nil { + return "", fmt.Errorf("unable to get absolute path for analysis path=%q: %w", path, err) + } + return filepath.Dir(dereferencedAbsAnalysisPath), nil +} + func (s *FileSource) Close() error { if s.closer == nil { return nil diff --git a/syft/source/file_source_test.go b/syft/source/file_source_test.go index 614808d7bdf..54475c7c14f 100644 --- a/syft/source/file_source_test.go +++ b/syft/source/file_source_test.go @@ -48,6 +48,22 @@ func TestNewFromFile(t *testing.T) { }, expRefs: 1, }, + { + desc: "normal path", + input: "test-fixtures/actual-path/empty", + testPathFn: func(resolver file.Resolver) ([]file.Location, error) { + return resolver.FilesByPath("empty") + }, + expRefs: 1, + }, + { + desc: "path containing symlink", + input: "test-fixtures/symlink/empty", + testPathFn: func(resolver file.Resolver) ([]file.Location, error) { + return resolver.FilesByPath("empty") + }, + expRefs: 1, + }, } for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { diff --git a/syft/source/test-fixtures/actual-path/empty b/syft/source/test-fixtures/actual-path/empty new file mode 100644 index 00000000000..e69de29bb2d diff --git a/syft/source/test-fixtures/symlink b/syft/source/test-fixtures/symlink new file mode 120000 index 00000000000..b124011449c --- /dev/null +++ b/syft/source/test-fixtures/symlink @@ -0,0 +1 @@ +actual-path \ No newline at end of file diff --git a/test/cli/symlink_test.go b/test/cli/symlink_test.go new file mode 100644 index 00000000000..a81a0d9b8ca --- /dev/null +++ b/test/cli/symlink_test.go @@ -0,0 +1,13 @@ +package cli + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_RequestedPathIncludesSymlink(t *testing.T) { + // path contains a symlink + path := "test-fixtures/image-pkg-coverage/pkgs/java/example-java-app-maven-0.1.0.jar" + _, stdout, _ := runSyft(t, nil, "packages", path) + assert.Contains(t, stdout, "example-java-app-maven") +}