Skip to content

Commit b1d7115

Browse files
authored
Enable conan support (#781)
* 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
1 parent b70fc31 commit b1d7115

File tree

7 files changed

+141
-0
lines changed

7 files changed

+141
-0
lines changed

.github/workflows/test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ jobs:
136136
distribution: "adopt"
137137
java-version: "11"
138138

139+
- name: Install Conan
140+
run: |
141+
python -m pip install conan
142+
conan profile detect
143+
139144
# Generate mocks
140145
- name: Generate mocks
141146
run: go generate ./...

packagehandlers/commonpackagehandler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ func GetCompatiblePackageHandler(vulnDetails *utils.VulnerabilityDetails, detail
4242
handler = &GradlePackageHandler{}
4343
case techutils.Pnpm:
4444
handler = &PnpmPackageHandler{}
45+
case techutils.Conan:
46+
handler = &ConanPackageHandler{}
4547
default:
4648
handler = &UnsupportedPackageHandler{}
4749
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package packagehandlers
2+
3+
import (
4+
"fmt"
5+
"github.com/jfrog/frogbot/v2/utils"
6+
"github.com/jfrog/jfrog-client-go/utils/log"
7+
"os"
8+
"strings"
9+
)
10+
11+
const (
12+
conanFileTxt = "conanfile.txt"
13+
conanFilePy = "conanfile.py"
14+
)
15+
16+
type ConanPackageHandler struct {
17+
CommonPackageHandler
18+
}
19+
20+
func (conan *ConanPackageHandler) UpdateDependency(vulnDetails *utils.VulnerabilityDetails) error {
21+
if vulnDetails.IsDirectDependency {
22+
return conan.updateDirectDependency(vulnDetails)
23+
} else {
24+
return &utils.ErrUnsupportedFix{
25+
PackageName: vulnDetails.ImpactedDependencyName,
26+
FixedVersion: vulnDetails.SuggestedFixedVersion,
27+
ErrorType: utils.IndirectDependencyFixNotSupported,
28+
}
29+
}
30+
}
31+
32+
func (conan *ConanPackageHandler) updateDirectDependency(vulnDetails *utils.VulnerabilityDetails) (err error) {
33+
conanDescriptors, err := conan.CommonPackageHandler.GetAllDescriptorFilesFullPaths([]string{conanFileTxt, conanFilePy})
34+
if err != nil {
35+
err = fmt.Errorf("failed while searching for Conan descriptor files in project: %s", err.Error())
36+
return
37+
}
38+
isAnyDescriptorFileChanged := false
39+
for _, descriptor := range conanDescriptors {
40+
var isFileChanged bool
41+
isFileChanged, err = conan.updateConanFile(descriptor, vulnDetails)
42+
if err != nil {
43+
return
44+
}
45+
isAnyDescriptorFileChanged = isAnyDescriptorFileChanged || isFileChanged
46+
}
47+
if !isAnyDescriptorFileChanged {
48+
err = fmt.Errorf("impacted package '%s' was not found or could not be fixed in all descriptor files", vulnDetails.ImpactedDependencyName)
49+
} else {
50+
log.Info("Requirements file was updated with a suggested fix version, but no installation was performed. " +
51+
"In order to update the dependencies, please run 'conan install' command")
52+
}
53+
return
54+
}
55+
56+
func (conan *ConanPackageHandler) updateConanFile(conanFilePath string, vulnDetails *utils.VulnerabilityDetails) (isFileChanged bool, err error) {
57+
data, err := os.ReadFile(conanFilePath)
58+
if err != nil {
59+
return false, fmt.Errorf("an error occurred while attempting to read the requirements file '%s': %s\n", conanFilePath, err.Error())
60+
}
61+
currentFile := string(data)
62+
fixedPackage := vulnDetails.ImpactedDependencyName + "/" + vulnDetails.SuggestedFixedVersion
63+
impactedDependency := vulnDetails.ImpactedDependencyName + "/" + vulnDetails.ImpactedDependencyVersion
64+
fixedFile := strings.Replace(currentFile, impactedDependency, strings.ToLower(fixedPackage), 1)
65+
66+
if fixedFile == currentFile {
67+
log.Debug(fmt.Sprintf("impacted dependency '%s' not found in descriptor '%s', moving to the next descriptor if exists...", impactedDependency, conanFilePath))
68+
return false, nil
69+
}
70+
if err = os.WriteFile(conanFilePath, []byte(fixedFile), 0600); err != nil {
71+
err = fmt.Errorf("an error occured while writing the fixed version of %s to the requirements file '%s': %s", vulnDetails.ImpactedDependencyName, conanFilePath, err.Error())
72+
}
73+
isFileChanged = true
74+
return
75+
}

packagehandlers/packagehandlers_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,30 @@ func TestUpdateDependency(t *testing.T) {
344344
descriptorsToCheck: []string{"package.json"},
345345
},
346346
},
347+
348+
// Conan test cases
349+
{
350+
{
351+
vulnDetails: &utils.VulnerabilityDetails{
352+
SuggestedFixedVersion: "3.0.14",
353+
IsDirectDependency: true,
354+
VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: techutils.Conan, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "openssl", ImpactedDependencyVersion: "3.0.9"}},
355+
},
356+
scanDetails: scanDetails,
357+
fixSupported: true,
358+
testDirName: "conan",
359+
descriptorsToCheck: []string{"conanfile.py", "conanfile.txt"},
360+
},
361+
{
362+
vulnDetails: &utils.VulnerabilityDetails{
363+
SuggestedFixedVersion: "3.0.14",
364+
IsDirectDependency: false,
365+
VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: techutils.Conan, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "openssl", ImpactedDependencyVersion: "3.0.9"}},
366+
},
367+
scanDetails: scanDetails,
368+
fixSupported: false,
369+
},
370+
},
347371
}
348372

349373
for _, testBatch := range testCases {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from conan import ConanFile
2+
3+
class MyPackage(ConanFile):
4+
name = "my_package"
5+
version = "1.0.0"
6+
7+
requires = [
8+
"zlib/1.3.1",
9+
"openssl/3.0.9",
10+
"meson/1.4.1"
11+
]
12+
13+
def build_requirements(self):
14+
self.build_requires("meson/1.4.1")
15+
16+
def build(self):
17+
pass
18+
19+
def package(self):
20+
pass
21+
22+
def package_info(self):
23+
pass
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[requires]
2+
zlib/1.3.1
3+
openssl/3.0.9
4+
meson/1.4.1

testdata/projects/conan/profile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[settings]
2+
arch=x86_64
3+
build_type=Release
4+
compiler=gcc
5+
compiler.cppstd=gnu17
6+
compiler.libcxx=libstdc++11
7+
compiler.version=11
8+
os=Linux

0 commit comments

Comments
 (0)