Skip to content

Commit

Permalink
Support Curation to run after package manager installation failure on…
Browse files Browse the repository at this point in the history
… 403
  • Loading branch information
asafambar committed Aug 5, 2024
1 parent 2e5856b commit ec991d7
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 29 deletions.
72 changes: 68 additions & 4 deletions cli/scancommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package cli
import (
"fmt"
enrichDocs "github.com/jfrog/jfrog-cli-security/cli/docs/enrich"
"github.com/jfrog/jfrog-cli-security/commands/audit/sca"
"github.com/jfrog/jfrog-cli-security/commands/enrich"
"github.com/jfrog/jfrog-cli-security/utils/xray"
"os"
"strings"

Expand Down Expand Up @@ -505,21 +507,83 @@ func AuditSpecificCmd(c *components.Context, technology techutils.Technology) er
}

func CurationCmd(c *components.Context) error {
threads, err := pluginsCommon.GetThreadsCount(c)
curationAuditCommand, err := getCurationCommand(c)
if err != nil {
return err
}
return progressbar.ExecWithProgress(curationAuditCommand)
}

var supportedCommandsForPostInstallationFailure = map[string]struct{}{
"install": {},
"build": {},
"i": {},
"add": {},
"ci": {},
"get": {},
"mod": {},
}

func IsSupportedCommandForPostInstallationFailure(cmd string) bool {
_, ok := supportedCommandsForPostInstallationFailure[cmd]
return ok
}

func CurationCmdPostInstallationFailure(c *components.Context, cmd string, tech techutils.Technology, originError error) error {
// check the command supported
if !IsSupportedCommandForPostInstallationFailure(cmd) {
return nil
}
// Curation post run failure is only relevant for forbidden errors
if !sca.IsForbiddenError(tech, originError.Error()) {
return nil
}
// If the command is not running in the context of github actions, we don't want to run the curation audit automatically
if os.Getenv("JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR") == "" {
return nil
}

curationAuditCommand, err := getCurationCommand(c)
if err != nil {
return err
}
// check if user entitled for curation
serverDetails, err := curationAuditCommand.GetAuth(tech)
if err != nil {
return err
}
xrayManager, err := xray.CreateXrayServiceManager(serverDetails)
if err != nil {
return err
}
entitled, err := curation.IsEntitledForCuration(xrayManager)
if err != nil {
return err
}
if !entitled {
log.Info("Curation feature is not entitled, skipping curation audit")
return nil
}

return progressbar.ExecWithProgress(curationAuditCommand)
}

func getCurationCommand(c *components.Context) (*curation.CurationAuditCommand, error) {
threads, err := pluginsCommon.GetThreadsCount(c)
if err != nil {
return nil, err
}
curationAuditCommand := curation.NewCurationAuditCommand().
SetWorkingDirs(splitByCommaAndTrim(c.GetStringFlagValue(flags.WorkingDirs))).
SetParallelRequests(threads)

serverDetails, err := pluginsCommon.CreateServerDetailsWithConfigOffer(c, true, cliutils.Rt)
if err != nil {
return err
return nil, err
}
format, err := curation.GetCurationOutputFormat(c.GetStringFlagValue(flags.OutputFormat))
if err != nil {
return err
return nil, err
}
curationAuditCommand.SetServerDetails(serverDetails).
SetIsCurationCmd(true).
Expand All @@ -529,7 +593,7 @@ func CurationCmd(c *components.Context) error {
SetInsecureTls(c.GetBoolFlagValue(flags.InsecureTls)).
SetNpmScope(c.GetStringFlagValue(flags.DepType)).
SetPipRequirementsFile(c.GetStringFlagValue(flags.RequirementsFile))
return progressbar.ExecWithProgress(curationAuditCommand)
return curationAuditCommand, nil
}

func DockerScanMockCommand() components.Command {
Expand Down
29 changes: 15 additions & 14 deletions commands/audit/sca/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,24 +167,25 @@ func setPathsForIssues(dependency *xrayUtils.GraphNode, issuesImpactPathsMap map
}
}

func SuspectCurationBlockedError(isCurationCmd bool, tech techutils.Technology, cmdOutput string) (msgToUser string) {
if !isCurationCmd {
return
func GetMsgToUserForCurationBlock(isCurationCmd bool, tech techutils.Technology, cmdOutput string) (msgToUser string) {
if isCurationCmd && IsForbiddenError(tech, cmdOutput) {
msgToUser = fmt.Sprintf(CurationErrorMsgToUserTemplate, tech)
}
return
}

func IsForbiddenError(tech techutils.Technology, cmdOutput string) bool {
switch tech {
case techutils.Npm:
return strings.Contains(strings.ToLower(cmdOutput), "403 forbidden")
case techutils.Maven:
if strings.Contains(cmdOutput, "status code: 403") || strings.Contains(strings.ToLower(cmdOutput), "403 forbidden") ||
strings.Contains(cmdOutput, "status code: 500") {
msgToUser = fmt.Sprintf(CurationErrorMsgToUserTemplate, techutils.Maven)
}
return strings.Contains(cmdOutput, "status code: 403") || strings.Contains(strings.ToLower(cmdOutput), "403 forbidden") ||
// In some cases mvn returns 500 status code even though it got 403 from artifactory.
strings.Contains(cmdOutput, "status code: 500")
case techutils.Pip:
if strings.Contains(strings.ToLower(cmdOutput), "http error 403") {
msgToUser = fmt.Sprintf(CurationErrorMsgToUserTemplate, techutils.Pip)
}
return strings.Contains(strings.ToLower(cmdOutput), "http error 403")
case techutils.Go:
if strings.Contains(strings.ToLower(cmdOutput), "403 forbidden") {
msgToUser = fmt.Sprintf(CurationErrorMsgToUserTemplate, techutils.Go)
}
return strings.Contains(strings.ToLower(cmdOutput), "403 forbidden")
}
return
return false
}
2 changes: 1 addition & 1 deletion commands/audit/sca/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ func TestSuspectCurationBlockedError(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, SuspectCurationBlockedError(tt.isCurationCmd, tt.tech, tt.output), tt.expect)
assert.Equal(t, GetMsgToUserForCurationBlock(tt.isCurationCmd, tt.tech, tt.output), tt.expect)
})
}
}
2 changes: 1 addition & 1 deletion commands/audit/sca/go/golang.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func handleCurationGoError(err error) (bool, error) {
if err == nil {
return false, nil
}
if msgToUser := sca.SuspectCurationBlockedError(true, techutils.Go, err.Error()); msgToUser != "" {
if msgToUser := sca.GetMsgToUserForCurationBlock(true, techutils.Go, err.Error()); msgToUser != "" {
return true, errors.New(msgToUser)
}
return false, nil
Expand Down
2 changes: 1 addition & 1 deletion commands/audit/sca/java/mvn.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func (mdt *MavenDepTreeManager) RunMvnCmd(goals []string) (cmdOutput []byte, err
if len(cmdOutput) > 0 {
log.Info(stringOutput)
}
if msg := sca.SuspectCurationBlockedError(mdt.isCurationCmd, techutils.Maven, stringOutput); msg != "" {
if msg := sca.GetMsgToUserForCurationBlock(mdt.isCurationCmd, techutils.Maven, stringOutput); msg != "" {
err = fmt.Errorf("failed running command 'mvn %s\n\n%s", strings.Join(goals, " "), msg)
} else {
err = fmt.Errorf("failed running command 'mvn %s': %s", strings.Join(goals, " "), err.Error())
Expand Down
2 changes: 1 addition & 1 deletion commands/audit/sca/python/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func installPipDeps(auditPython *AuditPython) (restoreEnv func() error, err erro
}
}
if err != nil || reqErr != nil {
if msgToUser := sca.SuspectCurationBlockedError(auditPython.IsCurationCmd, techutils.Pip, errors.Join(err, reqErr).Error()); msgToUser != "" {
if msgToUser := sca.GetMsgToUserForCurationBlock(auditPython.IsCurationCmd, techutils.Pip, errors.Join(err, reqErr).Error()); msgToUser != "" {
err = errors.Join(err, errors.New(msgToUser))
}
}
Expand Down
28 changes: 21 additions & 7 deletions commands/curation/curationaudit.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ import (
"strings"
"sync"

"github.com/jfrog/jfrog-cli-core/v2/common/cliutils"
config "github.com/jfrog/jfrog-cli-core/v2/utils/config"

"github.com/jfrog/gofrog/datastructures"
"github.com/jfrog/gofrog/parallel"
rtUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/common/cliutils"
outFormat "github.com/jfrog/jfrog-cli-core/v2/common/format"
"github.com/jfrog/jfrog-cli-core/v2/common/project"
config "github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-security/commands/audit"
"github.com/jfrog/jfrog-cli-security/commands/audit/sca/python"
Expand All @@ -33,6 +32,7 @@ import (
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/httputils"
"github.com/jfrog/jfrog-client-go/utils/log"
xrayClient "github.com/jfrog/jfrog-client-go/xray"
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
)

Expand Down Expand Up @@ -207,6 +207,7 @@ func (ca *CurationAuditCommand) Run() (err error) {
if err != nil {
return errorutils.CheckError(err)
}
// This is an internal flag that is used to indicate that the command was run as part of the post-installation process.
if len(ca.workingDirs) > 0 {
defer func() {
if e := errorutils.CheckError(os.Chdir(rootDir)); err == nil {
Expand Down Expand Up @@ -314,6 +315,18 @@ func (ca *CurationAuditCommand) doCurateAudit(results map[string]*CurationReport
}

func (ca *CurationAuditCommand) getRtManagerAndAuth(tech techutils.Technology) (rtManager artifactory.ArtifactoryServicesManager, serverDetails *config.ServerDetails, err error) {
serverDetails, err = ca.GetAuth(tech)
if err != nil {
return
}
rtManager, err = rtUtils.CreateServiceManager(serverDetails, 2, 0, false)
if err != nil {
return
}
return
}

func (ca *CurationAuditCommand) GetAuth(tech techutils.Technology) (serverDetails *config.ServerDetails, err error) {
if ca.PackageManagerConfig == nil {
if err = ca.SetRepo(tech); err != nil {
return
Expand All @@ -323,10 +336,6 @@ func (ca *CurationAuditCommand) getRtManagerAndAuth(tech techutils.Technology) (
if err != nil {
return
}
rtManager, err = rtUtils.CreateServiceManager(serverDetails, 2, 0, false)
if err != nil {
return
}
return
}

Expand Down Expand Up @@ -804,3 +813,8 @@ func GetCurationOutputFormat(formatFlagVal string) (format outFormat.OutputForma
}
return
}

func IsEntitledForCuration(xrayManager *xrayClient.XrayServicesManager) (entitled bool, err error) {
return xrayManager.IsEntitled("curation")

}

0 comments on commit ec991d7

Please sign in to comment.