Diff
1diff --git a/pkg/backend/repo.go b/pkg/backend/repo.go
2index 1e3b63bcfb3f39ff32111a4d6e1a906c3144412b..f9b70bbc3a8f07be4a0e440bd103042fa162b550 100644
3--- a/pkg/backend/repo.go
4+++ b/pkg/backend/repo.go
5@@ -25,6 +25,15 @@ import (
6 "github.com/charmbracelet/soft-serve/pkg/webhook"
7 )
8
9+func validateImportRemote(remote string) error {
10+ endpoint, err := lfs.NewEndpoint(remote)
11+ if err != nil || endpoint.Host == "" {
12+ return proto.ErrInvalidRemote
13+ }
14+
15+ return nil
16+}
17+
18 // CreateRepository creates a new repository.
19 //
20 // It implements backend.Backend.
21@@ -96,6 +105,11 @@ func (d *Backend) ImportRepository(_ context.Context, name string, user proto.Us
22 return nil, err
23 }
24
25+ remote = utils.Sanitize(remote)
26+ if err := validateImportRemote(remote); err != nil {
27+ return nil, err
28+ }
29+
30 rp := filepath.Join(d.repoPath(name))
31
32 tid := "import:" + name
33diff --git a/pkg/proto/errors.go b/pkg/proto/errors.go
34index fa4bc6126a253e972c4fe328193fc46ac03eba6c..1ff116e5ef91dc543b2c3303c7e7e3230e41837d 100644
35--- a/pkg/proto/errors.go
36+++ b/pkg/proto/errors.go
37@@ -7,6 +7,8 @@ import (
38 var (
39 // ErrUnauthorized is returned when the user is not authorized to perform action.
40 ErrUnauthorized = errors.New("unauthorized")
41+ // ErrInvalidRemote is returned when a repository import remote is invalid.
42+ ErrInvalidRemote = errors.New("remote must be a network URL")
43 // ErrFileNotFound is returned when the file is not found.
44 ErrFileNotFound = errors.New("file not found")
45 // ErrRepoNotFound is returned when a repository is not found.
46diff --git a/testscript/testdata/repo-import-local-path.txtar b/testscript/testdata/repo-import-local-path.txtar
47new file mode 100644
48index 0000000000000000000000000000000000000000..7ffa30ad73e16f93d7f7cb9e61271e3163f021ab
49--- /dev/null
50+++ b/testscript/testdata/repo-import-local-path.txtar
51@@ -0,0 +1,34 @@
52+# vi: set ft=conf
53+
54+[windows] skip 'uses a raw server filesystem path as the import remote'
55+
56+# start soft serve
57+exec soft serve &
58+# wait for SSH server to start
59+ensureserverrunning SSH_PORT
60+
61+# create a private repo and a second user
62+soft repo create secret -p
63+soft user create user1 --key "$USER1_AUTHORIZED_KEY"
64+
65+# seed the private repo with content
66+git clone ssh://localhost:$SSH_PORT/secret secret
67+mkfile ./secret/SECRET.txt 'top secret'
68+git -C secret add -A
69+git -C secret commit -m 'first'
70+git -C secret push origin HEAD
71+
72+# user1 cannot read the private repo directly
73+! usoft repo info secret
74+stderr 'repository not found'
75+
76+# user1 also must not be able to import the server-local repo path
77+! usoft repo import stolen "$DATA_PATH/repos/secret.git" --lfs-endpoint http://example.com
78+stderr 'remote must be a network URL'
79+
80+# the failed import must not create a readable repo
81+! usoft repo info stolen
82+stderr 'repository not found'
83+
84+[windows] stopserver
85+[windows] ! stderr .