diff --git a/artifactory/commands/golang/go.go b/artifactory/commands/golang/go.go index 93ce330e0..68ab8002f 100644 --- a/artifactory/commands/golang/go.go +++ b/artifactory/commands/golang/go.go @@ -219,7 +219,7 @@ func copyGoPackageFiles(destPath, packageName, rtTargetRepo string, authArtDetai return fmt.Errorf("couldn't find suitable package files: %s", packageFilesPath) } // Set permission recursively - return coreutils.SetPermissionsRecursively(destPath, 0700) + return coreutils.SetPermissionsRecursively(destPath, 0755) } // getPackageFilePathFromArtifactory returns a string that represents the package files cache path. diff --git a/artifactory/commands/npm/npmcommand.go b/artifactory/commands/npm/npmcommand.go index c6b97cff7..7d6061a2e 100644 --- a/artifactory/commands/npm/npmcommand.go +++ b/artifactory/commands/npm/npmcommand.go @@ -63,108 +63,108 @@ func NewNpmCiCommand() *NpmCommand { return &NpmCommand{cmdName: "ci", internalCommandName: "rt_npm_ci"} } -func (ca *NpmCommand) CommandName() string { - return ca.internalCommandName +func (nc *NpmCommand) CommandName() string { + return nc.internalCommandName } -func (ca *NpmCommand) SetConfigFilePath(configFilePath string) *NpmCommand { - ca.configFilePath = configFilePath - return ca +func (nc *NpmCommand) SetConfigFilePath(configFilePath string) *NpmCommand { + nc.configFilePath = configFilePath + return nc } -func (ca *NpmCommand) SetArgs(args []string) *NpmCommand { - ca.npmArgs = args - return ca +func (nc *NpmCommand) SetArgs(args []string) *NpmCommand { + nc.npmArgs = args + return nc } -func (ca *NpmCommand) SetRepoConfig(conf *utils.RepositoryConfig) *NpmCommand { +func (nc *NpmCommand) SetRepoConfig(conf *utils.RepositoryConfig) *NpmCommand { serverDetails, _ := conf.ServerDetails() - ca.SetRepo(conf.TargetRepo()).SetServerDetails(serverDetails) - return ca + nc.SetRepo(conf.TargetRepo()).SetServerDetails(serverDetails) + return nc } -func (ca *NpmCommand) SetServerDetails(serverDetails *config.ServerDetails) *NpmCommand { - ca.serverDetails = serverDetails - return ca +func (nc *NpmCommand) SetServerDetails(serverDetails *config.ServerDetails) *NpmCommand { + nc.serverDetails = serverDetails + return nc } -func (ca *NpmCommand) SetRepo(repo string) *NpmCommand { - ca.repo = repo - return ca +func (nc *NpmCommand) SetRepo(repo string) *NpmCommand { + nc.repo = repo + return nc } -func (ca *NpmCommand) Init() error { +func (nc *NpmCommand) Init() error { // Read config file. - log.Debug("Preparing to read the config file", ca.configFilePath) - vConfig, err := utils.ReadConfigFile(ca.configFilePath, utils.YAML) + log.Debug("Preparing to read the config file", nc.configFilePath) + vConfig, err := utils.ReadConfigFile(nc.configFilePath, utils.YAML) if err != nil { return err } // Extract resolution params. - resolverParams, err := utils.GetRepoConfigByPrefix(ca.configFilePath, utils.ProjectConfigResolverPrefix, vConfig) + resolverParams, err := utils.GetRepoConfigByPrefix(nc.configFilePath, utils.ProjectConfigResolverPrefix, vConfig) if err != nil { return err } - _, _, _, filteredNpmArgs, buildConfiguration, err := commandUtils.ExtractNpmOptionsFromArgs(ca.npmArgs) + _, _, _, filteredNpmArgs, buildConfiguration, err := commandUtils.ExtractNpmOptionsFromArgs(nc.npmArgs) if err != nil { return err } - ca.SetRepoConfig(resolverParams).SetArgs(filteredNpmArgs).SetBuildConfiguration(buildConfiguration) + nc.SetRepoConfig(resolverParams).SetArgs(filteredNpmArgs).SetBuildConfiguration(buildConfiguration) return nil } -func (ca *NpmCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *NpmCommand { - ca.buildConfiguration = buildConfiguration - return ca +func (nc *NpmCommand) SetBuildConfiguration(buildConfiguration *utils.BuildConfiguration) *NpmCommand { + nc.buildConfiguration = buildConfiguration + return nc } -func (ca *NpmCommand) ServerDetails() (*config.ServerDetails, error) { - return ca.serverDetails, nil +func (nc *NpmCommand) ServerDetails() (*config.ServerDetails, error) { + return nc.serverDetails, nil } -func (ca *NpmCommand) RestoreNpmrcFunc() func() error { - return ca.restoreNpmrcFunc +func (nc *NpmCommand) RestoreNpmrcFunc() func() error { + return nc.restoreNpmrcFunc } -func (ca *NpmCommand) PreparePrerequisites(repo string) error { +func (nc *NpmCommand) PreparePrerequisites(repo string) error { log.Debug("Preparing prerequisites...") var err error - ca.npmVersion, ca.executablePath, err = biutils.GetNpmVersionAndExecPath(log.Logger) + nc.npmVersion, nc.executablePath, err = biutils.GetNpmVersionAndExecPath(log.Logger) if err != nil { return err } - if ca.npmVersion.Compare(minSupportedNpmVersion) > 0 { + if nc.npmVersion.Compare(minSupportedNpmVersion) > 0 { return errorutils.CheckErrorf( - "JFrog CLI npm %s command requires npm client version %s or higher. The Current version is: %s", ca.cmdName, minSupportedNpmVersion, ca.npmVersion.GetVersion()) + "JFrog CLI npm %s command requires npm client version %s or higher. The Current version is: %s", nc.cmdName, minSupportedNpmVersion, nc.npmVersion.GetVersion()) } - if err := ca.setJsonOutput(); err != nil { + if err = nc.setJsonOutput(); err != nil { return err } - ca.workingDirectory, err = coreutils.GetWorkingDirectory() + nc.workingDirectory, err = coreutils.GetWorkingDirectory() if err != nil { return err } - log.Debug("Working directory set to:", ca.workingDirectory) - if err = ca.setArtifactoryAuth(); err != nil { + log.Debug("Working directory set to:", nc.workingDirectory) + if err = nc.setArtifactoryAuth(); err != nil { return err } - ca.npmAuth, ca.registry, err = commandUtils.GetArtifactoryNpmRepoDetails(repo, &ca.authArtDetails) + nc.npmAuth, nc.registry, err = commandUtils.GetArtifactoryNpmRepoDetails(repo, &nc.authArtDetails) if err != nil { return err } - return ca.setRestoreNpmrcFunc() + return nc.setRestoreNpmrcFunc() } -func (ca *NpmCommand) setRestoreNpmrcFunc() error { - restoreNpmrcFunc, err := commandUtils.BackupFile(filepath.Join(ca.workingDirectory, npmrcFileName), npmrcBackupFileName) +func (nc *NpmCommand) setRestoreNpmrcFunc() error { + restoreNpmrcFunc, err := commandUtils.BackupFile(filepath.Join(nc.workingDirectory, npmrcFileName), npmrcBackupFileName) if err != nil { return err } - ca.restoreNpmrcFunc = func() error { + nc.restoreNpmrcFunc = func() error { if unsetEnvErr := os.Unsetenv(npmConfigAuthEnv); unsetEnvErr != nil { return unsetEnvErr } @@ -173,43 +173,43 @@ func (ca *NpmCommand) setRestoreNpmrcFunc() error { return nil } -func (ca *NpmCommand) setArtifactoryAuth() error { - authArtDetails, err := ca.serverDetails.CreateArtAuthConfig() +func (nc *NpmCommand) setArtifactoryAuth() error { + authArtDetails, err := nc.serverDetails.CreateArtAuthConfig() if err != nil { return err } if authArtDetails.GetSshAuthHeaders() != nil { return errorutils.CheckErrorf("SSH authentication is not supported in this command") } - ca.authArtDetails = authArtDetails + nc.authArtDetails = authArtDetails return nil } -func (ca *NpmCommand) setJsonOutput() error { - jsonOutput, err := npm.ConfigGet(ca.npmArgs, "json", ca.executablePath) +func (nc *NpmCommand) setJsonOutput() error { + jsonOutput, err := npm.ConfigGet(nc.npmArgs, "json", nc.executablePath) if err != nil { return err } // In case of --json=, the value of json is set to 'true', but the result from the command is not 'true' - ca.jsonOutput = jsonOutput != "false" + nc.jsonOutput = jsonOutput != "false" return nil } -func (ca *NpmCommand) processConfigLine(configLine string) (filteredLine string, err error) { +func (nc *NpmCommand) processConfigLine(configLine string) (filteredLine string, err error) { splitOption := strings.SplitN(configLine, "=", 2) key := strings.TrimSpace(splitOption[0]) validLine := len(splitOption) == 2 && isValidKey(key) if !validLine { if strings.HasPrefix(splitOption[0], "@") { // Override scoped registries (@scope = xyz) - return fmt.Sprintf("%s = %s\n", splitOption[0], ca.registry), nil + return fmt.Sprintf("%s = %s\n", splitOption[0], nc.registry), nil } return } value := strings.TrimSpace(splitOption[1]) if key == "_auth" { - return "", ca.setNpmConfigAuthEnv(value) + return "", nc.setNpmConfigAuthEnv(value) } if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") { return addArrayConfigs(key, value), nil @@ -218,11 +218,11 @@ func (ca *NpmCommand) processConfigLine(configLine string) (filteredLine string, return fmt.Sprintf("%s\n", configLine), err } -func (ca *NpmCommand) setNpmConfigAuthEnv(value string) error { +func (nc *NpmCommand) setNpmConfigAuthEnv(value string) error { // Check if the npm version is bigger or equal to 9.3.1 - if ca.npmVersion.Compare(npmVersionForLegacyEnv) <= 0 { + if nc.npmVersion.Compare(npmVersionForLegacyEnv) <= 0 { // Get registry name without the protocol name but including the '//' - registryWithoutProtocolName := ca.registry[strings.Index(ca.registry, "://")+1:] + registryWithoutProtocolName := nc.registry[strings.Index(nc.registry, "://")+1:] // Set "npm_config_//:_auth" environment variable to allow authentication with Artifactory scopedRegistryEnv := fmt.Sprintf(npmConfigAuthEnv, registryWithoutProtocolName) return os.Setenv(scopedRegistryEnv, value) @@ -232,16 +232,16 @@ func (ca *NpmCommand) setNpmConfigAuthEnv(value string) error { return os.Setenv(npmLegacyConfigAuthEnv, value) } -func (ca *NpmCommand) prepareConfigData(data []byte) ([]byte, error) { +func (nc *NpmCommand) prepareConfigData(data []byte) ([]byte, error) { var filteredConf []string - configString := string(data) + "\n" + ca.npmAuth + configString := string(data) + "\n" + nc.npmAuth scanner := bufio.NewScanner(strings.NewReader(configString)) for scanner.Scan() { currOption := scanner.Text() if currOption == "" { continue } - filteredLine, err := ca.processConfigLine(currOption) + filteredLine, err := nc.processConfigLine(currOption) if err != nil { return nil, errorutils.CheckError(err) } @@ -253,88 +253,87 @@ func (ca *NpmCommand) prepareConfigData(data []byte) ([]byte, error) { return nil, errorutils.CheckError(err) } - filteredConf = append(filteredConf, "json = ", strconv.FormatBool(ca.jsonOutput), "\n") - filteredConf = append(filteredConf, "registry = ", ca.registry, "\n") + filteredConf = append(filteredConf, "json = ", strconv.FormatBool(nc.jsonOutput), "\n") + filteredConf = append(filteredConf, "registry = ", nc.registry, "\n") return []byte(strings.Join(filteredConf, "")), nil } -func (ca *NpmCommand) CreateTempNpmrc() error { - log.Debug("Creating project .npmrc file.") - data, err := npm.GetConfigList(ca.npmArgs, ca.executablePath) +func (nc *NpmCommand) CreateTempNpmrc() error { + data, err := npm.GetConfigList(nc.npmArgs, nc.executablePath) if err != nil { return err } - configData, err := ca.prepareConfigData(data) + configData, err := nc.prepareConfigData(data) if err != nil { return errorutils.CheckError(err) } - if err = removeNpmrcIfExists(ca.workingDirectory); err != nil { + if err = removeNpmrcIfExists(nc.workingDirectory); err != nil { return err } - - return errorutils.CheckError(os.WriteFile(filepath.Join(ca.workingDirectory, npmrcFileName), configData, 0600)) + log.Debug("Creating temporary .npmrc file.") + return errorutils.CheckError(os.WriteFile(filepath.Join(nc.workingDirectory, npmrcFileName), configData, 0755)) } -func (ca *NpmCommand) Run() (err error) { - if err = ca.PreparePrerequisites(ca.repo); err != nil { +func (nc *NpmCommand) Run() (err error) { + if err = nc.PreparePrerequisites(nc.repo); err != nil { return } defer func() { - err = errors.Join(err, ca.restoreNpmrcFunc()) + err = errors.Join(err, nc.restoreNpmrcFunc()) }() - if err = ca.CreateTempNpmrc(); err != nil { + if err = nc.CreateTempNpmrc(); err != nil { return } - if err = ca.prepareBuildInfoModule(); err != nil { + if err = nc.prepareBuildInfoModule(); err != nil { return } - err = ca.collectDependencies() + err = nc.collectDependencies() return } -func (ca *NpmCommand) prepareBuildInfoModule() error { +func (nc *NpmCommand) prepareBuildInfoModule() error { var err error - if ca.collectBuildInfo { - ca.collectBuildInfo, err = ca.buildConfiguration.IsCollectBuildInfo() + if nc.collectBuildInfo { + nc.collectBuildInfo, err = nc.buildConfiguration.IsCollectBuildInfo() if err != nil { return err } } // Build-info should not be created when installing a single package (npm install ). - if ca.collectBuildInfo && len(filterFlags(ca.npmArgs)) > 0 { + if nc.collectBuildInfo && len(filterFlags(nc.npmArgs)) > 0 { log.Info("Build-info dependencies collection is not supported for installations of single packages. Build-info creation is skipped.") - ca.collectBuildInfo = false + nc.collectBuildInfo = false } - buildName, err := ca.buildConfiguration.GetBuildName() + buildName, err := nc.buildConfiguration.GetBuildName() if err != nil { return err } - buildNumber, err := ca.buildConfiguration.GetBuildNumber() + buildNumber, err := nc.buildConfiguration.GetBuildNumber() if err != nil { return err } buildInfoService := utils.CreateBuildInfoService() - npmBuild, err := buildInfoService.GetOrCreateBuildWithProject(buildName, buildNumber, ca.buildConfiguration.GetProject()) + npmBuild, err := buildInfoService.GetOrCreateBuildWithProject(buildName, buildNumber, nc.buildConfiguration.GetProject()) if err != nil { return errorutils.CheckError(err) } - ca.buildInfoModule, err = npmBuild.AddNpmModule(ca.workingDirectory) + nc.buildInfoModule, err = npmBuild.AddNpmModule(nc.workingDirectory) if err != nil { return errorutils.CheckError(err) } - ca.buildInfoModule.SetCollectBuildInfo(ca.collectBuildInfo) - if ca.buildConfiguration.GetModule() != "" { - ca.buildInfoModule.SetName(ca.buildConfiguration.GetModule()) + nc.buildInfoModule.SetCollectBuildInfo(nc.collectBuildInfo) + if nc.buildConfiguration.GetModule() != "" { + nc.buildInfoModule.SetName(nc.buildConfiguration.GetModule()) } return nil } -func (ca *NpmCommand) collectDependencies() error { - ca.buildInfoModule.SetNpmArgs(append([]string{ca.cmdName}, ca.npmArgs...)) - return errorutils.CheckError(ca.buildInfoModule.Build()) +func (nc *NpmCommand) collectDependencies() error { + nc.buildInfoModule.SetNpmArgs(append([]string{nc.cmdName}, nc.npmArgs...)) + return errorutils.CheckError(nc.buildInfoModule.Build()) } // Gets a config with value which is an array @@ -362,7 +361,7 @@ func removeNpmrcIfExists(workingDirectory string) error { return errorutils.CheckError(err) } - log.Debug("Removing Existing .npmrc file") + log.Debug("Removing existing .npmrc file") return errorutils.CheckError(os.Remove(filepath.Join(workingDirectory, npmrcFileName))) } diff --git a/artifactory/commands/transferconfig/transferconfig.go b/artifactory/commands/transferconfig/transferconfig.go index c0e1da318..796e99c86 100644 --- a/artifactory/commands/transferconfig/transferconfig.go +++ b/artifactory/commands/transferconfig/transferconfig.go @@ -347,13 +347,11 @@ func (tcc *TransferConfigCommand) exportSourceArtifactory() (string, func() erro } // Do export - trueValue := true - falseValue := false exportParams := services.ExportParams{ ExportPath: exportPath, - IncludeMetadata: &falseValue, + IncludeMetadata: clientutils.Pointer(false), Verbose: &tcc.verbose, - ExcludeContent: &trueValue, + ExcludeContent: clientutils.Pointer(true), } cleanUp := func() error { return fileutils.RemoveTempDir(exportPath) } if err = tcc.SourceArtifactoryManager.Export(exportParams); err != nil { diff --git a/artifactory/commands/transferconfigmerge/transferconfigmerge_test.go b/artifactory/commands/transferconfigmerge/transferconfigmerge_test.go index b18a52d27..48d184c83 100644 --- a/artifactory/commands/transferconfigmerge/transferconfigmerge_test.go +++ b/artifactory/commands/transferconfigmerge/transferconfigmerge_test.go @@ -3,6 +3,7 @@ package transferconfigmerge import ( "github.com/jfrog/jfrog-client-go/access/services" artifactoryServices "github.com/jfrog/jfrog-client-go/artifactory/services" + clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/stretchr/testify/assert" "strings" "testing" @@ -62,17 +63,15 @@ func createProjects(sameKey, sameName, sameDescription, sameAdmin, sameQuotaByte if !sameDescription { targetDescription = sourceDescription + "Target" } - trueValue := true - falseValue := false if !sameAdmin { - targetAdmin.ManageMembers = &trueValue - targetAdmin.IndexResources = &trueValue + targetAdmin.ManageMembers = clientutils.Pointer(true) + targetAdmin.IndexResources = clientutils.Pointer(true) } - var sourceSoftLimit = &falseValue - var targetSoftLimit = &falseValue + var sourceSoftLimit = clientutils.Pointer(false) + var targetSoftLimit = clientutils.Pointer(false) if !sameSoftLimit { - targetSoftLimit = &trueValue + targetSoftLimit = clientutils.Pointer(true) } if !sameQuotaBytes { targetQuotaBytes += 125 @@ -83,24 +82,21 @@ func createProjects(sameKey, sameName, sameDescription, sameAdmin, sameQuotaByte } func TestCompareInterfaces(t *testing.T) { - trueValue := true - falseValue := false - first := artifactoryServices.DockerRemoteRepositoryParams{} first.RemoteRepositoryBaseParams = artifactoryServices.RemoteRepositoryBaseParams{Password: "ppppp"} first.Key = "string1" - first.BlackedOut = &trueValue - first.AssumedOfflinePeriodSecs = 1111 + first.BlackedOut = clientutils.Pointer(true) + first.AssumedOfflinePeriodSecs = clientutils.Pointer(1111) first.Environments = []string{"111", "aaa"} - first.ContentSynchronisation = &artifactoryServices.ContentSynchronisation{Enabled: &trueValue} + first.ContentSynchronisation = &artifactoryServices.ContentSynchronisation{Enabled: clientutils.Pointer(true)} second := artifactoryServices.DockerRemoteRepositoryParams{} second.RemoteRepositoryBaseParams = artifactoryServices.RemoteRepositoryBaseParams{Password: "sssss"} second.Key = "string2" - second.BlackedOut = &falseValue - second.AssumedOfflinePeriodSecs = 2222 + second.BlackedOut = clientutils.Pointer(false) + second.AssumedOfflinePeriodSecs = clientutils.Pointer(2222) second.Environments = []string{"222", "bbb"} - second.ContentSynchronisation = &artifactoryServices.ContentSynchronisation{Enabled: &falseValue} + second.ContentSynchronisation = &artifactoryServices.ContentSynchronisation{Enabled: clientutils.Pointer(false)} diff, err := compareInterfaces(first, second, filteredRepoKeys...) assert.NoError(t, err) diff --git a/artifactory/commands/utils/npmcmdutils.go b/artifactory/commands/utils/npmcmdutils.go index 883fa88d2..4ed2ea571 100644 --- a/artifactory/commands/utils/npmcmdutils.go +++ b/artifactory/commands/utils/npmcmdutils.go @@ -118,18 +118,20 @@ func ExtractNpmOptionsFromArgs(args []string) (detailedSummary, xrayScan bool, s // If there is no file at filePath, a backup file won't be created, and the restore function will delete the file at filePath. func BackupFile(filePath, backupFileName string) (restore func() error, err error) { fileInfo, err := os.Stat(filePath) - if err != nil { + if errorutils.CheckError(err) != nil { if os.IsNotExist(err) { - return createRestoreFileFunc(filePath, backupFileName), nil + restore = createRestoreFileFunc(filePath, backupFileName) + err = nil } - return nil, errorutils.CheckError(err) + return } if err = cloneFile(filePath, backupFileName, fileInfo.Mode()); err != nil { - return nil, err + return } log.Debug("The file", filePath, "was backed up successfully to", backupFileName) - return createRestoreFileFunc(filePath, backupFileName), nil + restore = createRestoreFileFunc(filePath, backupFileName) + return } func cloneFile(origFile, newName string, fileMode os.FileMode) (err error) { diff --git a/artifactory/utils/dependenciesutils.go b/artifactory/utils/dependenciesutils.go index 91fa38cd1..bb1d12850 100644 --- a/artifactory/utils/dependenciesutils.go +++ b/artifactory/utils/dependenciesutils.go @@ -215,7 +215,7 @@ func DownloadDependency(artDetails *config.ServerDetails, downloadPath, targetPa if err = errorutils.CheckResponseStatus(resp, http.StatusOK); err != nil { return err } - err = coreutils.SetPermissionsRecursively(tempDirPath, 0700) + err = coreutils.SetPermissionsRecursively(tempDirPath, 0755) if err != nil { return err } diff --git a/general/envsetup/envsetup.go b/general/envsetup/envsetup.go index fa2fafe32..cbe844133 100644 --- a/general/envsetup/envsetup.go +++ b/general/envsetup/envsetup.go @@ -47,8 +47,6 @@ const ( " jf docker scan :" ) -var trueValue = true - type EnvSetupCommand struct { registrationURL string // In case encodedConnectionDetails were provided - we have a registered user that was invited to the platform. @@ -268,7 +266,7 @@ func GenerateNewLongTermRefreshableAccessToken(server *config.ServerDetails) (er func createLongExpirationRefreshableTokenParams() *services.CreateTokenParams { params := services.CreateTokenParams{} params.ExpiresIn = nonExpiredTokenValue - params.Refreshable = &trueValue + params.Refreshable = clientUtils.Pointer(true) params.Audience = "*@*" return ¶ms } diff --git a/general/invite/invite.go b/general/invite/invite.go index 4b8316d9f..84bdda983 100644 --- a/general/invite/invite.go +++ b/general/invite/invite.go @@ -6,6 +6,7 @@ import ( "github.com/jfrog/jfrog-client-go/access" accessservices "github.com/jfrog/jfrog-client-go/access/services" "github.com/jfrog/jfrog-client-go/artifactory/services" + clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/log" "strings" @@ -73,20 +74,18 @@ func (ic *InviteCommand) Run() (err error) { } func (ic *InviteCommand) createNewInvitedUser() *services.User { - var trueValue = true - var falseValue = false userDetails := services.User{} // Parameters "name" and "email" should both be with the email value for internal reasons in access. userDetails.Email = ic.invitedEmail userDetails.Name = ic.invitedEmail // Random valid password - information won't be used in access. userDetails.Password = "Password1!" - userDetails.Admin = &trueValue - userDetails.ShouldInvite = &trueValue + userDetails.Admin = clientutils.Pointer(true) + userDetails.ShouldInvite = clientutils.Pointer(true) userDetails.Source = accessservices.InviteCliSourceName - userDetails.ProfileUpdatable = &trueValue - userDetails.DisableUIAccess = &falseValue - userDetails.InternalPasswordDisabled = &falseValue + userDetails.ProfileUpdatable = clientutils.Pointer(true) + userDetails.DisableUIAccess = clientutils.Pointer(false) + userDetails.InternalPasswordDisabled = clientutils.Pointer(false) return &userDetails } diff --git a/go.mod b/go.mod index f4b687efc..da2539daf 100644 --- a/go.mod +++ b/go.mod @@ -14,10 +14,11 @@ require ( github.com/jedib0t/go-pretty/v6 v6.4.7 github.com/jfrog/build-info-go v1.9.10 github.com/jfrog/gofrog v1.3.0 + github.com/jfrog/jfrog-apps-config v1.0.1 github.com/jfrog/jfrog-client-go v1.32.3 github.com/magiconair/properties v1.8.7 github.com/manifoldco/promptui v0.9.0 - github.com/owenrumney/go-sarif/v2 v2.2.0 + github.com/owenrumney/go-sarif/v2 v2.2.2 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 @@ -36,7 +37,7 @@ require ( github.com/BurntSushi/toml v1.3.2 // indirect github.com/CycloneDX/cyclonedx-go v0.7.2 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/acomagu/bufpipe v1.0.4 // indirect @@ -93,3 +94,7 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) + +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20230928142526-622034e3f57b + +replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20230928084830-478bd49f5d3e diff --git a/go.sum b/go.sum index 737b839c2..31b7169b1 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/CycloneDX/cyclonedx-go v0.7.2/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7B github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE= +github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= @@ -195,12 +195,14 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jedib0t/go-pretty/v6 v6.4.7 h1:lwiTJr1DEkAgzljsUsORmWsVn5MQjt1BPJdPCtJ6KXE= github.com/jedib0t/go-pretty/v6 v6.4.7/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= -github.com/jfrog/build-info-go v1.9.10 h1:uXnDLVxpqxoAMpXcki00QaBB+M2BoGMMpHODPkmmYOY= -github.com/jfrog/build-info-go v1.9.10/go.mod h1:ujJ8XQZMdT2tMkLSMJNyDd1pCY+duwHdjV+9or9FLIg= +github.com/jfrog/build-info-go v1.8.9-0.20230928084830-478bd49f5d3e h1:tWNlQScbapCz5/EBc+lKBBQcZ/3QLgM3tM3HBEtxCTs= +github.com/jfrog/build-info-go v1.8.9-0.20230928084830-478bd49f5d3e/go.mod h1:ujJ8XQZMdT2tMkLSMJNyDd1pCY+duwHdjV+9or9FLIg= github.com/jfrog/gofrog v1.3.0 h1:o4zgsBZE4QyDbz2M7D4K6fXPTBJht+8lE87mS9bw7Gk= github.com/jfrog/gofrog v1.3.0/go.mod h1:IFMc+V/yf7rA5WZ74CSbXe+Lgf0iApEQLxRZVzKRUR0= -github.com/jfrog/jfrog-client-go v1.32.3 h1:B2M8Gu8EMrokbHWPPDgN1b7YRWwf0oe746epvQASK6c= -github.com/jfrog/jfrog-client-go v1.32.3/go.mod h1:UewnwkIf/77HzBgwCPzOHZCK6V/Nw5/JwdzN/tRb4aU= +github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYLipdsOFMY= +github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w= +github.com/jfrog/jfrog-client-go v1.28.1-0.20230928142526-622034e3f57b h1:WXxRXkWaxFRdMechZJ0pkzZWCI6HNqlxLzAfr3qXjP8= +github.com/jfrog/jfrog-client-go v1.28.1-0.20230928142526-622034e3f57b/go.mod h1:AePTNv5H1YSGycxiL+1jXHCzqu3rCGruVP7S0N+BEEo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= @@ -251,8 +253,8 @@ github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7 github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= -github.com/owenrumney/go-sarif/v2 v2.2.0 h1:1DmZaijK0HBZCR1fgcDSGa7VzYkU9NDmbZ7qC2QfUjE= -github.com/owenrumney/go-sarif/v2 v2.2.0/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= +github.com/owenrumney/go-sarif/v2 v2.2.2 h1:x2acaiiAW9hu+78wbEYBRGLk5nRtHmkv7HeUsKvblwc= +github.com/owenrumney/go-sarif/v2 v2.2.2/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM= @@ -319,7 +321,7 @@ github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+ github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= diff --git a/utils/usage/usage.go b/utils/usage/usage.go index 30f40f18c..9b493637b 100644 --- a/utils/usage/usage.go +++ b/utils/usage/usage.go @@ -2,7 +2,6 @@ package usage import ( "fmt" - "golang.org/x/sync/errgroup" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/config" @@ -12,7 +11,7 @@ import ( "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/log" ecosysusage "github.com/jfrog/jfrog-client-go/utils/usage" - xrayusage "github.com/jfrog/jfrog-client-go/xray/usage" + "golang.org/x/sync/errgroup" ) const ( @@ -47,7 +46,6 @@ func NewUsageReporter(productId string, serverDetails *config.ServerDetails) *Us serverDetails: serverDetails, reportWaitGroup: new(errgroup.Group), sendToEcosystem: true, - sendToXray: true, sendToArtifactory: true, } } @@ -110,12 +108,15 @@ func (ur *UsageReporter) WaitForResponses() (err error) { func (ur *UsageReporter) reportToEcosystem(features ...ReportFeature) (err error) { if ur.serverDetails.Url == "" { - err = errorutils.CheckErrorf("platform Url is not set") + err = errorutils.CheckErrorf("platform URL is not set") return } reports, err := ur.convertAttributesToEcosystemReports(features...) - if len(reports) == 0 || err != nil { - err = errorutils.CheckErrorf("Nothing to send.") + if err != nil { + return + } + if len(reports) == 0 { + err = errorutils.CheckErrorf("nothing to send") return } return ecosysusage.SendEcosystemUsageReports(reports...) @@ -123,7 +124,7 @@ func (ur *UsageReporter) reportToEcosystem(features ...ReportFeature) (err error func (ur *UsageReporter) reportToArtifactory(features ...ReportFeature) (err error) { if ur.serverDetails.ArtifactoryUrl == "" { - err = errorutils.CheckErrorf("Artifactory Url is not set..") + err = errorutils.CheckErrorf("Artifactory URL is not set") return } serviceManager, err := utils.CreateServiceManager(ur.serverDetails, -1, 0, false) @@ -132,7 +133,7 @@ func (ur *UsageReporter) reportToArtifactory(features ...ReportFeature) (err err } converted := ur.convertAttributesToArtifactoryFeatures(features...) if len(converted) == 0 { - err = errorutils.CheckErrorf("Nothing to send.") + err = errorutils.CheckErrorf("nothing to send") return } return usage.ReportUsageToArtifactory(ur.ProductId, serviceManager, converted...) @@ -163,29 +164,6 @@ func (ur *UsageReporter) convertAttributesToArtifactoryFeatures(reportFeatures . return } -func (ur *UsageReporter) convertAttributesToXrayEvents(reportFeatures ...ReportFeature) (events []xrayusage.ReportXrayEventData) { - for _, feature := range reportFeatures { - convertedAttributes := []xrayusage.ReportUsageAttribute{} - for _, attribute := range feature.Attributes { - convertedAttributes = append(convertedAttributes, xrayusage.ReportUsageAttribute{ - AttributeName: attribute.AttributeName, - AttributeValue: attribute.AttributeValue, - }) - } - if feature.ClientId != "" { - // Add clientId as attribute - convertedAttributes = append(convertedAttributes, xrayusage.ReportUsageAttribute{ - AttributeName: clientIdAttributeName, - AttributeValue: feature.ClientId, - }) - } - events = append(events, xrayusage.CreateUsageEvent( - ur.ProductId, feature.FeatureId, convertedAttributes..., - )) - } - return -} - func (ur *UsageReporter) convertAttributesToEcosystemReports(reportFeatures ...ReportFeature) (reports []ecosysusage.ReportEcosystemUsageData, err error) { accountId := ur.serverDetails.Url clientToFeaturesMap := map[string][]string{} diff --git a/utils/usage/usage_test.go b/utils/usage/usage_test.go index 657f19ba1..c3b2b08a1 100644 --- a/utils/usage/usage_test.go +++ b/utils/usage/usage_test.go @@ -10,7 +10,6 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-client-go/artifactory/usage" ecosysusage "github.com/jfrog/jfrog-client-go/utils/usage" - xrayusage "github.com/jfrog/jfrog-client-go/xray/usage" "github.com/stretchr/testify/assert" ) @@ -40,28 +39,6 @@ var ( {FeatureId: "featureId", ClientId: "clientId2"}, {FeatureId: "featureId"}, } - xrayEvents = []xrayusage.ReportXrayEventData{ - { - ProductId: productName, - EventId: "server_" + productName + "_featureId2", - Attributes: map[string]string{ - "clientId": "clientId", - "attribute": "value", - }, - Origin: "API_CLI", - }, - { - ProductId: productName, - EventId: "server_" + productName + "_featureId", - Attributes: map[string]string{"clientId": "clientId2"}, - Origin: "API_CLI", - }, - { - ProductId: productName, - EventId: "server_" + productName + "_featureId", - Origin: "API_CLI", - }, - } ecosystemData = []ecosysusage.ReportEcosystemUsageData{ { ProductId: productName, @@ -90,13 +67,6 @@ func TestConvertToArtifactoryUsage(t *testing.T) { } } -func TestConvertToXrayUsage(t *testing.T) { - reporter := NewUsageReporter(productName, &config.ServerDetails{XrayUrl: serverUrl + "/"}) - for i := 0; i < len(features); i++ { - assert.Equal(t, xrayEvents[i], reporter.convertAttributesToXrayEvents(features[i])[0]) - } -} - func TestConvertToEcosystemUsage(t *testing.T) { reporter := NewUsageReporter(productName, &config.ServerDetails{Url: serverUrl}) for i := 0; i < len(features); i++ { @@ -173,7 +143,7 @@ func TestReportEcosystemUsageError(t *testing.T) { } func create404UsageHandler(t *testing.T) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotFound) } } diff --git a/xray/commands/audit/jas/applicability/applicabilitymanager.go b/xray/commands/audit/jas/applicability/applicabilitymanager.go index c3b83e462..202e3d9ff 100644 --- a/xray/commands/audit/jas/applicability/applicabilitymanager.go +++ b/xray/commands/audit/jas/applicability/applicabilitymanager.go @@ -3,6 +3,7 @@ package applicability import ( "path/filepath" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" "github.com/jfrog/gofrog/datastructures" @@ -101,19 +102,22 @@ func isDirectComponents(components []string, directDependencies []string) bool { return false } -func (asm *ApplicabilityScanManager) Run(wd string) (err error) { - if len(asm.scanner.WorkingDirs) > 1 { - log.Info("Running applicability scanning in the", wd, "directory...") +func (asm *ApplicabilityScanManager) Run(module jfrogappsconfig.Module) (err error) { + if jas.ShouldSkipScanner(module, utils.Applicability) { + return + } + if len(asm.scanner.JFrogAppsConfig.Modules) > 1 { + log.Info("Running applicability scanning in the", module.SourceRoot, "directory...") } else { log.Info("Running applicability scanning...") } - if err = asm.createConfigFile(wd); err != nil { + if err = asm.createConfigFile(module); err != nil { return } if err = asm.runAnalyzerManager(); err != nil { return } - workingDirResults, err := jas.ReadJasScanRunsFromFile(asm.scanner.ResultsFileName, wd, applicabilityDocsUrlSuffix) + workingDirResults, err := jas.ReadJasScanRunsFromFile(asm.scanner.ResultsFileName, module.SourceRoot, applicabilityDocsUrlSuffix) if err != nil { return } @@ -142,25 +146,29 @@ type scanConfiguration struct { SkippedDirs []string `yaml:"skipped-folders"` } -func (asm *ApplicabilityScanManager) createConfigFile(workingDir string) error { - skipDirs := jas.SkippedDirs +func (asm *ApplicabilityScanManager) createConfigFile(module jfrogappsconfig.Module) error { + roots, err := jas.GetSourceRoots(module, nil) + if err != nil { + return err + } + excludePatterns := jas.GetExcludePatterns(module, nil) if asm.thirdPartyScan { log.Info("Including node modules folder in applicability scan") - skipDirs = removeElementFromSlice(skipDirs, jas.NodeModulesPattern) + excludePatterns = removeElementFromSlice(excludePatterns, jas.NodeModulesPattern) } configFileContent := applicabilityScanConfig{ Scans: []scanConfiguration{ { - Roots: []string{workingDir}, + Roots: roots, Output: asm.scanner.ResultsFileName, Type: applicabilityScanType, GrepDisable: false, CveWhitelist: asm.directDependenciesCves, - SkippedDirs: skipDirs, + SkippedDirs: excludePatterns, }, }, } - return jas.CreateScannersConfigFile(asm.scanner.ConfigFileName, configFileContent) + return jas.CreateScannersConfigFile(asm.scanner.ConfigFileName, configFileContent, utils.Applicability) } // Runs the analyzerManager app and returns a boolean to indicate whether the user is entitled for diff --git a/xray/commands/audit/jas/applicability/applicabilitymanager_test.go b/xray/commands/audit/jas/applicability/applicabilitymanager_test.go index 36a5fd22c..554909181 100644 --- a/xray/commands/audit/jas/applicability/applicabilitymanager_test.go +++ b/xray/commands/audit/jas/applicability/applicabilitymanager_test.go @@ -1,13 +1,15 @@ package applicability import ( + "os" + "path/filepath" + "testing" + + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" "github.com/jfrog/jfrog-client-go/xray/services" "github.com/stretchr/testify/assert" - "os" - "path/filepath" - "testing" ) var mockDirectDependencies = []string{"issueId_2_direct_dependency", "issueId_1_direct_dependency"} @@ -36,7 +38,7 @@ func TestNewApplicabilityScanManager_DependencyTreeDoesntExist(t *testing.T) { // Assert if assert.NotNil(t, applicabilityManager) { assert.NotNil(t, applicabilityManager.scanner.ScannerDirCleanupFunc) - assert.Len(t, applicabilityManager.scanner.WorkingDirs, 1) + assert.Len(t, applicabilityManager.scanner.JFrogAppsConfig.Modules, 1) assert.NotEmpty(t, applicabilityManager.scanner.ConfigFileName) assert.NotEmpty(t, applicabilityManager.scanner.ResultsFileName) assert.Empty(t, applicabilityManager.directDependenciesCves) @@ -255,7 +257,7 @@ func TestCreateConfigFile_VerifyFileWasCreated(t *testing.T) { currWd, err := coreutils.GetWorkingDirectory() assert.NoError(t, err) - err = applicabilityManager.createConfigFile(currWd) + err = applicabilityManager.createConfigFile(jfrogappsconfig.Module{SourceRoot: currWd}) assert.NoError(t, err) defer func() { @@ -280,7 +282,7 @@ func TestParseResults_EmptyResults_AllCvesShouldGetUnknown(t *testing.T) { // Act var err error - applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.WorkingDirs[0], applicabilityDocsUrlSuffix) + applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, applicabilityDocsUrlSuffix) if assert.NoError(t, err) { assert.Len(t, applicabilityManager.applicabilityScanResults, 1) @@ -297,7 +299,7 @@ func TestParseResults_ApplicableCveExist(t *testing.T) { // Act var err error - applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.WorkingDirs[0], applicabilityDocsUrlSuffix) + applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, applicabilityDocsUrlSuffix) if assert.NoError(t, err) && assert.NotNil(t, applicabilityManager.applicabilityScanResults) { assert.Len(t, applicabilityManager.applicabilityScanResults, 1) @@ -314,7 +316,7 @@ func TestParseResults_AllCvesNotApplicable(t *testing.T) { // Act var err error - applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.WorkingDirs[0], applicabilityDocsUrlSuffix) + applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, applicabilityDocsUrlSuffix) if assert.NoError(t, err) && assert.NotNil(t, applicabilityManager.applicabilityScanResults) { assert.Len(t, applicabilityManager.applicabilityScanResults, 1) diff --git a/xray/commands/audit/jas/common.go b/xray/commands/audit/jas/common.go index e37c67863..be165aa32 100644 --- a/xray/commands/audit/jas/common.go +++ b/xray/commands/audit/jas/common.go @@ -2,21 +2,25 @@ package jas import ( "errors" + "fmt" "os" "path/filepath" "strings" "testing" "unicode" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" rtutils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/xray/utils" "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" "github.com/jfrog/jfrog-client-go/xray/services" "github.com/owenrumney/go-sarif/v2/sarif" "github.com/stretchr/testify/assert" + "golang.org/x/exp/slices" "gopkg.in/yaml.v3" ) @@ -25,7 +29,7 @@ const ( ) var ( - SkippedDirs = []string{"**/*test*/**", "**/*venv*/**", NodeModulesPattern, "**/*target*/**"} + DefaultExcludePatterns = []string{"**/*test*/**", "**/*venv*/**", NodeModulesPattern, "**/*target*/**"} mapSeverityToScore = map[string]string{ "": "0.0", @@ -42,7 +46,7 @@ type JasScanner struct { ResultsFileName string AnalyzerManager utils.AnalyzerManager ServerDetails *config.ServerDetails - WorkingDirs []string + JFrogAppsConfig *jfrogappsconfig.JFrogAppsConfig ScannerDirCleanupFunc func() error } @@ -61,22 +65,42 @@ func NewJasScanner(workingDirs []string, serverDetails *config.ServerDetails, mu scanner.ServerDetails = serverDetails scanner.ConfigFileName = filepath.Join(tempDir, "config.yaml") scanner.ResultsFileName = filepath.Join(tempDir, "results.sarif") - scanner.WorkingDirs, err = coreutils.GetFullPathsWorkingDirs(workingDirs) + scanner.JFrogAppsConfig, err = createJFrogAppsConfig(workingDirs) scanner.AnalyzerManager.MultiScanId = multiScanId return } +func createJFrogAppsConfig(workingDirs []string) (*jfrogappsconfig.JFrogAppsConfig, error) { + if jfrogAppsConfig, err := jfrogappsconfig.LoadConfigIfExist(); err != nil { + return nil, errorutils.CheckError(err) + } else if jfrogAppsConfig != nil { + // jfrog-apps-config.yml exist in the workspace + return jfrogAppsConfig, nil + } + + // jfrog-apps-config.yml does not exist in the workspace + fullPathsWorkingDirs, err := coreutils.GetFullPathsWorkingDirs(workingDirs) + if err != nil { + return nil, err + } + jfrogAppsConfig := new(jfrogappsconfig.JFrogAppsConfig) + for _, workingDir := range fullPathsWorkingDirs { + jfrogAppsConfig.Modules = append(jfrogAppsConfig.Modules, jfrogappsconfig.Module{SourceRoot: workingDir}) + } + return jfrogAppsConfig, nil +} + type ScannerCmd interface { - Run(wd string) (err error) + Run(module jfrogappsconfig.Module) (err error) } func (a *JasScanner) Run(scannerCmd ScannerCmd) (err error) { - for _, workingDir := range a.WorkingDirs { + for _, module := range a.JFrogAppsConfig.Modules { func() { defer func() { err = errors.Join(err, deleteJasProcessFiles(a.ConfigFileName, a.ResultsFileName)) }() - if err = scannerCmd.Run(workingDir); err != nil { + if err = scannerCmd.Run(module); err != nil { return } }() @@ -173,11 +197,12 @@ func convertToScore(severity string) string { return "" } -func CreateScannersConfigFile(fileName string, fileContent interface{}) error { +func CreateScannersConfigFile(fileName string, fileContent interface{}, scanType utils.JasScanType) error { yamlData, err := yaml.Marshal(&fileContent) if errorutils.CheckError(err) != nil { return err } + log.Debug(scanType.String() + " scanner input YAML:\n" + string(yamlData)) err = os.WriteFile(fileName, yamlData, 0644) return errorutils.CheckError(err) } @@ -216,3 +241,38 @@ func InitJasTest(t *testing.T, workingDirs ...string) (*JasScanner, func()) { func GetTestDataPath() string { return filepath.Join("..", "..", "..", "testdata") } + +func ShouldSkipScanner(module jfrogappsconfig.Module, scanType utils.JasScanType) bool { + lowerScanType := strings.ToLower(string(scanType)) + if slices.Contains(module.ExcludeScanners, lowerScanType) { + log.Info(fmt.Sprintf("Skipping %s scanning", scanType)) + return true + } + return false +} + +func GetSourceRoots(module jfrogappsconfig.Module, scanner *jfrogappsconfig.Scanner) ([]string, error) { + root, err := filepath.Abs(module.SourceRoot) + if err != nil { + return []string{}, errorutils.CheckError(err) + } + if scanner == nil || len(scanner.WorkingDirs) == 0 { + return []string{root}, errorutils.CheckError(err) + } + var roots []string + for _, workingDir := range scanner.WorkingDirs { + roots = append(roots, filepath.Join(root, workingDir)) + } + return roots, nil +} + +func GetExcludePatterns(module jfrogappsconfig.Module, scanner *jfrogappsconfig.Scanner) []string { + excludePatterns := module.ExcludePatterns + if scanner != nil { + excludePatterns = append(excludePatterns, scanner.ExcludePatterns...) + } + if len(excludePatterns) == 0 { + return DefaultExcludePatterns + } + return excludePatterns +} diff --git a/xray/commands/audit/jas/commons_test.go b/xray/commands/audit/jas/commons_test.go new file mode 100644 index 000000000..d600d7a73 --- /dev/null +++ b/xray/commands/audit/jas/commons_test.go @@ -0,0 +1,129 @@ +package jas + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" + clientTestUtils "github.com/jfrog/jfrog-client-go/utils/tests" + + "github.com/jfrog/jfrog-cli-core/v2/xray/utils" + "github.com/stretchr/testify/assert" +) + +var createJFrogAppsConfigCases = []struct { + workingDirs []string +}{ + {workingDirs: []string{}}, + {workingDirs: []string{"working-dir"}}, + {workingDirs: []string{"working-dir-1", "working-dir-2"}}, +} + +func TestCreateJFrogAppsConfig(t *testing.T) { + wd, err := os.Getwd() + assert.NoError(t, err) + + for _, testCase := range createJFrogAppsConfigCases { + t.Run(fmt.Sprintf("%v", testCase.workingDirs), func(t *testing.T) { + jfrogAppsConfig, err := createJFrogAppsConfig(testCase.workingDirs) + assert.NoError(t, err) + assert.NotNil(t, jfrogAppsConfig) + if len(testCase.workingDirs) == 0 { + assert.Len(t, jfrogAppsConfig.Modules, 1) + assert.Equal(t, wd, jfrogAppsConfig.Modules[0].SourceRoot) + return + } + assert.Len(t, jfrogAppsConfig.Modules, len(testCase.workingDirs)) + for i, workingDir := range testCase.workingDirs { + assert.Equal(t, filepath.Join(wd, workingDir), jfrogAppsConfig.Modules[i].SourceRoot) + } + }) + } +} + +func TestCreateJFrogAppsConfigWithConfig(t *testing.T) { + wd, err := os.Getwd() + assert.NoError(t, err) + chdirCallback := clientTestUtils.ChangeDirWithCallback(t, wd, "testdata") + defer chdirCallback() + + jfrogAppsConfig, err := createJFrogAppsConfig([]string{}) + assert.NoError(t, err) + assert.NotNil(t, jfrogAppsConfig) + assert.Equal(t, "1.0", jfrogAppsConfig.Version) + assert.Len(t, jfrogAppsConfig.Modules, 1) +} + +func TestShouldSkipScanner(t *testing.T) { + module := jfrogappsconfig.Module{} + assert.False(t, ShouldSkipScanner(module, utils.IaC)) + + module = jfrogappsconfig.Module{ExcludeScanners: []string{"sast"}} + assert.False(t, ShouldSkipScanner(module, utils.IaC)) + assert.True(t, ShouldSkipScanner(module, utils.Sast)) +} + +var getSourceRootsCases = []struct { + scanner *jfrogappsconfig.Scanner +}{ + {scanner: nil}, + {&jfrogappsconfig.Scanner{WorkingDirs: []string{"working-dir"}}}, + {&jfrogappsconfig.Scanner{WorkingDirs: []string{"working-dir-1", "working-dir-2"}}}, +} + +func TestGetSourceRoots(t *testing.T) { + testGetSourceRoots(t, "source-root") +} + +func TestGetSourceRootsEmptySourceRoot(t *testing.T) { + testGetSourceRoots(t, "") +} + +func testGetSourceRoots(t *testing.T, sourceRoot string) { + sourceRoot, err := filepath.Abs(sourceRoot) + assert.NoError(t, err) + module := jfrogappsconfig.Module{SourceRoot: sourceRoot} + for _, testCase := range getSourceRootsCases { + t.Run("", func(t *testing.T) { + scanner := testCase.scanner + actualSourceRoots, err := GetSourceRoots(module, scanner) + assert.NoError(t, err) + if scanner == nil { + assert.ElementsMatch(t, []string{module.SourceRoot}, actualSourceRoots) + return + } + expectedWorkingDirs := []string{} + for _, workingDir := range scanner.WorkingDirs { + expectedWorkingDirs = append(expectedWorkingDirs, filepath.Join(module.SourceRoot, workingDir)) + } + assert.ElementsMatch(t, actualSourceRoots, expectedWorkingDirs) + }) + } +} + +var getExcludePatternsCases = []struct { + scanner *jfrogappsconfig.Scanner +}{ + {scanner: nil}, + {&jfrogappsconfig.Scanner{WorkingDirs: []string{"exclude-dir"}}}, + {&jfrogappsconfig.Scanner{WorkingDirs: []string{"exclude-dir-1", "exclude-dir-2"}}}, +} + +func TestGetExcludePatterns(t *testing.T) { + module := jfrogappsconfig.Module{ExcludePatterns: []string{"exclude-root"}} + for _, testCase := range getExcludePatternsCases { + t.Run("", func(t *testing.T) { + scanner := testCase.scanner + actualExcludePatterns := GetExcludePatterns(module, scanner) + if scanner == nil { + assert.ElementsMatch(t, module.ExcludePatterns, actualExcludePatterns) + return + } + expectedExcludePatterns := module.ExcludePatterns + expectedExcludePatterns = append(expectedExcludePatterns, scanner.ExcludePatterns...) + assert.ElementsMatch(t, actualExcludePatterns, expectedExcludePatterns) + }) + } +} \ No newline at end of file diff --git a/xray/commands/audit/jas/iac/iacscanner.go b/xray/commands/audit/jas/iac/iacscanner.go index 03ef52d88..402557e3e 100644 --- a/xray/commands/audit/jas/iac/iacscanner.go +++ b/xray/commands/audit/jas/iac/iacscanner.go @@ -1,9 +1,11 @@ package iac import ( - "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" "path/filepath" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" + "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" + "github.com/jfrog/jfrog-cli-core/v2/xray/utils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/owenrumney/go-sarif/v2/sarif" @@ -49,15 +51,17 @@ func newIacScanManager(scanner *jas.JasScanner) (manager *IacScanManager) { } } -func (iac *IacScanManager) Run(wd string) (err error) { - scanner := iac.scanner - if err = iac.createConfigFile(wd); err != nil { +func (iac *IacScanManager) Run(module jfrogappsconfig.Module) (err error) { + if jas.ShouldSkipScanner(module, utils.IaC) { + return + } + if err = iac.createConfigFile(module); err != nil { return } if err = iac.runAnalyzerManager(); err != nil { return } - workingDirResults, err := jas.ReadJasScanRunsFromFile(scanner.ResultsFileName, wd, iacDocsUrlSuffix) + workingDirResults, err := jas.ReadJasScanRunsFromFile(iac.scanner.ResultsFileName, module.SourceRoot, iacDocsUrlSuffix) if err != nil { return } @@ -76,18 +80,22 @@ type iacScanConfiguration struct { SkippedDirs []string `yaml:"skipped-folders"` } -func (iac *IacScanManager) createConfigFile(currentWd string) error { +func (iac *IacScanManager) createConfigFile(module jfrogappsconfig.Module) error { + roots, err := jas.GetSourceRoots(module, module.Scanners.Iac) + if err != nil { + return err + } configFileContent := iacScanConfig{ Scans: []iacScanConfiguration{ { - Roots: []string{currentWd}, + Roots: roots, Output: iac.scanner.ResultsFileName, Type: iacScannerType, - SkippedDirs: jas.SkippedDirs, + SkippedDirs: jas.GetExcludePatterns(module, module.Scanners.Iac), }, }, } - return jas.CreateScannersConfigFile(iac.scanner.ConfigFileName, configFileContent) + return jas.CreateScannersConfigFile(iac.scanner.ConfigFileName, configFileContent, utils.IaC) } func (iac *IacScanManager) runAnalyzerManager() error { diff --git a/xray/commands/audit/jas/iac/iacscanner_test.go b/xray/commands/audit/jas/iac/iacscanner_test.go index 484693ab6..1f9482ded 100644 --- a/xray/commands/audit/jas/iac/iacscanner_test.go +++ b/xray/commands/audit/jas/iac/iacscanner_test.go @@ -1,11 +1,13 @@ package iac import ( - "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" "os" "path/filepath" "testing" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" + "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/stretchr/testify/assert" ) @@ -20,7 +22,7 @@ func TestNewIacScanManager(t *testing.T) { if assert.NotNil(t, iacScanManager) { assert.NotEmpty(t, iacScanManager.scanner.ConfigFileName) assert.NotEmpty(t, iacScanManager.scanner.ResultsFileName) - assert.NotEmpty(t, iacScanManager.scanner.WorkingDirs) + assert.NotEmpty(t, iacScanManager.scanner.JFrogAppsConfig.Modules[0].SourceRoot) assert.Equal(t, &jas.FakeServerDetails, iacScanManager.scanner.ServerDetails) } } @@ -33,7 +35,7 @@ func TestIacScan_CreateConfigFile_VerifyFileWasCreated(t *testing.T) { currWd, err := coreutils.GetWorkingDirectory() assert.NoError(t, err) - err = iacScanManager.createConfigFile(currWd) + err = iacScanManager.createConfigFile(jfrogappsconfig.Module{SourceRoot: currWd}) defer func() { err = os.Remove(iacScanManager.scanner.ConfigFileName) @@ -57,7 +59,7 @@ func TestIacParseResults_EmptyResults(t *testing.T) { // Act var err error - iacScanManager.iacScannerResults, err = jas.ReadJasScanRunsFromFile(iacScanManager.scanner.ResultsFileName, scanner.WorkingDirs[0], iacDocsUrlSuffix) + iacScanManager.iacScannerResults, err = jas.ReadJasScanRunsFromFile(iacScanManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, iacDocsUrlSuffix) if assert.NoError(t, err) && assert.NotNil(t, iacScanManager.iacScannerResults) { assert.Len(t, iacScanManager.iacScannerResults, 1) assert.Empty(t, iacScanManager.iacScannerResults[0].Results) @@ -73,7 +75,7 @@ func TestIacParseResults_ResultsContainIacViolations(t *testing.T) { // Act var err error - iacScanManager.iacScannerResults, err = jas.ReadJasScanRunsFromFile(iacScanManager.scanner.ResultsFileName, scanner.WorkingDirs[0], iacDocsUrlSuffix) + iacScanManager.iacScannerResults, err = jas.ReadJasScanRunsFromFile(iacScanManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, iacDocsUrlSuffix) if assert.NoError(t, err) && assert.NotNil(t, iacScanManager.iacScannerResults) { assert.Len(t, iacScanManager.iacScannerResults, 1) assert.Len(t, iacScanManager.iacScannerResults[0].Results, 4) diff --git a/xray/commands/audit/jas/sast/sastscanner.go b/xray/commands/audit/jas/sast/sastscanner.go index b7ed62c64..f4133cf41 100644 --- a/xray/commands/audit/jas/sast/sastscanner.go +++ b/xray/commands/audit/jas/sast/sastscanner.go @@ -3,6 +3,9 @@ package sast import ( "fmt" + "path/filepath" + + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" "github.com/jfrog/jfrog-cli-core/v2/xray/utils" "github.com/jfrog/jfrog-client-go/utils/log" @@ -11,6 +14,7 @@ import ( ) const ( + sastScannerType = "sast" sastScanCommand = "zd" sastDocsUrlSuffix = "sast" ) @@ -41,12 +45,18 @@ func newSastScanManager(scanner *jas.JasScanner) (manager *SastScanManager) { } } -func (ssm *SastScanManager) Run(wd string) (err error) { +func (ssm *SastScanManager) Run(module jfrogappsconfig.Module) (err error) { + if jas.ShouldSkipScanner(module, utils.Sast) { + return + } + if err = ssm.createConfigFile(module); err != nil { + return + } scanner := ssm.scanner - if err = ssm.runAnalyzerManager(wd); err != nil { + if err = ssm.runAnalyzerManager(filepath.Dir(ssm.scanner.AnalyzerManager.AnalyzerManagerFullPath)); err != nil { return } - workingDirRuns, err := jas.ReadJasScanRunsFromFile(scanner.ResultsFileName, wd, sastDocsUrlSuffix) + workingDirRuns, err := jas.ReadJasScanRunsFromFile(scanner.ResultsFileName, module.SourceRoot, sastDocsUrlSuffix) if err != nil { return } @@ -55,8 +65,43 @@ func (ssm *SastScanManager) Run(wd string) (err error) { return } +type sastScanConfig struct { + Scans []scanConfiguration `yaml:"scans,omitempty"` +} + +type scanConfiguration struct { + Roots []string `yaml:"roots,omitempty"` + Type string `yaml:"type,omitempty"` + Language string `yaml:"language,omitempty"` + ExcludePatterns []string `yaml:"exclude_patterns,omitempty"` + ExcludedRules []string `yaml:"excluded-rules,omitempty"` +} + +func (ssm *SastScanManager) createConfigFile(module jfrogappsconfig.Module) error { + sastScanner := module.Scanners.Sast + if sastScanner == nil { + sastScanner = &jfrogappsconfig.SastScanner{} + } + roots, err := jas.GetSourceRoots(module, &sastScanner.Scanner) + if err != nil { + return err + } + configFileContent := sastScanConfig{ + Scans: []scanConfiguration{ + { + Type: sastScannerType, + Roots: roots, + Language: sastScanner.Language, + ExcludedRules: sastScanner.ExcludedRules, + ExcludePatterns: jas.GetExcludePatterns(module, &sastScanner.Scanner), + }, + }, + } + return jas.CreateScannersConfigFile(ssm.scanner.ConfigFileName, configFileContent, utils.Sast) +} + func (ssm *SastScanManager) runAnalyzerManager(wd string) error { - return ssm.scanner.AnalyzerManager.Exec(ssm.scanner.ResultsFileName, sastScanCommand, wd, ssm.scanner.ServerDetails) + return ssm.scanner.AnalyzerManager.ExecWithOutputFile(ssm.scanner.ConfigFileName, sastScanCommand, wd, ssm.scanner.ResultsFileName, ssm.scanner.ServerDetails) } // In the Sast scanner, there can be multiple results with the same location. diff --git a/xray/commands/audit/jas/sast/sastscanner_test.go b/xray/commands/audit/jas/sast/sastscanner_test.go index c3dca7115..43eedf705 100644 --- a/xray/commands/audit/jas/sast/sastscanner_test.go +++ b/xray/commands/audit/jas/sast/sastscanner_test.go @@ -21,7 +21,7 @@ func TestNewSastScanManager(t *testing.T) { if assert.NotNil(t, sastScanManager) { assert.NotEmpty(t, sastScanManager.scanner.ConfigFileName) assert.NotEmpty(t, sastScanManager.scanner.ResultsFileName) - assert.NotEmpty(t, sastScanManager.scanner.WorkingDirs) + assert.NotEmpty(t, sastScanManager.scanner.JFrogAppsConfig.Modules[0].SourceRoot) assert.Equal(t, &jas.FakeServerDetails, sastScanManager.scanner.ServerDetails) } } @@ -36,7 +36,7 @@ func TestSastParseResults_EmptyResults(t *testing.T) { // Act var err error - sastScanManager.sastScannerResults, err = jas.ReadJasScanRunsFromFile(sastScanManager.scanner.ResultsFileName, scanner.WorkingDirs[0], sastDocsUrlSuffix) + sastScanManager.sastScannerResults, err = jas.ReadJasScanRunsFromFile(sastScanManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, sastDocsUrlSuffix) // Assert if assert.NoError(t, err) && assert.NotNil(t, sastScanManager.sastScannerResults) { @@ -57,7 +57,7 @@ func TestSastParseResults_ResultsContainIacViolations(t *testing.T) { // Act var err error - sastScanManager.sastScannerResults, err = jas.ReadJasScanRunsFromFile(sastScanManager.scanner.ResultsFileName, scanner.WorkingDirs[0], sastDocsUrlSuffix) + sastScanManager.sastScannerResults, err = jas.ReadJasScanRunsFromFile(sastScanManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, sastDocsUrlSuffix) // Assert if assert.NoError(t, err) && assert.NotNil(t, sastScanManager.sastScannerResults) { diff --git a/xray/commands/audit/jas/secrets/secretsscanner.go b/xray/commands/audit/jas/secrets/secretsscanner.go index e2c9fbd17..aad7fc6a6 100644 --- a/xray/commands/audit/jas/secrets/secretsscanner.go +++ b/xray/commands/audit/jas/secrets/secretsscanner.go @@ -4,6 +4,7 @@ import ( "path/filepath" "strings" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" "github.com/jfrog/jfrog-cli-core/v2/xray/utils" "github.com/jfrog/jfrog-client-go/utils/log" @@ -49,19 +50,21 @@ func newSecretsScanManager(scanner *jas.JasScanner) (manager *SecretScanManager) } } -func (s *SecretScanManager) Run(wd string) (err error) { - scanner := s.scanner - if err = s.createConfigFile(wd); err != nil { +func (ssm *SecretScanManager) Run(module jfrogappsconfig.Module) (err error) { + if jas.ShouldSkipScanner(module, utils.Secrets) { return } - if err = s.runAnalyzerManager(); err != nil { + if err = ssm.createConfigFile(module); err != nil { return } - workingDirRuns, err := jas.ReadJasScanRunsFromFile(scanner.ResultsFileName, wd, secretsDocsUrlSuffix) + if err = ssm.runAnalyzerManager(); err != nil { + return + } + workingDirRuns, err := jas.ReadJasScanRunsFromFile(ssm.scanner.ResultsFileName, module.SourceRoot, secretsDocsUrlSuffix) if err != nil { return } - s.secretsScannerResults = append(s.secretsScannerResults, processSecretScanRuns(workingDirRuns)...) + ssm.secretsScannerResults = append(ssm.secretsScannerResults, processSecretScanRuns(workingDirRuns)...) return } @@ -76,18 +79,22 @@ type secretsScanConfiguration struct { SkippedDirs []string `yaml:"skipped-folders"` } -func (s *SecretScanManager) createConfigFile(currentWd string) error { +func (s *SecretScanManager) createConfigFile(module jfrogappsconfig.Module) error { + roots, err := jas.GetSourceRoots(module, module.Scanners.Secrets) + if err != nil { + return err + } configFileContent := secretsScanConfig{ Scans: []secretsScanConfiguration{ { - Roots: []string{currentWd}, + Roots: roots, Output: s.scanner.ResultsFileName, Type: secretsScannerType, - SkippedDirs: jas.SkippedDirs, + SkippedDirs: jas.GetExcludePatterns(module, module.Scanners.Secrets), }, }, } - return jas.CreateScannersConfigFile(s.scanner.ConfigFileName, configFileContent) + return jas.CreateScannersConfigFile(s.scanner.ConfigFileName, configFileContent, utils.Secrets) } func (s *SecretScanManager) runAnalyzerManager() error { diff --git a/xray/commands/audit/jas/secrets/secretsscanner_test.go b/xray/commands/audit/jas/secrets/secretsscanner_test.go index da972bf01..1b2a053ec 100644 --- a/xray/commands/audit/jas/secrets/secretsscanner_test.go +++ b/xray/commands/audit/jas/secrets/secretsscanner_test.go @@ -5,6 +5,7 @@ import ( "path/filepath" "testing" + jfrogappsconfig "github.com/jfrog/jfrog-apps-config/go" "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/jas" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -29,7 +30,7 @@ func TestSecretsScan_CreateConfigFile_VerifyFileWasCreated(t *testing.T) { currWd, err := coreutils.GetWorkingDirectory() assert.NoError(t, err) - err = secretScanManager.createConfigFile(currWd) + err = secretScanManager.createConfigFile(jfrogappsconfig.Module{SourceRoot: currWd}) assert.NoError(t, err) defer func() { @@ -65,7 +66,7 @@ func TestParseResults_EmptyResults(t *testing.T) { // Act var err error - secretScanManager.secretsScannerResults, err = jas.ReadJasScanRunsFromFile(secretScanManager.scanner.ResultsFileName, scanner.WorkingDirs[0], secretsDocsUrlSuffix) + secretScanManager.secretsScannerResults, err = jas.ReadJasScanRunsFromFile(secretScanManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, secretsDocsUrlSuffix) // Assert if assert.NoError(t, err) && assert.NotNil(t, secretScanManager.secretsScannerResults) { @@ -88,7 +89,7 @@ func TestParseResults_ResultsContainSecrets(t *testing.T) { // Act var err error - secretScanManager.secretsScannerResults, err = jas.ReadJasScanRunsFromFile(secretScanManager.scanner.ResultsFileName, scanner.WorkingDirs[0], secretsDocsUrlSuffix) + secretScanManager.secretsScannerResults, err = jas.ReadJasScanRunsFromFile(secretScanManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, secretsDocsUrlSuffix) // Assert if assert.NoError(t, err) && assert.NotNil(t, secretScanManager.secretsScannerResults) { diff --git a/xray/commands/audit/jas/testdata/.jfrog/jfrog-apps-config.yml b/xray/commands/audit/jas/testdata/.jfrog/jfrog-apps-config.yml new file mode 100644 index 000000000..9357059d7 --- /dev/null +++ b/xray/commands/audit/jas/testdata/.jfrog/jfrog-apps-config.yml @@ -0,0 +1,50 @@ +# [Required] JFrog Applications Config version +version: "1.0" + +modules: + # [Required] Module name + - name: FrogLeapApp + # [Optional, default: "."] Application's root directory + source_root: "src" + # [Optional] Directories to exclude from scanning across all scanners + exclude_patterns: + - "docs/" + # [Optional] Scanners to exclude from JFrog Advanced Security (Options: "secrets", "sast", "iac") + exclude_scanners: + - secrets + # [Optional] Customize scanner configurations + scanners: + # [Optional] Configuration for Static Application Security Testing (SAST) + sast: + # [Optional] Specify the programming language for SAST + language: java + # [Optional] Working directories specific to SAST (Relative to source_root) + working_dirs: + - "src/module1" + - "src/module2" + # [Optional] Additional exclude patterns for this scanner + exclude_patterns: + - "src/module1/test" + # [Optional] List of specific scan rules to exclude from the scan + excluded_rules: + - xss-injection + + # [Optional] Configuration for secrets scan + secrets: + # [Optional] Working directories specific to the secret scanner (Relative to source_root) + working_dirs: + - "src/module1" + - "src/module2" + # [Optional] Additional exclude patterns for this scanner + exclude_patterns: + - "src/module1/test" + + # [Optional] Configuration for Infrastructure as Code scan (IaC) + iac: + # [Optional] Working directories specific to IaC (Relative to source_root) + working_dirs: + - "src/module1" + - "src/module2" + # [Optional] Additional exclude patterns for this Scanner + exclude_patterns: + - "src/module1/test" \ No newline at end of file diff --git a/xray/commands/audit/scarunner.go b/xray/commands/audit/scarunner.go index f78ac8dc2..7a364076d 100644 --- a/xray/commands/audit/scarunner.go +++ b/xray/commands/audit/scarunner.go @@ -135,7 +135,7 @@ func getDirectDependenciesFromTree(dependencyTrees []*xrayCmdUtils.GraphNode) [] func GetTechDependencyTree(params *xrayutils.AuditBasicParams, tech coreutils.Technology) (flatTree *xrayCmdUtils.GraphNode, fullDependencyTrees []*xrayCmdUtils.GraphNode, err error) { logMessage := fmt.Sprintf("Calculating %s dependencies", tech.ToFormal()) - log.Info(logMessage) + log.Info(logMessage + "...") if params.Progress() != nil { params.Progress().SetHeadlineMsg(logMessage) } diff --git a/xray/utils/analyzermanager.go b/xray/utils/analyzermanager.go index 936224df2..cf894d660 100644 --- a/xray/utils/analyzermanager.go +++ b/xray/utils/analyzermanager.go @@ -100,10 +100,21 @@ type AnalyzerManager struct { } func (am *AnalyzerManager) Exec(configFile, scanCommand, workingDir string, serverDetails *config.ServerDetails) (err error) { + return am.ExecWithOutputFile(configFile, scanCommand, workingDir, "", serverDetails) +} + +func (am *AnalyzerManager) ExecWithOutputFile(configFile, scanCommand, workingDir, outputFile string, serverDetails *config.ServerDetails) (err error) { if err = SetAnalyzerManagerEnvVariables(serverDetails); err != nil { return } - cmd := exec.Command(am.AnalyzerManagerFullPath, scanCommand, configFile, am.MultiScanId) + var cmd *exec.Cmd + if len(outputFile) > 0 { + log.Debug("Executing", am.AnalyzerManagerFullPath, scanCommand, configFile, outputFile, am.MultiScanId) + cmd = exec.Command(am.AnalyzerManagerFullPath, scanCommand, configFile, outputFile, am.MultiScanId) + } else { + log.Debug("Executing", am.AnalyzerManagerFullPath, scanCommand, configFile, am.MultiScanId) + cmd = exec.Command(am.AnalyzerManagerFullPath, scanCommand, configFile, am.MultiScanId) + } defer func() { if cmd.ProcessState != nil && !cmd.ProcessState.Exited() { if killProcessError := cmd.Process.Kill(); errorutils.CheckError(killProcessError) != nil { diff --git a/xray/utils/resultwriter.go b/xray/utils/resultwriter.go index 5d6e43474..900ad1922 100644 --- a/xray/utils/resultwriter.go +++ b/xray/utils/resultwriter.go @@ -117,7 +117,7 @@ func (rw *ResultsWriter) PrintScanResults() error { case Json: return PrintJson(rw.results.getXrayScanResults()) case Sarif: - sarifFile, err := rw.generateSarifContentFromResults(false) + sarifFile, err := GenerateSarifContentFromResults(rw.results, rw.isMultipleRoots, rw.includeLicenses, false) if err != nil { return err } @@ -171,21 +171,21 @@ func printMessage(message string) { log.Output("💬" + message) } -func (rw *ResultsWriter) generateSarifContentFromResults(markdownOutput bool) (sarifStr string, err error) { +func GenerateSarifContentFromResults(extendedResults *ExtendedScanResults, isMultipleRoots, includeLicenses, markdownOutput bool) (sarifStr string, err error) { report, err := NewReport() if err != nil { return } - xrayRun, err := rw.convertXrayResponsesToSarifRun(markdownOutput) + xrayRun, err := convertXrayResponsesToSarifRun(extendedResults, isMultipleRoots, includeLicenses, markdownOutput) if err != nil { return } report.Runs = append(report.Runs, xrayRun) - report.Runs = append(report.Runs, rw.results.ApplicabilityScanResults...) - report.Runs = append(report.Runs, rw.results.IacScanResults...) - report.Runs = append(report.Runs, rw.results.SecretsScanResults...) - report.Runs = append(report.Runs, rw.results.SastScanResults...) + report.Runs = append(report.Runs, extendedResults.ApplicabilityScanResults...) + report.Runs = append(report.Runs, extendedResults.IacScanResults...) + report.Runs = append(report.Runs, extendedResults.SecretsScanResults...) + report.Runs = append(report.Runs, extendedResults.SastScanResults...) out, err := json.Marshal(report) if err != nil { @@ -195,13 +195,13 @@ func (rw *ResultsWriter) generateSarifContentFromResults(markdownOutput bool) (s return clientUtils.IndentJson(out), nil } -func (rw *ResultsWriter) convertXrayResponsesToSarifRun(markdownOutput bool) (run *sarif.Run, err error) { - xrayJson, err := rw.convertXrayScanToSimpleJson(true) +func convertXrayResponsesToSarifRun(extendedResults *ExtendedScanResults, isMultipleRoots, includeLicenses, markdownOutput bool) (run *sarif.Run, err error) { + xrayJson, err := convertXrayScanToSimpleJson(extendedResults, isMultipleRoots, includeLicenses, true) if err != nil { return } xrayRun := sarif.NewRunWithInformationURI("JFrog Xray SCA", BaseDocumentationURL+"sca") - xrayRun.Tool.Driver.Version = &rw.results.XrayVersion + xrayRun.Tool.Driver.Version = &extendedResults.XrayVersion if len(xrayJson.Vulnerabilities) > 0 || len(xrayJson.SecurityViolations) > 0 { if err = extractXrayIssuesToSarifRun(xrayRun, xrayJson, markdownOutput); err != nil { return @@ -325,18 +325,18 @@ func addResultToSarifRun(issueId, msg, severity string, location *sarif.Location return } -func (rw *ResultsWriter) convertXrayScanToSimpleJson(simplifiedOutput bool) (formats.SimpleJsonResults, error) { - violations, vulnerabilities, licenses := SplitScanResults(rw.results.XrayResults) +func convertXrayScanToSimpleJson(extendedResults *ExtendedScanResults, isMultipleRoots, includeLicenses, simplifiedOutput bool) (formats.SimpleJsonResults, error) { + violations, vulnerabilities, licenses := SplitScanResults(extendedResults.XrayResults) jsonTable := formats.SimpleJsonResults{} if len(vulnerabilities) > 0 { - vulJsonTable, err := PrepareVulnerabilities(vulnerabilities, rw.results, rw.isMultipleRoots, simplifiedOutput) + vulJsonTable, err := PrepareVulnerabilities(vulnerabilities, extendedResults, isMultipleRoots, simplifiedOutput) if err != nil { return formats.SimpleJsonResults{}, err } jsonTable.Vulnerabilities = vulJsonTable } if len(violations) > 0 { - secViolationsJsonTable, licViolationsJsonTable, opRiskViolationsJsonTable, err := PrepareViolations(violations, rw.results, rw.isMultipleRoots, simplifiedOutput) + secViolationsJsonTable, licViolationsJsonTable, opRiskViolationsJsonTable, err := PrepareViolations(violations, extendedResults, isMultipleRoots, simplifiedOutput) if err != nil { return formats.SimpleJsonResults{}, err } @@ -344,7 +344,7 @@ func (rw *ResultsWriter) convertXrayScanToSimpleJson(simplifiedOutput bool) (for jsonTable.LicensesViolations = licViolationsJsonTable jsonTable.OperationalRiskViolations = opRiskViolationsJsonTable } - if rw.includeLicenses { + if includeLicenses { licJsonTable, err := PrepareLicenses(licenses) if err != nil { return formats.SimpleJsonResults{}, err @@ -356,7 +356,7 @@ func (rw *ResultsWriter) convertXrayScanToSimpleJson(simplifiedOutput bool) (for } func (rw *ResultsWriter) convertScanToSimpleJson() (formats.SimpleJsonResults, error) { - jsonTable, err := rw.convertXrayScanToSimpleJson(false) + jsonTable, err := convertXrayScanToSimpleJson(rw.results, rw.isMultipleRoots, rw.includeLicenses, false) if err != nil { return formats.SimpleJsonResults{}, err }