diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 81b531e94..a29570a6c 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -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, diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 099f09465..ad9bfb80e 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -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...") diff --git a/sca/bom/indexer/indexerbom.go b/sca/bom/indexer/indexerbom.go index a468d0002..3d1871302 100644 --- a/sca/bom/indexer/indexerbom.go +++ b/sca/bom/indexer/indexerbom.go @@ -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" @@ -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 @@ -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) @@ -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 diff --git a/sca/bom/indexer/indexerbom_test.go b/sca/bom/indexer/indexerbom_test.go new file mode 100644 index 000000000..0f5f068d3 --- /dev/null +++ b/sca/bom/indexer/indexerbom_test.go @@ -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"]) + } + }) + } +} diff --git a/sca/bom/xrayplugin/plugin/plugin.go b/sca/bom/xrayplugin/plugin/plugin.go index c808f3256..00713c7db 100644 --- a/sca/bom/xrayplugin/plugin/plugin.go +++ b/sca/bom/xrayplugin/plugin/plugin.go @@ -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" diff --git a/sca/bom/xrayplugin/xraylibbom.go b/sca/bom/xrayplugin/xraylibbom.go index eaf342d04..908ef10af 100644 --- a/sca/bom/xrayplugin/xraylibbom.go +++ b/sca/bom/xrayplugin/xraylibbom.go @@ -23,7 +23,6 @@ type XrayLibBomGenerator struct { binaryPath string snippetDetection bool specificTechs []techutils.Technology - ServerDetails *config.ServerDetails // Artifactory Repository params DownloadServerDetails *config.ServerDetails @@ -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) @@ -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" }