fix: resolve actions commit status permission per repository (#38977)

Various pages did not display the correct action run list tooltips. Fix
those tooltips like here on the `/pulls` page:

`ctx.Repo.Permission` is the zero value outside a repository route, so
on `/pulls`, `/issues`, `/notifications/subscriptions` and the dashboard
repo list the commit status "Details" link was always stripped. The live
job status is looked up from that target URL, so running checks also
rendered as a static pending dot instead of a spinner.

Resolve the Actions unit permission per repository instead.

Also drops the releases page's gate on *loading* statuses, which hid
external CI results from anyone without Actions read; it now loads them
and hides only the URL, like every other page.

Co-authored-by: bircni <bircni@icloud.com>
This commit is contained in:
silverwind
2026-08-19 20:09:00 +02:00
committed by GitHub
parent e355c39e91
commit 4e813a262f
19 changed files with 98 additions and 97 deletions
+1 -5
View File
@@ -70,14 +70,10 @@ func Branches(ctx *context.Context) {
ctx.ServerError("LoadBranches", err)
return
}
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
for key := range commitStatuses {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
}
}
commitStatus := make(map[string]*git_model.CommitStatus)
for commitID, cs := range commitStatuses {
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, cs)
commitStatus[commitID] = git_model.CalcCommitStatus(cs)
}
+2 -13
View File
@@ -17,7 +17,6 @@ import (
issues_model "gitea.dev/models/issues"
"gitea.dev/models/renderhelper"
repo_model "gitea.dev/models/repo"
unit_model "gitea.dev/models/unit"
user_model "gitea.dev/models/user"
"gitea.dev/modules/base"
"gitea.dev/modules/fileicon"
@@ -388,9 +387,7 @@ func Diff(ctx *context.Context) {
if err != nil {
log.Error("GetLatestCommitStatus: %v", err)
}
if !ctx.Repo.Permission.CanRead(unit_model.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, statuses)
}
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, statuses)
ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["CommitStatuses"] = statuses
@@ -466,14 +463,6 @@ func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) ([]*git_m
if err != nil {
return nil, err
}
if !ctx.Repo.Permission.CanRead(unit_model.TypeActions) {
for _, commit := range commits {
if commit.Status == nil {
continue
}
commit.Status.HideActionsURL(ctx)
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
}
}
git_model.SignCommitsApplyDoerPermission(ctx, ctx.Doer, commits)
return commits, nil
}
+1 -8
View File
@@ -13,11 +13,9 @@ import (
"strings"
"gitea.dev/models/db"
git_model "gitea.dev/models/git"
issues_model "gitea.dev/models/issues"
"gitea.dev/models/organization"
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unit"
user_model "gitea.dev/models/user"
issue_indexer "gitea.dev/modules/indexer/issues"
db_indexer "gitea.dev/modules/indexer/issues/db"
@@ -640,16 +638,11 @@ func prepareIssueFilterAndList(ctx *context.Context, milestoneID int64, projectI
}
}
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, ctx.Doer, issues)
if err != nil {
ctx.ServerError("GetIssuesAllCommitStatus", err)
return
}
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
for key := range commitStatuses {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
}
}
if err := issues.LoadAttributes(ctx); err != nil {
ctx.ServerError("issues.LoadAttributes", err)
+1 -9
View File
@@ -794,15 +794,7 @@ func prepareIssueViewCommentsAndSidebarParticipants(ctx *context.Context, issue
ctx.ServerError("LoadCommentPushCommits", err)
return
}
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
for _, commit := range comment.Commits {
if commit.Status == nil {
continue
}
commit.Status.HideActionsURL(ctx)
git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
}
}
git_model.SignCommitsApplyDoerPermission(ctx, ctx.Doer, comment.Commits)
} else if comment.Type == issues_model.CommentTypeAddTimeManual ||
comment.Type == issues_model.CommentTypeStopTracking ||
comment.Type == issues_model.CommentTypeDeleteTimeManual {
+1 -3
View File
@@ -432,9 +432,7 @@ func (prInfo *pullRequestViewInfo) prepareMergeBoxStatusCheckData(ctx *context.C
}
data.hasRequiredStatusContexts = len(requiredContexts) > 0
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses)
}
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, commitStatuses)
combinedCommitStatus := git_model.CalcCommitStatus(commitStatuses)
statusCheckData.ApproveLink = fmt.Sprintf("%s/actions/approve-all-checks?commit_id=%s", ctx.Repo.Repository.Link(), headCommitID)
statusCheckData.PullCommitStatuses = commitStatuses
+5 -3
View File
@@ -97,11 +97,12 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions)
}
var ok bool
canReadActions := ctx.Repo.Permission.CanRead(unit.TypeActions)
// statuses describe the tagged code, and unlike the other pages showing them this one is not behind the code unit
canReadCode := ctx.Repo.Permission.CanRead(unit.TypeCode)
// Bulk-load commit statuses for all releases in one query.
var commitStatusMap map[string][]*git_model.CommitStatus
if canReadActions && len(releases) > 0 {
if canReadCode && len(releases) > 0 {
shas := make([]string, 0, len(releases))
for _, r := range releases {
shas = append(shas, r.Sha1)
@@ -140,8 +141,9 @@ func getReleaseInfos(ctx *context.Context, opts *repo_model.FindReleasesOptions)
Release: r,
}
if canReadActions {
if canReadCode {
statuses := commitStatusMap[r.Sha1]
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, statuses)
info.CommitStatus = git_model.CalcCommitStatus(statuses)
info.CommitStatuses = statuses
}
+1 -3
View File
@@ -526,9 +526,7 @@ func SearchRepo(ctx *context.Context) {
ctx.JSON(http.StatusInternalServerError, nil)
return
}
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, latestCommitStatuses)
}
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, latestCommitStatuses)
results := make([]*repo_service.WebSearchRepository, len(repos))
for i, repo := range repos {
+1 -3
View File
@@ -143,9 +143,7 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool {
if err != nil {
log.Error("GetLatestCommitStatus: %v", err)
}
if !ctx.Repo.Permission.CanRead(unit_model.TypeActions) {
git_model.CommitStatusesHideActionsURL(ctx, statuses)
}
git_model.CommitStatusesApplyDoerPermission(ctx, ctx.Doer, statuses)
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["LatestCommitStatuses"] = statuses
+1 -7
View File
@@ -17,7 +17,6 @@ import (
activities_model "gitea.dev/models/activities"
asymkey_model "gitea.dev/models/asymkey"
"gitea.dev/models/db"
git_model "gitea.dev/models/git"
issues_model "gitea.dev/models/issues"
"gitea.dev/models/organization"
"gitea.dev/models/renderhelper"
@@ -554,16 +553,11 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
}
}
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, ctx.Doer, issues)
if err != nil {
ctx.ServerError("GetIssuesLastCommitStatus", err)
return
}
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
for key := range commitStatuses {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
}
}
// -------------------------------
// Fill stats to post to ctx.Data.
+1 -8
View File
@@ -11,11 +11,9 @@ import (
activities_model "gitea.dev/models/activities"
"gitea.dev/models/db"
git_model "gitea.dev/models/git"
issues_model "gitea.dev/models/issues"
access_model "gitea.dev/models/perm/access"
repo_model "gitea.dev/models/repo"
"gitea.dev/models/unit"
user_model "gitea.dev/models/user"
"gitea.dev/modules/base"
"gitea.dev/modules/container"
@@ -268,16 +266,11 @@ func NotificationSubscriptions(ctx *context.Context) {
return
}
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, ctx.Doer, issues)
if err != nil {
ctx.ServerError("GetIssuesAllCommitStatus", err)
return
}
if !ctx.Repo.Permission.CanRead(unit.TypeActions) {
for key := range commitStatuses {
git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
}
}
ctx.Data["CommitLastStatus"] = lastStatus
ctx.Data["CommitStatuses"] = commitStatuses
ctx.Data["Issues"] = issues