Merge default debian
authorPaul Crowley <paul@lshift.net>
Fri, 17 Dec 2010 21:00:06 +0000
branchdebian
changeset 277 265b258904d2
parent 261 b6e65bddda7c (current diff)
parent 276 cc3dd97f7300 (diff)
child 278 8ec40c135ec2
Merge default
.hgignore
--- a/.hgignore	Sat Dec 04 20:22:01 2010 +0000
+++ b/.hgignore	Fri Dec 17 21:00:06 2010 +0000
@@ -1,4 +1,5 @@
 ^build/
+^dev/chroot-test/build/
 ^build-stamp$
 ^configure-stamp$
 ^debian/files$
@@ -11,4 +12,3 @@
 *.pyc
 *.orig
 *.rej
-
--- a/CREDITS	Sat Dec 04 20:22:01 2010 +0000
+++ b/CREDITS	Fri Dec 17 21:00:06 2010 +0000
@@ -17,6 +17,8 @@
 Martin Bagge <brother@bsnet.se>
 Vincenzo Campanella <vinz65@gmail.com>
 Ji ZhengYu <zhengyuji@gmail.com>
+Waldemar Augustyn <waldemar@astyn.com>
+Steven King <kingrst@gmail.com>
 
 This credits file may be incomplete - please remind me about people I
 should add!
--- a/NEWS	Sat Dec 04 20:22:01 2010 +0000
+++ b/NEWS	Fri Dec 17 21:00:06 2010 +0000
@@ -1,3 +1,18 @@
+======================
+mercurial-server 1.1
+======================
+
+* Allow subrepo creation
+* New log filename
+* Changed logging format to use JSON/YAML
+* Add the source IP address and other info in the SSH_CONNECTION environment variable
+* Lock log file
+* Make sure authorized_keys file is mode 600
+* Add dev/chroot-test testing code
+* Extend documentation
+
+Upgrading: note the changes to the log file format listed above.
+
 ======================
 mercurial-server 1.0.1
 ======================
--- a/README	Sat Dec 04 20:22:01 2010 +0000
+++ b/README	Fri Dec 17 21:00:06 2010 +0000
@@ -6,7 +6,7 @@
 
 http://www.lshift.net/mercurial-server.html
 
-Copyright (C) 2008-2009 LShift Ltd.
+Copyright (C) 2008-2010 LShift Ltd.
 
     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
@@ -40,5 +40,5 @@
 
 See doc/manual.docbook for the rest of the documentation.
 
-Paul Crowley, paul@lshift.net, 2009
+Paul Crowley, paul@lshift.net, 2010
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/action/go	Fri Dec 17 21:00:06 2010 +0000
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+set -e
+
+cd action
+
+ls -l
+
+. ./testing_system
+
+#exec > results 2>&1
+
+#aptitude --allow-untrusted --quiet --without-recommends --assume-yes  install mercurial
+#hg --version
+
+aptitude --allow-untrusted --quiet --without-recommends --assume-yes  install \
+    make mercurial xsltproc docbook-xsl openssh-server \
+    python python-support adduser 
+
+#aptitude --allow-untrusted --quiet --without-recommends --assume-yes  install \
+#     debconf python python-support adduser mercurial openssh-server 
+     
+
+perl -i -pe 's/^Port 22$/Port 2222/' /etc/ssh/sshd_config
+/etc/init.d/ssh start
+ssh-keyscan -p 2222 localhost > /etc/ssh/ssh_known_hosts
+
+#dpkg -i mercurial-server_1.0-1_all.deb
+cd mercurial-server
+make setup-adduser
+
+for user in test1 test2 ; do
+    adduser --gecos $user --disabled-password $user
+    su -l -c 'mkdir .ssh' $user
+    su -l -c 'ssh-keygen -N "" -f .ssh/id_rsa -t rsa' $user
+done
+cp /home/test1/.ssh/id_rsa.pub /etc/mercurial-server/keys/root/test1
+su -l -c /usr/local/share/mercurial-server/refresh-auth hg
+su -l -c /action/test1 test1
+su -l -c /action/test2 test2
+
+/etc/init.d/ssh stop
+
+#touch results
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/action/test1	Fri Dec 17 21:00:06 2010 +0000
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+set -e
+
+cd
+
+cat > .ssh/config <<__END__
+Host chroothg
+Hostname localhost
+User hg
+Port 2222
+__END__
+
+echo "Cloning hgadmin..."
+hg clone ssh://chroothg/hgadmin
+echo "Updating hgadmin..."
+cd hgadmin
+
+cat > access.conf <<__END__
+read user=restricted/** file=denied/**
+write user=restricted/**
+__END__
+mkdir -p keys/restricted
+cp /home/test2/.ssh/id_rsa.pub keys/restricted/test2
+
+hg add keys/restricted/test2 access.conf
+hg commit -u test1 -m "Added user test2"
+echo "Push"
+hg push
+cd ..
+hg init realrepo
+cd realrepo
+mkdir denied
+echo "This is a file" > content
+echo "This is a file not everyone can write to" > denied/cantwrite
+hg init nested
+echo "This is a file in a nested repo" > nested/content
+hg add -R nested nested/content
+hg commit -u test1 -R nested -m "Add files to the subrepo"
+echo "nested = nested" > .hgsub
+hg add content denied/cantwrite .hgsub
+hg commit -u test1 -m "Add files to the repo"
+echo "Pushing changes"
+hg clone . ssh://chroothg/real/project
+hg clone nested ssh://chroothg/real/project/nested
+echo "Done for user test1"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/action/test2	Fri Dec 17 21:00:06 2010 +0000
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+set -e
+
+cd
+
+cat > .ssh/config <<__END__
+Host chroothg
+Hostname localhost
+User hg
+Port 2222
+__END__
+
+echo "Pulling real project"
+hg clone ssh://chroothg/real/project
+cd project
+[ -e nested/content ]
+echo "and I'm adding something" >> content
+hg commit -u test2 -m "Added something to the file"
+echo "This push should succeed"
+hg push
+echo "And it did"
+echo "This should fail" >> denied/cantwrite
+hg commit -u test2 -m "WONTPUSH"
+# Fail only if this succeeds
+echo "About to do bad push"
+hg push && false
+echo "really checking now"
+hg outgoing --template '{desc}' | grep -q WONTPUSH
+echo "done"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/action/testing_system	Fri Dec 17 21:00:06 2010 +0000
@@ -0,0 +1,5 @@
+
+if [ \! -e /please-trash-this-system ] ; then
+    echo "These tests will only run in a special test environment, sorry"
+    exit -1
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/policy-rc.d	Fri Dec 17 21:00:06 2010 +0000
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# Refuse everything - nothing should start.
+return 101
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/run-test	Fri Dec 17 21:00:06 2010 +0000
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# Must be root to run this
+
+set -e
+
+DEBVERSION=sid
+
+PRISTINE=/var/local/cache/pristine/$DEBVERSION
+
+if [ ! -e $PRISTINE ] ; then
+    echo "Missing:" $PRISTINE
+    echo "Debian pristine image not found, try running these commands as root:"
+    echo mkdir -p /var/local/cache/pristine
+    echo debootstrap $DEBVERSION $PRISTINE http://ftp.uk.debian.org/debian/
+    exit -1
+fi
+
+TOPDIR=`pwd`
+mkdir -p $TOPDIR/build/env
+BACKING=$TOPDIR/build/env/backing
+MOUNT=$TOPDIR/build/env/mount
+if [ -e $MOUNT ] ; then
+    echo "Removing old filesystem"
+    # FIXME: evil hack!
+    chroot $MOUNT /etc/init.d/ssh stop || true
+    umount $MOUNT/proc || true
+    umount $MOUNT || true
+    rm -rf $MOUNT
+fi
+if [ -e $BACKING ] ; then
+    echo "Copying deb files into cache"
+    cp $BACKING/var/cache/apt/archives/* build/aptcache/$DEBVERSION || true
+    echo "Deleting old filesystem backing store"
+    rm -rf $BACKING
+fi
+mkdir $BACKING $MOUNT
+
+touch $BACKING/please-trash-this-system
+mkdir -p $BACKING/etc
+echo "pristine" > $BACKING/etc/debian_chroot
+cp -v policy-rc.d $BACKING/etc/policy-rc.d
+
+mkdir -p $BACKING/var/cache/apt/archives
+echo "Copying deb files out of cache"
+cp build/aptcache/$DEBVERSION/* $BACKING/var/cache/apt/archives || true
+
+cp -av action $BACKING
+#hg -R ../mercurial-server archive -r default $BACKING/action/mercurial-server
+( cd $(hg root) && \
+    hg st -mac0n | cpio -p -0 -d $BACKING/action/mercurial-server )
+
+#cp ../mercurial-server/build/debian/mercurial-server_1.0-1_all.deb $BACKING/action
+
+unionfs-fuse -o cow -o allow_other,suid,dev $BACKING=RW:$PRISTINE=RO $MOUNT
+
+#mount --bind /dev "$MOUNT/dev"
+#mount --bind /dev/pts "$MOUNT/dev/pts"
+mount -t proc proc $MOUNT/proc
+
+chroot $MOUNT ./action/go
+
+
+#cat $BACKING/action/results
+
+#rm -rf build/env
+
--- a/doc/manual.docbook	Sat Dec 04 20:22:01 2010 +0000
+++ b/doc/manual.docbook	Fri Dec 17 21:00:06 2010 +0000
@@ -4,7 +4,7 @@
 <info>
   <title>Sharing Mercurial repositories with mercurial-server</title>
   <author><firstname>Paul</firstname><surname>Crowley</surname></author>
-  <copyright><year>2009</year><holder>Paul Crowley, LShift Ltd</holder></copyright>
+  <copyright><year>2008-2010</year><holder>Paul Crowley, LShift Ltd</holder></copyright>
 </info>
 <section>
 <title>About mercurial-server</title>
@@ -420,6 +420,8 @@
 </section>
 </section>
 <section>
+<title>In detail</title>
+<section>
 <title>How mercurial-server works</title>
 <para>
 All of the repositories controlled by mercurial-server are owned by a
@@ -475,12 +477,31 @@
 <para>
 However, while the first paragraph holds no matter what bugs
 mercurial-server contains, the second depends on the relevant code being
-correct; though the entire codebase is short, mercurial-server is a fairly
-new program and may harbour bugs. Backups are essential!
+correct; though the entire codebase is short, like all software mercurial-server may harbour bugs. Backups are essential!
+</para>
+</section>
+<section>
+<title>Logging</title>
+<para>
+Every successful access is logged in a file called
+<filename>~hg/repos/<replaceable>repository</replaceable>/.hg/mercurial-server.log</filename>. This file is in YAML format for easy parsing, but if you don't like YAML, simply treat each line as a JSON data structure prepended with <code>- </code>. The log records the time as a
+UTC ISO 8601 time, the operation ("push" or "pull"), the path to the key as
+used in the access rules, the SSH connection information (including the source IP address), and the hex changeset IDs.
 </para>
 </section>
 <section>
-<title>Legalese</title>
+<title>Paths and configuration</title>
+<para>
+For security reasons, all mercurial-server code runs as the <systemitem
+class="username">hg</systemitem> user.  The first thing this code reads when it starts is <filename>~hg/.mercurial-server</filename>; if this file is absent or corrupt the code won't run.  This file specifies all of the file paths that mercurial-server uses.  In particular, it specifies that mercurial-server always uses <code>HGRCPATH = /etc/mercurial-server/remote-hgrc.d</code> for remote operations, overriding any system <code>HGRCPATH</code>.
+</para>
+<para>
+By creating such a file with suitable entries, you can run mercurial-server as a user other than <systemitem
+class="username">hg</systemitem>, or install it without root privileges; however I strongly recommend that if you need to do this, you use a user account that is used for no other purpose, and take the time to thoroughly understand how mercurial-server works before you attempt it.
+</para>
+</section>
+<section>
+<title>License</title>
 <para>
 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
@@ -506,8 +527,9 @@
 it.
 </para>
 <para>
-Paul Crowley, <email>paul@lshift.net</email>, 2009
+Paul Crowley, <email>paul@lshift.net</email>, 2010
 </para>
 </section>
+</section>
 </article>
 
--- a/setup.py	Sat Dec 04 20:22:01 2010 +0000
+++ b/setup.py	Fri Dec 17 21:00:06 2010 +0000
@@ -7,7 +7,7 @@
     name="mercurial-server",
     description="Centralized Mercurial repository manager",
     url="http://www.lshift.net/mercurial-server.html",
-    version="1.0.1", # FIXME: infer this
+    version="1.1", # FIXME: infer this
     package_dir = {'': 'src'},
     packages = ["mercurialserver"],
     requires = ["mercurial"], # FIXME: what version?
--- a/src/hg-ssh	Sat Dec 04 20:22:01 2010 +0000
+++ b/src/hg-ssh	Fri Dec 17 21:00:06 2010 +0000
@@ -34,17 +34,8 @@
     if head:
         checkDots(head)
 
-def checkParents(path):
-    path = os.path.dirname(path)
-    if path == "":
-        return
-    if os.path.exists(path + "/.hg"):
-        fail("Cannot create repo under existing repo")
-    checkParents(path)
-
 def getrepo(op, repo):
     # First canonicalise, then check the string, then the rules
-    # and finally the filesystem.
     repo = repo.strip().rstrip("/")
     if len(repo) == 0:
         fail("path to repository seems to be empty")
@@ -54,7 +45,6 @@
     ruleset.rules.set(repo=repo)
     if not ruleset.rules.allow(op, branch=None, file=None):
         fail("access denied")
-    checkParents(repo)
     return repo
 
 config.initExe()
--- a/src/mercurialserver/refreshauth.py	Sat Dec 04 20:22:01 2010 +0000
+++ b/src/mercurialserver/refreshauth.py	Fri Dec 17 21:00:06 2010 +0000
@@ -4,7 +4,7 @@
 
 import re
 import base64
-import os
+import os, stat
 import os.path
 import subprocess
 from mercurialserver import config
@@ -55,6 +55,7 @@
                     if len(l):
                         akeys.write('%s"%s %s" %s\n' % (prefix, wrappercommand, keyname, l))
     akeys.close()
+    os.chmod(akeyfile + "_new", stat.S_IRUSR)
     os.rename(akeyfile + "_new", akeyfile)
     
 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
--- a/src/mercurialserver/servelog.py	Sat Dec 04 20:22:01 2010 +0000
+++ b/src/mercurialserver/servelog.py	Fri Dec 17 21:00:06 2010 +0000
@@ -8,6 +8,8 @@
 
 import os
 import time
+import fcntl
+import json
 from mercurialserver import ruleset, changes
 
 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
@@ -18,13 +20,18 @@
     else:
         raise mercurial.util.Abort(_('servelog installed as wrong hook type,'
             ' must be changegroup or outgoing but is %s') % hooktype)
-    t = time.strftime("%Y-%m-%d_%H:%M:%S", time.gmtime())
-    user = ruleset.rules.get('user')
-    # FIXME: lock it
-    log = open(repo.join("serve-log"), "a+")
+    log = open(repo.join("mercurial-server.log"), "a+")
     try:
-        for ctx in changes.changes(repo, node):
-            log.write("%s %s key=%s changeset=%s\n" % 
-                (t, op, user, mercurial.node.hex(ctx.node())))
+        fcntl.flock(log.fileno(), fcntl.LOCK_EX)
+        log.seek(0, os.SEEK_END)
+        # YAML log file format
+        log.write("- {0}\n".format(json.dumps(dict(
+            timestamp=time.strftime("%Y-%m-%d_%H:%M:%S Z", time.gmtime()),
+            op=op,
+            key=ruleset.rules.get('user'),
+            ssh_connection=os.environ['SSH_CONNECTION'],
+            nodes=[mercurial.node.hex(ctx.node())
+                for ctx in changes.changes(repo, node)],
+         ))))
     finally:
         log.close()