0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-24 23:26:34 +02:00

Fix all bugs I found in the code

This commit is contained in:
Excellencedev 2025-12-20 05:46:33 +01:00
parent a5163fa5f2
commit 9c5b278622
9 changed files with 127 additions and 106 deletions

View File

@ -272,7 +272,14 @@ func GetActionsUserRepoPermission(ctx context.Context, repo *repo_model.Reposito
return perm, err
}
actionsUnit := repo.MustGetUnit(ctx, unit.TypeActions)
actionsUnit, err := repo.GetUnit(ctx, unit.TypeActions)
if err != nil {
// If Actions unit doesn't exist, return empty permission
if repo_model.IsErrUnitTypeNotExist(err) {
return perm, nil
}
return perm, err
}
actionsCfg := actionsUnit.ActionsConfig()
if task.RepoID != repo.ID {

View File

@ -3779,11 +3779,17 @@
"general.token_permissions.restricted.description": "Workflows have read permissions in the repository for the contents and packages scopes only.",
"general.token_permissions.fork_pr_note": "Note: For workflows triggered by a pull request from a forked repository, the default GITHUB_TOKEN is always read-only.",
"general.token_permissions.contents": "Contents",
"general.token_permissions.contents.description": "Access source code, files, commits and branches.",
"general.token_permissions.issues": "Issues",
"general.token_permissions.issues.description": "Organize bug reports, tasks and milestones.",
"general.token_permissions.pull_requests": "Pull Requests",
"general.token_permissions.pull_requests.description": "Enable pull requests and code reviews.",
"general.token_permissions.packages": "Packages",
"general.token_permissions.packages.description": "Manage repository packages.",
"general.token_permissions.actions_scope": "Actions",
"general.token_permissions.actions_scope.description": "Manage actions.",
"general.token_permissions.wiki": "Wiki",
"general.token_permissions.wiki.description": "Write and share documentation with collaborators.",
"general.token_permissions.access_read": "Read",
"general.token_permissions.access_write": "Write",
"general.token_permissions.access_none": "No access",

View File

@ -81,51 +81,54 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
}
}
if ctx.Data["IsActionsToken"] == true {
if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() {
// Actions rules:
// 1. If the package key matches the task repo, allow.
// 2. If not, check cross-repo policy.
isActionsToken, _ := ctx.Data["IsActionsToken"].(bool)
if isActionsToken && ctx.Package != nil && ctx.Package.Owner != nil && ctx.Package.Owner.Visibility.IsPrivate() {
// Actions rules:
// 1. If the package key matches the task repo, allow.
// 2. If not, check cross-repo policy.
taskID, ok := ctx.Data["ActionsTaskID"].(int64)
if ok {
task, err := actions_model.GetTaskByID(ctx, taskID)
if err != nil {
log.Error("GetTaskByID: %v", err)
ctx.HTTPError(http.StatusInternalServerError, "GetTaskByID", err.Error())
taskID, ok := ctx.Data["ActionsTaskID"].(int64)
if ok && taskID > 0 {
task, err := actions_model.GetTaskByID(ctx, taskID)
if err != nil {
log.Error("GetTaskByID: %v", err)
ctx.HTTPError(http.StatusInternalServerError, "GetTaskByID", err.Error())
return
}
if task == nil {
ctx.HTTPError(http.StatusInternalServerError, "GetTaskByID", "task not found")
return
}
var packageRepoID int64
if ctx.Package.Descriptor != nil && ctx.Package.Descriptor.Package != nil {
packageRepoID = ctx.Package.Descriptor.Package.RepoID
}
if task.RepoID != packageRepoID {
// 1. Private packages MUST be linked to a repository
if packageRepoID == 0 {
ctx.HTTPError(http.StatusForbidden, "reqPackageAccess", "private package must be linked to a repository to be accessed by Actions")
return
}
var packageRepoID int64
if ctx.Package.Descriptor != nil && ctx.Package.Descriptor.Package != nil {
packageRepoID = ctx.Package.Descriptor.Package.RepoID
}
if task.RepoID != packageRepoID {
// 1. Private packages MUST be linked to a repository
if packageRepoID == 0 {
ctx.HTTPError(http.StatusForbidden, "reqPackageAccess", "private package must be linked to a repository to be accessed by Actions")
// 2. Check Org Cross-Repo Access Policy
if ctx.Package.Owner.IsOrganization() {
cfg, err := actions_model.GetOrgActionsConfig(ctx, ctx.Package.Owner.ID)
if err != nil {
log.Error("GetOrgActionsConfig: %v", err)
ctx.HTTPError(http.StatusInternalServerError, "GetOrgActionsConfig", err.Error())
return
}
// 2. Check Org Cross-Repo Access Policy
if ctx.Package.Owner.IsOrganization() {
cfg, err := actions_model.GetOrgActionsConfig(ctx, ctx.Package.Owner.ID)
if err != nil {
log.Error("GetOrgActionsConfig: %v", err)
ctx.HTTPError(http.StatusInternalServerError, "GetOrgActionsConfig", err.Error())
return
}
if !cfg.AllowCrossRepoAccess {
ctx.HTTPError(http.StatusForbidden, "reqPackageAccess", "cross-repository package access is disabled")
return
}
if !cfg.AllowCrossRepoAccess {
ctx.HTTPError(http.StatusForbidden, "reqPackageAccess", "cross-repository package access is disabled")
return
}
// 3. Fallthrough to GetActionsUserRepoPermission
// We rely on the backend permission check below to handle other Cross-Repository restrictions
// (e.g., User collaborative owners, token scopes).
}
// 3. Fallthrough to GetActionsUserRepoPermission
// We rely on the backend permission check below to handle other Cross-Repository restrictions
// (e.g., User collaborative owners, token scopes).
}
}
}

View File

@ -63,23 +63,26 @@ func ActionsGeneralPost(ctx *context.Context) {
}
if actionsCfg.TokenPermissionMode == repo_model.ActionsTokenPermissionModeCustom {
// Custom mode uses radio buttons for each permission scope
parsePerm := func(name string) perm.AccessMode {
if ctx.FormBool(name + "_write") {
value := ctx.FormString(name)
switch value {
case "write":
return perm.AccessModeWrite
}
if ctx.FormBool(name + "_read") {
case "read":
return perm.AccessModeRead
default:
return perm.AccessModeNone
}
return perm.AccessModeNone
}
actionsCfg.DefaultTokenPermissions = &repo_model.ActionsTokenPermissions{
Actions: parsePerm("actions"),
Contents: parsePerm("contents"),
Issues: parsePerm("issues"),
Packages: parsePerm("packages"),
PullRequests: parsePerm("pull_requests"),
Wiki: parsePerm("wiki"),
Actions: parsePerm("perm_actions"),
Contents: parsePerm("perm_contents"),
Issues: parsePerm("perm_issues"),
Packages: parsePerm("perm_packages"),
PullRequests: parsePerm("perm_pull_requests"),
Wiki: parsePerm("perm_wiki"),
}
} else {
actionsCfg.DefaultTokenPermissions = nil

View File

@ -156,23 +156,26 @@ func UpdateTokenPermissions(ctx *context.Context) {
}
if actionsCfg.TokenPermissionMode == repo_model.ActionsTokenPermissionModeCustom {
// Custom mode uses radio buttons for each permission scope
parsePerm := func(name string) perm.AccessMode {
if ctx.FormBool(name + "_write") {
value := ctx.FormString(name)
switch value {
case "write":
return perm.AccessModeWrite
}
if ctx.FormBool(name + "_read") {
case "read":
return perm.AccessModeRead
default:
return perm.AccessModeNone
}
return perm.AccessModeNone
}
actionsCfg.DefaultTokenPermissions = &repo_model.ActionsTokenPermissions{
Actions: parsePerm("actions"),
Contents: parsePerm("contents"),
Issues: parsePerm("issues"),
Packages: parsePerm("packages"),
PullRequests: parsePerm("pull_requests"),
Wiki: parsePerm("wiki"),
Actions: parsePerm("perm_actions"),
Contents: parsePerm("perm_contents"),
Issues: parsePerm("perm_issues"),
Packages: parsePerm("perm_packages"),
PullRequests: parsePerm("perm_pull_requests"),
Wiki: parsePerm("perm_wiki"),
}
} else {
actionsCfg.DefaultTokenPermissions = nil

View File

@ -18,10 +18,32 @@
<div class="divider"></div>
<!-- Default Permission Mode -->
<h5 class="ui header">
{{ctx.Locale.Tr "actions.general.token_permissions.mode"}}
</h5>
<div class="grouped fields">
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="token_permission_mode" value="permissive" {{if eq .TokenPermissionMode .TokenPermissionModePermissive}}checked{{end}}>
<label>{{ctx.Locale.Tr "actions.general.token_permissions.permissive"}}</label>
</div>
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.permissive.description"}}</p>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="token_permission_mode" value="restricted" {{if eq .TokenPermissionMode .TokenPermissionModeRestricted}}checked{{end}}>
<label>{{ctx.Locale.Tr "actions.general.token_permissions.restricted"}}</label>
</div>
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.restricted.description"}}</p>
</div>
</div>
<div class="divider"></div>
<!-- Maximum Permissions Table -->
<h5 class="ui header">
{{ctx.Locale.Tr "actions.general.token_permissions.maximum"}}
<span class="ui red text">*</span>
</h5>
<p class="help">{{ctx.Locale.Tr "actions.general.token_permissions.maximum.description"}}</p>
@ -29,17 +51,16 @@
<thead>
<tr>
<th style="width: 40%">{{ctx.Locale.Tr "units.unit"}}</th>
<th style="width: 20%; text-align: center">{{ctx.Locale.Tr "actions.general.token_permissions.access_none"}} <span class="ui basic circular label" data-tooltip="{{ctx.Locale.Tr "actions.general.token_permissions.access_none"}}">?</span></th>
<th style="width: 20%; text-align: center">{{ctx.Locale.Tr "actions.general.token_permissions.access_read"}} <span class="ui basic circular label" data-tooltip="{{ctx.Locale.Tr "actions.general.token_permissions.access_read"}}">?</span></th>
<th style="width: 20%; text-align: center">{{ctx.Locale.Tr "actions.general.token_permissions.access_write"}} <span class="ui basic circular label" data-tooltip="{{ctx.Locale.Tr "actions.general.token_permissions.access_write"}}">?</span></th>
<th style="width: 20%; text-align: center">{{ctx.Locale.Tr "actions.general.token_permissions.access_none"}}</th>
<th style="width: 20%; text-align: center">{{ctx.Locale.Tr "actions.general.token_permissions.access_read"}}</th>
<th style="width: 20%; text-align: center">{{ctx.Locale.Tr "actions.general.token_permissions.access_write"}}</th>
</tr>
</thead>
<tbody>
<!-- Code -->
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.contents"}}</strong>
<p class="text small grey">Access source code, files, commits and branches.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.contents.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -60,11 +81,10 @@
</div>
</td>
</tr>
<!-- Issues -->
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.issues"}}</strong>
<p class="text small grey">Organize bug reports, tasks and milestones.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.issues.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -85,11 +105,10 @@
</div>
</td>
</tr>
<!-- Pull Requests -->
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.pull_requests"}}</strong>
<p class="text small grey">Enable pull requests and code reviews.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.pull_requests.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -110,11 +129,10 @@
</div>
</td>
</tr>
<!-- Wiki -->
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.wiki"}}</strong>
<p class="text small grey">Write and share documentation with collaborators.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.wiki.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -135,11 +153,10 @@
</div>
</td>
</tr>
<!-- Packages -->
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.packages"}}</strong>
<p class="text small grey">Manage repository packages.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.packages.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -160,11 +177,10 @@
</div>
</td>
</tr>
<!-- Actions -->
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.actions_scope"}}</strong>
<p class="text small grey">Manage actions.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.actions_scope.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -197,4 +213,3 @@
</div>
</div>
{{template "org/settings/layout_footer" .}}

View File

@ -53,7 +53,7 @@
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.contents"}}</strong>
<p class="text small grey">Access source code, files, commits and branches.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.contents.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -78,7 +78,7 @@
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.issues"}}</strong>
<p class="text small grey">Organize bug reports, tasks and milestones.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.issues.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -103,7 +103,7 @@
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.pull_requests"}}</strong>
<p class="text small grey">Enable pull requests and code reviews.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.pull_requests.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -128,7 +128,7 @@
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.wiki"}}</strong>
<p class="text small grey">Write and share documentation with collaborators.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.wiki.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -153,7 +153,7 @@
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.packages"}}</strong>
<p class="text small grey">Manage repository packages.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.packages.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -178,7 +178,7 @@
<tr>
<td>
<strong>{{ctx.Locale.Tr "actions.general.token_permissions.actions_scope"}}</strong>
<p class="text small grey">Manage actions.</p>
<p class="text small grey">{{ctx.Locale.Tr "actions.general.token_permissions.actions_scope.description"}}</p>
</td>
<td style="text-align: center">
<div class="ui radio checkbox">
@ -199,7 +199,7 @@
</div>
</td>
</tr>
</tbody>
</tbody>
</table>
<div class="divider"></div>

View File

@ -128,15 +128,17 @@ func TestActionsTokenPermissionsModes(t *testing.T) {
func testActionsTokenPermissionsMode(u *url.URL, mode string, expectReadOnly bool) func(t *testing.T) {
return func(t *testing.T) {
// Update repository settings to the requested mode
// Update repository settings to the requested mode
if mode != "" {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo4", OwnerName: "user5"})
require.NoError(t, repo.LoadUnits(t.Context()))
actionsUnit := repo.MustGetUnit(t.Context(), unit_model.TypeActions)
actionsUnit, err := repo.GetUnit(t.Context(), unit_model.TypeActions)
require.NoError(t, err, "Actions unit should exist for repo4")
actionsCfg := actionsUnit.ActionsConfig()
actionsCfg.TokenPermissionMode = repo_model.ActionsTokenPermissionMode(mode)
actionsCfg.DefaultTokenPermissions = nil // Ensure no custom permissions override the mode
actionsCfg.MaxTokenPermissions = nil // Ensure no max permissions interfere
// Update the config
actionsUnit.Config = actionsCfg
require.NoError(t, repo_model.UpdateRepoUnit(t.Context(), actionsUnit))
}

View File

@ -1,24 +1,6 @@
// initRepoSettingsActionsPermissions is currently a no-op placeholder.
// The permission mode radio buttons work via standard HTML form submission
// without requiring JavaScript for toggling visibility.
export function initRepoSettingsActionsPermissions(): void {
const radios = document.querySelectorAll<HTMLInputElement>(
'input[name="token_permission_mode"]',
);
if (!radios.length) return;
function toggleCustom(): void {
const customPerms = document.querySelector<HTMLElement>('#custom-permissions');
if (!customPerms) return;
const selected = document.querySelector<HTMLInputElement>(
'input[name="token_permission_mode"]:checked',
);
customPerms.style.display =
selected?.value === 'custom' ? 'block' : 'none';
}
for (const radio of radios) {
radio.addEventListener('change', toggleCustom);
}
toggleCustom();
// No-op - form submission handles permission updates
}