github.com/jfrog/frogbot@v1.1.1-0.20231221090046-821a26f50338/packagehandlers/commonpackagehandler.go (about) 1 package packagehandlers 2 3 import ( 4 "fmt" 5 "github.com/jfrog/frogbot/utils" 6 "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" 7 "github.com/jfrog/jfrog-client-go/utils/log" 8 "os/exec" 9 "strings" 10 ) 11 12 // PackageHandler interface to hold operations on packages 13 type PackageHandler interface { 14 UpdateDependency(details *utils.VulnerabilityDetails) error 15 } 16 17 func GetCompatiblePackageHandler(vulnDetails *utils.VulnerabilityDetails, details *utils.ScanDetails) (handler PackageHandler) { 18 switch vulnDetails.Technology { 19 case coreutils.Go: 20 handler = &GoPackageHandler{} 21 case coreutils.Poetry: 22 handler = &PythonPackageHandler{} 23 case coreutils.Pipenv: 24 handler = &PythonPackageHandler{} 25 case coreutils.Npm: 26 handler = &NpmPackageHandler{} 27 case coreutils.Yarn: 28 handler = &YarnPackageHandler{} 29 case coreutils.Pip: 30 handler = &PythonPackageHandler{pipRequirementsFile: details.PipRequirementsFile} 31 case coreutils.Maven: 32 handler = NewMavenPackageHandler(details) 33 case coreutils.Nuget: 34 handler = &NugetPackageHandler{} 35 case coreutils.Gradle: 36 handler = &GradlePackageHandler{} 37 default: 38 handler = &UnsupportedPackageHandler{} 39 } 40 return 41 } 42 43 type CommonPackageHandler struct{} 44 45 // UpdateDependency updates the impacted package to the fixed version 46 func (cph *CommonPackageHandler) UpdateDependency(vulnDetails *utils.VulnerabilityDetails, installationCommand string, extraArgs ...string) (err error) { 47 // Lower the package name to avoid duplicates 48 impactedPackage := strings.ToLower(vulnDetails.ImpactedDependencyName) 49 commandArgs := []string{installationCommand} 50 commandArgs = append(commandArgs, extraArgs...) 51 versionOperator := vulnDetails.Technology.GetPackageVersionOperator() 52 fixedPackageArgs := getFixedPackage(impactedPackage, versionOperator, vulnDetails.SuggestedFixedVersion) 53 commandArgs = append(commandArgs, fixedPackageArgs...) 54 return runPackageMangerCommand(vulnDetails.Technology.GetExecCommandName(), vulnDetails.Technology.String(), commandArgs) 55 } 56 57 func runPackageMangerCommand(commandName string, techName string, commandArgs []string) error { 58 fullCommand := commandName + " " + strings.Join(commandArgs, " ") 59 log.Debug(fmt.Sprintf("Running '%s'", fullCommand)) 60 //#nosec G204 -- False positive - the subprocess only runs after the user's approval. 61 output, err := exec.Command(commandName, commandArgs...).CombinedOutput() 62 if err != nil { 63 return fmt.Errorf("failed to update %s dependency: '%s' command failed: %s\n%s", techName, fullCommand, err.Error(), output) 64 } 65 return nil 66 } 67 68 // Returns the updated package and version as it should be run in the update command: 69 // If the package manager expects a single string (example: <packName>@<version>) it returns []string{<packName>@<version>} 70 // If the command args suppose to be seperated by spaces (example: <packName> -v <version>) it returns []string{<packName>, "-v", <version>} 71 func getFixedPackage(impactedPackage string, versionOperator string, suggestedFixedVersion string) (fixedPackageArgs []string) { 72 fixedPackageString := strings.TrimSpace(impactedPackage) + versionOperator + strings.TrimSpace(suggestedFixedVersion) 73 fixedPackageArgs = strings.Split(fixedPackageString, " ") 74 return 75 }