X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=infra%2Fdgit-repos-server;h=7c7262f50fce372dcfaf89c763fa3a223f04a9d7;hb=3201106edaaaa5859f8a4f1228e250f9f8968428;hp=5bf4416267c72c4cec207e20908faf64ade5af26;hpb=ff53225eafcc9e53998f9f49085a366f3f98fc9c;p=dgit.git diff --git a/infra/dgit-repos-server b/infra/dgit-repos-server index 5bf44162..7c7262f5 100755 --- a/infra/dgit-repos-server +++ b/infra/dgit-repos-server @@ -1,6 +1,23 @@ #!/usr/bin/perl -w # dgit-repos-server # +# git protocol proxy to check dgit pushes etc. +# +# Copyright (C) 2014-2016 Ian Jackson +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + # usages: # dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [] --ssh # dgit-repos-server DISTRO DISTRO-DIR AUTH-SPEC [] --cron @@ -34,6 +51,7 @@ use strict; +use Debian::Dgit::Infra; # must precede Debian::Dgit; - can change @INC! use Debian::Dgit qw(:DEFAULT :policyflags); setup_sigwarn(); @@ -142,6 +160,10 @@ setup_sigwarn(); # FRESHREPO (4) # blow away repo right away (ie, as if before push or fetch) # ("check-package" and "push" only) +# NOCOMMITCHECK (8) +# suppress dgit-repos-server's check that commits do +# not lack "committer" info (eg as produced by #849041) +# ("push" only) # any unexpected bits mean failure, and then known set bits are ignored # if no unexpected bits set, operation continues (subject to meaning # of any expected bits set). So, eg, exit 0 means "continue normally" @@ -281,13 +303,6 @@ sub reject ($) { die "\ndgit-repos-server: reject: $why\n\n"; } -sub runcmd { - debugcmd '+',@_; - $!=0; $?=0; - my $r = system @_; - die (shellquote @_)." $? $!" if $r; -} - sub policyhook { my ($policyallowbits, @polargs) = @_; # => ($exitstatuspolicybitmap); @@ -385,16 +400,21 @@ sub makeworkingclone () { rmtree "${workrepo}_fresh"; } +sub mkscript ($$) { + my ($path,$contents) = @_; + my $fh = new IO::File $path, O_WRONLY|O_CREAT|O_TRUNC, 0777 + or die "$path: $!"; + print $fh $contents or die "$path: $!"; + close $fh or die "$path: $!"; +} + sub setupstunthook () { my $prerecv = "$workrepo/hooks/pre-receive"; - my $fh = new IO::File $prerecv, O_WRONLY|O_CREAT|O_TRUNC, 0777 - or die "$prerecv: $!"; - print $fh <error and die $!; reject "push is missing tag ref update" unless %tags; - my @newtags = grep { m#^archive/# } keys %tags; - my @omtags = grep { !m#^archive/# } keys %tags; - reject "pushing too many similar tags" if @newtags>1 || @omtags>1; - if (@newtags) { - ($tagname) = @newtags; - ($maint_tagname) = @omtags; - } else { - ($tagname) = @omtags or die; - } + my @dtags = grep { m#^archive/# } keys %tags; + reject "need exactly one archive/* tag" if @dtags!=1; + my @mtags = grep { !m#^archive/# } keys %tags; + reject "pushing too many non-dgit tags" if @mtags>1; + ($tagname) = @dtags; + ($maint_tagname) = @mtags; $tagval = $tags{$tagname}; $maint_tagval = $tags{$maint_tagname // ''}; @@ -842,8 +859,7 @@ sub checks () { grep { $tagname eq $_ } @expecttagnames or die; foreach my $othertag (grep { $_ ne $tagname } @expecttagnames) { - reject "tag $othertag (pushed with differing dgit version)". - " already exists -". + reject "tag $othertag already exists -". " not replacing previously-pushed version" if git_get_ref "refs/tags/".$othertag; } @@ -852,7 +868,7 @@ sub checks () { @policy_args = ($package,$version,$suite,$tagname, join(",",@deliberatelies)); - $policy = policyhook(NOFFCHECK|FRESHREPO, 'push', @policy_args); + $policy = policyhook(NOFFCHECK|FRESHREPO|NOCOMMITCHECK, 'push', @policy_args); if (defined $tagexists_error) { if ($policy & FRESHREPO) { @@ -872,6 +888,27 @@ sub checks () { chomp $mb; $mb eq $oldcommit or reject "not fast forward on dgit branch"; } + + # defend against commits generated by #849041 + if (!($policy & NOCOMMITCHECK)) { + my @checks = qw(%at + %ct); + my @chk = qw(git log -z); + push @chk, '--pretty=tformat:%H%n'. + (join "", map { $_, '%n' } @checks); + push @chk, "^$oldcommit" if $oldcommit =~ m/[^0]/; + push @chk, $commit;; + printdebug " ~NOCOMMITCHECK @chk\n"; + open CHK, "-|", @chk or die $!; + local $/ = "\0"; + while () { + next unless m/^$/m; + m/^\w+(?=\n)/ or die; + reject "corrupted object $& (missing metadata)"; + } + $!=0; $?=0; close CHK or $?==256 or die "$? $!"; + } + if ($policy & FRESHREPO) { # It's a bit late to be discovering this here, isn't it ? # @@ -895,6 +932,17 @@ sub onwardpush () { my @cmdbase = (qw(git send-pack), $destrepo); push @cmdbase, qw(--force) if $policy & NOFFCHECK; + if ($ENV{GIT_QUARANTINE_PATH}) { + my $recv_wrapper = "$ENV{GIT_QUARANTINE_PATH}/dgit-recv-wrapper"; + mkscript $recv_wrapper, <<'END'; +#!/bin/sh +set -e +unset GIT_QUARANTINE_PATH +exec git receive-pack "$@" +END + push @cmdbase, "--receive-pack=$recv_wrapper"; + } + my @cmd = @cmdbase; push @cmd, "$commit:refs/dgit/$suite", "$tagval:refs/tags/$tagname";