mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Backport #21464 and #21465 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -40,6 +40,7 @@ type Command struct { | |||||||
| 	parentContext    context.Context | 	parentContext    context.Context | ||||||
| 	desc             string | 	desc             string | ||||||
| 	globalArgsLength int | 	globalArgsLength int | ||||||
|  | 	brokenArgs       []string | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Command) String() string { | func (c *Command) String() string { | ||||||
| @@ -50,6 +51,7 @@ func (c *Command) String() string { | |||||||
| } | } | ||||||
|  |  | ||||||
| // NewCommand creates and returns a new Git Command based on given command and arguments. | // NewCommand creates and returns a new Git Command based on given command and arguments. | ||||||
|  | // Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead. | ||||||
| func NewCommand(ctx context.Context, args ...string) *Command { | func NewCommand(ctx context.Context, args ...string) *Command { | ||||||
| 	// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it | 	// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it | ||||||
| 	cargs := make([]string, len(globalCommandArgs)) | 	cargs := make([]string, len(globalCommandArgs)) | ||||||
| @@ -63,11 +65,13 @@ func NewCommand(ctx context.Context, args ...string) *Command { | |||||||
| } | } | ||||||
|  |  | ||||||
| // 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 | // 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 | ||||||
|  | // Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead. | ||||||
| func NewCommandNoGlobals(args ...string) *Command { | func NewCommandNoGlobals(args ...string) *Command { | ||||||
| 	return NewCommandContextNoGlobals(DefaultContext, args...) | 	return NewCommandContextNoGlobals(DefaultContext, args...) | ||||||
| } | } | ||||||
|  |  | ||||||
| // 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 | // 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 | ||||||
|  | // Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead. | ||||||
| func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command { | func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command { | ||||||
| 	return &Command{ | 	return &Command{ | ||||||
| 		name:          GitExecutable, | 		name:          GitExecutable, | ||||||
| @@ -89,12 +93,28 @@ func (c *Command) SetDescription(desc string) *Command { | |||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
| // AddArguments adds new argument(s) to the command. | // AddArguments adds new argument(s) to the command. Each argument must be safe to be trusted. | ||||||
|  | // User-provided arguments should be passed to AddDynamicArguments instead. | ||||||
| func (c *Command) AddArguments(args ...string) *Command { | func (c *Command) AddArguments(args ...string) *Command { | ||||||
| 	c.args = append(c.args, args...) | 	c.args = append(c.args, args...) | ||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // AddDynamicArguments adds new dynamic argument(s) to the command. | ||||||
|  | // The arguments may come from user input and can not be trusted, so no leading '-' is allowed to avoid passing options | ||||||
|  | func (c *Command) AddDynamicArguments(args ...string) *Command { | ||||||
|  | 	for _, arg := range args { | ||||||
|  | 		if arg != "" && arg[0] == '-' { | ||||||
|  | 			c.brokenArgs = append(c.brokenArgs, arg) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if len(c.brokenArgs) != 0 { | ||||||
|  | 		return c | ||||||
|  | 	} | ||||||
|  | 	c.args = append(c.args, args...) | ||||||
|  | 	return c | ||||||
|  | } | ||||||
|  |  | ||||||
| // RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored. | // RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored. | ||||||
| type RunOpts struct { | type RunOpts struct { | ||||||
| 	Env               []string | 	Env               []string | ||||||
| @@ -138,8 +158,14 @@ func CommonCmdServEnvs() []string { | |||||||
| 	return commonBaseEnvs() | 	return commonBaseEnvs() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | var ErrBrokenCommand = errors.New("git command is broken") | ||||||
|  |  | ||||||
| // Run runs the command with the RunOpts | // Run runs the command with the RunOpts | ||||||
| func (c *Command) Run(opts *RunOpts) error { | func (c *Command) Run(opts *RunOpts) error { | ||||||
|  | 	if len(c.brokenArgs) != 0 { | ||||||
|  | 		log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " ")) | ||||||
|  | 		return ErrBrokenCommand | ||||||
|  | 	} | ||||||
| 	if opts == nil { | 	if opts == nil { | ||||||
| 		opts = &RunOpts{} | 		opts = &RunOpts{} | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -26,4 +26,19 @@ func TestRunWithContextStd(t *testing.T) { | |||||||
| 		assert.Contains(t, err.Error(), "exit status 129 - unknown option:") | 		assert.Contains(t, err.Error(), "exit status 129 - unknown option:") | ||||||
| 		assert.Empty(t, stdout) | 		assert.Empty(t, stdout) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	cmd = NewCommand(context.Background()) | ||||||
|  | 	cmd.AddDynamicArguments("-test") | ||||||
|  | 	assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand) | ||||||
|  |  | ||||||
|  | 	cmd = NewCommand(context.Background()) | ||||||
|  | 	cmd.AddDynamicArguments("--test") | ||||||
|  | 	assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand) | ||||||
|  |  | ||||||
|  | 	subCmd := "version" | ||||||
|  | 	cmd = NewCommand(context.Background()).AddDynamicArguments(subCmd) // for test purpose only, the sub-command should never be dynamic for production | ||||||
|  | 	stdout, stderr, err = cmd.RunStdString(&RunOpts{}) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Empty(t, stderr) | ||||||
|  | 	assert.Contains(t, stdout, "git version") | ||||||
| } | } | ||||||
|   | |||||||
| @@ -163,7 +163,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file | |||||||
| // CommitsCountFiles returns number of total commits of until given revision. | // CommitsCountFiles returns number of total commits of until given revision. | ||||||
| func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) { | func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) { | ||||||
| 	cmd := NewCommand(ctx, "rev-list", "--count") | 	cmd := NewCommand(ctx, "rev-list", "--count") | ||||||
| 	cmd.AddArguments(revision...) | 	cmd.AddDynamicArguments(revision...) | ||||||
| 	if len(relpath) > 0 { | 	if len(relpath) > 0 { | ||||||
| 		cmd.AddArguments("--") | 		cmd.AddArguments("--") | ||||||
| 		cmd.AddArguments(relpath...) | 		cmd.AddArguments(relpath...) | ||||||
|   | |||||||
| @@ -158,7 +158,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co | |||||||
| 				// add previous arguments except for --grep and --all | 				// add previous arguments except for --grep and --all | ||||||
| 				hashCmd.AddArguments(args...) | 				hashCmd.AddArguments(args...) | ||||||
| 				// add keyword as <commit> | 				// add keyword as <commit> | ||||||
| 				hashCmd.AddArguments(v) | 				hashCmd.AddDynamicArguments(v) | ||||||
|  |  | ||||||
| 				// search with given constraints for commit matching sha hash of v | 				// search with given constraints for commit matching sha hash of v | ||||||
| 				hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path}) | 				hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path}) | ||||||
| @@ -208,14 +208,15 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) ( | |||||||
| 	}() | 	}() | ||||||
| 	go func() { | 	go func() { | ||||||
| 		stderr := strings.Builder{} | 		stderr := strings.Builder{} | ||||||
| 		err := NewCommand(repo.Ctx, "log", revision, "--follow", | 		gitCmd := NewCommand(repo.Ctx, "log", prettyLogFormat, "--follow", | ||||||
| 			"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page), | 			"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page)) | ||||||
| 			prettyLogFormat, "--", file). | 		gitCmd.AddDynamicArguments(revision) | ||||||
| 			Run(&RunOpts{ | 		gitCmd.AddArguments("--", file) | ||||||
| 				Dir:    repo.Path, | 		err := gitCmd.Run(&RunOpts{ | ||||||
| 				Stdout: stdoutWriter, | 			Dir:    repo.Path, | ||||||
| 				Stderr: &stderr, | 			Stdout: stdoutWriter, | ||||||
| 			}) | 			Stderr: &stderr, | ||||||
|  | 		}) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String())) | 			_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String())) | ||||||
| 		} else { | 		} else { | ||||||
|   | |||||||
| @@ -59,15 +59,15 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string) | |||||||
| 		_ = stdoutWriter.Close() | 		_ = stdoutWriter.Close() | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	args := []string{"log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since)} | 	gitCmd := NewCommand(repo.Ctx, "log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since)) | ||||||
| 	if len(branch) == 0 { | 	if len(branch) == 0 { | ||||||
| 		args = append(args, "--branches=*") | 		gitCmd.AddArguments("--branches=*") | ||||||
| 	} else { | 	} else { | ||||||
| 		args = append(args, "--first-parent", branch) | 		gitCmd.AddArguments("--first-parent").AddDynamicArguments(branch) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	stderr := new(strings.Builder) | 	stderr := new(strings.Builder) | ||||||
| 	err = NewCommand(repo.Ctx, args...).Run(&RunOpts{ | 	err = gitCmd.Run(&RunOpts{ | ||||||
| 		Env:    []string{}, | 		Env:    []string{}, | ||||||
| 		Dir:    repo.Path, | 		Dir:    repo.Path, | ||||||
| 		Stdout: stdoutWriter, | 		Stdout: stdoutWriter, | ||||||
|   | |||||||
| @@ -24,19 +24,17 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo | |||||||
| 		page = 1 | 		page = 1 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	args := make([]string, 0, 12+len(branches)+len(files)) | 	graphCmd := git.NewCommand(r.Ctx, "log", "--graph", "--date-order", "--decorate=full") | ||||||
|  |  | ||||||
| 	args = append(args, "--graph", "--date-order", "--decorate=full") |  | ||||||
|  |  | ||||||
| 	if hidePRRefs { | 	if hidePRRefs { | ||||||
| 		args = append(args, "--exclude="+git.PullPrefix+"*") | 		graphCmd.AddArguments("--exclude=" + git.PullPrefix + "*") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(branches) == 0 { | 	if len(branches) == 0 { | ||||||
| 		args = append(args, "--all") | 		graphCmd.AddArguments("--all") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	args = append(args, | 	graphCmd.AddArguments( | ||||||
| 		"-C", | 		"-C", | ||||||
| 		"-M", | 		"-M", | ||||||
| 		fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page), | 		fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page), | ||||||
| @@ -44,15 +42,12 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo | |||||||
| 		fmt.Sprintf("--pretty=format:%s", format)) | 		fmt.Sprintf("--pretty=format:%s", format)) | ||||||
|  |  | ||||||
| 	if len(branches) > 0 { | 	if len(branches) > 0 { | ||||||
| 		args = append(args, branches...) | 		graphCmd.AddDynamicArguments(branches...) | ||||||
| 	} | 	} | ||||||
| 	args = append(args, "--") |  | ||||||
| 	if len(files) > 0 { | 	if len(files) > 0 { | ||||||
| 		args = append(args, files...) | 		graphCmd.AddArguments("--") | ||||||
|  | 		graphCmd.AddArguments(files...) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	graphCmd := git.NewCommand(r.Ctx, "log") |  | ||||||
| 	graphCmd.AddArguments(args...) |  | ||||||
| 	graph := NewGraph() | 	graph := NewGraph() | ||||||
|  |  | ||||||
| 	stderr := new(strings.Builder) | 	stderr := new(strings.Builder) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 6543
					6543