sidekiq 8.0.10 → 8.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 +4 -4
- data/Changes.md +19 -0
- data/README.md +15 -0
- data/bin/lint-herb +13 -0
- data/lib/sidekiq/cli.rb +1 -0
- data/lib/sidekiq/config.rb +3 -4
- data/lib/sidekiq/job.rb +2 -0
- data/lib/sidekiq/job_retry.rb +7 -3
- data/lib/sidekiq/launcher.rb +4 -4
- data/lib/sidekiq/scheduled.rb +4 -2
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +1 -1
- data/lib/sidekiq/web/config.rb +3 -6
- data/lib/sidekiq/web/helpers.rb +1 -1
- data/lib/sidekiq/web.rb +23 -4
- data/sidekiq.gemspec +5 -5
- data/web/assets/stylesheets/style.css +0 -2
- data/web/views/{metrics.erb → metrics.html.erb} +3 -2
- metadata +34 -34
- data/lib/sidekiq/web/csrf_protection.rb +0 -183
- /data/web/views/{_footer.erb → _footer.html.erb} +0 -0
- /data/web/views/{_job_info.erb → _job_info.html.erb} +0 -0
- /data/web/views/{_metrics_period_select.erb → _metrics_period_select.html.erb} +0 -0
- /data/web/views/{_nav.erb → _nav.html.erb} +0 -0
- /data/web/views/{_paging.erb → _paging.html.erb} +0 -0
- /data/web/views/{_poll_link.erb → _poll_link.html.erb} +0 -0
- /data/web/views/{_summary.erb → _summary.html.erb} +0 -0
- /data/web/views/{busy.erb → busy.html.erb} +0 -0
- /data/web/views/{dashboard.erb → dashboard.html.erb} +0 -0
- /data/web/views/{dead.erb → dead.html.erb} +0 -0
- /data/web/views/{filtering.erb → filtering.html.erb} +0 -0
- /data/web/views/{layout.erb → layout.html.erb} +0 -0
- /data/web/views/{metrics_for_job.erb → metrics_for_job.html.erb} +0 -0
- /data/web/views/{morgue.erb → morgue.html.erb} +0 -0
- /data/web/views/{profiles.erb → profiles.html.erb} +0 -0
- /data/web/views/{queue.erb → queue.html.erb} +0 -0
- /data/web/views/{queues.erb → queues.html.erb} +0 -0
- /data/web/views/{retries.erb → retries.html.erb} +0 -0
- /data/web/views/{retry.erb → retry.html.erb} +0 -0
- /data/web/views/{scheduled.erb → scheduled.html.erb} +0 -0
- /data/web/views/{scheduled_job_info.erb → scheduled_job_info.html.erb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 63658318932ac6b7045211590b07f84ed9e1e6398f908ace790a0df20d5ac1f0
|
|
4
|
+
data.tar.gz: 0c3f5e69ada7529bdac7392acb1c56ef2a19b8ed13210be8c36aac19858c6df4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a5e95a2faccbbf42f8e651c4882c9495ad72b0500bb8fe77fa2a93fb4aa6f8cb96fc820621cd1910fb4b00accf35d75a99d548b3cc8ccdd41a18b5620a9ad73
|
|
7
|
+
data.tar.gz: 1bc66490ee07c548c71f680fb280e876efa7eeb8c6f234277df73211ce05c5ae29f5c9bc13064972da945568d1df6634252a6c22a7c5298bdd436b7266246c53
|
data/Changes.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
[Sidekiq Changes](https://github.com/sidekiq/sidekiq/blob/main/Changes.md) | [Sidekiq Pro Changes](https://github.com/sidekiq/sidekiq/blob/main/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/sidekiq/sidekiq/blob/main/Ent-Changes.md)
|
|
4
4
|
|
|
5
|
+
8.1.0
|
|
6
|
+
----------
|
|
7
|
+
|
|
8
|
+
- `retry_for` and `retry` are now mutually exclusive [#6878, Saidbek]
|
|
9
|
+
- `perform_inline` now enforces `strict_args!` [#6718, Saidbek]
|
|
10
|
+
- Integrate Herb linting for ERB templates [#6760, Saidbek]
|
|
11
|
+
- Remove CSRF code, use `Sec-Fetch-Site` header [#6874, deve1212]
|
|
12
|
+
- Allow custom Web UI `assets_path` for CDN purposes [#6865, stanhu]
|
|
13
|
+
- Upgrade to connection_pool 3.0
|
|
14
|
+
- Allow idle connection reaping after N seconds.
|
|
15
|
+
You can activate this **beta** feature like below.
|
|
16
|
+
Feedback requested: is this feature stable and useful for you in production?
|
|
17
|
+
This feature may or may not be enabled by default in Sidekiq 9.0.
|
|
18
|
+
```ruby
|
|
19
|
+
Sidekiq.configure_server do |cfg|
|
|
20
|
+
cfg.reap_idle_redis_connections(60)
|
|
21
|
+
end
|
|
22
|
+
```
|
|
23
|
+
|
|
5
24
|
8.0.10
|
|
6
25
|
----------
|
|
7
26
|
|
data/README.md
CHANGED
|
@@ -97,6 +97,21 @@ Contributing
|
|
|
97
97
|
|
|
98
98
|
See [the contributing guidelines](https://github.com/sidekiq/sidekiq/blob/main/.github/contributing.md).
|
|
99
99
|
|
|
100
|
+
### ERB Linting with HERB
|
|
101
|
+
|
|
102
|
+
This project uses [HERB](https://herb-tools.dev/) for ERB file linting and formatting. All ERB files have been renamed to use the `.html.erb` extension for better tooling support.
|
|
103
|
+
|
|
104
|
+
**Local Development:**
|
|
105
|
+
```bash
|
|
106
|
+
# Run HERB linting
|
|
107
|
+
bundle exec rake lint:herb
|
|
108
|
+
# or
|
|
109
|
+
bin/lint-herb
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**CI Integration:**
|
|
113
|
+
HERB linting is automatically run in CI to ensure all ERB files are properly formatted and free of parse errors.
|
|
114
|
+
|
|
100
115
|
License
|
|
101
116
|
-----------------
|
|
102
117
|
|
data/bin/lint-herb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# HERB Linting Script
|
|
5
|
+
# Run this script to lint all ERB files in the project
|
|
6
|
+
# Usage: bin/lint-herb
|
|
7
|
+
|
|
8
|
+
require "bundler/setup"
|
|
9
|
+
|
|
10
|
+
puts "🔍 Running HERB linting on ERB files..."
|
|
11
|
+
puts
|
|
12
|
+
|
|
13
|
+
exec("bundle exec herb analyze web/views -n --no-log-file")
|
data/lib/sidekiq/cli.rb
CHANGED
|
@@ -203,6 +203,7 @@ module Sidekiq # :nodoc:
|
|
|
203
203
|
},
|
|
204
204
|
# deprecated, use INFO
|
|
205
205
|
"TTIN" => ->(cli) {
|
|
206
|
+
cli.logger.error { "DEPRECATED: Please use the INFO signal for backtraces, support for TTIN will be removed in Sidekiq 9.0." }
|
|
206
207
|
Thread.list.each do |thread|
|
|
207
208
|
cli.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
|
|
208
209
|
if thread.backtrace
|
data/lib/sidekiq/config.rb
CHANGED
|
@@ -37,7 +37,7 @@ module Sidekiq
|
|
|
37
37
|
reloader: proc { |&block| block.call },
|
|
38
38
|
backtrace_cleaner: ->(backtrace) { backtrace },
|
|
39
39
|
logged_job_attributes: ["bid", "tags"],
|
|
40
|
-
|
|
40
|
+
redis_idle_timeout: nil
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
ERROR_HANDLER = ->(ex, ctx, cfg = Sidekiq.default_configuration) {
|
|
@@ -146,10 +146,9 @@ module Sidekiq
|
|
|
146
146
|
@redis_config = @redis_config.merge(hash)
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
def reap_idle_redis_connections(timeout =
|
|
150
|
-
self[:
|
|
149
|
+
def reap_idle_redis_connections(timeout = 60)
|
|
150
|
+
self[:redis_idle_timeout] = timeout
|
|
151
151
|
end
|
|
152
|
-
alias_method :reap, :reap_idle_redis_connections
|
|
153
152
|
|
|
154
153
|
def redis_pool
|
|
155
154
|
Thread.current[:sidekiq_redis_pool] || Thread.current[:sidekiq_capsule]&.redis_pool || local_redis_pool
|
data/lib/sidekiq/job.rb
CHANGED
data/lib/sidekiq/job_retry.rb
CHANGED
|
@@ -178,10 +178,14 @@ module Sidekiq
|
|
|
178
178
|
msg["error_backtrace"] = compress_backtrace(lines)
|
|
179
179
|
end
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
# retry_for and retry are mutually exclusive - if retry_for is set,
|
|
182
|
+
# we exclusively use duration-based retry logic and ignore count-based logic
|
|
183
183
|
rf = msg["retry_for"]
|
|
184
|
-
|
|
184
|
+
if rf
|
|
185
|
+
return retries_exhausted(jobinst, msg, exception) if (time_for(msg["failed_at"]) + rf) < Time.now
|
|
186
|
+
elsif count >= max_retry_attempts
|
|
187
|
+
return retries_exhausted(jobinst, msg, exception)
|
|
188
|
+
end
|
|
185
189
|
|
|
186
190
|
strategy, delay = delay_for(jobinst, count, exception, msg)
|
|
187
191
|
case strategy
|
data/lib/sidekiq/launcher.rb
CHANGED
|
@@ -142,10 +142,10 @@ module Sidekiq
|
|
|
142
142
|
key = identity
|
|
143
143
|
fails = procd = 0
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
if
|
|
147
|
-
config.capsules.each_value { |cap| cap.local_redis_pool.reap(
|
|
148
|
-
config.local_redis_pool.reap(
|
|
145
|
+
idle_timeout = config[:redis_idle_timeout]
|
|
146
|
+
if idle_timeout
|
|
147
|
+
config.capsules.each_value { |cap| cap.local_redis_pool.reap(idle_seconds: idle_timeout, &:close) }
|
|
148
|
+
config.local_redis_pool.reap(idle_seconds: idle_timeout, &:close)
|
|
149
149
|
end
|
|
150
150
|
|
|
151
151
|
begin
|
data/lib/sidekiq/scheduled.rb
CHANGED
|
@@ -72,6 +72,7 @@ module Sidekiq
|
|
|
72
72
|
include Sidekiq::Component
|
|
73
73
|
|
|
74
74
|
INITIAL_WAIT = 10
|
|
75
|
+
attr_accessor :rnd
|
|
75
76
|
|
|
76
77
|
def initialize(config)
|
|
77
78
|
@config = config
|
|
@@ -80,6 +81,7 @@ module Sidekiq
|
|
|
80
81
|
@done = false
|
|
81
82
|
@thread = nil
|
|
82
83
|
@count_calls = 0
|
|
84
|
+
@rnd = Random.new
|
|
83
85
|
end
|
|
84
86
|
|
|
85
87
|
# Shut down this instance, will pause until the thread is dead.
|
|
@@ -151,11 +153,11 @@ module Sidekiq
|
|
|
151
153
|
|
|
152
154
|
if count < 10
|
|
153
155
|
# For small clusters, calculate a random interval that is ±50% the desired average.
|
|
154
|
-
interval * rand + interval.to_f / 2
|
|
156
|
+
interval * @rnd.rand + interval.to_f / 2
|
|
155
157
|
else
|
|
156
158
|
# With 10+ processes, we should have enough randomness to get decent polling
|
|
157
159
|
# across the entire timespan
|
|
158
|
-
interval * rand * 2
|
|
160
|
+
interval * @rnd.rand * 2
|
|
159
161
|
end
|
|
160
162
|
end
|
|
161
163
|
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/action.rb
CHANGED
|
@@ -117,7 +117,7 @@ module Sidekiq
|
|
|
117
117
|
if content.is_a? Symbol
|
|
118
118
|
unless respond_to?(:"_erb_#{content}")
|
|
119
119
|
views = options[:views] || Web.views
|
|
120
|
-
filename = "#{views}/#{content}.erb"
|
|
120
|
+
filename = "#{views}/#{content}.html.erb"
|
|
121
121
|
src = ERB.new(File.read(filename)).src
|
|
122
122
|
|
|
123
123
|
# Need to use lineno less by 1 because erb generates a
|
data/lib/sidekiq/web/config.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "sidekiq/web/csrf_protection"
|
|
4
|
-
|
|
5
3
|
module Sidekiq
|
|
6
4
|
class Web
|
|
7
5
|
##
|
|
@@ -24,10 +22,7 @@ module Sidekiq
|
|
|
24
22
|
# and very difficult for us to vendor or provide ourselves. If you are worried
|
|
25
23
|
# about data security and wish to self-host, you can change these URLs.
|
|
26
24
|
profile_view_url: "https://profiler.firefox.com/public/%s",
|
|
27
|
-
profile_store_url: "https://api.profiler.firefox.com/compressed-store"
|
|
28
|
-
# TODO Will be false in Sidekiq 9.0.
|
|
29
|
-
# CSRF is unnecessary if you are using SameSite=(Strict|Lax) cookies.
|
|
30
|
-
csrf: true
|
|
25
|
+
profile_store_url: "https://api.profiler.firefox.com/compressed-store"
|
|
31
26
|
}
|
|
32
27
|
|
|
33
28
|
##
|
|
@@ -54,11 +49,13 @@ module Sidekiq
|
|
|
54
49
|
|
|
55
50
|
# Adds the "Back to App" link in the header
|
|
56
51
|
attr_accessor :app_url
|
|
52
|
+
attr_accessor :assets_path
|
|
57
53
|
|
|
58
54
|
def initialize
|
|
59
55
|
@options = OPTIONS.dup
|
|
60
56
|
@locales = LOCALES
|
|
61
57
|
@views = VIEWS
|
|
58
|
+
@assets_path = ASSETS
|
|
62
59
|
@tabs = DEFAULT_TABS.dup
|
|
63
60
|
@middlewares = []
|
|
64
61
|
@custom_job_info_rows = []
|
data/lib/sidekiq/web/helpers.rb
CHANGED
data/lib/sidekiq/web.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Sidekiq
|
|
|
13
13
|
ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../web")
|
|
14
14
|
VIEWS = "#{ROOT}/views"
|
|
15
15
|
LOCALES = ["#{ROOT}/locales"]
|
|
16
|
-
LAYOUT = "#{VIEWS}/layout.erb"
|
|
16
|
+
LAYOUT = "#{VIEWS}/layout.html.erb"
|
|
17
17
|
ASSETS = "#{ROOT}/assets"
|
|
18
18
|
|
|
19
19
|
DEFAULT_TABS = {
|
|
@@ -42,6 +42,12 @@ module Sidekiq
|
|
|
42
42
|
@@config.app_url = url
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
def assets_path=(path)
|
|
46
|
+
@@config.assets_path = path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def assets_path = @@config.assets_path
|
|
50
|
+
|
|
45
51
|
def tabs = @@config.tabs
|
|
46
52
|
|
|
47
53
|
def locales = @@config.locales
|
|
@@ -87,13 +93,27 @@ module Sidekiq
|
|
|
87
93
|
env[:web_config] = Sidekiq::Web.configure
|
|
88
94
|
env[:csp_nonce] = SecureRandom.hex(8)
|
|
89
95
|
env[:redis_pool] = self.class.redis_pool
|
|
90
|
-
app.call(env)
|
|
96
|
+
safe_request?(env) ? app.call(env) : deny(env)
|
|
91
97
|
end
|
|
92
98
|
|
|
93
99
|
def app
|
|
94
100
|
@app ||= build(@@config)
|
|
95
101
|
end
|
|
96
102
|
|
|
103
|
+
def safe_methods?(env)
|
|
104
|
+
%w[GET HEAD OPTIONS TRACE].include? env["REQUEST_METHOD"]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def safe_request?(env)
|
|
108
|
+
return true if safe_methods?(env)
|
|
109
|
+
env["HTTP_SEC_FETCH_SITE"] == "same-origin"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def deny(env)
|
|
113
|
+
Sidekiq.logger.warn "attack prevented by #{self.class}"
|
|
114
|
+
[403, {Rack::CONTENT_TYPE => "text/plain"}, ["Forbidden"]]
|
|
115
|
+
end
|
|
116
|
+
|
|
97
117
|
private
|
|
98
118
|
|
|
99
119
|
def build(cfg)
|
|
@@ -105,11 +125,10 @@ module Sidekiq
|
|
|
105
125
|
|
|
106
126
|
::Rack::Builder.new do
|
|
107
127
|
use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"],
|
|
108
|
-
root:
|
|
128
|
+
root: cfg.assets_path,
|
|
109
129
|
cascade: true,
|
|
110
130
|
header_rules: rules
|
|
111
131
|
m.each { |middleware, block| use(*middleware, &block) }
|
|
112
|
-
use CsrfProtection if cfg[:csrf]
|
|
113
132
|
run Sidekiq::Web::Application.new(self.class)
|
|
114
133
|
end
|
|
115
134
|
end
|
data/sidekiq.gemspec
CHANGED
|
@@ -23,9 +23,9 @@ Gem::Specification.new do |gem|
|
|
|
23
23
|
"rubygems_mfa_required" => "true"
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
gem.add_dependency "redis-client", ">= 0.
|
|
27
|
-
gem.add_dependency "connection_pool", ">=
|
|
28
|
-
gem.add_dependency "rack", ">= 3.
|
|
29
|
-
gem.add_dependency "json", ">= 2.
|
|
30
|
-
gem.add_dependency "logger", ">= 1.
|
|
26
|
+
gem.add_dependency "redis-client", ">= 0.26.0"
|
|
27
|
+
gem.add_dependency "connection_pool", ">= 3.0.0"
|
|
28
|
+
gem.add_dependency "rack", ">= 3.2.0"
|
|
29
|
+
gem.add_dependency "json", ">= 2.16.0"
|
|
30
|
+
gem.add_dependency "logger", ">= 1.7.0"
|
|
31
31
|
end
|
|
@@ -58,8 +58,9 @@
|
|
|
58
58
|
id="<%= id %>"
|
|
59
59
|
class="metrics-swatch"
|
|
60
60
|
value="<%= kls %>"
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
<% if visible_kls.include?(kls) %>
|
|
62
|
+
checked
|
|
63
|
+
<% end %>>
|
|
63
64
|
<code><a href="<%= root_path %>metrics/<%= kls %>?period=<%= @period %>"><%= kls %></a></code>
|
|
64
65
|
</div>
|
|
65
66
|
</td>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sidekiq
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.0
|
|
4
|
+
version: 8.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mike Perham
|
|
@@ -15,70 +15,70 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.26.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.26.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: connection_pool
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version:
|
|
32
|
+
version: 3.0.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version:
|
|
39
|
+
version: 3.0.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: rack
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: 3.
|
|
46
|
+
version: 3.2.0
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - ">="
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: 3.
|
|
53
|
+
version: 3.2.0
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: json
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
|
58
58
|
- - ">="
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: 2.
|
|
60
|
+
version: 2.16.0
|
|
61
61
|
type: :runtime
|
|
62
62
|
prerelease: false
|
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
65
|
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: 2.
|
|
67
|
+
version: 2.16.0
|
|
68
68
|
- !ruby/object:Gem::Dependency
|
|
69
69
|
name: logger
|
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
|
71
71
|
requirements:
|
|
72
72
|
- - ">="
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 1.
|
|
74
|
+
version: 1.7.0
|
|
75
75
|
type: :runtime
|
|
76
76
|
prerelease: false
|
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
79
|
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 1.
|
|
81
|
+
version: 1.7.0
|
|
82
82
|
description: Simple, efficient background processing for Ruby.
|
|
83
83
|
email:
|
|
84
84
|
- info@contribsys.com
|
|
@@ -91,6 +91,7 @@ files:
|
|
|
91
91
|
- Changes.md
|
|
92
92
|
- LICENSE.txt
|
|
93
93
|
- README.md
|
|
94
|
+
- bin/lint-herb
|
|
94
95
|
- bin/multi_queue_bench
|
|
95
96
|
- bin/sidekiq
|
|
96
97
|
- bin/sidekiqload
|
|
@@ -151,7 +152,6 @@ files:
|
|
|
151
152
|
- lib/sidekiq/web/action.rb
|
|
152
153
|
- lib/sidekiq/web/application.rb
|
|
153
154
|
- lib/sidekiq/web/config.rb
|
|
154
|
-
- lib/sidekiq/web/csrf_protection.rb
|
|
155
155
|
- lib/sidekiq/web/helpers.rb
|
|
156
156
|
- lib/sidekiq/web/router.rb
|
|
157
157
|
- lib/sidekiq/worker_compatibility_alias.rb
|
|
@@ -199,28 +199,28 @@ files:
|
|
|
199
199
|
- web/locales/vi.yml
|
|
200
200
|
- web/locales/zh-CN.yml
|
|
201
201
|
- web/locales/zh-TW.yml
|
|
202
|
-
- web/views/_footer.erb
|
|
203
|
-
- web/views/_job_info.erb
|
|
204
|
-
- web/views/_metrics_period_select.erb
|
|
205
|
-
- web/views/_nav.erb
|
|
206
|
-
- web/views/_paging.erb
|
|
207
|
-
- web/views/_poll_link.erb
|
|
208
|
-
- web/views/_summary.erb
|
|
209
|
-
- web/views/busy.erb
|
|
210
|
-
- web/views/dashboard.erb
|
|
211
|
-
- web/views/dead.erb
|
|
212
|
-
- web/views/filtering.erb
|
|
213
|
-
- web/views/layout.erb
|
|
214
|
-
- web/views/metrics.erb
|
|
215
|
-
- web/views/metrics_for_job.erb
|
|
216
|
-
- web/views/morgue.erb
|
|
217
|
-
- web/views/profiles.erb
|
|
218
|
-
- web/views/queue.erb
|
|
219
|
-
- web/views/queues.erb
|
|
220
|
-
- web/views/retries.erb
|
|
221
|
-
- web/views/retry.erb
|
|
222
|
-
- web/views/scheduled.erb
|
|
223
|
-
- web/views/scheduled_job_info.erb
|
|
202
|
+
- web/views/_footer.html.erb
|
|
203
|
+
- web/views/_job_info.html.erb
|
|
204
|
+
- web/views/_metrics_period_select.html.erb
|
|
205
|
+
- web/views/_nav.html.erb
|
|
206
|
+
- web/views/_paging.html.erb
|
|
207
|
+
- web/views/_poll_link.html.erb
|
|
208
|
+
- web/views/_summary.html.erb
|
|
209
|
+
- web/views/busy.html.erb
|
|
210
|
+
- web/views/dashboard.html.erb
|
|
211
|
+
- web/views/dead.html.erb
|
|
212
|
+
- web/views/filtering.html.erb
|
|
213
|
+
- web/views/layout.html.erb
|
|
214
|
+
- web/views/metrics.html.erb
|
|
215
|
+
- web/views/metrics_for_job.html.erb
|
|
216
|
+
- web/views/morgue.html.erb
|
|
217
|
+
- web/views/profiles.html.erb
|
|
218
|
+
- web/views/queue.html.erb
|
|
219
|
+
- web/views/queues.html.erb
|
|
220
|
+
- web/views/retries.html.erb
|
|
221
|
+
- web/views/retry.html.erb
|
|
222
|
+
- web/views/scheduled.html.erb
|
|
223
|
+
- web/views/scheduled_job_info.html.erb
|
|
224
224
|
homepage: https://sidekiq.org
|
|
225
225
|
licenses:
|
|
226
226
|
- LGPL-3.0
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# this file originally based on authenticity_token.rb from the sinatra/rack-protection project
|
|
4
|
-
#
|
|
5
|
-
# The MIT License (MIT)
|
|
6
|
-
#
|
|
7
|
-
# Copyright (c) 2011-2017 Konstantin Haase
|
|
8
|
-
# Copyright (c) 2015-2017 Zachary Scott
|
|
9
|
-
#
|
|
10
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
|
11
|
-
# a copy of this software and associated documentation files (the
|
|
12
|
-
# 'Software'), to deal in the Software without restriction, including
|
|
13
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
|
14
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
15
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
|
16
|
-
# the following conditions:
|
|
17
|
-
#
|
|
18
|
-
# The above copyright notice and this permission notice shall be
|
|
19
|
-
# included in all copies or substantial portions of the Software.
|
|
20
|
-
#
|
|
21
|
-
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
22
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
23
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
24
|
-
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
25
|
-
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
26
|
-
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
27
|
-
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
|
-
|
|
29
|
-
require "securerandom"
|
|
30
|
-
require "rack/request"
|
|
31
|
-
|
|
32
|
-
module Sidekiq
|
|
33
|
-
class Web
|
|
34
|
-
class CsrfProtection
|
|
35
|
-
def initialize(app, options = nil)
|
|
36
|
-
@app = app
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def call(env)
|
|
40
|
-
accept?(env) ? admit(env) : deny(env)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
private
|
|
44
|
-
|
|
45
|
-
def admit(env)
|
|
46
|
-
# On each successful request, we create a fresh masked token
|
|
47
|
-
# which will be used in any forms rendered for this request.
|
|
48
|
-
s = session(env)
|
|
49
|
-
s[:csrf] ||= SecureRandom.base64(TOKEN_LENGTH)
|
|
50
|
-
env[:csrf_token] = mask_token(s[:csrf])
|
|
51
|
-
@app.call(env)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def safe?(env)
|
|
55
|
-
%w[GET HEAD OPTIONS TRACE].include? env["REQUEST_METHOD"]
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def logger(env)
|
|
59
|
-
@logger ||= env["rack.logger"] || ::Logger.new(env["rack.errors"])
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def deny(env)
|
|
63
|
-
logger(env).warn "attack prevented by #{self.class}"
|
|
64
|
-
[403, {Rack::CONTENT_TYPE => "text/plain"}, ["Forbidden"]]
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def session(env)
|
|
68
|
-
env["rack.session"] || fail(<<~EOM)
|
|
69
|
-
Sidekiq::Web needs a valid Rack session for CSRF protection. If this is a Rails app,
|
|
70
|
-
make sure you mount Sidekiq::Web *inside* your application routes:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Rails.application.routes.draw do
|
|
74
|
-
mount Sidekiq::Web => "/sidekiq"
|
|
75
|
-
....
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
If this is a Rails app in API mode, you need to enable sessions.
|
|
80
|
-
|
|
81
|
-
https://guides.rubyonrails.org/api_app.html#using-session-middlewares
|
|
82
|
-
|
|
83
|
-
If this is a bare Rack app, use a session middleware before Sidekiq::Web:
|
|
84
|
-
|
|
85
|
-
# first, use IRB to create a shared secret key for sessions and commit it
|
|
86
|
-
require 'securerandom'; File.open(".session.key", "w") {|f| f.write(SecureRandom.hex(32)) }
|
|
87
|
-
|
|
88
|
-
# now use the secret with a session cookie middleware
|
|
89
|
-
use Rack::Session::Cookie, secret: File.read(".session.key"), same_site: true, max_age: 86400
|
|
90
|
-
run Sidekiq::Web
|
|
91
|
-
|
|
92
|
-
EOM
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def accept?(env)
|
|
96
|
-
return true if safe?(env)
|
|
97
|
-
|
|
98
|
-
giventoken = ::Rack::Request.new(env).params["authenticity_token"]
|
|
99
|
-
valid_token?(env, giventoken)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
TOKEN_LENGTH = 32
|
|
103
|
-
|
|
104
|
-
# Checks that the token given to us as a parameter matches
|
|
105
|
-
# the token stored in the session.
|
|
106
|
-
def valid_token?(env, giventoken)
|
|
107
|
-
return false if giventoken.nil? || giventoken.empty?
|
|
108
|
-
|
|
109
|
-
begin
|
|
110
|
-
token = decode_token(giventoken)
|
|
111
|
-
rescue ArgumentError # client input is invalid
|
|
112
|
-
return false
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
sess = session(env)
|
|
116
|
-
localtoken = sess[:csrf]
|
|
117
|
-
|
|
118
|
-
# Checks that Rack::Session::Cookie actually contains the csrf token
|
|
119
|
-
return false if localtoken.nil?
|
|
120
|
-
|
|
121
|
-
# Rotate the session token after every use
|
|
122
|
-
sess[:csrf] = SecureRandom.base64(TOKEN_LENGTH)
|
|
123
|
-
|
|
124
|
-
# See if it's actually a masked token or not. We should be able
|
|
125
|
-
# to handle any unmasked tokens that we've issued without error.
|
|
126
|
-
|
|
127
|
-
if unmasked_token?(token)
|
|
128
|
-
compare_with_real_token token, localtoken
|
|
129
|
-
elsif masked_token?(token)
|
|
130
|
-
unmasked = unmask_token(token)
|
|
131
|
-
compare_with_real_token unmasked, localtoken
|
|
132
|
-
else
|
|
133
|
-
false # Token is malformed
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# Creates a masked version of the authenticity token that varies
|
|
138
|
-
# on each request. The masking is used to mitigate SSL attacks
|
|
139
|
-
# like BREACH.
|
|
140
|
-
def mask_token(token)
|
|
141
|
-
token = decode_token(token)
|
|
142
|
-
one_time_pad = SecureRandom.random_bytes(token.length)
|
|
143
|
-
encrypted_token = xor_byte_strings(one_time_pad, token)
|
|
144
|
-
masked_token = one_time_pad + encrypted_token
|
|
145
|
-
encode_token(masked_token)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
# Essentially the inverse of +mask_token+.
|
|
149
|
-
def unmask_token(masked_token)
|
|
150
|
-
# Split the token into the one-time pad and the encrypted
|
|
151
|
-
# value and decrypt it
|
|
152
|
-
token_length = masked_token.length / 2
|
|
153
|
-
one_time_pad = masked_token[0...token_length]
|
|
154
|
-
encrypted_token = masked_token[token_length..]
|
|
155
|
-
xor_byte_strings(one_time_pad, encrypted_token)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def unmasked_token?(token)
|
|
159
|
-
token.length == TOKEN_LENGTH
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def masked_token?(token)
|
|
163
|
-
token.length == TOKEN_LENGTH * 2
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def compare_with_real_token(token, local)
|
|
167
|
-
::Rack::Utils.secure_compare(token.to_s, decode_token(local).to_s)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def encode_token(token)
|
|
171
|
-
[token].pack("m0").tr("+/", "-_")
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def decode_token(token)
|
|
175
|
-
token.tr("-_", "+/").unpack1("m0")
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def xor_byte_strings(s1, s2)
|
|
179
|
-
s1.bytes.zip(s2.bytes).map { |(c1, c2)| c1 ^ c2 }.pack("c*")
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|