Skip to content

Commit 07d3e04

Browse files
authored
Merge pull request #6967 from snyk/fix/CLI-1634-risk-score-dropped-with-explicit-path-v2
fix: Exclude passthrough args after -- from scan input directories
2 parents b6736a4 + 087092b commit 07d3e04

2 files changed

Lines changed: 98 additions & 57 deletions

File tree

cliv2/pkg/core/main.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,18 @@ func updateConfigFromParameter(config configuration.Configuration, args []string
162162
}
163163
config.Set(configuration.UNKNOWN_ARGS, doubleDashArgs)
164164

165-
// only consider the first positional argument as input directory if it is not behind a double dash.
166-
if len(args) > 0 && !utils.Contains(doubleDashArgs, args[0]) {
167-
config.Set(configuration.INPUT_DIRECTORY, args)
168-
config.Set(localworkflows.ConfigurationNewAuthenticationToken, args[0])
165+
// Only positional args before "--" are input directories. Everything after "--" is
166+
// passthrough (e.g. build-tool flags like `-s settings.xml`) and must not leak into
167+
// INPUT_DIRECTORY, otherwise it gets misread as a path/package and force-routes to legacy.
168+
// cobra appends the post-"--" tokens as the suffix of args, so trim them off.
169+
positionalArgs := args
170+
if len(doubleDashArgs) > 0 && len(args) >= len(doubleDashArgs) {
171+
positionalArgs = args[:len(args)-len(doubleDashArgs)]
172+
}
173+
174+
if len(positionalArgs) > 0 {
175+
config.Set(configuration.INPUT_DIRECTORY, positionalArgs)
176+
config.Set(localworkflows.ConfigurationNewAuthenticationToken, positionalArgs[0])
169177
}
170178
}
171179

cliv2/pkg/core/main_test.go

Lines changed: 86 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -185,71 +185,104 @@ func Test_CreateCommandsForWorkflowWithSubcommands(t *testing.T) {
185185
assert.True(t, cmd2.Hidden)
186186
}
187187

188-
func Test_runMainWorkflow_unknownargs(t *testing.T) {
188+
// setupMainWorkflowTestEnv wires up the global engine/config that runMainWorkflow needs and
189+
// returns a fresh per-invocation config plus a command. Callers should `defer cleanup()`.
190+
func setupMainWorkflowTestEnv(t *testing.T) (configuration.Configuration, *cobra.Command) {
191+
t.Helper()
192+
193+
globalConfiguration = configuration.New()
194+
globalConfiguration.Set(configuration.DEBUG, true)
195+
globalEngine = workflow.NewWorkFlowEngine(globalConfiguration)
196+
197+
noopWorkflow := func(workflow.InvocationContext, []workflow.Data) ([]workflow.Data, error) {
198+
return []workflow.Data{}, nil
199+
}
200+
for _, name := range []string{"command", localworkflows.WORKFLOWID_OUTPUT_WORKFLOW.Host} {
201+
opts := workflow.ConfigurationOptionsFromFlagset(pflag.NewFlagSet("pla", pflag.ContinueOnError))
202+
_, err := globalEngine.Register(workflow.NewWorkflowIdentifier(name), opts, noopWorkflow)
203+
require.NoError(t, err)
204+
}
205+
require.NoError(t, localworkflows.InitDataTransformationWorkflow(globalEngine))
206+
_ = globalEngine.Init()
207+
require.NoError(t, localworkflows.InitFilterFindingsWorkflow(globalEngine))
208+
209+
return configuration.NewWithOpts(configuration.WithAutomaticEnv()), &cobra.Command{Use: "command"}
210+
}
211+
212+
// Test_runMainWorkflow_inputDirectoryParsing is the CLI-1631 regression coverage. It asserts how
213+
// positional paths and "--" passthrough args map onto INPUT_DIRECTORY and UNKNOWN_ARGS. The key
214+
// invariant: passthrough tokens after "--" must never leak into INPUT_DIRECTORY (which would make
215+
// the downstream flow router misread them as package names and force the legacy, no-Risk-Score flow),
216+
// regardless of the path shape. wantInputDirs == nil means INPUT_DIRECTORY must be left unset so it
217+
// later defaults to the working directory.
218+
func Test_runMainWorkflow_inputDirectoryParsing(t *testing.T) {
189219
tests := map[string]struct {
190-
inputDir string
191-
unknownArgs []string
220+
positionalArgs []string
221+
rawArgs []string
222+
wantInputDirs []string
223+
wantUnknownArgs []string
192224
}{
193-
"input dir with unknown arguments": {inputDir: "a/b/c", unknownArgs: []string{"a", "b", "c"}},
194-
"no input dir with unknown arguments": {inputDir: "", unknownArgs: []string{"a", "b", "c"}},
195-
"input dir without unknown arguments": {inputDir: "a", unknownArgs: []string{}},
225+
"path with -- passthrough, current dir": {
226+
positionalArgs: []string{".", "-s", "settings.xml"},
227+
rawArgs: []string{"snyk", "test", ".", "--", "-s", "settings.xml"},
228+
wantInputDirs: []string{"."},
229+
wantUnknownArgs: []string{"-s", "settings.xml"},
230+
},
231+
"path with -- passthrough, relative": {
232+
positionalArgs: []string{"sub/project", "-s", "settings.xml"},
233+
rawArgs: []string{"snyk", "test", "sub/project", "--", "-s", "settings.xml"},
234+
wantInputDirs: []string{"sub/project"},
235+
wantUnknownArgs: []string{"-s", "settings.xml"},
236+
},
237+
"path with -- passthrough, absolute": {
238+
positionalArgs: []string{"/home/user/project", "-s", "settings.xml"},
239+
rawArgs: []string{"snyk", "test", "/home/user/project", "--", "-s", "settings.xml"},
240+
wantInputDirs: []string{"/home/user/project"},
241+
wantUnknownArgs: []string{"-s", "settings.xml"},
242+
},
243+
"only -- passthrough, no path": {
244+
positionalArgs: []string{"-s", "settings.xml"},
245+
rawArgs: []string{"snyk", "test", "--", "-s", "settings.xml"},
246+
wantInputDirs: nil,
247+
wantUnknownArgs: []string{"-s", "settings.xml"},
248+
},
249+
"no --, single path": {
250+
positionalArgs: []string{"."},
251+
rawArgs: []string{"snyk", "test", "."},
252+
wantInputDirs: []string{"."},
253+
},
254+
"no --, multiple paths": {
255+
positionalArgs: []string{"dir1", "dir2"},
256+
rawArgs: []string{"snyk", "test", "dir1", "dir2"},
257+
wantInputDirs: []string{"dir1", "dir2"},
258+
},
259+
"bare command, no path no --": {
260+
positionalArgs: []string{},
261+
rawArgs: []string{"snyk", "test"},
262+
wantInputDirs: nil,
263+
},
196264
}
197265

198266
for name, tc := range tests {
199267
t.Run(name, func(t *testing.T) {
200-
expectedInputDir := tc.inputDir
201-
expectedUnknownArgs := tc.unknownArgs
202-
203268
defer cleanup()
204-
globalConfiguration = configuration.New()
205-
globalConfiguration.Set(configuration.DEBUG, true)
206-
globalEngine = workflow.NewWorkFlowEngine(globalConfiguration)
207-
208-
fn := func(invocation workflow.InvocationContext, input []workflow.Data) ([]workflow.Data, error) {
209-
return []workflow.Data{}, nil
210-
}
211-
212-
// setup workflow engine to contain a workflow with subcommands
213-
commandList := []string{"command", localworkflows.WORKFLOWID_OUTPUT_WORKFLOW.Host}
214-
for _, v := range commandList {
215-
workflowConfig := workflow.ConfigurationOptionsFromFlagset(pflag.NewFlagSet("pla", pflag.ContinueOnError))
216-
workflowId1 := workflow.NewWorkflowIdentifier(v)
217-
_, err := globalEngine.Register(workflowId1, workflowConfig, fn)
218-
assert.NoError(t, err)
219-
}
269+
config, cmd := setupMainWorkflowTestEnv(t)
220270

221-
// Register our data transformation workflow
222-
err := localworkflows.InitDataTransformationWorkflow(globalEngine)
223-
assert.NoError(t, err)
271+
require.NoError(t, runMainWorkflow(config, cmd, tc.positionalArgs, tc.rawArgs))
224272

225-
_ = globalEngine.Init()
226-
// Register our data filter workflow
227-
err = localworkflows.InitFilterFindingsWorkflow(globalEngine)
228-
assert.NoError(t, err)
229-
230-
config := configuration.NewWithOpts(configuration.WithAutomaticEnv())
231-
cmd := &cobra.Command{
232-
Use: "command",
273+
if tc.wantInputDirs == nil {
274+
assert.Nil(t, config.Get(configuration.INPUT_DIRECTORY),
275+
"INPUT_DIRECTORY must be left unset so it defaults to the working directory")
276+
} else {
277+
assert.Equal(t, tc.wantInputDirs, config.GetStringSlice(configuration.INPUT_DIRECTORY),
278+
"passthrough args after -- must not leak into INPUT_DIRECTORY")
233279
}
234280

235-
positionalArgs := []string{expectedInputDir}
236-
positionalArgs = append(positionalArgs, expectedUnknownArgs...)
237-
238-
rawArgs := []string{"app", "command", "--sad", expectedInputDir}
239-
if len(expectedUnknownArgs) > 0 {
240-
rawArgs = append(rawArgs, "--")
241-
rawArgs = append(rawArgs, expectedUnknownArgs...)
281+
if len(tc.wantUnknownArgs) == 0 {
282+
assert.Empty(t, config.GetStringSlice(configuration.UNKNOWN_ARGS))
283+
} else {
284+
assert.Equal(t, tc.wantUnknownArgs, config.GetStringSlice(configuration.UNKNOWN_ARGS))
242285
}
243-
244-
// call method under test
245-
err = runMainWorkflow(config, cmd, positionalArgs, rawArgs)
246-
assert.Nil(t, err)
247-
248-
actualInputDir := config.GetString(configuration.INPUT_DIRECTORY)
249-
assert.Equal(t, expectedInputDir, actualInputDir)
250-
251-
actualUnknownArgs := config.GetStringSlice(configuration.UNKNOWN_ARGS)
252-
assert.Equal(t, expectedUnknownArgs, actualUnknownArgs)
253286
})
254287
}
255288
}

0 commit comments

Comments
 (0)