[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.17-1283-gcf603cf
eric at webkit.org
eric at webkit.org
Tue Jan 5 23:49:41 UTC 2010
The following commit has been merged in the webkit-1.1 branch:
commit 50f03a7fe7ae4465ab2b7e24cfeff20260192129
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