Skip to content

Commit 0360f8d

Browse files
committed
Merge branch 'dev' of https://github.com/jfrog/jfrog-cli-security into config-profile-with-repo-api-integration
2 parents 5c51e45 + a42170d commit 0360f8d

File tree

14 files changed

+183
-83
lines changed

14 files changed

+183
-83
lines changed

cli/docs/flags.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package docs
22

33
import (
44
"fmt"
5-
"github.com/jfrog/jfrog-cli-security/commands/git"
65
"strings"
76

7+
"github.com/jfrog/jfrog-cli-security/commands/git"
8+
89
"github.com/jfrog/jfrog-cli-core/v2/common/cliutils"
910
pluginsCommon "github.com/jfrog/jfrog-cli-core/v2/plugins/common"
1011
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
@@ -114,6 +115,7 @@ const (
114115
useWrapperAudit = auditPrefix + UseWrapper
115116
ExcludeTestDeps = "exclude-test-deps"
116117
DepType = "dep-type"
118+
MaxTreeDepth = "max-tree-depth"
117119
ThirdPartyContextualAnalysis = "third-party-contextual-analysis"
118120
RequirementsFile = "requirements-file"
119121
WorkingDirs = "working-dirs"
@@ -240,17 +242,18 @@ var flagsMap = map[string]components.Flag{
240242
"List of exclusions separated by semicolons, utilized to skip sub-projects from undergoing an audit. These exclusions may incorporate the * and ? wildcards.",
241243
components.WithStrDefaultValue(strings.Join(utils.DefaultScaExcludePatterns, ";")),
242244
),
243-
Mvn: components.NewBoolFlag(Mvn, "Set to true to request audit for a Maven project."),
244-
Gradle: components.NewBoolFlag(Gradle, "Set to true to request audit for a Gradle project."),
245-
Npm: components.NewBoolFlag(Npm, "Set to true to request audit for a npm project."),
246-
Pnpm: components.NewBoolFlag(Pnpm, "Set to true to request audit for a Pnpm project."),
247-
Yarn: components.NewBoolFlag(Yarn, "Set to true to request audit for a Yarn project."),
248-
Nuget: components.NewBoolFlag(Nuget, "Set to true to request audit for a .NET project."),
249-
Pip: components.NewBoolFlag(Pip, "Set to true to request audit for a Pip project."),
250-
Pipenv: components.NewBoolFlag(Pipenv, "Set to true to request audit for a Pipenv project."),
251-
Poetry: components.NewBoolFlag(Poetry, "Set to true to request audit for a Poetry project."),
252-
Go: components.NewBoolFlag(Go, "Set to true to request audit for a Go project."),
253-
DepType: components.NewStringFlag(DepType, "[npm] Defines npm dependencies type. Possible values are: all, devOnly and prodOnly."),
245+
Mvn: components.NewBoolFlag(Mvn, "Set to true to request audit for a Maven project."),
246+
Gradle: components.NewBoolFlag(Gradle, "Set to true to request audit for a Gradle project."),
247+
Npm: components.NewBoolFlag(Npm, "Set to true to request audit for a npm project."),
248+
Pnpm: components.NewBoolFlag(Pnpm, "Set to true to request audit for a Pnpm project."),
249+
Yarn: components.NewBoolFlag(Yarn, "Set to true to request audit for a Yarn project."),
250+
Nuget: components.NewBoolFlag(Nuget, "Set to true to request audit for a .NET project."),
251+
Pip: components.NewBoolFlag(Pip, "Set to true to request audit for a Pip project."),
252+
Pipenv: components.NewBoolFlag(Pipenv, "Set to true to request audit for a Pipenv project."),
253+
Poetry: components.NewBoolFlag(Poetry, "Set to true to request audit for a Poetry project."),
254+
Go: components.NewBoolFlag(Go, "Set to true to request audit for a Go project."),
255+
DepType: components.NewStringFlag(DepType, "[npm] Defines npm dependencies type. Possible values are: all, devOnly and prodOnly."),
256+
MaxTreeDepth: components.NewStringFlag(MaxTreeDepth, "[pnpm] Max depth of the generated dependencies tree for SCA scan.", components.WithStrDefaultValue("Infinity")),
254257
ThirdPartyContextualAnalysis: components.NewBoolFlag(
255258
ThirdPartyContextualAnalysis,
256259
"[npm] when set, the Contextual Analysis scan also uses the code of the project dependencies to determine the applicability of the vulnerability.",

cli/scancommands.go

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ func ScanCmd(c *components.Context) error {
206206
if err != nil {
207207
return err
208208
}
209-
xrayVersion, xscVersion, err := GetJfrogServicesVersion(serverDetails)
209+
xrayVersion, xscVersion, err := xsc.GetJfrogServicesVersion(serverDetails)
210210
if err != nil {
211211
return err
212212
}
@@ -453,7 +453,7 @@ func CreateAuditCmd(c *components.Context) (string, string, *coreConfig.ServerDe
453453
if err != nil {
454454
return "", "", nil, nil, err
455455
}
456-
xrayVersion, xscVersion, err := GetJfrogServicesVersion(serverDetails)
456+
xrayVersion, xscVersion, err := xsc.GetJfrogServicesVersion(serverDetails)
457457
if err != nil {
458458
return "", "", nil, nil, err
459459
}
@@ -500,6 +500,7 @@ func CreateAuditCmd(c *components.Context) (string, string, *coreConfig.ServerDe
500500
SetInsecureTls(c.GetBoolFlagValue(flags.InsecureTls)).
501501
SetNpmScope(c.GetStringFlagValue(flags.DepType)).
502502
SetPipRequirementsFile(c.GetStringFlagValue(flags.RequirementsFile)).
503+
SetMaxTreeDepth(c.GetStringFlagValue(flags.MaxTreeDepth)).
503504
SetExclusions(pluginsCommon.GetStringsArrFlagValue(c, flags.Exclusions))
504505
return xrayVersion, xscVersion, serverDetails, auditCmd, err
505506
}
@@ -713,7 +714,7 @@ func DockerScan(c *components.Context, image string) error {
713714
if err != nil {
714715
return err
715716
}
716-
xrayVersion, xscVersion, err := GetJfrogServicesVersion(serverDetails)
717+
xrayVersion, xscVersion, err := xsc.GetJfrogServicesVersion(serverDetails)
717718
if err != nil {
718719
return err
719720
}
@@ -747,26 +748,3 @@ func DockerScan(c *components.Context, image string) error {
747748
}
748749
return progressbar.ExecWithProgress(containerScanCommand)
749750
}
750-
751-
func GetJfrogServicesVersion(serverDetails *coreConfig.ServerDetails) (xrayVersion, xscVersion string, err error) {
752-
xrayManager, err := xray.CreateXrayServiceManager(serverDetails)
753-
if err != nil {
754-
return
755-
}
756-
xrayVersion, err = xrayManager.GetVersion()
757-
if err != nil {
758-
return
759-
}
760-
log.Debug("Xray version: " + xrayVersion)
761-
xscService, err := xsc.CreateXscService(xrayVersion, serverDetails)
762-
if err != nil {
763-
return
764-
}
765-
xscVersion, e := xscService.GetVersion()
766-
if e != nil {
767-
log.Debug("Using Xray: " + e.Error())
768-
return
769-
}
770-
log.Debug("XSC version: " + xscVersion)
771-
return
772-
}

commands/audit/sca/pnpm/pnpm.go

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ import (
1010
"github.com/jfrog/gofrog/datastructures"
1111
"github.com/jfrog/gofrog/io"
1212
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
13-
"golang.org/x/exp/maps"
14-
"golang.org/x/exp/slices"
15-
1613
"github.com/jfrog/jfrog-cli-security/commands/audit/sca"
1714
"github.com/jfrog/jfrog-cli-security/commands/audit/sca/npm"
1815
"github.com/jfrog/jfrog-cli-security/utils"
@@ -21,6 +18,7 @@ import (
2118
"github.com/jfrog/jfrog-client-go/utils/errorutils"
2219
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
2320
"github.com/jfrog/jfrog-client-go/utils/log"
21+
"golang.org/x/exp/maps"
2422

2523
biutils "github.com/jfrog/build-info-go/utils"
2624
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
@@ -123,13 +121,17 @@ func installProjectIfNeeded(pnpmExecPath, workingDir string) (dirForDependencies
123121
err = fmt.Errorf("failed copying project to temp dir: %w", err)
124122
return
125123
}
126-
err = getPnpmCmd(pnpmExecPath, dirForDependenciesCalculation, "install", npm.IgnoreScriptsFlag).GetCmd().Run()
124+
output, err := getPnpmCmd(pnpmExecPath, dirForDependenciesCalculation, "install", npm.IgnoreScriptsFlag).GetCmd().CombinedOutput()
125+
if err != nil {
126+
err = fmt.Errorf("failed to install project: %w\n%s", err, string(output))
127+
}
127128
return
128129
}
129130

130131
// Run 'pnpm ls ...' command (project must be installed) and parse the returned result to create a dependencies trees for the projects.
131132
func calculateDependencies(executablePath, workingDir string, params utils.AuditParams) (dependencyTrees []*xrayUtils.GraphNode, uniqueDeps []string, err error) {
132-
lsArgs := append([]string{"--depth", "Infinity", "--json", "--long"}, params.Args()...)
133+
lsArgs := append([]string{"--depth", params.MaxTreeDepth(), "--json", "--long"}, params.Args()...)
134+
log.Debug("Running Pnpm ls command with args:", lsArgs)
133135
npmLsCmdContent, err := getPnpmCmd(executablePath, workingDir, "ls", lsArgs...).RunWithOutput()
134136
if err != nil {
135137
return
@@ -163,13 +165,13 @@ func createProjectDependenciesTree(project pnpmLsProject) map[string]xray.DepTre
163165
for depName, dependency := range project.Dependencies {
164166
directDependency := getDependencyId(depName, dependency.Version)
165167
directDependencies = append(directDependencies, directDependency)
166-
appendTransitiveDependencies(directDependency, dependency.Dependencies, treeMap)
168+
appendTransitiveDependencies(directDependency, dependency.Dependencies, &treeMap)
167169
}
168170
// Handle dev-dependencies
169171
for depName, dependency := range project.DevDependencies {
170172
directDependency := getDependencyId(depName, dependency.Version)
171173
directDependencies = append(directDependencies, directDependency)
172-
appendTransitiveDependencies(directDependency, dependency.Dependencies, treeMap)
174+
appendTransitiveDependencies(directDependency, dependency.Dependencies, &treeMap)
173175
}
174176
if len(directDependencies) > 0 {
175177
treeMap[getDependencyId(project.Name, project.Version)] = xray.DepTreeNode{Children: directDependencies}
@@ -182,21 +184,15 @@ func getDependencyId(depName, version string) string {
182184
return techutils.Npm.GetPackageTypeId() + depName + ":" + version
183185
}
184186

185-
func appendTransitiveDependencies(parent string, dependencies map[string]pnpmLsDependency, result map[string]xray.DepTreeNode) {
187+
func appendTransitiveDependencies(parent string, dependencies map[string]pnpmLsDependency, result *map[string]xray.DepTreeNode) {
186188
for depName, dependency := range dependencies {
187189
dependencyId := getDependencyId(depName, dependency.Version)
188-
if node, ok := result[parent]; ok {
189-
node.Children = appendUniqueChild(node.Children, dependencyId)
190+
if node, ok := (*result)[parent]; ok {
191+
node.Children = append(node.Children, dependencyId)
192+
(*result)[parent] = node
190193
} else {
191-
result[parent] = xray.DepTreeNode{Children: []string{dependencyId}}
194+
(*result)[parent] = xray.DepTreeNode{Children: []string{dependencyId}}
192195
}
193196
appendTransitiveDependencies(dependencyId, dependency.Dependencies, result)
194197
}
195198
}
196-
197-
func appendUniqueChild(children []string, candidateDependency string) []string {
198-
if slices.Contains(children, candidateDependency) {
199-
return children
200-
}
201-
return append(children, candidateDependency)
202-
}

commands/audit/sca/pnpm/pnpm_test.go

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package pnpm
22

33
import (
4-
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
5-
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
64
"path/filepath"
5+
"sort"
76
"testing"
87

8+
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
9+
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
10+
911
"github.com/stretchr/testify/assert"
1012
"github.com/stretchr/testify/require"
1113

@@ -16,6 +18,70 @@ import (
1618
"github.com/jfrog/jfrog-cli-security/utils"
1719
)
1820

21+
func TestBuildDependencyTreeLimitedDepth(t *testing.T) {
22+
// Create and change directory to test workspace
23+
_, cleanUp := sca.CreateTestWorkspace(t, filepath.Join("projects", "package-managers", "npm", "npm-big-tree"))
24+
defer cleanUp()
25+
testCases := []struct {
26+
name string
27+
treeDepth string
28+
expectedUniqueDeps []string
29+
expectedTree *xrayUtils.GraphNode
30+
}{
31+
{
32+
name: "Only direct dependencies",
33+
treeDepth: "0",
34+
expectedUniqueDeps: []string{
35+
"npm://zen-website:1.0.0",
36+
"npm://balaganjs:1.0.0",
37+
},
38+
expectedTree: &xrayUtils.GraphNode{
39+
Id: "npm://zen-website:1.0.0",
40+
Nodes: []*xrayUtils.GraphNode{{Id: "npm://balaganjs:1.0.0"}},
41+
},
42+
},
43+
{
44+
name: "With transitive dependencies",
45+
treeDepth: "1",
46+
expectedUniqueDeps: []string{
47+
"npm://axios:1.7.9",
48+
"npm://balaganjs:1.0.0",
49+
"npm://yargs:13.3.0",
50+
"npm://zen-website:1.0.0",
51+
},
52+
expectedTree: &xrayUtils.GraphNode{
53+
Id: "npm://zen-website:1.0.0",
54+
Nodes: []*xrayUtils.GraphNode{
55+
{
56+
Id: "npm://balaganjs:1.0.0",
57+
Nodes: []*xrayUtils.GraphNode{{Id: "npm://axios:1.7.9"}, {Id: "npm://yargs:13.3.0"}},
58+
},
59+
},
60+
},
61+
},
62+
}
63+
64+
for _, testCase := range testCases {
65+
t.Run(testCase.name, func(t *testing.T) {
66+
// Build dependency tree
67+
params := &utils.AuditBasicParams{}
68+
rootNode, uniqueDeps, err := BuildDependencyTree(params.SetMaxTreeDepth(testCase.treeDepth))
69+
require.NoError(t, err)
70+
sort.Slice(uniqueDeps, func(i, j int) bool {
71+
return uniqueDeps[i] < uniqueDeps[j]
72+
})
73+
// Validations
74+
assert.ElementsMatch(t, uniqueDeps, testCase.expectedUniqueDeps, "First is actual, Second is Expected")
75+
if assert.Len(t, rootNode, 1) {
76+
assert.Equal(t, rootNode[0].Id, testCase.expectedTree.Id)
77+
if !tests.CompareTree(testCase.expectedTree, rootNode[0]) {
78+
t.Error("expected:", testCase.expectedTree.Nodes, "got:", rootNode[0].Nodes)
79+
}
80+
}
81+
})
82+
}
83+
}
84+
1985
func TestBuildDependencyTree(t *testing.T) {
2086
// Create and change directory to test workspace
2187
_, cleanUp := sca.CreateTestWorkspace(t, filepath.Join("projects", "package-managers", "npm", "npm-no-lock"))

commands/enrich/enrich.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package enrich
22

33
import (
4-
"encoding/json"
54
"encoding/xml"
65
"errors"
76
"fmt"
7+
"github.com/jfrog/jfrog-cli-security/utils/results/output"
88
"os"
99
"os/exec"
1010
"path/filepath"
@@ -17,7 +17,6 @@ import (
1717
"github.com/jfrog/jfrog-cli-security/commands/enrich/enrichgraph"
1818
"github.com/jfrog/jfrog-cli-security/utils"
1919
"github.com/jfrog/jfrog-cli-security/utils/results"
20-
"github.com/jfrog/jfrog-cli-security/utils/results/output"
2120
"github.com/jfrog/jfrog-cli-security/utils/techutils"
2221
"github.com/jfrog/jfrog-cli-security/utils/xray"
2322
"github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns"
@@ -27,6 +26,7 @@ import (
2726
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
2827
"github.com/jfrog/jfrog-client-go/utils/log"
2928
"github.com/jfrog/jfrog-client-go/xray/services"
29+
orderedJson "github.com/virtuald/go-ordered-json"
3030
)
3131

3232
type FileContext func(string) parallel.TaskFunc
@@ -75,8 +75,8 @@ func AppendVulnsToJson(cmdResults *results.SecurityCommandResults) error {
7575
if err != nil {
7676
return fmt.Errorf("error reading file: %s", err.Error())
7777
}
78-
var data map[string]interface{}
79-
err = json.Unmarshal(fileContent, &data)
78+
var data orderedJson.OrderedObject
79+
err = orderedJson.Unmarshal(fileContent, &data)
8080
if err != nil {
8181
return fmt.Errorf("error parsing JSON: %s", err.Error())
8282
}
@@ -93,7 +93,7 @@ func AppendVulnsToJson(cmdResults *results.SecurityCommandResults) error {
9393
vulnerabilities = append(vulnerabilities, vulnerability)
9494
}
9595
}
96-
data["vulnerabilities"] = vulnerabilities
96+
data = append(data, orderedJson.Member{Key: "vulnerabilities", Value: vulnerabilities})
9797
return output.PrintJson(data)
9898
}
9999

commands/scan/scan.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/jfrog/jfrog-cli-security/utils/techutils"
2626
"github.com/jfrog/jfrog-cli-security/utils/xray"
2727
"github.com/jfrog/jfrog-cli-security/utils/xray/scangraph"
28+
"github.com/jfrog/jfrog-cli-security/utils/xsc"
2829
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
2930
"golang.org/x/sync/errgroup"
3031

@@ -625,5 +626,9 @@ func directDepsListFromVulnerabilities(scanResult ...services.ScanResponse) *[]s
625626
}
626627

627628
func ConditionalUploadDefaultScanFunc(serverDetails *config.ServerDetails, fileSpec *spec.SpecFiles, threads int, scanOutputFormat format.OutputFormat) error {
628-
return NewScanCommand().SetServerDetails(serverDetails).SetSpec(fileSpec).SetThreads(threads).SetOutputFormat(scanOutputFormat).SetFail(true).SetPrintExtendedTable(false).Run()
629+
xrayVersion, xscVersion, err := xsc.GetJfrogServicesVersion(serverDetails)
630+
if err != nil {
631+
return err
632+
}
633+
return NewScanCommand().SetServerDetails(serverDetails).SetXrayVersion(xrayVersion).SetXscVersion(xscVersion).SetSpec(fileSpec).SetThreads(threads).SetOutputFormat(scanOutputFormat).SetFail(true).SetPrintExtendedTable(false).Run()
629634
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ require (
1616
github.com/owenrumney/go-sarif/v2 v2.3.0
1717
github.com/stretchr/testify v1.9.0
1818
github.com/urfave/cli v1.22.16
19+
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74
1920
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
2021
golang.org/x/sync v0.10.0
2122
golang.org/x/text v0.21.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
257257
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
258258
github.com/vbauerster/mpb/v8 v8.8.3 h1:dTOByGoqwaTJYPubhVz3lO5O6MK553XVgUo33LdnNsQ=
259259
github.com/vbauerster/mpb/v8 v8.8.3/go.mod h1:JfCCrtcMsJwP6ZwMn9e5LMnNyp3TVNpUWWkN+nd4EWk=
260+
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo=
261+
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c=
260262
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
261263
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
262264
github.com/xanzy/go-gitlab v0.110.0 h1:hsFIFp01v/0D0sdUXoZfRk6CROzZbHQplk6NzKSFKhc=

jas/analyzermanager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
const (
2525
ApplicabilityFeatureId = "contextual_analysis"
2626
AnalyzerManagerZipName = "analyzerManager.zip"
27-
defaultAnalyzerManagerVersion = "1.12.0"
27+
defaultAnalyzerManagerVersion = "1.12.2"
2828
analyzerManagerDownloadPath = "xsc-gen-exe-analyzer-manager-local/v1"
2929
analyzerManagerDirName = "analyzerManager"
3030
analyzerManagerExecutableName = "analyzerManager"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "zen-website",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"publishConfig": {
7+
"registry": "http://artifactory-unified.soleng-us.jfrog.team/artifactory/api/npm/npm/"
8+
},
9+
"scripts": {
10+
"dev": "nodemon ./index.js",
11+
"ui": "browser-sync start --config bs-config.js"
12+
},
13+
"keywords": [],
14+
"author": "",
15+
"license": "ISC",
16+
"dependencies": {
17+
"balaganjs": "1.0.0"
18+
}
19+
}
20+

0 commit comments

Comments
 (0)