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:
parent
a5163fa5f2
commit
9c5b278622
@ -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 {
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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" .}}
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user