64

I have some git repositories accessed remotely through SSH and I want to make some of them read-only to prevent more pushes. Some people have remotes pointing to these repositories.

These bare repositories were initialised --shared=group, so is setting file permissions to 660 for all files good enough to still allow SSH access, but disallow writes? Or is there an easier way?

Cheers.

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
Steve Folly
  • 8,327
  • 9
  • 52
  • 63

10 Answers10

54

There is more than one possible way to do this.

  • If your users each have a shell account (perhaps limited), and each of them accessing git repositories via their own account, you can use filesystem permissions to control SSH access to git repositories. On Unix those would be write permissions on directories, perhaps with the help of creating a group and specific permissions for a group (with "sticky group ID" set).

  • Pushing requires git-receive-pack to be in $PATH of user, and be executable for them... although I am not sure how feasible this approach would be.

  • You can use update or pre-receive hook to do access control to repository, for example using update-paranoid example hook from contrib/hooks in git sources.

  • With larger number of users you could be better with using a tool to manage access to git repositories, like Gitosis (in Python, requires setuptools) or Gitolite (in Perl).

  • For read only access you can setup git daemon to provide read-only anonymous (and unauthenticated) access via git:// protocol, instead of access via SSH protocol.

    See documentation for url.<base>.insteadOf config variable for a way to ease the transition from SSH to GIT protocol.


See also Chapter 4. "Git on the Server" of Pro Git book by Scott Chacon (CC-BY-NC-SA licensed).

Community
  • 1
  • 1
Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230
  • 2
    Should note that for filesystem permissions, you can use chmod, as suggested by Pat Notz. – Emil Sit Nov 04 '09 at 16:13
  • 10
    Thanks for the ideas (everyone). Inspired by the update-paranoid example hook, I now have a hook in my repos which simply does `echo "Closed for all pushes" ; exit 1` – Steve Folly Nov 12 '09 at 21:30
  • 2
    @SteveFolly If your comment was an answer, I would vote for it instead of the accepted answer. Yours is short, to the point, and works. – Klas Mellbourn Apr 28 '15 at 06:56
  • @KlasMellbourn I added a proper answer based on Steves comment. – Per Lundberg Nov 06 '18 at 07:05
  • Is this possible to do with GitHub Enterprise without access to configuring the entire instance meaning an org/repo owner could do it? It seems like the admins of the actual server would need to help you out per this document: https://help.github.com/en/enterprise/2.18/admin/developer-workflow/creating-a-pre-receive-hook-script – kayleeFrye_onDeck Nov 25 '19 at 23:40
16

A pre-receive hook that simply prints an informative message and exits with a non zero status does the job.

Assuming you put some meaningful information in your message, it also cuts down on the queries from frustrated users asking why they can't push:

#!/bin/bash
echo "=================================================="
echo "This repository is no longer available for pushes."
echo "Please visit blah blah yadda yadda ...."
echo "=================================================="
exit 1

Remember to set the executable permission for the script and to make sure is owned by the right user and/or group, or else it will not execute and will not give any warning.

Xavier Rubio Jansana
  • 6,388
  • 1
  • 27
  • 50
Dale C. Anderson
  • 2,280
  • 1
  • 24
  • 24
8
chmod -R a-w /path/to/repo.git
Pat Notz
  • 208,672
  • 30
  • 90
  • 92
3

Since git relies primarily on the filesystem for access control, that will work. Note that in your permissions, the world has no access to the file, but the user and group have read/write access. If you want world-readable, your permissions should be 0444.

You could do further fine-grained control by setting the repo permissions as 0664 where the user is nobody and the group is something like gitdevs. Then, only people in the gitdevs group will have the ability to write to the repo, but the world can read from it.

Follow-up Here is a link that covers various ways to share your repo and covers come pro's & cons and access control features.

jheddings
  • 26,717
  • 8
  • 52
  • 65
  • 666 is world readable and writable files. 776 is world and group readable, writable and executable and other users read and write. Not sure where you got the numbers you're recommending, but they're generally dangerous. – Dustin Nov 02 '09 at 22:50
  • Thanks, corrected my answer. Too much typing, not enough thinking. – jheddings Nov 02 '09 at 22:58
3

Inspired by this comment:

  1. Update your hooks/pre-receive file with the following content:

    #!/bin/sh
    
    echo "Closed for all pushes" ; exit 1
    

This way, all users trying to push changes to this repo will receive the message above and the push will be rejected.

Per Lundberg
  • 3,837
  • 1
  • 36
  • 46
  • 1
    Thanks. This worked for me. By the way, it's worth mentioning that the hooks directory lives under the repository root filesystem path. – hmacias Mar 01 '19 at 16:50
1

If you need access control as well, check out gitosis. Pretty easy to set-up and you can use a simple script to control who can do what.

Makis
  • 12,468
  • 10
  • 62
  • 71
0

Another possibility is the git protocol, but it requires the git daemon to be running.

Ikke
  • 99,403
  • 23
  • 97
  • 120
0

Recently I used limiting access to path "/repo.git/git-receive-pack" to achive result that the repository is read-write for some users and read-only for some others. In httpd config it looks like this:

    <Location /repo.git/>
            Require group developers developers-ro
    </Location>

    <Location /repo.git/git-receive-pack>
            Require group developers
    </Location>
keypress
  • 759
  • 9
  • 12
0

As I am just a user of our GitLab (and I didn't wanted to bother the admins in the first step), I searched for another way and found one:

  • Open the GitLab webinterface and go to the repository you want to set to read-only
  • Choose Settings > Repository
  • Expand Protected Branches
  • Add the master branch and set Allowed to merge and Allowed to push to No one
  • If the master branch is protected already, you can set these values in the list below
Nicolas
  • 754
  • 8
  • 22
0

FWIW, if you're trying to make a Github repo read-only, you can archive it: https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/archiving-a-github-repository/about-archiving-repositories

Steve K
  • 2,044
  • 3
  • 24
  • 37