sentry-sanitizer 0.8.3 → 0.10.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/.github/workflows/{ci-linux.yml → ci.yml} +2 -1
- data/.rubocop.yml +6 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile +6 -1
- data/Gemfile.lock +28 -2
- data/README.md +13 -8
- data/bin/bundle +13 -11
- data/lib/sentry/sanitizer/cleaner.rb +20 -63
- data/lib/sentry/sanitizer/configuration.rb +28 -1
- data/lib/sentry/sanitizer/configuration_mixin.rb +58 -3
- data/lib/sentry/sanitizer/filter.rb +53 -0
- data/lib/sentry/sanitizer/version.rb +1 -1
- data/sentry-sanitizer.gemspec +1 -1
- metadata +5 -5
- data/.github/workflows/ci-macos.yml +0 -40
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 66ddbe0333a1066f7d4211acfcc2aac24576a4746250bd704e3a89463f079819
|
|
4
|
+
data.tar.gz: f468dfe97322b7a7c292f500359452c689be0714b13715d2efb61f75e0144e19
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc6683ac363591cc334b986955bb2c5bbc7590d883139b62f5e6347c5782ef01255a5db627deaa026270267434f1fa2769e4df7e2f6b696c48aa207cd5a58b9f
|
|
7
|
+
data.tar.gz: a12af9ce0587f0d8d4068524bf34c1db70d66114ce04348d2a210d54798099d6b27bc2e669720fb16bb246727a5d2ef38d00604be773988f7b756672002544d8
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name: CI
|
|
1
|
+
name: CI
|
|
2
2
|
on:
|
|
3
3
|
push:
|
|
4
4
|
pull_request:
|
|
@@ -11,6 +11,7 @@ jobs:
|
|
|
11
11
|
matrix:
|
|
12
12
|
include:
|
|
13
13
|
- { ruby_version: 3.3, sentry_version: "~> 6.0" }
|
|
14
|
+
- { ruby_version: 3.3, sentry_version: "~> 7.0" }
|
|
14
15
|
- { ruby_version: 3.4, sentry_version: "~> 6.0" }
|
|
15
16
|
- { ruby_version: 3.4, sentry_version: "~> 7.0" }
|
|
16
17
|
- { ruby_version: 4.0, sentry_version: "~> 6.0" }
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
- Sanitize transaction events (`before_send_transaction`) and check-in events (`before_send_check_in`). Only `request` and `extra` are sanitized; span data is not
|
|
6
|
+
- Allow multiple `before_send_transaction` and `before_send_check_in` hooks
|
|
7
|
+
- Stop the `before_send` hook chain when a hook returns `nil`, so next hooks do not get `nil`
|
|
8
|
+
|
|
9
|
+
## 0.9.0
|
|
10
|
+
|
|
11
|
+
- Add `filter` option to pass a custom filter, e.g. `ActiveSupport::ParameterFilter` [#25](https://github.com/mrexox/sentry-sanitizer/pull/25)
|
|
12
|
+
- `filter` can't be combined with `fields` or `mask`
|
|
13
|
+
|
|
14
|
+
## 0.8.3
|
|
15
|
+
|
|
16
|
+
- Add Sentry 7 support [#24](https://github.com/mrexox/sentry-sanitizer/pull/24)
|
|
17
|
+
|
|
3
18
|
## 0.8.2
|
|
4
19
|
|
|
5
20
|
- Sanitize breadcrumb data only if it's a Hash [#22](https://github.com/mrexox/sentry-sanitizer/pull/22)
|
data/Gemfile
CHANGED
|
@@ -16,9 +16,14 @@ gem "logger"
|
|
|
16
16
|
gem "base64"
|
|
17
17
|
gem "cgi"
|
|
18
18
|
gem "rubocop", "~> 1.28.2"
|
|
19
|
-
gem "simplecov", require: false, group: :test
|
|
20
19
|
|
|
21
20
|
gem "bundler", ">= 2.3"
|
|
22
21
|
gem "rack"
|
|
23
22
|
gem "rake", "~> 12"
|
|
24
23
|
gem "rspec", "~> 3.0"
|
|
24
|
+
|
|
25
|
+
group :test do
|
|
26
|
+
gem "activesupport", "~> 8.0"
|
|
27
|
+
|
|
28
|
+
gem "simplecov", require: false
|
|
29
|
+
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,20 +1,41 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
sentry-sanitizer (0.
|
|
5
|
-
sentry-ruby (>=
|
|
4
|
+
sentry-sanitizer (0.10.0)
|
|
5
|
+
sentry-ruby (>= 6.0, < 8.0.0)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
9
9
|
specs:
|
|
10
|
+
activesupport (8.1.4)
|
|
11
|
+
base64
|
|
12
|
+
bigdecimal
|
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
14
|
+
connection_pool (>= 2.2.5)
|
|
15
|
+
drb
|
|
16
|
+
i18n (>= 1.6, < 2)
|
|
17
|
+
json
|
|
18
|
+
logger (>= 1.4.2)
|
|
19
|
+
minitest (>= 5.1)
|
|
20
|
+
securerandom (>= 0.3)
|
|
21
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
22
|
+
uri (>= 0.13.1)
|
|
10
23
|
ast (2.4.3)
|
|
11
24
|
base64 (0.3.0)
|
|
12
25
|
bigdecimal (4.1.3)
|
|
13
26
|
cgi (0.5.2)
|
|
14
27
|
concurrent-ruby (1.3.8)
|
|
28
|
+
connection_pool (3.0.2)
|
|
15
29
|
diff-lcs (1.5.0)
|
|
16
30
|
docile (1.4.0)
|
|
31
|
+
drb (2.2.3)
|
|
32
|
+
i18n (1.15.2)
|
|
33
|
+
concurrent-ruby (~> 1.0)
|
|
34
|
+
json (3.0.2)
|
|
17
35
|
logger (1.7.0)
|
|
36
|
+
minitest (6.0.6)
|
|
37
|
+
drb (~> 2.0)
|
|
38
|
+
prism (~> 1.5)
|
|
18
39
|
parallel (1.27.0)
|
|
19
40
|
parser (3.3.10.0)
|
|
20
41
|
ast (~> 2.4.1)
|
|
@@ -52,6 +73,7 @@ GEM
|
|
|
52
73
|
parser (>= 3.3.7.2)
|
|
53
74
|
prism (~> 1.4)
|
|
54
75
|
ruby-progressbar (1.13.0)
|
|
76
|
+
securerandom (0.4.1)
|
|
55
77
|
sentry-ruby (6.7.0)
|
|
56
78
|
bigdecimal
|
|
57
79
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
@@ -60,12 +82,16 @@ GEM
|
|
|
60
82
|
docile (~> 1.1)
|
|
61
83
|
simplecov-html (~> 0.11)
|
|
62
84
|
simplecov-html (0.12.3)
|
|
85
|
+
tzinfo (2.0.6)
|
|
86
|
+
concurrent-ruby (~> 1.0)
|
|
63
87
|
unicode-display_width (2.6.0)
|
|
88
|
+
uri (1.1.2)
|
|
64
89
|
|
|
65
90
|
PLATFORMS
|
|
66
91
|
ruby
|
|
67
92
|
|
|
68
93
|
DEPENDENCIES
|
|
94
|
+
activesupport (~> 8.0)
|
|
69
95
|
base64
|
|
70
96
|
bundler (>= 2.3)
|
|
71
97
|
cgi
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://github.com/mrexox/sentry-sanitizer/actions/workflows/ci.yml)
|
|
2
2
|
[](https://badge.fury.io/rb/sentry-sanitizer)
|
|
3
3
|
[](https://coveralls.io/github/mrexox/sentry-sanitizer?branch=master)
|
|
4
4
|
|
|
@@ -40,22 +40,27 @@ Add following lines to your Sentry configuration:
|
|
|
40
40
|
Sentry.init do |config|
|
|
41
41
|
# ... your configuration
|
|
42
42
|
|
|
43
|
-
#
|
|
43
|
+
# Mask same fields as Rails does
|
|
44
44
|
config.sanitize.fields = Rails.application.config.filter_parameters
|
|
45
|
-
|
|
46
|
-
# You can also pass custom array
|
|
45
|
+
# Or pass custom fields
|
|
47
46
|
config.sanitize.fields = %w[password super_secret_token]
|
|
48
47
|
|
|
48
|
+
# Use custom filter (e.g. from activesupport).
|
|
49
|
+
# Must implement #filter(array_or_hash) and #filter_param(key, value)
|
|
50
|
+
# Don't set 'config.sanitize.fields' if using this.
|
|
51
|
+
config.sanitize.filter = ActiveSupport::ParameterFilter.new(
|
|
52
|
+
Rails.application.config.filter_parameters, mask: "[FILTERED]"
|
|
53
|
+
)
|
|
54
|
+
|
|
49
55
|
# HTTP headers can be sanitized too (it is case insensitive)
|
|
50
56
|
config.sanitize.http_headers = %w[Authorization X-Xsrf-Token]
|
|
51
|
-
|
|
52
|
-
# You can sanitize all HTTP headers with setting `true` value
|
|
57
|
+
# Mask all headers
|
|
53
58
|
config.sanitize.http_headers = true
|
|
54
59
|
|
|
55
|
-
#
|
|
60
|
+
# Mask all cookies
|
|
56
61
|
config.sanitize.cookies = true
|
|
57
62
|
|
|
58
|
-
#
|
|
63
|
+
# Parse and sanitize request query string
|
|
59
64
|
config.sanitize.query_string = true
|
|
60
65
|
|
|
61
66
|
# Sanitize breadcrumbs data[:body] payload (Setry::Net:HTTP)
|
data/bin/bundle
CHANGED
|
@@ -14,31 +14,31 @@ m = Module.new do
|
|
|
14
14
|
module_function
|
|
15
15
|
|
|
16
16
|
def invoked_as_script?
|
|
17
|
-
File.expand_path($
|
|
17
|
+
File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def env_var_version
|
|
21
|
-
ENV
|
|
21
|
+
ENV.fetch("BUNDLER_VERSION", nil)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def cli_arg_version
|
|
25
25
|
return unless invoked_as_script? # don't want to hijack other binstubs
|
|
26
26
|
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
|
|
27
|
+
|
|
27
28
|
bundler_version = nil
|
|
28
29
|
update_index = nil
|
|
29
30
|
ARGV.each_with_index do |a, i|
|
|
30
|
-
if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
|
|
31
|
-
bundler_version = a
|
|
32
|
-
end
|
|
31
|
+
bundler_version = a if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
|
|
33
32
|
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
|
|
34
|
-
|
|
33
|
+
|
|
34
|
+
bundler_version = Regexp.last_match(1)
|
|
35
35
|
update_index = i
|
|
36
36
|
end
|
|
37
37
|
bundler_version
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def gemfile
|
|
41
|
-
gemfile = ENV
|
|
41
|
+
gemfile = ENV.fetch("BUNDLE_GEMFILE", nil)
|
|
42
42
|
return gemfile if gemfile && !gemfile.empty?
|
|
43
43
|
|
|
44
44
|
File.expand_path("../Gemfile", __dir__)
|
|
@@ -55,15 +55,17 @@ m = Module.new do
|
|
|
55
55
|
|
|
56
56
|
def lockfile_version
|
|
57
57
|
return unless File.file?(lockfile)
|
|
58
|
+
|
|
58
59
|
lockfile_contents = File.read(lockfile)
|
|
59
60
|
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
|
|
61
|
+
|
|
60
62
|
Regexp.last_match(1)
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
def bundler_requirement
|
|
64
66
|
@bundler_requirement ||=
|
|
65
67
|
env_var_version || cli_arg_version ||
|
|
66
|
-
|
|
68
|
+
bundler_requirement_for(lockfile_version)
|
|
67
69
|
end
|
|
68
70
|
|
|
69
71
|
def bundler_requirement_for(version)
|
|
@@ -91,10 +93,12 @@ m = Module.new do
|
|
|
91
93
|
gem "bundler", bundler_requirement
|
|
92
94
|
end
|
|
93
95
|
return if gem_error.nil?
|
|
96
|
+
|
|
94
97
|
require_error = activation_error_handling do
|
|
95
98
|
require "bundler/version"
|
|
96
99
|
end
|
|
97
100
|
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
|
101
|
+
|
|
98
102
|
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
|
|
99
103
|
exit 42
|
|
100
104
|
end
|
|
@@ -109,6 +113,4 @@ end
|
|
|
109
113
|
|
|
110
114
|
m.load_bundler!
|
|
111
115
|
|
|
112
|
-
if m.invoked_as_script?
|
|
113
|
-
load Gem.bin_path("bundler", "bundle")
|
|
114
|
-
end
|
|
116
|
+
load Gem.bin_path("bundler", "bundle") if m.invoked_as_script?
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "sentry/sanitizer/filter"
|
|
4
5
|
|
|
5
6
|
module Sentry
|
|
6
7
|
module Sanitizer
|
|
7
8
|
class Cleaner
|
|
8
|
-
DEFAULT_MASK = "[FILTERED]"
|
|
9
9
|
DEFAULT_SENSITIVE_HEADERS = %w[
|
|
10
10
|
Authorization
|
|
11
11
|
X-Xsrf-Token
|
|
@@ -14,11 +14,16 @@ module Sentry
|
|
|
14
14
|
private_constant :DEFAULT_SENSITIVE_HEADERS
|
|
15
15
|
|
|
16
16
|
def initialize(config)
|
|
17
|
-
@
|
|
17
|
+
@filter = config.filter || Filter.new(config.fields, mask: config.mask)
|
|
18
|
+
|
|
18
19
|
@http_headers = config.http_headers || DEFAULT_SENSITIVE_HEADERS
|
|
20
|
+
@headers_filter = Filter.new(@http_headers, mask: config.mask) if @http_headers.is_a?(Array)
|
|
21
|
+
|
|
19
22
|
@do_cookies = config.cookies || false
|
|
20
23
|
@do_query_string = config.query_string || false
|
|
21
|
-
|
|
24
|
+
|
|
25
|
+
@mask = config.mask || Filter::DEFAULT_MASK
|
|
26
|
+
|
|
22
27
|
@breadcrumbs_json_data_fields = config.breadcrumbs.json_data_fields || []
|
|
23
28
|
end
|
|
24
29
|
|
|
@@ -79,20 +84,23 @@ module Sentry
|
|
|
79
84
|
# ignore
|
|
80
85
|
end
|
|
81
86
|
|
|
82
|
-
def sanitize_data(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
def sanitize_data(data)
|
|
88
|
+
case data
|
|
89
|
+
when Hash, Array
|
|
90
|
+
filter.filter(data)
|
|
91
|
+
else
|
|
92
|
+
data
|
|
93
|
+
end
|
|
87
94
|
end
|
|
88
95
|
|
|
89
96
|
private
|
|
90
97
|
|
|
91
|
-
attr_reader :
|
|
98
|
+
attr_reader :filter,
|
|
99
|
+
:headers_filter,
|
|
100
|
+
:mask,
|
|
92
101
|
:http_headers,
|
|
93
102
|
:do_cookies,
|
|
94
103
|
:do_query_string,
|
|
95
|
-
:mask,
|
|
96
104
|
:breadcrumbs_json_data_fields
|
|
97
105
|
|
|
98
106
|
# Sanitize specified headers
|
|
@@ -101,15 +109,7 @@ module Sentry
|
|
|
101
109
|
when TrueClass
|
|
102
110
|
headers.transform_values { mask }
|
|
103
111
|
when Array
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
http_headers_regex = sensitive_regexp(http_headers)
|
|
107
|
-
|
|
108
|
-
headers.keys.select { |key| key.match?(http_headers_regex) }.each do |key|
|
|
109
|
-
headers[key] = mask
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
headers
|
|
112
|
+
headers_filter.filter(headers)
|
|
113
113
|
else
|
|
114
114
|
headers
|
|
115
115
|
end
|
|
@@ -141,56 +141,13 @@ module Sentry
|
|
|
141
141
|
def sanitize_query_string_from_string(query_string)
|
|
142
142
|
sanitized_array = query_string.split("&").map do |kv_pair|
|
|
143
143
|
k, v = kv_pair.split("=")
|
|
144
|
-
new_v =
|
|
144
|
+
new_v = filter.filter_param(k, v)
|
|
145
145
|
|
|
146
146
|
"#{k}=#{new_v}"
|
|
147
147
|
end
|
|
148
148
|
|
|
149
149
|
sanitized_array.join("&")
|
|
150
150
|
end
|
|
151
|
-
|
|
152
|
-
def sanitize_value(value, key)
|
|
153
|
-
case value
|
|
154
|
-
when Hash
|
|
155
|
-
sanitize_hash(key, value)
|
|
156
|
-
when Array
|
|
157
|
-
sanitize_array(key, value)
|
|
158
|
-
when String
|
|
159
|
-
sanitize_string(key, value)
|
|
160
|
-
else
|
|
161
|
-
value
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def sanitize_hash(key, value)
|
|
166
|
-
if key&.match?(sensitive_fields)
|
|
167
|
-
mask
|
|
168
|
-
elsif value.frozen?
|
|
169
|
-
value.merge(value) { |k, v| sanitize_value(v, k) }
|
|
170
|
-
else
|
|
171
|
-
value.merge!(value) { |k, v| sanitize_value(v, k) }
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def sanitize_array(key, value)
|
|
176
|
-
if value.frozen?
|
|
177
|
-
value.map { |val| sanitize_value(val, key) }
|
|
178
|
-
else
|
|
179
|
-
value.map! { |val| sanitize_value(val, key) }
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def sanitize_string(key, value)
|
|
184
|
-
key&.match?(sensitive_fields) ? mask : value
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def sensitive_fields
|
|
188
|
-
@sensitive_fields ||= sensitive_regexp(fields)
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def sensitive_regexp(fields)
|
|
192
|
-
Regexp.new(fields.map { |field| "\\b#{field}\\b" }.join("|"), "i")
|
|
193
|
-
end
|
|
194
151
|
end
|
|
195
152
|
end
|
|
196
153
|
end
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "sentry/configuration"
|
|
4
4
|
require "sentry/sanitizer/cleaner"
|
|
5
|
+
require "sentry/sanitizer/filter"
|
|
5
6
|
require "sentry/sanitizer/configuration_mixin"
|
|
6
7
|
|
|
7
8
|
module Sentry
|
|
@@ -22,6 +23,18 @@ module Sentry
|
|
|
22
23
|
event
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
self.before_send_transaction = lambda { |event, _hint|
|
|
27
|
+
Sentry::Sanitizer::Cleaner.new(Sentry.configuration.sanitize).call(event)
|
|
28
|
+
|
|
29
|
+
event
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
self.before_send_check_in = lambda { |event, _hint|
|
|
33
|
+
Sentry::Sanitizer::Cleaner.new(Sentry.configuration.sanitize).call(event)
|
|
34
|
+
|
|
35
|
+
event
|
|
36
|
+
}
|
|
37
|
+
|
|
25
38
|
self.before_breadcrumb = lambda { |breadcrumb, _hint|
|
|
26
39
|
Sentry::Sanitizer::Cleaner.new(Sentry.configuration.sanitize).call(breadcrumb)
|
|
27
40
|
|
|
@@ -43,6 +56,7 @@ module Sentry
|
|
|
43
56
|
end
|
|
44
57
|
|
|
45
58
|
attr_reader :fields,
|
|
59
|
+
:filter,
|
|
46
60
|
:http_headers,
|
|
47
61
|
:cookies,
|
|
48
62
|
:query_string,
|
|
@@ -51,6 +65,7 @@ module Sentry
|
|
|
51
65
|
def configured?
|
|
52
66
|
[
|
|
53
67
|
fields,
|
|
68
|
+
filter,
|
|
54
69
|
http_headers,
|
|
55
70
|
cookies,
|
|
56
71
|
query_string,
|
|
@@ -63,11 +78,22 @@ module Sentry
|
|
|
63
78
|
end
|
|
64
79
|
|
|
65
80
|
def fields=(fields)
|
|
66
|
-
raise ArgumentError, "
|
|
81
|
+
raise ArgumentError, "fields must be array" unless fields.is_a? Array
|
|
82
|
+
raise ArgumentError, "specify either 'fields' or 'filter'" if filter
|
|
67
83
|
|
|
68
84
|
@fields = fields
|
|
69
85
|
end
|
|
70
86
|
|
|
87
|
+
def filter=(filter)
|
|
88
|
+
methods = Sanitizer::Filter.instance_methods(false)
|
|
89
|
+
implements = methods.all? { |method| filter.respond_to?(method) }
|
|
90
|
+
raise ArgumentError, "specify either 'fields' or 'filter'" if fields
|
|
91
|
+
raise ArgumentError, "mask can't be used when 'filter' is set" if mask
|
|
92
|
+
raise ArgumentError, "filter must implement #{methods.join(', ')}" unless implements
|
|
93
|
+
|
|
94
|
+
@filter = filter
|
|
95
|
+
end
|
|
96
|
+
|
|
71
97
|
def http_headers=(headers)
|
|
72
98
|
raise ArgumentError, "sanitize_http_headers must be array" unless [Array, TrueClass, FalseClass].include?(headers.class)
|
|
73
99
|
|
|
@@ -88,6 +114,7 @@ module Sentry
|
|
|
88
114
|
|
|
89
115
|
def mask=(mask)
|
|
90
116
|
raise ArgumentError, "mask must be string" unless mask.is_a?(String)
|
|
117
|
+
raise ArgumentError, "mask can't be used when 'filter' is set" if filter
|
|
91
118
|
|
|
92
119
|
@mask = mask
|
|
93
120
|
end
|
|
@@ -4,11 +4,12 @@ module Sentry
|
|
|
4
4
|
module Sanitizer
|
|
5
5
|
module ConfigurationMixin
|
|
6
6
|
# Allow adding multiple hooks to `before_send`, so user hooks are not ignored.
|
|
7
|
+
# Available since sentry-ruby 4.5.0
|
|
7
8
|
#
|
|
8
9
|
# @param [nil, #call] value
|
|
9
10
|
#
|
|
10
11
|
def before_send=(value)
|
|
11
|
-
|
|
12
|
+
_check_callable!("before_send", value)
|
|
12
13
|
|
|
13
14
|
return unless value
|
|
14
15
|
|
|
@@ -18,6 +19,53 @@ module Sentry
|
|
|
18
19
|
@before_send = lambda { |event, hint|
|
|
19
20
|
@before_send_hook_list.each do |hook|
|
|
20
21
|
event = hook.call(event, hint)
|
|
22
|
+
break unless event
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
event
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Allow adding multiple hooks to `before_send_transaction`, so user hooks are not ignored.
|
|
30
|
+
# Available since sentry-ruby 5.8.0
|
|
31
|
+
#
|
|
32
|
+
# @param [nil, #call] value
|
|
33
|
+
#
|
|
34
|
+
def before_send_transaction=(value)
|
|
35
|
+
_check_callable!("before_send_transaction", value)
|
|
36
|
+
|
|
37
|
+
return unless value
|
|
38
|
+
|
|
39
|
+
@before_send_transaction_hook_list ||= []
|
|
40
|
+
@before_send_transaction_hook_list << value
|
|
41
|
+
|
|
42
|
+
@before_send_transaction = lambda { |event, hint|
|
|
43
|
+
@before_send_transaction_hook_list.each do |hook|
|
|
44
|
+
event = hook.call(event, hint)
|
|
45
|
+
break unless event
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
event
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Allow adding multiple hooks to `before_send_check_in`, so user hooks are not ignored.
|
|
53
|
+
# Available since sentry-ruby 6.0.0
|
|
54
|
+
#
|
|
55
|
+
# @param [nil, #call] value
|
|
56
|
+
#
|
|
57
|
+
def before_send_check_in=(value)
|
|
58
|
+
_check_callable!("before_send_check_in", value)
|
|
59
|
+
|
|
60
|
+
return unless value
|
|
61
|
+
|
|
62
|
+
@before_send_check_in_hook_list ||= []
|
|
63
|
+
@before_send_check_in_hook_list << value
|
|
64
|
+
|
|
65
|
+
@before_send_check_in = lambda { |event, hint|
|
|
66
|
+
@before_send_check_in_hook_list.each do |hook|
|
|
67
|
+
event = hook.call(event, hint)
|
|
68
|
+
break unless event
|
|
21
69
|
end
|
|
22
70
|
|
|
23
71
|
event
|
|
@@ -25,11 +73,12 @@ module Sentry
|
|
|
25
73
|
end
|
|
26
74
|
|
|
27
75
|
# Allow adding multiple hooks to `before_breadcrumb`, so user hooks are not ignored.
|
|
76
|
+
# Available since sentry-ruby 4.5.0
|
|
28
77
|
#
|
|
29
78
|
# @param [nil, #call] value
|
|
30
79
|
#
|
|
31
|
-
def before_breadcrumb=(value)
|
|
32
|
-
|
|
80
|
+
def before_breadcrumb=(value)
|
|
81
|
+
_check_callable!("before_breadcrumb", value)
|
|
33
82
|
|
|
34
83
|
return unless value
|
|
35
84
|
|
|
@@ -45,6 +94,12 @@ module Sentry
|
|
|
45
94
|
breadcrumb
|
|
46
95
|
}
|
|
47
96
|
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def _check_callable!(hook, value)
|
|
101
|
+
raise ArgumentError, "#{hook} must be callable (or nil to disable)" unless value.nil? || value == false || value.respond_to?(:call)
|
|
102
|
+
end
|
|
48
103
|
end
|
|
49
104
|
end
|
|
50
105
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sentry
|
|
4
|
+
module Sanitizer
|
|
5
|
+
class Filter
|
|
6
|
+
DEFAULT_MASK = "[FILTERED]"
|
|
7
|
+
|
|
8
|
+
def initialize(fields, mask: nil)
|
|
9
|
+
@filters = compile_filters(fields || [])
|
|
10
|
+
@mask = mask || DEFAULT_MASK
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def filter(params)
|
|
14
|
+
filters.nil? ? params : sanitize_value(nil, params)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def filter_param(key, value)
|
|
18
|
+
filters.nil? ? value : sanitize_value(key, value)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
attr_reader :mask, :filters
|
|
24
|
+
|
|
25
|
+
def compile_filters(fields)
|
|
26
|
+
return nil if fields.size.zero?
|
|
27
|
+
|
|
28
|
+
Regexp.new(fields.map { |field| "\\b#{field}\\b" }.join("|"), "i")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def sanitize_value(key, value)
|
|
32
|
+
return mask if key&.match?(filters)
|
|
33
|
+
|
|
34
|
+
case value
|
|
35
|
+
when Hash
|
|
36
|
+
if value.frozen?
|
|
37
|
+
value.merge(value) { |k, v| sanitize_value(k, v) }
|
|
38
|
+
else
|
|
39
|
+
value.merge!(value) { |k, v| sanitize_value(k, v) }
|
|
40
|
+
end
|
|
41
|
+
when Array
|
|
42
|
+
if value.frozen?
|
|
43
|
+
value.map { |v| sanitize_value(key, v) }
|
|
44
|
+
else
|
|
45
|
+
value.map! { |v| sanitize_value(key, v) }
|
|
46
|
+
end
|
|
47
|
+
else
|
|
48
|
+
value
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/sentry-sanitizer.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sentry-sanitizer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Valentine Kiselev
|
|
@@ -15,7 +15,7 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
18
|
+
version: '6.0'
|
|
19
19
|
- - "<"
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
21
|
version: 8.0.0
|
|
@@ -25,7 +25,7 @@ dependencies:
|
|
|
25
25
|
requirements:
|
|
26
26
|
- - ">="
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
|
-
version: '
|
|
28
|
+
version: '6.0'
|
|
29
29
|
- - "<"
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: 8.0.0
|
|
@@ -36,8 +36,7 @@ executables: []
|
|
|
36
36
|
extensions: []
|
|
37
37
|
extra_rdoc_files: []
|
|
38
38
|
files:
|
|
39
|
-
- ".github/workflows/ci
|
|
40
|
-
- ".github/workflows/ci-macos.yml"
|
|
39
|
+
- ".github/workflows/ci.yml"
|
|
41
40
|
- ".github/workflows/coveralls-report.yml"
|
|
42
41
|
- ".gitignore"
|
|
43
42
|
- ".rspec"
|
|
@@ -59,6 +58,7 @@ files:
|
|
|
59
58
|
- lib/sentry/sanitizer/cleaner.rb
|
|
60
59
|
- lib/sentry/sanitizer/configuration.rb
|
|
61
60
|
- lib/sentry/sanitizer/configuration_mixin.rb
|
|
61
|
+
- lib/sentry/sanitizer/filter.rb
|
|
62
62
|
- lib/sentry/sanitizer/version.rb
|
|
63
63
|
- sentry-sanitizer.gemspec
|
|
64
64
|
- tea.yml
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
name: CI macos
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
pull_request:
|
|
5
|
-
|
|
6
|
-
jobs:
|
|
7
|
-
rspec:
|
|
8
|
-
name: Unit tests
|
|
9
|
-
runs-on: macos-13
|
|
10
|
-
strategy:
|
|
11
|
-
matrix:
|
|
12
|
-
include:
|
|
13
|
-
- { ruby_version: 3.3, sentry_version: "~> 6.0" }
|
|
14
|
-
- { ruby_version: 3.4, sentry_version: "~> 6.0" }
|
|
15
|
-
- { ruby_version: 3.4, sentry_version: "~> 7.0" }
|
|
16
|
-
- { ruby_version: 4.0, sentry_version: "~> 6.0" }
|
|
17
|
-
- { ruby_version: 4.0, sentry_version: "~> 7.0" }
|
|
18
|
-
- { ruby_version: jruby, sentry_version: "~> 6.0" }
|
|
19
|
-
env:
|
|
20
|
-
SENTRY_VERSION: ${{ matrix.sentry_version }}
|
|
21
|
-
steps:
|
|
22
|
-
- uses: actions/checkout@v1
|
|
23
|
-
|
|
24
|
-
- name: Set up Ruby ${{ matrix.ruby_version }}
|
|
25
|
-
uses: ruby/setup-ruby@v1
|
|
26
|
-
with:
|
|
27
|
-
bundler: 2
|
|
28
|
-
ruby-version: ${{ matrix.ruby_version }}
|
|
29
|
-
|
|
30
|
-
- name: Run specs
|
|
31
|
-
run: |
|
|
32
|
-
bundle install --jobs 4 --retry 3 --no-cache
|
|
33
|
-
bundle exec rspec
|
|
34
|
-
|
|
35
|
-
- uses: coverallsapp/github-action@v2
|
|
36
|
-
env:
|
|
37
|
-
COVERALLS_SERVICE_NUMBER: ${{ github.sha }}
|
|
38
|
-
with:
|
|
39
|
-
flag-name: ruby-${{ join(matrix.*, '-') }}
|
|
40
|
-
parallel: true
|