diff --git a/pkg/backend/repo.go b/pkg/backend/repo.go index 1e3b63bcfb3f39ff32111a4d6e1a906c3144412b..f9b70bbc3a8f07be4a0e440bd103042fa162b550 100644 --- a/pkg/backend/repo.go +++ b/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 diff --git a/pkg/proto/errors.go b/pkg/proto/errors.go index fa4bc6126a253e972c4fe328193fc46ac03eba6c..1ff116e5ef91dc543b2c3303c7e7e3230e41837d 100644 --- a/pkg/proto/errors.go +++ b/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. diff --git a/testscript/testdata/repo-import-local-path.txtar b/testscript/testdata/repo-import-local-path.txtar new file mode 100644 index 0000000000000000000000000000000000000000..7ffa30ad73e16f93d7f7cb9e61271e3163f021ab --- /dev/null +++ b/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 .