Skip to content

Commit

Permalink
Enable conan support (#781)
Browse files Browse the repository at this point in the history
* conan package handler

* IsFileExists fix

* conan package handler

* IsFileExists fix

* conan tests

* fixed installation command

* test fix

* Install Conan in test yaml

* Install Conan in test yaml

* Install Conan in test yaml

* one more commit

* conan profile detect

* removed installation part

* GetAllDescriptorFilesFullPaths

* fixed tests data structure

* error messages change

* static analysis fix

* tests update

* removed logNoInstallationMessage
  • Loading branch information
orto17 authored Jan 6, 2025
1 parent b70fc31 commit b1d7115
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ jobs:
distribution: "adopt"
java-version: "11"

- name: Install Conan
run: |
python -m pip install conan
conan profile detect
# Generate mocks
- name: Generate mocks
run: go generate ./...
Expand Down
2 changes: 2 additions & 0 deletions packagehandlers/commonpackagehandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ func GetCompatiblePackageHandler(vulnDetails *utils.VulnerabilityDetails, detail
handler = &GradlePackageHandler{}
case techutils.Pnpm:
handler = &PnpmPackageHandler{}
case techutils.Conan:
handler = &ConanPackageHandler{}
default:
handler = &UnsupportedPackageHandler{}
}
Expand Down
75 changes: 75 additions & 0 deletions packagehandlers/conanpackagehandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package packagehandlers

import (
"fmt"
"github.com/jfrog/frogbot/v2/utils"
"github.com/jfrog/jfrog-client-go/utils/log"
"os"
"strings"
)

const (
conanFileTxt = "conanfile.txt"
conanFilePy = "conanfile.py"
)

type ConanPackageHandler struct {
CommonPackageHandler
}

func (conan *ConanPackageHandler) UpdateDependency(vulnDetails *utils.VulnerabilityDetails) error {
if vulnDetails.IsDirectDependency {
return conan.updateDirectDependency(vulnDetails)
} else {
return &utils.ErrUnsupportedFix{
PackageName: vulnDetails.ImpactedDependencyName,
FixedVersion: vulnDetails.SuggestedFixedVersion,
ErrorType: utils.IndirectDependencyFixNotSupported,
}
}
}

func (conan *ConanPackageHandler) updateDirectDependency(vulnDetails *utils.VulnerabilityDetails) (err error) {
conanDescriptors, err := conan.CommonPackageHandler.GetAllDescriptorFilesFullPaths([]string{conanFileTxt, conanFilePy})
if err != nil {
err = fmt.Errorf("failed while searching for Conan descriptor files in project: %s", err.Error())
return
}
isAnyDescriptorFileChanged := false
for _, descriptor := range conanDescriptors {
var isFileChanged bool
isFileChanged, err = conan.updateConanFile(descriptor, vulnDetails)
if err != nil {
return
}
isAnyDescriptorFileChanged = isAnyDescriptorFileChanged || isFileChanged
}
if !isAnyDescriptorFileChanged {
err = fmt.Errorf("impacted package '%s' was not found or could not be fixed in all descriptor files", vulnDetails.ImpactedDependencyName)
} else {
log.Info("Requirements file was updated with a suggested fix version, but no installation was performed. " +
"In order to update the dependencies, please run 'conan install' command")
}
return
}

func (conan *ConanPackageHandler) updateConanFile(conanFilePath string, vulnDetails *utils.VulnerabilityDetails) (isFileChanged bool, err error) {
data, err := os.ReadFile(conanFilePath)
if err != nil {
return false, fmt.Errorf("an error occurred while attempting to read the requirements file '%s': %s\n", conanFilePath, err.Error())
}
currentFile := string(data)
fixedPackage := vulnDetails.ImpactedDependencyName + "/" + vulnDetails.SuggestedFixedVersion
impactedDependency := vulnDetails.ImpactedDependencyName + "/" + vulnDetails.ImpactedDependencyVersion
fixedFile := strings.Replace(currentFile, impactedDependency, strings.ToLower(fixedPackage), 1)

if fixedFile == currentFile {
log.Debug(fmt.Sprintf("impacted dependency '%s' not found in descriptor '%s', moving to the next descriptor if exists...", impactedDependency, conanFilePath))
return false, nil
}
if err = os.WriteFile(conanFilePath, []byte(fixedFile), 0600); err != nil {
err = fmt.Errorf("an error occured while writing the fixed version of %s to the requirements file '%s': %s", vulnDetails.ImpactedDependencyName, conanFilePath, err.Error())
}
isFileChanged = true
return
}
24 changes: 24 additions & 0 deletions packagehandlers/packagehandlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,30 @@ func TestUpdateDependency(t *testing.T) {
descriptorsToCheck: []string{"package.json"},
},
},

// Conan test cases
{
{
vulnDetails: &utils.VulnerabilityDetails{
SuggestedFixedVersion: "3.0.14",
IsDirectDependency: true,
VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: techutils.Conan, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "openssl", ImpactedDependencyVersion: "3.0.9"}},
},
scanDetails: scanDetails,
fixSupported: true,
testDirName: "conan",
descriptorsToCheck: []string{"conanfile.py", "conanfile.txt"},
},
{
vulnDetails: &utils.VulnerabilityDetails{
SuggestedFixedVersion: "3.0.14",
IsDirectDependency: false,
VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: techutils.Conan, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "openssl", ImpactedDependencyVersion: "3.0.9"}},
},
scanDetails: scanDetails,
fixSupported: false,
},
},
}

for _, testBatch := range testCases {
Expand Down
23 changes: 23 additions & 0 deletions testdata/projects/conan/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from conan import ConanFile

class MyPackage(ConanFile):
name = "my_package"
version = "1.0.0"

requires = [
"zlib/1.3.1",
"openssl/3.0.9",
"meson/1.4.1"
]

def build_requirements(self):
self.build_requires("meson/1.4.1")

def build(self):
pass

def package(self):
pass

def package_info(self):
pass
4 changes: 4 additions & 0 deletions testdata/projects/conan/conanfile.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[requires]
zlib/1.3.1
openssl/3.0.9
meson/1.4.1
8 changes: 8 additions & 0 deletions testdata/projects/conan/profile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[settings]
arch=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=11
os=Linux

0 comments on commit b1d7115

Please sign in to comment.