fix: duplicate file in tar archive causes read to fail (#1445)

This commit is contained in:
Keith Zantow 2023-01-10 14:55:02 -05:00 committed by GitHub
parent e480443c8c
commit 725529f43f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 4 deletions

View File

@ -301,6 +301,12 @@ func fileAnalysisPath(path string) (string, func()) {
// unarchived. // unarchived.
envelopedUnarchiver, err := archiver.ByExtension(path) envelopedUnarchiver, err := archiver.ByExtension(path)
if unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver); err == nil && ok { if unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver); err == nil && ok {
if tar, ok := unarchiver.(*archiver.Tar); ok {
// when tar files are extracted, if there are multiple entries at the same
// location, the last entry wins
// NOTE: this currently does not display any messages if an overwrite happens
tar.OverwriteExisting = true
}
unarchivedPath, tmpCleanup, err := unarchiveToTmp(path, unarchiver) unarchivedPath, tmpCleanup, err := unarchiveToTmp(path, unarchiver)
if err != nil { if err != nil {
log.Warnf("file could not be unarchived: %+v", err) log.Warnf("file could not be unarchived: %+v", err)

View File

@ -4,6 +4,7 @@
package source package source
import ( import (
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@ -252,6 +253,8 @@ func TestNewFromFile_WithArchive(t *testing.T) {
expString string expString string
inputPaths []string inputPaths []string
expRefs int expRefs int
layer2 bool
contents string
}{ }{
{ {
desc: "path detected", desc: "path detected",
@ -259,10 +262,18 @@ func TestNewFromFile_WithArchive(t *testing.T) {
inputPaths: []string{"/.vimrc"}, inputPaths: []string{"/.vimrc"},
expRefs: 1, expRefs: 1,
}, },
{
desc: "lest entry for duplicate paths",
input: "test-fixtures/path-detected",
inputPaths: []string{"/.vimrc"},
expRefs: 1,
layer2: true,
contents: "Another .vimrc file",
},
} }
for _, test := range testCases { for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
archivePath := setupArchiveTest(t, test.input) archivePath := setupArchiveTest(t, test.input, test.layer2)
src, cleanup := NewFromFile(archivePath) src, cleanup := NewFromFile(archivePath)
if cleanup != nil { if cleanup != nil {
@ -279,6 +290,16 @@ func TestNewFromFile_WithArchive(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, refs, test.expRefs) assert.Len(t, refs, test.expRefs)
if test.contents != "" {
reader, err := resolver.FileContentsByLocation(refs[0])
require.NoError(t, err)
data, err := io.ReadAll(reader)
require.NoError(t, err)
assert.Equal(t, test.contents, string(data))
}
}) })
} }
} }
@ -716,7 +737,7 @@ func Test_crossPlatformExclusions(t *testing.T) {
} }
// createArchive creates a new archive file at destinationArchivePath based on the directory found at sourceDirPath. // createArchive creates a new archive file at destinationArchivePath based on the directory found at sourceDirPath.
func createArchive(t testing.TB, sourceDirPath, destinationArchivePath string) { func createArchive(t testing.TB, sourceDirPath, destinationArchivePath string, layer2 bool) {
t.Helper() t.Helper()
cwd, err := os.Getwd() cwd, err := os.Getwd()
@ -749,13 +770,21 @@ func createArchive(t testing.TB, sourceDirPath, destinationArchivePath string) {
} }
} }
if layer2 {
cmd = exec.Command("tar", "-rvf", destinationArchivePath, ".")
cmd.Dir = filepath.Join(cwd, "test-fixtures", path.Base(sourceDirPath+"-2"))
if err := cmd.Start(); err != nil {
t.Fatalf("unable to start tar appending fixture script: %+v", err)
}
_ = cmd.Wait()
}
} }
// setupArchiveTest encapsulates common test setup work for tar file tests. It returns a cleanup function, // setupArchiveTest encapsulates common test setup work for tar file tests. It returns a cleanup function,
// which should be called (typically deferred) by the caller, the path of the created tar archive, and an error, // which should be called (typically deferred) by the caller, the path of the created tar archive, and an error,
// which should trigger a fatal test failure in the consuming test. The returned cleanup function will never be nil // which should trigger a fatal test failure in the consuming test. The returned cleanup function will never be nil
// (even if there's an error), and it should always be called. // (even if there's an error), and it should always be called.
func setupArchiveTest(t testing.TB, sourceDirPath string) string { func setupArchiveTest(t testing.TB, sourceDirPath string, layer2 bool) string {
t.Helper() t.Helper()
archivePrefix, err := ioutil.TempFile("", "syft-archive-TEST-") archivePrefix, err := ioutil.TempFile("", "syft-archive-TEST-")
@ -771,7 +800,7 @@ func setupArchiveTest(t testing.TB, sourceDirPath string) string {
destinationArchiveFilePath := archivePrefix.Name() + ".tar" destinationArchiveFilePath := archivePrefix.Name() + ".tar"
t.Logf("archive path: %s", destinationArchiveFilePath) t.Logf("archive path: %s", destinationArchiveFilePath)
createArchive(t, sourceDirPath, destinationArchiveFilePath) createArchive(t, sourceDirPath, destinationArchiveFilePath, layer2)
t.Cleanup( t.Cleanup(
assertNoError(t, assertNoError(t,

View File

@ -0,0 +1 @@
Another .vimrc file