bullet 8.0.4 → 8.0.6

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: a61908a92c8bc22bba69f9ea56946f1b6b2abd320e392e7539a3a6024b939b0c
4
- data.tar.gz: 1fc844bc72f0e9e4c046590ef3f981180ce0beb5e32fab2217592d21e3456705
3
+ metadata.gz: f00b664af513340b8b094dfa967a2dbd2c3a72edfcb0031532dd4ba38a1fb4b2
4
+ data.tar.gz: 76b42f07c889542a50cc75a52d52fef26bf8647721d3c9913eb4f1dbb21db9a0
5
5
  SHA512:
6
- metadata.gz: 456c8c81a574243cda8ad3a3bb728b0ae97f169434e1608158a72967b8f9a6e7153939fcb2ce7c9d9e363921e918871e6a8b3ed7c374a45bc910170a4cb3e779
7
- data.tar.gz: 3ebfc6724a13326f9d2286506727edb5d47b66b01253fbc48a2407d9e7f1c6c3f8ac700d7405024fcc86766a9fd65d170d0eea0678ffd1af3c60dd90b0c82b06
6
+ metadata.gz: db329cba6757c1ec372a7a7b6a8a9aa4a92fd5c63ce1a0e92cd43c89abd852768a83eddd95873a1cdeb2155abfa899d4c385df2a670b326c3eaa8736398a996e
7
+ data.tar.gz: 35c6df4a0e0aefd934c1038f2dc5faa7978cbe7b81e482ea0ca931045d4b445a67d33d0c69d603830111cee46f9bf5128a9824277de7ef3dc347c10eae5d84ea
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  ## Next Release
2
2
 
3
- ## 8.0.4 (04/18/2024)
3
+ ## 8.0.6 (05/07/2025)
4
+
5
+ * Add CSP nonce for footer styles as well
6
+ * Add support for OpenTelemetry reporting
7
+
8
+ ## 8.0.5 (04/21/2025)
9
+
10
+ * Properly insert ContentSecurityPolicy middleware
11
+ * Properly parse query string
12
+
13
+ ## 8.0.4 (04/18/2025)
4
14
 
5
15
  * Insert bullet middleware before `ContentSecurityPolicy`
6
16
  * Support url query `skip_html_injection=true`
data/README.md CHANGED
@@ -74,6 +74,7 @@ config.after_initialize do
74
74
  Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
75
75
  Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware', ['my_file.rb', 'my_method'], ['my_file.rb', 16..20] ]
76
76
  Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' }
77
+ Bullet.opentelemetry = true
77
78
  end
78
79
  ```
79
80
 
@@ -100,6 +101,7 @@ The code above will enable all of the Bullet notification systems:
100
101
  Each item can be a string (match substring), a regex, or an array where the first item is a path to match, and the second
101
102
  item is a line number, a Range of line numbers, or a (bare) method name, to exclude only particular lines in a file.
102
103
  * `Bullet.slack`: add notifications to slack
104
+ * `Bullet.opentelemetry`: add notifications to OpenTelemetry
103
105
  * `Bullet.raise`: raise errors, useful for making your specs fail unless they have optimized queries
104
106
  * `Bullet.always_append_html_body`: always append the html body even if no notifications are present. Note: `console` or `add_footer` must also be true. Useful for Single Page Applications where the initial page load might not have any notifications present.
105
107
  * `Bullet.skip_user_in_notification`: exclude the OS user (`whoami`) from notifications.
data/lib/bullet/rack.rb CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  require 'rack/request'
4
4
  require 'json'
5
+ require 'cgi'
5
6
 
6
7
  module Bullet
7
8
  class Rack
8
9
  include Dependency
9
10
 
10
- NONCE_MATCHER = /script-src .*'nonce-(?<nonce>[A-Za-z0-9+\/]+={0,2})'/
11
+ NONCE_MATCHER = /(script|style)-src .*'nonce-(?<nonce>[A-Za-z0-9+\/]+={0,2})'/
11
12
 
12
13
  def initialize(app)
13
14
  @app = app
@@ -28,7 +29,7 @@ module Bullet
28
29
  response_body = response_body(response)
29
30
 
30
31
  with_security_policy_nonce(headers) do |nonce|
31
- response_body = append_to_html_body(response_body, footer_note) if Bullet.add_footer
32
+ response_body = append_to_html_body(response_body, footer_note(nonce)) if Bullet.add_footer
32
33
  response_body = append_to_html_body(response_body, Bullet.gather_inline_notifications)
33
34
  if Bullet.add_footer && !Bullet.skip_http_headers
34
35
  response_body = append_to_html_body(response_body, xhr_script(nonce))
@@ -69,8 +70,22 @@ module Bullet
69
70
  end
70
71
  end
71
72
 
72
- def footer_note
73
- "<details #{details_attributes}><summary #{summary_attributes}>Bullet Warnings</summary><div #{footer_content_attributes}>#{Bullet.footer_info.uniq.join('<br>')}#{footer_console_message}</div></details>"
73
+ def footer_note(nonce = nil)
74
+ %(<details id="bullet-footer" data-is-bullet-footer><summary>Bullet Warnings</summary><div>#{Bullet.footer_info.uniq.join('<br>')}#{footer_console_message(nonce)}</div>#{footer_style(nonce)}</details>)
75
+ end
76
+
77
+ # Make footer styles work with ContentSecurityPolicy style-src as self
78
+ def footer_style(nonce = nil)
79
+ css = <<~CSS
80
+ details#bullet-footer {cursor: pointer; position: fixed; left: 0px; bottom: 0px; z-index: 9999; background: #fdf2f2; color: #9b1c1c; font-size: 12px; border-radius: 0px 8px 0px 0px; border: 1px solid #9b1c1c;}
81
+ details#bullet-footer summary {font-weight: 600; padding: 2px 8px;}
82
+ details#bullet-footer div {padding: 8px; border-top: 1px solid #9b1c1c;}
83
+ CSS
84
+ if nonce
85
+ %(<style type="text/css" nonce="#{nonce}">#{css}</style>)
86
+ else
87
+ %(<style type="text/css">#{css}</style>)
88
+ end
74
89
  end
75
90
 
76
91
  def set_header(headers, header_name, header_array)
@@ -85,17 +100,20 @@ module Bullet
85
100
  query_string = request.env['QUERY_STRING']
86
101
  return false if query_string.nil? || query_string.empty?
87
102
 
88
- if defined?(Rack::QueryParser)
89
- parser = Rack::QueryParser.new
90
- params = parser.parse_nested_query(query_string)
91
- else
92
- # compatible with rack 1.x,
93
- # remove it after dropping rails 4.2 suppport
94
- params = Rack::Utils.parse_nested_query(query_string)
95
- end
103
+ params = simple_parse_query_string(query_string)
96
104
  params['skip_html_injection'] == 'true'
97
105
  end
98
106
 
107
+ # Simple query string parser
108
+ def simple_parse_query_string(query_string)
109
+ params = {}
110
+ query_string.split('&').each do |pair|
111
+ key, value = pair.split('=', 2).map { |s| CGI.unescape(s) }
112
+ params[key] = value if key && !key.empty?
113
+ end
114
+ params
115
+ end
116
+
99
117
  def file?(headers)
100
118
  headers['Content-Transfer-Encoding'] == 'binary' || headers['Content-Disposition']
101
119
  end
@@ -118,28 +136,18 @@ module Bullet
118
136
 
119
137
  private
120
138
 
121
- def details_attributes
122
- <<~EOF
123
- id="bullet-footer" data-is-bullet-footer
124
- style="cursor: pointer; position: fixed; left: 0px; bottom: 0px; z-index: 9999; background: #fdf2f2; color: #9b1c1c; font-size: 12px; border-radius: 0px 8px 0px 0px; border: 1px solid #9b1c1c;"
125
- EOF
126
- end
127
-
128
- def summary_attributes
129
- <<~EOF
130
- style="font-weight: 600; padding: 2px 8px"
131
- EOF
132
- end
133
-
134
- def footer_content_attributes
135
- <<~EOF
136
- style="padding: 8px; border-top: 1px solid #9b1c1c;"
137
- EOF
138
- end
139
-
140
- def footer_console_message
139
+ def footer_console_message(nonce = nil)
141
140
  if Bullet.console_enabled?
142
- "<br/><span style='font-style: italic;'>See 'Uniform Notifier' in JS Console for Stacktrace</span>"
141
+ footer = %(<br/><span id="console-message">See 'Uniform Notifier' in JS Console for Stacktrace</span>)
142
+ css = "details#bullet-footer #console-message {font-style: italic;}"
143
+ style =
144
+ if nonce
145
+ %(<style type="text/css" nonce="#{nonce}">#{css}</style>)
146
+ else
147
+ %(<style type="text/css">#{css}</style>)
148
+ end
149
+
150
+ footer + style
143
151
  end
144
152
  end
145
153
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bullet
4
- VERSION = '8.0.4'
4
+ VERSION = '8.0.6'
5
5
  end
data/lib/bullet.rb CHANGED
@@ -23,11 +23,14 @@ module Bullet
23
23
 
24
24
  if defined?(Rails::Railtie)
25
25
  class BulletRailtie < Rails::Railtie
26
- initializer 'bullet.configure_rails_initialization' do |app|
27
- if defined?(ActionDispatch::ContentSecurityPolicy::Middleware)
28
- app.middleware.insert_before ActionDispatch::ContentSecurityPolicy::Middleware, Bullet::Rack
29
- else
26
+ initializer 'bullet.add_middleware' do |app|
27
+ # I don't find a way to detect if the middleware is already in the stack,
28
+ # so I'm using the api_only flag.
29
+ # If it is true, ActionDispatch::ContentSecurityPolicy::Middleware is not in the stack.
30
+ if app.config.api_only || !defined?(ActionDispatch::ContentSecurityPolicy::Middleware)
30
31
  app.middleware.use Bullet::Rack
32
+ else
33
+ app.middleware.insert_before ActionDispatch::ContentSecurityPolicy::Middleware, Bullet::Rack
31
34
  end
32
35
  end
33
36
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.4
4
+ version: 8.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport
@@ -112,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
112
  - !ruby/object:Gem::Version
113
113
  version: 1.3.6
114
114
  requirements: []
115
- rubygems_version: 3.6.2
115
+ rubygems_version: 3.6.7
116
116
  specification_version: 4
117
117
  summary: help to kill N+1 queries and unused eager loading.
118
118
  test_files: []