Git LFS file locks are not scoped per repository - lock list is shared across all projects #2863
iCONTEN GmbH opened 1 week ago

Summary

Git LFS file locks created in one project are visible in (and affect) every other project on the same OneDev instance. The LFS File Locking API is specified per repository, but OneDev appears to keep a single instance-wide lock store.

Spec reference: https://github.com/git-lfs/git-lfs/blob/main/docs/api/locking.md (lock endpoints are defined relative to a repository's LFS endpoint, i.e. <repo>.git/info/lfs/locks).

Steps to reproduce

Tested with OneDev 16.1.0 (1dev/server:latest, release date 2026-07-16, commit 140e1958) in Docker, unattended setup:

docker run --name onedev-lock-test -d \
  -e initial_user=admin -e initial_password=<pw> \
  -e [email protected] -e initial_server_url=http://localhost:6610 \
  -v /tmp/onedev-lock-test:/opt/onedev -p 6610:6610 1dev/server
  1. Create two independent projects lock-a and lock-b (via UI or POST /~api/projects), push an initial commit to each.
  2. Create an LFS lock in lock-a only:
curl -u admin:<pw> \
  -H 'Content-Type: application/vnd.git-lfs+json' \
  -H 'Accept: application/vnd.git-lfs+json' \
  -X POST http://localhost:6610/lock-a.git/info/lfs/locks \
  -d '{"path":"assets/data.bin"}'
  1. List locks of both projects:
curl -u admin:<pw> -H 'Accept: application/vnd.git-lfs+json' \
  http://localhost:6610/lock-a.git/info/lfs/locks
curl -u admin:<pw> -H 'Accept: application/vnd.git-lfs+json' \
  http://localhost:6610/lock-b.git/info/lfs/locks

Actual result

Both endpoints return the same lock with the same id:

{ 
  "locks" : [ 
    { 
      "owner" : { "name" : "admin" },
      "path" : "assets/data.bin",
      "locked_at" : "2026-07-17T14:58:25Z",
      "id" : "1"
     }
    ]
}

The same behavior is visible with the plain git-lfs client (git lfs locks inside a clone of lock-b shows locks created in lock-a and in any other project of the instance). Observed on a production instance running 14.1.9 as well.

Expected result

lock-b returns an empty lock list. Locks must be scoped to the repository whose LFS endpoint they were created on:

  • Two repositories containing the same relative path must be lockable independently.
  • git lfs locks / lock verification (lfs.locksverify) in one repository must not be influenced by locks of other repositories.
  • Unlocking via one repository's endpoint must not remove another repository's lock.

Impact

Any workflow that relies on LFS file locking (e.g. exclusive check-out of binary files) breaks as soon as more than one repository on the instance uses the same relative paths - which is the normal case when repositories share a common directory layout. Locks from unrelated (even private) projects also leak into every project's lock listing, which is a minor information disclosure issue as well.

  • Robin Shen changed fields 1 week ago
    Name Previous Value Current Value
    Assignee
    robin
    wh
  • Work Horse commented 1 week ago

    Fixed in pr #84.

    Git LFS locks are now scoped per project: create/list/verify/unlock all filter by repository, and unlock rejects locks that belong to another project. Existing locks are removed during upgrade because they were not associated with a project and cannot be migrated reliably.

  • Chief Work Horse referenced from pull request 1 week ago
  • OneDev commented 1 week ago

    State changed as build OD-7736 (16.2.0) is successful

  • OneDev changed state to 'Closed' 1 week ago
    Previous Value Current Value
    Open
    Closed
1/1
Type
Bug
Priority
Normal
Assignee
Affected Versions
16.1.0
Labels
No labels
Issue Votes (0)
Watchers (3)
Reference
OD-2863
Please wait...
Connection lost or session expired, reload to recover
Page is in error, reload to recover