right_hook 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -9,6 +9,8 @@ Right Hook is a collection of tools to aid in setting up a web app to handle Git
9
9
 
10
10
  To see some example usage, head over to [right-hook/hookbooks](https://github.com/right-hook/hookbooks).
11
11
 
12
+ To see the documentation for the current version of the gem, visit [rubydoc.info](http://rubydoc.info/gems/right_hook).
13
+
12
14
  ## Installation
13
15
 
14
16
  Add this line to your application's Gemfile:
@@ -4,6 +4,8 @@ require 'json'
4
4
  require 'right_hook/event'
5
5
 
6
6
  module RightHook
7
+ # Inherit from this class and implement the on_issue, on_pull_request, etc. methods to
8
+ # configure how you respond to GitHub hooks.
7
9
  class App < Sinatra::Base
8
10
  post '/hook/:owner/:repo_name/:event_type' do
9
11
  owner = params[:owner]
@@ -27,6 +29,11 @@ module RightHook
27
29
  end
28
30
  end
29
31
 
32
+ # It is up to you to override secret to determine how to look up the correct secret for an owner/repo combo.
33
+ def secret(owner, repo_name, event_type)
34
+ raise NotImplementedError, "You didn't specify how to find the secret for a repo!"
35
+ end
36
+
30
37
  private
31
38
  def require_valid_signature(content, owner, repo_name, event_type)
32
39
  s = secret(owner, repo_name, event_type)
@@ -0,0 +1,28 @@
1
+ require 'openssl'
2
+ require 'uri'
3
+
4
+ module RightHook
5
+ # Helpers for specs!
6
+ # Typical usage is to include this module into your spec context, just like you would with Rack::Test::Methods.
7
+ module SpecHelpers
8
+ # Post to the given path, including the correct signature header based on the payload and secret.
9
+ # @param [Hash] opts The options to use when crafting the request.
10
+ # @option opts [String] :path The full path of the endpoint to which to post
11
+ # @option opts [String] :payload A JSON-parseable string containing a payload as described in http://developer.github.com/v3/activity/events/types/
12
+ # @option opts [String] :secret The secret to use when calculating the HMAC for the X-Hub-Signature header
13
+ def post_with_signature(opts)
14
+ path = opts.fetch(:path)
15
+ payload = opts.fetch(:payload)
16
+ secret = opts.fetch(:secret)
17
+
18
+ post path, {payload: payload}, generate_secret_header(secret, URI.encode_www_form(payload: payload))
19
+ end
20
+
21
+ # :nodoc:
22
+ def generate_secret_header(secret, body)
23
+ sha = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha1'), secret, body)
24
+ # GitHub sends it as 'X-Hub-Signature', but Rack provides it as HTTP_X_HUB_SIGNATURE... :/
25
+ {'HTTP_X_HUB_SIGNATURE' => "sha1=#{sha}"}
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module RightHook
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -1,10 +1,7 @@
1
1
  require 'spec_helper'
2
- require 'rack/test'
3
2
 
4
3
  describe RightHook::App do
5
4
  describe 'Issues' do
6
- include Rack::Test::Methods
7
-
8
5
  class IssueApp < RightHook::App
9
6
  class << self
10
7
  attr_accessor :owner, :repo_name, :action, :issue_json
@@ -31,9 +28,7 @@ describe RightHook::App do
31
28
  end
32
29
 
33
30
  it 'captures the interesting data' do
34
- post '/ignore', {payload: ISSUE_JSON}
35
- body = last_request.body.read
36
- post '/hook/mark-rushakoff/right_hook/issue', {payload: ISSUE_JSON}, generate_secret_header('issue', body)
31
+ post_with_signature(path: '/hook/mark-rushakoff/right_hook/issue', payload: ISSUE_JSON, secret: 'issue')
37
32
  expect(last_response.status).to eq(200)
38
33
  expect(app.owner).to eq('mark-rushakoff')
39
34
  expect(app.repo_name).to eq('right_hook')
@@ -44,7 +39,7 @@ describe RightHook::App do
44
39
  end
45
40
 
46
41
  it 'fails when the secret is wrong' do
47
- post '/hook/mark-rushakoff/right_hook/issue', {payload: ISSUE_JSON}, generate_secret_header('wrong', 'stuff')
42
+ post_with_signature(path: '/hook/mark-rushakoff/right_hook/issue', payload: ISSUE_JSON, secret: 'wrong')
48
43
  expect(last_response.status).to eq(202)
49
44
  expect(app.owner).to be_nil
50
45
  end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'rack/test'
3
2
 
4
3
  describe RightHook::App do
5
4
  describe 'Pull requests' do
@@ -32,9 +31,7 @@ describe RightHook::App do
32
31
  end
33
32
 
34
33
  it 'captures the interesting data' do
35
- post '/ignore', {payload: PULL_REQUEST_JSON}
36
- body = last_request.body.read
37
- post '/hook/mark-rushakoff/right_hook/pull_request', {payload: PULL_REQUEST_JSON}, generate_secret_header('pull_request', body)
34
+ post_with_signature(path: '/hook/mark-rushakoff/right_hook/pull_request', payload: PULL_REQUEST_JSON, secret: 'pull_request')
38
35
  expect(last_response.status).to eq(200)
39
36
  expect(app.owner).to eq('mark-rushakoff')
40
37
  expect(app.repo_name).to eq('right_hook')
@@ -46,7 +43,7 @@ describe RightHook::App do
46
43
  end
47
44
 
48
45
  it 'fails when the secret is wrong' do
49
- post '/hook/mark-rushakoff/right_hook/pull_request', {payload: PULL_REQUEST_JSON}, generate_secret_header('wrong', 'stuff')
46
+ post_with_signature(path: '/hook/mark-rushakoff/right_hook/pull_request', payload: PULL_REQUEST_JSON, secret: 'wrong')
50
47
  expect(last_response.status).to eq(202)
51
48
  expect(app.owner).to be_nil
52
49
  end
data/spec/app_spec.rb CHANGED
@@ -1,9 +1,6 @@
1
1
  require 'spec_helper'
2
- require 'rack/test'
3
2
 
4
3
  describe RightHook::App do
5
- include Rack::Test::Methods
6
-
7
4
  class BareApp < RightHook::App
8
5
  def secret(owner, repo_name, event_type)
9
6
  ''
@@ -15,12 +12,16 @@ describe RightHook::App do
15
12
  end
16
13
 
17
14
  it 'is status 501 for a non-implemented hook' do
18
- post '/hook/mark-rushakoff/right_hook/issue', '{}', generate_secret_header('secret', '{}')
15
+ post_with_signature(path: '/hook/mark-rushakoff/right_hook/issue', payload: '{}', secret: '')
19
16
  expect(last_response.status).to eq(501)
20
17
  end
21
18
 
22
19
  it 'is 404 for an unknown hook' do
23
- post '/hook/mark-rushakoff/right_hook/foobar', '{}', generate_secret_header('secret', '{}')
20
+ post_with_signature(path: '/hook/mark-rushakoff/right_hook/not_a_real_thing', payload: '{}', secret: '')
24
21
  expect(last_response.status).to eq(404)
25
22
  end
23
+
24
+ it 'raises NotImplementedError for an unimplemented secret' do
25
+ expect { RightHook::App.new!.secret('owner', 'repo', 'issue') }.to raise_error(NotImplementedError)
26
+ end
26
27
  end
data/spec/spec_helper.rb CHANGED
@@ -1,19 +1,19 @@
1
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
1
  require 'right_hook'
3
2
  require 'right_hook/app'
4
3
  require 'right_hook/authenticated_client'
5
4
  require 'right_hook/authenticator'
6
5
  require 'right_hook/commenter'
7
6
  require 'right_hook/event'
7
+ require 'right_hook/spec_helpers'
8
8
  require 'right_hook/subscriber'
9
9
 
10
- require_relative './support/spec_helpers.rb'
11
-
12
10
  require 'webmock/rspec'
11
+ require 'rack/test'
13
12
 
14
13
  require 'coveralls'
15
14
  Coveralls.wear!
16
15
 
17
16
  RSpec.configure do |c|
17
+ c.include Rack::Test::Methods
18
18
  c.include RightHook::SpecHelpers
19
19
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_hook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-01 00:00:00.000000000 Z
12
+ date: 2013-10-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -176,6 +176,7 @@ files:
176
176
  - lib/right_hook/commenter.rb
177
177
  - lib/right_hook/event.rb
178
178
  - lib/right_hook/logger.rb
179
+ - lib/right_hook/spec_helpers.rb
179
180
  - lib/right_hook/subscriber.rb
180
181
  - lib/right_hook/version.rb
181
182
  - right_hook.gemspec
@@ -189,7 +190,6 @@ files:
189
190
  - spec/event_spec.rb
190
191
  - spec/spec_helper.rb
191
192
  - spec/subscriber_spec.rb
192
- - spec/support/spec_helpers.rb
193
193
  homepage: https://github.com/mark-rushakoff/right_hook
194
194
  licenses:
195
195
  - MIT
@@ -227,5 +227,4 @@ test_files:
227
227
  - spec/event_spec.rb
228
228
  - spec/spec_helper.rb
229
229
  - spec/subscriber_spec.rb
230
- - spec/support/spec_helpers.rb
231
230
  has_rdoc:
@@ -1,11 +0,0 @@
1
- require 'openssl'
2
-
3
- module RightHook
4
- module SpecHelpers
5
- def generate_secret_header(secret, body)
6
- sha = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha1'), secret, body)
7
- # GitHub sends it as 'X-Hub-Signature', but Rack provides it as HTTP_X_HUB_SIGNATURE... :/
8
- {'HTTP_X_HUB_SIGNATURE' => "sha1=#{sha}"}
9
- end
10
- end
11
- end