Skip to content

Commit

Permalink
Merge pull request #978 from Checkmarx/feature/Disabling-triggering-a…
Browse files Browse the repository at this point in the history
…-Scorecard-scan-for-repos-other-than-GitHub

Disable triggering scorecard scan for hosts other than https github (AST-78326)
  • Loading branch information
LeonardoLordelloFontes authored Jan 9, 2025
2 parents 0ff299a + b36ea88 commit 3e4bf34
Show file tree
Hide file tree
Showing 2 changed files with 242 additions and 56 deletions.
136 changes: 80 additions & 56 deletions internal/commands/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"path"
"path/filepath"
"reflect"
"regexp"
"slices"
"strconv"
"strings"
Expand Down Expand Up @@ -106,6 +107,7 @@ const (
"--scs-repo-url your_repo_url --scs-repo-token your_repo_token"
ScsRepoWarningMsg = "SCS scan warning: Unable to start Scorecard scan due to missing required flags, please include in the ast-cli arguments: " +
"--scs-repo-url your_repo_url --scs-repo-token your_repo_token"
ScsScorecardUnsupportedHostWarningMsg = "SCS scan warning: Unable to run Scorecard scanner due to unsupported repo host. Currently, Scorecard can only run on GitHub Cloud repos."
)

var (
Expand Down Expand Up @@ -956,69 +958,91 @@ func createResubmitConfig(resubmitConfig []wrappers.Config, scsRepoToken, scsRep
}
return scsConfig
}
func addSCSScan(cmd *cobra.Command, resubmitConfig []wrappers.Config, hasEnterpriseSecretsLicense bool) (map[string]interface{}, error) {
if scanTypeEnabled(commonParams.ScsType) || scanTypeEnabled(commonParams.MicroEnginesType) {
scsConfig := wrappers.SCSConfig{}
SCSMapConfig := make(map[string]interface{})
SCSMapConfig[resultsMapType] = commonParams.MicroEnginesType // scs is still microengines in the scans API
userScanTypes, _ := cmd.Flags().GetString(commonParams.ScanTypes)
scsRepoToken := viper.GetString(commonParams.ScsRepoTokenKey)
if token, _ := cmd.Flags().GetString(commonParams.SCSRepoTokenFlag); token != "" {
scsRepoToken = token
}
viper.Set(commonParams.SCSRepoTokenFlag, scsRepoToken) // sanitizeLogs uses viper to get the value
scsRepoURL, _ := cmd.Flags().GetString(commonParams.SCSRepoURLFlag)
viper.Set(commonParams.SCSRepoURLFlag, scsRepoURL) // sanitizeLogs uses viper to get the value
SCSEngines, _ := cmd.Flags().GetString(commonParams.SCSEnginesFlag)
if resubmitConfig != nil {
scsConfig = createResubmitConfig(resubmitConfig, scsRepoToken, scsRepoURL, hasEnterpriseSecretsLicense)
SCSMapConfig[resultsMapValue] = &scsConfig
return SCSMapConfig, nil
}

scsSecretDetectionSelected := false
scsScoreCardSelected := false

if SCSEngines != "" {
SCSEnginesTypes := strings.Split(SCSEngines, ",")
for _, engineType := range SCSEnginesTypes {
engineType = strings.TrimSpace(engineType)
switch engineType {
case ScsSecretDetectionType:
scsSecretDetectionSelected = true
case ScsScoreCardType:
scsScoreCardSelected = true
}
}
} else {
scsSecretDetectionSelected = true
scsScoreCardSelected = true
}

if scsSecretDetectionSelected && hasEnterpriseSecretsLicense {
scsConfig.Twoms = trueString
}
if scsScoreCardSelected {
if scsRepoToken != "" && scsRepoURL != "" {
scsConfig.Scorecard = trueString
scsConfig.RepoToken = scsRepoToken
scsConfig.RepoURL = strings.ToLower(scsRepoURL)
} else {
if userScanTypes == "" {
fmt.Println(ScsRepoWarningMsg)
} else {
return nil, errors.Errorf(ScsRepoRequiredMsg)
}
}
func getSCSEnginesSelected(scsEngines string) (isScorecardSelected, isSecretDetectionSelected bool) {
if scsEngines == "" {
return true, true
}
scsEnginesTypes := strings.Split(scsEngines, ",")
for _, engineType := range scsEnginesTypes {
engineType = strings.TrimSpace(engineType)
switch engineType {
case ScsSecretDetectionType:
isSecretDetectionSelected = true
case ScsScoreCardType:
isScorecardSelected = true
}
if scsConfig.Scorecard != trueString && scsConfig.Twoms != trueString {
return nil, nil
}
return isScorecardSelected, isSecretDetectionSelected
}

func isURLSupportedByScorecard(scsRepoURL string) bool {
// only for https; currently our scorecard solution doesn't support GitHub Enterprise Server hosts
githubURLPattern := regexp.MustCompile(`^(?:https?://)?github\.com/.+`)
isGithubURL := githubURLPattern.MatchString(scsRepoURL)
if scsRepoURL != "" && !isGithubURL {
fmt.Println(ScsScorecardUnsupportedHostWarningMsg)
}
return isGithubURL
}

func isScorecardRunnable(scsRepoToken, scsRepoURL, userScanTypes string) (bool, error) {
if scsRepoToken == "" || scsRepoURL == "" {
if userScanTypes != "" {
return false, errors.Errorf(ScsRepoRequiredMsg)
}
fmt.Println(ScsRepoWarningMsg)
return false, nil
}

return isURLSupportedByScorecard(scsRepoURL), nil
}

func addSCSScan(cmd *cobra.Command, resubmitConfig []wrappers.Config, hasEnterpriseSecretsLicense bool) (map[string]interface{}, error) {
if !scanTypeEnabled(commonParams.ScsType) && !scanTypeEnabled(commonParams.MicroEnginesType) {
return nil, nil
}
scsConfig := wrappers.SCSConfig{}
SCSMapConfig := make(map[string]interface{})
SCSMapConfig[resultsMapType] = commonParams.MicroEnginesType // scs is still microengines in the scans API
userScanTypes, _ := cmd.Flags().GetString(commonParams.ScanTypes)
scsRepoToken := viper.GetString(commonParams.ScsRepoTokenKey)
if token, _ := cmd.Flags().GetString(commonParams.SCSRepoTokenFlag); token != "" {
scsRepoToken = token
}
viper.Set(commonParams.SCSRepoTokenFlag, scsRepoToken) // sanitizeLogs uses viper to get the value
scsRepoURL, _ := cmd.Flags().GetString(commonParams.SCSRepoURLFlag)
viper.Set(commonParams.SCSRepoURLFlag, scsRepoURL) // sanitizeLogs uses viper to get the value
SCSEngines, _ := cmd.Flags().GetString(commonParams.SCSEnginesFlag)
if resubmitConfig != nil {
scsConfig = createResubmitConfig(resubmitConfig, scsRepoToken, scsRepoURL, hasEnterpriseSecretsLicense)
SCSMapConfig[resultsMapValue] = &scsConfig
return SCSMapConfig, nil
}
return nil, nil
scsScoreCardSelected, scsSecretDetectionSelected := getSCSEnginesSelected(SCSEngines)

if scsSecretDetectionSelected && hasEnterpriseSecretsLicense {
scsConfig.Twoms = trueString
}

if scsScoreCardSelected {
canRunScorecard, err := isScorecardRunnable(scsRepoToken, scsRepoURL, userScanTypes)
if err != nil {
return nil, err
}
if canRunScorecard {
scsConfig.Scorecard = trueString
scsConfig.RepoToken = scsRepoToken
scsConfig.RepoURL = strings.ToLower(scsRepoURL)
}
}

if scsConfig.Scorecard != trueString && scsConfig.Twoms != trueString {
return nil, nil
}

SCSMapConfig[resultsMapValue] = &scsConfig
return SCSMapConfig, nil
}

func validateScanTypes(cmd *cobra.Command, jwtWrapper wrappers.JWTWrapper, featureFlagsWrapper wrappers.FeatureFlagsWrapper) error {
Expand Down
162 changes: 162 additions & 0 deletions internal/commands/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"archive/zip"
"bytes"
"fmt"
"io"
"log"
"os"
"reflect"
Expand All @@ -31,7 +32,9 @@ const (
unknownFlag = "unknown flag: --chibutero"
blankSpace = " "
errorMissingBranch = "Failed creating a scan: Please provide a branch"
dummyGitlabRepo = "https://gitlab.com/dummy-org/gitlab-dummy"
dummyRepo = "https://github.com/dummyuser/dummy_project.git"
dummyShortenedGithubRepo = "github.com/dummyuser/dummy_project.git"
dummyToken = "dummyToken"
dummySSHRepo = "[email protected]:dummyRepo/dummyProject.git"
errorSourceBadFormat = "Failed creating a scan: Input in bad format: Sources input has bad format: "
Expand Down Expand Up @@ -1034,6 +1037,165 @@ func TestCreateScan_WithSCSSecretDetection_scsMapHasSecretDetection(t *testing.T
}
}

func TestCreateScan_WithSCSSecretDetectionAndScorecardShortenedGithubRepo_scsMapHasBoth(t *testing.T) {
// Create a pipe for capturing stdout
r, w, _ := os.Pipe()
oldStdout := os.Stdout
defer func() { os.Stdout = oldStdout }()
os.Stdout = w // Redirecting stdout to the pipe

var resubmitConfig []wrappers.Config
cmdCommand := &cobra.Command{
Use: "scan",
Short: "Scan a project",
Long: `Scan a project`,
}
cmdCommand.PersistentFlags().String(commonParams.SCSEnginesFlag, "", "SCS Engine flag")
cmdCommand.PersistentFlags().String(commonParams.SCSRepoTokenFlag, "", "GitHub token to be used with SCS engines")
cmdCommand.PersistentFlags().String(commonParams.SCSRepoURLFlag, "", "GitHub url to be used with SCS engines")
_ = cmdCommand.Execute()
_ = cmdCommand.Flags().Set(commonParams.SCSEnginesFlag, "secret-detection,scorecard")
_ = cmdCommand.Flags().Set(commonParams.SCSRepoTokenFlag, dummyToken)
_ = cmdCommand.Flags().Set(commonParams.SCSRepoURLFlag, dummyShortenedGithubRepo)

result, _ := addSCSScan(cmdCommand, resubmitConfig, true)

// Close the writer to signal that we are done capturing the output
w.Close()

// Read from the pipe (stdout)
var buf bytes.Buffer
_, err := io.Copy(&buf, r) // Copy the captured output to a buffer
if err != nil {
t.Fatalf("Failed to capture output: %v", err)
}

output := buf.String()
if strings.Contains(output, ScsScorecardUnsupportedHostWarningMsg) {
t.Errorf("Expected output to not contain %q, but got %q", ScsScorecardUnsupportedHostWarningMsg, output)
}

scsConfig := wrappers.SCSConfig{
Twoms: "true",
Scorecard: "true",
RepoURL: dummyShortenedGithubRepo,
RepoToken: dummyToken,
}
scsMapConfig := make(map[string]interface{})
scsMapConfig[resultsMapType] = commonParams.MicroEnginesType
scsMapConfig[resultsMapValue] = &scsConfig

if !reflect.DeepEqual(result, scsMapConfig) {
t.Errorf("Expected %+v, but got %+v", scsMapConfig, result)
}
}

func TestCreateScan_WithSCSSecretDetectionAndScorecardGitLabRepo_scsMapHasSecretDetection(t *testing.T) {
// Create a pipe for capturing stdout
r, w, _ := os.Pipe()
oldStdout := os.Stdout
defer func() { os.Stdout = oldStdout }()
os.Stdout = w // Redirecting stdout to the pipe

var resubmitConfig []wrappers.Config
cmdCommand := &cobra.Command{
Use: "scan",
Short: "Scan a project",
Long: `Scan a project`,
}
cmdCommand.PersistentFlags().String(commonParams.SCSEnginesFlag, "", "SCS Engine flag")
cmdCommand.PersistentFlags().String(commonParams.SCSRepoTokenFlag, "", "GitHub token to be used with SCS engines")
cmdCommand.PersistentFlags().String(commonParams.SCSRepoURLFlag, "", "GitHub url to be used with SCS engines")
_ = cmdCommand.Execute()
_ = cmdCommand.Flags().Set(commonParams.SCSEnginesFlag, "secret-detection,scorecard")
_ = cmdCommand.Flags().Set(commonParams.SCSRepoTokenFlag, dummyToken)
_ = cmdCommand.Flags().Set(commonParams.SCSRepoURLFlag, dummyGitlabRepo)

result, _ := addSCSScan(cmdCommand, resubmitConfig, true)

// Close the writer to signal that we are done capturing the output
w.Close()

// Read from the pipe (stdout)
var buf bytes.Buffer
_, err := io.Copy(&buf, r) // Copy the captured output to a buffer
if err != nil {
t.Fatalf("Failed to capture output: %v", err)
}

output := buf.String()
if !strings.Contains(output, ScsScorecardUnsupportedHostWarningMsg) {
t.Errorf("Expected output to contain %q, but got %q", ScsScorecardUnsupportedHostWarningMsg, output)
}

scsConfig := wrappers.SCSConfig{
Twoms: "true",
Scorecard: "",
RepoURL: "",
RepoToken: "",
}
scsMapConfig := make(map[string]interface{})
scsMapConfig[resultsMapType] = commonParams.MicroEnginesType
scsMapConfig[resultsMapValue] = &scsConfig

if !reflect.DeepEqual(result, scsMapConfig) {
t.Errorf("Expected %+v, but got %+v", scsMapConfig, result)
}
}

func TestCreateScan_WithSCSSecretDetectionAndScorecardGitSSHRepo_scsMapHasSecretDetection(t *testing.T) {
// Create a pipe for capturing stdout
r, w, _ := os.Pipe()
oldStdout := os.Stdout
defer func() { os.Stdout = oldStdout }()
os.Stdout = w // Redirecting stdout to the pipe

var resubmitConfig []wrappers.Config
cmdCommand := &cobra.Command{
Use: "scan",
Short: "Scan a project",
Long: `Scan a project`,
}
cmdCommand.PersistentFlags().String(commonParams.SCSEnginesFlag, "", "SCS Engine flag")
cmdCommand.PersistentFlags().String(commonParams.SCSRepoTokenFlag, "", "GitHub token to be used with SCS engines")
cmdCommand.PersistentFlags().String(commonParams.SCSRepoURLFlag, "", "GitHub url to be used with SCS engines")
_ = cmdCommand.Execute()
_ = cmdCommand.Flags().Set(commonParams.SCSEnginesFlag, "secret-detection,scorecard")
_ = cmdCommand.Flags().Set(commonParams.SCSRepoTokenFlag, dummyToken)
_ = cmdCommand.Flags().Set(commonParams.SCSRepoURLFlag, dummySSHRepo)

result, _ := addSCSScan(cmdCommand, resubmitConfig, true)

// Close the writer to signal that we are done capturing the output
w.Close()

// Read from the pipe (stdout)
var buf bytes.Buffer
_, err := io.Copy(&buf, r) // Copy the captured output to a buffer
if err != nil {
t.Fatalf("Failed to capture output: %v", err)
}

output := buf.String()
if !strings.Contains(output, ScsScorecardUnsupportedHostWarningMsg) {
t.Errorf("Expected output to contain %q, but got %q", ScsScorecardUnsupportedHostWarningMsg, output)
}

scsConfig := wrappers.SCSConfig{
Twoms: "true",
Scorecard: "",
RepoURL: "",
RepoToken: "",
}
scsMapConfig := make(map[string]interface{})
scsMapConfig[resultsMapType] = commonParams.MicroEnginesType
scsMapConfig[resultsMapValue] = &scsConfig

if !reflect.DeepEqual(result, scsMapConfig) {
t.Errorf("Expected %+v, but got %+v", scsMapConfig, result)
}
}

func Test_isDirFiltered(t *testing.T) {
type args struct {
filename string
Expand Down

0 comments on commit 3e4bf34

Please sign in to comment.