github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/python/parse_pipfile_lock_test.go (about) 1 package python 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/anchore/syft/syft/artifact" 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 TestParsePipFileLock(t *testing.T) { 14 15 fixture := "test-fixtures/pipfile-lock/Pipfile.lock" 16 locations := file.NewLocationSet(file.NewLocation(fixture)) 17 expectedPkgs := []pkg.Package{ 18 { 19 Name: "aio-pika", 20 Version: "6.8.0", 21 PURL: "pkg:pypi/aio-pika@6.8.0", 22 Locations: locations, 23 Language: pkg.Python, 24 Type: pkg.PythonPkg, 25 Metadata: pkg.PythonPipfileLockEntry{ 26 Index: "https://pypi.org/simple", 27 Hashes: []string{ 28 "sha256:1d4305a5f78af3857310b4fe48348cdcf6c097e0e275ea88c2cd08570531a369", 29 "sha256:e69afef8695f47c5d107bbdba21bdb845d5c249acb3be53ef5c2d497b02657c0", 30 }}, 31 }, 32 { 33 Name: "aiodns", 34 Version: "2.0.0", 35 PURL: "pkg:pypi/aiodns@2.0.0", 36 Locations: locations, 37 Language: pkg.Python, 38 Type: pkg.PythonPkg, 39 Metadata: pkg.PythonPipfileLockEntry{ 40 Index: "https://test.pypi.org/simple", 41 Hashes: []string{ 42 "sha256:815fdef4607474295d68da46978a54481dd1e7be153c7d60f9e72773cd38d77d", 43 "sha256:aaa5ac584f40fe778013df0aa6544bf157799bd3f608364b451840ed2c8688de", 44 }, 45 }, 46 }, 47 { 48 Name: "aiohttp", 49 Version: "3.7.4.post0", 50 PURL: "pkg:pypi/aiohttp@3.7.4.post0", 51 Locations: locations, 52 Language: pkg.Python, 53 Type: pkg.PythonPkg, 54 Metadata: pkg.PythonPipfileLockEntry{ 55 Index: "https://pypi.org/simple", 56 Hashes: []string{ 57 "sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe", 58 "sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe", 59 }, 60 }, 61 }, 62 { 63 Name: "aiohttp-jinja2", 64 Version: "1.4.2", 65 PURL: "pkg:pypi/aiohttp-jinja2@1.4.2", 66 Locations: locations, 67 Language: pkg.Python, 68 Type: pkg.PythonPkg, 69 Metadata: pkg.PythonPipfileLockEntry{ 70 Index: "https://pypi.org/simple", 71 Hashes: []string{ 72 "sha256:860da7582efa866744bad5883947557d0f82e457d69903ea65d666b66f8a69ca", 73 "sha256:9c22a0e48e3b277fc145c67dd8c3b8f609dab36bce9eb337f70dfe716663c9a0", 74 }, 75 }, 76 }, 77 } 78 79 // TODO: relationships are not under test 80 var expectedRelationships []artifact.Relationship 81 82 pipfileLockParser := newPipfileLockParser(DefaultCatalogerConfig()) 83 pkgtest.TestFileParser(t, fixture, pipfileLockParser.parsePipfileLock, expectedPkgs, expectedRelationships) 84 } 85 86 func TestParsePipfileLockWithLicenseEnrichment(t *testing.T) { 87 ctx := context.TODO() 88 fixture := "test-fixtures/pypi-remote/Pipfile.lock" 89 locations := file.NewLocationSet(file.NewLocation(fixture)) 90 mux, url, teardown := setupPypiRegistry() 91 defer teardown() 92 tests := []struct { 93 name string 94 fixture string 95 config CatalogerConfig 96 requestHandlers []handlerPath 97 expectedPackages []pkg.Package 98 }{ 99 { 100 name: "search remote licenses returns the expected licenses when search is set to true", 101 config: CatalogerConfig{SearchRemoteLicenses: true}, 102 requestHandlers: []handlerPath{ 103 { 104 path: "/certifi/2025.10.5/json", 105 handler: generateMockPypiRegistryHandler("test-fixtures/pypi-remote/registry_response.json"), 106 }, 107 }, 108 expectedPackages: []pkg.Package{ 109 { 110 Name: "certifi", 111 Version: "2025.10.5", 112 Locations: locations, 113 PURL: "pkg:pypi/certifi@2025.10.5", 114 Licenses: pkg.NewLicenseSet(pkg.NewLicenseWithContext(ctx, "MPL-2.0")), 115 Language: pkg.Python, 116 Type: pkg.PythonPkg, 117 Metadata: pkg.PythonPipfileLockEntry{ 118 Index: "https://pypi.org/simple", 119 Hashes: []string{ 120 "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", 121 "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", 122 }, 123 }, 124 }, 125 }, 126 }, 127 } 128 for _, tc := range tests { 129 t.Run(tc.name, func(t *testing.T) { 130 // set up the mock server 131 for _, handler := range tc.requestHandlers { 132 mux.HandleFunc(handler.path, handler.handler) 133 } 134 tc.config.PypiBaseURL = url 135 pipfileLockParser := newPipfileLockParser(tc.config) 136 pkgtest.TestFileParser(t, fixture, pipfileLockParser.parsePipfileLock, tc.expectedPackages, nil) 137 }) 138 } 139 } 140 141 func Test_corruptPipfileLock(t *testing.T) { 142 pipfileLockParser := newPipfileLockParser(DefaultCatalogerConfig()) 143 pkgtest.NewCatalogTester(). 144 FromFile(t, "test-fixtures/glob-paths/src/Pipfile.lock"). 145 WithError(). 146 TestParser(t, pipfileLockParser.parsePipfileLock) 147 }