Repository: bradshjg/flask-githubapp

Issue:
Support X-Hub-Signature-256
We should prefer this header and probably fall back to the `X-Hub-Signature` header in the case that it's missing (in the case of maybe old Enterprise Server installations???)

I'm also a little conflicted about the current practice of requiring a secret to be set. I think there are probably legitimate use cases where a secret isn't needed and it makes some approaches to local dev and testing a bit more complicated. For now let's provide an interface to opt-out and give a more kind error message (right now I'm pretty sure we throw a relatively opaque `KeyError` 😞) in the case that the user has not opted out and the header is missing.

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9d7387b..dffcf2e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Changed
+- `GITHUBAPP_SECRET` can now be set to `False` to skip verifying the signature of
+the webhook payload.
+
+- The `X-Hub-Signature-256` header is now preferred for signature checking.
+Previously, `X-Hub-Signature` (and `sha1`) were used to verify the payload.
+
 ## [0.2.0]
 ### Added
 - This changelog.
@@ -23,4 +30,4 @@ The goal is to aid in debugging, as GitHub allows app owners to view hook respon
 
 
 [Unreleased]: https://github.com/bradshjg/flask-githubapp/compare/0.2.0...HEAD
-[0.2.0]: https://github.com/bradshjg/flask-githubapp/compare/0.1.0...0.2.0
\ No newline at end of file
+[0.2.0]: https://github.com/bradshjg/flask-githubapp/compare/0.1.0...0.2.0
diff --git a/README.md b/README.md
index 4afb175..f0ef049 100644
--- a/README.md
+++ b/README.md
@@ -98,7 +98,8 @@ outside a hook context).
 
 `GITHUBAPP_KEY`: Private key used to sign access token requests as bytes or utf-8 encoded string (required). Default: None
 
-`GITHUBAPP_SECRET`: Secret used to secure webhooks as bytes or utf-8 encoded string (required). Default: None
+`GITHUBAPP_SECRET`: Secret used to secure webhooks as bytes or utf-8 encoded string (required). Set to `False` to disable
+verification.
 
 `GITHUBAPP_URL`: URL of GitHub instance (used for GitHub Enterprise) as a string. Default: None
 
diff --git a/flask_githubapp/core.py b/flask_githubapp/core.py
index bc78d83..34af98f 100644
--- a/flask_githubapp/core.py
+++ b/flask_githubapp/core.py
@@ -44,7 +44,8 @@ class GitHubApp(object):
 
         `GITHUBAPP_SECRET`:
 
-            Secret used to secure webhooks as bytes or utf-8 encoded string (required).
+            Secret used to secure webhooks as bytes or utf-8 encoded string (required). set to `False` to disable
+            verification (not recommended for production).
             Default: None
 
         `GITHUBAPP_URL`:
@@ -59,7 +60,7 @@ class GitHubApp(object):
         """
         required_settings = ['GITHUBAPP_ID', 'GITHUBAPP_KEY', 'GITHUBAPP_SECRET']
         for setting in required_settings:
-            if not app.config.get(setting):
+            if not setting in app.config:
                 raise RuntimeError("Flask-GitHubApp requires the '%s' config var to be set" % setting)
 
         app.add_url_rule(app.config.get('GITHUBAPP_ROUTE', '/'),
@@ -169,7 +170,8 @@ class GitHubApp(object):
         event = request.headers['X-GitHub-Event']
         action = request.json.get('action')
 
-        self._verify_webhook()
+        if current_app.config['GITHUBAPP_SECRET'] is not False:
+            self._verify_webhook()
 
         if event in self._hook_mappings:
             functions_to_call += self._hook_mappings[event]
@@ -189,9 +191,21 @@ class GitHubApp(object):
                         'calls': calls})
 
     def _verify_webhook(self):
-        signature = request.headers['X-Hub-Signature'].split('=')[1]
+        signature_header ='X-Hub-Signature-256'
+        signature_header_legacy = 'X-Hub-Signature'
+
+        if request.headers.get(signature_header):
+            signature = request.headers[signature_header].split('=')[1]
+            digestmod = 'sha256'
+        elif request.headers.get(signature_header_legacy):
+            signature = request.headers[signature_header_legacy].split('=')[1]
+            digestmod = 'sha1'
+        else:
+            LOG.warning('Signature header missing. Configure your GitHub App with a secret or set GITHUBAPP_SECRET'
+                        'to False to disable verification.')
+            abort(400)
 
-        mac = hmac.new(self.secret, msg=request.data, digestmod='sha1')
+        mac = hmac.new(self.secret, msg=request.data, digestmod=digestmod)
 
         if not hmac.compare_digest(mac.hexdigest(), signature):
             LOG.warning('GitHub hook signature verification failed.')


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index 9543e06..1950624 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -2,6 +2,8 @@ import pytest
 
 from flask import Flask
 
+from flask_githubapp import GitHubApp
+
 
 @pytest.fixture
 def app():
@@ -9,4 +11,22 @@ def app():
     app.config['GITHUBAPP_ID'] = 1
     app.config['GITHUBAPP_KEY'] = 'key'
     app.config['GITHUBAPP_SECRET'] = 'secret'
-    return app
\ No newline at end of file
+    return app
+
+@pytest.fixture
+def github_app(app):
+    github_app = GitHubApp(app)
+
+    @github_app.on('issues')
+    def test_issue():
+        return 'issue event'
+
+    @github_app.on('issues.edited')
+    def test_issue_edited():
+        return 'issue edited action'
+
+    @github_app.on('push')
+    def test_push():
+        return 'push event'
+
+    return app
diff --git a/tests/fixtures/issues_hook.json b/tests/fixtures/issues_hook.json
index b23edd3..b4cdc81 100644
--- a/tests/fixtures/issues_hook.json
+++ b/tests/fixtures/issues_hook.json
@@ -1,1 +1,247 @@
-{"action":"opened","issue":{"url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/issues/24","repository_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks","labels_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/issues/24/labels{/name}","comments_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/issues/24/comments","events_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/issues/24/events","html_url":"https://github.com/bradshjg/test-github-app-hooks/issues/24","id":394496214,"node_id":"MDU6SXNzdWUzOTQ0OTYyMTQ=","number":24,"title":"integration testing","user":{"login":"bradshjg","id":916017,"node_id":"MDQ6VXNlcjkxNjAxNw==","avatar_url":"https://avatars0.githubusercontent.com/u/916017?v=4","gravatar_id":"","url":"https://api.github.com/users/bradshjg","html_url":"https://github.com/bradshjg","followers_url":"https://api.github.com/users/bradshjg/followers","following_url":"https://api.github.com/users/bradshjg/following{/other_user}","gists_url":"https://api.github.com/users/bradshjg/gists{/gist_id}","starred_url":"https://api.github.com/users/bradshjg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bradshjg/subscriptions","organizations_url":"https://api.github.com/users/bradshjg/orgs","repos_url":"https://api.github.com/users/bradshjg/repos","events_url":"https://api.github.com/users/bradshjg/events{/privacy}","received_events_url":"https://api.github.com/users/bradshjg/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-12-27T21:58:45Z","updated_at":"2018-12-27T21:58:45Z","closed_at":null,"author_association":"OWNER","body":""},"repository":{"id":163124770,"node_id":"MDEwOlJlcG9zaXRvcnkxNjMxMjQ3NzA=","name":"test-github-app-hooks","full_name":"bradshjg/test-github-app-hooks","private":false,"owner":{"login":"bradshjg","id":916017,"node_id":"MDQ6VXNlcjkxNjAxNw==","avatar_url":"https://avatars0.githubusercontent.com/u/916017?v=4","gravatar_id":"","url":"https://api.github.com/users/bradshjg","html_url":"https://github.com/bradshjg","followers_url":"https://api.github.com/users/bradshjg/followers","following_url":"https://api.github.com/users/bradshjg/following{/other_user}","gists_url":"https://api.github.com/users/bradshjg/gists{/gist_id}","starred_url":"https://api.github.com/users/bradshjg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bradshjg/subscriptions","organizations_url":"https://api.github.com/users/bradshjg/orgs","repos_url":"https://api.github.com/users/bradshjg/repos","events_url":"https://api.github.com/users/bradshjg/events{/privacy}","received_events_url":"https://api.github.com/users/bradshjg/received_events","type":"User","site_admin":false},"html_url":"https://github.com/bradshjg/test-github-app-hooks","description":"test github app hooks","fork":false,"url":"https://api.github.com/repos/bradshjg/test-github-app-hooks","forks_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/forks","keys_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/teams","hooks_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/hooks","issue_events_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/issues/events{/number}","events_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/events","assignees_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/assignees{/user}","branches_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/branches{/branch}","tags_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/tags","blobs_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/git/refs{/sha}","trees_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/statuses/{sha}","languages_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/languages","stargazers_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/stargazers","contributors_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/contributors","subscribers_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/subscribers","subscription_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/subscription","commits_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/commits{/sha}","git_commits_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/git/commits{/sha}","comments_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/comments{/number}","issue_comment_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/issues/comments{/number}","contents_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/contents/{+path}","compare_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/merges","archive_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/downloads","issues_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/issues{/number}","pulls_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/pulls{/number}","milestones_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/milestones{/number}","notifications_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/labels{/name}","releases_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/releases{/id}","deployments_url":"https://api.github.com/repos/bradshjg/test-github-app-hooks/deployments","created_at":"2018-12-26T01:58:14Z","updated_at":"2018-12-26T02:00:21Z","pushed_at":"2018-12-26T02:00:19Z","git_url":"git://github.com/bradshjg/test-github-app-hooks.git","ssh_url":"git@github.com:bradshjg/test-github-app-hooks.git","clone_url":"https://github.com/bradshjg/test-github-app-hooks.git","svn_url":"https://github.com/bradshjg/test-github-app-hooks","homepage":null,"size":0,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":19,"license":null,"forks":0,"open_issues":19,"watchers":0,"default_branch":"master"},"sender":{"login":"bradshjg","id":916017,"node_id":"MDQ6VXNlcjkxNjAxNw==","avatar_url":"https://avatars0.githubusercontent.com/u/916017?v=4","gravatar_id":"","url":"https://api.github.com/users/bradshjg","html_url":"https://github.com/bradshjg","followers_url":"https://api.github.com/users/bradshjg/followers","following_url":"https://api.github.com/users/bradshjg/following{/other_user}","gists_url":"https://api.github.com/users/bradshjg/gists{/gist_id}","starred_url":"https://api.github.com/users/bradshjg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bradshjg/subscriptions","organizations_url":"https://api.github.com/users/bradshjg/orgs","repos_url":"https://api.github.com/users/bradshjg/repos","events_url":"https://api.github.com/users/bradshjg/events{/privacy}","received_events_url":"https://api.github.com/users/bradshjg/received_events","type":"User","site_admin":false},"installation":{"id":540027,"node_id":"MDIzOkludGVncmF0aW9uSW5zdGFsbGF0aW9uNTQwMDI3"}}
\ No newline at end of file
+{
+  "action": "edited",
+  "issue": {
+    "url": "https://api.github.com/repos/Codertocat/Hello-World/issues/1",
+    "repository_url": "https://api.github.com/repos/Codertocat/Hello-World",
+    "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/1/labels{/name}",
+    "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/1/comments",
+    "events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/1/events",
+    "html_url": "https://github.com/Codertocat/Hello-World/issues/1",
+    "id": 444500041,
+    "node_id": "MDU6SXNzdWU0NDQ1MDAwNDE=",
+    "number": 1,
+    "title": "Spelling error in the README file",
+    "user": {
+      "login": "Codertocat",
+      "id": 21031067,
+      "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/Codertocat",
+      "html_url": "https://github.com/Codertocat",
+      "followers_url": "https://api.github.com/users/Codertocat/followers",
+      "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+      "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+      "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+      "repos_url": "https://api.github.com/users/Codertocat/repos",
+      "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+      "type": "User",
+      "site_admin": false
+    },
+    "labels": [
+      {
+        "id": 1362934389,
+        "node_id": "MDU6TGFiZWwxMzYyOTM0Mzg5",
+        "url": "https://api.github.com/repos/Codertocat/Hello-World/labels/bug",
+        "name": "bug",
+        "color": "d73a4a",
+        "default": true
+      }
+    ],
+    "state": "open",
+    "locked": false,
+    "assignee": {
+      "login": "Codertocat",
+      "id": 21031067,
+      "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/Codertocat",
+      "html_url": "https://github.com/Codertocat",
+      "followers_url": "https://api.github.com/users/Codertocat/followers",
+      "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+      "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+      "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+      "repos_url": "https://api.github.com/users/Codertocat/repos",
+      "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+      "type": "User",
+      "site_admin": false
+    },
+    "assignees": [
+      {
+        "login": "Codertocat",
+        "id": 21031067,
+        "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+        "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+        "gravatar_id": "",
+        "url": "https://api.github.com/users/Codertocat",
+        "html_url": "https://github.com/Codertocat",
+        "followers_url": "https://api.github.com/users/Codertocat/followers",
+        "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+        "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+        "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+        "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+        "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+        "repos_url": "https://api.github.com/users/Codertocat/repos",
+        "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+        "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+        "type": "User",
+        "site_admin": false
+      }
+    ],
+    "milestone": {
+      "url": "https://api.github.com/repos/Codertocat/Hello-World/milestones/1",
+      "html_url": "https://github.com/Codertocat/Hello-World/milestone/1",
+      "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones/1/labels",
+      "id": 4317517,
+      "node_id": "MDk6TWlsZXN0b25lNDMxNzUxNw==",
+      "number": 1,
+      "title": "v1.0",
+      "description": "Add new space flight simulator",
+      "creator": {
+        "login": "Codertocat",
+        "id": 21031067,
+        "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+        "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+        "gravatar_id": "",
+        "url": "https://api.github.com/users/Codertocat",
+        "html_url": "https://github.com/Codertocat",
+        "followers_url": "https://api.github.com/users/Codertocat/followers",
+        "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+        "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+        "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+        "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+        "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+        "repos_url": "https://api.github.com/users/Codertocat/repos",
+        "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+        "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+        "type": "User",
+        "site_admin": false
+      },
+      "open_issues": 1,
+      "closed_issues": 0,
+      "state": "closed",
+      "created_at": "2019-05-15T15:20:17Z",
+      "updated_at": "2019-05-15T15:20:18Z",
+      "due_on": "2019-05-23T07:00:00Z",
+      "closed_at": "2019-05-15T15:20:18Z"
+    },
+    "comments": 0,
+    "created_at": "2019-05-15T15:20:18Z",
+    "updated_at": "2019-05-15T15:20:18Z",
+    "closed_at": null,
+    "author_association": "OWNER",
+    "body": "It looks like you accidently spelled 'commit' with two 't's."
+  },
+  "changes": {},
+  "repository": {
+    "id": 186853002,
+    "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=",
+    "name": "Hello-World",
+    "full_name": "Codertocat/Hello-World",
+    "private": false,
+    "owner": {
+      "login": "Codertocat",
+      "id": 21031067,
+      "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/Codertocat",
+      "html_url": "https://github.com/Codertocat",
+      "followers_url": "https://api.github.com/users/Codertocat/followers",
+      "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+      "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+      "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+      "repos_url": "https://api.github.com/users/Codertocat/repos",
+      "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+      "type": "User",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/Codertocat/Hello-World",
+    "description": null,
+    "fork": false,
+    "url": "https://api.github.com/repos/Codertocat/Hello-World",
+    "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks",
+    "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams",
+    "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks",
+    "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events",
+    "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags",
+    "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages",
+    "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers",
+    "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors",
+    "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers",
+    "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription",
+    "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges",
+    "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads",
+    "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}",
+    "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments",
+    "created_at": "2019-05-15T15:19:25Z",
+    "updated_at": "2019-05-15T15:19:27Z",
+    "pushed_at": "2019-05-15T15:20:13Z",
+    "git_url": "git://github.com/Codertocat/Hello-World.git",
+    "ssh_url": "git@github.com:Codertocat/Hello-World.git",
+    "clone_url": "https://github.com/Codertocat/Hello-World.git",
+    "svn_url": "https://github.com/Codertocat/Hello-World",
+    "homepage": null,
+    "size": 0,
+    "stargazers_count": 0,
+    "watchers_count": 0,
+    "language": null,
+    "has_issues": true,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": true,
+    "forks_count": 0,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 1,
+    "license": null,
+    "forks": 0,
+    "open_issues": 1,
+    "watchers": 0,
+    "default_branch": "master"
+  },
+  "sender": {
+    "login": "Codertocat",
+    "id": 21031067,
+    "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+    "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/Codertocat",
+    "html_url": "https://github.com/Codertocat",
+    "followers_url": "https://api.github.com/users/Codertocat/followers",
+    "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+    "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+    "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+    "repos_url": "https://api.github.com/users/Codertocat/repos",
+    "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+    "type": "User",
+    "site_admin": false
+  }
+}
diff --git a/tests/fixtures/push_hook.json b/tests/fixtures/push_hook.json
new file mode 100644
index 0000000..b9f7ca2
--- /dev/null
+++ b/tests/fixtures/push_hook.json
@@ -0,0 +1,134 @@
+{
+  "ref": "refs/tags/simple-tag",
+  "before": "6113728f27ae82c7b1a177c8d03f9e96e0adf246",
+  "after": "0000000000000000000000000000000000000000",
+  "created": false,
+  "deleted": true,
+  "forced": false,
+  "base_ref": null,
+  "compare": "https://github.com/Codertocat/Hello-World/compare/6113728f27ae...000000000000",
+  "commits": [],
+  "head_commit": null,
+  "repository": {
+    "id": 186853002,
+    "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=",
+    "name": "Hello-World",
+    "full_name": "Codertocat/Hello-World",
+    "private": false,
+    "owner": {
+      "name": "Codertocat",
+      "email": "21031067+Codertocat@users.noreply.github.com",
+      "login": "Codertocat",
+      "id": 21031067,
+      "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/Codertocat",
+      "html_url": "https://github.com/Codertocat",
+      "followers_url": "https://api.github.com/users/Codertocat/followers",
+      "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+      "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+      "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+      "repos_url": "https://api.github.com/users/Codertocat/repos",
+      "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+      "type": "User",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/Codertocat/Hello-World",
+    "description": null,
+    "fork": false,
+    "url": "https://github.com/Codertocat/Hello-World",
+    "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks",
+    "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams",
+    "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks",
+    "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events",
+    "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags",
+    "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages",
+    "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers",
+    "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors",
+    "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers",
+    "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription",
+    "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges",
+    "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads",
+    "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}",
+    "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments",
+    "created_at": 1557933565,
+    "updated_at": "2019-05-15T15:20:41Z",
+    "pushed_at": 1557933657,
+    "git_url": "git://github.com/Codertocat/Hello-World.git",
+    "ssh_url": "git@github.com:Codertocat/Hello-World.git",
+    "clone_url": "https://github.com/Codertocat/Hello-World.git",
+    "svn_url": "https://github.com/Codertocat/Hello-World",
+    "homepage": null,
+    "size": 0,
+    "stargazers_count": 0,
+    "watchers_count": 0,
+    "language": "Ruby",
+    "has_issues": true,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": true,
+    "forks_count": 1,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 2,
+    "license": null,
+    "forks": 1,
+    "open_issues": 2,
+    "watchers": 0,
+    "default_branch": "master",
+    "stargazers": 0,
+    "master_branch": "master"
+  },
+  "pusher": {
+    "name": "Codertocat",
+    "email": "21031067+Codertocat@users.noreply.github.com"
+  },
+  "sender": {
+    "login": "Codertocat",
+    "id": 21031067,
+    "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+    "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/Codertocat",
+    "html_url": "https://github.com/Codertocat",
+    "followers_url": "https://api.github.com/users/Codertocat/followers",
+    "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+    "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+    "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+    "repos_url": "https://api.github.com/users/Codertocat/repos",
+    "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+    "type": "User",
+    "site_admin": false
+  }
+}
diff --git a/tests/fixtures/release_hook.json b/tests/fixtures/release_hook.json
new file mode 100644
index 0000000..867099f
--- /dev/null
+++ b/tests/fixtures/release_hook.json
@@ -0,0 +1,156 @@
+{
+  "action": "published",
+  "release": {
+    "url": "https://api.github.com/repos/Codertocat/Hello-World/releases/17372790",
+    "assets_url": "https://api.github.com/repos/Codertocat/Hello-World/releases/17372790/assets",
+    "upload_url": "https://uploads.github.com/repos/Codertocat/Hello-World/releases/17372790/assets{?name,label}",
+    "html_url": "https://github.com/Codertocat/Hello-World/releases/tag/0.0.1",
+    "id": 17372790,
+    "node_id": "MDc6UmVsZWFzZTE3MzcyNzkw",
+    "tag_name": "0.0.1",
+    "target_commitish": "master",
+    "name": null,
+    "draft": false,
+    "author": {
+      "login": "Codertocat",
+      "id": 21031067,
+      "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/Codertocat",
+      "html_url": "https://github.com/Codertocat",
+      "followers_url": "https://api.github.com/users/Codertocat/followers",
+      "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+      "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+      "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+      "repos_url": "https://api.github.com/users/Codertocat/repos",
+      "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+      "type": "User",
+      "site_admin": false
+    },
+    "prerelease": false,
+    "created_at": "2019-05-15T15:19:25Z",
+    "published_at": "2019-05-15T15:20:53Z",
+    "assets": [],
+    "tarball_url": "https://api.github.com/repos/Codertocat/Hello-World/tarball/0.0.1",
+    "zipball_url": "https://api.github.com/repos/Codertocat/Hello-World/zipball/0.0.1",
+    "body": null
+  },
+  "repository": {
+    "id": 186853002,
+    "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=",
+    "name": "Hello-World",
+    "full_name": "Codertocat/Hello-World",
+    "private": false,
+    "owner": {
+      "login": "Codertocat",
+      "id": 21031067,
+      "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/Codertocat",
+      "html_url": "https://github.com/Codertocat",
+      "followers_url": "https://api.github.com/users/Codertocat/followers",
+      "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+      "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+      "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+      "repos_url": "https://api.github.com/users/Codertocat/repos",
+      "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+      "type": "User",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/Codertocat/Hello-World",
+    "description": null,
+    "fork": false,
+    "url": "https://api.github.com/repos/Codertocat/Hello-World",
+    "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks",
+    "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams",
+    "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks",
+    "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events",
+    "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags",
+    "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages",
+    "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers",
+    "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors",
+    "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers",
+    "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription",
+    "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges",
+    "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads",
+    "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}",
+    "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments",
+    "created_at": "2019-05-15T15:19:25Z",
+    "updated_at": "2019-05-15T15:20:41Z",
+    "pushed_at": "2019-05-15T15:20:52Z",
+    "git_url": "git://github.com/Codertocat/Hello-World.git",
+    "ssh_url": "git@github.com:Codertocat/Hello-World.git",
+    "clone_url": "https://github.com/Codertocat/Hello-World.git",
+    "svn_url": "https://github.com/Codertocat/Hello-World",
+    "homepage": null,
+    "size": 0,
+    "stargazers_count": 0,
+    "watchers_count": 0,
+    "language": "Ruby",
+    "has_issues": true,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": true,
+    "forks_count": 1,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 2,
+    "license": null,
+    "forks": 1,
+    "open_issues": 2,
+    "watchers": 0,
+    "default_branch": "master"
+  },
+  "sender": {
+    "login": "Codertocat",
+    "id": 21031067,
+    "node_id": "MDQ6VXNlcjIxMDMxMDY3",
+    "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/Codertocat",
+    "html_url": "https://github.com/Codertocat",
+    "followers_url": "https://api.github.com/users/Codertocat/followers",
+    "following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
+    "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
+    "organizations_url": "https://api.github.com/users/Codertocat/orgs",
+    "repos_url": "https://api.github.com/users/Codertocat/repos",
+    "events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/Codertocat/received_events",
+    "type": "User",
+    "site_admin": false
+  }
+}
diff --git a/tests/test_integration.py b/tests/test_integration.py
index 3e44e62..9d6a438 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -1,37 +1,50 @@
 import os
 
-from flask_githubapp import GitHubApp
-
 FIXURES_DIR = os.path.join(
     os.path.dirname(os.path.abspath(__file__)),
     'fixtures'
 )
 
 
-def test_issues_hook_valid_signature(app):
+def test_issues_hook_valid_legacy_signature(github_app):
+    """a valid webhook w/ legacy signature should return a 200 response with a valid response payload"""
     with open(os.path.join(FIXURES_DIR, 'issues_hook.json'), 'rb') as hook:
         issues_data = hook.read()
 
-    GitHubApp(app)
+    with github_app.test_client() as client:
+        resp = client.post('/',
+                           data=issues_data,
+                           headers={
+                               'Content-Type': 'application/json',
+                               'X-GitHub-Event': 'issues',
+                               'X-Hub-Signature': 'sha1=ad68425a164a7a06d4849a63163f15656810175b'
+                           })
+        assert resp.status_code == 200
+        assert resp.json == {'calls': {'test_issue': 'issue event', 'test_issue_edited': 'issue edited action'},
+                             'status': 'HIT'}
+
+def test_issues_hook_valid_signature(github_app):
+    """a valid webhook w/ signature should return a 200 response with a valid response payload"""
+    with open(os.path.join(FIXURES_DIR, 'issues_hook.json'), 'rb') as hook:
+        issues_data = hook.read()
 
-    with app.test_client() as client:
+    with github_app.test_client() as client:
         resp = client.post('/',
                            data=issues_data,
                            headers={
                                'Content-Type': 'application/json',
                                'X-GitHub-Event': 'issues',
-                               'X-Hub-Signature': 'sha1=85d20eda7a4e518f956b99f432b1225de8516e56'
+                               'X-Hub-Signature-256': 'sha256=5700c0515bec05804df657c3ebbf5f9585701a9f0a2a5633ca2d6dbd375a63a2'
                            })
         assert resp.status_code == 200
+        assert resp.json == {'calls': {'test_issue': 'issue event', 'test_issue_edited': 'issue edited action'}, 'status': 'HIT'}
 
 
-def test_issues_hook_invalid_signature(app):
+def test_issues_hook_invalid_legacy_signature(github_app):
     with open(os.path.join(FIXURES_DIR, 'issues_hook.json'), 'rb') as hook:
         issues_data = hook.read()
 
-    GitHubApp(app)
-
-    with app.test_client() as client:
+    with github_app.test_client() as client:
         resp = client.post('/',
                            data=issues_data,
                            headers={
@@ -40,3 +53,85 @@ def test_issues_hook_invalid_signature(app):
                                'X-Hub-Signature': 'sha1=badhash'
                            })
         assert resp.status_code == 400
+
+
+def test_issues_hook_invalid_signature(github_app):
+    with open(os.path.join(FIXURES_DIR, 'issues_hook.json'), 'rb') as hook:
+        issues_data = hook.read()
+
+    with github_app.test_client() as client:
+        resp = client.post('/',
+                           data=issues_data,
+                           headers={
+                               'Content-Type': 'application/json',
+                               'X-GitHub-Event': 'issues',
+                               'X-Hub-Signature': 'sha256=badhash'
+                           })
+        assert resp.status_code == 400
+
+
+def test_issues_hook_missing_signature(github_app):
+    """Return 400 response if the signature is missing and verification is enabled"""
+    with open(os.path.join(FIXURES_DIR, 'issues_hook.json'), 'rb') as hook:
+        issues_data = hook.read()
+
+    with github_app.test_client() as client:
+        resp = client.post('/',
+                           data=issues_data,
+                           headers={
+                               'Content-Type': 'application/json',
+                               'X-GitHub-Event': 'issues',
+                           })
+        assert resp.status_code == 400
+
+
+def test_issues_hook_verification_disabled_missing_signature(github_app):
+    """Return 200 response and valid payload if the signature is missing and verification has been disabled"""
+    with open(os.path.join(FIXURES_DIR, 'issues_hook.json'), 'rb') as hook:
+        issues_data = hook.read()
+
+    github_app.config['GITHUBAPP_SECRET'] = False
+
+    with github_app.test_client() as client:
+        resp = client.post('/',
+                           data=issues_data,
+                           headers={
+                               'Content-Type': 'application/json',
+                               'X-GitHub-Event': 'issues',
+                           })
+        assert resp.status_code == 200
+        assert resp.json == {'calls': {'test_issue': 'issue event', 'test_issue_edited': 'issue edited action'}, 'status': 'HIT'}
+
+def test_hook_without_action(github_app):
+    """Return a 200 response and valid payload for hooks without an action key"""
+    with open(os.path.join(FIXURES_DIR, 'push_hook.json'), 'rb') as hook:
+        issues_data = hook.read()
+
+    github_app.config['GITHUBAPP_SECRET'] = False
+
+    with github_app.test_client() as client:
+        resp = client.post('/',
+                           data=issues_data,
+                           headers={
+                               'Content-Type': 'application/json',
+                               'X-GitHub-Event': 'push',
+                           })
+        assert resp.status_code == 200
+        assert resp.json == {'calls': {'test_push': 'push event'}, 'status': 'HIT'}
+
+def test_hook_without_match(github_app):
+    """Return a 200 response and valid payload for hooks with no matches"""
+    with open(os.path.join(FIXURES_DIR, 'release_hook.json'), 'rb') as hook:
+        issues_data = hook.read()
+
+    github_app.config['GITHUBAPP_SECRET'] = False
+
+    with github_app.test_client() as client:
+        resp = client.post('/',
+                           data=issues_data,
+                           headers={
+                               'Content-Type': 'application/json',
+                               'X-GitHub-Event': 'release',
+                           })
+        assert resp.status_code == 200
+        assert resp.json == {'calls': {}, 'status': 'MISS'}