diff --git a/dvc/exceptions.py b/dvc/exceptions.py index e5fb6f00d..1ced27032 100644 --- a/dvc/exceptions.py +++ b/dvc/exceptions.py @@ -268,6 +268,15 @@ class FileMissingError(DvcException): ) +class NoAbsolutePathError(DvcException): + def __init__(self, path, cause=None): + super(NoAbsolutePathError, self).__init__( + "The path '{}' is an absolute path. ".format(path) + + "Provide a relative path.", + cause=cause, + ) + + class DvcIgnoreInCollectedDirError(DvcException): def __init__(self, ignore_dirname): super(DvcIgnoreInCollectedDirError, self).__init__( diff --git a/dvc/repo/get.py b/dvc/repo/get.py index ee4765678..bb2482302 100644 --- a/dvc/repo/get.py +++ b/dvc/repo/get.py @@ -8,6 +8,7 @@ from dvc.exceptions import GetDVCFileError from dvc.exceptions import NotDvcRepoError from dvc.exceptions import OutputNotFoundError from dvc.exceptions import UrlNotDvcRepoError +from dvc.exceptions import NoAbsolutePathError from dvc.external_repo import external_repo from dvc.path_info import PathInfo from dvc.stage import Stage @@ -20,6 +21,9 @@ logger = logging.getLogger(__name__) @staticmethod def get(url, path, out=None, rev=None): + if os.path.isabs(path): + raise NoAbsolutePathError(path) + out = resolve_output(path, out) if Stage.is_valid_filename(out): diff --git a/tests/func/test_get.py b/tests/func/test_get.py index f8143fc34..ce0a7ab42 100644 --- a/tests/func/test_get.py +++ b/tests/func/test_get.py @@ -9,6 +9,7 @@ import pytest from dvc.config import Config from dvc.exceptions import GetDVCFileError from dvc.exceptions import UrlNotDvcRepoError +from dvc.exceptions import NoAbsolutePathError from dvc.repo import Repo from dvc.system import System from dvc.utils import makedirs @@ -106,6 +107,13 @@ def test_get_a_dvc_file(erepo): Repo.get(erepo.root_dir, "some_file.dvc") +# Prevent `Repo.get()` from copying any file on the filesystem +# https://github.com/iterative/dvc/pull/2837#discussion_r352123053 +def test_fails_with_absolute_paths(erepo): + with pytest.raises(NoAbsolutePathError): + Repo.get(erepo.root_dir, "/root/") + + @pytest.mark.parametrize("dname", [".", "dir", "dir/subdir"]) def test_get_to_dir(dname, erepo): src = erepo.FOO