Skip to content

Commit edf036e

Browse files
committed
Merge branch 'dev' of https://github.com/jfrog/jfrog-cli-security into update-dependencies-for-1.20.0
2 parents 96fee63 + 2c88232 commit edf036e

File tree

7 files changed

+63
-33
lines changed

7 files changed

+63
-33
lines changed

sca/bom/buildinfo/technologies/python/python.go

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const (
3636
)
3737

3838
func BuildDependencyTree(params technologies.BuildInfoBomGeneratorParams, technology techutils.Technology) (dependencyTree []*clientutils.GraphNode, uniqueDeps []string, downloadUrls map[string]string, err error) {
39-
dependenciesGraph, directDependenciesList, pipUrls, errGetTree := getDependencies(params, technology)
39+
rootDetected, dependenciesGraph, directDependenciesList, pipUrls, errGetTree := getDependencies(params, technology)
4040
if errGetTree != nil {
4141
err = errGetTree
4242
return
@@ -52,16 +52,40 @@ func BuildDependencyTree(params technologies.BuildInfoBomGeneratorParams, techno
5252
populatePythonDependencyTree(directDependency, dependenciesGraph, uniqueDepsSet)
5353
directDependencies = append(directDependencies, directDependency)
5454
}
55-
root := &clientutils.GraphNode{
56-
Id: "root",
57-
Nodes: directDependencies,
58-
}
59-
dependencyTree = []*clientutils.GraphNode{root}
55+
dependencyTree = getRootNodes(directDependencies, rootDetected)
6056
uniqueDeps = uniqueDepsSet.ToSlice()
6157
return
6258
}
6359

64-
func getDependencies(params technologies.BuildInfoBomGeneratorParams, technology techutils.Technology) (dependenciesGraph map[string][]string, directDependencies []string, pipUrls map[string]string, err error) {
60+
func getRootNodes(directDependencies []*clientutils.GraphNode, rootDetected bool) (roots []*clientutils.GraphNode) {
61+
if !rootDetected {
62+
return []*clientutils.GraphNode{{
63+
Id: "root",
64+
Nodes: directDependencies,
65+
}}
66+
}
67+
// root was detected. in Pip, the pip version is also detected as root component.
68+
// In this case, we need to append the pip node to the actual roots.
69+
roots = []*clientutils.GraphNode{}
70+
var pipNode *clientutils.GraphNode
71+
// Search if pip is one of the direct dependencies.
72+
for _, dep := range directDependencies {
73+
if strings.HasPrefix(dep.Id, PythonPackageTypeIdentifier+techutils.Pip.String()+":") {
74+
pipNode = dep
75+
} else {
76+
roots = append(roots, dep)
77+
}
78+
}
79+
if pipNode != nil {
80+
// Append pip node to actual roots.
81+
for _, root := range roots {
82+
root.Nodes = append(root.Nodes, pipNode)
83+
}
84+
}
85+
return
86+
}
87+
88+
func getDependencies(params technologies.BuildInfoBomGeneratorParams, technology techutils.Technology) (rootDetected bool, dependenciesGraph map[string][]string, directDependencies []string, pipUrls map[string]string, err error) {
6589
wd, err := os.Getwd()
6690
if errorutils.CheckError(err) != nil {
6791
return
@@ -95,7 +119,7 @@ func getDependencies(params technologies.BuildInfoBomGeneratorParams, technology
95119
pythonTool := pythonutils.PythonTool(technology)
96120
if technology == techutils.Pipenv || !params.SkipAutoInstall {
97121
var restoreEnv func() error
98-
restoreEnv, err = runPythonInstall(params, pythonTool)
122+
rootDetected, restoreEnv, err = runPythonInstall(params, pythonTool)
99123
defer func() {
100124
err = errors.Join(err, restoreEnv())
101125
}()
@@ -180,7 +204,7 @@ type pypiMetaData struct {
180204
Version string `json:"version"`
181205
}
182206

183-
func runPythonInstall(params technologies.BuildInfoBomGeneratorParams, tool pythonutils.PythonTool) (restoreEnv func() error, err error) {
207+
func runPythonInstall(params technologies.BuildInfoBomGeneratorParams, tool pythonutils.PythonTool) (rootDetected bool, restoreEnv func() error, err error) {
184208
switch tool {
185209
case pythonutils.Pip:
186210
return installPipDeps(params)
@@ -192,28 +216,28 @@ func runPythonInstall(params technologies.BuildInfoBomGeneratorParams, tool pyth
192216
return
193217
}
194218

195-
func installPoetryDeps(params technologies.BuildInfoBomGeneratorParams) (restoreEnv func() error, err error) {
219+
func installPoetryDeps(params technologies.BuildInfoBomGeneratorParams) (rootDetected bool, restoreEnv func() error, err error) {
196220
restoreEnv = func() error {
197221
return nil
198222
}
199223
if params.DependenciesRepository != "" {
200224
rtUrl, username, password, err := artifactoryutils.GetPypiRepoUrlWithCredentials(params.ServerDetails, params.DependenciesRepository, false)
201225
if err != nil {
202-
return restoreEnv, err
226+
return false, restoreEnv, err
203227
}
204228
if password != "" {
205229
err = artifactoryutils.ConfigPoetryRepo(rtUrl.Scheme+"://"+rtUrl.Host+rtUrl.Path, username, password, params.DependenciesRepository)
206230
if err != nil {
207-
return restoreEnv, err
231+
return false, restoreEnv, err
208232
}
209233
}
210234
}
211235
// Run 'poetry install'
212236
_, err = executeCommand("poetry", "install")
213-
return restoreEnv, err
237+
return false, restoreEnv, err
214238
}
215239

216-
func installPipenvDeps(params technologies.BuildInfoBomGeneratorParams) (restoreEnv func() error, err error) {
240+
func installPipenvDeps(params technologies.BuildInfoBomGeneratorParams) (rootDetected bool, restoreEnv func() error, err error) {
217241
// Set virtualenv path to venv dir
218242
err = os.Setenv("WORKON_HOME", ".jfrog")
219243
if err != nil {
@@ -223,14 +247,14 @@ func installPipenvDeps(params technologies.BuildInfoBomGeneratorParams) (restore
223247
return os.Unsetenv("WORKON_HOME")
224248
}
225249
if params.DependenciesRepository != "" {
226-
return restoreEnv, runPipenvInstallFromRemoteRegistry(params.ServerDetails, params.DependenciesRepository)
250+
return false, restoreEnv, runPipenvInstallFromRemoteRegistry(params.ServerDetails, params.DependenciesRepository)
227251
}
228252
// Run 'pipenv install -d'
229253
_, err = executeCommand("pipenv", "install", "-d")
230-
return restoreEnv, err
254+
return false, restoreEnv, err
231255
}
232256

233-
func installPipDeps(params technologies.BuildInfoBomGeneratorParams) (restoreEnv func() error, err error) {
257+
func installPipDeps(params technologies.BuildInfoBomGeneratorParams) (setupFileUsed bool, restoreEnv func() error, err error) {
234258
restoreEnv, err = SetPipVirtualEnvPath()
235259
if err != nil {
236260
return
@@ -256,7 +280,7 @@ func installPipDeps(params technologies.BuildInfoBomGeneratorParams) (restoreEnv
256280
}
257281
reportFileName = pythonReportFile
258282
}
259-
283+
setupFileUsed = params.PipRequirementsFile == ""
260284
pipInstallArgs := getPipInstallArgs(params.PipRequirementsFile, remoteUrl, curationCachePip, reportFileName, params.InstallCommandArgs...)
261285
var reqErr error
262286
_, err = executeCommand("python", pipInstallArgs...)
@@ -269,6 +293,7 @@ func installPipDeps(params technologies.BuildInfoBomGeneratorParams) (restoreEnv
269293
} else {
270294
err = nil
271295
}
296+
setupFileUsed = false
272297
}
273298
if err != nil || reqErr != nil {
274299
if msgToUser := technologies.GetMsgToUserForCurationBlock(params.IsCurationCmd, techutils.Pip, errors.Join(err, reqErr).Error()); msgToUser != "" {

sca/bom/buildinfo/technologies/python/python_test.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ func TestBuildPipDependencyListSetuppy(t *testing.T) {
3232
assert.Contains(t, uniqueDeps, PythonPackageTypeIdentifier+"ptyprocess:0.7.0")
3333
assert.Contains(t, uniqueDeps, PythonPackageTypeIdentifier+"pip-example:1.2.3")
3434
assert.Len(t, rootNode, 1)
35+
// Test direct dependency
36+
tests.GetAndAssertNode(t, rootNode, "pip-example:1.2.3")
3537
if len(rootNode) > 0 {
3638
assert.NotEmpty(t, rootNode[0].Nodes)
3739
if rootNode[0].Nodes != nil {
38-
// Test direct dependency
39-
directDepNode := tests.GetAndAssertNode(t, rootNode[0].Nodes, "pip-example:1.2.3")
4040
// Test child module
41-
childNode := tests.GetAndAssertNode(t, directDepNode.Nodes, "pexpect:4.8.0")
41+
childNode := tests.GetAndAssertNode(t, rootNode[0].Nodes, "pexpect:4.8.0")
4242
// Test sub child module
4343
tests.GetAndAssertNode(t, childNode.Nodes, "ptyprocess:0.7.0")
4444
}
@@ -69,11 +69,10 @@ func TestBuildPipDependencyListSetuppyForCuration(t *testing.T) {
6969
assert.Contains(t, uniqueDeps, PythonPackageTypeIdentifier+"ptyprocess:0.7.0")
7070
assert.Contains(t, uniqueDeps, PythonPackageTypeIdentifier+"pip-example:1.2.3")
7171
assert.Len(t, rootNode, 1)
72+
tests.GetAndAssertNode(t, rootNode, "pip-example:1.2.3")
7273
if assert.NotNil(t, rootNode[0].Nodes) && assert.NotEmpty(t, rootNode[0].Nodes) {
73-
// Test direct dependency
74-
directDepNode := tests.GetAndAssertNode(t, rootNode[0].Nodes, "pip-example:1.2.3")
7574
// Test child module
76-
childNode := tests.GetAndAssertNode(t, directDepNode.Nodes, "pexpect:4.8.0")
75+
childNode := tests.GetAndAssertNode(t, rootNode[0].Nodes, "pexpect:4.8.0")
7776
// Test sub child module
7877
tests.GetAndAssertNode(t, childNode.Nodes, "ptyprocess:0.7.0")
7978

@@ -201,31 +200,36 @@ func TestBuildDependencyTreeWhenInstallForbidden(t *testing.T) {
201200
testDir string
202201
technology techutils.Technology
203202
installBeforeFetchingInitialDeps bool
203+
rootDetected bool
204204
}{
205205
// pip
206206
{
207207
name: "pip: project not installed | install forbidden",
208208
testDir: filepath.Join("projects", "package-managers", "python", "pip", "pip", "requirementsproject"),
209209
technology: techutils.Pip,
210210
installBeforeFetchingInitialDeps: false,
211+
rootDetected: false,
211212
},
212213
{
213214
name: "pip: project installed before dep tree construction| install forbidden",
214215
testDir: filepath.Join("projects", "package-managers", "python", "pip", "pip", "requirementsproject"),
215216
technology: techutils.Pip,
216217
installBeforeFetchingInitialDeps: true,
218+
rootDetected: false,
217219
},
218220
{
219221
name: "poetry: project not installed | install forbidden",
220222
testDir: filepath.Join("projects", "package-managers", "python", "poetry", "poetry"),
221223
technology: techutils.Poetry,
222224
installBeforeFetchingInitialDeps: false,
225+
rootDetected: false,
223226
},
224227
{
225228
name: "poetry: project installed before dep tree construction| install forbidden",
226229
testDir: filepath.Join("projects", "package-managers", "python", "poetry", "poetry"),
227230
technology: techutils.Poetry,
228231
installBeforeFetchingInitialDeps: true,
232+
rootDetected: false,
229233
},
230234
}
231235

@@ -253,11 +257,12 @@ func TestBuildDependencyTreeWhenInstallForbidden(t *testing.T) {
253257
}
254258

255259
if test.installBeforeFetchingInitialDeps {
256-
restoreEnv, err := runPythonInstall(params, pythonutils.PythonTool(test.technology))
260+
rootDetected, restoreEnv, err := runPythonInstall(params, pythonutils.PythonTool(test.technology))
257261
defer func() {
258262
assert.NoError(t, restoreEnv(), "restoring env after setting "+test.technology+" virtual env creation failed")
259263
}()
260264
require.NoError(t, err)
265+
assert.Equal(t, test.rootDetected, rootDetected, "Root detection mismatch for "+test.technology+" technology")
261266
}
262267

263268
// Checking dependencies before BuildDependencyTree

sca/bom/scang/plugin/plugin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const (
2929
scangPluginRtRepository = "scang/v1"
3030

3131
scangPluginDirName = "scang"
32-
ScangPluginExecutableName = "scangplugin"
32+
ScangPluginExecutableName = "xray-scan-plugin"
3333
pluginName = "scang"
3434

3535
scangPluginMagicCookieKey = "SCANG_PLUGIN_MAGIC_COOKIE"

tests/validations/test_validate_cyclonedx.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func countSbomComponents(content *cyclonedx.BOM) (sbomComponents, rootComponents
5959
}
6060
}
6161
}
62-
relation := cdxutils.GetComponentRelation(content, component.BOMRef)
62+
relation := cdxutils.GetComponentRelation(content, component.BOMRef, true)
6363
if relation == cdxutils.UnknownRelation {
6464
continue
6565
}

utils/formats/cdxutils/cyclonedxutils.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func SearchDependencyEntry(dependencies *[]cyclonedx.Dependency, ref string) *cy
9090
return nil
9191
}
9292

93-
func GetComponentRelation(bom *cyclonedx.BOM, componentRef string) ComponentRelation {
93+
func GetComponentRelation(bom *cyclonedx.BOM, componentRef string, skipDefaultRoot bool) ComponentRelation {
9494
if bom == nil || bom.Components == nil {
9595
return UnknownRelation
9696
}
@@ -105,7 +105,7 @@ func GetComponentRelation(bom *cyclonedx.BOM, componentRef string) ComponentRela
105105
}
106106
parents := SearchParents(componentRef, *bom.Components, dependencies...)
107107
// Calculate the root components
108-
for _, root := range GetRootDependenciesEntries(bom, true) {
108+
for _, root := range GetRootDependenciesEntries(bom, skipDefaultRoot) {
109109
if root.Ref == componentRef {
110110
// The component is a root
111111
return RootRelation
@@ -283,7 +283,7 @@ func Exclude(bom cyclonedx.BOM, componentsToExclude ...cyclonedx.Component) (fil
283283
}
284284
filteredSbom = &bom
285285
for _, compToExclude := range componentsToExclude {
286-
if matchedBomComp := SearchComponentByRef(bom.Components, compToExclude.BOMRef); matchedBomComp == nil || GetComponentRelation(&bom, matchedBomComp.BOMRef) == RootRelation {
286+
if matchedBomComp := SearchComponentByRef(bom.Components, compToExclude.BOMRef); matchedBomComp == nil || GetComponentRelation(&bom, matchedBomComp.BOMRef, false) == RootRelation {
287287
// If not a match or Root component, skip it
288288
continue
289289
}

utils/formats/cdxutils/cyclonedxutils_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ func TestGetComponentRelation(t *testing.T) {
388388

389389
for _, tt := range tests {
390390
t.Run(tt.name, func(t *testing.T) {
391-
result := GetComponentRelation(tt.bom, tt.componentRef)
391+
result := GetComponentRelation(tt.bom, tt.componentRef, true)
392392
assert.Equal(t, tt.expected, result, "Expected component relation does not match")
393393
})
394394
}

utils/results/common.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ func ForEachSbomComponent(bom *cyclonedx.BOM, handler ParseSbomComponentFunc) (e
286286
if err := handler(
287287
component,
288288
cdxutils.SearchDependencyEntry(bom.Dependencies, component.BOMRef),
289-
cdxutils.GetComponentRelation(bom, component.BOMRef),
289+
cdxutils.GetComponentRelation(bom, component.BOMRef, true),
290290
); err != nil {
291291
return err
292292
}
@@ -859,7 +859,7 @@ func ExtractCdxDependenciesCves(bom *cyclonedx.BOM) (directCves []string, indire
859859
continue
860860
}
861861
for _, affectedComponent := range *vulnerability.Affects {
862-
relation := cdxutils.GetComponentRelation(bom, affectedComponent.Ref)
862+
relation := cdxutils.GetComponentRelation(bom, affectedComponent.Ref, true)
863863
if relation == cdxutils.TransitiveRelation {
864864
indirectCvesSet.Add(vulnerability.BOMRef)
865865
} else {

0 commit comments

Comments
 (0)