about summary refs log tree commit diff
path: root/third_party/git/contrib/hooks/update-paranoid
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/git/contrib/hooks/update-paranoid')
-rwxr-xr-xthird_party/git/contrib/hooks/update-paranoid421
1 files changed, 0 insertions, 421 deletions
diff --git a/third_party/git/contrib/hooks/update-paranoid b/third_party/git/contrib/hooks/update-paranoid
deleted file mode 100755
index d18b317b2f..0000000000
--- a/third_party/git/contrib/hooks/update-paranoid
+++ /dev/null
@@ -1,421 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use File::Spec;
-
-$ENV{PATH}     = '/opt/git/bin';
-my $acl_git    = '/vcs/acls.git';
-my $acl_branch = 'refs/heads/master';
-my $debug      = 0;
-
-=doc
-Invoked as: update refname old-sha1 new-sha1
-
-This script is run by git-receive-pack once for each ref that the
-client is trying to modify.  If we exit with a non-zero exit value
-then the update for that particular ref is denied, but updates for
-other refs in the same run of receive-pack may still be allowed.
-
-We are run after the objects have been uploaded, but before the
-ref is actually modified.  We take advantage of that fact when we
-look for "new" commits and tags (the new objects won't show up in
-`rev-list --all`).
-
-This script loads and parses the content of the config file
-"users/$this_user.acl" from the $acl_branch commit of $acl_git ODB.
-The acl file is a git-config style file, but uses a slightly more
-restricted syntax as the Perl parser contained within this script
-is not nearly as permissive as git-config.
-
-Example:
-
-  [user]
-    committer = John Doe <john.doe@example.com>
-    committer = John R. Doe <john.doe@example.com>
-
-  [repository "acls"]
-    allow = heads/master
-    allow = CDUR for heads/jd/
-    allow = C    for ^tags/v\\d+$
-
-For all new commit or tag objects the committer (or tagger) line
-within the object must exactly match one of the user.committer
-values listed in the acl file ("HEAD:users/$this_user.acl").
-
-For a branch to be modified an allow line within the matching
-repository section must be matched for both the refname and the
-opcode.
-
-Repository sections are matched on the basename of the repository
-(after removing the .git suffix).
-
-The opcode abbrevations are:
-
-  C: create new ref
-  D: delete existing ref
-  U: fast-forward existing ref (no commit loss)
-  R: rewind/rebase existing ref (commit loss)
-
-if no opcodes are listed before the "for" keyword then "U" (for
-fast-forward update only) is assumed as this is the most common
-usage.
-
-Refnames are matched by always assuming a prefix of "refs/".
-This hook forbids pushing or deleting anything not under "refs/".
-
-Refnames that start with ^ are Perl regular expressions, and the ^
-is kept as part of the regexp.  \\ is needed to get just one \, so
-\\d expands to \d in Perl.  The 3rd allow line above is an example.
-
-Refnames that don't start with ^ but that end with / are prefix
-matches (2nd allow line above); all other refnames are strict
-equality matches (1st allow line).
-
-Anything pushed to "heads/" (ok, really "refs/heads/") must be
-a commit.  Tags are not permitted here.
-
-Anything pushed to "tags/" (err, really "refs/tags/") must be an
-annotated tag.  Commits, blobs, trees, etc. are not permitted here.
-Annotated tag signatures aren't checked, nor are they required.
-
-The special subrepository of 'info/new-commit-check' can
-be created and used to allow users to push new commits and
-tags from another local repository to this one, even if they
-aren't the committer/tagger of those objects.  In a nut shell
-the info/new-commit-check directory is a Git repository whose
-objects/info/alternates file lists this repository and all other
-possible sources, and whose refs subdirectory contains symlinks
-to this repository's refs subdirectory, and to all other possible
-sources refs subdirectories.  Yes, this means that you cannot
-use packed-refs in those repositories as they won't be resolved
-correctly.
-
-=cut
-
-my $git_dir = $ENV{GIT_DIR};
-my $new_commit_check = "$git_dir/info/new-commit-check";
-my $ref = $ARGV[0];
-my $old = $ARGV[1];
-my $new = $ARGV[2];
-my $new_type;
-my ($this_user) = getpwuid $<; # REAL_USER_ID
-my $repository_name;
-my %user_committer;
-my @allow_rules;
-my @path_rules;
-my %diff_cache;
-
-sub deny ($) {
-	print STDERR "-Deny-    $_[0]\n" if $debug;
-	print STDERR "\ndenied: $_[0]\n\n";
-	exit 1;
-}
-
-sub grant ($) {
-	print STDERR "-Grant-   $_[0]\n" if $debug;
-	exit 0;
-}
-
-sub info ($) {
-	print STDERR "-Info-    $_[0]\n" if $debug;
-}
-
-sub git_value (@) {
-	open(T,'-|','git',@_); local $_ = <T>; chop; close T; $_;
-}
-
-sub match_string ($$) {
-	my ($acl_n, $ref) = @_;
-	   ($acl_n eq $ref)
-	|| ($acl_n =~ m,/$, && substr($ref,0,length $acl_n) eq $acl_n)
-	|| ($acl_n =~ m,^\^, && $ref =~ m:$acl_n:);
-}
-
-sub parse_config ($$$$) {
-	my $data = shift;
-	local $ENV{GIT_DIR} = shift;
-	my $br = shift;
-	my $fn = shift;
-	return unless git_value('rev-list','--max-count=1',$br,'--',$fn);
-	info "Loading $br:$fn";
-	open(I,'-|','git','cat-file','blob',"$br:$fn");
-	my $section = '';
-	while (<I>) {
-		chomp;
-		if (/^\s*$/ || /^\s*#/) {
-		} elsif (/^\[([a-z]+)\]$/i) {
-			$section = lc $1;
-		} elsif (/^\[([a-z]+)\s+"(.*)"\]$/i) {
-			$section = join('.',lc $1,$2);
-		} elsif (/^\s*([a-z][a-z0-9]+)\s*=\s*(.*?)\s*$/i) {
-			push @{$data->{join('.',$section,lc $1)}}, $2;
-		} else {
-			deny "bad config file line $. in $br:$fn";
-		}
-	}
-	close I;
-}
-
-sub all_new_committers () {
-	local $ENV{GIT_DIR} = $git_dir;
-	$ENV{GIT_DIR} = $new_commit_check if -d $new_commit_check;
-
-	info "Getting committers of new commits.";
-	my %used;
-	open(T,'-|','git','rev-list','--pretty=raw',$new,'--not','--all');
-	while (<T>) {
-		next unless s/^committer //;
-		chop;
-		s/>.*$/>/;
-		info "Found $_." unless $used{$_}++;
-	}
-	close T;
-	info "No new commits." unless %used;
-	keys %used;
-}
-
-sub all_new_taggers () {
-	my %exists;
-	open(T,'-|','git','for-each-ref','--format=%(objectname)','refs/tags');
-	while (<T>) {
-		chop;
-		$exists{$_} = 1;
-	}
-	close T;
-
-	info "Getting taggers of new tags.";
-	my %used;
-	my $obj = $new;
-	my $obj_type = $new_type;
-	while ($obj_type eq 'tag') {
-		last if $exists{$obj};
-		$obj_type = '';
-		open(T,'-|','git','cat-file','tag',$obj);
-		while (<T>) {
-			chop;
-			if (/^object ([a-z0-9]{40})$/) {
-				$obj = $1;
-			} elsif (/^type (.+)$/) {
-				$obj_type = $1;
-			} elsif (s/^tagger //) {
-				s/>.*$/>/;
-				info "Found $_." unless $used{$_}++;
-				last;
-			}
-		}
-		close T;
-	}
-	info "No new tags." unless %used;
-	keys %used;
-}
-
-sub check_committers (@) {
-	my @bad;
-	foreach (@_) { push @bad, $_ unless $user_committer{$_}; }
-	if (@bad) {
-		print STDERR "\n";
-		print STDERR "You are not $_.\n" foreach (sort @bad);
-		deny "You cannot push changes not committed by you.";
-	}
-}
-
-sub load_diff ($) {
-	my $base = shift;
-	my $d = $diff_cache{$base};
-	unless ($d) {
-		local $/ = "\0";
-		my %this_diff;
-		if ($base =~ /^0{40}$/) {
-			# Don't load the diff at all; we are making the
-			# branch and have no base to compare to in this
-			# case.  A file level ACL makes no sense in this
-			# context.  Having an empty diff will allow the
-			# branch creation.
-			#
-		} else {
-			open(T,'-|','git','diff-tree',
-				'-r','--name-status','-z',
-				$base,$new) or return undef;
-			while (<T>) {
-				my $op = $_;
-				chop $op;
-
-				my $path = <T>;
-				chop $path;
-
-				$this_diff{$path} = $op;
-			}
-			close T or return undef;
-		}
-		$d = \%this_diff;
-		$diff_cache{$base} = $d;
-	}
-	return $d;
-}
-
-deny "No GIT_DIR inherited from caller" unless $git_dir;
-deny "Need a ref name" unless $ref;
-deny "Refusing funny ref $ref" unless $ref =~ s,^refs/,,;
-deny "Bad old value $old" unless $old =~ /^[a-z0-9]{40}$/;
-deny "Bad new value $new" unless $new =~ /^[a-z0-9]{40}$/;
-deny "Cannot determine who you are." unless $this_user;
-grant "No change requested." if $old eq $new;
-
-$repository_name = File::Spec->rel2abs($git_dir);
-$repository_name =~ m,/([^/]+)(?:\.git|/\.git)$,;
-$repository_name = $1;
-info "Updating in '$repository_name'.";
-
-my $op;
-if    ($old =~ /^0{40}$/) { $op = 'C'; }
-elsif ($new =~ /^0{40}$/) { $op = 'D'; }
-else                      { $op = 'R'; }
-
-# This is really an update (fast-forward) if the
-# merge base of $old and $new is $old.
-#
-$op = 'U' if ($op eq 'R'
-	&& $ref =~ m,^heads/,
-	&& $old eq git_value('merge-base',$old,$new));
-
-# Load the user's ACL file. Expand groups (user.memberof) one level.
-{
-	my %data = ('user.committer' => []);
-	parse_config(\%data,$acl_git,$acl_branch,"external/$repository_name.acl");
-
-	%data = (
-		'user.committer' => $data{'user.committer'},
-		'user.memberof' => [],
-	);
-	parse_config(\%data,$acl_git,$acl_branch,"users/$this_user.acl");
-
-	%user_committer = map {$_ => $_} @{$data{'user.committer'}};
-	my $rule_key = "repository.$repository_name.allow";
-	my $rules = $data{$rule_key} || [];
-
-	foreach my $group (@{$data{'user.memberof'}}) {
-		my %g;
-		parse_config(\%g,$acl_git,$acl_branch,"groups/$group.acl");
-		my $group_rules = $g{$rule_key};
-		push @$rules, @$group_rules if $group_rules;
-	}
-
-RULE:
-	foreach (@$rules) {
-		while (/\${user\.([a-z][a-zA-Z0-9]+)}/) {
-			my $k = lc $1;
-			my $v = $data{"user.$k"};
-			next RULE unless defined $v;
-			next RULE if @$v != 1;
-			next RULE unless defined $v->[0];
-			s/\${user\.$k}/$v->[0]/g;
-		}
-
-		if (/^([AMD ]+)\s+of\s+([^\s]+)\s+for\s+([^\s]+)\s+diff\s+([^\s]+)$/) {
-			my ($ops, $pth, $ref, $bst) = ($1, $2, $3, $4);
-			$ops =~ s/ //g;
-			$pth =~ s/\\\\/\\/g;
-			$ref =~ s/\\\\/\\/g;
-			push @path_rules, [$ops, $pth, $ref, $bst];
-		} elsif (/^([AMD ]+)\s+of\s+([^\s]+)\s+for\s+([^\s]+)$/) {
-			my ($ops, $pth, $ref) = ($1, $2, $3);
-			$ops =~ s/ //g;
-			$pth =~ s/\\\\/\\/g;
-			$ref =~ s/\\\\/\\/g;
-			push @path_rules, [$ops, $pth, $ref, $old];
-		} elsif (/^([CDRU ]+)\s+for\s+([^\s]+)$/) {
-			my $ops = $1;
-			my $ref = $2;
-			$ops =~ s/ //g;
-			$ref =~ s/\\\\/\\/g;
-			push @allow_rules, [$ops, $ref];
-		} elsif (/^for\s+([^\s]+)$/) {
-			# Mentioned, but nothing granted?
-		} elsif (/^[^\s]+$/) {
-			s/\\\\/\\/g;
-			push @allow_rules, ['U', $_];
-		}
-	}
-}
-
-if ($op ne 'D') {
-	$new_type = git_value('cat-file','-t',$new);
-
-	if ($ref =~ m,^heads/,) {
-		deny "$ref must be a commit." unless $new_type eq 'commit';
-	} elsif ($ref =~ m,^tags/,) {
-		deny "$ref must be an annotated tag." unless $new_type eq 'tag';
-	}
-
-	check_committers (all_new_committers);
-	check_committers (all_new_taggers) if $new_type eq 'tag';
-}
-
-info "$this_user wants $op for $ref";
-foreach my $acl_entry (@allow_rules) {
-	my ($acl_ops, $acl_n) = @$acl_entry;
-	next unless $acl_ops =~ /^[CDRU]+$/; # Uhh.... shouldn't happen.
-	next unless $acl_n;
-	next unless $op =~ /^[$acl_ops]$/;
-	next unless match_string $acl_n, $ref;
-
-	# Don't test path rules on branch deletes.
-	#
-	grant "Allowed by: $acl_ops for $acl_n" if $op eq 'D';
-
-	# Aggregate matching path rules; allow if there aren't
-	# any matching this ref.
-	#
-	my %pr;
-	foreach my $p_entry (@path_rules) {
-		my ($p_ops, $p_n, $p_ref, $p_bst) = @$p_entry;
-		next unless $p_ref;
-		push @{$pr{$p_bst}}, $p_entry if match_string $p_ref, $ref;
-	}
-	grant "Allowed by: $acl_ops for $acl_n" unless %pr;
-
-	# Allow only if all changes against a single base are
-	# allowed by file path rules.
-	#
-	my @bad;
-	foreach my $p_bst (keys %pr) {
-		my $diff_ref = load_diff $p_bst;
-		deny "Cannot difference trees." unless ref $diff_ref;
-
-		my %fd = %$diff_ref;
-		foreach my $p_entry (@{$pr{$p_bst}}) {
-			my ($p_ops, $p_n, $p_ref, $p_bst) = @$p_entry;
-			next unless $p_ops =~ /^[AMD]+$/;
-			next unless $p_n;
-
-			foreach my $f_n (keys %fd) {
-				my $f_op = $fd{$f_n};
-				next unless $f_op;
-				next unless $f_op =~ /^[$p_ops]$/;
-				delete $fd{$f_n} if match_string $p_n, $f_n;
-			}
-			last unless %fd;
-		}
-
-		if (%fd) {
-			push @bad, [$p_bst, \%fd];
-		} else {
-			# All changes relative to $p_bst were allowed.
-			#
-			grant "Allowed by: $acl_ops for $acl_n diff $p_bst";
-		}
-	}
-
-	foreach my $bad_ref (@bad) {
-		my ($p_bst, $fd) = @$bad_ref;
-		print STDERR "\n";
-		print STDERR "Not allowed to make the following changes:\n";
-		print STDERR "(base: $p_bst)\n";
-		foreach my $f_n (sort keys %$fd) {
-			print STDERR "  $fd->{$f_n} $f_n\n";
-		}
-	}
-	deny "You are not permitted to $op $ref";
-}
-close A;
-deny "You are not permitted to $op $ref";