github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/snap/parse_base_dpkg.go (about)

     1  package snap
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"gopkg.in/yaml.v3"
     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  // dpkgYaml represents the structure of dpkg.yaml files found in base snaps
    17  type dpkgYaml struct {
    18  	PackageRepositories []packageRepository `yaml:"package-repositories"`
    19  	Packages            []string            `yaml:"packages"`
    20  }
    21  
    22  type packageRepository struct {
    23  	Type string `yaml:"type"`
    24  	PPA  string `yaml:"ppa,omitempty"`
    25  	URL  string `yaml:"url,omitempty"`
    26  }
    27  
    28  // parseBaseDpkgYaml parses dpkg.yaml files from base snaps
    29  func parseBaseDpkgYaml(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
    30  	var dpkg dpkgYaml
    31  
    32  	decoder := yaml.NewDecoder(reader)
    33  	if err := decoder.Decode(&dpkg); err != nil {
    34  		return nil, nil, fmt.Errorf("failed to parse dpkg.yaml: %w", err)
    35  	}
    36  
    37  	var packages []pkg.Package
    38  
    39  	snapMetadata := pkg.SnapEntry{
    40  		SnapType: pkg.SnapTypeBase,
    41  	}
    42  
    43  	// Parse each package entry in "name=version" format
    44  	for _, pkgEntry := range dpkg.Packages {
    45  		if !strings.Contains(pkgEntry, "=") {
    46  			continue // Skip malformed entries
    47  		}
    48  
    49  		parts := strings.SplitN(pkgEntry, "=", 2)
    50  		if len(parts) != 2 {
    51  			continue
    52  		}
    53  
    54  		name := strings.TrimSpace(parts[0])
    55  		version := strings.TrimSpace(parts[1])
    56  
    57  		// Skip empty names or versions
    58  		if name == "" || version == "" {
    59  			continue
    60  		}
    61  
    62  		// Handle architecture suffixes (e.g., "libssl1.1:amd64")
    63  		if strings.Contains(name, ":") {
    64  			archParts := strings.SplitN(name, ":", 2)
    65  			name = archParts[0]
    66  			snapMetadata.Architecture = archParts[1]
    67  		}
    68  
    69  		debPkg := newDebianPackageFromSnap(
    70  			name,
    71  			version,
    72  			snapMetadata,
    73  			reader.Location,
    74  		)
    75  
    76  		packages = append(packages, debPkg)
    77  	}
    78  
    79  	return packages, nil, nil
    80  }