mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-24 23:26:34 +02:00
Improve test coverage
This commit is contained in:
parent
b2f05ff4f7
commit
06b3db5507
@ -10,14 +10,17 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
actions_model "code.gitea.io/gitea/models/actions"
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/perm"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
unit_model "code.gitea.io/gitea/models/unit"
|
unit_model "code.gitea.io/gitea/models/unit"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
org_model "code.gitea.io/gitea/models/organization"
|
||||||
"code.gitea.io/gitea/modules/util"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -229,3 +232,135 @@ func testActionsTokenPermissionsMode(u *url.URL, mode string, expectReadOnly boo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestActionsTokenPermissionsClamping(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
|
httpContext := NewAPITestContext(t, "user2", "repo-clamping", auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
t.Run("Create Repository", doAPICreateRepository(httpContext, false, func(t *testing.T, repository structs.Repository) {
|
||||||
|
// Enable Actions unit with Clamping Config
|
||||||
|
err := db.Insert(t.Context(), &repo_model.RepoUnit{
|
||||||
|
RepoID: repository.ID,
|
||||||
|
Type: unit_model.TypeActions,
|
||||||
|
Config: &repo_model.ActionsConfig{
|
||||||
|
TokenPermissionMode: repo_model.ActionsTokenPermissionModeCustom,
|
||||||
|
DefaultTokenPermissions: &repo_model.ActionsTokenPermissions{
|
||||||
|
Contents: perm.AccessModeWrite, // Default is Write
|
||||||
|
},
|
||||||
|
MaxTokenPermissions: &repo_model.ActionsTokenPermissions{
|
||||||
|
Contents: perm.AccessModeRead, // Max is Read
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Create Task and Token
|
||||||
|
task := &actions_model.ActionTask{
|
||||||
|
RepoID: repository.ID,
|
||||||
|
Status: actions_model.StatusRunning,
|
||||||
|
IsForkPullRequest: false,
|
||||||
|
}
|
||||||
|
require.NoError(t, task.GenerateToken())
|
||||||
|
require.NoError(t, db.Insert(t.Context(), task))
|
||||||
|
|
||||||
|
// Verify Token Permissions
|
||||||
|
session := emptyTestSession(t)
|
||||||
|
testCtx := APITestContext{
|
||||||
|
Session: session,
|
||||||
|
Token: task.Token,
|
||||||
|
Username: "user2",
|
||||||
|
Reponame: "repo-clamping",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Try to Write (Create File) - Should Fail (403) because Max is Read
|
||||||
|
testCtx.ExpectedCode = http.StatusForbidden
|
||||||
|
t.Run("Fail to Create File (Max Clamping)", doAPICreateFile(testCtx, "clamping.txt", &structs.CreateFileOptions{
|
||||||
|
ContentBase64: base64.StdEncoding.EncodeToString([]byte("test")),
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 2. Try to Read (Get Repository) - Should Succeed (200)
|
||||||
|
testCtx.ExpectedCode = http.StatusOK
|
||||||
|
t.Run("Get Repository (Read Allowed)", doAPIGetRepository(testCtx, func(t *testing.T, r structs.Repository) {
|
||||||
|
assert.Equal(t, "repo-clamping", r.Name)
|
||||||
|
}))
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestActionsCrossRepoAccess(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteOrganization)
|
||||||
|
|
||||||
|
// 1. Create Organization
|
||||||
|
orgName := "org-cross-test"
|
||||||
|
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs", &structs.CreateOrgOption{
|
||||||
|
UserName: orgName,
|
||||||
|
}).AddTokenAuth(token)
|
||||||
|
MakeRequest(t, req, http.StatusCreated)
|
||||||
|
|
||||||
|
// 2. Create Two Repositories in Org
|
||||||
|
createRepoInOrg := func(name string) int64 {
|
||||||
|
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/repos", orgName), &structs.CreateRepoOption{
|
||||||
|
Name: name,
|
||||||
|
AutoInit: true,
|
||||||
|
Private: true, // Must be private for potential restrictions
|
||||||
|
}).AddTokenAuth(token)
|
||||||
|
resp := MakeRequest(t, req, http.StatusCreated)
|
||||||
|
var repo structs.Repository
|
||||||
|
DecodeJSON(t, resp, &repo)
|
||||||
|
return repo.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
repoA_ID := createRepoInOrg("repo-A")
|
||||||
|
// repoB_ID is unused as we access it via API name
|
||||||
|
createRepoInOrg("repo-B")
|
||||||
|
|
||||||
|
// 3. Enable Actions in Repo A (Source)
|
||||||
|
err := db.Insert(t.Context(), &repo_model.RepoUnit{
|
||||||
|
RepoID: repoA_ID,
|
||||||
|
Type: unit_model.TypeActions,
|
||||||
|
Config: &repo_model.ActionsConfig{
|
||||||
|
TokenPermissionMode: repo_model.ActionsTokenPermissionModePermissive,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// 4. Create Task in Repo A
|
||||||
|
task := &actions_model.ActionTask{
|
||||||
|
RepoID: repoA_ID,
|
||||||
|
Status: actions_model.StatusRunning,
|
||||||
|
IsForkPullRequest: false,
|
||||||
|
}
|
||||||
|
require.NoError(t, task.GenerateToken())
|
||||||
|
require.NoError(t, db.Insert(t.Context(), task))
|
||||||
|
|
||||||
|
// 5. Verify Access to Repo B (Target)
|
||||||
|
testCtx := APITestContext{
|
||||||
|
Session: emptyTestSession(t),
|
||||||
|
Token: task.Token,
|
||||||
|
Username: orgName,
|
||||||
|
Reponame: "repo-B",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case A: Default (AllowCrossRepoAccess = false/unset) -> Should Fail (404 Not Found)
|
||||||
|
// API returns 404 for private repos you can't access, not 403, to avoid leaking existence.
|
||||||
|
testCtx.ExpectedCode = http.StatusNotFound
|
||||||
|
t.Run("Cross-Repo Access Denied (Default)", doAPIGetRepository(testCtx, nil))
|
||||||
|
|
||||||
|
// Case B: Enable AllowCrossRepoAccess
|
||||||
|
org, err := org_model.GetOrgByName(t.Context(), orgName)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cfg := &repo_model.ActionsConfig{
|
||||||
|
AllowCrossRepoAccess: true,
|
||||||
|
}
|
||||||
|
err = actions_model.SetOrgActionsConfig(t.Context(), org.ID, cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Retry -> Should Succeed (200) - Read Only
|
||||||
|
testCtx.ExpectedCode = http.StatusOK
|
||||||
|
t.Run("Cross-Repo Access Allowed", doAPIGetRepository(testCtx, func(t *testing.T, r structs.Repository) {
|
||||||
|
assert.Equal(t, "repo-B", r.Name)
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user