Merge commit from fork

Evan MORVAN created

Change summary

pkg/backend/repo.go                              | 14 +++++++
pkg/proto/errors.go                              |  2 +
testscript/testdata/repo-import-local-path.txtar | 34 ++++++++++++++++++
3 files changed, 50 insertions(+)

Detailed changes

pkg/backend/repo.go 🔗

@@ -25,6 +25,15 @@ import (
 	"github.com/charmbracelet/soft-serve/pkg/webhook"
 )
 
+func validateImportRemote(remote string) error {
+	endpoint, err := lfs.NewEndpoint(remote)
+	if err != nil || endpoint.Host == "" {
+		return proto.ErrInvalidRemote
+	}
+
+	return nil
+}
+
 // CreateRepository creates a new repository.
 //
 // It implements backend.Backend.
@@ -96,6 +105,11 @@ func (d *Backend) ImportRepository(_ context.Context, name string, user proto.Us
 		return nil, err
 	}
 
+	remote = utils.Sanitize(remote)
+	if err := validateImportRemote(remote); err != nil {
+		return nil, err
+	}
+
 	rp := filepath.Join(d.repoPath(name))
 
 	tid := "import:" + name

pkg/proto/errors.go 🔗

@@ -7,6 +7,8 @@ import (
 var (
 	// ErrUnauthorized is returned when the user is not authorized to perform action.
 	ErrUnauthorized = errors.New("unauthorized")
+	// ErrInvalidRemote is returned when a repository import remote is invalid.
+	ErrInvalidRemote = errors.New("remote must be a network URL")
 	// ErrFileNotFound is returned when the file is not found.
 	ErrFileNotFound = errors.New("file not found")
 	// ErrRepoNotFound is returned when a repository is not found.

testscript/testdata/repo-import-local-path.txtar 🔗

@@ -0,0 +1,34 @@
+# vi: set ft=conf
+
+[windows] skip 'uses a raw server filesystem path as the import remote'
+
+# start soft serve
+exec soft serve &
+# wait for SSH server to start
+ensureserverrunning SSH_PORT
+
+# create a private repo and a second user
+soft repo create secret -p
+soft user create user1 --key "$USER1_AUTHORIZED_KEY"
+
+# seed the private repo with content
+git clone ssh://localhost:$SSH_PORT/secret secret
+mkfile ./secret/SECRET.txt 'top secret'
+git -C secret add -A
+git -C secret commit -m 'first'
+git -C secret push origin HEAD
+
+# user1 cannot read the private repo directly
+! usoft repo info secret
+stderr 'repository not found'
+
+# user1 also must not be able to import the server-local repo path
+! usoft repo import stolen "$DATA_PATH/repos/secret.git" --lfs-endpoint http://example.com
+stderr 'remote must be a network URL'
+
+# the failed import must not create a readable repo
+! usoft repo info stolen
+stderr 'repository not found'
+
+[windows] stopserver
+[windows] ! stderr .