fix: add missing access checks and size limits (#39942) (#40085)

Backport https://github.com/go-gitea/gitea/pull/39942

Several handlers and parsers skipped checks that their siblings already
perform.

- Reject issue, comment, label, milestone and release mutations in
archived repositories via the API with one guard per route group,
matching the web UI
- Hide timeline references and dependencies pointing at issues the doer
cannot read, in the web UI and the API, including pull requests of the
same repository without pull request access
- Reject workflow runs with more than `MaxJobNumPerRun` jobs, including
inline reusable workflow jobs, and show rejected pushes as invalid
workflow runs
- Bound how much of a Helm chart archive is inflated while looking for
`Chart.yaml`

`release/v28` lacks two helpers this needs, so they are included:
`insertInvalidWorkflowRun`, split out of `handleInvalidWorkflows` by
https://github.com/go-gitea/gitea/pull/39480, and
`packages.NewLimitedReader` from
https://github.com/go-gitea/gitea/pull/39366.

Co-authored-by: bircni <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-10-30 08:08:32 +01:00
1 parent 8cf0f9798f
commit 0964106988
18 files changed
+298 -136

No files matched your search

@@ -6,6 +6,7 @@ package integration
import (
"fmt"
"net/http"
"slices"
"strconv"
"testing"
@@ -189,3 +190,32 @@ func TestWebDeleteIssueDependencyCrossRepoPermission(t *testing.T) {
session.MakeRequest(t, req, http.StatusOK)
unittest.AssertNotExistsBean(t, &issues_model.IssueDependency{IssueID: targetIssue.ID, DependencyID: dependencyIssue.ID})
}
func TestIssueTimelineDependencyCrossRepoPermission(t *testing.T) {
defer tests.PrepareTestEnv(t)()
targetIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: 1, Index: 1})
dependencyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
assert.True(t, dependencyRepo.IsPrivate)
dependencyIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: dependencyRepo.ID, Index: 1})
enableRepoDependencies(t, targetIssue.RepoID)
enableRepoDependencies(t, dependencyRepo.ID)
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
assert.NoError(t, issues_model.CreateIssueDependency(t.Context(), user1, targetIssue, dependencyIssue))
session := loginUser(t, "user40")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue)
assertDependencyVisible := func(visible bool) {
t.Helper()
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/issues/1/timeline").AddTokenAuth(token)
comments := DecodeJSON(t, MakeRequest(t, req, http.StatusOK), []*api.TimelineComment{})
assert.Equal(t, visible, slices.ContainsFunc(comments, func(c *api.TimelineComment) bool { return c.Type == "add_dependency" }))
resp := session.MakeRequest(t, NewRequest(t, "GET", "/user2/repo1/issues/1"), http.StatusOK)
assert.Equal(t, visible, NewHTMLParser(t, resp.Body).Find(`.timeline-item a[href$="/org3/repo3/issues/1"]`).Length() > 0)
}
assertDependencyVisible(false)
user40 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 40})
assert.NoError(t, repo_service.AddOrUpdateCollaborator(t.Context(), dependencyRepo, user40, perm.AccessModeRead))
assertDependencyVisible(true)
}