github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/pkg/cataloger/dart/parse_pubspec_lock.go (about) 1 package dart 2 3 import ( 4 "fmt" 5 "net/url" 6 "sort" 7 8 "github.com/nextlinux/gosbom/gosbom/artifact" 9 "github.com/nextlinux/gosbom/gosbom/file" 10 "github.com/nextlinux/gosbom/gosbom/pkg" 11 "github.com/nextlinux/gosbom/gosbom/pkg/cataloger/generic" 12 "github.com/nextlinux/gosbom/internal/log" 13 "gopkg.in/yaml.v3" 14 ) 15 16 var _ generic.Parser = parsePubspecLock 17 18 const defaultPubRegistry string = "https://pub.dartlang.org" 19 20 type pubspecLock struct { 21 Packages map[string]pubspecLockPackage `yaml:"packages"` 22 Sdks map[string]string `yaml:"sdks"` 23 } 24 25 type pubspecLockPackage struct { 26 Dependency string `yaml:"dependency" mapstructure:"dependency"` 27 Description pubspecLockDescription `yaml:"description" mapstructure:"description"` 28 Source string `yaml:"source" mapstructure:"source"` 29 Version string `yaml:"version" mapstructure:"version"` 30 } 31 32 type pubspecLockDescription struct { 33 Name string `yaml:"name" mapstructure:"name"` 34 URL string `yaml:"url" mapstructure:"url"` 35 Path string `yaml:"path" mapstructure:"path"` 36 Ref string `yaml:"ref" mapstructure:"ref"` 37 ResolvedRef string `yaml:"resolved-ref" mapstructure:"resolved-ref"` 38 } 39 40 func (p *pubspecLockDescription) UnmarshalYAML(value *yaml.Node) error { 41 type pld pubspecLockDescription 42 var p2 pld 43 44 if value.Decode(&p.Name) == nil { 45 return nil 46 } 47 48 if err := value.Decode(&p2); err != nil { 49 return err 50 } 51 52 *p = pubspecLockDescription(p2) 53 54 return nil 55 } 56 57 func parsePubspecLock(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 58 var pkgs []pkg.Package 59 60 dec := yaml.NewDecoder(reader) 61 62 var p pubspecLock 63 if err := dec.Decode(&p); err != nil { 64 return nil, nil, fmt.Errorf("failed to parse pubspec.lock file: %w", err) 65 } 66 67 var names []string 68 for name := range p.Packages { 69 names = append(names, name) 70 } 71 72 // always ensure there is a stable ordering of packages 73 sort.Strings(names) 74 75 for _, name := range names { 76 pubPkg := p.Packages[name] 77 pkgs = append(pkgs, 78 newPubspecLockPackage( 79 name, 80 pubPkg, 81 reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 82 ), 83 ) 84 } 85 86 return pkgs, nil, nil 87 } 88 89 func (p *pubspecLockPackage) getVcsURL() string { 90 if p.Source == "git" { 91 if p.Description.Path == "." { 92 return fmt.Sprintf("%s@%s", p.Description.URL, p.Description.ResolvedRef) 93 } 94 95 return fmt.Sprintf("%s@%s#%s", p.Description.URL, p.Description.ResolvedRef, p.Description.Path) 96 } 97 98 return "" 99 } 100 101 func (p *pubspecLockPackage) getHostedURL() string { 102 if p.Source == "hosted" && p.Description.URL != defaultPubRegistry { 103 u, err := url.Parse(p.Description.URL) 104 if err != nil { 105 log.Debugf("Unable to parse registry url %w", err) 106 return p.Description.URL 107 } 108 return u.Host 109 } 110 111 return "" 112 }