github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/python/parse_pipfile_lock.go (about) 1 package python 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "io" 8 "strings" 9 10 "github.com/anchore/syft/syft/artifact" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/pkg" 13 "github.com/anchore/syft/syft/pkg/cataloger/generic" 14 ) 15 16 type pipfileLock struct { 17 Meta struct { 18 Hash struct { 19 Sha256 string `json:"sha256"` 20 } `json:"hash"` 21 PipfileSpec int `json:"pipfile-spec"` 22 Requires struct { 23 PythonVersion string `json:"python_version"` 24 } `json:"requires"` 25 Sources []struct { 26 Name string `json:"name"` 27 URL string `json:"url"` 28 VerifySsl bool `json:"verify_ssl"` 29 } `json:"sources"` 30 } `json:"_meta"` 31 Default map[string]Dependency `json:"default"` 32 Develop map[string]Dependency `json:"develop"` 33 } 34 35 type Dependency struct { 36 Hashes []string `json:"hashes"` 37 Version string `json:"version"` 38 Index string `json:"index"` 39 } 40 41 var _ generic.Parser = parsePipfileLock 42 43 // parsePipfileLock is a parser function for Pipfile.lock contents, returning "Default" python packages discovered. 44 func parsePipfileLock(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 45 pkgs := make([]pkg.Package, 0) 46 dec := json.NewDecoder(reader) 47 48 for { 49 var lock pipfileLock 50 if err := dec.Decode(&lock); errors.Is(err, io.EOF) { 51 break 52 } else if err != nil { 53 return nil, nil, fmt.Errorf("failed to parse Pipfile.lock file: %w", err) 54 } 55 sourcesMap := map[string]string{} 56 for _, source := range lock.Meta.Sources { 57 sourcesMap[source.Name] = source.URL 58 } 59 for name, pkgMeta := range lock.Default { 60 var index string 61 if pkgMeta.Index != "" { 62 index = sourcesMap[pkgMeta.Index] 63 } else { 64 // https://pipenv.pypa.io/en/latest/advanced/#specifying-package-indexes 65 index = "https://pypi.org/simple" 66 } 67 version := strings.TrimPrefix(pkgMeta.Version, "==") 68 pkgs = append(pkgs, newPackageForIndexWithMetadata(name, version, pkg.PythonPipfileLockMetadata{Index: index, Hashes: pkgMeta.Hashes}, reader.Location)) 69 } 70 } 71 72 pkg.Sort(pkgs) 73 74 return pkgs, nil, nil 75 }