@@ -11,8 +11,10 @@ import (
1111 "net/http"
1212 "net/url"
1313 "os"
14+ "os/exec"
1415 "path"
1516 "path/filepath"
17+ "slices"
1618 "strconv"
1719 "testing"
1820 "time"
@@ -31,7 +33,9 @@ import (
3133 gitea_context "code.gitea.io/gitea/services/context"
3234 "code.gitea.io/gitea/tests"
3335
36+ "github.com/kballard/go-shellquote"
3437 "github.com/stretchr/testify/assert"
38+ "github.com/stretchr/testify/require"
3539)
3640
3741const (
@@ -105,7 +109,12 @@ func testGitGeneral(t *testing.T, u *url.URL) {
105109
106110 // Setup key the user ssh key
107111 withKeyFile (t , keyname , func (keyFile string ) {
108- t .Run ("CreateUserKey" , doAPICreateUserKey (sshContext , "test-key" , keyFile ))
112+ var keyID int64
113+ t .Run ("CreateUserKey" , doAPICreateUserKey (sshContext , "test-key" , keyFile , func (t * testing.T , key api.PublicKey ) {
114+ keyID = key .ID
115+ }))
116+ assert .NotZero (t , keyID )
117+ t .Run ("LFSAccessTest" , doSSHLFSAccessTest (sshContext , keyID ))
109118
110119 // Setup remote link
111120 // TODO: get url from api
@@ -136,6 +145,36 @@ func testGitGeneral(t *testing.T, u *url.URL) {
136145 })
137146}
138147
148+ func doSSHLFSAccessTest (_ APITestContext , keyID int64 ) func (* testing.T ) {
149+ return func (t * testing.T ) {
150+ sshCommand := os .Getenv ("GIT_SSH_COMMAND" ) // it is set in withKeyFile
151+ sshCmdParts , err := shellquote .Split (sshCommand ) // and parse the ssh command to construct some mocked arguments
152+ require .NoError (t , err )
153+
154+ t .Run ("User2AccessOwned" , func (t * testing.T ) {
155+ sshCmdUser2Self := append (slices .Clone (sshCmdParts ),
156+ "-p" , strconv .Itoa (setting .SSH .ListenPort ), "git@" + setting .SSH .ListenHost ,
157+ "git-lfs-authenticate" , "user2/repo1.git" , "upload" , // accessible to own repo
158+ )
159+ cmd := exec .CommandContext (git .DefaultContext , sshCmdUser2Self [0 ], sshCmdUser2Self [1 :]... )
160+ _ , err := cmd .Output ()
161+ assert .NoError (t , err ) // accessible, no error
162+ })
163+
164+ t .Run ("User2AccessOther" , func (t * testing.T ) {
165+ sshCmdUser2Other := append (slices .Clone (sshCmdParts ),
166+ "-p" , strconv .Itoa (setting .SSH .ListenPort ), "git@" + setting .SSH .ListenHost ,
167+ "git-lfs-authenticate" , "user5/repo4.git" , "upload" , // inaccessible to other's (user5/repo4)
168+ )
169+ cmd := exec .CommandContext (git .DefaultContext , sshCmdUser2Other [0 ], sshCmdUser2Other [1 :]... )
170+ _ , err := cmd .Output ()
171+ var errExit * exec.ExitError
172+ require .ErrorAs (t , err , & errExit ) // inaccessible, error
173+ assert .Contains (t , string (errExit .Stderr ), fmt .Sprintf ("User: 2:user2 with Key: %d:test-key is not authorized to write to user5/repo4." , keyID ))
174+ })
175+ }
176+ }
177+
139178func ensureAnonymousClone (t * testing.T , u * url.URL ) {
140179 dstLocalPath := t .TempDir ()
141180 t .Run ("CloneAnonymous" , doGitClone (dstLocalPath , u ))
0 commit comments