diff --git a/syft/internal/fileresolver/directory.go b/syft/internal/fileresolver/directory.go index c517c00f2..36bf3cf90 100644 --- a/syft/internal/fileresolver/directory.go +++ b/syft/internal/fileresolver/directory.go @@ -16,8 +16,8 @@ import ( type archiveAccessPath struct { realPath string accessPath string - archiveDepth int archiveRealPath string + archiveDepth int } const ( @@ -100,7 +100,11 @@ func (r *Directory) buildIndex() error { func (r *Directory) buildArchiveIndex(archiveTempDir string, archives []string, maxArchiveIndexDepth int) error { archivesToIndex := make([]archiveAccessPath, len(archives)) for i, archive := range archives { - archivesToIndex[i] = archiveAccessPath{realPath: archive, accessPath: archive, archiveRealPath: archive} + archivesToIndex[i] = archiveAccessPath{ + realPath: archive, + accessPath: archive, + archiveRealPath: archive, + } } loop: @@ -119,59 +123,59 @@ loop: continue } - archivePath, err := os.MkdirTemp(archiveTempDir, archiveContentTempPathPattern) + envelopedUnarchiver, err := archiver.ByExtension(currentArchivePath.archiveRealPath) + if err != nil { + return fmt.Errorf("could not determine archive envelope type: %w", err) + } + + unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver) + if !ok { + return fmt.Errorf("unarchiver %T is not an archiver", envelopedUnarchiver) + } + + archiveDestinationTempDir, err := os.MkdirTemp(archiveTempDir, archiveContentTempPathPattern) if err != nil { return fmt.Errorf("unable to create tempdir for archive processing: %w", err) } - archiveRealPath, err := filepath.EvalSymlinks(archivePath) + archiveDestinationPath, err := filepath.EvalSymlinks(archiveDestinationTempDir) if err != nil { var pathErr *os.PathError if errors.As(err, &pathErr) { // we can't index the path, but we shouldn't consider this to be fatal // TODO: known-unknowns - log.WithFields("archivePath", archivePath, "error", err).Trace("unable to evaluate symlink while indexing branch") - return nil + log.WithFields("archivePath", archiveDestinationTempDir, "error", err).Trace("unable to evaluate symlink while indexing branch") + continue } return err } - envelopedUnarchiver, err := archiver.ByExtension(currentArchivePath.archiveRealPath) - if err != nil { - return err + if err = unarchiver.Unarchive(currentArchivePath.archiveRealPath, archiveDestinationPath); err != nil { + return fmt.Errorf("unable to unarchive nested file: %w", err) } - unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver) - if !ok { - return ErrSkipPath - } - - if err = unarchiver.Unarchive(currentArchivePath.archiveRealPath, archiveRealPath); err != nil { - return err - } - - d, err := newFromDirectoryWithoutIndex(archiveRealPath, "") + d, err := newFromDirectoryWithoutIndex(archiveDestinationPath, "") if err != nil { return err } if err = d.buildIndex(); err != nil { - return err + return fmt.Errorf("unable to build index of archive: %w", err) } for _, archive := range d.indexer.archivePaths { archivesToIndex = append(archivesToIndex, archiveAccessPath{ realPath: currentArchivePath.realPath, - accessPath: strings.Replace(archive, archiveRealPath, currentArchivePath.accessPath, 1), - archiveDepth: currentArchivePath.archiveDepth + 1, + accessPath: strings.Replace(archive, archiveDestinationPath, currentArchivePath.accessPath, 1), archiveRealPath: archive, + archiveDepth: currentArchivePath.archiveDepth + 1, }) } d.chroot = r.chroot d.realPath = currentArchivePath.realPath d.accessPath = currentArchivePath.accessPath - d.tempDir = archiveRealPath + d.archiveRealPath = archiveDestinationPath r.archives = append(r.archives, &d.filetreeResolver) } diff --git a/syft/internal/fileresolver/filetree_resolver.go b/syft/internal/fileresolver/filetree_resolver.go index b8126bfd4..57b405955 100644 --- a/syft/internal/fileresolver/filetree_resolver.go +++ b/syft/internal/fileresolver/filetree_resolver.go @@ -21,10 +21,10 @@ type filetreeResolver struct { index filetree.IndexReader searchContext filetree.Searcher - realPath string - accessPath string - tempDir string - archives []*filetreeResolver + realPath string + accessPath string + archiveRealPath string + archives []*filetreeResolver } func (r *filetreeResolver) requestPath(userPath string) (string, error) { @@ -33,8 +33,8 @@ func (r *filetreeResolver) requestPath(userPath string) (string, error) { return "", err } - if r.accessPath != "" && r.tempDir != "" { - return strings.Replace(requestPath, r.accessPath, r.tempDir, 1), nil + if r.accessPath != "" && r.archiveRealPath != "" { + return strings.Replace(requestPath, r.accessPath, r.archiveRealPath, 1), nil } return requestPath, nil @@ -42,15 +42,19 @@ func (r *filetreeResolver) requestPath(userPath string) (string, error) { // responsePath takes a path from the underlying fs domain and converts it to a path that is relative to the root of the file resolver. func (r filetreeResolver) responsePath(path string) string { - if r.tempDir != "" && strings.HasPrefix(path, r.tempDir) { + if r.archiveRealPath != "" && strings.HasPrefix(path, r.archiveRealPath) { path = r.realPath } + return r.chroot.ToChrootPath(path) } func (r filetreeResolver) responseAccessPath(path string) string { - responsePath := strings.Replace(path, r.tempDir, r.accessPath, 1) - return r.chroot.ToChrootPath(responsePath) + if r.accessPath != "" && r.archiveRealPath != "" { + path = strings.Replace(path, r.archiveRealPath, r.accessPath, 1) + } + + return r.chroot.ToChrootPath(path) } // HasPath indicates if the given path exists in the underlying source. @@ -138,7 +142,11 @@ func (r filetreeResolver) requestGlob(pattern string) (string, error) { return "", err } - return strings.Replace(nativeGlob, r.accessPath, r.tempDir, 1), nil + if r.accessPath != "" && r.archiveRealPath != "" { + return strings.Replace(nativeGlob, r.accessPath, r.archiveRealPath, 1), nil + } + + return nativeGlob, nil } // FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image. diff --git a/syft/internal/fileresolver/filetree_resolver_test.go b/syft/internal/fileresolver/filetree_resolver_test.go index 97de6d2b5..490f4e88b 100644 --- a/syft/internal/fileresolver/filetree_resolver_test.go +++ b/syft/internal/fileresolver/filetree_resolver_test.go @@ -1664,6 +1664,7 @@ func TestFileResolver_AllLocations_errorOnDirRequest(t *testing.T) { } func TestFileResolver_AllLocations(t *testing.T) { + defer goleak.VerifyNone(t) // Verify both the parent and the file itself are indexed filePath := "./test-fixtures/system_paths/target/home/place" parentPath, err := absoluteSymlinkFreePathToParent(filePath) @@ -1685,11 +1686,10 @@ func TestFileResolver_AllLocations(t *testing.T) { sort.Strings(pathsList) assert.ElementsMatchf(t, expected, pathsList, "expected all paths to be indexed, but found different paths: \n%s", cmp.Diff(expected, paths.List())) - - goleak.VerifyNone(t) } func Test_FileResolver_AllLocationsDoesNotLeakGoRoutine(t *testing.T) { + defer goleak.VerifyNone(t) filePath := "./test-fixtures/system_paths/target/home/place" parentPath, err := absoluteSymlinkFreePathToParent(filePath) require.NoError(t, err) @@ -1703,6 +1703,4 @@ func Test_FileResolver_AllLocationsDoesNotLeakGoRoutine(t *testing.T) { break } cancel() - - goleak.VerifyNone(t) }