From: Sitaram Chamarty <sitaramc@gmail.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: "git@vger.kernel.org" <git@vger.kernel.org>
Subject: Re: saving "git push --signed" certificate blobs
Date: Thu, 01 Jan 2015 07:29:14 +0530 [thread overview]
Message-ID: <54A4A9F2.6020601@gmail.com> (raw)
In-Reply-To: <xmqqiogtrptu.fsf@gitster.dls.corp.google.com>
[-- Attachment #1: Type: text/plain, Size: 2555 bytes --]
On 12/30/2014 11:18 PM, Junio C Hamano wrote:
> Sitaram Chamarty <sitaramc@gmail.com> writes:
>
>> Just wanted to say there's a little script at [1] that saves the certificate
>> blobs generated on the server side by "git push --signed".
>>
>> Quoting from the source:
>>
>> # Collects the cert blob on push and saves it, then, if a certain number of
>> # signed pushes have been seen, processes all the "saved" blobs in one go,
>> # adding them to the special ref 'refs/push-certs'. This is done in a way
>> # that allows searching for all the certs pertaining to one specific branch
>> # (thanks to Junio Hamano for this idea plus general brainstorming).
>>
>> Note that although I posted it in the gitolite ML, this has very little to do
>> with gitolite. Any git server can use it, with only one very minor change [2]
>> needed.
>>
>> sitaram
>>
>> [1]: https://groups.google.com/forum/#!topic/gitolite/7cSrU6JorEY
>>
>> [2]: Either set the GL_OPTIONS_GPC_PENDING environment variable by reading its
>> value from 'git config', or replace the only line that uses that variable, with
>> some other "test".
>
> Nicely done.
>
> We'd need to give you a tool to make it easy to create a "validated
> chain of certificates" out of
>
> $ git log refs/push-certs -- refs/heads/master
>
> to make the history this script creates truly useful, but I think it
> is a very good start.
>
> I can see that you tried to make the log output "human readable" by
> reformatting $cf, I am not sure if it gives us much value. I would
> have expected that you would just use the blob contents for the log
> message as-is, so that
>
> $ git log --pretty=raw refs/push-certs -- refs/heads/master |
> validate-cert-chain
>
> can just work on blobs (shown in the "log" output) without having to
> extract the blobs by doing something like
>
> $ git rev-list refs/push-certs -- refs/heads/master |
> while read commit
> do
> git cat-file blob $commit:refs/heads/master |
> validate-cert
> done
I see what you mean. And it looks like using "--format=%B also works
pretty well. Will fix.
> By the way, you seem to like "cat" too much, though. You don't have
> to cat a single file into a pipeline.
Gee I hope Randal Schwartz is not on this list :)
Anyway the previous fix also removes most of them.
I'm attaching the current version so non-gitolite users can find it
without having to go to the gitolite repo. For gitolite users, it's
somewhere in "contrib/" in the source tree.
sitaram
> Thanks.
>
[-- Attachment #2: save-push-signatures --]
[-- Type: text/plain, Size: 6610 bytes --]
#!/bin/sh
# ----------------------------------------------------------------------
# post-receive hook to adopt push certs into 'refs/push-certs'
# Collects the cert blob on push and saves it, then, if a certain number of
# signed pushes have been seen, processes all the "saved" blobs in one go,
# adding them to the special ref 'refs/push-certs'. This is done in a way
# that allows searching for all the certs pertaining to one specific branch
# (thanks to Junio Hamano for this idea plus general brainstorming).
# The "collection" happens only if $GIT_PUSH_CERT_NONCE_STATUS = OK; again,
# thanks to Junio for pointing this out; see [1]
#
# [1]: https://groups.google.com/forum/#!topic/gitolite/7cSrU6JorEY
# WARNINGS:
# Does not check that GIT_PUSH_CERT_STATUS = "G". If you want to check that
# and FAIL the push, you'll have to write a simple pre-receive hook
# (post-receive is not the place for that; see 'man githooks').
#
# Gitolite users: failing the hook cannot be done as a VREF because git does
# not set those environment variables in the update hook. You'll have to
# write a trivial pre-receive hook and add that in.
# Relevant gitolite doc links:
# repo-specific environment variables
# http://gitolite.com/gitolite/dev-notes.html#rsev
# repo-specific hooks
# http://gitolite.com/gitolite/non-core.html#rsh
# http://gitolite.com/gitolite/cookbook.html#v3.6-variation-repo-specific-hooks
# Environment:
# GIT_PUSH_CERT_NONCE_STATUS should be "OK" (as mentioned above)
#
# GL_OPTIONS_GPC_PENDING (optional; defaults to 1). This is the number of
# git push certs that should be waiting in order to trigger the post
# processing. You can set it within gitolite like so:
#
# repo foo bar # or maybe just 'repo @all'
# option ENV.GPC_PENDING = 5
# Setup:
# Set up this code as a post-receive hook for whatever repos you need to.
# Then arrange to have the environment variable GL_OPTION_GPC_PENDING set to
# some number, as shown above. (This is only required if you need it to be
# greater than 1.) It could of course be different for different repos.
# Also see "Invocation" section below.
# Invocation:
# Normally via git (see 'man githooks'), once it is setup as a post-receive
# hook.
#
# However, if you set the "pending" limit high, and want to periodically
# "clean up" pending certs without necessarily waiting for the counter to
# trip, do the following (untested):
#
# RB=$(gitolite query-rc GL_REPO_BASE)
# for r in $(gitolite list-phy-repos)
# do
# cd $RB/$repo.git
# unset GL_OPTIONS_GPC_PENDING # if it is set higher up
# hooks/post-receive post_process
# done
#
# That will take care of it.
# Using without gitolite:
# Just set GL_OPTIONS_GPC_PENDING within the script (maybe read it from git
# config). Everything else is independent of gitolite.
# ----------------------------------------------------------------------
# make it work on BSD also (but NOT YET TESTED on FreeBSD!)
uname_s=`uname -s`
if [ "$uname_s" = "Linux" ]
then
_lock() { flock "$@"; }
else
_lock() { lockf -k "$@"; }
# I'm assuming other BSDs also have this; I only have FreeBSD.
fi
# ----------------------------------------------------------------------
# standard stuff
die() { echo "$@" >&2; exit 1; }
warn() { echo "$@" >&2; }
# ----------------------------------------------------------------------
# if there are no arguments, we're running as a "post-receive" hook
if [ -z "$1" ]
then
# ignore if it may be a replay attack
[ "$GIT_PUSH_CERT_NONCE_STATUS" = "OK" ] || exit 1
# I don't think "exit 1" does anything in a post-receive anyway, so that's
# just a symbolic gesture!
# note the lock file used
_lock .gpc.lock $0 cat_blob
# if you want to initiate the post-processing ONLY from outside (for
# example via cron), comment out the next line.
exec $0 post_process
fi
# ----------------------------------------------------------------------
# the 'post_process' part; see "Invocation" section in the doc at the top
if [ "$1" = "post_process" ]
then
# this is the same lock file as above
_lock .gpc.lock $0 count_and_rotate $$
[ -d git-push-certs.$$ ] || exit 0
# but this is a different one
_lock .gpc.ref.lock $0 update_ref $$
exit 0
fi
# ----------------------------------------------------------------------
# other values for "$1" are internal use only
if [ "$1" = "cat_blob" ]
then
mkdir -p git-push-certs
git cat-file blob $GIT_PUSH_CERT > git-push-certs/$GIT_PUSH_CERT
echo $GIT_PUSH_CERT >> git-push-certs/.blob.list
fi
if [ "$1" = "count_and_rotate" ]
then
count=$(ls git-push-certs | wc -l)
if test $count -ge ${GL_OPTIONS_GPC_PENDING:-1}
then
# rotate the directory
mv git-push-certs git-push-certs.$2
fi
fi
if [ "$1" = "update_ref" ]
then
# use a different index file for all this
GIT_INDEX_FILE=push_certs_index; export GIT_INDEX_FILE
# prepare the special ref to receive commits
PUSH_CERTS=refs/push-certs
if git rev-parse -q --verify $PUSH_CERTS >/dev/null
then
git read-tree $PUSH_CERTS
else
git read-tree --empty
T=$(git write-tree)
C=$(echo 'start' | git commit-tree $T)
git update-ref $PUSH_CERTS $C
fi
# for each cert blob...
for b in `cat git-push-certs.$2/.blob.list`
do
cf=git-push-certs.$2/$b
# it's highly unlikely that the blob got GC-ed already but write it
# back anyway, just in case
B=$(git hash-object -w $cf)
# bit of a sanity check
[ "$B" = "$b" ] || warn "this should not happen: $B is not equal to $b"
# for each ref described within the cert, update the index
for ref in `cat $cf | egrep '^[a-f0-9]+ [a-f0-9]+ refs/' | cut -f3 -d' '`
do
git update-index --add --cacheinfo 100644,$b,$ref
# we're using the ref name as a "fake" filename, so people can,
# for example, 'git log refs/push-certs -- refs/heads/master', to
# see all the push certs pertaining to the master branch. This
# idea came from Junio Hamano, the git maintanier (I certainly
# don't deal with git plumbing enough to have thought of it!)
done
T=$(git write-tree)
C=$( git commit-tree -p $PUSH_CERTS $T < $cf )
git update-ref $PUSH_CERTS $C
rm -f $cf
done
rm -f git-push-certs.$2/.blob.list
rmdir git-push-certs.$2
fi
prev parent reply other threads:[~2015-01-01 2:00 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <54A10ED1.9020704@gmail.com>
2014-12-30 4:09 ` saving "git push --signed" certificate blobs Sitaram Chamarty
2014-12-30 17:48 ` Junio C Hamano
2015-01-01 1:59 ` Sitaram Chamarty [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=54A4A9F2.6020601@gmail.com \
--to=sitaramc@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.