Hide the "Details" link of commit status when the user cannot access actions (#30156)

Fix #26685

If a commit status comes from Gitea Actions and the user cannot access
the repo's actions unit (the user does not have the permission or the
actions unit is disabled), a 404 page will occur after clicking the
"Details" link. We should hide the "Details" link in this case.

<img
src="https://github.com/go-gitea/gitea/assets/15528715/68361714-b784-4bb5-baab-efde4221f466"
width="400px" />
This commit is contained in:
Zettat123 2024-07-28 23:11:40 +08:00 committed by GitHub
parent aa36989bd0
commit 7dec8de914
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 131 additions and 6 deletions

View File

@ -171,13 +171,17 @@ func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (in
return newIdx, nil return newIdx, nil
} }
func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) { func (status *CommitStatus) loadRepository(ctx context.Context) (err error) {
if status.Repo == nil { if status.Repo == nil {
status.Repo, err = repo_model.GetRepositoryByID(ctx, status.RepoID) status.Repo, err = repo_model.GetRepositoryByID(ctx, status.RepoID)
if err != nil { if err != nil {
return fmt.Errorf("getRepositoryByID [%d]: %w", status.RepoID, err) return fmt.Errorf("getRepositoryByID [%d]: %w", status.RepoID, err)
} }
} }
return nil
}
func (status *CommitStatus) loadCreator(ctx context.Context) (err error) {
if status.Creator == nil && status.CreatorID > 0 { if status.Creator == nil && status.CreatorID > 0 {
status.Creator, err = user_model.GetUserByID(ctx, status.CreatorID) status.Creator, err = user_model.GetUserByID(ctx, status.CreatorID)
if err != nil { if err != nil {
@ -187,6 +191,13 @@ func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) {
return nil return nil
} }
func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) {
if err := status.loadRepository(ctx); err != nil {
return err
}
return status.loadCreator(ctx)
}
// APIURL returns the absolute APIURL to this commit-status. // APIURL returns the absolute APIURL to this commit-status.
func (status *CommitStatus) APIURL(ctx context.Context) string { func (status *CommitStatus) APIURL(ctx context.Context) string {
_ = status.loadAttributes(ctx) _ = status.loadAttributes(ctx)
@ -198,6 +209,21 @@ func (status *CommitStatus) LocaleString(lang translation.Locale) string {
return lang.TrString("repo.commitstatus." + status.State.String()) return lang.TrString("repo.commitstatus." + status.State.String())
} }
// HideActionsURL set `TargetURL` to an empty string if the status comes from Gitea Actions
func (status *CommitStatus) HideActionsURL(ctx context.Context) {
if status.Repo == nil {
if err := status.loadRepository(ctx); err != nil {
log.Error("loadRepository: %v", err)
return
}
}
prefix := fmt.Sprintf("%s/actions", status.Repo.Link())
if strings.HasPrefix(status.TargetURL, prefix) {
status.TargetURL = ""
}
}
// CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc // CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc
func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus { func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus {
var lastStatus *CommitStatus var lastStatus *CommitStatus
@ -506,3 +532,15 @@ func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo
repo, repo,
) )
} }
// CommitStatusesHideActionsURL hide Gitea Actions urls
func CommitStatusesHideActionsURL(ctx context.Context, statuses []*CommitStatus) {
idToRepos := make(map[int64]*repo_model.Repository)
for _, status := range statuses {
if status.Repo == nil {
status.Repo = idToRepos[status.RepoID]
}
status.HideActionsURL(ctx)
idToRepos[status.RepoID] = status.Repo
}
}

View File

@ -4,9 +4,11 @@
package git_test package git_test
import ( import (
"fmt"
"testing" "testing"
"time" "time"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git" git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -231,3 +233,26 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) {
assert.Equal(t, "compliance/lint-backend", contexts[0]) assert.Equal(t, "compliance/lint-backend", contexts[0])
} }
} }
func TestCommitStatusesHideActionsURL(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 791, RepoID: repo.ID})
assert.NoError(t, run.LoadAttributes(db.DefaultContext))
statuses := []*git_model.CommitStatus{
{
RepoID: repo.ID,
TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), run.Index),
},
{
RepoID: repo.ID,
TargetURL: "https://mycicd.org/1",
},
}
git_model.CommitStatusesHideActionsURL(db.DefaultContext, statuses)
assert.Empty(t, statuses[0].TargetURL)
assert.Equal(t, "https://mycicd.org/1", statuses[1].TargetURL)
}

View File

@ -70,6 +70,11 @@ func Branches(ctx *context.Context) {
ctx.ServerError("LoadBranches", err) ctx.ServerError("LoadBranches", err)
return return
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
for key := range commitStatuses {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
}
}
commitStatus := make(map[string]*git_model.CommitStatus) commitStatus := make(map[string]*git_model.CommitStatus)
for commitID, cs := range commitStatuses { for commitID, cs := range commitStatuses {

View File

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git" git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/charset"
@ -81,7 +82,7 @@ func Commits(ctx *context.Context) {
ctx.ServerError("CommitsByRange", err) ctx.ServerError("CommitsByRange", err)
return return
} }
ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commits, ctx.Repo.Repository) ctx.Data["Commits"] = processGitCommits(ctx, commits)
ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name
@ -199,7 +200,7 @@ func SearchCommits(ctx *context.Context) {
return return
} }
ctx.Data["CommitCount"] = len(commits) ctx.Data["CommitCount"] = len(commits)
ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commits, ctx.Repo.Repository) ctx.Data["Commits"] = processGitCommits(ctx, commits)
ctx.Data["Keyword"] = query ctx.Data["Keyword"] = query
if all { if all {
@ -242,7 +243,7 @@ func FileHistory(ctx *context.Context) {
ctx.ServerError("CommitsByFileAndRange", err) ctx.ServerError("CommitsByFileAndRange", err)
return return
} }
ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commits, ctx.Repo.Repository) ctx.Data["Commits"] = processGitCommits(ctx, commits)
ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name
@ -353,6 +354,9 @@ func Diff(ctx *context.Context) {
if err != nil { if err != nil {
log.Error("GetLatestCommitStatus: %v", err) log.Error("GetLatestCommitStatus: %v", err)
} }
if !ctx.Repo.CanRead(unit_model.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, statuses)
}
ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses) ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["CommitStatuses"] = statuses ctx.Data["CommitStatuses"] = statuses
@ -433,3 +437,14 @@ func RawDiff(ctx *context.Context) {
return return
} }
} }
func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) []*git_model.SignCommitWithStatuses {
commits := git_model.ConvertFromGitCommit(ctx, gitCommits, ctx.Repo.Repository)
if !ctx.Repo.CanRead(unit_model.TypeActions) {
for _, commit := range commits {
commit.Status.HideActionsURL(ctx)
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
}
}
return commits
}

View File

@ -643,7 +643,7 @@ func PrepareCompareDiff(
return false return false
} }
commits := git_model.ConvertFromGitCommit(ctx, ci.CompareInfo.Commits, ci.HeadRepo) commits := processGitCommits(ctx, ci.CompareInfo.Commits)
ctx.Data["Commits"] = commits ctx.Data["Commits"] = commits
ctx.Data["CommitCount"] = len(commits) ctx.Data["CommitCount"] = len(commits)

View File

@ -339,6 +339,11 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
ctx.ServerError("GetIssuesAllCommitStatus", err) ctx.ServerError("GetIssuesAllCommitStatus", err)
return return
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
for key := range commitStatuses {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
}
}
if err := issues.LoadAttributes(ctx); err != nil { if err := issues.LoadAttributes(ctx); err != nil {
ctx.ServerError("issues.LoadAttributes", err) ctx.ServerError("issues.LoadAttributes", err)
@ -1757,6 +1762,12 @@ func ViewIssue(ctx *context.Context) {
ctx.ServerError("LoadPushCommits", err) ctx.ServerError("LoadPushCommits", err)
return return
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
for _, commit := range comment.Commits {
commit.Status.HideActionsURL(ctx)
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
}
}
} else if comment.Type == issues_model.CommentTypeAddTimeManual || } else if comment.Type == issues_model.CommentTypeAddTimeManual ||
comment.Type == issues_model.CommentTypeStopTracking || comment.Type == issues_model.CommentTypeStopTracking ||
comment.Type == issues_model.CommentTypeDeleteTimeManual { comment.Type == issues_model.CommentTypeDeleteTimeManual {

View File

@ -283,6 +283,10 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
ctx.ServerError("GetLatestCommitStatus", err) ctx.ServerError("GetLatestCommitStatus", err)
return nil return nil
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses)
}
if len(commitStatuses) != 0 { if len(commitStatuses) != 0 {
ctx.Data["LatestCommitStatuses"] = commitStatuses ctx.Data["LatestCommitStatuses"] = commitStatuses
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses)
@ -345,6 +349,10 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.ServerError("GetLatestCommitStatus", err) ctx.ServerError("GetLatestCommitStatus", err)
return nil return nil
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses)
}
if len(commitStatuses) > 0 { if len(commitStatuses) > 0 {
ctx.Data["LatestCommitStatuses"] = commitStatuses ctx.Data["LatestCommitStatuses"] = commitStatuses
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses)
@ -437,6 +445,10 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.ServerError("GetLatestCommitStatus", err) ctx.ServerError("GetLatestCommitStatus", err)
return nil return nil
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses)
}
if len(commitStatuses) > 0 { if len(commitStatuses) > 0 {
ctx.Data["LatestCommitStatuses"] = commitStatuses ctx.Data["LatestCommitStatuses"] = commitStatuses
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses) ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(commitStatuses)
@ -603,7 +615,7 @@ func ViewPullCommits(ctx *context.Context) {
ctx.Data["Username"] = ctx.Repo.Owner.Name ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name ctx.Data["Reponame"] = ctx.Repo.Repository.Name
commits := git_model.ConvertFromGitCommit(ctx, prInfo.Commits, ctx.Repo.Repository) commits := processGitCommits(ctx, prInfo.Commits)
ctx.Data["Commits"] = commits ctx.Data["Commits"] = commits
ctx.Data["CommitCount"] = len(commits) ctx.Data["CommitCount"] = len(commits)

View File

@ -656,6 +656,9 @@ func SearchRepo(ctx *context.Context) {
ctx.JSON(http.StatusInternalServerError, nil) ctx.JSON(http.StatusInternalServerError, nil)
return return
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, latestCommitStatuses)
}
results := make([]*repo_service.WebSearchRepository, len(repos)) results := make([]*repo_service.WebSearchRepository, len(repos))
for i, repo := range repos { for i, repo := range repos {

View File

@ -363,6 +363,9 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool {
if err != nil { if err != nil {
log.Error("GetLatestCommitStatus: %v", err) log.Error("GetLatestCommitStatus: %v", err)
} }
if !ctx.Repo.CanRead(unit_model.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, statuses)
}
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses) ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["LatestCommitStatuses"] = statuses ctx.Data["LatestCommitStatuses"] = statuses

View File

@ -17,6 +17,7 @@ import (
activities_model "code.gitea.io/gitea/models/activities" activities_model "code.gitea.io/gitea/models/activities"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -568,6 +569,11 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
ctx.ServerError("GetIssuesLastCommitStatus", err) ctx.ServerError("GetIssuesLastCommitStatus", err)
return return
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
for key := range commitStatuses {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
}
}
// ------------------------------- // -------------------------------
// Fill stats to post to ctx.Data. // Fill stats to post to ctx.Data.

View File

@ -13,8 +13,10 @@ import (
activities_model "code.gitea.io/gitea/models/activities" activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues" issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/optional"
@ -303,6 +305,11 @@ func NotificationSubscriptions(ctx *context.Context) {
ctx.ServerError("GetIssuesAllCommitStatus", err) ctx.ServerError("GetIssuesAllCommitStatus", err)
return return
} }
if !ctx.Repo.CanRead(unit.TypeActions) {
for key := range commitStatuses {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
}
}
ctx.Data["CommitLastStatus"] = lastStatus ctx.Data["CommitLastStatus"] = lastStatus
ctx.Data["CommitStatuses"] = commitStatuses ctx.Data["CommitStatuses"] = commitStatuses
ctx.Data["Issues"] = issues ctx.Data["Issues"] = issues