[PATCH STABLE] serve: move hg-ssh readonly logic into hg serve

Durham Goode durham at fb.com
Wed Apr 26 20:50:29 EDT 2017


# HG changeset patch
# User Durham Goode <durham at fb.com>
# Date 1493254201 25200
#      Wed Apr 26 17:50:01 2017 -0700
# Branch stable
# Node ID 5ea1bd9ca7795ef353efc73a8eb38b66c516d69b
# Parent  6e0368b6e0bb2aa5210daec091c0200583553a78
serve: move hg-ssh readonly logic into hg serve

Recently hg-ssh as changed to do in-memory hook configuration instead of passing
config hooks to block transactions, and dispatch blocks any invocation of hg
serve --stdio that has options passed. We have infrastructure that sets up read
only serve processes without using hg-ssh, and it was broken by this change.

Let's add a --read-only option to hg serve so non-hg-ssh solutions can still
launch hg in read-only mode. This makes it also work with non-stdio serve
processes as well.

diff --git a/contrib/hg-ssh b/contrib/hg-ssh
--- a/contrib/hg-ssh
+++ b/contrib/hg-ssh
@@ -32,7 +32,7 @@ command="hg-ssh --read-only repos/*"
 # enable importing on demand to reduce startup time
 from mercurial import demandimport; demandimport.enable()
 
-from mercurial import dispatch, ui as uimod
+from mercurial import dispatch
 
 import sys, os, shlex
 
@@ -61,14 +61,9 @@ def main():
         repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path)))
         if repo in allowed_paths:
             cmd = ['-R', repo, 'serve', '--stdio']
+            if readonly:
+                cmd.append('--read-only')
             req = dispatch.request(cmd)
-            if readonly:
-                if not req.ui:
-                    req.ui = uimod.ui.load()
-                req.ui.setconfig('hooks', 'pretxnopen.hg-ssh',
-                                 'python:__main__.rejectpush', 'hg-ssh')
-                req.ui.setconfig('hooks', 'prepushkey.hg-ssh',
-                                 'python:__main__.rejectpush', 'hg-ssh')
             dispatch.dispatch(req)
         else:
             sys.stderr.write('Illegal repository "%s"\n' % repo)
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -4619,8 +4619,9 @@ def root(ui, repo):
     ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
     ('', 'style', '', _('template style to use'), _('STYLE')),
     ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
-    ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
-     + subrepoopts,
+    ('', 'certificate', '', _('SSL certificate file'), _('FILE')),
+    ('', 'read-only', None, _('only allow read operations')),
+    ] + subrepoopts,
     _('[OPTION]...'),
     optionalrepo=True)
 def serve(ui, repo, **opts):
diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -214,6 +214,18 @@ def _runcatch(req):
             # it's not a command that server operators expect to
             # be safe to offer to users in a sandbox.
             pass
+
+        if realcmd == 'serve' and '--read-only' in req.args:
+            argindex = req.args.index('--read-only')
+            del req.args[argindex]
+
+            if not req.ui:
+                req.ui = uimod.ui.load()
+            req.ui.setconfig('hooks', 'pretxnopen.rejectpush',
+                             rejectpush, 'dispatch')
+            req.ui.setconfig('hooks', 'prepushkey.rejectpush',
+                             rejectpush, 'dispatch')
+
         if realcmd == 'serve' and '--stdio' in cmdargs:
             # We want to constrain 'hg serve --stdio' instances pretty
             # closely, as many shared-ssh access tools want to grant
@@ -993,3 +1005,9 @@ def handlecommandexception(ui):
     ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
     ui.warn(warning)
     return False  # re-raise the exception
+
+def rejectpush(ui, **kwargs):
+    ui.warn(("Permission denied\n"))
+    # mercurial hooks use unix process conventions for hook return values
+    # so a truthy return means failure
+    return True
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -181,6 +181,7 @@ Show the options for the "serve" command
   --prefix
   --profile
   --quiet
+  --read-only
   --repository
   --stdio
   --style
@@ -227,7 +228,7 @@ Show all commands + options
   pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
   push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
   remove: after, force, subrepos, include, exclude
-  serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, subrepos
+  serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, read-only, subrepos
   status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
   summary: remote
   update: clean, check, merge, date, rev, tool
diff --git a/tests/test-ssh-bundle1.t b/tests/test-ssh-bundle1.t
--- a/tests/test-ssh-bundle1.t
+++ b/tests/test-ssh-bundle1.t
@@ -410,9 +410,9 @@ Test hg-ssh in read-only mode:
   pushing to ssh://user@dummy/*/remote (glob)
   searching for changes
   remote: Permission denied
-  remote: abort: pretxnopen.hg-ssh hook failed
+  remote: abort: pretxnopen.rejectpush hook failed
   remote: Permission denied
-  remote: pushkey-abort: prepushkey.hg-ssh hook failed
+  remote: pushkey-abort: prepushkey.rejectpush hook failed
   updating 6c0482d977a3 to public failed!
   [1]
 
diff --git a/tests/test-ssh.t b/tests/test-ssh.t
--- a/tests/test-ssh.t
+++ b/tests/test-ssh.t
@@ -427,7 +427,7 @@ Test hg-ssh in read-only mode:
   pushing to ssh://user@dummy/*/remote (glob)
   searching for changes
   remote: Permission denied
-  remote: pretxnopen.hg-ssh hook failed
+  remote: pretxnopen.rejectpush hook failed
   abort: push failed on remote
   [255]
 


More information about the Mercurial-devel mailing list