github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/python/cataloger_test.go (about) 1 package python 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 8 "github.com/anchore/syft/syft/file" 9 "github.com/anchore/syft/syft/pkg" 10 "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" 11 ) 12 13 func Test_PackageCataloger(t *testing.T) { 14 tests := []struct { 15 name string 16 fixtures []string 17 expectedPackage pkg.Package 18 }{ 19 { 20 name: "egg-file-no-version", 21 fixtures: []string{"test-fixtures/no-version-py3.8.egg-info"}, 22 expectedPackage: pkg.Package{ 23 Name: "no-version", 24 PURL: "pkg:pypi/no-version", 25 Type: pkg.PythonPkg, 26 Language: pkg.Python, 27 FoundBy: "python-package-cataloger", 28 MetadataType: pkg.PythonPackageMetadataType, 29 Metadata: pkg.PythonPackageMetadata{ 30 Name: "no-version", 31 SitePackagesRootPath: "test-fixtures", 32 }, 33 }, 34 }, 35 { 36 name: "egg-info directory", 37 fixtures: []string{ 38 "test-fixtures/egg-info/PKG-INFO", 39 "test-fixtures/egg-info/RECORD", 40 "test-fixtures/egg-info/top_level.txt", 41 }, 42 expectedPackage: pkg.Package{ 43 Name: "requests", 44 Version: "2.22.0", 45 PURL: "pkg:pypi/requests@2.22.0", 46 Type: pkg.PythonPkg, 47 Language: pkg.Python, 48 Licenses: pkg.NewLicenseSet( 49 pkg.NewLicenseFromLocations("Apache 2.0", file.NewLocation("test-fixtures/egg-info/PKG-INFO")), 50 ), 51 FoundBy: "python-package-cataloger", 52 MetadataType: pkg.PythonPackageMetadataType, 53 Metadata: pkg.PythonPackageMetadata{ 54 Name: "requests", 55 Version: "2.22.0", 56 Platform: "UNKNOWN", 57 Author: "Kenneth Reitz", 58 AuthorEmail: "me@kennethreitz.org", 59 SitePackagesRootPath: "test-fixtures", 60 Files: []pkg.PythonFileRecord{ 61 {Path: "requests-2.22.0.dist-info/INSTALLER", Digest: &pkg.PythonFileDigest{"sha256", "zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg"}, Size: "4"}, 62 {Path: "requests/__init__.py", Digest: &pkg.PythonFileDigest{"sha256", "PnKCgjcTq44LaAMzB-7--B2FdewRrE8F_vjZeaG9NhA"}, Size: "3921"}, 63 {Path: "requests/__pycache__/__version__.cpython-38.pyc"}, 64 {Path: "requests/__pycache__/utils.cpython-38.pyc"}, 65 {Path: "requests/__version__.py", Digest: &pkg.PythonFileDigest{"sha256", "Bm-GFstQaFezsFlnmEMrJDe8JNROz9n2XXYtODdvjjc"}, Size: "436"}, 66 {Path: "requests/utils.py", Digest: &pkg.PythonFileDigest{"sha256", "LtPJ1db6mJff2TJSJWKi7rBpzjPS3mSOrjC9zRhoD3A"}, Size: "30049"}, 67 }, 68 TopLevelPackages: []string{"requests"}, 69 }, 70 }, 71 }, 72 { 73 name: "dist-info directory", 74 fixtures: []string{ 75 "test-fixtures/dist-info/METADATA", 76 "test-fixtures/dist-info/RECORD", 77 "test-fixtures/dist-info/top_level.txt", 78 "test-fixtures/dist-info/direct_url.json", 79 }, 80 expectedPackage: pkg.Package{ 81 Name: "Pygments", 82 Version: "2.6.1", 83 PURL: "pkg:pypi/Pygments@2.6.1?vcs_url=git+https://github.com/python-test/test.git%40aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 84 Type: pkg.PythonPkg, 85 Language: pkg.Python, 86 Licenses: pkg.NewLicenseSet( 87 pkg.NewLicenseFromLocations("BSD License", file.NewLocation("test-fixtures/dist-info/METADATA")), 88 ), 89 FoundBy: "python-package-cataloger", 90 MetadataType: pkg.PythonPackageMetadataType, 91 Metadata: pkg.PythonPackageMetadata{ 92 Name: "Pygments", 93 Version: "2.6.1", 94 Platform: "any", 95 Author: "Georg Brandl", 96 AuthorEmail: "georg@python.org", 97 SitePackagesRootPath: "test-fixtures", 98 Files: []pkg.PythonFileRecord{ 99 {Path: "../../../bin/pygmentize", Digest: &pkg.PythonFileDigest{"sha256", "dDhv_U2jiCpmFQwIRHpFRLAHUO4R1jIJPEvT_QYTFp8"}, Size: "220"}, 100 {Path: "Pygments-2.6.1.dist-info/AUTHORS", Digest: &pkg.PythonFileDigest{"sha256", "PVpa2_Oku6BGuiUvutvuPnWGpzxqFy2I8-NIrqCvqUY"}, Size: "8449"}, 101 {Path: "Pygments-2.6.1.dist-info/RECORD"}, 102 {Path: "pygments/__pycache__/__init__.cpython-38.pyc"}, 103 {Path: "pygments/util.py", Digest: &pkg.PythonFileDigest{"sha256", "586xXHiJGGZxqk5PMBu3vBhE68DLuAe5MBARWrSPGxA"}, Size: "10778"}, 104 105 {Path: "pygments/x_util.py", Digest: &pkg.PythonFileDigest{"sha256", "qpzzsOW31KT955agi-7NS--90I0iNiJCyLJQnRCHgKI="}, Size: "10778"}, 106 }, 107 TopLevelPackages: []string{"pygments", "something_else"}, 108 DirectURLOrigin: &pkg.PythonDirectURLOriginInfo{URL: "https://github.com/python-test/test.git", VCS: "git", CommitID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, 109 }, 110 }, 111 }, 112 { 113 name: "malformed-record", 114 fixtures: []string{ 115 "test-fixtures/malformed-record/dist-info/METADATA", 116 "test-fixtures/malformed-record/dist-info/RECORD", 117 }, 118 expectedPackage: pkg.Package{ 119 Name: "Pygments", 120 Version: "2.6.1", 121 PURL: "pkg:pypi/Pygments@2.6.1", 122 Type: pkg.PythonPkg, 123 Language: pkg.Python, 124 Licenses: pkg.NewLicenseSet( 125 pkg.NewLicenseFromLocations("BSD License", file.NewLocation("test-fixtures/malformed-record/dist-info/METADATA")), 126 ), 127 FoundBy: "python-package-cataloger", 128 MetadataType: pkg.PythonPackageMetadataType, 129 Metadata: pkg.PythonPackageMetadata{ 130 Name: "Pygments", 131 Version: "2.6.1", 132 Platform: "any", 133 Author: "Georg Brandl", 134 AuthorEmail: "georg@python.org", 135 SitePackagesRootPath: "test-fixtures/malformed-record", 136 Files: []pkg.PythonFileRecord{ 137 {Path: "flask/json/tag.py", Digest: &pkg.PythonFileDigest{"sha256", "9ehzrmt5k7hxf7ZEK0NOs3swvQyU9fWNe-pnYe69N60"}, Size: "8223"}, 138 {Path: "../../Scripts/flask.exe", Digest: &pkg.PythonFileDigest{"sha256", "mPrbVeZCDX20himZ_bRai1nCs_tgr7jHIOGZlcgn-T4"}, Size: "93063"}, 139 {Path: "../../Scripts/flask.exe", Size: "89470", Digest: &pkg.PythonFileDigest{"sha256", "jvqh4N3qOqXLlq40i6ZOLCY9tAOwfwdzIpLDYhRjoqQ"}}, 140 {Path: "Flask-1.0.2.dist-info/INSTALLER", Size: "4", Digest: &pkg.PythonFileDigest{"sha256", "zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg"}}, 141 }, 142 }, 143 }, 144 }, 145 { 146 // in cases where the metadata file is available and the record is not we should still record there is a package 147 // additionally empty top_level.txt files should not result in an error 148 name: "partial dist-info directory", 149 fixtures: []string{"test-fixtures/partial.dist-info/METADATA"}, 150 expectedPackage: pkg.Package{ 151 Name: "Pygments", 152 Version: "2.6.1", 153 PURL: "pkg:pypi/Pygments@2.6.1", 154 Type: pkg.PythonPkg, 155 Language: pkg.Python, 156 Licenses: pkg.NewLicenseSet( 157 pkg.NewLicenseFromLocations("BSD License", file.NewLocation("test-fixtures/partial.dist-info/METADATA")), 158 ), 159 FoundBy: "python-package-cataloger", 160 MetadataType: pkg.PythonPackageMetadataType, 161 Metadata: pkg.PythonPackageMetadata{ 162 Name: "Pygments", 163 Version: "2.6.1", 164 Platform: "any", 165 Author: "Georg Brandl", 166 AuthorEmail: "georg@python.org", 167 SitePackagesRootPath: "test-fixtures", 168 }, 169 }, 170 }, 171 { 172 name: "egg-info regular file", 173 fixtures: []string{"test-fixtures/test.egg-info"}, 174 expectedPackage: pkg.Package{ 175 Name: "requests", 176 Version: "2.22.0", 177 PURL: "pkg:pypi/requests@2.22.0", 178 Type: pkg.PythonPkg, 179 Language: pkg.Python, 180 Licenses: pkg.NewLicenseSet( 181 pkg.NewLicenseFromLocations("Apache 2.0", file.NewLocation("test-fixtures/test.egg-info")), 182 ), 183 FoundBy: "python-package-cataloger", 184 MetadataType: pkg.PythonPackageMetadataType, 185 Metadata: pkg.PythonPackageMetadata{ 186 Name: "requests", 187 Version: "2.22.0", 188 Platform: "UNKNOWN", 189 Author: "Kenneth Reitz", 190 AuthorEmail: "me@kennethreitz.org", 191 SitePackagesRootPath: "test-fixtures", 192 }, 193 }, 194 }, 195 } 196 197 for _, test := range tests { 198 t.Run(test.name, func(t *testing.T) { 199 resolver := file.NewMockResolverForPaths(test.fixtures...) 200 201 locations, err := resolver.FilesByPath(test.fixtures...) 202 require.NoError(t, err) 203 204 test.expectedPackage.Locations = file.NewLocationSet(locations...) 205 206 pkgtest.NewCatalogTester(). 207 WithResolver(resolver). 208 Expects([]pkg.Package{test.expectedPackage}, nil). 209 TestCataloger(t, NewPythonPackageCataloger()) 210 }) 211 } 212 } 213 214 func Test_PackageCataloger_IgnorePackage(t *testing.T) { 215 tests := []struct { 216 MetadataFixture string 217 }{ 218 { 219 MetadataFixture: "test-fixtures/Python-2.7.egg-info", 220 }, 221 { 222 MetadataFixture: "test-fixtures/empty-1.0.0-py3.8.egg-info", 223 }, 224 } 225 226 for _, test := range tests { 227 t.Run(test.MetadataFixture, func(t *testing.T) { 228 resolver := file.NewMockResolverForPaths(test.MetadataFixture) 229 230 actual, _, err := NewPythonPackageCataloger().Catalog(resolver) 231 require.NoError(t, err) 232 233 if len(actual) != 0 { 234 t.Fatalf("Expected 0 packages but found: %d", len(actual)) 235 } 236 }) 237 } 238 } 239 240 func Test_IndexCataloger_Globs(t *testing.T) { 241 tests := []struct { 242 name string 243 fixture string 244 expected []string 245 }{ 246 { 247 name: "obtain index files", 248 fixture: "test-fixtures/glob-paths", 249 expected: []string{ 250 "src/requirements.txt", 251 "src/extra-requirements.txt", 252 "src/requirements-dev.txt", 253 "src/1-requirements-dev.txt", 254 "src/setup.py", 255 "src/poetry.lock", 256 "src/Pipfile.lock", 257 }, 258 }, 259 } 260 261 for _, test := range tests { 262 t.Run(test.name, func(t *testing.T) { 263 pkgtest.NewCatalogTester(). 264 FromDirectory(t, test.fixture). 265 ExpectsResolverContentQueries(test.expected). 266 TestCataloger(t, NewPythonIndexCataloger(DefaultCatalogerConfig())) 267 }) 268 } 269 } 270 271 func Test_PackageCataloger_Globs(t *testing.T) { 272 tests := []struct { 273 name string 274 fixture string 275 expected []string 276 }{ 277 { 278 name: "obtain index files", 279 fixture: "test-fixtures/glob-paths", 280 expected: []string{ 281 "site-packages/x.dist-info/METADATA", 282 "site-packages/y.egg-info/PKG-INFO", 283 "site-packages/z.egg-info", 284 }, 285 }, 286 } 287 288 for _, test := range tests { 289 t.Run(test.name, func(t *testing.T) { 290 pkgtest.NewCatalogTester(). 291 FromDirectory(t, test.fixture). 292 ExpectsResolverContentQueries(test.expected). 293 TestCataloger(t, NewPythonPackageCataloger()) 294 }) 295 } 296 }