github.com/jfrog/frogbot@v1.1.1-0.20231221090046-821a26f50338/packagehandlers/yarnpackagehandler.go (about)

     1  package packagehandlers
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	biUtils "github.com/jfrog/build-info-go/build/utils"
     7  	"github.com/jfrog/frogbot/utils"
     8  	"github.com/jfrog/gofrog/version"
     9  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    10  	"github.com/jfrog/jfrog-client-go/utils/log"
    11  )
    12  
    13  const (
    14  	yarnV2Version          = "2.0.0"
    15  	yarnV1PackageUpdateCmd = "upgrade"
    16  	yarnV2PackageUpdateCmd = "up"
    17  	modulesFolderFlag      = "--modules-folder="
    18  )
    19  
    20  type YarnPackageHandler struct {
    21  	CommonPackageHandler
    22  }
    23  
    24  func (yarn *YarnPackageHandler) UpdateDependency(vulnDetails *utils.VulnerabilityDetails) error {
    25  	if vulnDetails.IsDirectDependency {
    26  		return yarn.updateDirectDependency(vulnDetails)
    27  	} else {
    28  		return &utils.ErrUnsupportedFix{
    29  			PackageName:  vulnDetails.ImpactedDependencyName,
    30  			FixedVersion: vulnDetails.SuggestedFixedVersion,
    31  			ErrorType:    utils.IndirectDependencyFixNotSupported,
    32  		}
    33  	}
    34  }
    35  
    36  func (yarn *YarnPackageHandler) updateDirectDependency(vulnDetails *utils.VulnerabilityDetails) (err error) {
    37  	isYarn1, executableYarnVersion, err := isYarnV1Project()
    38  	if err != nil {
    39  		return
    40  	}
    41  
    42  	var installationCommand string
    43  	var extraArgs []string
    44  
    45  	if isYarn1 {
    46  		installationCommand = yarnV1PackageUpdateCmd
    47  		// This dir is created to store node_modules that are created during updating packages in Yarn V1. This dir is to be deleted and not pushed into the PR
    48  		var tmpNodeModulesDir string
    49  		tmpNodeModulesDir, err = fileutils.CreateTempDir()
    50  		defer func() {
    51  			err = errors.Join(err, fileutils.RemoveTempDir(tmpNodeModulesDir))
    52  		}()
    53  
    54  		if err != nil {
    55  			return
    56  		}
    57  		extraArgs = append(extraArgs, modulesFolderFlag+tmpNodeModulesDir)
    58  	} else {
    59  		installationCommand = yarnV2PackageUpdateCmd
    60  	}
    61  	err = yarn.CommonPackageHandler.UpdateDependency(vulnDetails, installationCommand, extraArgs...)
    62  	if err != nil {
    63  		err = fmt.Errorf("running 'yarn %s for '%s' failed:\n%s\nHint: The Yarn version that was used is: %s. If your project was built with a different major version of Yarn, please configure your CI runner to include it",
    64  			installationCommand,
    65  			vulnDetails.ImpactedDependencyName,
    66  			err.Error(),
    67  			executableYarnVersion)
    68  	}
    69  	return
    70  }
    71  
    72  // isYarnV1Project gets the current executed yarn version and returns whether the current yarn version is V1 or not
    73  func isYarnV1Project() (isYarn1 bool, executableYarnVersion string, err error) {
    74  	// NOTICE: in case your global yarn version is 1.x this function will always return true even if the project is originally in higher yarn version
    75  	executableYarnVersion, err = biUtils.GetVersion("yarn", "")
    76  	if err != nil {
    77  		return
    78  	}
    79  	log.Info("Using Yarn version: ", executableYarnVersion)
    80  	isYarn1 = version.NewVersion(executableYarnVersion).Compare(yarnV2Version) > 0
    81  	return
    82  }