From 54709d9efd4624745ed0f67029ca30ee2ca87bc9 Mon Sep 17 00:00:00 2001 From: Dylan Katz Date: Mon, 21 Aug 2017 11:14:37 -0600 Subject: Fix leaking environment variables --- git/repo/base.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 28bb2a5d..1dfe9184 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -9,6 +9,7 @@ import logging import os import re import sys +import warnings from git.cmd import ( Git, @@ -50,8 +51,11 @@ BlameEntry = namedtuple('BlameEntry', ['commit', 'linenos', 'orig_path', 'orig_l __all__ = ('Repo',) -def _expand_path(p): - return osp.normpath(osp.abspath(osp.expandvars(osp.expanduser(p)))) +def _expand_path(p, unsafe=True): + if unsafe: + return osp.normpath(osp.abspath(osp.expandvars(osp.expanduser(p)))) + else: + return osp.normpath(osp.abspath(osp.expanduser(p))) class Repo(object): @@ -90,7 +94,7 @@ class Repo(object): # Subclasses may easily bring in their own custom types by placing a constructor or type here GitCommandWrapperType = Git - def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=False): + def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=False, unsafe=True): """Create a new Repo instance :param path: @@ -121,7 +125,10 @@ class Repo(object): epath = os.getcwd() if Git.is_cygwin(): epath = decygpath(epath) - epath = _expand_path(epath or path or os.getcwd()) + if unsafe and ("%" in epath or "$" in epath): + warnings.warn("The use of environment variables in paths is deprecated" + + "\nfor security reasons and may be removed in the future!!") + epath = _expand_path(epath or path or os.getcwd(), unsafe) if not os.path.exists(epath): raise NoSuchPathError(epath) @@ -148,7 +155,7 @@ class Repo(object): sm_gitpath = find_worktree_git_dir(dotgit) if sm_gitpath is not None: - self.git_dir = _expand_path(sm_gitpath) + self.git_dir = _expand_path(sm_gitpath, unsafe) self._working_tree_dir = curpath break @@ -862,12 +869,17 @@ class Repo(object): the directory containing the database objects, i.e. .git/objects. It will be used to access all object data + :param unsafe: + if specified, environment variables will not be escaped. This + can lead to information disclosure, allowing attackers to + access the contents of environment variables + :parm kwargs: keyword arguments serving as additional options to the git-init command :return: ``git.Repo`` (the newly created repo)""" if path: - path = _expand_path(path) + path = _expand_path(path, unsafe) if mkdir and path and not osp.exists(path): os.makedirs(path, 0o755) -- cgit v1.2.1 From d1c40f46bd547be663b4cd97a80704279708ea8a Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Thu, 3 Aug 2017 17:33:07 -0400 Subject: worktrees: make non-packed refs also work correctly. Turns out aec58a9 did the right thing for /packed/ refs, but didn't work correctly on /unpacked/ refs. So this patch gives unpacked refs the same treatment. Without the fix here, the test added will cause this traceback: ====================================================================== ERROR: Check that we find .git as a worktree file and find the worktree ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/pjones/devel/github.com/GitPython/git/test/lib/helper.py", line 92, in wrapper return func(self, path) File "/home/pjones/devel/github.com/GitPython/git/test/test_repo.py", line 938, in test_git_work_tree_dotgit self.assertIsInstance(repo.heads['aaaaaaaa'], Head) File "/home/pjones/devel/github.com/GitPython/git/util.py", line 893, in __getitem__ raise IndexError("No item found with id %r" % (self._prefix + index)) IndexError: No item found with id 'aaaaaaaa' Woops. Things I've learned: - test_remote doesn't work currently if you start on a branch. I think it never did? - Because of 346424da, all *sorts* of stuff in the test suite doesn't work if you name your development branch "packed-refs" (This seems like a bug...) Signed-off-by: Peter Jones --- git/repo/base.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 28bb2a5d..d607deee 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -74,6 +74,7 @@ class Repo(object): working_dir = None _working_tree_dir = None git_dir = None + _common_dir = None # precompiled regex re_whitespace = re.compile(r'\s+') @@ -169,17 +170,23 @@ class Repo(object): # lets not assume the option exists, although it should pass + try: + common_dir = open(osp.join(self.git_dir, 'commondir'), 'rt').readlines()[0].strip() + self._common_dir = osp.join(self.git_dir, common_dir) + except (OSError, IOError): + self._common_dir = None + # adjust the wd in case we are actually bare - we didn't know that # in the first place if self._bare: self._working_tree_dir = None # END working dir handling - self.working_dir = self._working_tree_dir or self.git_dir + self.working_dir = self._working_tree_dir or self.common_dir self.git = self.GitCommandWrapperType(self.working_dir) # special handling, in special times - args = [osp.join(self.git_dir, 'objects')] + args = [osp.join(self.common_dir, 'objects')] if issubclass(odbt, GitCmdObjectDB): args.append(self.git) self.odb = odbt(*args) @@ -236,6 +243,13 @@ class Repo(object): """ return self._working_tree_dir + @property + def common_dir(self): + """:return: The git dir that holds everything except possibly HEAD, + FETCH_HEAD, ORIG_HEAD, COMMIT_EDITMSG, index, and logs/ . + """ + return self._common_dir or self.git_dir + @property def bare(self): """:return: True if the repository is bare""" @@ -574,7 +588,7 @@ class Repo(object): :note: The method does not check for the existence of the paths in alts as the caller is responsible.""" - alternates_path = osp.join(self.git_dir, 'objects', 'info', 'alternates') + alternates_path = osp.join(self.common_dir, 'objects', 'info', 'alternates') if not alts: if osp.isfile(alternates_path): os.remove(alternates_path) @@ -932,7 +946,7 @@ class Repo(object): * All remaining keyword arguments are given to the git-clone command :return: ``git.Repo`` (the newly cloned repo)""" - return self._clone(self.git, self.git_dir, path, type(self.odb), progress, **kwargs) + return self._clone(self.git, self.common_dir, path, type(self.odb), progress, **kwargs) @classmethod def clone_from(cls, url, to_path, progress=None, env=None, **kwargs): -- cgit v1.2.1 From 67291f0ab9b8aa24f7eb6032091c29106de818ab Mon Sep 17 00:00:00 2001 From: Dylan Katz Date: Mon, 21 Aug 2017 12:09:37 -0600 Subject: Fixed missing parameter and changed name --- git/repo/base.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 1dfe9184..d575466d 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -51,11 +51,11 @@ BlameEntry = namedtuple('BlameEntry', ['commit', 'linenos', 'orig_path', 'orig_l __all__ = ('Repo',) -def _expand_path(p, unsafe=True): - if unsafe: - return osp.normpath(osp.abspath(osp.expandvars(osp.expanduser(p)))) - else: - return osp.normpath(osp.abspath(osp.expanduser(p))) +def _expand_path(p, expand_vars=True): + p = osp.expanduser(p) + if expand_vars: + p = osp.expandvars(p) + return osp.normpath(osp.abspath(p)) class Repo(object): @@ -94,7 +94,7 @@ class Repo(object): # Subclasses may easily bring in their own custom types by placing a constructor or type here GitCommandWrapperType = Git - def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=False, unsafe=True): + def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=False, expand_vars=True): """Create a new Repo instance :param path: @@ -120,15 +120,17 @@ class Repo(object): :raise InvalidGitRepositoryError: :raise NoSuchPathError: :return: git.Repo """ + epath = path or os.getenv('GIT_DIR') if not epath: epath = os.getcwd() if Git.is_cygwin(): epath = decygpath(epath) - if unsafe and ("%" in epath or "$" in epath): - warnings.warn("The use of environment variables in paths is deprecated" - + "\nfor security reasons and may be removed in the future!!") - epath = _expand_path(epath or path or os.getcwd(), unsafe) + epath = epath or path or os.getcwd() + if expand_vars and ("%" in epath or "$" in epath): + warnings.warn("The use of environment variables in paths is deprecated" + + "\nfor security reasons and may be removed in the future!!") + epath = _expand_path(epath, expand_vars) if not os.path.exists(epath): raise NoSuchPathError(epath) @@ -155,7 +157,7 @@ class Repo(object): sm_gitpath = find_worktree_git_dir(dotgit) if sm_gitpath is not None: - self.git_dir = _expand_path(sm_gitpath, unsafe) + self.git_dir = _expand_path(sm_gitpath, expand_vars) self._working_tree_dir = curpath break @@ -851,7 +853,7 @@ class Repo(object): return blames @classmethod - def init(cls, path=None, mkdir=True, odbt=DefaultDBType, **kwargs): + def init(cls, path=None, mkdir=True, odbt=DefaultDBType, expand_vars=True, **kwargs): """Initialize a git repository at the given path if specified :param path: @@ -869,7 +871,7 @@ class Repo(object): the directory containing the database objects, i.e. .git/objects. It will be used to access all object data - :param unsafe: + :param expand_vars: if specified, environment variables will not be escaped. This can lead to information disclosure, allowing attackers to access the contents of environment variables @@ -879,7 +881,7 @@ class Repo(object): :return: ``git.Repo`` (the newly created repo)""" if path: - path = _expand_path(path, unsafe) + path = _expand_path(path, expand_vars) if mkdir and path and not osp.exists(path): os.makedirs(path, 0o755) -- cgit v1.2.1 From a2d678792d3154d5de04a5225079f2e0457b45b7 Mon Sep 17 00:00:00 2001 From: Alexis Horgix Chotard Date: Fri, 25 Aug 2017 11:51:22 +0200 Subject: util: move expand_path from repo/base and use it in Git class init --- git/repo/base.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'git/repo/base.py') diff --git a/git/repo/base.py b/git/repo/base.py index 28bb2a5d..74d56ee5 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -29,7 +29,7 @@ from git.index import IndexFile from git.objects import Submodule, RootModule, Commit from git.refs import HEAD, Head, Reference, TagReference from git.remote import Remote, add_progress, to_progress_instance -from git.util import Actor, finalize_process, decygpath, hex_to_bin +from git.util import Actor, finalize_process, decygpath, hex_to_bin, expand_path import os.path as osp from .fun import rev_parse, is_git_dir, find_submodule_git_dir, touch, find_worktree_git_dir @@ -50,10 +50,6 @@ BlameEntry = namedtuple('BlameEntry', ['commit', 'linenos', 'orig_path', 'orig_l __all__ = ('Repo',) -def _expand_path(p): - return osp.normpath(osp.abspath(osp.expandvars(osp.expanduser(p)))) - - class Repo(object): """Represents a git repository and allows you to query references, gather commit information, generate diffs, create and clone repositories query @@ -121,7 +117,7 @@ class Repo(object): epath = os.getcwd() if Git.is_cygwin(): epath = decygpath(epath) - epath = _expand_path(epath or path or os.getcwd()) + epath = expand_path(epath or path or os.getcwd()) if not os.path.exists(epath): raise NoSuchPathError(epath) @@ -148,7 +144,7 @@ class Repo(object): sm_gitpath = find_worktree_git_dir(dotgit) if sm_gitpath is not None: - self.git_dir = _expand_path(sm_gitpath) + self.git_dir = expand_path(sm_gitpath) self._working_tree_dir = curpath break @@ -867,7 +863,7 @@ class Repo(object): :return: ``git.Repo`` (the newly created repo)""" if path: - path = _expand_path(path) + path = expand_path(path) if mkdir and path and not osp.exists(path): os.makedirs(path, 0o755) -- cgit v1.2.1