• Icon: Improvement Improvement
    • Resolution: Fixed
    • Icon: Minor Minor
    • git-plugin
    • jenkins: 2.23 / Debian apt-get install
      git-plugin: 3.0.0
      git: 2.1.4
    • git plugin 4.7.1 and git client plugin 3.7.1 released 4 Apr 2021

      Please consider adding the means to confine the execution of a git command to a job's workspace directory.

      What I'm looking for is the behaviour implied by the GIT_CEILING_DIRECTORIES environment variable.

      https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables#_repository_locations

      GIT_CEILING_DIRECTORIES controls the behavior of searching for a .git directory. If you access directories that are slow to load (such as those on a tape drive, or across a slow network connection), you may want to have Git stop trying earlier than it might otherwise, especially if Git is invoked when building your shell prompt.

      https://git-scm.com/docs/git#Documentation/git.txt-codeGITCEILINGDIRECTORIEScode

      This should be a colon-separated list of absolute paths. If set, it is a list of directories that Git should not chdir up into while looking for a repository directory (useful for excluding slow-loading network directories). It will not exclude the current working directory or a GIT_DIR set on the command line or in the environment.

      In other words, a git command should never look for a .git directory outside of the job's workspace directory.

      Why?

      This would prevent any git command from clobbering any repositories further up the tree (case in point: Jenkins's $HOME) when a workspace's repo has somehow been messed up.

      "Messed up" includes, but is not limited to configuring the "Delete workspace before build starts" feature with some poorly understood exclude patterns that delete files but cause a complete directory structure - including the .git directory - to be left in the workspace.

      I've currently mitigated this problem by configuring GIT_CEILING_DIRECTORIES to ${HOME}/jobs in "Manage Jenkins / Configure System / Global properties / Environment variables", but I feel this would better be handled right out of the box.

      Steps to reproduce

      1. System:
        1. cd into the Jenkins home directory (e.g., /var/lib/jenkins);
        2. git init && git add . && git commit -m `initial commit` (don't bother for now that lot should normally be .gitignore-ed);
      2. UI:
        1. Create a project that checks out from a git repo;
        2. For completeness sake, I've got the "Advanced clone behaviours / Shallow clone / depth 0" enabled but I do not expect that to make a difference;
        3. Trigger a build at least once to create a non-empty workspace.
        4. Enable "Build Environment / Delete workspace before build starts" and configure an "exclude" pattern to simply: .git;
        5. Trigger build again;
      3. System:
        • Observe that your Jenkins home directory is now completely messed up;
        • Fortunately recoverably so: A git checkout master should fix it — at first glance at least; you'd probably have to remove a remote and related branches too!

      Fix:

      (after cleaning up)

      1. UI:
        1. Go to "Manage Jenkins / Configure System / Global properties / Environment variables"
        2. Add GIT_CEILING_DIRECTORIES with value ${HOME}/jobs
        3. Trigger build again

      A subsequent build's console log should now include something like this

      16:29:32.561  > git rev-parse --is-inside-work-tree # timeout=10
      16:29:32.573 ERROR: Workspace has a .git repository, but it appears to be corrupt.
      16:29:32.575 hudson.plugins.git.GitException: Command "git rev-parse --is-inside-work-tree" returned status code 128:
      16:29:32.575 stdout: 
      16:29:32.575 stderr: fatal: Not a git repository (or any of the parent directories): .git
      ...
      

          [JENKINS-38699] Confine git commands to workspace directory

          Mark R added a comment -

          Yes we set it to ${HOME}/jobs. I was wondering where workspace came from.

          Mark R added a comment - Yes we set it to ${HOME}/jobs. I was wondering where workspace came from.

          David Bouman added a comment -

          I've adjusted the issue description.

          David Bouman added a comment - I've adjusted the issue description.

          Raghav added a comment -

          I was trying to run the steps to reproduce after running the job successfully I found out that there were no changes in my directory

          Raghav added a comment - I was trying to run the steps to reproduce after running the job successfully I found out that there were no changes in my directory

          Harshit added a comment -

          Harshit added a comment - I have opened a PR for the issue: https://github.com/jenkinsci/git-client-plugin/pull/692

          David Bouman added a comment - - edited

          In reply to harshitchopra0712's comment: Brilliant! and... Finally! 

          David Bouman added a comment - - edited In reply to harshitchopra0712 's comment : Brilliant! and... Finally! 

          Mark Waite added a comment -

          I created a failing job definition in a folder of my test instance so that I can see the issue. My failure mode is different than the failure mode described, since it uses the "Clean workspace before checkout" option to damage the parent git repository.

          Mark Waite added a comment - I created a failing job definition in a folder of my test instance so that I can see the issue. My failure mode is different than the failure mode described, since it uses the "Clean workspace before checkout" option to damage the parent git repository.

          Mark Waite added a comment -

          The failing job needs to be inside a parent folder so that the damage is narrowed to only that folder. The failure mode still needs more assertions, but it is showing an alternating sequence of pass then fail, just as described in the bug report.

          Mark Waite added a comment - The failing job needs to be inside a parent folder so that the damage is narrowed to only that folder. The failure mode still needs more assertions, but it is showing an alternating sequence of pass then fail, just as described in the bug report.

          Harshit added a comment - - edited

          I tried to recreate the issue as you described markewaite , creating a parent folder with a failing job using "Clean workspace before checkout" option. I also tried using "Delete untracked nested repositories" option with nested repository. But I couldn't reproduce the issue, please let met know if am taking the right approach also are same build logs being generated as described in the issue above.

          Based on my understanding, the issue is caused when the .git directory is corrupted i.e empty or some file are not deleted, which  is caused by the Workspace Cleanup plugin, when specifying '.git' instead of '.git/' as the pattern for files to be excluded from being deleted and for directories as well, result of which the hasGitRepo() method traverses upwards searching for a valid .git directory. Thus causing the issue.

          Harshit added a comment - - edited I tried to recreate the issue as you described markewaite , creating a parent folder with a failing job using "Clean workspace before checkout" option. I also tried using "Delete untracked nested repositories" option with nested repository. But I couldn't reproduce the issue, please let met know if am taking the right approach also are same build logs being generated as described in the issue above. Based on my understanding, the issue is caused when the .git directory is corrupted i.e empty or some file are not deleted, which  is caused by the Workspace Cleanup plugin, when specifying '.git' instead of '.git/' as the pattern for files to be excluded from being deleted and for directories as well, result of which the hasGitRepo() method traverses upwards searching for a valid .git directory. Thus causing the issue.

          Mark Waite added a comment -

          harshitchopra0712 I'm glad that you're willing to try to duplicate the problem with my technique, but I don't think it is required.

          I believe you were able to duplicate the problem as originally described and that is sufficient. I wanted a test configuration that I could use to see the problem in my Docker image, without having to damage the Jenkins controller. The technique I'm using has done that. I needed it for my evaluation of the pull request, not for anything that you need to do.

          I am using the "Delete workspace before build starts" step in the Freestyle job with the ".git" exclusion and the setting to "Apply pattern also on directories". The linked job definitions include those settings.

          I believe your change is correct. I need to do more validation of the automated tests and I need to do more work on the configuration of the test in my Docker image. I think we may also need a compatibility change so that hasGitRepo() continues to behave as it did before and we have a new method hasGitRepo(false) that only looks in a single directory. Still evaluating that need and considering it for compatibility.

          Mark Waite added a comment - harshitchopra0712 I'm glad that you're willing to try to duplicate the problem with my technique, but I don't think it is required. I believe you were able to duplicate the problem as originally described and that is sufficient. I wanted a test configuration that I could use to see the problem in my Docker image, without having to damage the Jenkins controller. The technique I'm using has done that. I needed it for my evaluation of the pull request, not for anything that you need to do. I am using the "Delete workspace before build starts" step in the Freestyle job with the ".git" exclusion and the setting to "Apply pattern also on directories". The linked job definitions include those settings. I believe your change is correct. I need to do more validation of the automated tests and I need to do more work on the configuration of the test in my Docker image. I think we may also need a compatibility change so that hasGitRepo() continues to behave as it did before and we have a new method hasGitRepo(false) that only looks in a single directory. Still evaluating that need and considering it for compatibility.

          Mark Waite added a comment -

          New API is included in git client plugin 3.7.1. A new git plugin release will be needed in order to use the new API and resolve this issue.

          Mark Waite added a comment - New API is included in git client plugin 3.7.1. A new git plugin release will be needed in order to use the new API and resolve this issue.

            Unassigned Unassigned
            dsbouma David Bouman
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: