# HG changeset patch
# User Gregory Szorc <gregory.szorc@gmail.com>
# Date 1510036361 28800
#      Mon Nov 06 22:32:41 2017 -0800
# Branch stable
# Node ID 1a314176da9c62e843e90d2e40b14ba6cd32c4cb
# Parent  bd725a71f274b37206b0bc776050a4d3336cde30
subrepo: use per-type config options to enable subrepos

We change subrepos.allowed from a list of allowed subrepo types to
a combination of a master switch and per-type boolean flag.

If the master switch is set, subrepos can be disabled wholesale.

If subrepos are globally enabled, then per-type options are
consulted. Mercurial repos are enabled by default. Everything else
is disabled by default.

---
 mercurial/help/config.txt   |   42 +++++++++++++++++++++++++++++++-----------
 mercurial/subrepo.py        |   18 ++++++++++++++++--
 tests/test-convert-git.t    |    2 +-
 tests/test-mq-subrepo-svn.t |    3 ++-
 tests/test-subrepo-git.t    |   22 +++++++---------------
 tests/test-subrepo-svn.t    |    4 ++--
 tests/test-subrepo.t        |   26 ++++++++++++++++++--------
 7 files changed, 77 insertions(+), 40 deletions(-)

--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -1108,20 +1108,40 @@ are applied in definition order.
 This section contains options that control the behavior of the
 subrepositories feature. See also :hg:`help subrepos`.
 
+Security note: auditing in Mercurial is known to be insufficient to
+prevent clone-time code execution with carefully constructed Git
+subrepos. It is unknown if a similar detect is present in Subversion
+subrepos. Both Git and Subversion subrepos are disabled by default
+out of security concerns. These subrepo types can be enabled using
+the respective options below.
+
 ``allowed``
-    List of subrepository types (hg, git, svn) allowed in the working
-    directory.
+    Whether subrepositories are allowed in the working directory.
+
+    When false, commands involving subrepositories (like :hg:`update`)
+    will fail for all subrepository types.
+    (default: true)
+
+``hg:allowed``
+    Whether Mercurial subrepositories are allowed in the working
+    directory. This option only has an effect if ``subrepos.allowed``
+    is true.
+    (default: true)
+
+``git:allowed``
+    Whether Git subrepositories are allowed in the working directory.
+    This option only has an effect if ``subrepos.allowed`` is true.
+
+    See the security note above before enabling Git subrepos.
+    (default: false)
 
-    When disallowed, any commands including :hg:`update` will fail if
-    subrepositories are involved.
+``svn:allowed``
+    Whether Subversion subrepositories are allowed in the working
+    directory. This option only has an effect if ``subrepos.allowed``
+    is true.
 
-    Security note: auditing in Mercurial is known to be insufficient
-    to prevent clone-time code execution with carefully constructed
-    Git subrepos. It is unknown if a similar defect is present in
-    Subversion subrepos, so both are disabled by default out of an
-    abundance of caution. Re-enable such subrepos via this setting
-    with caution.
-    (default: `hg`)
+    See the security note above before enabling Subversion subrepos.
+    (default: false)
 
 ``trusted``
 -----------
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -340,10 +340,24 @@ def _auditsubrepopath(repo, path):
     if repo.wvfs.islink(path):
         raise error.Abort(_("subrepo '%s' traverses symbolic link") % path)
 
+SUBREPO_ALLOWED_DEFAULTS = {
+    'hg': True,
+    'git': False,
+    'svn': False,
+}
+
 def _checktype(ui, kind):
-    if kind not in ui.configlist('subrepos', 'allowed', ['hg']):
-        raise error.Abort(_("subrepo type %s not allowed") % kind,
+    # subrepos.allowed is a master kill switch. If disabled, subrepos are
+    # disabled period.
+    if not ui.configbool('subrepos', 'allowed', True):
+        raise error.Abort(_('subrepos not enabled'),
+                          hint=_("see 'hg help config.subrepos' for details"))
+
+    default = SUBREPO_ALLOWED_DEFAULTS.get(kind, False)
+    if not ui.configbool('subrepos', '%s:allowed' % kind, default):
+        raise error.Abort(_('%s subrepos not allowed') % kind,
                           hint=_("see 'hg help config.subrepos' for details"))
+
     if kind not in types:
         raise error.Abort(_('unknown subrepo type %s') % kind)
 
--- a/tests/test-convert-git.t
+++ b/tests/test-convert-git.t
@@ -9,7 +9,7 @@
   $ echo 'hgext.graphlog =' >> $HGRCPATH
   $ cat >> $HGRCPATH <<EOF
   > [subrepos]
-  > allowed = hg, git
+  > git:allowed = true
   > EOF
   $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
   $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
--- a/tests/test-mq-subrepo-svn.t
+++ b/tests/test-mq-subrepo-svn.t
@@ -6,7 +6,8 @@
   $ echo "nodates=1" >> $HGRCPATH
   $ cat >> $HGRCPATH <<EOF
   > [subrepos]
-  > allowed = hg, svn
+  > allowed = true
+  > svn:allowed = true
   > EOF
 
 fn to create new repository, and cd into it
--- a/tests/test-subrepo-git.t
+++ b/tests/test-subrepo-git.t
@@ -39,7 +39,7 @@ add subrepo clone
 git subrepo is disabled by default
 
   $ hg commit -m 'new git subrepo'
-  abort: subrepo type git not allowed
+  abort: git subrepos not allowed
   (see 'hg help config.subrepos' for details)
   [255]
 
@@ -47,7 +47,7 @@ so enable it
 
   $ cat >> $HGRCPATH <<EOF
   > [subrepos]
-  > allowed = hg, git
+  > git:allowed = true
   > EOF
 
   $ hg commit -m 'new git subrepo'
@@ -100,30 +100,22 @@ clone root
 
 clone with subrepo disabled (update should fail)
 
-  $ hg clone t -U tc2 --config subrepos.allowed=
-  $ hg update -R tc2 --config subrepos.allowed=
-  abort: subrepo type git not allowed
+  $ hg clone t -U tc2 --config subrepos.allowed=false
+  $ hg update -R tc2 --config subrepos.allowed=false
+  abort: subrepos not enabled
   (see 'hg help config.subrepos' for details)
   [255]
   $ ls tc2
   a
 
-  $ hg clone t tc3 --config subrepos.allowed=
+  $ hg clone t tc3 --config subrepos.allowed=false
   updating to branch default
-  abort: subrepo type git not allowed
+  abort: subrepos not enabled
   (see 'hg help config.subrepos' for details)
   [255]
   $ ls tc3
   a
 
-  $ hg clone t tc4 --config subrepos.allowed=hg
-  updating to branch default
-  abort: subrepo type git not allowed
-  (see 'hg help config.subrepos' for details)
-  [255]
-  $ ls tc4
-  a
-
 update to previous substate
 
   $ cd tc
--- a/tests/test-subrepo-svn.t
+++ b/tests/test-subrepo-svn.t
@@ -66,7 +66,7 @@ add first svn sub with leading whitespac
 svn subrepo is disabled by default
 
   $ hg ci -m1
-  abort: subrepo type svn not allowed
+  abort: svn subrepos not allowed
   (see 'hg help config.subrepos' for details)
   [255]
 
@@ -74,7 +74,7 @@ so enable it
 
   $ cat >> $HGRCPATH <<EOF
   > [subrepos]
-  > allowed = hg, svn
+  > svn:allowed = true
   > EOF
 
   $ hg ci -m1
--- a/tests/test-subrepo.t
+++ b/tests/test-subrepo.t
@@ -288,30 +288,40 @@ clone
 
 clone with subrepo disabled (update should fail)
 
-  $ hg clone t -U tc2 --config subrepos.allowed=
-  $ hg update -R tc2 --config subrepos.allowed=
-  abort: subrepo type hg not allowed
+  $ hg clone t -U tc2 --config subrepos.allowed=false
+  $ hg update -R tc2 --config subrepos.allowed=false
+  abort: subrepos not enabled
   (see 'hg help config.subrepos' for details)
   [255]
   $ ls tc2
   a
 
-  $ hg clone t tc3 --config subrepos.allowed=
+  $ hg clone t tc3 --config subrepos.allowed=false
   updating to branch default
-  abort: subrepo type hg not allowed
+  abort: subrepos not enabled
   (see 'hg help config.subrepos' for details)
   [255]
   $ ls tc3
   a
 
-  $ hg clone t tc4 --config subrepos.allowed=git
-  updating to branch default
-  abort: subrepo type hg not allowed
+And again with just the hg type disabled
+
+  $ hg clone t -U tc4 --config subrepos.hg:allowed=false
+  $ hg update -R tc4 --config subrepos.hg:allowed=false
+  abort: hg subrepos not allowed
   (see 'hg help config.subrepos' for details)
   [255]
   $ ls tc4
   a
 
+  $ hg clone t tc5 --config subrepos.hg:allowed=false
+  updating to branch default
+  abort: hg subrepos not allowed
+  (see 'hg help config.subrepos' for details)
+  [255]
+  $ ls tc5
+  a
+
 push
 
   $ cd tc
