#!/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 );