--- bz.py
+++ bz.py
@@ -31,46 +31,66 @@ _log = logging.getLogger(__name__)

 class Bugzilla(object):
     base_query = {
-        'query_format': 'advanced',
-        'emailreporter1': '1',
-        'emailtype1': 'exact',
+        "query_format": "advanced",
+        "emailreporter1": "1",
+        "emailtype1": "exact",
     }
-    bug_status_early = ['NEW', 'ASSIGNED']
+    bug_status_early = ["NEW", "ASSIGNED"]
     bug_status_open = bug_status_early + [
-        'MODIFIED', 'ON_DEV', 'ON_QA', 'VERIFIED', 'FAILS_QA',
-        'RELEASE_PENDING', 'POST']
-    bug_status_closed = ['CLOSED']
+        "MODIFIED",
+        "ON_DEV",
+        "ON_QA",
+        "VERIFIED",
+        "FAILS_QA",
+        "RELEASE_PENDING",
+        "POST",
+    ]
+    bug_status_closed = ["CLOSED"]

     new_bug = {
-        'op_sys': 'Unspecified',
-        'platform': 'Unspecified',
-        'bug_severity': 'unspecified',
+        "op_sys": "Unspecified",
+        "platform": "Unspecified",
+        "bug_severity": "unspecified",
     }

     def __init__(self, consumer, config):
         self.consumer = consumer
         self.config = config
-        default = 'https://partner-bugzilla.redhat.com'
-        url = self.config.get('url', default)
-        self.username = self.config['user']
-        password = self.config['password']
-        self.bugzilla = bugzilla.Bugzilla(
-            url=url, cookiefile=None, tokenfile=None)
+        default = "https://partner-bugzilla.redhat.com"
+        url = self.config.get("url", default)
+        self.username = self.config["user"]
+        password = self.config["password"]
+        api_key = self.config["api_key"]
+        _log.info("Using BZ URL %s" % url)
+
+        if api_key:
+            self.bugzilla = bugzilla.Bugzilla(
+                url=url, api_key=api_key, cookiefile=None, tokenfile=None
+            )
+        elif self.username and password:
+            self.bugzilla = bugzilla.Bugzilla(
+                url=url,
+                user=self.username,
+                password=password,
+                cookiefile=None,
+                tokenfile=None,
+            )
+        else:
+            self.bugzilla = bugzilla.Bugzilla(url=url, cookiefile=None, tokenfile=None)
+
         self.bugzilla.bug_autorefresh = True
-        _log.info("Logging in to %s" % url)
-        self.bugzilla.login(self.username, password)

-        self.base_query['product'] = self.config['product']
-        self.base_query['email1'] = self.config['user']
+        self.base_query["product"] = self.config["product"]
+        self.base_query["email1"] = self.config["user"]

-        self.new_bug['product'] = self.config['product']
+        self.new_bug["product"] = self.config["product"]
         if "keywords" in self.config:
-            self.new_bug['keywords'] = self.config['keywords']
-        self.new_bug['version'] = self.config['version']
-        self.new_bug['status'] = self.config['bug_status']
+            self.new_bug["keywords"] = self.config["keywords"]
+        self.new_bug["version"] = self.config["version"]
+        self.new_bug["status"] = self.config["bug_status"]

-        self.short_desc_template = self.config['short_desc_template']
-        self.description_template = self.config['description_template']
+        self.short_desc_template = self.config["short_desc_template"]
+        self.description_template = self.config["description_template"]

     def handle(self, projectid, package, upstream, version, release, url):
         """ Main API entry point.  Push updates to bugzilla.
@@ -82,22 +102,21 @@ class Bugzilla(object):
         - There is no bug and we need to file one.
         """
         kwargs = copy.copy(self.config)
-        kwargs.update(dict(
-            projectid=projectid,
-            package=package,
-            name=package,
-            version=version,
-            release=release,
-
-            repo_name=self.consumer.repoid,
-            repo_version=version,
-            repo_release=release,
-
-            upstream=upstream,
-            latest_upstream=upstream,
-
-            url=url,
-        ))
+        kwargs.update(
+            dict(
+                projectid=projectid,
+                package=package,
+                name=package,
+                version=version,
+                release=release,
+                repo_name=self.consumer.repoid,
+                repo_version=version,
+                repo_release=release,
+                upstream=upstream,
+                latest_upstream=upstream,
+                url=url,
+            )
+        )

         bug = self.exact_bug(**kwargs)
         if bug:
@@ -115,13 +134,7 @@ class Bugzilla(object):
         return bug

     def follow_up(self, text, bug):
-        update = {
-            'comment': {
-                'body': text,
-                'is_private': False,
-            },
-            'ids': [bug.bug_id],
-        }
+        update = {"comment": {"body": text, "is_private": False}, "ids": [bug.bug_id]}
         _log.debug("Following up on bug %r with %r" % (bug.bug_id, update))
         self.bugzilla._proxy.Bug.update(update)
         _log.info("Followed up on bug: %s" % bug.weburl)
@@ -133,21 +146,21 @@ class Bugzilla(object):
             _log.info("Attached file to bug: %s" % bug.weburl)

     def attach_log(self, filename, description, bug):
-        self._attach_file(filename, description, bug, content_type='text/plain')
+        self._attach_file(filename, description, bug, content_type="text/plain")

     def attach_patch(self, filename, description, bug):
         self._attach_file(filename, description, bug, is_patch=True)

     def ftbfs_bugs(self, name):
         """ Return all FTBFS bugs we find for a package """
-        short_desc_pattern = '%s: FTBFS in rawhide' % name
+        short_desc_pattern = "%s: FTBFS in rawhide" % name
         query = {
-            'component': name,
-            'bug_status': self.bug_status_open,
-            'short_desc': short_desc_pattern,
-            'short_desc_type': 'substring',
-            'product': self.config['product'],
-            'query_format': 'advanced',
+            "component": name,
+            "bug_status": self.bug_status_open,
+            "short_desc": short_desc_pattern,
+            "short_desc_type": "substring",
+            "product": self.config["product"],
+            "query_format": "advanced",
         }
         bugs = self.bugzilla.query(query)
         bugs = bugs or []
@@ -160,14 +173,14 @@ class Bugzilla(object):

     def review_request_bugs(self, name):
         """ Return the review request bugs for a package. """
-        short_desc_pattern = ' %s ' % name
+        short_desc_pattern = " %s " % name
         query = {
-            'component': 'Package Review',
-            'bug_status': self.bug_status_open,
-            'short_desc': short_desc_pattern,
-            'short_desc_type': 'substring',
-            'product': self.config['product'],
-            'query_format': 'advanced',
+            "component": "Package Review",
+            "bug_status": self.bug_status_open,
+            "short_desc": short_desc_pattern,
+            "short_desc_type": "substring",
+            "product": self.config["product"],
+            "query_format": "advanced",
         }
         bugs = self.bugzilla.query(query)
         bugs = bugs or []
@@ -176,12 +189,12 @@ class Bugzilla(object):

     def exact_bug(self, **package):
         """ Return a particular upstream release ticket for a package. """
-        short_desc_pattern = '%(name)s-%(upstream)s ' % package
+        short_desc_pattern = "%(name)s-%(upstream)s " % package
         query = {
-            'component': package['name'],
-            'bug_status': self.bug_status_open + self.bug_status_closed,
-            'short_desc': short_desc_pattern,
-            'short_desc_type': 'substring',
+            "component": package["name"],
+            "bug_status": self.bug_status_open + self.bug_status_closed,
+            "short_desc": short_desc_pattern,
+            "short_desc_type": "substring",
         }

         query.update(self.base_query)
@@ -198,13 +211,10 @@ class Bugzilla(object):
         """ Return any upstream release ticket for a package. """
         # We'll match bugs in the NEW or ASSIGNED state
         # https://github.com/fedora-infra/the-new-hotness/issues/58
-        possible_statuses = list(set(
-            self.bug_status_early + [self.config['bug_status']]
-        ))
-        query = {
-            'component': [package['name']],
-            'bug_status': possible_statuses,
-        }
+        possible_statuses = list(
+            set(self.bug_status_early + [self.config["bug_status"]])
+        )
+        query = {"component": [package["name"]], "bug_status": possible_statuses}

         query.update(self.base_query)
         bugs = self.bugzilla.query(query)
@@ -218,17 +228,17 @@ class Bugzilla(object):
         # short_desc should be '<name>-<version> <some text>'
         # To extract the version get everything before the first space
         # with split and then remove the name and '-' via slicing
-        bug_version = short_desc.split(" ")[0][len(package['name']) + 1:]
+        bug_version = short_desc.split(" ")[0][len(package["name"]) + 1 :]

-        _log.info("Comparing %r, %r" % (bug_version, package['upstream']))
-        if bug_version != package['upstream']:
+        _log.info("Comparing %r, %r" % (bug_version, package["upstream"]))
+        if bug_version != package["upstream"]:
             update = {
-                'summary': self.short_desc_template % package,
-                'comment': {
-                    'body': self.description_template % package,
-                    'is_private': False,
+                "summary": self.short_desc_template % package,
+                "comment": {
+                    "body": self.description_template % package,
+                    "is_private": False,
                 },
-                'ids': [bug.bug_id],
+                "ids": [bug.bug_id],
             }
             _log.debug("Updating bug %r with %r" % (bug.bug_id, update))
             res = self.bugzilla._proxy.Bug.update(update)
@@ -236,26 +246,28 @@ class Bugzilla(object):
             _log.info("Updated bug: %s" % bug.weburl)
             return True
         else:
-            _log.warn("They are the same, which is odd. %r == %r" % (
-                bug_version, package['upstream']))
+            _log.warn(
+                "They are the same, which is odd. %r == %r"
+                % (bug_version, package["upstream"])
+            )
             return False

     def create_bug(self, **package):
         bug_dict = {
-            'component': package['name'],
-            'short_desc': self.short_desc_template % package,
-            'description': self.description_template % package,
+            "component": package["name"],
+            "short_desc": self.short_desc_template % package,
+            "description": self.description_template % package,
         }
         bug_dict.update(self.new_bug)
         new_bug = self.bugzilla.createbug(**bug_dict)
         change_status = None
         _log.info("Created bug: %s" % new_bug)

-        if new_bug.bug_status != self.config['bug_status']:
+        if new_bug.bug_status != self.config["bug_status"]:
             change_status = self.bugzilla._proxy.bugzilla.changeStatus(
                 new_bug.bug_id,
-                self.config['bug_status'],
-                self.config['user'],
+                self.config["bug_status"],
+                self.config["user"],
                 "",
                 "",
                 False,
