github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/internal/pe/pe_test.go (about) 1 package pe 2 3 import ( 4 "testing" 5 6 "github.com/google/go-cmp/cmp" 7 "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/require" 9 10 "github.com/anchore/stereoscope/pkg/imagetest" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/source" 13 "github.com/anchore/syft/syft/source/stereoscopesource" 14 ) 15 16 func Test_Read_DotNetDetection(t *testing.T) { 17 tests := []struct { 18 name string 19 fixture string 20 path string 21 wantVR map[string]string 22 wantCLR bool 23 wantErr require.ErrorAssertionFunc 24 }{ 25 { 26 name: "newtonsoft", 27 path: "/app/Newtonsoft.Json.dll", 28 fixture: "image-net8-app", 29 wantCLR: true, 30 wantVR: map[string]string{ 31 // the numbers are the field parse order, which helped for debugging and understanding corrupted fields 32 "Comments": "Json.NET is a popular high-performance JSON framework for .NET", // 1 33 "CompanyName": "Newtonsoft", // 2 34 "FileDescription": "Json.NET .NET 6.0", // 3 35 "FileVersion": "13.0.3.27908", // 4 36 "InternalName": "Newtonsoft.Json.dll", // 5 37 "LegalCopyright": "Copyright © James Newton-King 2008", // 6 38 "LegalTrademarks": "", // 7 (empty value actually exists in the string table) 39 "OriginalFilename": "Newtonsoft.Json.dll", // 8 40 "ProductName": "Json.NET", // 9 41 "ProductVersion": "13.0.3+0a2e291c0d9c0c7675d445703e51750363a549ef", // 10 42 "Assembly Version": "13.0.0.0", // 11 43 }, 44 }, 45 { 46 name: "humanizer", 47 path: "/app/Humanizer.dll", 48 fixture: "image-net8-app", 49 wantCLR: true, 50 wantVR: map[string]string{ 51 "Comments": "A micro-framework that turns your normal strings, type names, enum fields, date fields ETC into a human friendly format", 52 "CompanyName": "Mehdi Khalili, Claire Novotny", 53 "FileDescription": "Humanizer", 54 "FileVersion": "2.14.1.48190", 55 "InternalName": "Humanizer.dll", 56 "LegalCopyright": "Copyright © .NET Foundation and Contributors", 57 "OriginalFilename": "Humanizer.dll", 58 "ProductName": "Humanizer (net6.0)", 59 "ProductVersion": "2.14.1+3ebc38de58", 60 "Assembly Version": "2.14.0.0", 61 }, 62 wantErr: require.NoError, 63 }, 64 { 65 name: "dotnetapp", 66 path: "/app/dotnetapp.dll", 67 fixture: "image-net8-app", 68 wantCLR: true, 69 wantVR: map[string]string{ 70 "CompanyName": "dotnetapp", 71 "FileDescription": "dotnetapp", 72 "FileVersion": "1.0.0.0", 73 "InternalName": "dotnetapp.dll", 74 "LegalCopyright": " ", 75 "OriginalFilename": "dotnetapp.dll", 76 "ProductName": "dotnetapp", 77 "ProductVersion": "1.0.0", 78 "Assembly Version": "1.0.0.0", 79 }, 80 wantErr: require.NoError, 81 }, 82 { 83 name: "jruby", 84 path: "/app/jruby_windows_9_3_15_0.exe", 85 fixture: "image-net8-app", 86 wantCLR: false, // important! 87 wantVR: map[string]string{ 88 "CompanyName": "JRuby Dev Team", 89 "FileDescription": "JRuby", 90 "FileVersion": "9.3.15.0", 91 "InternalName": "jruby", 92 "LegalCopyright": "JRuby Dev Team", 93 "OriginalFilename": "jruby_windows-x32_9_3_15_0.exe", 94 "ProductName": "JRuby", 95 "ProductVersion": "9.3.15.0", 96 }, 97 wantErr: require.NoError, 98 }, 99 { 100 name: "single file deployment", 101 path: "/app/dotnetapp.exe", 102 fixture: "image-net8-app-single-file", 103 // single file deployment does not have CLR metadata embedded in the COM descriptor. Instead we need 104 // to look for evidence of the CLR in other resources directory names, specifically for "CLRDEBUGINFO". 105 wantCLR: true, 106 wantVR: map[string]string{ 107 "CompanyName": "dotnetapp", 108 "FileDescription": "dotnetapp", 109 "FileVersion": "1.0.0.0", 110 "InternalName": "dotnetapp.dll", 111 "LegalCopyright": " ", 112 "OriginalFilename": "dotnetapp.dll", 113 "ProductName": "dotnetapp", 114 "ProductVersion": "1.0.0", 115 "Assembly Version": "1.0.0.0", 116 }, 117 wantErr: require.NoError, 118 }, 119 } 120 121 for _, tt := range tests { 122 t.Run(tt.name, func(t *testing.T) { 123 if tt.wantErr == nil { 124 tt.wantErr = require.NoError 125 } 126 127 reader := fixtureFile(t, tt.fixture, tt.path) 128 129 got, err := Read(reader) 130 tt.wantErr(t, err) 131 if err != nil { 132 return 133 } 134 135 if d := cmp.Diff(tt.wantVR, got.VersionResources); d != "" { 136 t.Errorf("unexpected version resources (-want +got): %s", d) 137 } 138 139 assert.Equal(t, tt.wantCLR, got.CLR.HasEvidenceOfCLR()) 140 }) 141 } 142 } 143 144 func fixtureFile(t *testing.T, fixture, path string) file.LocationReadCloser { 145 img := imagetest.GetFixtureImage(t, "docker-archive", fixture) 146 147 s := stereoscopesource.New(img, stereoscopesource.ImageConfig{ 148 Reference: fixture, 149 }) 150 151 r, err := s.FileResolver(source.SquashedScope) 152 require.NoError(t, err) 153 154 locs, err := r.FilesByPath(path) 155 require.NoError(t, err) 156 157 require.Len(t, locs, 1) 158 loc := locs[0] 159 160 reader, err := r.FileContentsByLocation(loc) 161 require.NoError(t, err) 162 return file.NewLocationReadCloser(loc, reader) 163 }