Skip to content

Commit 677af6a

Browse files
wxiaoguangdelvh
andauthored
Follow improve code quality (#21465)
After some discussion, introduce a new slice `brokenArgs` to make `gitCmd.Run()` return errors if any dynamic argument is invalid. Co-authored-by: delvh <[email protected]>
1 parent d98c5db commit 677af6a

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed

modules/git/command.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type Command struct {
4040
parentContext context.Context
4141
desc string
4242
globalArgsLength int
43+
brokenArgs []string
4344
}
4445

4546
func (c *Command) String() string {
@@ -50,6 +51,7 @@ func (c *Command) String() string {
5051
}
5152

5253
// NewCommand creates and returns a new Git Command based on given command and arguments.
54+
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
5355
func NewCommand(ctx context.Context, args ...string) *Command {
5456
// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it
5557
cargs := make([]string, len(globalCommandArgs))
@@ -63,11 +65,13 @@ func NewCommand(ctx context.Context, args ...string) *Command {
6365
}
6466

6567
// NewCommandNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
68+
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
6669
func NewCommandNoGlobals(args ...string) *Command {
6770
return NewCommandContextNoGlobals(DefaultContext, args...)
6871
}
6972

7073
// NewCommandContextNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
74+
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
7175
func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command {
7276
return &Command{
7377
name: GitExecutable,
@@ -89,20 +93,24 @@ func (c *Command) SetDescription(desc string) *Command {
8993
return c
9094
}
9195

92-
// AddArguments adds new argument(s) to the command.
96+
// AddArguments adds new argument(s) to the command. Each argument must be safe to be trusted.
97+
// User-provided arguments should be passed to AddDynamicArguments instead.
9398
func (c *Command) AddArguments(args ...string) *Command {
9499
c.args = append(c.args, args...)
95100
return c
96101
}
97102

98103
// AddDynamicArguments adds new dynamic argument(s) to the command.
99-
// If the argument is invalid (it shouldn't happen in real life), it panics to caller
104+
// The arguments may come from user input and can not be trusted, so no leading '-' is allowed to avoid passing options
100105
func (c *Command) AddDynamicArguments(args ...string) *Command {
101106
for _, arg := range args {
102107
if arg != "" && arg[0] == '-' {
103-
panic("invalid argument: " + arg)
108+
c.brokenArgs = append(c.brokenArgs, arg)
104109
}
105110
}
111+
if len(c.brokenArgs) != 0 {
112+
return c
113+
}
106114
c.args = append(c.args, args...)
107115
return c
108116
}
@@ -150,8 +158,14 @@ func CommonCmdServEnvs() []string {
150158
return commonBaseEnvs()
151159
}
152160

161+
var ErrBrokenCommand = errors.New("git command is broken")
162+
153163
// Run runs the command with the RunOpts
154164
func (c *Command) Run(opts *RunOpts) error {
165+
if len(c.brokenArgs) != 0 {
166+
log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " "))
167+
return ErrBrokenCommand
168+
}
155169
if opts == nil {
156170
opts = &RunOpts{}
157171
}

modules/git/command_test.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,13 @@ func TestRunWithContextStd(t *testing.T) {
2727
assert.Empty(t, stdout)
2828
}
2929

30-
assert.Panics(t, func() {
31-
cmd = NewCommand(context.Background())
32-
cmd.AddDynamicArguments("-test")
33-
})
34-
35-
assert.Panics(t, func() {
36-
cmd = NewCommand(context.Background())
37-
cmd.AddDynamicArguments("--test")
38-
})
30+
cmd = NewCommand(context.Background())
31+
cmd.AddDynamicArguments("-test")
32+
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
33+
34+
cmd = NewCommand(context.Background())
35+
cmd.AddDynamicArguments("--test")
36+
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
3937

4038
subCmd := "version"
4139
cmd = NewCommand(context.Background()).AddDynamicArguments(subCmd) // for test purpose only, the sub-command should never be dynamic for production

0 commit comments

Comments
 (0)