Skip to content

Commit eecf538

Browse files
lunnyGiteaBot
authored andcommitted
LFS locks must belong to the intended repo (go-gitea#36344)
1 parent 83ce45b commit eecf538

3 files changed

Lines changed: 87 additions & 5 deletions

File tree

models/git/lfs_lock.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@ func GetLFSLock(ctx context.Context, repo *repo_model.Repository, path string) (
108108
return rel, nil
109109
}
110110

111-
// GetLFSLockByID returns release by given id.
112-
func GetLFSLockByID(ctx context.Context, id int64) (*LFSLock, error) {
111+
// GetLFSLockByIDAndRepo returns lfs lock by given id and repository id.
112+
func GetLFSLockByIDAndRepo(ctx context.Context, id, repoID int64) (*LFSLock, error) {
113113
lock := new(LFSLock)
114-
has, err := db.GetEngine(ctx).ID(id).Get(lock)
114+
has, err := db.GetEngine(ctx).ID(id).And("repo_id = ?", repoID).Get(lock)
115115
if err != nil {
116116
return nil, err
117117
} else if !has {
@@ -160,7 +160,7 @@ func CountLFSLockByRepoID(ctx context.Context, repoID int64) (int64, error) {
160160
// DeleteLFSLockByID deletes a lock by given ID.
161161
func DeleteLFSLockByID(ctx context.Context, id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) {
162162
return db.WithTx2(ctx, func(ctx context.Context) (*LFSLock, error) {
163-
lock, err := GetLFSLockByID(ctx, id)
163+
lock, err := GetLFSLockByIDAndRepo(ctx, id, repo.ID)
164164
if err != nil {
165165
return nil, err
166166
}

models/git/lfs_lock_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2026 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package git
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
"time"
10+
11+
repo_model "code.gitea.io/gitea/models/repo"
12+
"code.gitea.io/gitea/models/unittest"
13+
user_model "code.gitea.io/gitea/models/user"
14+
15+
"github.com/stretchr/testify/assert"
16+
"github.com/stretchr/testify/require"
17+
)
18+
19+
func createTestLock(t *testing.T, repo *repo_model.Repository, owner *user_model.User) *LFSLock {
20+
t.Helper()
21+
22+
path := fmt.Sprintf("%s-%d-%d", t.Name(), repo.ID, time.Now().UnixNano())
23+
lock, err := CreateLFSLock(t.Context(), repo, &LFSLock{
24+
OwnerID: owner.ID,
25+
Path: path,
26+
})
27+
require.NoError(t, err)
28+
return lock
29+
}
30+
31+
func TestGetLFSLockByIDAndRepo(t *testing.T) {
32+
require.NoError(t, unittest.PrepareTestDatabase())
33+
34+
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
35+
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
36+
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
37+
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
38+
39+
lockRepo1 := createTestLock(t, repo1, user2)
40+
lockRepo3 := createTestLock(t, repo3, user4)
41+
42+
fetched, err := GetLFSLockByIDAndRepo(t.Context(), lockRepo1.ID, repo1.ID)
43+
require.NoError(t, err)
44+
assert.Equal(t, lockRepo1.ID, fetched.ID)
45+
assert.Equal(t, repo1.ID, fetched.RepoID)
46+
47+
_, err = GetLFSLockByIDAndRepo(t.Context(), lockRepo1.ID, repo3.ID)
48+
assert.Error(t, err)
49+
assert.True(t, IsErrLFSLockNotExist(err))
50+
51+
_, err = GetLFSLockByIDAndRepo(t.Context(), lockRepo3.ID, repo1.ID)
52+
assert.Error(t, err)
53+
assert.True(t, IsErrLFSLockNotExist(err))
54+
}
55+
56+
func TestDeleteLFSLockByIDRequiresRepoMatch(t *testing.T) {
57+
require.NoError(t, unittest.PrepareTestDatabase())
58+
59+
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
60+
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
61+
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
62+
user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
63+
64+
lockRepo1 := createTestLock(t, repo1, user2)
65+
lockRepo3 := createTestLock(t, repo3, user4)
66+
67+
_, err := DeleteLFSLockByID(t.Context(), lockRepo3.ID, repo1, user2, true)
68+
assert.Error(t, err)
69+
assert.True(t, IsErrLFSLockNotExist(err))
70+
71+
existing, err := GetLFSLockByIDAndRepo(t.Context(), lockRepo3.ID, repo3.ID)
72+
require.NoError(t, err)
73+
assert.Equal(t, lockRepo3.ID, existing.ID)
74+
75+
deleted, err := DeleteLFSLockByID(t.Context(), lockRepo3.ID, repo3, user4, true)
76+
require.NoError(t, err)
77+
assert.Equal(t, lockRepo3.ID, deleted.ID)
78+
79+
deleted, err = DeleteLFSLockByID(t.Context(), lockRepo1.ID, repo1, user2, false)
80+
require.NoError(t, err)
81+
assert.Equal(t, lockRepo1.ID, deleted.ID)
82+
}

services/lfs/locks.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func GetListLockHandler(ctx *context.Context) {
9090
})
9191
return
9292
}
93-
lock, err := git_model.GetLFSLockByID(ctx, v)
93+
lock, err := git_model.GetLFSLockByIDAndRepo(ctx, v, repository.ID)
9494
if err != nil && !git_model.IsErrLFSLockNotExist(err) {
9595
log.Error("Unable to get lock with ID[%s]: Error: %v", v, err)
9696
}

0 commit comments

Comments
 (0)