diff --git a/changelogs/unreleased/fj-add-sha-validations-to-raw-operations.yml b/changelogs/unreleased/fj-add-sha-validations-to-raw-operations.yml new file mode 100644 index 0000000000000000000000000000000000000000..41e935dc21dacaadc28693450ee1fa1352246b13 --- /dev/null +++ b/changelogs/unreleased/fj-add-sha-validations-to-raw-operations.yml @@ -0,0 +1,5 @@ +--- +title: Added sha format validations for Raw diff operations +merge_request: +author: +type: security diff --git a/internal/helper/security.go b/internal/helper/security.go index afbcced9d5099e726d1e87e9fcdb7961581755a2..54bc4ce4b67f8d9a6db2ff24ff49a3adb9a5ac60 100644 --- a/internal/helper/security.go +++ b/internal/helper/security.go @@ -1,6 +1,7 @@ package helper import ( + "fmt" "os" "regexp" "strings" @@ -24,3 +25,12 @@ var hostPattern = regexp.MustCompile(`(?i)([a-z][a-z0-9+\-.]*://)([a-z0-9\-._~%! func SanitizeString(str string) string { return hostPattern.ReplaceAllString(str, "$1[FILTERED]@$3$4") } + +// ValidSha checks if SHA is valid +func ValidSha(sha string) error { + if match, err := regexp.MatchString(`[0-9a-f]{40}`, sha); !match || err != nil { + return fmt.Errorf("invalid Sha") + } + + return nil +} diff --git a/internal/helper/security_test.go b/internal/helper/security_test.go index 9a8125dac612e1d673921665ab7937b881945627..fa6f594092955b05b73206c5b9c740d0822566c7 100644 --- a/internal/helper/security_test.go +++ b/internal/helper/security_test.go @@ -40,3 +40,24 @@ func TestSanitizeString(t *testing.T) { assert.Equal(t, tc.output, SanitizeString(tc.input)) } } + +func TestValidSha(t *testing.T) { + testCases := []struct { + sha string + error bool + }{ + {"", true}, + {"invalid-sha", true}, + {"878d0d962673697c1d038d47e8070f8e7a807028", false}, + {"878d0d962673697c1d038d47e8070f8e7a80702", true}, + {"878d0d962673697c1d038d47e8070f8e7a807028~", false}, + } + + for _, tc := range testCases { + if tc.error { + assert.Error(t, ValidSha(tc.sha), "Invalid Sha") + } else { + assert.NoError(t, ValidSha(tc.sha)) + } + } +} diff --git a/internal/service/diff/commit.go b/internal/service/diff/commit.go index be42f6c5be2269d90a9b3fb2e4619f23f7c92a0a..db185475b6f4779114561733a9cfcc967704b9cb 100644 --- a/internal/service/diff/commit.go +++ b/internal/service/diff/commit.go @@ -9,6 +9,7 @@ import ( "gitlab.com/gitlab-org/gitaly-proto/go/gitalypb" "gitlab.com/gitlab-org/gitaly/internal/diff" "gitlab.com/gitlab-org/gitaly/internal/git" + "gitlab.com/gitlab-org/gitaly/internal/helper" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -196,10 +197,19 @@ func validateRequest(in requestWithLeftRightCommitIds) error { if in.GetLeftCommitId() == "" { return fmt.Errorf("empty LeftCommitId") } + + if err := helper.ValidSha(in.GetLeftCommitId()); err != nil { + return fmt.Errorf("invalid LeftCommitId SHA") + } + if in.GetRightCommitId() == "" { return fmt.Errorf("empty RightCommitId") } + if err := helper.ValidSha(in.GetRightCommitId()); err != nil { + return fmt.Errorf("invalid RightCommitId SHA") + } + return nil } diff --git a/internal/service/diff/numstat_test.go b/internal/service/diff/numstat_test.go index ddebbf7c153a69203da78cd39659d0b098b1050a..fe39f2de0292291fca249c05f7c834e347804a3c 100644 --- a/internal/service/diff/numstat_test.go +++ b/internal/service/diff/numstat_test.go @@ -180,19 +180,19 @@ func TestFailedDiffStatsRequest(t *testing.T) { repo: testRepo, leftCommitID: "invalidinvalidinvalid", rightCommitID: "8a0f2ee90d940bfb0ba1e14e8214b0649056e4ab", - err: codes.Unavailable, + err: codes.InvalidArgument, }, { desc: "invalid right commit", repo: testRepo, leftCommitID: "e4003da16c1c2c3fc4567700121b17bf8e591c6c", rightCommitID: "invalidinvalidinvalid", - err: codes.Unavailable, + err: codes.InvalidArgument, }, { desc: "left commit not found", repo: testRepo, - leftCommitID: "z4003da16c1c2c3fc4567700121b17bf8e591c6c", + leftCommitID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", rightCommitID: "8a0f2ee90d940bfb0ba1e14e8214b0649056e4ab", err: codes.Unavailable, }, @@ -200,7 +200,7 @@ func TestFailedDiffStatsRequest(t *testing.T) { desc: "right commit not found", repo: testRepo, leftCommitID: "e4003da16c1c2c3fc4567700121b17bf8e591c6c", - rightCommitID: "z4003da16c1c2c3fc4567700121b17bf8e591c6c", + rightCommitID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", err: codes.Unavailable, }, } diff --git a/internal/service/diff/raw_test.go b/internal/service/diff/raw_test.go index e775d48dd59e8e0789789aedfff61fc9c5705cb8..67d2b92034e4455f9563613c486fca16ac33234b 100644 --- a/internal/service/diff/raw_test.go +++ b/internal/service/diff/raw_test.go @@ -97,6 +97,24 @@ func TestFailedRawDiffRequestDueToValidations(t *testing.T) { }, code: codes.InvalidArgument, }, + { + desc: "invalid right commit", + request: &gitalypb.RawDiffRequest{ + Repository: testRepo, + RightCommitId: "invalid-sha", + LeftCommitId: "e395f646b1499e8e0279445fc99a0596a65fab7e", + }, + code: codes.InvalidArgument, + }, + { + desc: "invalid left commit", + request: &gitalypb.RawDiffRequest{ + Repository: testRepo, + RightCommitId: "8a0f2ee90d940bfb0ba1e14e8214b0649056e4ab", + LeftCommitId: "invalid-sha", + }, + code: codes.InvalidArgument, + }, } for _, testCase := range testCases { @@ -189,6 +207,24 @@ func TestFailedRawPatchRequestDueToValidations(t *testing.T) { }, code: codes.InvalidArgument, }, + { + desc: "invalid right commit", + request: &gitalypb.RawPatchRequest{ + Repository: testRepo, + RightCommitId: "invalid-sha", + LeftCommitId: "e395f646b1499e8e0279445fc99a0596a65fab7e", + }, + code: codes.InvalidArgument, + }, + { + desc: "invalid left commit", + request: &gitalypb.RawPatchRequest{ + Repository: testRepo, + RightCommitId: "8a0f2ee90d940bfb0ba1e14e8214b0649056e4ab", + LeftCommitId: "invalid-sha", + }, + code: codes.InvalidArgument, + }, } for _, testCase := range testCases {