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  }