Skip to content

Commit

Permalink
Merge pull request #6582 from Checkmarx/kics/967
Browse files Browse the repository at this point in the history
feat(engine): add kics analyze command
  • Loading branch information
asofsilva authored Aug 14, 2023
2 parents 45deb5d + db53f82 commit fdea929
Show file tree
Hide file tree
Showing 13 changed files with 262 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ kics.config

# Results
results.*
platforms.json
gl-sast-results.json
sonarqube-results.json
cyclonedx-results.xml
Expand Down
15 changes: 15 additions & 0 deletions e2e/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ func Test_E2E_CLI(t *testing.T) {
checkExpectedOutput(t, &tt, arg)
}

if tt.Args.ExpectedAnalyzerResults != nil && arg < len(tt.Args.ExpectedResult) {
checkExpectedAnalyzerResults(t, &tt, arg)
}

if tt.Args.ExpectedPayload != nil {
// Check payload file
utils.FileCheck(t, tt.Args.ExpectedPayload[arg], tt.Args.ExpectedPayload[arg], "payload")
Expand Down Expand Up @@ -127,6 +131,11 @@ func Test_E2E_CLI(t *testing.T) {
})
}

func checkExpectedAnalyzerResults(t *testing.T, tt *testcases.TestCase, argIndex int) {
jsonFileName := tt.Args.ExpectedResult[argIndex].ResultsFile + ".json"
utils.JSONSchemaValidationFromFile(t, jsonFileName, "AnalyzerResults.json")
}

func checkExpectedOutput(t *testing.T, tt *testcases.TestCase, argIndex int) {
jsonFileName := tt.Args.ExpectedResult[argIndex].ResultsFile + ".json"
resultsFormats := tt.Args.ExpectedResult[argIndex].ResultsFormats
Expand Down Expand Up @@ -211,10 +220,16 @@ func prepareTemplates() testcases.TestTemplates {
remediateHelp = []string{}
}

var analyzeHelp, errAH = utils.PrepareExpected("analyze_help", "fixtures/assets")
if errAH != nil {
analyzeHelp = []string{}
}

return testcases.TestTemplates{
Help: strings.Join(help, "\n"),
ScanHelp: strings.Join(scanHelp, "\n"),
RemediateHelp: strings.Join(remediateHelp, "\n"),
AnalyzeHelp: strings.Join(analyzeHelp, "\n"),
}
}

Expand Down
1 change: 1 addition & 0 deletions e2e/fixtures/E2E_CLI_066_ANALYZE_RESULTS.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Types":["ansible","openapi"],"Exc":[],"ExpectedLOC":1233}
18 changes: 18 additions & 0 deletions e2e/fixtures/assets/analyze_help
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Usage:
kics remediate [flags]

Flags:
-h, --help help for analyze
--analyze-path strings paths or directories to scan
example: "./somepath,somefile.txt"
--analyze-results string points to the JSON results file of analyzer (default "platforms.json")

Global Flags:
--ci display only log messages to CLI output (mutually exclusive with silent)
-f, --log-format string determines log format (pretty,json) (default "pretty")
--log-level string determines log level (TRACE,DEBUG,INFO,WARN,ERROR,FATAL) (default "INFO")
--log-path string path to generate log file (info.log)
--no-color disable CLI color output
--profiling string enables performance profiler that prints resource consumption metrics in the logs during the execution (CPU, MEM)
-s, --silent silence stdout messages (mutually exclusive with verbose and ci)
-v, --verbose write logs to stdout too (mutually exclusive with silent)
1 change: 1 addition & 0 deletions e2e/fixtures/assets/help
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Usage:
kics [command]

Available Commands:
analyze Determines the detected platforms of a certain project
generate-id Generates uuid for query
help Help about any command
list-platforms List supported platforms
Expand Down
27 changes: 27 additions & 0 deletions e2e/fixtures/schemas/result-analyzer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"type": "object",
"required": [
"types",
"exc",
"expectedloc"
],
"properties": {
"types": {
"type": "array",
"items": {
"type": "string"
}
},
"exc": {
"type": "array",
"items": {
"type": "string"
}
},
"expectedloc": {
"type": "integer",
"minimum": 0
}
}
}

23 changes: 23 additions & 0 deletions e2e/testcases/e2e-cli-066_analyze_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Package testcases provides end-to-end (E2E) testing functionality for the application.
package testcases

// E2E-CLI-066 - KICS analyze
// should finish successfully and return exit code 0
func init() { //nolint
testSample := TestCase{
Name: "should perform a valid analyze [E2E-CLI-066]",
Args: args{
Args: []cmdArgs{
[]string{"analyze",
"--analyze-path", "/path/e2e/fixtures/samples/swagger",
"--analyze-results", "/path/e2e/output/E2E_CLI_066_ANALYZE_RESULTS.json"},
},
ExpectedAnalyzerResults: &ResultsValidation{
ResultsFile: "E2E_CLI_066_ANALYZE_RESULTS",
ResultsFormats: []string{"json"},
},
},
WantStatus: []int{0},
}
Tests = append(Tests, testSample)
}
14 changes: 8 additions & 6 deletions e2e/testcases/general.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,20 @@ type ResultsValidation struct {
}

type args struct {
Args []cmdArgs // args to pass to kics binary
ExpectedOut []string // path to file with expected output
ExpectedPayload []string
ExpectedResult []ResultsValidation
ExpectedLog LogValidation
UseMock []bool
Args []cmdArgs // args to pass to kics binary
ExpectedOut []string // path to file with expected output
ExpectedPayload []string
ExpectedResult []ResultsValidation
ExpectedAnalyzerResults *ResultsValidation
ExpectedLog LogValidation
UseMock []bool
}

type TestTemplates struct {
Help string
ScanHelp string
RemediateHelp string
AnalyzeHelp string
}

type cmdArgs []string
Expand Down
136 changes: 136 additions & 0 deletions internal/console/analyze.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package console

import (
_ "embed" // Embed kics CLI img and analyze-flags
"encoding/json"
"os"
"path/filepath"

"github.com/Checkmarx/kics/internal/console/flags"
sentryReport "github.com/Checkmarx/kics/internal/sentry"
"github.com/Checkmarx/kics/pkg/analyzer"
"github.com/Checkmarx/kics/pkg/engine/source"
"github.com/Checkmarx/kics/pkg/model"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)

var (
//go:embed assets/analyze-flags.json
analyzeFlagsListContent string
)

const (
perms = 0640
)

// NewAnalyzeCmd creates a new instance of the analyze Command
func NewAnalyzeCmd() *cobra.Command {
return &cobra.Command{
Use: "analyze",
Short: "Determines the detected platforms of a certain project",
RunE: func(cmd *cobra.Command, args []string) error {
return analyze()
},
}
}

func initAnalyzeCmd(analyzeCmd *cobra.Command) error {
if err := flags.InitJSONFlags(
analyzeCmd,
analyzeFlagsListContent,
false,
source.ListSupportedPlatforms(),
source.ListSupportedCloudProviders()); err != nil {
return err
}

if err := analyzeCmd.MarkFlagRequired(flags.AnalyzePath); err != nil {
sentryReport.ReportSentry(&sentryReport.Report{
Message: "Failed to add command required flags",
Err: err,
Location: "func initAnalyzeCmd()",
}, true)
log.Err(err).Msg("Failed to add command required flags")
}
return nil
}

func analyze() error {
// save the analyze parameters into the AnalyzeParameters struct
analyzeParams := getAnalyzeParameters()

return executeAnalyze(analyzeParams)
}

func getAnalyzeParameters() *analyzer.Parameters {
analyzeParams := analyzer.Parameters{
Path: flags.GetMultiStrFlag(flags.AnalyzePath),
Results: flags.GetStrFlag(flags.AnalyzeResults),
}

return &analyzeParams
}

func executeAnalyze(analyzeParams *analyzer.Parameters) error {
log.Debug().Msg("console.scan()")

for _, warn := range warnings {
log.Warn().Msgf(warn)
}

console := newConsole()

console.preScan()

analyzerStruct := &analyzer.Analyzer{
Paths: analyzeParams.Path,
Types: []string{""},
ExcludeTypes: []string{""},
Exc: []string{""},
ExcludeGitIgnore: false,
GitIgnoreFileName: "",
}

analyzedPaths, err := analyzer.Analyze(analyzerStruct)

if err != nil {
log.Err(err)
return err
}

err = writeToFile(analyzeParams.Results, analyzedPaths)

if err != nil {
log.Err(err)
return err
}

return nil
}

func writeToFile(resultsPath string, analyzerResults model.AnalyzedPaths) error {
err := os.MkdirAll(filepath.Dir(resultsPath), perms)
if err != nil {
return err
}

f, err := os.Create(resultsPath)
if err != nil {
return err
}

defer f.Close()

content, err := json.Marshal(analyzerResults)
if err != nil {
return err
}

_, err = f.Write(content)
if err != nil {
return err
}

return nil
}
14 changes: 14 additions & 0 deletions internal/console/assets/analyze-flags.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"analyze-path": {
"flagType": "multiStr",
"shorthandFlag": "",
"defaultValue": null,
"usage": "paths or directories to scan\nexample: \"./somepath,somefile.txt\""
},
"analyze-results": {
"flagType": "str",
"shorthandFlag": "",
"defaultValue": "platforms.json",
"usage": "points to the JSON results file of analyzer"
}
}
7 changes: 7 additions & 0 deletions internal/console/flags/analyze_flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package flags

// Flags constants for analyze
const (
AnalyzeResults = "analyze-results"
AnalyzePath = "analyze-path"
)
6 changes: 6 additions & 0 deletions internal/console/kics.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ func NewKICSCmd() *cobra.Command {
func initialize(rootCmd *cobra.Command) error {
scanCmd := NewScanCmd()
remediateCmd := NewRemediateCmd()
analyzeCmd := NewAnalyzeCmd()
rootCmd.AddCommand(NewVersionCmd())
rootCmd.AddCommand(NewGenerateIDCmd())
rootCmd.AddCommand(scanCmd)
rootCmd.AddCommand(NewListPlatformsCmd())
rootCmd.AddCommand(remediateCmd)
rootCmd.AddCommand(analyzeCmd)
rootCmd.CompletionOptions.DisableDefaultCmd = true

if err := flags.InitJSONFlags(
Expand All @@ -67,6 +69,10 @@ func initialize(rootCmd *cobra.Command) error {
return err
}

if err := initAnalyzeCmd(analyzeCmd); err != nil {
return err
}

return initScanCmd(scanCmd)
}

Expand Down
5 changes: 5 additions & 0 deletions pkg/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ const (
knative = "knative"
)

type Parameters struct {
Results string
Path []string
}

// regexSlice is a struct to contain a slice of regex
type regexSlice struct {
regex []*regexp.Regexp
Expand Down

0 comments on commit fdea929

Please sign in to comment.