From cc61032697e324cc92d8b015c75bb18f888eaa92 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Fri, 8 May 2026 09:14:41 -0700 Subject: [PATCH] fix(git): Fix smart http request scope bug (#37583) (#37605) Backport #37583 by @lunny Co-authored-by: Lunny Xiao Co-authored-by: Nicolas Co-authored-by: Claude Opus 4.7 Co-authored-by: silverwind --- tests/integration/git_smart_http_test.go | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/integration/git_smart_http_test.go b/tests/integration/git_smart_http_test.go index 33e90c7dfa..b07e047091 100644 --- a/tests/integration/git_smart_http_test.go +++ b/tests/integration/git_smart_http_test.go @@ -9,6 +9,9 @@ import ( "net/url" "testing" + auth_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth" + repo_model "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo" + "git.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unittest" "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting" "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/test" "git.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/util" @@ -20,6 +23,7 @@ import ( func TestGitSmartHTTP(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { testGitSmartHTTP(t, u) + testGitSmartHTTPTokenScopes(t) testRenamedRepoRedirect(t) testGitArchiveRemote(t, u) }) @@ -80,6 +84,42 @@ func testGitSmartHTTP(t *testing.T, u *url.URL) { } } +func testGitSmartHTTPTokenScopes(t *testing.T) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerName: "user2", Name: "repo2"}) + require.True(t, repo.IsPrivate) + + session := loginUser(t, "user2") + badToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadNotification) + readToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository) + writeToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopePublicOnly, auth_model.AccessTokenScopeReadRepository) + + t.Run("upload-pack requires read repository scope", func(t *testing.T) { + path := "/user2/repo2/info/refs?service=git-upload-pack" + + MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth(badToken, "x-oauth-basic"), http.StatusForbidden) + MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(badToken), http.StatusForbidden) + + resp := MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(readToken), http.StatusOK) + assert.Contains(t, resp.Body.String(), "refs/heads/master") + }) + + t.Run("receive-pack requires write repository scope", func(t *testing.T) { + path := "/user2/repo2/info/refs?service=git-receive-pack" + + MakeRequest(t, NewRequest(t, "GET", path).AddBasicAuth(readToken, "x-oauth-basic"), http.StatusForbidden) + MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(readToken), http.StatusForbidden) + + resp := MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(writeToken), http.StatusOK) + assert.Contains(t, resp.Body.String(), "refs/heads/master") + }) + + t.Run("public-only scope rejects private repo", func(t *testing.T) { + path := "/user2/repo2/info/refs?service=git-upload-pack" + MakeRequest(t, NewRequest(t, "GET", path).AddTokenAuth(publicOnlyToken), http.StatusForbidden) + }) +} + func testRenamedRepoRedirect(t *testing.T) { defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()