]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Bump gitolite and add new feature
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 14 Oct 2021 13:29:33 +0000 (15:29 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 14 Oct 2021 14:18:17 +0000 (16:18 +0200)
modules/private/gitolite/default.nix
overlays/default.nix
overlays/gitolite/default.nix [new file with mode: 0644]
overlays/gitolite/invite [new file with mode: 0755]

index e54ee8a2eedacbd44df4eed6693e4dd976d1225c..0fb1a999bf6af0c0e0d1be9b6a8f3c5411d8f664 100644 (file)
@@ -70,6 +70,8 @@ in {
     in
       [
         (pkgs.python3.withPackages python-packages)
+        pkgs.nettools
+        pkgs.findutils
       ];
     # Installation: https://git.immae.eu/mantisbt/view.php?id=93
     services.gitolite = {
index 1f1528c75d12394342bd0381cc67197d5e7f5dd7..a64097c7166098e38f6a491cf3c7c033183efc3a 100644 (file)
@@ -19,6 +19,7 @@ in flakes // {
   dwm = import ./dwm;
   elinks = import ./elinks;
   gitweb = import ./gitweb;
+  gitolite = import ./gitolite;
   goaccess = import ./goaccess;
   kanboard = import ./kanboard;
   ldapvi = import ./ldapvi;
diff --git a/overlays/gitolite/default.nix b/overlays/gitolite/default.nix
new file mode 100644 (file)
index 0000000..7f8f007
--- /dev/null
@@ -0,0 +1,8 @@
+self: super: {
+  gitolite = super.gitolite.overrideAttrs(old: {
+    postPatch = old.postPatch + ''
+      sed -i -e "s@/bin/rm@rm@" src/commands/sskm
+      cp ${./invite} src/commands/invite
+    '';
+  });
+}
diff --git a/overlays/gitolite/invite b/overlays/gitolite/invite
new file mode 100755 (executable)
index 0000000..3cc2dbd
--- /dev/null
@@ -0,0 +1,172 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use lib $ENV{GL_LIBDIR};
+use Gitolite::Rc;
+use Gitolite::Common;
+
+=for usage
+Please see usage at https://www.immae.eu/docs/forge-logicielle/gitolite.html#inviter-des-collaborateurs
+=cut
+
+usage() if @ARGV and ($ARGV[0] eq '-h' or $ARGV[0] eq '--help');
+
+my $rb = $rc{GL_REPO_BASE};
+my $ab = $rc{GL_ADMIN_BASE};
+# get to the keydir
+_chdir("$ab/keydir");
+
+# save arguments for later
+my $operation = shift || 'list';
+my $invitekeyid = shift || '';
+$invitekeyid and $invitekeyid !~ /^[-0-9a-z_]+@[-0-9a-z_]+$/i and die "invalid keyid $invitekeyid\n";
+my ($invited, $keyid) = split /@/, $invitekeyid;
+
+# get the actual userid and keytype
+my $gl_user = $ENV{GL_USER};
+die "This function is reserved for actual users" if $gl_user =~ s/-invite-(.*)$//;
+
+# ----
+# first collect the keys
+
+my ( @invited_keys );
+
+for my $pubkey (`find . -type f -name "*.pub" | sort`) {
+    chomp($pubkey);
+    $pubkey =~ s(^./)();    # artifact of the find command
+
+    my $user = $pubkey;
+    $user =~ s(.*/)();                # foo/bar/baz.pub -> baz.pub
+    $user =~ s/(\@[^.]+)?\.pub$//;    # baz.pub, baz@home.pub -> baz
+
+    if ( $user =~ m(^(zzz-marked-for-...-)?$gl_user-invite-) ) {
+        push @invited_keys, $pubkey;
+    }
+}
+
+# ----
+# list mode; just do it and exit
+sub print_keylist {
+    my ( $message, @list ) = @_;
+    return unless @list;
+    print "== $message ==\n";
+    my $count = 1;
+    for (@list) {
+        my $fp = fingerprint($_);
+        s/(zzz-marked-for-...-)?$gl_user-invite-//g;
+        s/\.pub$//;
+        s(.*/)();
+        print $count++ . ": $fp : $_\n";
+    }
+}
+if ( $operation eq 'list' ) {
+    print "you have the following invited keys:\n";
+    print_keylist( "keys for invited persons", @invited_keys );
+    print "\n\n";
+    exit;
+}
+
+# ----
+# please see docs for details on how a user interacts with this
+
+die "valid operations: add, del\n" unless $operation =~ /^(add|del)$/;
+
+if ( $operation eq 'add' ) {
+  print STDERR "please supply the new key on STDIN.  (I recommend you
+  don't try to do this interactively, but use a pipe)\n";
+  kf_add( $gl_user, $invited, $keyid, safe_stdin() );
+} elsif ( $operation eq 'del' ) {
+  kf_del( $gl_user, $invited, $keyid );
+}
+
+exit;
+
+# ----
+
+# make a temp clone and switch to it
+our $TEMPDIR;
+BEGIN { $TEMPDIR = `mktemp -d -t tmp.XXXXXXXXXX`; }
+END { `rm -rf $TEMPDIR`; }
+
+sub cd_temp_clone {
+    chomp($TEMPDIR);
+    hushed_git( "clone", "$rb/gitolite-admin.git", "$TEMPDIR" );
+    chdir($TEMPDIR);
+    my $hostname = `hostname`; chomp($hostname);
+    hushed_git( "config", "--get", "user.email" ) and hushed_git( "config", "user.email", $ENV{USER} . "@" . $hostname );
+    hushed_git( "config", "--get", "user.name" )  and hushed_git( "config", "user.name",  "$ENV{USER} on $hostname" );
+}
+
+sub fingerprint {
+    my ($fp, $output) = ssh_fingerprint_file(shift);
+    # Do not print the output of $output to an untrusted destination.
+    die "does not seem to be a valid pubkey\n" unless $fp;
+    return $fp;
+}
+
+sub safe_stdin {
+    # read one line from STDIN
+    my $data;
+    my $ret = read STDIN, $data, 4096;
+    # current pubkeys are approx 400 bytes so we go a little overboard
+    die "could not read pubkey data" . ( defined($ret) ? "" : ": $!" ) . "\n" unless $ret;
+    die "pubkey data seems to have more than one line\n" if $data =~ /\n./;
+    return $data;
+}
+
+sub hushed_git {
+    local (*STDOUT) = \*STDOUT;
+    local (*STDERR) = \*STDERR;
+    open( STDOUT, ">", "/dev/null" );
+    open( STDERR, ">", "/dev/null" );
+    system( "git", @_ );
+}
+
+sub highlander {
+    # there can be only one
+    my ( $keyid, $die_if_empty, @a ) = @_;
+    # too many?
+    if ( @a > 1 ) {
+        print STDERR "
+more than one key satisfies this condition, and I can't deal with that!
+The keys are:
+
+";
+        print STDERR "\t" . join( "\n\t", @a ), "\n\n";
+        exit 1;
+    }
+    # too few?
+    die "no keys with " . ( $keyid || "empty" ) . " keyid found\n" if $die_if_empty and not @a;
+
+    return @a;
+}
+
+sub kf_add {
+    my ( $gl_user, $invited, $keyid, $keymaterial ) = @_;
+
+    # add a new "invited" key for $gl_user.
+    cd_temp_clone();
+    chdir("keydir");
+
+    mkdir("invited");
+    _print( "invited/$gl_user-invite-$invited\@$keyid.pub", $keymaterial );
+    hushed_git( "add", "." ) and die "git add failed\n";
+    my $fp = fingerprint("invited/$gl_user-invite-$invited\@$keyid.pub");
+    hushed_git( "commit", "-m", "invite add $gl_user-invite-$invited\@$keyid ($fp)" ) and die "git commit failed\n";
+    system("gitolite push >/dev/null 2>/dev/null") and die "git push failed\n";
+}
+
+sub kf_del {
+    my ( $gl_user, $invited, $keyid ) = @_;
+
+    cd_temp_clone();
+    chdir("keydir");
+
+    my @pk = highlander( $keyid, 1, grep { m(^(.*/)?(zzz-marked-for-...-)?$gl_user-invite-$invited\@$keyid.pub$) } @invited_keys );
+
+    my $fp = fingerprint( $pk[0] );
+    hushed_git( "rm", $pk[0]) and die "git mv failed\n";
+    hushed_git( "commit", "-m", "invite del $pk[0] ($fp)" ) and die "git commit failed\n";
+    system("gitolite push >/dev/null 2>/dev/null") and die "git push failed\n";
+}