[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

eric at webkit.org eric at webkit.org
Thu Apr 8 00:36:20 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 8880aec558083ea4517575f7a532b52309eefd84
Author: eric at webkit.org <eric at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Dec 15 06:00:55 2009 +0000

    2009-12-14  Eric Seidel  <eric at webkit.org>
    
            Reviewed by Adam Barth.
    
            Move Credential handling out into a separate module
            https://bugs.webkit.org/show_bug.cgi?id=32531
    
            * Scripts/modules/bugzilla.py:
            * Scripts/modules/credentials.py: Added.
            * Scripts/modules/credentials_unittest.py: Added.
            * Scripts/run-webkit-unittests:
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@52135 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index f4c6a9e..9883bb1 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,3 +1,15 @@
+2009-12-14  Eric Seidel  <eric at webkit.org>
+
+        Reviewed by Adam Barth.
+
+        Move Credential handling out into a separate module
+        https://bugs.webkit.org/show_bug.cgi?id=32531
+
+        * Scripts/modules/bugzilla.py:
+        * Scripts/modules/credentials.py: Added.
+        * Scripts/modules/credentials_unittest.py: Added.
+        * Scripts/run-webkit-unittests:
+
 2009-12-14  Adam Barth  <abarth at webkit.org>
 
         Unreviewed.  Address reviewer comments from an earlier patch.  I didn't
diff --git a/WebKitTools/Scripts/modules/bugzilla.py b/WebKitTools/Scripts/modules/bugzilla.py
index be78544..a5673aa 100644
--- a/WebKitTools/Scripts/modules/bugzilla.py
+++ b/WebKitTools/Scripts/modules/bugzilla.py
@@ -29,8 +29,6 @@
 #
 # WebKit's Python module for interacting with Bugzilla
 
-import getpass
-import platform
 import re
 import subprocess
 import urllib2
@@ -40,6 +38,7 @@ from datetime import datetime # used in timestamp()
 # Import WebKit-specific modules.
 from modules.logging import error, log
 from modules.committers import CommitterList
+from modules.credentials import Credentials
 
 # WebKit includes a built copy of BeautifulSoup in Scripts/modules
 # so this import should always succeed.
@@ -59,39 +58,6 @@ http://wwwsearch.sourceforge.net/mechanize/
 """
     exit(1)
 
-def credentials_from_git():
-    return [read_config("username"), read_config("password")]
-
-def credentials_from_keychain(username=None):
-    if not is_mac_os_x():
-        return [username, None]
-
-    command = "/usr/bin/security %s -g -s %s" % ("find-internet-password", Bugzilla.bug_server_host)
-    if username:
-        command += " -a %s" % username
-
-    log('Reading Keychain for %s account and password.  Click "Allow" to continue...' % Bugzilla.bug_server_host)
-    keychain_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
-    value = keychain_process.communicate()[0]
-    exit_code = keychain_process.wait()
-
-    if exit_code:
-        return [username, None]
-
-    match = re.search('^\s*"acct"<blob>="(?P<username>.+)"', value, re.MULTILINE)
-    if match:
-        username = match.group('username')
-
-    password = None
-    match = re.search('^password: "(?P<password>.+)"', value, re.MULTILINE)
-    if match:
-        password = match.group('password')
-
-    return [username, password]
-
-def is_mac_os_x():
-    return platform.mac_ver()[0]
-
 def parse_bug_id(message):
     match = re.search("http\://webkit\.org/b/(?P<bug_id>\d+)", message)
     if match:
@@ -101,29 +67,6 @@ def parse_bug_id(message):
         return int(match.group('bug_id'))
     return None
 
-# FIXME: This should not depend on git for config storage
-def read_config(key):
-    # Need a way to read from svn too
-    config_process = subprocess.Popen("git config --get bugzilla.%s" % key, stdout=subprocess.PIPE, shell=True)
-    value = config_process.communicate()[0]
-    return_code = config_process.wait()
-
-    if return_code:
-        return None
-    return value.rstrip('\n')
-
-def read_credentials():
-    (username, password) = credentials_from_git()
-
-    if not username or not password:
-        (username, password) = credentials_from_keychain(username)
-
-    if not username:
-        username = raw_input("Bugzilla login: ")
-    if not password:
-        password = getpass.getpass("Bugzilla password for %s: " % username)
-
-    return [username, password]
 
 def timestamp():
     return datetime.now().strftime("%Y%m%d%H%M%S")
@@ -133,7 +76,7 @@ class BugzillaError(Exception):
     pass
 
 
-class Bugzilla:
+class Bugzilla(object):
     def __init__(self, dryrun=False, committers=CommitterList()):
         self.dryrun = dryrun
         self.authenticated = False
@@ -370,7 +313,7 @@ class Bugzilla:
             self.authenticated = True
             return
 
-        (username, password) = read_credentials()
+        (username, password) = Credentials(self.bug_server_host, git_prefix="bugzilla").read_credentials()
 
         log("Logging in as %s..." % username)
         self.browser.open(self.bug_server_url + "index.cgi?GoAheadAndLogIn=1")
diff --git a/WebKitTools/Scripts/modules/credentials.py b/WebKitTools/Scripts/modules/credentials.py
new file mode 100644
index 0000000..2226228
--- /dev/null
+++ b/WebKitTools/Scripts/modules/credentials.py
@@ -0,0 +1,91 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# 
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Python module for reading stored web credentials from the OS.
+
+import getpass
+import platform
+import re
+
+from modules.executive import Executive
+from modules.logging import log
+
+class Credentials(object):
+    def __init__(self, host, git_prefix=None, executive=None):
+        self.host = host
+        self.git_prefix = git_prefix
+        self.executive = executive or Executive()
+
+    def _credentials_from_git(self):
+        return [self._read_git_config("username"), self._read_git_config("password")]
+
+    def _read_git_config(self, key):
+        config_key = "%s.%s" % (self.git_prefix, key) if self.git_prefix else key
+        return self.executive.run_command(["git", "config", "--get", config_key], error_handler=Executive.ignore_error).rstrip('\n')
+
+    def _keychain_value_with_label(self, label, source_text):
+        match = re.search("%s\"(?P<value>.+)\"" % label, source_text, re.MULTILINE)
+        if match:
+            return match.group('value')
+
+    def _is_mac_os_x(self):
+        return platform.mac_ver()[0]
+
+    def _parse_security_tool_output(self, security_output):
+        username = self._keychain_value_with_label("^\s*\"acct\"<blob>=", security_output)
+        password = self._keychain_value_with_label("^password: ", security_output)
+        return [username, password]
+
+    def _run_security_tool(self, username=None):
+        security_command = ["/usr/bin/security", "find-internet-password", "-g", "-s", self.host]
+        if username:
+            security_command += ["-a", username]
+
+        log("Reading Keychain for %s account and password.  Click \"Allow\" to continue..." % self.host)
+        return self.executive.run_command(security_command)
+
+    def _credentials_from_keychain(self, username=None):
+        if not self._is_mac_os_x():
+            return [username, None]
+
+        security_output = self._run_security_tool(username)
+        return self._parse_security_tool_output(security_output)
+
+    def read_credentials(self):
+        (username, password) = self._credentials_from_git()
+
+        if not username or not password:
+            (username, password) = self._credentials_from_keychain(username)
+
+        if not username:
+            username = raw_input("%s login: " % self.host)
+        if not password:
+            password = getpass.getpass("%s password for %s: " % (self.host, username))
+
+        return [username, password]
diff --git a/WebKitTools/Scripts/modules/credentials_unittest.py b/WebKitTools/Scripts/modules/credentials_unittest.py
new file mode 100644
index 0000000..20d5bf3
--- /dev/null
+++ b/WebKitTools/Scripts/modules/credentials_unittest.py
@@ -0,0 +1,106 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#    * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#    * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#    * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+from modules.credentials import Credentials
+from modules.executive import Executive
+from modules.outputcapture import OutputCapture
+from modules.mock import Mock
+
+class CredentialsTest(unittest.TestCase):
+    example_security_output = """keychain: "/Users/test/Library/Keychains/login.keychain"
+class: "inet"
+attributes:
+    0x00000007 <blob>="bugs.webkit.org (test at webkit.org)"
+    0x00000008 <blob>=<NULL>
+    "acct"<blob>="test at webkit.org"
+    "atyp"<blob>="form"
+    "cdat"<timedate>=0x32303039303832353233353231365A00  "20090825235216Z\000"
+    "crtr"<uint32>=<NULL>
+    "cusi"<sint32>=<NULL>
+    "desc"<blob>="Web form password"
+    "icmt"<blob>="default"
+    "invi"<sint32>=<NULL>
+    "mdat"<timedate>=0x32303039303930393137323635315A00  "20090909172651Z\000"
+    "nega"<sint32>=<NULL>
+    "path"<blob>=<NULL>
+    "port"<uint32>=0x00000000 
+    "prot"<blob>=<NULL>
+    "ptcl"<uint32>="htps"
+    "scrp"<sint32>=<NULL>
+    "sdmn"<blob>=<NULL>
+    "srvr"<blob>="bugs.webkit.org"
+    "type"<uint32>=<NULL>
+password: "SECRETSAUCE"
+"""
+
+    def test_keychain_lookup_on_non_mac(self):
+        class FakeCredentials(Credentials):
+            def _is_mac_os_x(self):
+                return False
+        credentials = FakeCredentials("bugs.webkit.org")
+        self.assertEqual(credentials._is_mac_os_x(), False)
+        self.assertEqual(credentials._credentials_from_keychain("foo"), ["foo", None])
+
+    def test_security_output_parse(self):
+        credentials = Credentials("bugs.webkit.org")
+        self.assertEqual(credentials._parse_security_tool_output(self.example_security_output), ["test at webkit.org", "SECRETSAUCE"])
+
+    def _assert_security_call(self, username=None):
+        executive_mock = Mock()
+        credentials = Credentials("example.com", executive=executive_mock)
+
+        output = OutputCapture()
+        output.capture_output()
+        credentials._run_security_tool(username)
+        (stdout_output, stderr_output) = output.restore_output()
+        self.assertEqual(stdout_output, "")
+        self.assertEqual(stderr_output, "Reading Keychain for example.com account and password.  Click \"Allow\" to continue...\n")
+
+        security_args = ["/usr/bin/security", "find-internet-password", "-g", "-s", "example.com"]
+        if username:
+            security_args += ["-a", username]
+        executive_mock.run_command.assert_called_with(security_args)
+
+    def test_security_calls(self):
+        self._assert_security_call()
+        self._assert_security_call(username="foo")
+
+    def test_git_config_calls(self):
+        executive_mock = Mock()
+        credentials = Credentials("example.com", executive=executive_mock)
+        credentials._read_git_config("foo")
+        executive_mock.run_command.assert_called_with(["git", "config", "--get", "foo"], error_handler=Executive.ignore_error)
+
+        credentials = Credentials("example.com", git_prefix="test_prefix", executive=executive_mock)
+        credentials._read_git_config("foo")
+        executive_mock.run_command.assert_called_with(["git", "config", "--get", "test_prefix.foo"], error_handler=Executive.ignore_error)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/WebKitTools/Scripts/run-webkit-unittests b/WebKitTools/Scripts/run-webkit-unittests
index 3487299..5459168 100755
--- a/WebKitTools/Scripts/run-webkit-unittests
+++ b/WebKitTools/Scripts/run-webkit-unittests
@@ -37,6 +37,7 @@ from modules.commands.upload_unittest import *
 from modules.commands.queries_unittest import *
 from modules.commands.queues_unittest import *
 from modules.committers_unittest import *
+from modules.credentials_unittest import *
 from modules.cpp_style_unittest import *
 from modules.diff_parser_unittest import *
 from modules.logging_unittest import *

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list