github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/file/cataloger/filedigest/cataloger_test.go (about) 1 package filedigest 2 3 import ( 4 "crypto" 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 stereoscopeFile "github.com/anchore/stereoscope/pkg/file" 15 "github.com/anchore/stereoscope/pkg/imagetest" 16 intFile "github.com/anchore/syft/internal/file" 17 "github.com/anchore/syft/syft/file" 18 "github.com/anchore/syft/syft/source" 19 ) 20 21 func testDigests(t testing.TB, root string, files []string, hashes ...crypto.Hash) map[file.Coordinates][]file.Digest { 22 digests := make(map[file.Coordinates][]file.Digest) 23 24 for _, f := range files { 25 fh, err := os.Open(filepath.Join(root, f)) 26 if err != nil { 27 t.Fatalf("could not open %q : %+v", f, err) 28 } 29 b, err := io.ReadAll(fh) 30 if err != nil { 31 t.Fatalf("could not read %q : %+v", f, err) 32 } 33 34 if len(b) == 0 { 35 // we don't keep digests for empty files 36 digests[file.NewLocation(f).Coordinates] = []file.Digest{} 37 continue 38 } 39 40 for _, hash := range hashes { 41 h := hash.New() 42 h.Write(b) 43 digests[file.NewLocation(f).Coordinates] = append(digests[file.NewLocation(f).Coordinates], file.Digest{ 44 Algorithm: intFile.CleanDigestAlgorithmName(hash.String()), 45 Value: fmt.Sprintf("%x", h.Sum(nil)), 46 }) 47 } 48 } 49 50 return digests 51 } 52 53 func TestDigestsCataloger(t *testing.T) { 54 55 tests := []struct { 56 name string 57 digests []crypto.Hash 58 files []string 59 expected map[file.Coordinates][]file.Digest 60 }{ 61 { 62 name: "md5", 63 digests: []crypto.Hash{crypto.MD5}, 64 files: []string{"test-fixtures/last/empty/empty", "test-fixtures/last/path.txt"}, 65 expected: testDigests(t, "test-fixtures/last", []string{"empty/empty", "path.txt"}, crypto.MD5), 66 }, 67 { 68 name: "md5-sha1-sha256", 69 digests: []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.SHA256}, 70 files: []string{"test-fixtures/last/empty/empty", "test-fixtures/last/path.txt"}, 71 expected: testDigests(t, "test-fixtures/last", []string{"empty/empty", "path.txt"}, crypto.MD5, crypto.SHA1, crypto.SHA256), 72 }, 73 } 74 75 for _, test := range tests { 76 t.Run(test.name, func(t *testing.T) { 77 c := NewCataloger(test.digests) 78 79 src, err := source.NewFromDirectoryPath("test-fixtures/last/") 80 require.NoError(t, err) 81 82 resolver, err := src.FileResolver(source.SquashedScope) 83 require.NoError(t, err) 84 85 actual, err := c.Catalog(resolver) 86 require.NoError(t, err) 87 88 assert.Equal(t, test.expected, actual, "mismatched digests") 89 }) 90 } 91 } 92 93 func TestDigestsCataloger_MixFileTypes(t *testing.T) { 94 testImage := "image-file-type-mix" 95 96 img := imagetest.GetFixtureImage(t, "docker-archive", testImage) 97 98 src, err := source.NewFromStereoscopeImageObject(img, testImage, nil) 99 if err != nil { 100 t.Fatalf("could not create source: %+v", err) 101 } 102 103 resolver, err := src.FileResolver(source.SquashedScope) 104 if err != nil { 105 t.Fatalf("could not create resolver: %+v", err) 106 } 107 108 tests := []struct { 109 path string 110 expected string 111 }{ 112 { 113 path: "/file-1.txt", 114 expected: "888c139e550867814eb7c33b84d76e4d", 115 }, 116 // this is difficult to reproduce in a cross-platform way 117 //{ 118 // path: "/hardlink-1", 119 //}, 120 { 121 path: "/symlink-1", 122 }, 123 { 124 path: "/char-device-1", 125 }, 126 { 127 path: "/block-device-1", 128 }, 129 { 130 path: "/fifo-1", 131 }, 132 { 133 path: "/bin", 134 }, 135 } 136 137 for _, test := range tests { 138 t.Run(test.path, func(t *testing.T) { 139 c := NewCataloger([]crypto.Hash{crypto.MD5}) 140 141 actual, err := c.Catalog(resolver) 142 if err != nil { 143 t.Fatalf("could not catalog: %+v", err) 144 } 145 146 _, ref, err := img.SquashedTree().File(stereoscopeFile.Path(test.path)) 147 if err != nil { 148 t.Fatalf("unable to get file=%q : %+v", test.path, err) 149 } 150 l := file.NewLocationFromImage(test.path, *ref.Reference, img) 151 152 if len(actual[l.Coordinates]) == 0 { 153 if test.expected != "" { 154 t.Fatalf("no digest found, but expected one") 155 } 156 157 } else { 158 assert.Equal(t, actual[l.Coordinates][0].Value, test.expected, "mismatched digests") 159 } 160 }) 161 } 162 }