mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-12 22:10:25 +00:00
feat: implement fine-grained access tokens in /repos/issues/search
This commit is contained in:
parent
2192184d9b
commit
0da4505a49
2 changed files with 93 additions and 0 deletions
|
|
@ -166,6 +166,8 @@ func SearchIssues(ctx *context.APIContext) {
|
||||||
// MySQL will return different results when sorting by null in some cases
|
// MySQL will return different results when sorting by null in some cases
|
||||||
OrderBy: db.SearchOrderByAlphabetically,
|
OrderBy: db.SearchOrderByAlphabetically,
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
|
|
||||||
|
AuthorizationReducer: ctx.Reducer,
|
||||||
}
|
}
|
||||||
if ctx.IsSigned {
|
if ctx.IsSigned {
|
||||||
opts.Private = !ctx.PublicOnly
|
opts.Private = !ctx.PublicOnly
|
||||||
|
|
|
||||||
|
|
@ -660,6 +660,97 @@ func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||||
assert.Len(t, apiIssues, 2)
|
assert.Len(t, apiIssues, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPISearchIssuesAccessTokenResources(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
var issues []*api.Issue
|
||||||
|
|
||||||
|
// Test repos: repo1 (public), repo2 (private), repo16 (private).
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
writeToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteIssue)
|
||||||
|
|
||||||
|
// On those three test repos, create an issue with a specific title for search.
|
||||||
|
for _, repo := range []string{"repo1", "repo2", "repo16"} {
|
||||||
|
trueBool := true
|
||||||
|
// Enable issues on each target repo as well
|
||||||
|
req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/user2/%s", repo), &api.EditRepoOption{
|
||||||
|
HasIssues: &trueBool,
|
||||||
|
}).AddTokenAuth(writeToken)
|
||||||
|
MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/user2/%s/issues", repo), &api.CreateIssueOption{
|
||||||
|
Body: "body: abracadabra",
|
||||||
|
Title: "important issue",
|
||||||
|
}).AddTokenAuth(writeToken)
|
||||||
|
MakeRequest(t, req, http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
find := func() (bool, bool, bool) {
|
||||||
|
foundRepo1 := false // public user2/repo1
|
||||||
|
foundRepo2 := false // private user2/repo2
|
||||||
|
foundRepo16 := false // second private repo user2/repo16 used in fine-grain testing, included as baseline
|
||||||
|
for _, issue := range issues {
|
||||||
|
switch issue.Repo.Name {
|
||||||
|
case "repo1":
|
||||||
|
foundRepo1 = true
|
||||||
|
case "repo2":
|
||||||
|
foundRepo2 = true
|
||||||
|
case "repo16":
|
||||||
|
foundRepo16 = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundRepo1, foundRepo2, foundRepo16
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("all access token", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
allToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue)
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/api/v1/repos/issues/search").AddTokenAuth(allToken)
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &issues)
|
||||||
|
foundRepo1, foundRepo2, foundRepo16 := find()
|
||||||
|
|
||||||
|
assert.True(t, foundRepo1) // public user2/repo1
|
||||||
|
assert.True(t, foundRepo2) // private user2/repo2
|
||||||
|
assert.True(t, foundRepo16) // private user2/repo16, used in fine-grain testing, included as baseline
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("public-only access token", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopePublicOnly, auth_model.AccessTokenScopeReadIssue)
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/api/v1/repos/issues/search").AddTokenAuth(publicOnlyToken)
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &issues)
|
||||||
|
foundRepo1, foundRepo2, foundRepo16 := find()
|
||||||
|
|
||||||
|
assert.True(t, foundRepo1) // public user2/repo1
|
||||||
|
assert.False(t, foundRepo2) // private user2/repo2
|
||||||
|
assert.False(t, foundRepo16) // private user2/repo16
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("specific repo access token", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
repo2OnlyToken := createFineGrainedRepoAccessToken(t, "user2",
|
||||||
|
[]auth_model.AccessTokenScope{auth_model.AccessTokenScopeReadIssue},
|
||||||
|
[]int64{2},
|
||||||
|
)
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/api/v1/repos/issues/search").AddTokenAuth(repo2OnlyToken)
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &issues)
|
||||||
|
foundRepo1, foundRepo2, foundRepo16 := find()
|
||||||
|
|
||||||
|
assert.True(t, foundRepo1) // public user2/repo1, allowed as it's public and read-access only
|
||||||
|
assert.True(t, foundRepo2) // private user2/repo2, allowed inside fine-grain
|
||||||
|
assert.False(t, foundRepo16) // private user2/repo16, denied outside fine-grain
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestAPIInternalAndExternalIssueTracker(t *testing.T) {
|
func TestAPIInternalAndExternalIssueTracker(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue