configwizard: port file permissions checking (bug 1277406); r?glob draft
authorGregory Szorc <gps@mozilla.com>
Wed, 01 Jun 2016 16:28:30 -0700
changeset 8506 fa342d0d8b1de9a080f3d7bef69403648552f623
parent 8505 99f1ba59c1111b25549d461344298ef8d320471d
child 8507 ffb38f765f7087fa32b60ae047e6670da98c54b5
push id918
push userbmo:gps@mozilla.com
push dateThu, 09 Jun 2016 19:23:31 +0000
reviewersglob
bugs1277406
configwizard: port file permissions checking (bug 1277406); r?glob Almost a straight port. MozReview-Commit-ID: 4l3RQRMsHK3
hgext/configwizard/__init__.py
hgext/configwizard/hgsetup/wizard.py
hgext/configwizard/tests/test-permissions.t
--- a/hgext/configwizard/__init__.py
+++ b/hgext/configwizard/__init__.py
@@ -1,16 +1,17 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
 """Manage Mercurial configuration in a Mozilla-tailored way."""
 
 import difflib
 import io
 import os
+import stat
 import subprocess
 import sys
 import uuid
 
 from mercurial import (
     cmdutil,
     error,
     scmutil,
@@ -202,16 +203,25 @@ try syntax and pushes it to the try serv
 to be used in concert with other tools generating try syntax so that
 they can push to try without depending on mq or other workarounds.
 
 (Relevant config option: extensions.push-to-try)
 
 Would you like to activate push-to-try (Yn)? $$ &Yes $$ &No
 '''.strip()
 
+FILE_PERMISSIONS_WARNING = '''
+Your hgrc file is currently readable by others.
+
+Sensitive information such as your Bugzilla credentials could be
+stolen if others have access to this file/machine.
+
+Would you like to fix the file permissions (Yn) $$ &Yes $$ &No
+'''.strip()
+
 
 testedwith = '3.5 3.6 3.7 3.8'
 buglink = 'https://bugzilla.mozilla.org/enter_bug.cgi?product=Developer%20Services&component=General'
 
 cmdtable = {}
 command = cmdutil.command(cmdtable)
 
 wizardsteps = {
@@ -222,16 +232,17 @@ wizardsteps = {
     'historyediting',
     'fsmonitor',
     'wip',
     'security',
     'firefoxtree',
     'codereview',
     'pushtotry',
     'configchange',
+    'permissions',
 }
 
 @command('configwizard', [
     ('s', 'statedir', '', _('directory to store state')),
     ], _('hg configwizard'), optionalrepo=True)
 def configwizard(ui, repo, statedir=None, **opts):
     """Ensure your Mercurial configuration is up to date."""
     runsteps = set(wizardsteps)
@@ -280,17 +291,20 @@ def configwizard(ui, repo, statedir=None
 
     if 'codereview' in runsteps:
         _checkcodereview(ui, cw)
 
     if 'pushtotry' in runsteps:
         _promptvctextension(ui, cw, 'push-to-try', PUSHTOTRY_INFO)
 
     if 'configchange' in runsteps:
-        return _handleconfigchange(ui, cw)
+        _handleconfigchange(ui, cw)
+
+    if 'permissions' in runsteps:
+        _checkpermissions(ui, cw)
 
     return 0
 
 
 def _checkhgversion(ui, hgversion):
     if hgversion >= OLDEST_NON_LEGACY_VERSION:
         return
 
@@ -592,16 +606,34 @@ def _handleconfigchange(ui, cw):
             with open(cw.path, 'wb') as fh:
                 fh.write(newbuf.getvalue())
         else:
             ui.write('config changes not written; we would have written the following:\n')
             ui.write(newbuf.getvalue())
             return 1
 
 
+def _checkpermissions(ui, cw):
+    # Config file may contain sensitive content, such as API keys. Prompt to
+    # remove global permissions.
+    if sys.platform == 'win32':
+        return
+
+    mode = os.stat(cw.path).st_mode
+    if mode & (stat.S_IRWXG | stat.S_IRWXO):
+        if uipromptchoice(ui, FILE_PERMISSIONS_WARNING):
+            return
+
+        # We don't care about sticky and set UID bits because
+        # this is a regular file.
+        mode = mode & stat.S_IRWXU
+        ui.write('Changing permissions of %s\n' % cw.path)
+        os.chmod(cw.path, mode)
+
+
 class configobjwrapper(object):
     """Manipulate config files with ConfigObj.
 
     Mercurial doesn't support writing config files. ConfigObj does. ConfigObj
     also supports preserving comments in config files, which is user friendly.
 
     This class provides a mechanism to load and write config files with
     ConfigObj.
--- a/hgext/configwizard/hgsetup/wizard.py
+++ b/hgext/configwizard/hgsetup/wizard.py
@@ -4,17 +4,16 @@
 
 from __future__ import unicode_literals
 
 import difflib
 import errno
 import os
 import shutil
 import ssl
-import stat
 import sys
 import subprocess
 
 from distutils.version import LooseVersion
 
 from configobj import ConfigObjError
 from StringIO import StringIO
 
@@ -27,23 +26,16 @@ from .config import (
     ParseException,
 )
 
 FINISHED = '''
 Your Mercurial should now be properly configured and recommended extensions
 should be up to date!
 '''.strip()
 
-FILE_PERMISSIONS_WARNING = '''
-Your hgrc file is currently readable by others.
-
-Sensitive information such as your Bugzilla credentials could be
-stolen if others have access to this file/machine.
-'''.strip()
-
 MULTIPLE_VCT = '''
 *** WARNING ***
 
 Multiple version-control-tools repositories are referenced in your
 Mercurial config. Extensions and other code within the
 version-control-tools repository could run with inconsistent results.
 
 Please manually edit the following file to reference a single
@@ -97,32 +89,16 @@ class MercurialSetupWizard(object):
 
             i = v.index('version-control-tools')
             vct = v[0:i + len('version-control-tools')]
             seen_vct.add(os.path.realpath(os.path.expanduser(vct)))
 
         if len(seen_vct) > 1:
             print(MULTIPLE_VCT % c.config_path)
 
-        # At this point the config should be finalized.
-
-        if sys.platform != 'win32':
-            # Config file may contain sensitive content, such as passwords.
-            # Prompt to remove global permissions.
-            mode = os.stat(config_path).st_mode
-            if mode & (stat.S_IRWXG | stat.S_IRWXO):
-                print(FILE_PERMISSIONS_WARNING)
-                if self._prompt_yn('Remove permissions for others to '
-                                   'read your hgrc file'):
-                    # We don't care about sticky and set UID bits because
-                    # this is a regular file.
-                    mode = mode & stat.S_IRWXU
-                    print('Changing permissions of %s' % config_path)
-                    os.chmod(config_path, mode)
-
         print(FINISHED)
         return 0
 
     def can_use_extension(self, c, name, path=None):
         # Load extension to hg and search stdout for printed exceptions
         if not path:
             path = os.path.join(self.vcs_tools_dir, 'hgext', name)
         result = subprocess.check_output(['hg',
new file mode 100644
--- /dev/null
+++ b/hgext/configwizard/tests/test-permissions.t
@@ -0,0 +1,31 @@
+  $ . $TESTDIR/hgext/configwizard/tests/helpers.sh
+
+File permissions of hgrc should be updated when group or all read perms are set
+
+  $ touch .hgrc
+  $ chmod 664 .hgrc
+
+  $ hg --config configwizard.steps=configchange,permissions configwizard
+  This wizard will guide you through configuring Mercurial for an optimal
+  experience contributing to Mozilla projects.
+  
+  The wizard makes no changes without your permission.
+  
+  To begin, press the enter/return key.
+   <RETURN>
+  Your hgrc file is currently readable by others.
+  
+  Sensitive information such as your Bugzilla credentials could be
+  stolen if others have access to this file/machine.
+  
+  Would you like to fix the file permissions (Yn)  y
+  Changing permissions of $TESTTMP/.hgrc
+
+  $ hg --config configwizard.steps=configchange,permissions configwizard
+  This wizard will guide you through configuring Mercurial for an optimal
+  experience contributing to Mozilla projects.
+  
+  The wizard makes no changes without your permission.
+  
+  To begin, press the enter/return key.
+   <RETURN>