rails_discord_notifier 0.3.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6527e49521148326dc463e191ed0fe51097c0625e7a09b89074615eb6b21f431
4
- data.tar.gz: 3502ab8e704d8e0d995cdd17fb8d06fc36d9c6bae13122455cb33b013c9eff3c
3
+ metadata.gz: 78212ad50963b77ccf50a72b4d7c0d79efd23557465c73cd829dc6bcc3c88251
4
+ data.tar.gz: c394690be33b31b3ff588041ccbe8232079657a479b204f968c9e58b3f30b6d0
5
5
  SHA512:
6
- metadata.gz: 2933ce5afd5ee5ae228d589c4c556fdde5dee1def8146a07204fc2230b80ccdbe89dbcbd055786af2389653518d8518e3de564d1dc3147851a8236a50f48ac5f
7
- data.tar.gz: 01a951280d579cac677a76e6e2120b9fb30b4c8c94fd584459423a0b4e1b7d65e8ab178584ef4e9b41178a216a3b010d2a0d34950d481e0ef341d28050609bc5
6
+ metadata.gz: 6b2c309fd867f9b24963e37b04958c081a984fd4c3cadb1a969b08ed981d5776dfaeea0555b87ea89722dd22249600ed7ff792ffac426d7fa367d9c57a1aba31
7
+ data.tar.gz: 39e26aa259b490ddfd3227183350a4a8dd74123e6c93527f2a228519da99ab67d83703b50c21d3179918e8c70a67a0b21ae1ed668413b9536bb2b150edfaaeca
data/CHANGELOG.md CHANGED
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.2] - 2026-10-28
11
+
12
+ ### Security
13
+
14
+ - **The URL field no longer includes the query string.** Query values were
15
+ sent twice, filtered, in the URL and in Params, and the URL copy was still
16
+ sent with `config.include_params = false`. The query string is now sent only
17
+ as part of Params, so `include_params = false` leaves it out. An exception
18
+ message that quotes a value is still sent, with its best-effort scrub.
19
+
20
+ ## [0.3.1] - 2026-10-28
21
+
22
+ ### Changed
23
+
24
+ - **Backtraces show your app's frames.** The backtrace goes through
25
+ `Rails.backtrace_cleaner`, so your own lines are no longer crowded out by gem
26
+ frames and cut off at the size limit. An error that never reaches your code
27
+ keeps its library frames, with short gem paths.
28
+ - **`Host` shows the Heroku dyno name** (`web.1`, `worker.2`) instead of the
29
+ dyno's random hostname.
30
+ - **Google Chat reports from outside a request no longer repeat the error
31
+ class** as a heading above the message.
32
+
10
33
  ## [0.3.0] - 2026-10-28
11
34
 
12
35
  ### Added
data/README.md CHANGED
@@ -63,7 +63,7 @@ Exception in POST /orders
63
63
  ActiveRecord::RecordInvalid: Validation failed: Email can't be blank
64
64
  Caused by ArgumentError: missing email
65
65
 
66
- URL https://shop.example.com/orders?utm_source=newsletter
66
+ URL https://shop.example.com/orders
67
67
  Controller orders Action create
68
68
  Environment production Release a1b2c3d
69
69
  Request ID 8f3c… Host web-01
@@ -75,6 +75,12 @@ In Google Chat, the same details as a single text message, with the params and
75
75
  backtrace in code blocks. Chat has no per-message sender name or avatar: those
76
76
  come from the name and avatar you gave the webhook when you created it.
77
77
 
78
+ The backtrace goes through `Rails.backtrace_cleaner`, as on Rails' own error
79
+ pages, so it shows your app's frames rather than gem internals. When an error
80
+ never reaches your code, such as a job class that doesn't exist, the library
81
+ frames are shown with short gem paths instead. On Heroku, `Host` is the dyno
82
+ name (`web.1`, `worker.2`) rather than the dyno's random hostname.
83
+
78
84
  ## Configuration
79
85
 
80
86
  Everything is optional except `webhook_url`.
@@ -90,7 +96,7 @@ Everything is optional except `webhook_url`.
90
96
  | `ignored_exceptions` | routing/404-style noise (see below) | Exception class names, matched including subclasses. |
91
97
  | `include_params` | `true` | Include filtered request parameters. |
92
98
  | `filter_parameters` | `[]` | Extra redaction matchers, unioned with your app's `config.filter_parameters` and the gem's built-in list. |
93
- | `backtrace_lines` | `10` | Backtrace lines to send, trimmed to fit the message size limit. |
99
+ | `backtrace_lines` | `10` | Backtrace lines to send after cleaning, trimmed to fit the message size limit. |
94
100
  | `open_timeout` / `read_timeout` / `write_timeout` | `2` / `5` / `5` | Seconds. |
95
101
  | `environment` | `Rails.env`, else `RAILS_ENV`/`RACK_ENV` | Shown as a field, and decides the `enabled` default. |
96
102
  | `release` | `nil` | Shown as a field; handy for matching an error to a deploy. |
@@ -134,9 +140,11 @@ Parameters and query strings are filtered recursively with
134
140
  `session`, `credential`).
135
141
 
136
142
  Because it is a union, enabling this gem can never redact less than your
137
- application already does. To send no parameters at all, set
138
- `config.include_params = false`. The same filter applies to extra fields from
139
- `config.context` and from `Rails.error` context.
143
+ application already does. The URL field leaves out the query string, so the
144
+ query string is sent only as part of the filtered params. To leave out params
145
+ and the query string, set `config.include_params = false`. An exception message
146
+ that quotes a parameter value is still sent (see below). The same filter
147
+ applies to extra fields from `config.context` and from `Rails.error` context.
140
148
 
141
149
  Exception messages are free text rather than structured parameters, so they get
142
150
  a best-effort scrub instead: `token=abc`, `password="x"`, `Api_Key: abc`,
@@ -22,8 +22,11 @@ module RailsDiscordNotifier
22
22
 
23
23
  private
24
24
 
25
+ # Outside a request the title is only the class name, which the description
26
+ # already opens with, so it is left out rather than repeated.
25
27
  def render(embed)
26
- heading = [bold(embed[:title]), embed[:description], ""]
28
+ heading = [embed[:description], ""]
29
+ heading.unshift(bold(embed[:title])) if request
27
30
  (heading + embed[:fields].map { |field| render_field(field) }).join("\n")
28
31
  end
29
32
 
@@ -42,7 +45,7 @@ module RailsDiscordNotifier
42
45
  end
43
46
 
44
47
  def formatted_backtrace
45
- lines = Array(exception.backtrace).first(config.backtrace_lines)
48
+ lines = clean_backtrace
46
49
  return "No backtrace available" if lines.empty?
47
50
 
48
51
  fence(lines.join("\n"))
@@ -112,7 +112,7 @@ module RailsDiscordNotifier
112
112
 
113
113
  def request_fields
114
114
  [
115
- { name: "URL", value: filtered_url },
115
+ { name: "URL", value: request_url },
116
116
  { name: "Controller", value: rails_params["controller"], inline: true },
117
117
  { name: "Action", value: rails_params["action"], inline: true },
118
118
  { name: "Environment", value: config.environment, inline: true },
@@ -169,7 +169,7 @@ module RailsDiscordNotifier
169
169
  end
170
170
 
171
171
  def formatted_backtrace
172
- lines = Array(exception.backtrace).first(config.backtrace_lines)
172
+ lines = clean_backtrace
173
173
  return "No backtrace available" if lines.empty?
174
174
 
175
175
  lines.each_with_object(+"") do |line, out|
@@ -181,21 +181,25 @@ module RailsDiscordNotifier
181
181
  end
182
182
  end
183
183
 
184
- def filtered_url
185
- return nil unless request
184
+ # The app's own frames, as on Rails' error pages, so the lines that matter
185
+ # fit the message. An error raised entirely inside library code keeps its
186
+ # library frames, with gem paths shortened. Raw frames when the cleaner is
187
+ # unavailable (no Rails) or raises, and without an app root: Rails 6.1 and
188
+ # 7.0 would then strip the leading "/" from every path.
189
+ def clean_backtrace
190
+ lines = Array(exception.backtrace)
191
+ return lines.first(config.backtrace_lines) unless Rails.root
186
192
 
187
- base = "#{request.base_url}#{request.path}"
188
- query = filtered_query_string
189
- query.empty? ? base : "#{base}?#{query}"
193
+ app_frames = Rails.backtrace_cleaner.clean(lines)
194
+ (app_frames.empty? ? Rails.backtrace_cleaner.clean(lines, :all) : app_frames).first(config.backtrace_lines)
195
+ rescue StandardError
196
+ Array(exception.backtrace).first(config.backtrace_lines)
190
197
  end
191
198
 
192
- def filtered_query_string
193
- raw = request.query_string.to_s
194
- return "" if raw.empty?
195
-
196
- Rack::Utils.build_nested_query(parameter_filter.filter(Rack::Utils.parse_nested_query(raw)))
197
- rescue StandardError
198
- ""
199
+ # Without the query string, which is sent only as part of the filtered
200
+ # Params field, so include_params = false leaves it out.
201
+ def request_url
202
+ request && "#{request.base_url}#{request.path}"
199
203
  end
200
204
 
201
205
  def request_params
@@ -232,8 +236,10 @@ module RailsDiscordNotifier
232
236
  @parameter_filter ||= ActiveSupport::ParameterFilter.new(config.filter_parameters)
233
237
  end
234
238
 
239
+ # Heroku hostnames are random IDs; DYNO ("web.1", "worker.2") names the process.
235
240
  def hostname
236
- @hostname ||= Socket.gethostname
241
+ dyno = ENV.fetch("DYNO", "")
242
+ @hostname ||= dyno.empty? ? Socket.gethostname : dyno
237
243
  rescue StandardError
238
244
  nil
239
245
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsDiscordNotifier
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_discord_notifier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - GettinDrikkieWithIt