enhanced the directory restriction of the pre-commit hook configurable

This commit is contained in:
hyung-hwan 2015-02-16 12:27:25 +00:00
parent 63d0c15ef9
commit 827e4b4e87
4 changed files with 100 additions and 67 deletions

View File

@ -2,7 +2,7 @@ Package: @PACKAGE@
Version: @VERSION@ Version: @VERSION@
Maintainer: @PACKAGE_BUGREPORT@ Maintainer: @PACKAGE_BUGREPORT@
Homepage: @PACKAGE_URL@ Homepage: @PACKAGE_URL@
Depends: subversion, apache2-mpm-prefork, libapache2-svn, php5, php5-ldap, php5-gd, perl, libconfig-simple-perl, libsvn-perl Depends: subversion, apache2, libapache2-svn, libapache2-mod-perl2, libapache2-mod-php5, php5, php5-ldap, php5-gd, perl, libdbi-perl, libconfig-simple-perl, libsvn-perl, libnet-ldap-perl, libdigest-sha1-perl
Recommends: php5-mysql, php5-svn (>= 0.5.1) Recommends: php5-mysql, php5-svn (>= 0.5.1)
Suggests: slapd, mysql-server Suggests: slapd, mysql-server
Section: web Section: web

View File

@ -199,19 +199,6 @@ allow_set_time_limit = "no"
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
signin_for_code_search = "yes" signin_for_code_search = "yes"
;------------------------------------------------------------------------------
; Subversion read access is limited to the specified user type. The types
; include anonymous, authenticated, member. This applies to a public project
; only. Write access to any projects and read access to a non-public project
; require membership regardless of this item.
;------------------------------------------------------------------------------
svn_read_access = "member"
;------------------------------------------------------------------------------
; The length of a commit message must be as long as this value.
;------------------------------------------------------------------------------
svn_min_commit_message_length = "0"
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
; customized footer ; customized footer
@ -226,3 +213,24 @@ footer = ""
; Full path to the CLOC command ; Full path to the CLOC command
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
cloc_command_path = "@CFGDIR@/cloc.pl" cloc_command_path = "@CFGDIR@/cloc.pl"
;------------------------------------------------------------------------------
; Subversion read access is limited to the specified user type. The types
; include anonymous, authenticated, member. This applies to a public project
; only. Write access to any projects and read access to a non-public project
; require membership regardless of this item.
;------------------------------------------------------------------------------
svn_read_access = "member"
;------------------------------------------------------------------------------
; The length of a commit message must be as long as this value.
;------------------------------------------------------------------------------
svn_min_commit_message_length = "0"
;------------------------------------------------------------------------------
; The operations on the files under one of svn_restricted_topdirs
; is limited. The value can be separated by a comma.
;------------------------------------------------------------------------------
svn_restricted_topdirs = ""
svn_restriction_allowed_subdir_depth_min = 1
svn_restriction_allowed_subdir_depth_max = 1

View File

@ -48,8 +48,11 @@ sub get_config
database_name => $cfg->param ('database_name'), database_name => $cfg->param ('database_name'),
database_driver => $cfg->param ('database_driver'), database_driver => $cfg->param ('database_driver'),
database_prefix => $cfg->param ('database_prefix'), database_prefix => $cfg->param ('database_prefix'),
svn_min_commit_message_length => $cfg->param ('svn_min_commit_message_length') svn_min_commit_message_length => $cfg->param ('svn_min_commit_message_length'),
svn_restricted_topdirs => $cfg->param('svn_restricted_topdirs'),
svn_restriction_allowed_subdir_depth_min => $cfg->param('svn_restriction_allowed_subdir_depth_min'),
svn_restriction_allowed_subdir_depth_max => $cfg->param('svn_restriction_allowed_subdir_depth_max')
}; };
return $config; return $config;
@ -314,9 +317,9 @@ sub restrict_changes_in_directory_old
return ($disallowed > 0)? -1: 0; return ($disallowed > 0)? -1: 0;
} }
sub restrict_changes_in_directory sub restrict_changes_in_topdirs
{ {
my ($dir, $min_level, $max_level) = @_; my ($min_level, $max_level, @topdirs) = @_;
my $disallowed = 0; my $disallowed = 0;
my $pool = SVN::Pool->new(undef); my $pool = SVN::Pool->new(undef);
@ -392,64 +395,66 @@ sub restrict_changes_in_directory
#print STDERR "@@@@@ [$affected_file] [$action_verb] [$source_file] [$is_source_file_dir] [$is_affected_file_dir]\n"; #print STDERR "@@@@@ [$affected_file] [$action_verb] [$source_file] [$is_source_file_dir] [$is_affected_file_dir]\n";
if ($affected_file =~ /\/${dir}\/(.*)$/) foreach my $topdir(@topdirs)
{ {
# the affected file is located under the given directory. if ($affected_file =~ /\/${topdir}\/(.*)$/)
my $affected_file_nodir = "${1}";
if (defined($source_file))
{ {
# it's being copied. # the affected file is located under the given directory.
if (!$is_affected_file_dir) my $affected_file_nodir = "${1}";
if (defined($source_file))
{ {
# the file beging added by copying is not a directory. # it's being copied.
# it disallows individual file copying. if (!$is_affected_file_dir)
# copy a whole directory at one go. {
print (STDERR "Disallowed to copy ${source_file} to ${affected_file}\n"); # the file beging added by copying is not a directory.
$disallowed++; # it disallows individual file copying.
} # copy a whole directory at one go.
elsif ($source_file =~ /^\/${dir}\/(.*)$/) print (STDERR "Disallowed to copy ${source_file} to ${affected_file}\n");
{ $disallowed++;
# i don't want to be a copied file or directory to be }
# a source of another copy operation. elsif ($source_file =~ /^\/${topdir}\/(.*)$/)
print (STDERR "Disallowed to copy ${source_file} to ${affected_file}\n"); {
$disallowed++; # i don't want to be a copied file or directory to be
# a source of another copy operation.
print (STDERR "Disallowed to copy ${source_file} to ${affected_file}\n");
$disallowed++;
}
else
{
# TODO: DISALLOW THIS if the parent directory is a copied directory
#my $pardir = dirname ($affected_file);
}
} }
else else
{ {
# TODO: DISALLOW THIS if the parent directory is a copied directory if ($is_affected_file_dir)
#my $pardir = dirname ($affected_file); {
} my @segs = split ('/', $affected_file_nodir);
} my $num_segs = scalar(@segs);
else # NOTE: for a string like abc/def/, split() seems to return 2 segments only.
{
if ($is_affected_file_dir)
{
my @segs = split ('/', $affected_file_nodir);
my $num_segs = scalar(@segs);
# NOTE: for a string like abc/def/, split() seems to return 2 segments only.
if ($affected_file_nodir eq '') if ($affected_file_nodir eq '')
{ {
# it is the main directory itself. # it is the main directory itself.
# allow operation on it. # allow operation on it.
}
elsif ($num_segs < $min_level || $num_segs > $max_level)
{
# disallow deletion if the directory name to be deleted
# matches a tag pattern
print (STDERR "Disallowed to ${action_verb} a directory - ${affected_file}\n");
$disallowed++;
}
} }
elsif ($num_segs < $min_level || $num_segs > $max_level) else
{ {
# disallow deletion if the directory name to be deleted print (STDERR "Disallowed to ${action_verb} a file - ${affected_file}\n");
# matches a tag pattern
print (STDERR "Disallowed to ${action_verb} a directory - ${affected_file}\n");
$disallowed++; $disallowed++;
} }
} }
else
{
print (STDERR "Disallowed to ${action_verb} a file - ${affected_file}\n");
$disallowed++;
}
} }
} }
} }
# 'svn rename' within the restricted directory is disallowed because # 'svn rename' within the restricted directory is disallowed because
@ -482,10 +487,24 @@ if (check_commit_message ($cfg->{svn_min_commit_message_length}) <= 0)
exit (1); exit (1);
} }
# TODO: make 'tags' and 'min_level', 'max_level' configurable.
if (restrict_changes_in_directory ('tags', 1, 2) <= -1) # TODO: enable per-project settings for topdir restriction
my $min_level = $cfg->{svn_restriction_allowed_subdir_depth_min};
if (!defined($min_level)) { $min_level = 0; }
my $max_level = $cfg->{svn_restriction_allowed_subdir_depth_max};
if (!defined($max_level)) { $max_level = 0; }
my $topdirs = $cfg->{svn_restricted_topdirs};
if (defined($topdirs))
{ {
exit (1); my @topdir_array = split (/\s*,\s*/, $topdirs);
if (scalar(@topdir_array) > 0)
{
if (restrict_changes_in_topdirs ($min_level, $max_level, @topdir_array) <= -1)
{
exit (1);
}
}
} }
#my $dbh = open_database ($cfg); #my $dbh = open_database ($cfg);

View File

@ -78,10 +78,16 @@ function load_ini ($file)
array ('force_project_delete', 'boolean', FALSE), array ('force_project_delete', 'boolean', FALSE),
array ('allow_set_time_limit', 'boolean', FALSE), array ('allow_set_time_limit', 'boolean', FALSE),
array ('signin_for_code_search', 'boolean', TRUE), array ('signin_for_code_search', 'boolean', TRUE),
array ('svn_for_members_only', 'boolean', FALSE),
array ('footer', 'string', ''), array ('footer', 'string', ''),
array ('cloc_command_path', 'string', CODEPOT_CFG_DIR.'/cloc.pl') array ('cloc_command_path', 'string', CODEPOT_CFG_DIR.'/cloc.pl'),
// these items are not used by php but by subersion hooks written in perl.
array ('svn_read_access', 'string', 'member'),
array ('svn_min_commit_message_length', 'integer', 0),
array ('svn_restricted_topdirs', 'string', ''),
array ('svn_restriction_allowed_subdir_depth_min', 'integer', 0),
array ('svn_restriction_allowed_subdir_depth_max', 'integer', 0)
); );
foreach ($xcfgs as $x) foreach ($xcfgs as $x)