github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/dotnet/parse_dotnet_portable_executable.go (about)

     1  package dotnet
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/saferwall/pe"
     8  
     9  	"github.com/anchore/packageurl-go"
    10  	"github.com/anchore/syft/internal/log"
    11  	"github.com/anchore/syft/syft/artifact"
    12  	"github.com/anchore/syft/syft/file"
    13  	"github.com/anchore/syft/syft/pkg"
    14  	"github.com/anchore/syft/syft/pkg/cataloger/generic"
    15  )
    16  
    17  var _ generic.Parser = parseDotnetPortableExecutable
    18  
    19  func parseDotnetPortableExecutable(_ file.Resolver, _ *generic.Environment, f file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
    20  	by, err := io.ReadAll(f)
    21  	if err != nil {
    22  		return nil, nil, fmt.Errorf("unable to read file: %w", err)
    23  	}
    24  
    25  	peFile, err := pe.NewBytes(by, &pe.Options{})
    26  	if err != nil {
    27  		return nil, nil, fmt.Errorf("unable to create PE file instance: %w", err)
    28  	}
    29  
    30  	err = peFile.Parse()
    31  	if err != nil {
    32  		return nil, nil, fmt.Errorf("unable to parse PE file: %w", err)
    33  	}
    34  
    35  	versionResources, err := peFile.ParseVersionResources()
    36  	if err != nil {
    37  		// this is not a fatal error, just log and continue
    38  		// TODO: consider this case for "known unknowns" (same goes for cases below)
    39  		log.Tracef("unable to parse version resources in PE file: %s", f.RealPath)
    40  		return nil, nil, nil
    41  	}
    42  
    43  	name := versionResources["FileDescription"]
    44  	if name == "" {
    45  		log.Tracef("unable to find FileDescription in PE file: %s", f.RealPath)
    46  		return nil, nil, nil
    47  	}
    48  
    49  	version := versionResources["FileVersion"]
    50  	if version == "" {
    51  		log.Tracef("unable to find FileVersion in PE file: %s", f.RealPath)
    52  		return nil, nil, nil
    53  	}
    54  
    55  	purl := packageurl.NewPackageURL(
    56  		packageurl.TypeNuget, // See explanation in syft/pkg/cataloger/dotnet/package.go as to why this was chosen.
    57  		"",
    58  		name,
    59  		version,
    60  		nil,
    61  		"",
    62  	).ToString()
    63  
    64  	metadata := pkg.DotnetPortableExecutableMetadata{
    65  		AssemblyVersion: versionResources["Assembly Version"],
    66  		LegalCopyright:  versionResources["LegalCopyright"],
    67  		Comments:        versionResources["Comments"],
    68  		InternalName:    versionResources["InternalName"],
    69  		CompanyName:     versionResources["CompanyName"],
    70  		ProductName:     versionResources["ProductName"],
    71  		ProductVersion:  versionResources["ProductVersion"],
    72  	}
    73  
    74  	p := pkg.Package{
    75  		Name:         name,
    76  		Version:      version,
    77  		Locations:    file.NewLocationSet(f.Location),
    78  		Type:         pkg.DotnetPkg,
    79  		PURL:         purl,
    80  		MetadataType: pkg.DotnetPortableExecutableMetadataType,
    81  		Metadata:     metadata,
    82  	}
    83  
    84  	p.SetID()
    85  
    86  	return []pkg.Package{p}, nil, nil
    87  }