fluent-plugin-webhook-github 0.0.1 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e923883115c0db82c6949857520454371405355
4
- data.tar.gz: 411b18a816bddd71848bc803735eed69e1d159bc
3
+ metadata.gz: de9f951a5814c20c8c607c6bee818f7d2c05f199
4
+ data.tar.gz: 2096cb5f1e9da7bec2661639c3d4a626aa8cd411
5
5
  SHA512:
6
- metadata.gz: 9660b12470cbf52461c134aaa7ded8d1cc1d52cbdde763befe5552eb97c37e4e31c2c7b94472e518f967f81483cf7ce245d7b4e46254065f6646af99fc5406e8
7
- data.tar.gz: 40d9b3f67dff59bc02c888c2a627455c4bc1c634c95eba1e978b708da106fd020e5a28292df8b0559de61873eec93cbfc0ff79dea8429be30d6642d588ccf388
6
+ metadata.gz: 6b985724b8552de1b4e9ea9d17303b165c5d9579dafcd30002b7005e8c7676928e0af7dc5acddd27d929d9b686103565c76e8859c77c7c4ffe228df9d4d70683
7
+ data.tar.gz: 44d0fa1289062639b4fe1c69e7b9e50e1a3437eb5ce1fbd4d508f08e6ab540c68a43c740dfa9a4d66740b38f4ba95862333a9ecba72a2c3d68496a650ad2c5fd
data/README.md CHANGED
@@ -15,10 +15,13 @@ fluentd input plugin for incoming webhook from GitHub.
15
15
  type webhook_github
16
16
  tag gh
17
17
 
18
+ secret THE_SECRET_STRING_YOU_SET # the hook's secret. optional, but strongly recommended.
19
+
18
20
  # optional (values are default)
19
21
  bind 0.0.0.0
20
22
  port 8080
21
23
  mount /
24
+ with_payload false
22
25
  </source>
23
26
 
24
27
  <match gh.*>
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ Rake::TestTask.new(:test) do |test|
4
+ test.libs << 'lib' << 'test'
5
+ test.pattern = 'test/**/test_*.rb'
6
+ test.verbose = true
7
+ end
2
8
 
9
+ task :default => :test
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.1.0
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_runtime_dependency "fluentd", "~> 0"
21
+ spec.add_runtime_dependency "secure_compare", "~> 0"
21
22
  spec.add_development_dependency "bundler", "~> 1.6"
22
23
  spec.add_development_dependency "rake"
23
24
  end
@@ -3,6 +3,8 @@
3
3
  require "thread"
4
4
  require "json"
5
5
  require 'fluent/process'
6
+ require 'openssl'
7
+ require 'secure_compare'
6
8
 
7
9
  module Fluent
8
10
  class WebhookGithubInput < Input
@@ -14,64 +16,85 @@ module Fluent
14
16
  config_param :bind, :string, :default => "0.0.0.0"
15
17
  config_param :port, :integer, :default => 8080
16
18
  config_param :mount, :string, :default => "/"
19
+ config_param :secret, :string, :default => nil
20
+ config_param :with_payload, :bool, :default => false
17
21
 
18
22
  def start
19
23
  @thread = Thread.new(&method(:run))
20
24
  end
21
25
 
22
26
  def shutdown
27
+ @server.shutdown
23
28
  Thread.kill(@thread)
24
29
  end
25
30
 
31
+ HMAC_DIGEST = OpenSSL::Digest.new('sha1')
32
+
26
33
  def run
27
- server = WEBrick::HTTPServer.new(
34
+ @server = WEBrick::HTTPServer.new(
28
35
  :BindAddress => @bind,
29
36
  :Port => @port,
30
37
  )
31
38
  $log.debug "Listen on http://#{@bind}:#{@port}#{@mount}"
32
- server.mount_proc(@mount) do |req, res|
39
+ @server.mount_proc(@mount) do |req, res|
33
40
  begin
34
41
  $log.debug req.header
35
- payload = JSON.parse(req.body || "{}")
36
- event = req.header["x-github-event"].first
37
- process(event, payload)
38
- res.status = 204
42
+
43
+ if verify_signature(req)
44
+ payload = JSON.parse(req.body || "{}")
45
+ event = req.header["x-github-event"].first
46
+ process(event, payload)
47
+ res.status = 204
48
+ else
49
+ res.status = 401
50
+ end
39
51
  rescue => e
40
52
  $log.error e.inspect
41
53
  $log.error e.backtrace.join("\n")
42
54
  res.status = 400
43
55
  end
44
56
  end
45
- server.start
57
+ @server.start
58
+ end
59
+
60
+ def verify_signature(req)
61
+ return true unless @secret
62
+ sig = 'sha1='+OpenSSL::HMAC.hexdigest(HMAC_DIGEST, @secret, req.body)
63
+ SecureCompare.compare(sig, req.header["x-hub-signature"].first)
46
64
  end
47
65
 
48
66
  def process(event, payload)
49
67
  content = case event
50
68
  when "issue", "issue_comment"
51
69
  {
52
- :url => payload["issue"]["html_url"],
53
- :title => payload["issue"]["title"],
54
- :user => payload["issue"]["user"]["login"],
55
- :body => payload["comment"]["body"],
70
+ :url => payload["issue"] && payload["issue"]["html_url"],
71
+ :title => payload["issue"] && payload["issue"]["title"],
72
+ :user => payload["issue"] && payload["issue"]["user"]["login"],
73
+ :body => payload["comment"] && payload["comment"]["body"],
56
74
  }
57
75
  when "pull_request"
58
76
  {
59
- :url => payload["pull_request"]["html_url"],
60
- :title => payload["pull_request"]["title"],
61
- :user => payload["pull_request"]["user"]["login"],
62
- :body => payload["pull_request"]["body"],
77
+ :url => payload["pull_request"] && payload["pull_request"]["html_url"],
78
+ :title => payload["pull_request"] && payload["pull_request"]["title"],
79
+ :user => payload["pull_request"] && payload["pull_request"]["user"]["login"],
80
+ :body => payload["pull_request"] && payload["pull_request"]["body"],
63
81
  }
64
82
  when "pull_request_review_comment"
65
83
  {
66
- :url => payload["comment"]["html_url"],
67
- :title => payload["pull_request"]["title"],
68
- :user => payload["comment"]["user"]["login"],
69
- :body => payload["comment"]["body"],
84
+ :url => payload["comment"] && payload["comment"]["html_url"],
85
+ :title => payload["pull_request"] && payload["pull_request"]["title"],
86
+ :user => payload["comment"] && payload["comment"]["user"]["login"],
87
+ :body => payload["comment"] && payload["comment"]["body"],
70
88
  }
89
+ else
90
+ {}
71
91
  end
92
+
72
93
  if content
73
94
  content[:origin] = "github"
74
- $log.info "tag: #{@tag.dup}.#{event}, event:#{event}, content:#{content}"
95
+ content[:event] = event
96
+ content[:payload] = payload if @with_payload
97
+ $log.info "tag: #{@tag.dup}.#{event}, event:#{event}, content:#{content}"
75
98
  Engine.emit("#{@tag.dup}.#{event}", Engine.now, content) if content
76
99
  else
77
100
  $log.warn "unknown hook received #{event} #{payload.inspect}"
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+
15
+ require 'fluent/test'
16
+ require 'fluent/plugin/in_webhook_github'
17
+
18
+ def unused_port
19
+ s = TCPServer.open(0)
20
+ port = s.addr[1]
21
+ s.close
22
+ port
23
+ end
24
+
@@ -0,0 +1,172 @@
1
+ require 'helper'
2
+ require 'net/http'
3
+
4
+ class GithubWebhookInputTest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ end
8
+
9
+ PORT = unused_port
10
+ CONFIG = %[
11
+ port #{PORT}
12
+ tag gwebhook
13
+ ]
14
+
15
+ def create_driver(conf=CONFIG, tag='test')
16
+ Fluent::Test::OutputTestDriver.new(Fluent::WebhookGithubInput, tag).configure(conf)
17
+ end
18
+
19
+ def test_configure
20
+ assert_raise(Fluent::ConfigError) {
21
+ d = create_driver('')
22
+ }
23
+ d = create_driver
24
+ assert_equal 'gwebhook', d.instance.tag
25
+ assert_equal PORT, d.instance.port
26
+ assert_equal '/', d.instance.mount
27
+ assert_equal '0.0.0.0', d.instance.bind
28
+ end
29
+
30
+ def test_basic
31
+ d = create_driver
32
+
33
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
34
+ Fluent::Engine.now = time
35
+
36
+ d.expect_emit "gwebhook.issue", time, {
37
+ :event => 'issue',
38
+ :url => 'http://',
39
+ :title => 'tttt',
40
+ :user => 'Ore',
41
+ :body => 'Karada',
42
+ :origin => 'github',
43
+ }
44
+
45
+ payload = {
46
+ 'issue' => {
47
+ 'html_url' => 'http://',
48
+ 'title' => 'tttt',
49
+ 'user' => {
50
+ 'login' => 'Ore',
51
+ },
52
+ },
53
+ 'comment' => {
54
+ 'body' => 'Karada',
55
+ }
56
+ }
57
+
58
+ d.run do
59
+ d.expected_emits.each {|tag, time, record|
60
+ res = post("/", payload.to_json, {
61
+ 'x-github-event' => 'issue',
62
+ })
63
+ assert_equal "204", res.code
64
+ }
65
+ end
66
+ end
67
+
68
+
69
+ def test_signature
70
+ d = create_driver(CONFIG + %[
71
+ secret secret1234
72
+ ])
73
+
74
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
75
+ Fluent::Engine.now = time
76
+
77
+ d.expect_emit "gwebhook.issue", time, {
78
+ :event => 'issue',
79
+ :url => nil,
80
+ :title => nil,
81
+ :user => nil,
82
+ :body => nil,
83
+ :origin => 'github',
84
+ }
85
+
86
+ d.run do
87
+ d.expected_emits.each {|tag, time, record|
88
+ res = post("/", '{"hoge":"fuga"}', {
89
+ 'x-github-event' => 'issue',
90
+ 'x-hub-signature' => 'sha1=5ea783ea13c9feef6dbb9c8c805450e2ba1fb0c0',
91
+ })
92
+ assert_equal "204", res.code
93
+ }
94
+ res = post("/", '{"hoge":"fuga"}', {
95
+ 'x-github-event' => 'issue',
96
+ 'x-hub-signature' => 'sha1=5ea783ea13c9feef6dbb9c8c805450e2ba1fb0c0-dummy',
97
+ })
98
+ assert_equal "401", res.code
99
+ end
100
+ end
101
+
102
+ def test_with_payload
103
+ d = create_driver(CONFIG + %[
104
+ with_payload true
105
+ ])
106
+
107
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
108
+ Fluent::Engine.now = time
109
+
110
+ payload = {
111
+ 'issue' => {
112
+ 'html_url' => 'http://',
113
+ 'title' => 'tttt',
114
+ 'user' => {
115
+ 'login' => 'Ore',
116
+ },
117
+ },
118
+ 'comment' => {
119
+ 'body' => 'Karada',
120
+ }
121
+ }
122
+
123
+ d.expect_emit "gwebhook.issue", time, {
124
+ :event => 'issue',
125
+ :url => 'http://',
126
+ :title => 'tttt',
127
+ :user => 'Ore',
128
+ :body => 'Karada',
129
+ :origin => 'github',
130
+ :payload => payload
131
+ }
132
+
133
+ payload_delete = {
134
+ 'ref' => 'simple-tag',
135
+ 'ref_type' => 'tag',
136
+ 'pusher_type' => 'user',
137
+ 'repository' => {},
138
+ 'sender' => {
139
+ 'login' => 'baxterthehacker',
140
+ 'id' => 6752317,
141
+ },
142
+ }
143
+
144
+ d.expect_emit "gwebhook.delete", time, {
145
+ :event => 'delete',
146
+ :origin => 'github',
147
+ :payload => payload_delete,
148
+ }
149
+
150
+ d.run do
151
+ d.expected_emits.each {|tag, time, record|
152
+ res = post("/", record[:payload].to_json, {
153
+ 'x-github-event' => record[:event],
154
+ })
155
+ assert_equal "204", res.code
156
+ }
157
+ end
158
+ end
159
+
160
+
161
+ def post(path, params, header = {})
162
+ http = Net::HTTP.new("127.0.0.1", PORT)
163
+ req = Net::HTTP::Post.new(path, header)
164
+ if params.is_a?(String)
165
+ req.body = params
166
+ else
167
+ req.set_form_data(params)
168
+ end
169
+ http.request(req)
170
+ end
171
+
172
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-webhook-github
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - uu59
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-06 00:00:00.000000000 Z
11
+ date: 2014-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: secure_compare
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,6 +81,8 @@ files:
67
81
  - VERSION
68
82
  - fluent-plugin-webhook-github.gemspec
69
83
  - lib/fluent/plugin/in_webhook_github.rb
84
+ - test/helper.rb
85
+ - test/plugin/test_in_webhook_github.rb
70
86
  homepage: ''
71
87
  licenses:
72
88
  - MIT
@@ -91,4 +107,6 @@ rubygems_version: 2.2.2
91
107
  signing_key:
92
108
  specification_version: 4
93
109
  summary: fluentd input plugin for receive GitHub webhook
94
- test_files: []
110
+ test_files:
111
+ - test/helper.rb
112
+ - test/plugin/test_in_webhook_github.rb