webhukhs 0.7.0 → 0.8.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.yard-lint.yml +1 -0
  3. data/AGENTS.md +9 -11
  4. data/Appraisals +2 -2
  5. data/CHANGELOG.md +13 -0
  6. data/README.md +98 -10
  7. data/Rakefile +7 -0
  8. data/example/Gemfile +5 -6
  9. data/example/Gemfile.lock +260 -141
  10. data/example/app/webhooks/acme_handler.rb +16 -0
  11. data/example/app/webhooks/flaky_handler.rb +8 -0
  12. data/example/app/webhooks/signed_handler.rb +10 -0
  13. data/example/config/initializers/webhukhs.rb +4 -3
  14. data/example/config/routes.rb +3 -0
  15. data/example/db/migrate/20240601000000_add_headers_to_webhukhs_webhooks.rb +7 -0
  16. data/example/db/schema.rb +2 -1
  17. data/example/db/seeds.rb +71 -7
  18. data/gemfiles/{rails_7.1.gemfile → rails_7.2.gemfile} +1 -4
  19. data/gemfiles/rails_7.2.gemfile.lock +477 -0
  20. data/gemfiles/rails_8.0.gemfile +0 -3
  21. data/gemfiles/rails_8.0.gemfile.lock +74 -4
  22. data/gemfiles/rails_8.1.gemfile +0 -3
  23. data/gemfiles/rails_8.1.gemfile.lock +74 -4
  24. data/gemfiles/rails_master.gemfile +0 -3
  25. data/lib/webhukhs/admin/application_controller.rb +32 -0
  26. data/lib/webhukhs/admin/assets/admin.css +476 -0
  27. data/lib/webhukhs/admin/assets/admin.js +111 -0
  28. data/lib/webhukhs/admin/config/routes.rb +6 -0
  29. data/lib/webhukhs/admin/engine.rb +20 -0
  30. data/lib/webhukhs/admin/received_webhook_presenter.rb +63 -0
  31. data/lib/webhukhs/admin/received_webhooks_controller.rb +60 -0
  32. data/lib/webhukhs/admin/view_helper.rb +50 -0
  33. data/lib/webhukhs/admin/views/layouts/webhukhs/admin/application.html.erb +22 -0
  34. data/lib/webhukhs/admin/views/webhukhs/admin/received_webhooks/index.html.erb +50 -0
  35. data/lib/webhukhs/admin/views/webhukhs/admin/received_webhooks/show.html.erb +55 -0
  36. data/lib/webhukhs/admin.rb +17 -0
  37. data/lib/webhukhs/engine.rb +0 -4
  38. data/lib/webhukhs/models/received_webhook.rb +3 -0
  39. data/lib/webhukhs/version.rb +1 -1
  40. data/test/admin_test.rb +334 -0
  41. data/test/base_handler_test.rb +3 -3
  42. data/test/browser/admin_click_through.rb +208 -0
  43. data/test/processing_job_test.rb +15 -28
  44. data/test/received_webhook_test.rb +16 -0
  45. data/test/test_app.rb +2 -0
  46. data/test/test_helper.rb +9 -6
  47. data/test/webhukhs_test.rb +20 -62
  48. metadata +165 -8
  49. data/example/.ruby-version +0 -1
  50. data/gemfiles/rails_7.1.gemfile.lock +0 -412
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83faf212a808c37ee8d293dc4e1d74d82d8ce0a7fb653d3850ee01ff9da7000b
4
- data.tar.gz: 4d599377df025e4bd52c885efd5067127e50876eef1be8a9ee3117960d8bcf14
3
+ metadata.gz: cae5927b7426085a8e140f6bdb4565423d43d1b72c65b65c9602b72bd81a1338
4
+ data.tar.gz: e77b5321fbd8b814b3d6265da104ec9b4e77ffc36a2d0b0c62e67ae1c1f3ff05
5
5
  SHA512:
6
- metadata.gz: a0834f112be61de4bf50a6a99d8eee1ebd439e11c2a4ab26fe2e178d4ba70baeee4c62a06ea13fac44f2797bf5d7db40689249f7252cc3e5038d76f4997fdac2
7
- data.tar.gz: 4070b8ad54761f7a888659c52a5284b660f86e729f645a8b1cc2658193b408b1852a4c6551147bd4ffe07f2c55f37dfb7b5aa8401388af44a2f762f1af973ccc
6
+ metadata.gz: 40519e7b2ca3b8c8e4bbf924f78d86269f6f4b68b1a72f3a7f963ec87fde656f49db69c6268de76f19b22ec762e3e14078c9839f44e080b41bc1e99131ecb449
7
+ data.tar.gz: 2a8e469254e9f76b46068a9b06001157f570f33a6cab931c2ee23cada3c13eadbff765c368cba58e6a62a1d657db8d142a2f89d2b8fe94b4034eb76f45cb4e6c
data/.yard-lint.yml CHANGED
@@ -11,6 +11,7 @@ AllValidators:
11
11
  # Global file exclusion patterns
12
12
  Exclude:
13
13
  - '\.git'
14
+ - 'lib/webhukhs/engine.rb'
14
15
  - 'vendor/**/*'
15
16
  - 'node_modules/**/*'
16
17
  - 'spec/**/*'
data/AGENTS.md CHANGED
@@ -1,21 +1,25 @@
1
- You are working in a Ruby project that uses mutation testing.
1
+ You are working in a Ruby project that uses mutation testing, but also tracks line and branch coverage.
2
2
 
3
3
  ## Goal
4
4
 
5
- Achieve 100% mutation coverage. Verify with:
5
+ Achieve 100% line, branch and mutation coverage. Verify with:
6
+
7
+ ```
8
+ SIMPLECOV=1 bundle exec rspec
9
+ ```
6
10
 
7
11
  ```
8
12
  bundle exec mutant run
9
13
  ```
10
14
 
11
- When iterating, prefer `--fail-fast` so you address one surviving
15
+ When iterating mutant coverage, prefer `--fail-fast` so you address one surviving
12
16
  mutant at a time:
13
17
 
14
18
  ```
15
19
  bundle exec mutant run --fail-fast
16
20
  ```
17
21
 
18
- ## When you find an alive mutation
22
+ ## When you find coverage issue
19
23
 
20
24
  Decide which bucket it falls into:
21
25
 
@@ -36,16 +40,10 @@ the user.
36
40
 
37
41
  ## Constraints
38
42
 
39
- - Line coverage must stay at 100%. Verify with:
40
-
41
- ```
42
- SIMPLECOV=1 bundle exec rspec
43
- ```
44
-
45
43
  - You may not skip mutants by configuring mutant to ignore them.
46
44
  No `expressions:` filters, no `coverage_criteria:` tweaks.
47
45
  - You may not use `send` or `__send__` to invoke private methods
48
- in tests just to satisfy mutant.
46
+ in tests just to satisfy coverage requirement.
49
47
  - You may not stub or mock the system under test (`Age`).
50
48
 
51
49
  ## Done
data/Appraisals CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise "rails-7.1" do
4
- gem "rails", "~> 7.1.0"
3
+ appraise "rails-7.2" do
4
+ gem "rails", "~> 7.2.0"
5
5
  end
6
6
 
7
7
  appraise "rails-8.1" do
data/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ This format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
5
5
 
6
6
  ## Unreleased
7
7
 
8
+ ## 0.8.0
9
+ ## Added
10
+ - An optional, read-only admin engine (`require "webhukhs/admin"`, mount `Webhukhs::Admin::Engine`) to list,
11
+ sort, filter and inspect received webhooks
12
+ - `bin/dev`, which runs the `example` app - now with the admin mounted, more handlers and seed data
13
+
14
+ ## Fixed
15
+ - Form-encoded webhooks were stored with an empty body: Rails had already read the body stream to parse
16
+ the params by the time Webhukhs got to it
17
+
18
+ ## Changed
19
+ - Rails 7.2 or newer is now required (and with it Ruby 3.1), and the test matrix runs Rails 7.2 instead of 7.1
20
+
8
21
  ## 0.7.0
9
22
  ## Added
10
23
  - Codebase is fully mutant tested now and test coverage increased
data/README.md CHANGED
@@ -19,32 +19,116 @@ Generate migrations and initializer file.
19
19
 
20
20
  `bin/rails g webhukhs:install`
21
21
 
22
- Mount webhukhs engine in your routes.
22
+ Mount webhukhs engine in `config/routes.rb` file (simple approach, with only one dynamic route showing up in `rails routes`)
23
23
 
24
24
  ```ruby
25
25
  mount Webhukhs::Engine, at: "/webhooks"
26
26
  ```
27
27
 
28
- Define a class for your first handler (let's call it `ExampleHandler`) and inherit it from `Webhukhs::BaseHandler`. We recommend `app/webhooks`, but any place known to autoloading will do. Add these to your `webhukhs.rb` config file:
28
+ Advanced mounting approach (all webhooks paths will be shown in `rails routes`)
29
+
30
+ ```ruby
31
+ Webhukhs.configuration.active_handlers.each_key do |service_id|
32
+ post "/webhooks/#{service_id}",
33
+ to: "webhukhs/receive_webhooks#create",
34
+ defaults: { service_id: service_id },
35
+ as: :"#{service_id.tr('-', '_')}_webhook"
36
+ end
37
+ ```
38
+
39
+ Define a class for your first handler (let's call it `ExampleHandler`) and inherit it from `Webhukhs::BaseHandler`. We recommend `app/webhooks`, but any place known to autoloading will do.
40
+
41
+ ```ruby
42
+ # app/webhooks/example_handler.rb
43
+ class ExampleHandler < Webhukhs::BaseHandler
44
+ # Called asynchronously to process a stored webhook.
45
+ def process(received_webhook)
46
+ payload = JSON.parse(received_webhook.body, symbolize_names: true)
47
+ # handle payload...
48
+ end
49
+
50
+ # Optional: verify the request signature before processing.
51
+ # Return false to mark the webhook as failed_validation.
52
+ def valid?(action_dispatch_request)
53
+ action_dispatch_request.headers["X-Secret-Token"] == ENV["EXAMPLE_WEBHOOK_SECRET"]
54
+ end
55
+
56
+ # Optional: use a sender-supplied ID for deduplication.
57
+ def extract_event_id_from_request(action_dispatch_request)
58
+ action_dispatch_request.headers["X-Event-Id"] || SecureRandom.uuid
59
+ end
60
+ end
61
+ ```
62
+
63
+ Add the handler to your `webhukhs.rb` config file:
29
64
 
30
65
  ```ruby
31
66
  Webhukhs.configure do |config|
32
67
  config.active_handlers = {
33
- "test-handler" => "WebhookTestHandler"
68
+ "example" => "ExampleHandler"
34
69
  }
35
70
  end
36
71
  ```
37
72
 
38
- ## Examples
39
- - `example` folder contains a demo app with engine fully configured.
40
- - We provide a number of webhook handlers which demonstrate certain features of Webhukhs. You will find them in `handler-examples`.
73
+ Now you will be able to accept webhooks on `/webhooks/example` path.
41
74
 
42
- ## Requirements
75
+ ## Admin
76
+
77
+ Webhukhs comes with a read-only admin for looking at the webhooks you have received: a sortable,
78
+ filterable list, and a page per webhook with its body (pretty-printed when it is JSON) and the
79
+ request headers it arrived with. It is not loaded by default - require it in your Gemfile (it has to be
80
+ loaded before the app boots, so `config/routes.rb` is too late):
43
81
 
44
- This project depends on two dependencies:
82
+ ```ruby
83
+ gem "webhukhs", require: ["webhukhs", "webhukhs/admin"]
84
+ ```
45
85
 
46
- - Ruby >= 3.0
47
- - Rails >= 7.0
86
+ and mount it:
87
+
88
+ ```ruby
89
+ # config/routes.rb
90
+ Rails.application.routes.draw do
91
+ mount Webhukhs::Admin::Engine, at: "/admin/webhooks"
92
+ end
93
+ ```
94
+
95
+ The admin does no authentication of its own, and webhook bodies tend to carry personal data and
96
+ secrets - so mount it behind whatever guards the rest of your admin. For example, with Devise:
97
+
98
+ ```ruby
99
+ authenticate :user, ->(user) { user.admin? } do
100
+ mount Webhukhs::Admin::Engine, at: "/admin/webhooks"
101
+ end
102
+ ```
103
+
104
+ or with HTTP basic auth:
105
+
106
+ ```ruby
107
+ webhukhs_admin = Rack::Builder.new do
108
+ use Rack::Auth::Basic do |username, password|
109
+ ActiveSupport::SecurityUtils.secure_compare(username, ENV.fetch("ADMIN_USER")) &
110
+ ActiveSupport::SecurityUtils.secure_compare(password, ENV.fetch("ADMIN_PASSWORD"))
111
+ end
112
+ run Webhukhs::Admin::Engine
113
+ end
114
+ mount webhukhs_admin, at: "/admin/webhooks"
115
+ ```
116
+
117
+ The admin brings its own CSS and JS, served by [Assiette](https://github.com/julik/assiette) from
118
+ inside the engine - it does not touch your asset pipeline (Propshaft, Sprockets or anything else) and needs
119
+ no build step.
120
+
121
+ To try it out, run `bin/dev` from a checkout of this repository. It starts the app in `example`
122
+ with some webhooks seeded, and the admin at http://localhost:3000/admin/webhukhs.
123
+
124
+ ## More Examples
125
+ - `example` folder contains a demo app with the engine and the admin fully configured - run it with `bin/dev`.
126
+ - We provide a number of webhook handlers which demonstrate certain features of Webhukhs. You will find them in `handler-examples`.
127
+
128
+ ## Requirements
129
+
130
+ - Ruby >= 3.1
131
+ - Rails >= 7.2
48
132
 
49
133
  ## Error reporter
50
134
 
@@ -64,6 +148,10 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
64
148
 
65
149
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
66
150
 
151
+ The admin also has a click-through test in a real (headless) Chrome, which `rake test` leaves out.
152
+ Run it with `bundle exec rake test:browser` - it needs Chrome or Chromium installed, and finds it
153
+ by itself or through `BROWSER_PATH`.
154
+
67
155
  ## Contributing
68
156
 
69
157
  Bug reports and pull requests are welcome on GitHub at https://github.com/skatkov/webhukhs.
data/Rakefile CHANGED
@@ -23,4 +23,11 @@ Rake::TestTask.new(:test) do |t|
23
23
  end
24
24
  end
25
25
 
26
+ # Needs Chrome, so it stays out of the default task
27
+ Rake::TestTask.new("test:browser") do |t|
28
+ t.libs << "test"
29
+ t.libs << "lib"
30
+ t.test_files = FileList["test/browser/**/*.rb"]
31
+ end
32
+
26
33
  task default: [:test, :standard]
data/example/Gemfile CHANGED
@@ -3,23 +3,22 @@
3
3
  source "https://rubygems.org"
4
4
  git_source(:github) { |repo| "https://github.com/#{repo}.git" }
5
5
 
6
- ruby "3.2.2"
7
-
8
6
  # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
9
- gem "rails", ">= 7.0.8.1"
7
+ gem "rails", ">= 7.2"
10
8
 
11
9
  # The modern asset pipeline for Rails [https://github.com/rails/propshaft]
12
10
  gem "propshaft"
13
11
 
14
12
  # Use sqlite3 as the database for Active Record
15
- gem "sqlite3", "~> 1.4"
13
+ gem "sqlite3", ">= 2.1"
16
14
 
17
15
  # Use the Puma web server [https://github.com/puma/puma]
18
- gem "puma", "~> 5.0"
16
+ gem "puma", ">= 6.0"
19
17
 
20
18
  # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
21
19
  gem "tzinfo-data", platforms: %i[mingw mswin x64_mingw jruby]
22
- gem "webhukhs", path: "../"
20
+ # The admin is optional, and has to be required before the app boots
21
+ gem "webhukhs", path: "../", require: ["webhukhs", "webhukhs/admin"]
23
22
 
24
23
  group :development, :test do
25
24
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem