fluent-plugin-webhook-github 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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