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  }