Skip to content

Commit e1e14e7

Browse files
committed
fix lfs locks for actions user
1 parent 38fd35c commit e1e14e7

File tree

5 files changed

+89
-7
lines changed

5 files changed

+89
-7
lines changed

models/git/lfs_lock.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,20 @@ func CheckLFSAccessForRepo(ctx context.Context, ownerID int64, repo *repo_model.
186186
if ownerID == 0 {
187187
return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode}
188188
}
189+
if ownerID == user_model.ActionsUserID {
190+
taskId, ok := ctx.Value(user_model.ActionsUserName).(int64)
191+
if !ok || taskId == 0 {
192+
return ErrLFSUnauthorizedAction{repo.ID, user_model.ActionsUserName, mode}
193+
}
194+
perm, err := access_model.GetActionsUserRepoPermission(ctx, repo, user_model.NewActionsUser(), taskId)
195+
if err != nil {
196+
return err
197+
}
198+
if !perm.CanAccess(mode, unit.TypeCode) {
199+
return ErrLFSUnauthorizedAction{repo.ID, user_model.ActionsUserName, mode}
200+
}
201+
return nil
202+
}
189203
u, err := user_model.GetUserByID(ctx, ownerID)
190204
if err != nil {
191205
return err

services/convert/convert.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,13 @@ func ToOAuth2Application(app *auth.OAuth2Application) *api.OAuth2Application {
771771

772772
// ToLFSLock convert a LFSLock to api.LFSLock
773773
func ToLFSLock(ctx context.Context, l *git_model.LFSLock) *api.LFSLock {
774-
u, err := user_model.GetUserByID(ctx, l.OwnerID)
774+
var u *user_model.User
775+
var err error
776+
if l.OwnerID == user_model.ActionsUserID {
777+
u = user_model.NewActionsUser()
778+
} else {
779+
u, err = user_model.GetUserByID(ctx, l.OwnerID)
780+
}
775781
if err != nil {
776782
return nil
777783
}

services/lfs/locks.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
package lfs
55

66
import (
7+
go_context "context"
78
"net/http"
89
"strconv"
910
"strings"
1011

1112
auth_model "code.gitea.io/gitea/models/auth"
1213
git_model "code.gitea.io/gitea/models/git"
1314
repo_model "code.gitea.io/gitea/models/repo"
15+
user_model "code.gitea.io/gitea/models/user"
1416
"code.gitea.io/gitea/modules/json"
1517
lfs_module "code.gitea.io/gitea/modules/lfs"
1618
"code.gitea.io/gitea/modules/log"
@@ -175,7 +177,14 @@ func PostLockHandler(ctx *context.Context) {
175177
return
176178
}
177179

178-
lock, err := git_model.CreateLFSLock(ctx, repository, &git_model.LFSLock{
180+
var lockCtx go_context.Context = ctx
181+
// Pass Actions Task ID in context if creating lock using Actions Job Token
182+
if ctx.Doer != nil && ctx.Doer.ID == user_model.ActionsUserID {
183+
taskID := ctx.Data["ActionsTaskID"].(int64)
184+
lockCtx = go_context.WithValue(lockCtx, user_model.ActionsUserName, taskID)
185+
}
186+
187+
lock, err := git_model.CreateLFSLock(lockCtx, repository, &git_model.LFSLock{
179188
Path: req.Path,
180189
OwnerID: ctx.Doer.ID,
181190
})
@@ -315,7 +324,14 @@ func UnLockHandler(ctx *context.Context) {
315324
return
316325
}
317326

318-
lock, err := git_model.DeleteLFSLockByID(ctx, ctx.PathParamInt64("lid"), repository, ctx.Doer, req.Force)
327+
var lockCtx go_context.Context = ctx
328+
// Pass Actions Task ID in context if deleting lock using Actions Job Token
329+
if ctx.Doer != nil && ctx.Doer.ID == user_model.ActionsUserID {
330+
taskID := ctx.Data["ActionsTaskID"].(int64)
331+
lockCtx = go_context.WithValue(lockCtx, user_model.ActionsUserName, taskID)
332+
}
333+
334+
lock, err := git_model.DeleteLFSLockByID(lockCtx, ctx.PathParamInt64("lid"), repository, ctx.Doer, req.Force)
319335
if err != nil {
320336
if git_model.IsErrLFSUnauthorizedAction(err) {
321337
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)

tests/integration/actions_job_token_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ package integration
55

66
import (
77
"encoding/base64"
8+
"net/http"
89
"net/url"
910
"testing"
1011

1112
actions_model "code.gitea.io/gitea/models/actions"
13+
auth_model "code.gitea.io/gitea/models/auth"
14+
"code.gitea.io/gitea/models/db"
1215
"code.gitea.io/gitea/models/unittest"
1316
"code.gitea.io/gitea/modules/structs"
17+
api "code.gitea.io/gitea/modules/structs"
1418

19+
"github.com/stretchr/testify/assert"
1520
"github.com/stretchr/testify/require"
1621
)
1722

@@ -72,3 +77,44 @@ func testActionsJobTokenAccess(u *url.URL, isFork bool) func(t *testing.T) {
7277
}))
7378
}
7479
}
80+
81+
func TestActionsJobTokenAccessLFS(t *testing.T) {
82+
onGiteaRun(t, func(t *testing.T, u *url.URL) {
83+
httpContext := NewAPITestContext(t, "user2", "repo-lfs-test", auth_model.AccessTokenScopeWriteUser, auth_model.AccessTokenScopeWriteRepository)
84+
t.Run("Create Repository", doAPICreateRepository(httpContext, false, func(t *testing.T, repository api.Repository) {
85+
86+
task := &actions_model.ActionTask{}
87+
require.NoError(t, task.GenerateToken())
88+
task.Status = actions_model.StatusRunning
89+
task.IsForkPullRequest = false
90+
task.RepoID = repository.ID
91+
err := db.Insert(t.Context(), task)
92+
require.NoError(t, err)
93+
session := emptyTestSession(t)
94+
httpContext := APITestContext{
95+
Session: session,
96+
Token: task.Token,
97+
Username: "user2",
98+
Reponame: "repo-lfs-test",
99+
}
100+
101+
u.Path = httpContext.GitPath()
102+
dstPath := t.TempDir()
103+
104+
u.Path = httpContext.GitPath()
105+
u.User = url.UserPassword("gitea-actions", task.Token)
106+
107+
t.Run("Clone", doGitClone(dstPath, u))
108+
109+
dstPath2 := t.TempDir()
110+
111+
t.Run("Partial Clone", doPartialGitClone(dstPath2, u))
112+
113+
lfs := lfsCommitAndPushTest(t, dstPath, testFileSizeSmall)[0]
114+
115+
reqLFS := NewRequest(t, "GET", "/api/v1/repos/user2/repo-lfs-test/media/"+lfs).AddTokenAuth(task.Token)
116+
respLFS := MakeRequestNilResponseRecorder(t, reqLFS, http.StatusOK)
117+
assert.Equal(t, testFileSizeSmall, respLFS.Length)
118+
}))
119+
})
120+
}

tests/integration/api_repo_file_get_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ func TestAPIGetRawFileOrLFS(t *testing.T) {
2525

2626
// Test with LFS
2727
onGiteaRun(t, func(t *testing.T, u *url.URL) {
28-
httpContext := NewAPITestContext(t, "user2", "repo-lfs-test", auth_model.AccessTokenScopeWriteRepository)
29-
doAPICreateRepository(httpContext, false, func(t *testing.T, repository api.Repository) {
28+
httpContext := NewAPITestContext(t, "user2", "repo-lfs-test", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
29+
t.Run("repo-lfs-test", doAPICreateRepository(httpContext, false, func(t *testing.T, repository api.Repository) {
3030
u.Path = httpContext.GitPath()
3131
dstPath := t.TempDir()
3232

@@ -41,9 +41,9 @@ func TestAPIGetRawFileOrLFS(t *testing.T) {
4141

4242
lfs := lfsCommitAndPushTest(t, dstPath, testFileSizeSmall)[0]
4343

44-
reqLFS := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/"+lfs)
44+
reqLFS := NewRequest(t, "GET", "/api/v1/repos/user2/repo-lfs-test/media/"+lfs).AddTokenAuth(httpContext.Token)
4545
respLFS := MakeRequestNilResponseRecorder(t, reqLFS, http.StatusOK)
4646
assert.Equal(t, testFileSizeSmall, respLFS.Length)
47-
})
47+
}))
4848
})
4949
}

0 commit comments

Comments
 (0)