--- a/.hgignore Sat Dec 18 14:01:24 2010 +0000
+++ b/.hgignore Sat Dec 18 14:10:46 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/.hgtags Sat Dec 18 14:01:24 2010 +0000
+++ b/.hgtags Sat Dec 18 14:10:46 2010 +0000
@@ -9,3 +9,4 @@
8ce190faa5c2b50f63cc5b11e28daf98836498d8 release_1.0
60c2d676a754e02f1f7656a4b137399438b2ed35 debian_1.0-1
92cb6640a6417edaf52870c8a97000e11bb8b138 release_1.0.1
+c7aca86585824f39fa47015d6ebf1bab6a25b82c debian_1.0.1-1
--- a/CREDITS Sat Dec 18 14:01:24 2010 +0000
+++ b/CREDITS Sat Dec 18 14:10:46 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 18 14:01:24 2010 +0000
+++ b/NEWS Sat Dec 18 14:10:46 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 18 14:01:24 2010 +0000
+++ b/README Sat Dec 18 14:10:46 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
--- a/debian/changelog Sat Dec 18 14:01:24 2010 +0000
+++ b/debian/changelog Sat Dec 18 14:10:46 2010 +0000
@@ -1,3 +1,12 @@
+mercurial-server (1.1-1) unstable; urgency=low
+
+ * New upstream version
+ * Fix "leaves unowned files on purge": Delete user/group only
+ when purging data (Closes: #605584)
+ * Add translation for pt_BR (Closes: #607407)
+
+ -- Paul Crowley <paul@lshift.net> Sat, 18 Dec 2010 13:32:26 +0000
+
mercurial-server (1.0.1-1.1) unstable; urgency=medium
* Non-maintainer upload.
--- a/debian/control Sat Dec 18 14:01:24 2010 +0000
+++ b/debian/control Sat Dec 18 14:10:46 2010 +0000
@@ -3,7 +3,7 @@
Priority: extra
Maintainer: Paul Crowley <paul@lshift.net>
Build-Depends: debhelper (>= 7.0.50~), python-support, xsltproc, docbook-xsl
-Standards-Version: 3.8.3
+Standards-Version: 3.9.1
Homepage: http://www.lshift.net/mercurial-server.html
Vcs-Browser: http://hg.opensource.lshift.net/mercurial-server/
Vcs-Hg: http://hg.opensource.lshift.net/mercurial-server/
--- a/debian/copyright Sat Dec 18 14:01:24 2010 +0000
+++ b/debian/copyright Sat Dec 18 14:10:46 2010 +0000
@@ -2,8 +2,8 @@
<paul@lshift.net> on Sat, 07 Mar 2009 10:12:02 +0000. Both the package and
the Debian packaging carry this copyright and license:
-Copyright 2008-2009 Paul Crowley <paul@lshift.net>
-Copyright 2008-2009 LShift Ltd.
+Copyright 2008-2010 Paul Crowley <paul@lshift.net>
+Copyright 2008-2010 LShift Ltd.
License:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/po/pt_BR.po Sat Dec 18 14:10:46 2010 +0000
@@ -0,0 +1,28 @@
+# Debconf translations for mercurial-server.
+# Copyright (C) 2009 THE mercurial-server'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the mercurial-server package.
+# Adriano Rafael Gomes <adrianorg@gmail.com>, 2009, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mercurial-server 1.0.1-1.1\n"
+"Report-Msgid-Bugs-To: mercurial-server@packages.debian.org\n"
+"POT-Creation-Date: 2009-12-02 18:14+0000\n"
+"PO-Revision-Date: 2010-11-13 21:02-0200\n"
+"Last-Translator: Adriano Rafael Gomes <adrianorg@gmail.com>\n"
+"Language-Team: Brazilian Portuguese <debian-l10n-portuguese@lists.debian."
+"org>\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"pt_BR utf-8\n"
+
+#. Type: boolean
+#. Description
+#: ../templates:1001
+msgid ""
+"Do you want the repositories to be removed when mercurial-server is purged?"
+msgstr ""
+"Você quer que os repositórios sejam removidos quando o mercurial-server for "
+"expurgado?"
--- a/debian/postrm Sat Dec 18 14:01:24 2010 +0000
+++ b/debian/postrm Sat Dec 18 14:10:46 2010 +0000
@@ -21,12 +21,9 @@
if remove_repositories_on_purge; then
echo -n "Removing hg user and purging data..."
deluser --remove-home --quiet --system hg > /dev/null || true
- else
- echo -n "Removing hg user..."
- deluser --quiet --system hg > /dev/null || true
+ delgroup --quiet --system hg > /dev/null || true
+ echo done
fi
- delgroup --quiet --system hg > /dev/null || true
- echo done
;;
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
--- a/debian/source/format Sat Dec 18 14:01:24 2010 +0000
+++ b/debian/source/format Sat Dec 18 14:10:46 2010 +0000
@@ -1,1 +1,1 @@
-1.0
+3.0 (quilt)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/action/go Sat Dec 18 14:10:46 2010 +0000
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+set -e
+
+cd action
+
+ls -l
+
+. ./testing_system
+
+#exec > results 2>&1
+
+aptitude --allow-untrusted --quiet --without-recommends --assume-yes install \
+ 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
+
+. ./install-installables
+
+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 /action/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/install-installables Sat Dec 18 14:10:46 2010 +0000
@@ -0,0 +1,4 @@
+aptitude --allow-untrusted --quiet --without-recommends --assume-yes install \
+ debconf python python-support adduser mercurial openssh-server
+dpkg -i *.deb
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/action/refresh-auth Sat Dec 18 14:10:46 2010 +0000
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -e
+
+/usr/share/mercurial-server/refresh-auth
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/action/test1 Sat Dec 18 14:10:46 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 Sat Dec 18 14:10:46 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 Sat Dec 18 14:10:46 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/copy-installables Sat Dec 18 14:10:46 2010 +0000
@@ -0,0 +1,2 @@
+cp build/debian/*.deb $BACKING/action
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/chroot-test/policy-rc.d Sat Dec 18 14:10:46 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 Sat Dec 18 14:10:46 2010 +0000
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# Must be root to run this
+
+set -e
+cd $(hg root)
+
+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
+
+BUILDDIR=$(pwd)/build
+mkdir -p $BUILDDIR/env
+BACKING=$BUILDDIR/env/backing
+MOUNT=$BUILDDIR/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/* $BUILDDIR/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
+
+SCRIPTS=dev/chroot-test
+
+cp -v $SCRIPTS/policy-rc.d $BACKING/etc/policy-rc.d
+
+mkdir -p $BACKING/var/cache/apt/archives
+echo "Copying deb files out of cache"
+cp $BUILDDIR/aptcache/$DEBVERSION/* $BACKING/var/cache/apt/archives || true
+
+cp -av $SCRIPTS/action $BACKING
+. $SCRIPTS/copy-installables
+
+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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dev/debian-build/dbuild Sat Dec 18 14:10:46 2010 +0000
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+set -e
+
+cd $(hg root)
+
+PACKAGE=$(dpkg-parsechangelog | sed -n 's/^Source: \(.*\)/\1/p')
+DEBIAN_VERSION=$(dpkg-parsechangelog | sed -n 's/^Version: \(.*\)/\1/p')
+# Lazy, but hey
+UPSTREAM_VERSION=$(dpkg-parsechangelog | sed -n 's/^Version: \(.*\)-[^-]*/\1/p')
+UPSTREAM=$(hg log --template '{node}' -r 'heads(ancestors(.) and branch(default))')
+BUILDDIR=$(pwd)/build/debian
+
+echo PACKAGE $PACKAGE
+echo DEBIAN_VERSION $DEBIAN_VERSION
+echo UPSTREAM_VERSION $UPSTREAM_VERSION
+echo UPSTREAM $UPSTREAM
+echo BUILDDIR $BUILDDIR
+
+rm -rf ${BUILDDIR}
+mkdir -p ${BUILDDIR}
+hg archive -X '.hg*' -X 'dev/**' -t tgz -r ${UPSTREAM} \
+ ${BUILDDIR}/${PACKAGE}_${UPSTREAM_VERSION}.orig.tar.gz
+hg st -mac0n -X '.hg*' -X 'dev/**' | cpio -p -0 -d \
+ ${BUILDDIR}/${PACKAGE}-${UPSTREAM_VERSION}
+
+cd ${BUILDDIR}/${PACKAGE}-${UPSTREAM_VERSION}
+#dpkg-buildpackage -kFD56DDC0
+dpkg-buildpackage
+cd ..
+lintian -i --pedantic -IE ${PACKAGE}_${DEBIAN_VERSION}_*.changes
+#sudo pbuilder --build ${PACKAGE}_${DEBIAN_VERSION}.dsc
+
--- a/doc/manual.docbook Sat Dec 18 14:01:24 2010 +0000
+++ b/doc/manual.docbook Sat Dec 18 14:10:46 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 18 14:01:24 2010 +0000
+++ b/setup.py Sat Dec 18 14:10:46 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 18 14:01:24 2010 +0000
+++ b/src/hg-ssh Sat Dec 18 14:10:46 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 18 14:01:24 2010 +0000
+++ b/src/mercurialserver/refreshauth.py Sat Dec 18 14:10:46 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 18 14:01:24 2010 +0000
+++ b/src/mercurialserver/servelog.py Sat Dec 18 14:10:46 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()