mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-08-19 08:51:10 +00:00
Compare commits
2 commits
99f93beada
...
f6bc8f7cd7
Author | SHA1 | Date | |
---|---|---|---|
|
f6bc8f7cd7 | ||
|
cb4ffd29cf |
5 changed files with 151 additions and 21 deletions
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2024 The Forgejo Authors
|
||||
# Copyright 2025 The Forgejo Authors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: requirements
|
||||
|
@ -13,7 +13,8 @@ on:
|
|||
|
||||
jobs:
|
||||
merge-conditions:
|
||||
if: vars.ROLE == 'forgejo-coding'
|
||||
if: >
|
||||
vars.ROLE == 'forgejo-coding' && forge.event.pull_request.head.repo.full_name != 'forgejo-cascading-pr/forgejo'
|
||||
runs-on: docker
|
||||
container:
|
||||
image: 'data.forgejo.org/oci/node:22-bookworm'
|
||||
|
@ -26,9 +27,9 @@ jobs:
|
|||
- name: Missing test label
|
||||
if: >
|
||||
!(
|
||||
contains(toJSON(github.event.pull_request.labels), 'test/present')
|
||||
|| contains(toJSON(github.event.pull_request.labels), 'test/not-needed')
|
||||
|| contains(toJSON(github.event.pull_request.labels), 'test/manual')
|
||||
contains(toJSON(forge.event.pull_request.labels), 'test/present')
|
||||
|| contains(toJSON(forge.event.pull_request.labels), 'test/not-needed')
|
||||
|| contains(toJSON(forge.event.pull_request.labels), 'test/manual')
|
||||
)
|
||||
run: |
|
||||
echo "A team member must set the label to either 'present', 'not-needed' or 'manual'."
|
||||
|
@ -36,8 +37,8 @@ jobs:
|
|||
- name: Missing manual test instructions
|
||||
if: >
|
||||
(
|
||||
contains(toJSON(github.event.pull_request.labels), 'test/manual')
|
||||
&& !contains(toJSON(github.event.pull_request.body), '# Test')
|
||||
contains(toJSON(forge.event.pull_request.labels), 'test/manual')
|
||||
&& !contains(toJSON(forge.event.pull_request.body), '# Test')
|
||||
)
|
||||
run: |
|
||||
echo "Manual test label is set. The PR description needs to contain test steps introduced by a heading like:"
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
actions_model "forgejo.org/models/actions"
|
||||
"forgejo.org/models/db"
|
||||
"forgejo.org/models/organization"
|
||||
perm_model "forgejo.org/models/perm"
|
||||
|
@ -136,6 +137,33 @@ func (p *Permission) LogString() string {
|
|||
return fmt.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
func GetActionRepoPermission(ctx context.Context, repo *repo_model.Repository, task *actions_model.ActionTask) (Permission, error) {
|
||||
// straight forward case: an actions task is attempting to access its own repo
|
||||
if task.RepoID == repo.ID {
|
||||
var mode perm_model.AccessMode
|
||||
|
||||
// determine default access mode for repo:
|
||||
if task.IsForkPullRequest {
|
||||
mode = perm_model.AccessModeRead
|
||||
} else {
|
||||
mode = perm_model.AccessModeWrite
|
||||
}
|
||||
|
||||
if err := repo.LoadUnits(ctx); err != nil {
|
||||
return Permission{}, err
|
||||
}
|
||||
|
||||
perm := Permission{
|
||||
AccessMode: mode,
|
||||
Units: repo.Units,
|
||||
}
|
||||
|
||||
return perm, nil
|
||||
}
|
||||
|
||||
return GetUserRepoPermission(ctx, repo, user_model.NewActionsUser())
|
||||
}
|
||||
|
||||
// GetUserRepoPermission returns the user permissions to the repository
|
||||
func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (Permission, error) {
|
||||
var perm Permission
|
||||
|
|
78
models/perm/access/repo_permission_test.go
Normal file
78
models/perm/access/repo_permission_test.go
Normal file
|
@ -0,0 +1,78 @@
|
|||
package access_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
actions_model "forgejo.org/models/actions"
|
||||
"forgejo.org/models/db"
|
||||
perm_model "forgejo.org/models/perm"
|
||||
"forgejo.org/models/perm/access"
|
||||
repo_model "forgejo.org/models/repo"
|
||||
"forgejo.org/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func assertAccess(t *testing.T, expectedMode perm_model.AccessMode, perm *access.Permission) {
|
||||
assert.Equal(t, expectedMode, perm.AccessMode)
|
||||
|
||||
for _, unit := range perm.Units {
|
||||
assert.Equal(t, expectedMode, perm.UnitAccessMode(unit.Type))
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionTaskCanAccessOwnRepo(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: actionTask.RepoID})
|
||||
|
||||
perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask)
|
||||
require.NoError(t, err)
|
||||
assertAccess(t, perm_model.AccessModeWrite, &perm)
|
||||
}
|
||||
|
||||
func TestActionTaskCanAccessPublicRepo(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask)
|
||||
require.NoError(t, err)
|
||||
assertAccess(t, perm_model.AccessModeRead, &perm)
|
||||
}
|
||||
|
||||
func TestActionTaskCanAccessPublicRepoOfLimitedOrg(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 38})
|
||||
|
||||
perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask)
|
||||
require.NoError(t, err)
|
||||
assertAccess(t, perm_model.AccessModeRead, &perm)
|
||||
}
|
||||
|
||||
func TestActionTaskNoAccessPublicRepoOfPrivateOrg(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 40})
|
||||
|
||||
perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask)
|
||||
require.NoError(t, err)
|
||||
assertAccess(t, perm_model.AccessModeNone, &perm)
|
||||
}
|
||||
|
||||
func TestActionTaskNoAccessPrivateRepo(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
|
||||
perm, err := access.GetActionRepoPermission(db.DefaultContext, repo, actionTask)
|
||||
require.NoError(t, err)
|
||||
assertAccess(t, perm_model.AccessModeNone, &perm)
|
||||
}
|
|
@ -192,24 +192,19 @@ func httpBase(ctx *context.Context) *serviceHandler {
|
|||
ctx.ServerError("GetTaskByID", err)
|
||||
return nil
|
||||
}
|
||||
if task.RepoID != repo.ID {
|
||||
|
||||
p, err := access_model.GetActionRepoPermission(ctx, repo, task)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetActionRepoPermission", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !p.CanAccess(accessMode, unitType) {
|
||||
ctx.PlainText(http.StatusForbidden, "User permission denied")
|
||||
return nil
|
||||
}
|
||||
|
||||
if task.IsForkPullRequest {
|
||||
if accessMode > perm.AccessModeRead {
|
||||
ctx.PlainText(http.StatusForbidden, "User permission denied")
|
||||
return nil
|
||||
}
|
||||
environ = append(environ, fmt.Sprintf("%s=%d", repo_module.EnvActionPerm, perm.AccessModeRead))
|
||||
} else {
|
||||
if accessMode > perm.AccessModeWrite {
|
||||
ctx.PlainText(http.StatusForbidden, "User permission denied")
|
||||
return nil
|
||||
}
|
||||
environ = append(environ, fmt.Sprintf("%s=%d", repo_module.EnvActionPerm, perm.AccessModeWrite))
|
||||
}
|
||||
environ = append(environ, fmt.Sprintf("%s=%d", repo_module.EnvActionPerm, p.AccessMode))
|
||||
} else {
|
||||
p, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
|
||||
if err != nil {
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
actions_model "forgejo.org/models/actions"
|
||||
auth_model "forgejo.org/models/auth"
|
||||
"forgejo.org/models/db"
|
||||
git_model "forgejo.org/models/git"
|
||||
|
@ -51,6 +52,33 @@ func TestGit(t *testing.T) {
|
|||
onGiteaRun(t, testGit)
|
||||
}
|
||||
|
||||
func TestActionsTokenAuth(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
task := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 47})
|
||||
task.GenerateToken()
|
||||
actions_model.UpdateTask(db.DefaultContext, task)
|
||||
u.User = url.UserPassword("token", task.Token)
|
||||
|
||||
t.Run("clone task's own repo", func(t *testing.T) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: task.RepoID})
|
||||
u.Path = fmt.Sprintf("/%s/%s.git", repo.OwnerName, repo.Name)
|
||||
doGitClone(t.TempDir(), u)(t)
|
||||
})
|
||||
|
||||
t.Run("clone public repo of limited owner", func(t *testing.T) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 38})
|
||||
u.Path = fmt.Sprintf("/%s/%s.git", repo.OwnerName, repo.Name)
|
||||
doGitClone(t.TempDir(), u)(t)
|
||||
})
|
||||
|
||||
t.Run("cannot clone private repo", func(t *testing.T) {
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
u.Path = fmt.Sprintf("/%s/%s.git", repo.OwnerName, repo.Name)
|
||||
doGitCloneFail(u)(t)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func testGit(t *testing.T, u *url.URL) {
|
||||
username := "user2"
|
||||
baseAPITestContext := NewAPITestContext(t, username, "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue