Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion commands/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,6 @@ func populateScanTargets(cmdResults *results.SecurityCommandResults, params *Aud
bom.GenerateSbomForTarget(params.BomGenerator().WithOptions(
buildinfo.WithDescriptors(targetResult.GetDescriptors()),
xrayplugin.WithSnippetDetection(shouldIncludeSnippetDetection(params)),
xrayplugin.WithServerDetails(params.serverDetails),
),
bom.SbomGeneratorParams{
Target: targetResult,
Expand Down
6 changes: 5 additions & 1 deletion commands/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,11 @@ func (scanCmd *ScanCommand) prepareForScan(cmdResults *results.SecurityCommandRe
scaErrGroup := new(errgroup.Group)
if cmdResults.ResultContext.IncludeSbom || utils.IsScanRequested(cmdResults.CmdType, utils.ScaScan, cmdResults.IsScanRequestedByCentralConfig(utils.ScaScan), scanCmd.scansToPerform...) {
scaErrGroup.Go(func() error {
return scanCmd.bomGenerator.WithOptions(indexer.WithXray(xrayManager, scanCmd.xrayVersion), indexer.WithBypassArchiveLimits(scanCmd.bypassArchiveLimits)).PrepareGenerator()
return scanCmd.bomGenerator.WithOptions(
indexer.WithXray(xrayManager, scanCmd.xrayVersion),
indexer.WithBypassArchiveLimits(scanCmd.bypassArchiveLimits),
indexer.WithServerDetails(scanCmd.serverDetails),
).PrepareGenerator()
})
} else {
log.Debug("SCA scans were not initiated, so SCA scan preparation was skipped...")
Expand Down
38 changes: 38 additions & 0 deletions sca/bom/indexer/indexerbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"

"github.com/CycloneDX/cyclonedx-go"

"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
"github.com/jfrog/jfrog-client-go/utils/log"
Expand All @@ -24,12 +26,20 @@ import (
const (
indexingCommand = "graph"
fileNotSupportedExitCode = 3

XrayUrlEnvVariable = "JFROG_XRAY_PLATFORM_URL"
XrayUserEnvVariable = "JFROG_XRAY_USER"
// #nosec G101 -- Not credentials.
XrayPasswordEnvVariable = "JFROG_XRAY_PASSWORD"
// #nosec G101 -- Not credentials.
XrayTokenEnvVariable = "JFROG_XRAY_TOKEN"
)

// IndexerBomGenerator is a BomGenerator that uses the Xray Indexer to generate a CycloneDX SBOM.
// It indexes a file and converts the resulting component graph to a CycloneDX SBOM.
type IndexerBomGenerator struct {
bypassArchiveLimits bool
serverDetails *config.ServerDetails

xrayManager *xray.XrayServicesManager
xrayVersion string
Expand Down Expand Up @@ -59,6 +69,14 @@ func WithBypassArchiveLimits(bypass bool) bom.SbomGeneratorOption {
}
}

func WithServerDetails(serverDetails *config.ServerDetails) bom.SbomGeneratorOption {
return func(sg bom.SbomGenerator) {
if ibg, ok := sg.(*IndexerBomGenerator); ok {
ibg.serverDetails = serverDetails
}
}
}

func (ibg *IndexerBomGenerator) WithOptions(options ...bom.SbomGeneratorOption) bom.SbomGenerator {
for _, option := range options {
option(ibg)
Expand Down Expand Up @@ -116,12 +134,32 @@ func CreateTargetEmptySbom(target results.ScanTarget) *cyclonedx.BOM {
return sbom
}

func (ibg *IndexerBomGenerator) getIndexerEnvVars() utils.EnvironmentVariables {
platformEnv := utils.EnvironmentVariables{}
if ibg.serverDetails != nil {
platformEnv[XrayUrlEnvVariable] = ibg.serverDetails.XrayUrl
if ibg.serverDetails.AccessToken != "" {
platformEnv[XrayTokenEnvVariable] = ibg.serverDetails.AccessToken
} else {
platformEnv[XrayUserEnvVariable] = ibg.serverDetails.User
platformEnv[XrayPasswordEnvVariable] = ibg.serverDetails.Password
}
}
if len(platformEnv) == 0 {
return nil
}
return utils.EnvironmentVariables(utils.MergeMaps(utils.ToEnvVarsMap(os.Environ()), platformEnv))
}

func (ibg *IndexerBomGenerator) IndexFile(filePath string) (*xrayClientUtils.BinaryGraphNode, error) {
var indexerResults xrayClientUtils.BinaryGraphNode
indexerCmd := exec.Command(ibg.indexerPath, indexingCommand, filePath, "--temp-dir", ibg.indexerTempDir)
if ibg.bypassArchiveLimits {
indexerCmd.Args = append(indexerCmd.Args, "--bypass-archive-limits")
}
if envVars := ibg.getIndexerEnvVars(); len(envVars) > 0 {
indexerCmd.Env = envVars.ToCommandEnvVars()
}
var stderr bytes.Buffer
var stdout bytes.Buffer
indexerCmd.Stdout = &stdout
Expand Down
70 changes: 70 additions & 0 deletions sca/bom/indexer/indexerbom_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package indexer

import (
"testing"

"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestGetIndexerEnvVars(t *testing.T) {
tests := []struct {
name string
serverDetails *config.ServerDetails
wantKeys map[string]string
wantAbsent []string
}{
{
name: "nil server details",
serverDetails: nil,
wantAbsent: []string{XrayUrlEnvVariable, XrayUserEnvVariable, XrayPasswordEnvVariable, XrayTokenEnvVariable},
},
{
name: "access token preferred",
serverDetails: &config.ServerDetails{
XrayUrl: "https://xray.example/",
AccessToken: "tok",
User: "u",
Password: "p",
},
wantKeys: map[string]string{
XrayUrlEnvVariable: "https://xray.example/",
XrayTokenEnvVariable: "tok",
},
wantAbsent: []string{XrayUserEnvVariable, XrayPasswordEnvVariable},
},
{
name: "user and password",
serverDetails: &config.ServerDetails{
XrayUrl: "https://xray.example/",
User: "u",
Password: "p",
},
wantKeys: map[string]string{
XrayUrlEnvVariable: "https://xray.example/",
XrayUserEnvVariable: "u",
XrayPasswordEnvVariable: "p",
},
wantAbsent: []string{XrayTokenEnvVariable},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ibg := &IndexerBomGenerator{serverDetails: tt.serverDetails}
env := ibg.getIndexerEnvVars()
for k, v := range tt.wantKeys {
assert.Equal(t, v, env[k], "key %s", k)
}
for _, k := range tt.wantAbsent {
_, ok := env[k]
assert.False(t, ok, "key %s should be absent", k)
}
// When server details are set, env must include process env (PATH at minimum).
if tt.serverDetails != nil {
require.NotEmpty(t, env["PATH"])
}
})
}
}
6 changes: 0 additions & 6 deletions sca/bom/xrayplugin/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@ const (
defaultXrayLibPluginVersion = "1.4.0"

SnippetDetectionEnvVariable = "JFROG_XRAY_SNIPPET_SCAN_ENABLE"
XrayUrlEnvVariable = "JFROG_XRAY_PLATFORM_URL"
XrayUserEnvVariable = "JFROG_XRAY_USER"
// #nosec G101 -- Not credentials.
XrayPasswordEnvVariable = "JFROG_XRAY_PASSWORD"
// #nosec G101 -- Not credentials.
XrayTokenEnvVariable = "JFROG_XRAY_TOKEN"

xrayLibPluginRtRepository = "xray-scan-lib"
XrayLibPluginExecutableName = "xray-scan-plugin"
Expand Down
18 changes: 0 additions & 18 deletions sca/bom/xrayplugin/xraylibbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ type XrayLibBomGenerator struct {
binaryPath string
snippetDetection bool
specificTechs []techutils.Technology
ServerDetails *config.ServerDetails

// Artifactory Repository params
DownloadServerDetails *config.ServerDetails
Expand Down Expand Up @@ -70,14 +69,6 @@ func WithSnippetDetection(snippetDetection bool) bom.SbomGeneratorOption {
}
}

func WithServerDetails(serverDetails *config.ServerDetails) bom.SbomGeneratorOption {
return func(sg bom.SbomGenerator) {
if sbg, ok := sg.(*XrayLibBomGenerator); ok {
sbg.ServerDetails = serverDetails
}
}
}

func (sbg *XrayLibBomGenerator) WithOptions(options ...bom.SbomGeneratorOption) bom.SbomGenerator {
for _, option := range options {
option(sbg)
Expand Down Expand Up @@ -154,15 +145,6 @@ func (sbg *XrayLibBomGenerator) executeScanner(scanner plugin.Scanner, target re

func (sbg *XrayLibBomGenerator) getPluginEnvVars() utils.EnvironmentVariables {
envVars := utils.EnvironmentVariables{}
if sbg.ServerDetails != nil {
envVars[plugin.XrayUrlEnvVariable] = sbg.ServerDetails.XrayUrl
if sbg.ServerDetails.AccessToken != "" {
envVars[plugin.XrayTokenEnvVariable] = sbg.ServerDetails.AccessToken
} else {
envVars[plugin.XrayUserEnvVariable] = sbg.ServerDetails.User
envVars[plugin.XrayPasswordEnvVariable] = sbg.ServerDetails.Password
}
}
if sbg.snippetDetection {
envVars[plugin.SnippetDetectionEnvVariable] = "true"
}
Expand Down
Loading