github.com/anchore/syft@v1.38.2/syft/pkg/python.go (about) 1 package pkg 2 3 import ( 4 "sort" 5 6 "github.com/scylladb/go-set/strset" 7 ) 8 9 var _ FileOwner = (*PythonPackage)(nil) 10 11 // PythonPackage represents all captured data for a python egg or wheel package (specifically as outlined in 12 // the PyPA core metadata specification https://packaging.python.org/en/latest/specifications/core-metadata/). 13 // Historically these were defined in PEPs 345, 314, and 241, but have been superseded by PEP 566. This means that this 14 // struct can (partially) express at least versions 1.0, 1.1, 1.2, 2.1, 2.2, and 2.3 of the metadata format. 15 type PythonPackage struct { 16 // Name is the package name from the Name field in PKG-INFO or METADATA. 17 Name string `json:"name" mapstructure:"Name"` 18 // Version is the package version from the Version field in PKG-INFO or METADATA. 19 Version string `json:"version" mapstructure:"Version"` 20 // Author is the package author name from the Author field. 21 Author string `json:"author" mapstructure:"Author"` 22 // AuthorEmail is the package author's email address from the Author-Email field. 23 AuthorEmail string `json:"authorEmail" mapstructure:"AuthorEmail"` 24 // Platform indicates the target platform for the package (e.g., "any", "linux", "win32"). 25 Platform string `json:"platform" mapstructure:"Platform"` 26 // Files are the installed files listed in the RECORD file for wheels or installed-files.txt for eggs. 27 Files []PythonFileRecord `json:"files,omitempty"` 28 // SitePackagesRootPath is the root directory path containing the package (e.g., "/usr/lib/python3.9/site-packages"). 29 SitePackagesRootPath string `json:"sitePackagesRootPath"` 30 // TopLevelPackages are the top-level Python module names from top_level.txt file. 31 TopLevelPackages []string `json:"topLevelPackages,omitempty"` 32 // DirectURLOrigin contains VCS or direct URL installation information from direct_url.json. 33 DirectURLOrigin *PythonDirectURLOriginInfo `json:"directUrlOrigin,omitempty"` 34 // RequiresPython specifies the Python version requirement (e.g., ">=3.6"). 35 RequiresPython string `json:"requiresPython,omitempty" mapstructure:"RequiresPython"` 36 // RequiresDist lists the package dependencies with version specifiers from Requires-Dist fields. 37 RequiresDist []string `json:"requiresDist,omitempty" mapstructure:"RequiresDist"` 38 // ProvidesExtra lists optional feature names that can be installed via extras (e.g., "dev", "test"). 39 ProvidesExtra []string `json:"providesExtra,omitempty" mapstructure:"ProvidesExtra"` 40 } 41 42 // PythonFileDigest represents the file metadata for a single file attributed to a python package. 43 type PythonFileDigest struct { 44 // Algorithm is the hash algorithm used (e.g., "sha256"). 45 Algorithm string `json:"algorithm"` 46 // Value is the hex-encoded hash digest value. 47 Value string `json:"value"` 48 } 49 50 // PythonFileRecord represents a single entry within a RECORD file for a python wheel or egg package 51 type PythonFileRecord struct { 52 // Path is the installed file path from the RECORD file. 53 Path string `json:"path"` 54 // Digest contains the hash algorithm and value for file integrity verification. 55 Digest *PythonFileDigest `json:"digest,omitempty"` 56 // Size is the file size in bytes as a string. 57 Size string `json:"size,omitempty"` 58 } 59 60 // PythonDirectURLOriginInfo represents installation source metadata from direct_url.json for packages installed from VCS or direct URLs. 61 type PythonDirectURLOriginInfo struct { 62 // URL is the source URL from which the package was installed. 63 URL string `json:"url"` 64 // CommitID is the VCS commit hash if installed from version control. 65 CommitID string `json:"commitId,omitempty"` 66 // VCS is the version control system type (e.g., "git", "hg"). 67 VCS string `json:"vcs,omitempty"` 68 } 69 70 func (m PythonPackage) OwnedFiles() (result []string) { 71 s := strset.New() 72 for _, f := range m.Files { 73 if f.Path != "" { 74 s.Add(f.Path) 75 } 76 } 77 result = s.List() 78 sort.Strings(result) 79 return result 80 } 81 82 // PythonPdmLockExtraVariant represents a specific extras combination variant within a PDM lock file. 83 // PDM creates separate package entries for different extras combinations; this struct captures those variants. 84 type PythonPdmLockExtraVariant struct { 85 // Extras are the optional extras enabled for this variant (e.g., ["toml"], ["dev"], or ["toml", "dev"]) 86 Extras []string `json:"extras"` 87 // Dependencies are the dependencies specific to this extras variant 88 Dependencies []string `json:"dependencies,omitempty"` 89 // Files are the package files specific to this variant (only populated if different from base) 90 Files []PythonPdmFileEntry `json:"files,omitempty"` 91 // Marker is the environment conditional expression for this variant (e.g., "python_version < \"3.11\"") 92 Marker string `json:"marker,omitempty"` 93 } 94 95 // PythonPdmLockEntry represents a single package entry within a pdm.lock file. 96 type PythonPdmLockEntry struct { 97 // Summary provides a description of the package 98 Summary string `mapstructure:"summary" json:"summary"` 99 // Files are the package files with their paths and hash digests (for the base package without extras) 100 Files []PythonPdmFileEntry `mapstructure:"files" json:"files"` 101 // Marker is the "environment" --conditional expressions that determine whether a package should be installed based on the runtime environment 102 Marker string `mapstructure:"marker" json:"marker,omitempty"` 103 // RequiresPython specifies the Python version requirement (e.g., ">=3.6"). 104 RequiresPython string `mapstructure:"RequiresPython" json:"requiresPython,omitempty" ` 105 // Dependencies are the dependency specifications for the base package (without extras) 106 Dependencies []string `mapstructure:"dependencies" json:"dependencies,omitempty"` 107 // Extras contains variants for different extras combinations (PDM may have multiple entries per package) 108 Extras []PythonPdmLockExtraVariant `json:"extras,omitempty"` 109 } 110 111 type PythonPdmFileEntry struct { 112 // URL is the file download URL 113 URL string `mapstructure:"url" json:"url"` 114 // Digest is the hash digest of the file hosted at the URL 115 Digest PythonFileDigest `mapstructure:"hash" json:"digest"` 116 } 117 118 // PythonPipfileLockEntry represents a single package entry within a Pipfile.lock file. 119 type PythonPipfileLockEntry struct { 120 // Hashes are the package file hash values in the format "algorithm:digest" for integrity verification. 121 Hashes []string `mapstructure:"hashes" json:"hashes"` 122 // Index is the PyPI index name where the package should be fetched from. 123 Index string `mapstructure:"index" json:"index"` 124 } 125 126 // PythonPoetryLockEntry represents a single package entry within a Pipfile.lock file. 127 type PythonPoetryLockEntry struct { 128 // Index is the package repository name where the package should be fetched from. 129 Index string `mapstructure:"index" json:"index"` 130 // Dependencies are the package's runtime dependencies with version constraints. 131 Dependencies []PythonPoetryLockDependencyEntry `json:"dependencies"` 132 // Extras are optional feature groups that include additional dependencies. 133 Extras []PythonPoetryLockExtraEntry `json:"extras,omitempty"` 134 } 135 136 // PythonPoetryLockDependencyEntry represents a single dependency entry within a Poetry lock file. 137 type PythonPoetryLockDependencyEntry struct { 138 // Name is the dependency package name. 139 Name string `json:"name"` 140 // Version is the locked version or version constraint for the dependency. 141 Version string `json:"version"` 142 // Optional indicates whether this dependency is optional (only needed for certain extras). 143 Optional bool `json:"optional"` 144 // Markers are environment marker expressions that conditionally enable the dependency (e.g., "python_version >= '3.8'"). 145 Markers string `json:"markers,omitempty"` 146 // Extras are the optional feature names from the dependency that should be installed. 147 Extras []string `json:"extras,omitempty"` 148 } 149 150 // PythonPoetryLockExtraEntry represents an optional feature group in a Poetry lock file. 151 type PythonPoetryLockExtraEntry struct { 152 // Name is the optional feature name (e.g., "dev", "test"). 153 Name string `json:"name"` 154 // Dependencies are the package names required when this extra is installed. 155 Dependencies []string `json:"dependencies"` 156 } 157 158 // PythonRequirementsEntry represents a single entry within a [*-]requirements.txt file. 159 type PythonRequirementsEntry struct { 160 // Name is the package name from the requirements file. 161 Name string `json:"name" mapstructure:"Name"` 162 // Extras are the optional features to install from the package (e.g., package[dev,test]). 163 Extras []string `json:"extras,omitempty" mapstructure:"Extras"` 164 // VersionConstraint specifies version requirements (e.g., ">=1.0,<2.0"). 165 VersionConstraint string `json:"versionConstraint" mapstructure:"VersionConstraint"` 166 // URL is the direct download URL or VCS URL if specified instead of a PyPI package. 167 URL string `json:"url,omitempty" mapstructure:"URL"` 168 // Markers are environment marker expressions for conditional installation (e.g., "python_version >= '3.8'"). 169 Markers string `json:"markers,omitempty" mapstructure:"Markers"` 170 } 171 172 // PythonUvLockDependencyEntry represents a single dependency entry within a uv lock file. 173 type PythonUvLockDependencyEntry struct { 174 // Name is the dependency package name. 175 Name string `json:"name"` 176 // Optional indicates whether this dependency is optional (only needed for certain extras). 177 Optional bool `json:"optional"` 178 // Markers are environment marker expressions that conditionally enable the dependency (e.g., "python_version >= '3.8'"). 179 Markers string `json:"markers,omitempty"` 180 // Extras are the optional feature names from the dependency that should be installed. 181 Extras []string `json:"extras,omitempty"` 182 } 183 184 // PythonUvLockExtraEntry represents an optional feature group in a uv lock file. 185 type PythonUvLockExtraEntry struct { 186 // Name is the optional feature name (e.g., "dev", "test"). 187 Name string `json:"name"` 188 // Dependencies are the package names required when this extra is installed. 189 Dependencies []string `json:"dependencies"` 190 } 191 192 // PythonUvLockEntry represents a single package entry within a uv.lock file. 193 type PythonUvLockEntry struct { 194 // Index is the package repository name where the package should be fetched from. 195 Index string `mapstructure:"index" json:"index"` 196 // Dependencies are the package's runtime dependencies with version constraints. 197 Dependencies []PythonUvLockDependencyEntry `json:"dependencies"` 198 // Extras are optional feature groups that include additional dependencies. 199 Extras []PythonUvLockExtraEntry `json:"extras,omitempty"` 200 }