github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/snap/parse_system_manifest.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 // systemManifest represents the structure of manifest.yaml files found in system/gadget snaps 17 type systemManifest struct { 18 Name string `yaml:"name"` 19 Version string `yaml:"version"` 20 Base string `yaml:"base"` 21 Grade string `yaml:"grade"` 22 Confinement string `yaml:"confinement"` 23 PrimedStagePackages []string `yaml:"primed-stage-packages"` 24 Architectures []string `yaml:"architectures"` 25 SnapcraftVersion string `yaml:"snapcraft-version"` 26 SnapcraftOSReleaseID string `yaml:"snapcraft-os-release-id"` 27 } 28 29 // parseSystemManifest parses manifest.yaml files from system/gadget snaps 30 func parseSystemManifest(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 31 var manifest systemManifest 32 33 decoder := yaml.NewDecoder(reader) 34 if err := decoder.Decode(&manifest); err != nil { 35 return nil, nil, fmt.Errorf("failed to parse manifest.yaml: %w", err) 36 } 37 38 var packages []pkg.Package 39 40 // Determine snap type - could be system, gadget, or app 41 snapType := pkg.SnapTypeApp // Default 42 if manifest.Name != "" { 43 // Try to infer type from name patterns or content 44 switch { 45 case strings.Contains(strings.ToLower(manifest.Name), "gadget"): 46 snapType = pkg.SnapTypeGadget 47 default: 48 snapType = pkg.SnapTypeApp // System snaps are often just regular apps 49 } 50 } 51 52 snapMetadata := pkg.SnapEntry{ 53 SnapType: snapType, 54 Base: manifest.Base, 55 SnapName: manifest.Name, 56 SnapVersion: manifest.Version, 57 } 58 59 // Set architecture if available 60 if len(manifest.Architectures) > 0 { 61 snapMetadata.Architecture = manifest.Architectures[0] 62 } 63 64 // Parse primed-stage-packages entries 65 for _, pkgEntry := range manifest.PrimedStagePackages { 66 if !strings.Contains(pkgEntry, "=") { 67 continue // Skip malformed entries 68 } 69 70 parts := strings.SplitN(pkgEntry, "=", 2) 71 if len(parts) != 2 { 72 continue 73 } 74 75 name := strings.TrimSpace(parts[0]) 76 version := strings.TrimSpace(parts[1]) 77 78 // Skip empty names or versions 79 if name == "" || version == "" { 80 continue 81 } 82 83 // Handle architecture suffixes if present 84 currentMetadata := snapMetadata 85 if strings.Contains(name, ":") { 86 archParts := strings.SplitN(name, ":", 2) 87 name = archParts[0] 88 currentMetadata.Architecture = archParts[1] 89 } 90 91 debPkg := newDebianPackageFromSnap( 92 name, 93 version, 94 currentMetadata, 95 reader.Location, 96 ) 97 98 packages = append(packages, debPkg) 99 } 100 101 return packages, nil, nil 102 }