saba-webhook-gateway 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b360d216c14fa19ecc9e6fb814f26bf0a9d8b0f2c07e98073bd74ff27e665cec
4
+ data.tar.gz: b381d002fb7a4c526ce4a00e3026aae881c50c7656f2da73a170cf5d0b7c5b5f
5
+ SHA512:
6
+ metadata.gz: 485b0ba83cdd8b7cc51bff9bd1120ad59212ee46dc55611f0c5cf1fb5dbe341792c814a2be3413d9934619249434cfeb05fec7291e100bb8c5a0fcfc354b48b3
7
+ data.tar.gz: 0eb0f2ac4b7ef20316400481b12c79fa2d3199651d39f98df7460d254787acb7e75a7eb6b5ffea52c488fd99b844ea0922e48bf420fc276ee5a7c72da30ab4b9
data/.rubocop.yml ADDED
@@ -0,0 +1,306 @@
1
+ AllCops:
2
+ Exclude:
3
+ - samples/**/*
4
+ - vendor/**/*
5
+ DisplayCopNames: true
6
+ NewCops: enable
7
+ TargetRubyVersion: 2.7
8
+
9
+ require:
10
+ - rubocop-performance
11
+ - rubocop-rake
12
+
13
+ #### Lint
14
+
15
+ Lint/NestedMethodDefinition:
16
+ Exclude:
17
+ - 'test/*'
18
+
19
+ Lint/AssignmentInCondition:
20
+ Enabled: false
21
+
22
+ Lint/ErbNewArguments:
23
+ Enabled: false
24
+
25
+ # make it enable when supporting only Ruby 3.0 and higher.
26
+ Lint/RedundantDirGlobSort:
27
+ Enabled: false
28
+
29
+ #### Performance
30
+
31
+ Performance/DeletePrefix:
32
+ Enabled: false
33
+
34
+ Performance/StringInclude:
35
+ Enabled: false
36
+
37
+ Performance/CollectionLiteralInLoop:
38
+ Enabled: false
39
+
40
+ Performance/MapCompact:
41
+ Enabled: false
42
+
43
+ #### Style
44
+
45
+ Style/AsciiComments:
46
+ Enabled: false
47
+
48
+ # Use alias_method instead of alias.
49
+ Style/Alias:
50
+ EnforcedStyle: prefer_alias_method
51
+ Enabled: true
52
+
53
+ Style/BarePercentLiterals:
54
+ EnforcedStyle: percent_q
55
+ Enabled: true
56
+
57
+ Style/CommentedKeyword:
58
+ Enabled: false
59
+
60
+ Style/DocumentDynamicEvalDefinition:
61
+ Enabled: false
62
+
63
+ Style/Documentation:
64
+ Enabled: false
65
+
66
+ Style/FormatString:
67
+ EnforcedStyle: sprintf
68
+ Enabled: true
69
+
70
+ Style/FormatStringToken:
71
+ Enabled: false
72
+
73
+ Style/GuardClause:
74
+ Enabled: false
75
+
76
+ Style/IfUnlessModifier:
77
+ Enabled: false
78
+
79
+ Style/MutableConstant:
80
+ Enabled: false
81
+
82
+ Style/ZeroLengthPredicate:
83
+ Enabled: false
84
+
85
+ Style/NumericPredicate:
86
+ EnforcedStyle: comparison
87
+ Enabled: true
88
+
89
+ Style/TernaryParentheses:
90
+ Enabled: false
91
+
92
+ Style/FrozenStringLiteralComment:
93
+ EnforcedStyle: never
94
+ Enabled: true
95
+
96
+ Style/SafeNavigation:
97
+ Enabled: false
98
+
99
+ Style/EmptyMethod:
100
+ EnforcedStyle: expanded
101
+ Enabled: true
102
+
103
+ Style/RescueModifier:
104
+ Enabled: false
105
+
106
+ Style/ClassAndModuleChildren:
107
+ EnforcedStyle: nested
108
+ Enabled: true
109
+
110
+ Style/LineEndConcatenation:
111
+ Enabled: false
112
+
113
+ Style/MethodCallWithArgsParentheses:
114
+ AllowedPatterns:
115
+ - 'require'
116
+ - 'include'
117
+ - 'file'
118
+ - 'task'
119
+ - 'desc'
120
+ - 'info'
121
+ - 'gem'
122
+ - 'exit'
123
+ - 'print'
124
+ - 'puts'
125
+ - 'write'
126
+ - 'warn'
127
+ - 'error'
128
+ - 'error!'
129
+ - 'app_error'
130
+ - 'raise'
131
+ - 'yield'
132
+ - 'source'
133
+ - 'assert'
134
+ - 'assert_equal'
135
+ - 'assert_raise'
136
+ - 'assert_raises'
137
+ - 'assert_nothing_raised'
138
+ - 'sh'
139
+ - 'mv'
140
+ - 'rm_rf'
141
+ Enabled: true
142
+
143
+ Style/MixinUsage:
144
+ Enabled: false
145
+
146
+ Style/NumericLiterals:
147
+ MinDigits: 6
148
+
149
+ Style/PercentQLiterals:
150
+ EnforcedStyle: upper_case_q
151
+ Enabled: true
152
+
153
+ Style/PerlBackrefs:
154
+ Enabled: false
155
+
156
+ Style/RaiseArgs:
157
+ EnforcedStyle: exploded
158
+ Enabled: true
159
+
160
+ Style/RedundantBegin:
161
+ Enabled: false
162
+
163
+ Style/RedundantReturn:
164
+ Enabled: false
165
+
166
+ Style/RedundantSelf:
167
+ Enabled: false
168
+
169
+ Style/StderrPuts:
170
+ Enabled: false
171
+
172
+ Style/WordArray:
173
+ MinSize: 10
174
+
175
+ Style/RedundantPercentQ:
176
+ Enabled: false
177
+
178
+ Style/WhileUntilModifier:
179
+ Enabled: false
180
+
181
+ Style/SlicingWithRange:
182
+ Enabled: false
183
+
184
+ Style/AccessorGrouping:
185
+ Enabled: false
186
+
187
+ Style/CaseLikeIf:
188
+ Enabled: false
189
+
190
+ Style/StringConcatenation:
191
+ Enabled: false
192
+
193
+ Style/OptionalBooleanParameter:
194
+ Enabled: false
195
+
196
+ Style/CombinableLoops:
197
+ Enabled: false
198
+
199
+ Style/FetchEnvVar:
200
+ Enabled: false
201
+
202
+ ### Layout
203
+
204
+ Layout/BlockAlignment:
205
+ Enabled: false
206
+
207
+ Layout/ClosingHeredocIndentation:
208
+ Enabled: false
209
+
210
+ Layout/DotPosition:
211
+ EnforcedStyle: trailing
212
+ Enabled: true
213
+
214
+ Layout/HeredocIndentation:
215
+ Enabled: false
216
+
217
+ Layout/SpaceAroundBlockParameters:
218
+ EnforcedStyleInsidePipes: no_space
219
+ Enabled: true
220
+
221
+ Layout/SpaceInsideStringInterpolation:
222
+ EnforcedStyle: no_space
223
+ Enabled: true
224
+
225
+ Layout/TrailingWhitespace:
226
+ Enabled: true
227
+ AllowInHeredoc: true
228
+
229
+ Layout/LineLength:
230
+ Max: 256
231
+ Exclude:
232
+ - "test/**/*"
233
+
234
+ #### Metrics
235
+
236
+ Metrics/BlockNesting:
237
+ Max: 4
238
+
239
+ Metrics/ModuleLength:
240
+ Max: 300
241
+
242
+ Metrics/ParameterLists:
243
+ Max: 8
244
+
245
+ Metrics/PerceivedComplexity:
246
+ Max: 28
247
+
248
+ Metrics/ClassLength:
249
+ Max: 1500
250
+ Exclude:
251
+ - 'test/*.rb'
252
+
253
+ ### should be < 50
254
+ Metrics/MethodLength:
255
+ Max: 100
256
+ Exclude:
257
+ - "bin/review-*"
258
+ - "bin/review2*"
259
+ - "test/**/*"
260
+
261
+ ### should be < 20
262
+ Metrics/CyclomaticComplexity:
263
+ Max: 25
264
+
265
+ ### should be < 60
266
+ Metrics/AbcSize:
267
+ Max: 120
268
+ Exclude:
269
+ - "bin/review-*"
270
+ - "test/**/*"
271
+
272
+ ### shoud be < 25
273
+ Metrics/BlockLength:
274
+ CountComments: false # count full line comments?
275
+ Max: 62
276
+ Exclude:
277
+ - 'Rakefile'
278
+ - '**/*.rake'
279
+ - 'test/**/*.rb'
280
+
281
+ ## Naming
282
+
283
+ Naming/FileName:
284
+ Enabled: false
285
+
286
+ Naming/HeredocDelimiterNaming:
287
+ Enabled: false
288
+
289
+ Naming/MethodParameterName:
290
+ Enabled: false
291
+
292
+ Naming/VariableNumber:
293
+ EnforcedStyle: normalcase
294
+ Enabled: true
295
+ Exclude:
296
+ - test/*
297
+
298
+ #### Security
299
+
300
+ #### Gemspec
301
+
302
+ Gemspec/RequiredRubyVersion:
303
+ Enabled: false
304
+
305
+ Gemspec/DevelopmentDependencies:
306
+ EnforcedStyle: gemspec
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile-lambda ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'faraday'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Kenshi Muto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # Saba Webhook Gateway
2
+
3
+ ![](./saba-webhook-gateway.png)
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/saba-webhook-gateway.svg)](https://rubygems.org/gems/saba-webhook-gateway)
6
+
7
+ Saba Webhook Gatewayは、監視サービス[Mackerel](https://ja.mackerel.io)のWebhookを受け取り、ほかの形式のWebhookに変換して引き渡すゲートウェイのライブラリです。
8
+
9
+ 以下のMackerelのWebhook通知に対応します。
10
+
11
+ - サンプル(Mackerelの「テスト」で送出されるもの)
12
+ - アラート通知
13
+ - アラートグループ通知
14
+ - ホストステータス変更
15
+ - ホスト登録
16
+ - ホスト退役
17
+ - 監視ルールの操作(追加・変更・削除)
18
+
19
+ ## Google Chatでの実行
20
+
21
+ 実装のリファレンスとして、Google Chat Webhook変換を用意しています。各通知をGoogle Chatに送信できます(ただし、現時点でGoogle ChatのWebhookは有償プランのみでしか使えません)。
22
+
23
+ ![Google Chatでの通知表示](./googlechat.png)
24
+
25
+ ### Sinatraを使う場合
26
+
27
+ 以下のようにGoogle ChatスペースのWebhook URLを指定した`.env`ファイルを用意し、本Gitリポジトリを展開しているフォルダに配置します。
28
+
29
+ ```
30
+ GOOGLECHAT_WEBHOOK=https://chat.googleapis.com/v1/spaces/…
31
+ ```
32
+
33
+ Sinatra gemをインストールします。
34
+
35
+ ```
36
+ $ gem install sinatra
37
+ ```
38
+
39
+ Sinatraのサーバーを起動します。
40
+
41
+ ```
42
+ $ exe/webhook-handler-googlechat.rb
43
+ ```
44
+
45
+ デフォルトでは全IPアドレスにバインドした状態でTCPポート4567、パス`/`で待ち受けます。変更したいときには`.env`ファイルで`SERVER_BIND`・`SERVER_PORT`・`SERVER_PATH`を指定してください。
46
+
47
+ 用意したこのサーバーに対してMackerelから送信するようチャンネルを設定します。インターネット経由でアクセスできる必要があるため、ngrokやWebサーバーのプロキシを使ってアクセスできるようにしておきましょう。
48
+
49
+ Mackerelの通知チャンネルの追加で「Webhook」を選び、URLにインターネット経由でアクセスされるURLを指定します。作成されたWebhookチャンネルで「テスト」をクリックすると、サンプルの通知がGoogle Chatに飛びます。
50
+
51
+ ### AWS Lambdaでの実行
52
+
53
+ AWS LambdaのRubyランタイムと関数URLを使ってサーバーレスで実行することもできます。
54
+
55
+ まず、アップロードするsaba-webhook-gateway-googlechat.zipファイルを作成します。
56
+
57
+ ```
58
+ $ ./make-lambda-zip.sh
59
+ ```
60
+
61
+ この作成シェルスクリプトはDebian bookworm用に作っており、Ruby 3.1で用意されるフォルダ名をLambdaのRuby 3.2用に変更しています。ほかのOSやバージョンの場合は適宜変更してください。
62
+
63
+ AWSでLambdaを用意します。
64
+
65
+ - 一から作成
66
+ - 関数名: 任意
67
+ - ランタイム: 「Ruby 3.2」
68
+ - アーキテクチャ: 任意
69
+ - デフォルトの実行ロールの変更: 環境に応じて
70
+ - 詳細設定の 関数URLを有効化: チェック
71
+ - 認証タイプ: NONE(※パブリックなエンドポイントになることに注意)
72
+ - 呼び出しモード: BUFFERED(デフォルト)
73
+ - オリジン間リソース共有(CORS)を設定: 任意
74
+
75
+ 「コード」タブの「コードソース」の「アップロード元」からsaba-webhook-gateway-googlechat.zipファイルをアップロードします。
76
+
77
+ 下にスクロールして「ランタイム設定」に進み、「編集」をクリックしてハンドラを以下のとおり変更します。
78
+
79
+ ```
80
+ exe/lambda-handler-googlechat.lambda_handler
81
+ ```
82
+
83
+ 次に「コード」に戻り、「設定」タブをクリックして、「環境変数」を選びます。「環境変数の追加」をクリックし、キーに `GOOGLECHAT_WEBHOOK` 、値にGoogle ChatスペースのWebhook URLを指定します。
84
+
85
+ さらに「暗号化の設定」を選び、「転送時の暗号化に使用するヘルパーの有効化」にチェックします。値の右に「転送時の暗号化」というボタンができるので、これをクリックし、KMSキーを選びます。
86
+
87
+ 「実行ロールポリシー」に復号のためにLambdaの実行IAMロールに追加する必要のあるポリシーが示されるので、これをIAMロールに付加してください。
88
+
89
+ 「関数の概要」にWebhookエンドポイントとなる「関数URL」が表示されているので、Mackerelの通知チャンネルの追加で「Webhook」を選び、URLにその関数URLを指定します。作成されたWebhookチャンネルで「テスト」をクリックすると、サンプルの通知がGoogle Chatに飛びます。
90
+
91
+ ### カスタマイズ
92
+
93
+ メッセージを変更したいときには、`lib/saba-webhook-gateway/googlechat.rb`を直接書き換える方法もありますが、一部だけであればメソッドをオーバーライドするのが簡単です。
94
+
95
+ ```
96
+ # Saba Webhook Gateway Override
97
+ module GoogleChatOverride
98
+ # SabaWebhookGateway::GoogleChat の一部のメソッドの挙動(カード出力など)を変えたいときにはここでメソッドを上書きする
99
+ # sampleメソッドを上書きする例
100
+ def sample(h)
101
+ header = { title: '通知のテスト' }
102
+ widget1 = [{ textParagraph: { text: h[:message] } }]
103
+ sections = [{ widgets: widget1 }]
104
+ googlechat_card(header, sections)
105
+ end
106
+ end
107
+
108
+ module SabaWebhookGateway
109
+ class GoogleChat
110
+ prepend GoogleChatOverride
111
+ end
112
+ end
113
+ ```
114
+
115
+ ## MackerelのWebhook JSONスキーマについて
116
+
117
+ webhooksフォルダに、参考としてMackerelのWebhook JSONのスキーマファイルを入れています。
118
+
119
+ 内部仕様ではなく、出力から導出したものなので、正確性の保証はないことに注意してください。また、スキーマ内部で本来分岐が必要なもの(監視ルールの設定など)についても対応はしていません。
120
+
121
+ ## ライセンス
122
+ ```
123
+ MIT License
124
+
125
+ Copyright (c) 2023 Kenshi Muto
126
+
127
+ Permission is hereby granted, free of charge, to any person obtaining a copy
128
+ of this software and associated documentation files (the "Software"), to deal
129
+ in the Software without restriction, including without limitation the rights
130
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
131
+ copies of the Software, and to permit persons to whom the Software is
132
+ furnished to do so, subject to the following conditions:
133
+
134
+ The above copyright notice and this permission notice shall be included in all
135
+ copies or substantial portions of the Software.
136
+
137
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
138
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
139
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
140
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
141
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
142
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
143
+ SOFTWARE.
144
+ ```
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'fileutils'
4
+
5
+ desc 'Check with rubocop'
6
+ task :rubocop do
7
+ begin
8
+ require 'rubocop/rake_task'
9
+ RuboCop::RakeTask.new
10
+ rescue LoadError
11
+ $stderr.puts 'rubocop not found'
12
+ end
13
+ end
14
+
15
+ task default: %i[rubocop]
@@ -0,0 +1,26 @@
1
+ require_relative '../lib/saba-webhook-gateway'
2
+ require 'aws-sdk-kms'
3
+ require 'base64'
4
+
5
+ ENCRYPTED = ENV['GOOGLECHAT_WEBHOOK']
6
+ # Decrypt code should run once and variables stored outside of the function
7
+ # handler so that these are decrypted once per container
8
+ DECRYPTED = Aws::KMS::Client.new.decrypt({
9
+ ciphertext_blob: Base64.decode64(ENCRYPTED),
10
+ encryption_context: { 'LambdaFunctionName' => ENV['AWS_LAMBDA_FUNCTION_NAME'] }
11
+ }).plaintext
12
+ ENV['GOOGLECHAT_WEBHOOK'] = DECRYPTED
13
+
14
+ # rubocop:disable Lint/UnusedMethodArgument
15
+ def lambda_handler(event:, context:)
16
+ m = SabaWebhookGateway::GoogleChat.new
17
+ h = m.parse(JSON.generate(event))
18
+ if h[:body]
19
+ m.run(m.parse(h[:body]))
20
+ elsif h[:event]
21
+ m.run(h)
22
+ end
23
+
24
+ { statusCode: 200, body: JSON.generate('received on Lambda') }
25
+ end
26
+ # rubocop:enable Lint/UnusedMethodArgument
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ # Saba Webhook Gateway Handler for Google Chat on Sinatra
3
+ #
4
+ # Copyright 2023 Kenshi Muto <kmuto@kmuto.jp>
5
+ require 'dotenv'
6
+ require 'sinatra'
7
+
8
+ require 'pathname'
9
+ bindir = Pathname.new(__FILE__).realpath.dirname
10
+ $LOAD_PATH.unshift((bindir + '../lib').realpath)
11
+
12
+ require 'saba-webhook-gateway'
13
+
14
+ Dotenv.load
15
+ @bind = ENV['SERVER_BIND'] || '0.0.0.0'
16
+ @port = ENV['SERVER_PORT'] || 4567
17
+ @path = ENV['SERVER_PATH'] || '/'
18
+
19
+ set :bind, @bind
20
+ set :port, @port
21
+
22
+ post @path do
23
+ status 204
24
+ request.body.rewind
25
+ request_json = request.body.read
26
+
27
+ m = SabaWebhookGateway::GoogleChat.new
28
+ h = m.parse(request_json)
29
+ m.run(h) if h
30
+ end
data/googlechat.png ADDED
Binary file