go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/npm/yarn.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package npm
     5  
     6  import (
     7  	"bufio"
     8  	"bytes"
     9  	"errors"
    10  	"io"
    11  	"regexp"
    12  	"strings"
    13  
    14  	"github.com/rs/zerolog/log"
    15  	"go.mondoo.com/cnquery/providers-sdk/v1/upstream/mvd"
    16  	"sigs.k8s.io/yaml"
    17  )
    18  
    19  type YarnLockEntry struct {
    20  	Version      string
    21  	Resolved     string
    22  	Dependencies map[string]string
    23  }
    24  
    25  func ParseYarnLock(r io.Reader) ([]*mvd.Package, error) {
    26  	var b bytes.Buffer
    27  
    28  	// iterate and convert the format to yaml on the fly
    29  	scanner := bufio.NewScanner(r)
    30  	for scanner.Scan() {
    31  		line := scanner.Text()
    32  
    33  		reStr := regexp.MustCompile(`^(\s*.*)\s\"(.*)$`)
    34  		repStr := "${1}: \"$2"
    35  		line = reStr.ReplaceAllString(line, repStr)
    36  
    37  		b.Write([]byte(line))
    38  		b.Write([]byte("\n"))
    39  	}
    40  	if err := scanner.Err(); err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	var yarnLock map[string]YarnLockEntry
    45  
    46  	err := yaml.Unmarshal(b.Bytes(), &yarnLock)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	entries := []*mvd.Package{}
    52  
    53  	// add all dependencies
    54  	for k, v := range yarnLock {
    55  		name, _, err := ParseYarnPackageName(k)
    56  		if err != nil {
    57  			log.Error().Str("name", name).Msg("cannot parse yarn package name")
    58  			continue
    59  		}
    60  		entries = append(entries, &mvd.Package{
    61  			Name:      name,
    62  			Version:   v.Version,
    63  			Format:    "npm",
    64  			Namespace: "nodejs",
    65  		})
    66  	}
    67  
    68  	return entries, nil
    69  }
    70  
    71  func ParseYarnPackageName(name string) (string, string, error) {
    72  	// a yarn package line may include may items
    73  	pkgNames := strings.Split(name, ",")
    74  
    75  	if len(pkgNames) == 0 {
    76  		// something wrong
    77  		return "", "", errors.New("cannot parse yarn package name")
    78  	}
    79  
    80  	parse := regexp.MustCompile(`^(.*)@(.*)$`)
    81  	m := parse.FindStringSubmatch(strings.TrimSpace(pkgNames[0]))
    82  	return m[1], m[2], nil
    83  }