From aa4ae846aaad9550bc11cc31ca17440bfe16549d Mon Sep 17 00:00:00 2001 From: appleboy Date: Sat, 16 Nov 2024 16:14:30 +0800 Subject: [PATCH] feat(remote): improve input validation and security in remote operations - Change file permissions from `0o700` to `0o600` in `WriteKey` function - Import `regexp` package in `remote.go` - Add `sanitizeInput` and `isValidInput` functions for input validation - Use sanitized inputs in `RemotePushNamedBranch` function - Add unit tests for `sanitizeInput` function in new `remote_test.go` file Signed-off-by: appleboy --- repo/key.go | 2 +- repo/remote.go | 23 ++++++++++++++++++++-- repo/remote_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 repo/remote_test.go diff --git a/repo/key.go b/repo/key.go index d05aa72..eae409d 100644 --- a/repo/key.go +++ b/repo/key.go @@ -45,7 +45,7 @@ func WriteKey(privateKey string) error { _ = os.WriteFile( confpath, []byte("StrictHostKeyChecking no\n"), - 0o700) + 0o600) return os.WriteFile( privpath, diff --git a/repo/remote.go b/repo/remote.go index daa3b80..a7072a6 100644 --- a/repo/remote.go +++ b/repo/remote.go @@ -2,6 +2,7 @@ package repo import ( "os/exec" + "regexp" ) // RemoteRemove drops the defined remote from a git repo. @@ -43,13 +44,31 @@ func RemotePullRebaseNamedBranch(remote, branch string) *exec.Cmd { return cmd } +var validBranchName = regexp.MustCompile(`^[\w\.\-\/]+$`) + +func sanitizeInput(input string) string { + if isValidInput(input) { + return input + } + return "" +} + +func isValidInput(input string) bool { + return validBranchName.MatchString(input) +} + // RemotePushNamedBranch puchs changes from a local to a remote branch. func RemotePushNamedBranch(remote, localbranch string, branch string, force bool, followtags bool) *exec.Cmd { + sanitizedRemote := sanitizeInput(remote) + sanitizedLocalBranch := sanitizeInput(localbranch) + sanitizedBranch := sanitizeInput(branch) + cmd := exec.Command( "git", "push", - remote, - localbranch+":"+branch) + sanitizedRemote, + sanitizedLocalBranch+":"+sanitizedBranch, + ) if force { cmd.Args = append( diff --git a/repo/remote_test.go b/repo/remote_test.go new file mode 100644 index 0000000..395de8f --- /dev/null +++ b/repo/remote_test.go @@ -0,0 +1,47 @@ +package repo + +import ( + "testing" +) + +func TestSanitizeInput(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "valid input with alphanumeric characters", + input: "feature-branch", + want: "feature-branch", + }, + { + name: "valid input with dots and slashes", + input: "release/1.0.0", + want: "release/1.0.0", + }, + { + name: "invalid input with spaces", + input: "invalid branch", + want: "", + }, + { + name: "invalid input with special characters", + input: "invalid@branch!", + want: "", + }, + { + name: "empty input", + input: "", + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := sanitizeInput(tt.input); got != tt.want { + t.Errorf("sanitizeInput() = %v, want %v", got, tt.want) + } + }) + } +}