diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 09:55:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 09:55:51 +0000 |
commit | 7685305e1f82212323ec32a321b1f5c623751b6c (patch) | |
tree | a1af617672e26aee4c1031a3aa83e8ff08f6a0a5 /contrib/t | |
parent | Initial commit. (diff) | |
download | gitolite3-7685305e1f82212323ec32a321b1f5c623751b6c.tar.xz gitolite3-7685305e1f82212323ec32a321b1f5c623751b6c.zip |
Adding upstream version 3.6.12.upstream/3.6.12upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | contrib/t/ukm.t | 447 | ||||
-rwxr-xr-x | contrib/triggers/IP-check | 43 | ||||
-rwxr-xr-x | contrib/triggers/file_mirror | 172 |
3 files changed, 662 insertions, 0 deletions
diff --git a/contrib/t/ukm.t b/contrib/t/ukm.t new file mode 100644 index 0000000..da4fc0b --- /dev/null +++ b/contrib/t/ukm.t @@ -0,0 +1,447 @@ +#!/usr/bin/perl + +# Call like this: +# TSH_VERBOSE=1 TSH_ERREXIT=1 HARNESS_ACTIVE=1 GITOLITE_TEST=y prove t/ukm.t + +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Common; +use Gitolite::Test; + +# basic tests using ssh +# ---------------------------------------------------------------------- + +my $bd = `gitolite query-rc -n GL_BINDIR`; +my $h = $ENV{HOME}; +my $ab = `gitolite query-rc -n GL_ADMIN_BASE`; +my $pd = "$bd/../t/keys"; # source for pubkeys +umask 0077; + +_mkdir( "$h/.ssh", 0700 ) if not -d "$h/.ssh"; + +try "plan 204"; + + +# Reset everything. +# Only admin and u1, u2, and u3 keys are available initially +# Keys u4, u5, and u6 are used as guests later. +# For easy access, we put the keys into ~/.ssh/, though. +try " + rm -f $h/.ssh/authorized_keys; ok or die 1 + cp $pd/u[1-6]* $h/.ssh; ok or die 2 + cp $pd/admin* $h/.ssh; ok or die 3 + cp $pd/config $h/.ssh; ok or die 4 + cat $h/.ssh/config + perl s/%USER/$ENV{USER}/ + put $h/.ssh/config + mkdir $ab/keydir; ok or die 5 + cp $pd/u[1-3].pub $ab/keydir; ok or die 6 + cp $pd/admin.pub $ab/keydir; ok or die 7 +"; + +# Put the keys into ~/.ssh/authorized_keys +system("gitolite ../triggers/post-compile/ssh-authkeys"); + +# enable user key management in a simple form. +# Guest key managers can add keyids looking like email addresses, but +# cannot add emails containing example.com or hemmecke.org. +system("sed -i \"s/.*ENABLE =>.*/'UKM_CONFIG'=>{'FORBIDDEN_GUEST_PATTERN'=>'example.com|hemmecke.org'}, ENABLE => ['ukm',/\" $h/.gitolite.rc"); + +# super-key-managers can add/del any key +# super-key-managers should in fact agree with people having write +# access to gitolite-admin repo. +# guest-key-managers can add/del guest keys +confreset; confadd ' + @guest-key-managers = u2 u3 + @creators = u2 u3 + repo pub/CREATOR/..* + C = @creators + RW+ = CREATOR + RW = WRITERS + R = READERS +'; + +# Populate the gitolite-admin/keydir in the same way as it was used for +# the initialization of .ssh/authorized_keys above. +try " + mkdir keydir; ok or die 8 + cp $pd/u[1-3].pub keydir; ok or die 9; + cp $pd/admin.pub keydir; ok or die 10; + git add conf keydir; ok + git commit -m ukm; ok; /master.* ukm/ +"; + +# Activate new config data. +try "PUSH admin; ok; gsh; /master -> master/; !/FATAL/" or die text(); + +# Check whether the above setup yields the expected behavior for ukm. +# The admin is super-key-manager, thus can manage every key. +try " + ssh admin ukm; ok; /Hello admin, you manage the following keys:/ + / admin +admin/ + / u1 +u1/ + / u2 +u2/ + / u3 +u3/ +"; + +# u1 isn't a key manager, so shouldn't be above to manage keys. +try "ssh u1 ukm; !ok; /FATAL: You are not a key manager./"; + +# u2 and u3 are guest key managers, but don't yet manage any key. +try "ssh u2 ukm; ok"; cmp "Hello u2, you manage the following keys:\n\n\n"; +try "ssh u3 ukm; ok"; cmp "Hello u3, you manage the following keys:\n\n\n"; + + +################################################################### +# Unknows subkommands abort ukm. +try "ssh u2 ukm fake; !ok; /FATAL: unknown ukm subcommand: fake/"; + + +################################################################### +# Addition of keys. + +# If no data is provided on stdin, we don't block, but rather timeout +# after one second and abort the program. +try "ssh u2 ukm add u4\@example.org; !ok; /FATAL: missing public key data/"; + +# If no keyid is given, we cannot add a key. +try "ssh u2 ukm add; !ok; /FATAL: keyid required/"; + +try " + DEF ADD = cat $pd/%1.pub|ssh %2 ukm add %3 + DEF ADDOK = ADD %1 %2 %3; ok + DEF ADDNOK = ADD %1 %2 %3; !ok + DEF FP = ADDNOK u4 u2 %1 + DEF FORBIDDEN_PATTERN = FP %1; /FATAL: keyid not allowed:/ +"; + +# Neither a guest key manager nor a super key manager can add keys that have +# double dot in their keyid. This is hardcoded to forbid paths with .. in it. +try " + ADDNOK u4 u2 u4\@hemmecke..org; /Not allowed to use '..' in keyid./ + ADDNOK u4 admin u4\@hemmecke..org; /Not allowed to use '..' in keyid./ + ADDNOK u4 admin ./../.myshrc; /Not allowed to use '..' in keyid./ +"; + +# guest-key-managers can only add keys that look like emails. +try " + FORBIDDEN_PATTERN u4 + FORBIDDEN_PATTERN u4\@example + FORBIDDEN_PATTERN u4\@foo\@example.org + + # No support for 'old style' multiple keys. + FORBIDDEN_PATTERN u4\@example.org\@foo + + # No path delimiter in keyid + FORBIDDEN_PATTERN foo/u4\@example.org + + # Certain specific domains listed in FORBIDDEN_GUEST_PATTERN are forbidden. + # Note that also u4\@example-com would be rejected, because MYDOMAIN + # contains a regular expression --> I don't care. + FORBIDDEN_PATTERN u4\@example.com + FORBIDDEN_PATTERN u4\@hemmecke.org +"; + +# Accept one guest key. +try "ADDOK u4 u2 u4\@example.org"; +try "ssh u2 ukm; ok; /Hello u2, you manage the following keys:/ + / u4\@example.org *u4\@example.org/"; + +# Various ways how a key must be rejected. +try " + # Cannot add the same key again. + ADDNOK u4 u2 u4\@example.org; /FATAL: cannot override existing key/ + + # u2 can also not add u4.pub under another keyid + ADDNOK u4 u2 u4\@example.net; /FATAL: cannot add key/ + /Same key is already available under another userid./ + + # u2 can also not add another key under the same keyid. + ADDNOK u5 u2 u4\@example.org; /FATAL: cannot override existing key/ + + # Also u3 cannot not add another key under the same keyid. + ADDNOK u5 u3 u4\@example.org + /FATAL: cannot add another public key for an existing user/ + + # And u3 cannot not add u4.pub under another keyid. + ADDNOK u4 u3 u4\@example.net; /FATAL: cannot add key/ + /Same key is already available under another userid./ + + # Not even the admin can add the same key u4 under a different userid. + ADDNOK u4 admin u4\@example.net; /FATAL: cannot add key/ + /Same key is already available under another userid./ + /Found .* u4\@example.org/ + + # Super key managers cannot add keys that start with @. + # We don't care about @ in the dirname, though. + ADDNOK u4 admin foo/\@ex.net; /FATAL: cannot add key that starts with \@/ + ADDNOK u4 admin foo/\@ex; /FATAL: cannot add key that starts with \@/ + ADDNOK u4 admin \@ex.net; /FATAL: cannot add key that starts with \@/ + ADDNOK u4 admin \@ex; /FATAL: cannot add key that starts with \@/ +"; + +# But u3 can add u4.pub under the same keyid. +try "ADDOK u4 u3 u4\@example.org"; + +try "ssh u3 ukm; ok; /Hello u3, you manage the following keys:/ + / u4\@example.org *u4\@example.org/"; + +# The admin can add multiple keys for the same userid. +try " + ADDOK u5 admin u4\@example.org + ADDOK u5 admin u4\@example.org\@home + ADDOK u5 admin laptop/u4\@example.org + ADDOK u5 admin laptop/u4\@example.org\@home +"; + +# And admin can also do this for other guest key managers. Note, +# however, that the gitolite-admin must be told where the +# GUEST_DIRECTORY is. But he/she could find out by cloning the +# gitolite-admin repository and adding the same key directly. +try " + ADDOK u5 admin zzz/guests/u2/u4\@example.org\@foo + ADDOK u6 admin zzz/guests/u3/u6\@example.org +"; + +try "ssh admin ukm; ok"; cmp "Hello admin, you manage the following keys: +fingerprint userid keyid +a4:d1:11:1d:25:5c:55:9b:5f:91:37:0e:44:a5:a5:f2 admin admin +00:2c:1f:dd:a3:76:5a:1e:c4:3c:01:15:65:19:a5:2e u1 u1 +69:6f:b5:8a:f5:7b:d8:40:ce:94:09:a2:b8:95:79:5b u2 u2 +26:4b:20:24:98:a4:e4:a5:b9:97:76:9a:15:92:27:2d u3 u3 +78:cf:7e:2b:bf:18:58:54:23:cc:4b:3d:7e:f4:63:79 u4\@example.org laptop/u4\@example.org +78:cf:7e:2b:bf:18:58:54:23:cc:4b:3d:7e:f4:63:79 u4\@example.org laptop/u4\@example.org\@home +78:cf:7e:2b:bf:18:58:54:23:cc:4b:3d:7e:f4:63:79 u4\@example.org u4\@example.org +78:cf:7e:2b:bf:18:58:54:23:cc:4b:3d:7e:f4:63:79 u4\@example.org u4\@example.org\@home +8c:a6:c0:a5:71:85:0b:89:d3:08:97:22:ae:95:e1:bb u4\@example.org zzz/guests/u2/u4\@example.org +78:cf:7e:2b:bf:18:58:54:23:cc:4b:3d:7e:f4:63:79 u4\@example.org zzz/guests/u2/u4\@example.org\@foo +8c:a6:c0:a5:71:85:0b:89:d3:08:97:22:ae:95:e1:bb u4\@example.org zzz/guests/u3/u4\@example.org +fc:0f:eb:52:7a:d2:35:da:89:96:f5:15:0e:85:46:e7 u6\@example.org zzz/guests/u3/u6\@example.org +\n\n"; + +# Now, u2 has two keys in his directory, but u2 can manage only one of +# them, since the one added by the admin has two @ in it. Thus the key +# added by admin is invisible to u2. +try "ssh u2 ukm; ok"; cmp "Hello u2, you manage the following keys: +fingerprint userid keyid +8c:a6:c0:a5:71:85:0b:89:d3:08:97:22:ae:95:e1:bb u4\@example.org u4\@example.org +\n\n"; + +# Since admin added key u6@example.org to the directory of u2, u2 is +# also able to see it and, in fact, to manage it. +try "ssh u3 ukm; ok"; cmp "Hello u3, you manage the following keys: +fingerprint userid keyid +8c:a6:c0:a5:71:85:0b:89:d3:08:97:22:ae:95:e1:bb u4\@example.org u4\@example.org +fc:0f:eb:52:7a:d2:35:da:89:96:f5:15:0e:85:46:e7 u6\@example.org u6\@example.org +\n\n"; + +################################################################### +# Deletion of keys. +try " + DEF DEL = ssh %1 ukm del %2 + DEF DELOK = DEL %1 %2; ok + DEF DELNOK = DEL %1 %2; !ok + DEF DELNOMGR = DELNOK %1 %2; /FATAL: You are not managing the key / +"; + +# Deletion requires a keyid. +try "ssh u3 ukm del; !ok; /FATAL: keyid required/"; + +# u3 can, of course, not remove any unmanaged key. +try "DELNOMGR u3 u2"; + +# But u3 can delete u4@example.org and u6@example.org. This will, of course, +# not remove the key u4@example.org that u2 manages. +try " + DELOK u3 u4\@example.org + DELOK u3 u6\@example.org +"; + +# After having deleted u4@example.org, u3 cannot remove it again, +# even though, u2 still manages that key. +try "DELNOMGR u3 u4\@example.org"; + +# Of course a super-key-manager can remove any (existing) key. +try " + DELOK admin zzz/guests/u2/u4\@example.org + DELNOK admin zzz/guests/u2/u4\@example.org + /FATAL: You are not managing the key zzz/guests/u2/u4\@example.org./ + DELNOK admin zzz/guests/u2/u4\@example.org\@x + /FATAL: You are not managing the key zzz/guests/u2/u4\@example.org./ + DELOK admin zzz/guests/u2/u4\@example.org\@foo +"; + +# As the admin could do that via pushing to the gitolite-admin manually, +# it's also allowed to delete even non-guest keys. +try "DELOK admin u3"; + +# Let's clean the environment again. +try " + DELOK admin laptop/u4\@example.org\@home + DELOK admin laptop/u4\@example.org + DELOK admin u4\@example.org\@home + DELOK admin u4\@example.org + ADDOK u3 admin u3 + "; + +# Currently the admin has just one key. It cannot be removed. +# But after adding another key, deletion should work fine. +try " + DELNOK admin admin; /FATAL: You cannot delete your last key./ + ADDOK u6 admin second/admin; /Adding new public key for admin./ + DELOK admin admin + DELNOK u6 admin; /FATAL: You are not managing the key admin./ + DELNOK u6 second/admin; /FATAL: You cannot delete your last key./ + ADDOK admin u6 admin; /Adding new public key for admin./ + DELOK u6 second/admin +"; + +################################################################### +# Selfkey management. + +# If self key management is not switched on in the .gitolite.rc file, +# it's not allowed at all. +try "ssh u2 ukm add \@second; !ok; /FATAL: selfkey management is not enabled/"; + +# Let's enable it. +system("sed -i \"/'UKM_CONFIG'=>/s/=>{/=>{'SELFKEY_MANAGEMENT'=>1,/\" $h/.gitolite.rc"); + +# And add self-key-managers to gitolite.conf +# chdir("../gitolite-admin") or die "in `pwd`, could not cd ../g-a"; +try "glt pull admin origin master; ok"; +put "|cut -c5- > conf/gitolite.conf", ' + repo gitolite-admin + RW+ = admin + repo testing + RW+ = @all + @guest-key-managers = u2 u3 + @self-key-managers = u1 u2 + @creators = u2 u3 + repo pub/CREATOR/..* + C = @creators + RW+ = CREATOR + RW = WRITERS + R = READERS +'; +try " + git add conf keydir; ok + git commit -m selfkey; ok; /master.* selfkey/ +"; +try "PUSH admin; ok; gsh; /master -> master/; !/FATAL/" or die text(); + +# Now we can start with the tests. + +# Only self key managers are allowed to use selfkey management. +# See variable @self-key-managers. +try "ssh u3 ukm add \@second; !ok; /FATAL: You are not a selfkey manager./"; + +# Cannot add keyid that are not alphanumeric. +try "ssh u1 ukm add \@second-key; !ok; /FATAL: keyid not allowed:/"; + +# Add a second key for u1, but leave it pending by not feeding in the +# session key. The new user can login, but he/she lives under a quite +# random gl_user name and thus is pretty much excluded from everything +# except permissions given to @all. If this new id calls ukm without +# providing the session key, this (pending) key is automatically +# removed from the system. +# If a certain keyid is in the system, then it cannot be added again. +try " + ADDOK u4 u1 \@second + ssh admin ukm; ok; /u1 zzz/self/u1/zzz-add-[a-z0-9]{32}-second-u1/ + ssh u1 ukm; ok; /u1 \@second .pending add./ + ADDNOK u4 u1 \@second; /FATAL: keyid already in use: \@second/ + ssh u4 ukm; ok; /pending keyid deleted: \@second/ + ssh admin ukm; ok; !/zzz/; !/second/ +"; + +# Not providing a proper ssh public key will abort. Providing a good +# ssh public key, which is not a session key makes the key invalid. +# The key will, therefore, be deleted by this operation. +try " + ADDOK u4 u1 \@second + echo fake|ssh u4 ukm; !ok; /FATAL: does not seem to be a valid pubkey/ + cat $pd/u5.pub | ssh u4 ukm; ok; + /session key not accepted/ + /pending keyid deleted: \@second/ +"; + +# True addition of a new selfkey is done via piping it to a second ssh +# call that uses the new key to call ukm. Note that the first ssh must +# have completed its job before the second ssh is able to successfully +# log in. This can be done via sleep or via redirecting to a file and +# then reading from it. +try " + # ADDOK u4 u1 \@second | (sleep 2; ssh u4 ukm); ok + ADD u4 u1 \@second > session; ok + cat session | ssh u4 ukm; ok; /pending keyid added: \@second/ +"; + +# u1 cannot add his/her initial key, since that key can never be +# confirmed via ukm, so it is forbidden altogether. In fact, u1 is not +# allowed to add any key twice. +try " + ADDNOK u1 u1 \@first + /FATAL: You cannot add a key that already belongs to you./ + ADDNOK u4 u1 \@first + /FATAL: You cannot add a key that already belongs to you./ +"; + +# u1 also can add more keys, but not under an existing keyid. That can +# be done by any of his/her identities (here we choose u4). +try " + ADDNOK u5 u1 \@second; /FATAL: keyid already in use: \@second/ + ADD u5 u4 \@third > session; ok + cat session | ssh u5 ukm; ok; /pending keyid added: \@third/ +"; + +# u2 cannot add the same key, but is allowed to use the same name (@third). +try " + ADDNOK u5 u2 \@third; /FATAL: cannot add key/ + /Same key is already available under another userid./ + ADD u6 u2 \@third > session; ok + cat session | ssh u6 ukm; ok; /pending keyid added: \@third/ +"; + +# u6 can schedule his/her own key for deletion, but cannot actually +# remove it. Trying to do so results in bringing back the key. Actual +# deletion must be confirmed by another key. +try " + ssh u6 ukm del \@third; /prepare deletion of key \@third/ + ssh u2 ukm; ok; /u2 \@third .pending del./ + ssh u6 ukm; ok; /undo pending deletion of keyid \@third/ + ssh u6 ukm del \@third; /prepare deletion of key \@third/ + ssh u2 ukm del \@third; ok; /pending keyid deleted: \@third/ +"; + +# While in pending-deletion state, it's forbidden to add another key +# with the same keyid. It's also forbidden to add a key with the same +# fingerprint as the to-be-deleted key). +# A new key under another keyid, is OK. +try " + ssh u1 ukm del \@third; /prepare deletion of key \@third/ + ADDNOK u4 u1 \@third; /FATAL: keyid already in use: \@third/ + ADDNOK u5 u1 \@fourth; + /FATAL: You cannot add a key that already belongs to you./ + ADD u6 u1 \@fourth > session; ok + ssh u1 ukm; ok; + /u1 \@second/ + /u1 \@fourth .pending add./ + /u1 \@third .pending del./ +"; +# We can remove a pending-for-addition key (@fourth) by logging in +# with a non-pending key. Trying to do anything with key u5 (@third) +# will just bring it back to its normal state, but not change the +# state of any other key. As already shown above, using u6 (@fourth) +# without a proper session key, would remove it from the system. +# Here we want to demonstrate that key u1 can delete u6 immediately. +try "ssh u1 ukm del \@fourth; /pending keyid deleted: \@fourth/"; + +# The pending-for-deletion key @third can also be removed via the u4 +# (@second) key. +try "ssh u4 ukm del \@third; ok; /pending keyid deleted: \@third/"; + +# Non-existing selfkeys cannot be deleted. +try "ssh u4 ukm del \@x; !ok; /FATAL: You are not managing the key \@x./"; diff --git a/contrib/triggers/IP-check b/contrib/triggers/IP-check new file mode 100755 index 0000000..9a4fda1 --- /dev/null +++ b/contrib/triggers/IP-check @@ -0,0 +1,43 @@ +#!/bin/bash + +# Check an IP before allowing access. + +# This is also a generic example of how to add arbitrary checks at the PRE_GIT +# stage, in order to control fetch/clone as well, not just push operations +# (VREFs, in contrast, only work for pushes). + +# Notice how repo-specific information is being passed to this code (bullet 3 +# below). For more on that, see: +# https://gitolite.com/gitolite/dev-notes/#appendix-1-repo-specific-environment-variables + +# Instructions: + +# 1. put this in an appropriate triggers directory (read about non-core +# code at http://gitolite.com/gitolite/non-core/ for more on this; the +# cookbook may also help here). + +# 2. add a line: +# PRE_GIT => [ 'IP-check' ], +# just before the "ENABLE" line in the rc file + +# 3. add a line like this to the "repo ..." section in gitolite.conf: +# option ENV.IP_allowed = 1.2.3.0/24 +# take care that this expression is valid, in the sense that passing it +# to 'ipcalc -n' will return the part before the "/". I.e., in this +# example, 'ipcalc -n 1.2.3.0/24' should (and does) return 1.2.3.0. + +# ---- + +[ -n "$GL_OPTION_IP_allowed" ] || exit 0 + +expected=${GL_OPTION_IP_allowed%/*} + mask=${GL_OPTION_IP_allowed#*/} + +current_ip=${SSH_CONNECTION%% *} + +eval `ipcalc -n $current_ip/$mask` + +[ "$expected" == "$NETWORK" ] && exit 0 + +echo >&2 "IP $current_ip does not match allowed block $GL_OPTION_IP_allowed" +exit 1 diff --git a/contrib/triggers/file_mirror b/contrib/triggers/file_mirror new file mode 100755 index 0000000..755ce86 --- /dev/null +++ b/contrib/triggers/file_mirror @@ -0,0 +1,172 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# Use an external (non-gitolite) mirror to backup gitolite repos. They will +# be automatically kept uptodate as people push to your gitolite server. If +# your server should die and you create a new one, you can quickly and easily +# get everything back from the external mirror with a few simple commands. + +# ------------------------------------------------------------- +# SEE WARNINGS/CAVEATS AND INSTRUCTIONS AT THE END OF THIS FILE +# ------------------------------------------------------------- + +# ---------------------------------------------------------------------- + +use lib $ENV{GL_LIBDIR}; +use Gitolite::Easy; + +my ( $trigger, $repo, $dummy, $op ) = @ARGV; +exit 0 unless $trigger eq 'POST_GIT' or $trigger eq 'POST_CREATE'; +exit 0 if $trigger eq 'POST_GIT' and $op ne 'W'; + +chdir("$rc{GL_REPO_BASE}/$repo.git") or _die "chdir failed: $!\n"; + +my %config = config( $repo, "gitolite-options\\.mirror\\.extcopy" ); +for my $copy ( values %config ) { + _do($copy); + + # processing one copy is sufficient for restoring! + last if $trigger eq 'POST_CREATE'; +} + +# in shell, that would be something like: +# gitolite git-config -r $repo gitolite-options\\.mirror\\.extcopy | cut -f3 | while read copy +# do +# ... + +# ---------------------------------------------------------------------- + +sub _do { + my $url = shift; + + if ( $trigger eq 'POST_CREATE' ) { + # brand new repo just created; needs to be populated from mirror + + # For your urls you will need a way to somehow query the server and + # ask if the repo is present; it's upto you how you do it. + my $path = $url; + $path =~ s(^file://)(); + return unless -d $path; + + # now fetch. Maybe we can put a "-q" in there? + system( "git", "fetch", $url, "+refs/*:refs/*" ); + + } elsif ( $trigger eq 'POST_GIT' ) { + # someone just pushed; we need to update our mirrors + + # need to create the repo on the mirror. Again, it's upto you how you + # make sure there's a repo on the mirror that can receive the push. + make_repo($url); # in case it doesn't already exist + + # now push + system( "git", "push", "--mirror", $url ); + } +} + +sub make_repo { + my $url = shift; + # in this example, the URL is 'file:///...'; for other urls, presumably + # the url tells you enough about how to *create* a repo. + + my $path = $url; + $path =~ s(^file://)(); + return if -d $path; + system( "git", "init", "--bare", $path ); +} + +__END__ + +WARNINGS +-------- + +1. THIS IS SAMPLE CODE. You will AT LEAST have to customise the _do() and + make_repo() functions above based on what your remote URLs are. For + example, I don't even know how to create a repo from the command line if + your external store is, say, github! + +2. THIS DOES NOT WORK FOR WILD REPOs. It can be made to work, with a few + extra steps to backup and restore the "gl-perms" and "gl-creator" files. + + "Left as an exercise for the reader!" + +DESIGN NOTES +------------ + +This is really just a combination of "upstream" (see src/triggers/upstream) +and mirroring (gitolite mirroring does allow a copy to be non-gitolite, as +long as the ssh stuff is done the same way). + +The main difference is that gitolite mirroring expects peers to all talk ssh, +whereas this method lets you use other protocols. Specifically, since this +whole thing was started off by someone wanting to put his repos on s3 +(apparently jgit can talk to s3 directly), you can modify the two functions to +deal with whatever remote server you have. + +LANGUAGE +-------- + +This doesn't have to be in perl. Shell equivalent for the only gitolite +specific code is supplied; the rest of the code is fairly straightforward. + +SETUP +----- + +1. Put this code into your LOCAL_CODE directory under "triggers"; see + non-core.html for details. + +2. Add these lines to your rc file, just before the ENABLE line. (I'm + assuming a v3.4 or later installation here). + + POST_CREATE => [ 'file_mirror' ], + POST_GIT => [ 'file_mirror' ], + +3. Backup your rc file, since you may have other changes in it that you'll + want to preserve. + +4. Do something like this in your gitolite.conf file: + + repo @all + option mirror.extcopy-1 = file:///tmp/he1/%GL_REPO.git + option mirror.extcopy-2 = file:///tmp/he2/%GL_REPO.git + + As you can see, since this is just for demo/test, we're using a couple of + temp directories to serve as our "remotes" using the file:// protocol. + +5. Do a one-time manual sync of all the repos (subsequent syncs happen on + each push): + + gitolite list-phy-repos | xargs -I xx gitolite trigger POST_GIT xx admin W + + (This is a little trick we're playing on the trigger stuff, but it should + work fine. Just make sure that, if you have other things in your POST_GIT + trigger list, they're not affected in some way. 'gitolite query-rc + POST_GIT' will tell you what else you have.) + +That takes care of the "setup" and "regular backup". + +RESTORE +------- + +1. Install gitolite normally. You'll get the usual two repos. + +2. Restore the previously backed up rc file to replace the default one that + gitolite created. At the very least, the rc file should have the + POST_CREATE and POST_GIT entries. + + --------------------------------------------------------- + IF YOU FORGET THIS STEP, NASTY THINGS WILL HAPPEN TO YOU! + --------------------------------------------------------- + +3. Clone the admin repo from one of your backup servers to some temp dir. In + our example, + + git clone /tmp/he1/gitolite-admin.git old-ga + +4. 'cd' to that clone and force push to your *new* admin repo: + + cd old-ga + git push -f admin:gitolite-admin + +That's it. As each repo gets created by the admin push, they'll get populated +by the backed up stuff due to the POST_CREATE trigger. |