mirror of https://github.com/databricks/cli.git
proper fix
This commit is contained in:
parent
5368972172
commit
90b80eb91b
|
@ -35,7 +35,7 @@ func filerForPath(ctx context.Context, fullPath string) (filer.Filer, string, er
|
|||
if runtime.GOOS == "windows" {
|
||||
parts := strings.SplitN(path, ":", 2)
|
||||
if len(parts) < 2 {
|
||||
return nil, "", fmt.Errorf("no volume specfied for path: %s", path)
|
||||
return nil, "", fmt.Errorf("no volume specified for path: %s", path)
|
||||
}
|
||||
volume := parts[0] + ":"
|
||||
relPath := parts[1]
|
||||
|
|
|
@ -67,14 +67,14 @@ type DbfsClient struct {
|
|||
workspaceClient *databricks.WorkspaceClient
|
||||
|
||||
// File operations will be relative to this path.
|
||||
root RootPath
|
||||
root UnixRootPath
|
||||
}
|
||||
|
||||
func NewDbfsClient(w *databricks.WorkspaceClient, root string) (Filer, error) {
|
||||
return &DbfsClient{
|
||||
workspaceClient: w,
|
||||
|
||||
root: NewRootPath(root),
|
||||
root: NewUnixRootPath(root),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -19,12 +19,13 @@ type LocalClient struct {
|
|||
|
||||
func NewLocalClient(root string) (Filer, error) {
|
||||
if runtime.GOOS == "windows" && root == "/" {
|
||||
// Windows paths require a Volume/Drive letter specified. This allows us
|
||||
// to create local filers at the root of a windows file system without specifying one
|
||||
return &LocalClient{root: NewRootPath("")}, nil
|
||||
// Windows file systems do not have a "root" directory. Instead paths require
|
||||
// a Volume/Drive letter specified. This allows us to refer to files across
|
||||
// different drives from a single client
|
||||
return &LocalClient{root: NopRootPath{}}, nil
|
||||
}
|
||||
return &LocalClient{
|
||||
root: NewRootPath(root),
|
||||
root: NewUnixRootPath(root),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -106,7 +107,7 @@ func (w *LocalClient) Delete(ctx context.Context, name string, mode ...DeleteMod
|
|||
}
|
||||
|
||||
// Illegal to delete the root path.
|
||||
if absPath == w.root.rootPath {
|
||||
if absPath == w.root.Root() {
|
||||
return CannotDeleteRootError{}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,17 +3,13 @@ package filer
|
|||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLocalClientAtRootForWindows(t *testing.T) {
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skip("this test is only meant for windows")
|
||||
}
|
||||
func TestLocalClientAtRootOfFilesystem(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
ctx := context.Background()
|
||||
|
||||
|
|
|
@ -1,34 +1,16 @@
|
|||
package filer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RootPath can be joined with a relative path and ensures that
|
||||
// the returned path is always a strict child of the root path.
|
||||
type RootPath struct {
|
||||
rootPath string
|
||||
type RootPath interface {
|
||||
Join(string) (string, error)
|
||||
Root() string
|
||||
}
|
||||
|
||||
// NewRootPath constructs and returns [RootPath].
|
||||
// The named path is cleaned on construction.
|
||||
func NewRootPath(name string) RootPath {
|
||||
return RootPath{
|
||||
rootPath: path.Clean(name),
|
||||
}
|
||||
type NopRootPath struct{}
|
||||
|
||||
func (rp NopRootPath) Join(name string) (string, error) {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// Join returns the specified path name joined to the root.
|
||||
// It returns an error if the resulting path is not a strict child of the root path.
|
||||
func (p *RootPath) Join(name string) (string, error) {
|
||||
absPath := path.Join(p.rootPath, name)
|
||||
|
||||
// Don't allow escaping the specified root using relative paths.
|
||||
if !strings.HasPrefix(absPath, p.rootPath) {
|
||||
return "", fmt.Errorf("relative path escapes root: %s", name)
|
||||
}
|
||||
|
||||
return absPath, nil
|
||||
func (rp NopRootPath) Root() string {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package filer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UnixRootPath can be joined with a relative path and ensures that
|
||||
// the returned path is always a strict child of the root path.
|
||||
type UnixRootPath struct {
|
||||
rootPath string
|
||||
}
|
||||
|
||||
// NewUnixRootPath constructs and returns [RootPath].
|
||||
// The named path is cleaned on construction.
|
||||
func NewUnixRootPath(name string) UnixRootPath {
|
||||
return UnixRootPath{
|
||||
rootPath: path.Clean(name),
|
||||
}
|
||||
}
|
||||
|
||||
// Join returns the specified path name joined to the root.
|
||||
// It returns an error if the resulting path is not a strict child of the root path.
|
||||
func (p UnixRootPath) Join(name string) (string, error) {
|
||||
absPath := path.Join(p.rootPath, name)
|
||||
|
||||
// Don't allow escaping the specified root using relative paths.
|
||||
if !strings.HasPrefix(absPath, p.rootPath) {
|
||||
return "", fmt.Errorf("relative path escapes root: %s", name)
|
||||
}
|
||||
|
||||
return absPath, nil
|
||||
}
|
||||
|
||||
func (p UnixRootPath) Root() string {
|
||||
return p.rootPath
|
||||
}
|
|
@ -7,9 +7,9 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testRootPath(t *testing.T, uncleanRoot string) {
|
||||
func testUnixRootPath(t *testing.T, uncleanRoot string) {
|
||||
cleanRoot := path.Clean(uncleanRoot)
|
||||
rp := NewRootPath(uncleanRoot)
|
||||
rp := NewUnixRootPath(uncleanRoot)
|
||||
|
||||
remotePath, err := rp.Join("a/b/c")
|
||||
assert.NoError(t, err)
|
||||
|
@ -79,12 +79,12 @@ func testRootPath(t *testing.T, uncleanRoot string) {
|
|||
assert.ErrorContains(t, err, `relative path escapes root: ../..`)
|
||||
}
|
||||
|
||||
func TestRootPathClean(t *testing.T) {
|
||||
testRootPath(t, "/some/root/path")
|
||||
func TestUnixRootPathClean(t *testing.T) {
|
||||
testUnixRootPath(t, "/some/root/path")
|
||||
}
|
||||
|
||||
func TestRootPathUnclean(t *testing.T) {
|
||||
testRootPath(t, "/some/root/path/")
|
||||
testRootPath(t, "/some/root/path/.")
|
||||
testRootPath(t, "/some/root/../path/")
|
||||
func TestUnixRootPathUnclean(t *testing.T) {
|
||||
testUnixRootPath(t, "/some/root/path/")
|
||||
testUnixRootPath(t, "/some/root/path/.")
|
||||
testUnixRootPath(t, "/some/root/../path/")
|
||||
}
|
|
@ -79,7 +79,7 @@ type WorkspaceFilesClient struct {
|
|||
apiClient *client.DatabricksClient
|
||||
|
||||
// File operations will be relative to this path.
|
||||
root RootPath
|
||||
root UnixRootPath
|
||||
}
|
||||
|
||||
func NewWorkspaceFilesClient(w *databricks.WorkspaceClient, root string) (Filer, error) {
|
||||
|
@ -92,7 +92,7 @@ func NewWorkspaceFilesClient(w *databricks.WorkspaceClient, root string) (Filer,
|
|||
workspaceClient: w,
|
||||
apiClient: apiClient,
|
||||
|
||||
root: NewRootPath(root),
|
||||
root: NewUnixRootPath(root),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue