Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support -- arguments for sbom and other extensions [HEAD-861] #4892

Merged
merged 6 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 44 additions & 22 deletions cliv2/cmd/cliv2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/snyk/go-application-framework/pkg/configuration"
localworkflows "github.com/snyk/go-application-framework/pkg/local_workflows"
"github.com/snyk/go-application-framework/pkg/networking"
"github.com/snyk/go-application-framework/pkg/utils"
"github.com/snyk/go-application-framework/pkg/workflow"
"github.com/snyk/go-httpauth/pkg/httpauth"
"github.com/snyk/snyk-iac-capture/pkg/capture"
Expand All @@ -43,7 +44,7 @@ import (

var internalOS string
var engine workflow.Engine
var config configuration.Configuration
var globalConfiguration configuration.Configuration
var helpProvided bool
var debugLogger = zerolog.New(zerolog.ConsoleWriter{
Out: os.Stderr,
Expand Down Expand Up @@ -141,23 +142,44 @@ func getFullCommandString(cmd *cobra.Command) string {
return name
}

func updateConfigFromParameter(config configuration.Configuration, args []string, rawArgs []string) {
// extract everything behind --
doubleDashArgs := []string{}
doubleDashPosition := -1
PeterSchafer marked this conversation as resolved.
Show resolved Hide resolved
for i, v := range rawArgs {
if doubleDashPosition >= 0 {
doubleDashArgs = append(doubleDashArgs, v)
} else if v == "--" {
doubleDashPosition = i
}
}
config.Set(configuration.UNKNOWN_ARGS, doubleDashArgs)

// only consider the first positional argument as input directory if it is not behind a double dash.
if len(args) > 0 && !utils.Contains(doubleDashArgs, args[0]) {
config.Set(configuration.INPUT_DIRECTORY, args[0])
}
}

// main workflow
func runCommand(cmd *cobra.Command, args []string) error {
return runMainWorkflow(globalConfiguration, cmd, args, os.Args)
PeterSchafer marked this conversation as resolved.
Show resolved Hide resolved
}

func runMainWorkflow(config configuration.Configuration, cmd *cobra.Command, args []string, rawArgs []string) error {

err := config.AddFlagSet(cmd.Flags())
if err != nil {
debugLogger.Print("Failed to add flags", err)
return err
}

updateConfigFromParameter(config, args, rawArgs)

name := getFullCommandString(cmd)
debugLogger.Print("Running ", name)
engine.GetAnalytics().SetCommand(name)

if len(args) > 0 {
config.Set(configuration.INPUT_DIRECTORY, args[0])
}

data, err := engine.Invoke(workflow.NewWorkflowIdentifier(name))
if err == nil {
_, err = engine.InvokeWithInput(localworkflows.WORKFLOWID_OUTPUT_WORKFLOW, data)
Expand Down Expand Up @@ -197,15 +219,15 @@ func defaultCmd(args []string) error {
// prepare the invocation of the legacy CLI by
// * enabling stdio
// * by specifying the raw cmd args for it
config.Set(configuration.WORKFLOW_USE_STDIO, true)
config.Set(configuration.RAW_CMD_ARGS, args)
globalConfiguration.Set(configuration.WORKFLOW_USE_STDIO, true)
PeterSchafer marked this conversation as resolved.
Show resolved Hide resolved
globalConfiguration.Set(configuration.RAW_CMD_ARGS, args)
_, err := engine.Invoke(basic_workflows.WORKFLOWID_LEGACY_CLI)
return err
}

func getGlobalFLags() *pflag.FlagSet {
globalConfiguration := workflow.GetGlobalConfiguration()
globalFLags := workflow.FlagsetFromConfigurationOptions(globalConfiguration)
globalConfigurationOptions := workflow.GetGlobalConfiguration()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): let's rename GetGlobalConfiguration to GetGlobalConfigurationOptions in a follow-up PR.

globalFLags := workflow.FlagsetFromConfigurationOptions(globalConfigurationOptions)
globalFLags.Bool(basic_workflows.PROXY_NOAUTH, false, "")
globalFLags.Bool(disable_analytics_flag, false, "")
return globalFLags
Expand Down Expand Up @@ -319,11 +341,11 @@ func handleError(err error) HandleError {
func displayError(err error) {
if err != nil {
if _, ok := err.(*exec.ExitError); !ok {
if config.GetBool(localworkflows.OUTPUT_CONFIG_KEY_JSON) {
if globalConfiguration.GetBool(localworkflows.OUTPUT_CONFIG_KEY_JSON) {
jsonError := JsonErrorStruct{
Ok: false,
ErrorMsg: err.Error(),
Path: config.GetString(configuration.INPUT_DIRECTORY),
Path: globalConfiguration.GetString(configuration.INPUT_DIRECTORY),
}

jsonErrorBuffer, _ := json.MarshalIndent(jsonError, "", " ")
Expand Down Expand Up @@ -439,20 +461,20 @@ func MainWithErrorCode() int {
_ = rootCommand.ParseFlags(os.Args)

// create engine
config = configuration.New()
err = config.AddFlagSet(rootCommand.LocalFlags())
globalConfiguration = configuration.New()
err = globalConfiguration.AddFlagSet(rootCommand.LocalFlags())
if err != nil {
debugLogger.Print("Failed to add flags to root command", err)
}

debugEnabled := config.GetBool(configuration.DEBUG)
debugLogger := getDebugLogger(config)
debugEnabled := globalConfiguration.GetBool(configuration.DEBUG)
debugLogger := getDebugLogger(globalConfiguration)

initApplicationConfiguration(config)
engine = app.CreateAppEngineWithOptions(app.WithZeroLogger(debugLogger), app.WithConfiguration(config))
initApplicationConfiguration(globalConfiguration)
engine = app.CreateAppEngineWithOptions(app.WithZeroLogger(debugLogger), app.WithConfiguration(globalConfiguration))

if noProxyAuth := config.GetBool(basic_workflows.PROXY_NOAUTH); noProxyAuth {
config.Set(configuration.PROXY_AUTHENTICATION_MECHANISM, httpauth.StringFromAuthenticationMechanism(httpauth.NoAuth))
if noProxyAuth := globalConfiguration.GetBool(basic_workflows.PROXY_NOAUTH); noProxyAuth {
globalConfiguration.Set(configuration.PROXY_AUTHENTICATION_MECHANISM, httpauth.StringFromAuthenticationMechanism(httpauth.NoAuth))
}

// initialize the extensions -> they register themselves at the engine
Expand Down Expand Up @@ -485,21 +507,21 @@ func MainWithErrorCode() int {
networkAccess.AddHeaderField(
"User-Agent",
networking.UserAgent(
networking.UaWithConfig(config),
networking.UaWithConfig(globalConfiguration),
networking.UaWithApplication("snyk-cli", cliv2.GetFullVersion()),
networking.UaWithOS(internalOS)).String(),
)

if debugEnabled {
writeLogHeader(config, networkAccess)
writeLogHeader(globalConfiguration, networkAccess)
}

// init Analytics
cliAnalytics := engine.GetAnalytics()
cliAnalytics.SetVersion(cliv2.GetFullVersion())
cliAnalytics.SetCmdArguments(os.Args[1:])
cliAnalytics.SetOperatingSystem(internalOS)
if config.GetBool(configuration.ANALYTICS_DISABLED) == false {
if globalConfiguration.GetBool(configuration.ANALYTICS_DISABLED) == false {
PeterSchafer marked this conversation as resolved.
Show resolved Hide resolved
defer sendAnalytics(cliAnalytics, debugLogger)
}

Expand Down
76 changes: 72 additions & 4 deletions cliv2/cmd/cliv2/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import (
"testing"

"github.com/snyk/go-application-framework/pkg/configuration"
localworkflows "github.com/snyk/go-application-framework/pkg/local_workflows"
"github.com/snyk/go-application-framework/pkg/workflow"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
)

func cleanup() {
helpProvided = false
config = nil
globalConfiguration = nil
engine = nil
}

Expand Down Expand Up @@ -87,9 +89,9 @@ func Test_initApplicationConfiguration_DisablesAnalytics(t *testing.T) {
func Test_CreateCommandsForWorkflowWithSubcommands(t *testing.T) {
defer cleanup()

config = configuration.New()
config.Set(configuration.DEBUG, true)
engine = workflow.NewWorkFlowEngine(config)
globalConfiguration = configuration.New()
globalConfiguration.Set(configuration.DEBUG, true)
engine = workflow.NewWorkFlowEngine(globalConfiguration)

fn := func(invocation workflow.InvocationContext, input []workflow.Data) ([]workflow.Data, error) {
return []workflow.Data{}, nil
Expand Down Expand Up @@ -145,3 +147,69 @@ func Test_CreateCommandsForWorkflowWithSubcommands(t *testing.T) {
assert.Equal(t, "cmd2", cmd2.Name())
assert.True(t, cmd2.Hidden)
}

func Test_runMainWorkflow_unknownargs(t *testing.T) {

tests := map[string]struct {
inputDir string
unknownArgs []string
}{
"input dir with unknown arguments": {inputDir: "a/b/c", unknownArgs: []string{"a", "b", "c"}},
"no input dir with unknown arguments": {inputDir: "", unknownArgs: []string{"a", "b", "c"}},
"input dir without unknown arguments": {inputDir: "a", unknownArgs: []string{}},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {

expectedInputDir := tc.inputDir
expectedUnknownArgs := tc.unknownArgs

defer cleanup()
globalConfiguration = configuration.New()
globalConfiguration.Set(configuration.DEBUG, true)
engine = workflow.NewWorkFlowEngine(globalConfiguration)

fn := func(invocation workflow.InvocationContext, input []workflow.Data) ([]workflow.Data, error) {
return []workflow.Data{}, nil
}

// setup workflow engine to contain a workflow with subcommands
commandList := []string{"command", localworkflows.WORKFLOWID_OUTPUT_WORKFLOW.Host}
for _, v := range commandList {
workflowConfig := workflow.ConfigurationOptionsFromFlagset(pflag.NewFlagSet("pla", pflag.ContinueOnError))
workflowId1 := workflow.NewWorkflowIdentifier(v)
_, err := engine.Register(workflowId1, workflowConfig, fn)
if err != nil {
t.Fatal(err)
}
}

_ = engine.Init()

config := configuration.NewInMemory()
cmd := &cobra.Command{
Use: "command",
}

positionalArgs := []string{expectedInputDir}
positionalArgs = append(positionalArgs, expectedUnknownArgs...)

rawArgs := []string{"app", "command", "--sad", expectedInputDir}
if len(expectedUnknownArgs) > 0 {
rawArgs = append(rawArgs, "--")
rawArgs = append(rawArgs, expectedUnknownArgs...)
}

// call method under test
err := runMainWorkflow(config, cmd, positionalArgs, rawArgs)
assert.Nil(t, err)

actualInputDir := config.GetString(configuration.INPUT_DIRECTORY)
assert.Equal(t, expectedInputDir, actualInputDir)

actualUnknownArgs := config.GetStringSlice(configuration.UNKNOWN_ARGS)
assert.Equal(t, expectedUnknownArgs, actualUnknownArgs)
})
}
}
2 changes: 1 addition & 1 deletion cliv2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/snyk/cli-extension-iac-rules v0.0.0-20230601153200-c572cfce46ce
github.com/snyk/cli-extension-sbom v0.0.0-20230926124903-9705d7d47d8f
github.com/snyk/container-cli v0.0.0-20230920093251-fe865879a91f
github.com/snyk/go-application-framework v0.0.0-20230915105125-18e4f97ef870
github.com/snyk/go-application-framework v0.0.0-20231004153030-f8b8df23bcf4
github.com/snyk/go-httpauth v0.0.0-20230726132335-d454674305a7
github.com/snyk/snyk-iac-capture v0.6.0
github.com/snyk/snyk-ls v0.0.0-20230911152618-39fc0f68d431
Expand Down
Loading
Loading