summaryrefslogtreecommitdiffstats
path: root/src/commands/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/commands/config')
-rwxr-xr-xsrc/commands/config110
1 files changed, 110 insertions, 0 deletions
diff --git a/src/commands/config b/src/commands/config
new file mode 100755
index 0000000..214158b
--- /dev/null
+++ b/src/commands/config
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+use 5.10.0;
+
+# ---- WARNING ----
+
+# If your site makes a distinction between "right to push the admin repo" and
+# "right to run arbitrary commands on the server" (i.e., if not all of your
+# "admins" have shell access to the server), this is a security risk. If that
+# is the case, DO NOT ENABLE THIS COMMAND.
+
+# ----------------------------------------------------------------------
+# gitolite command to allow "git config" on repos (with some restrictions)
+
+# (Not to be confused with the 'git-config' command, which is used only in
+# server-side scripts, not remotely.)
+
+# setup:
+# 1. Enable the command by adding it to the COMMANDS section in the ENABLE
+# list in the rc file. (Have you read the warning above?)
+#
+# 2. Specify configs allowed to be changed by the user. This is a space
+# separated regex list. For example:
+
+# repo ...
+# ... (various rules) ...
+# option user-configs = hook\..* foo.bar[0-9].*
+
+use strict;
+use warnings;
+
+use lib $ENV{GL_LIBDIR};
+use Gitolite::Easy;
+use Gitolite::Common;
+
+# ----------------------------------------------------------------------
+# usage
+
+=for usage
+Usage: ssh git@host config <repo> [git config options]
+
+Runs "git config" in the repo. Only the following 3 syntaxes are supported
+(see 'man git-config'):
+
+ --add name value
+ --get-all name
+ --unset-all name
+ --list
+
+Your administrator should tell you what keys are allowed for the "name".
+=cut
+
+# ----------------------------------------------------------------------
+# arg checks
+
+my %nargs = qw(
+ --add 3
+ --get-all 2
+ --unset-all 2
+ --list 1
+ );
+
+usage() if not @ARGV or $ARGV[0] eq '-h';
+
+my $repo = shift;
+
+my $op = shift;
+usage() unless $op and exists $nargs{$op};
+
+# ----------------------------------------------------------------------
+# authorisation checks
+
+die "sorry, you are not authorised\n" unless
+ owns($repo)
+ or
+ ( ( $op eq '--get-all' or $op eq '--list' )
+ ? can_read($repo)
+ : ( can_write($repo) and option( $repo, 'writer-is-owner' ) )
+ );
+
+# ----------------------------------------------------------------------
+# key validity checks
+
+unless ($op eq '--list') {
+ my $key = shift;
+
+ my $val = '';
+ $val = join(" ", @ARGV) if @ARGV;
+ # values with spaces embedded get flattened by sshd when it passes
+ # SSH_ORIGINAL_COMMAND to gitolite. In this specific instance, we will
+ # pretend we know what the user meant, and join up the last 1+ args into
+ # one space-separated arg.
+
+ my $user_configs = option( $repo, 'user-configs' );
+ # this is a space separated list of allowed config keys
+ my @validkeys = split( ' ', ( $user_configs || '' ) );
+ my @matched = grep { $key =~ /^$_$/i } @validkeys;
+ _die "config '$key' not allowed\n" if ( @matched < 1 );
+
+ @ARGV = ($key);
+ push @ARGV, $val if $val;
+}
+
+# ----------------------------------------------------------------------
+# go!
+
+unshift @ARGV, $op;
+usage() unless @ARGV == $nargs{$op};
+
+_chdir("$rc{GL_REPO_BASE}/$repo.git");
+_system( "git", "config", @ARGV );