sentry-ruby 5.9.0 → 5.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -10
- data/README.md +9 -9
- data/lib/sentry/background_worker.rb +8 -1
- data/lib/sentry/backpressure_monitor.rb +75 -0
- data/lib/sentry/breadcrumb.rb +8 -2
- data/lib/sentry/check_in_event.rb +60 -0
- data/lib/sentry/client.rb +48 -10
- data/lib/sentry/configuration.rb +89 -17
- data/lib/sentry/cron/configuration.rb +23 -0
- data/lib/sentry/cron/monitor_check_ins.rb +75 -0
- data/lib/sentry/cron/monitor_config.rb +53 -0
- data/lib/sentry/cron/monitor_schedule.rb +42 -0
- data/lib/sentry/envelope.rb +1 -1
- data/lib/sentry/event.rb +6 -28
- data/lib/sentry/hub.rb +74 -2
- data/lib/sentry/integrable.rb +6 -0
- data/lib/sentry/interfaces/single_exception.rb +5 -3
- data/lib/sentry/net/http.rb +26 -20
- data/lib/sentry/profiler.rb +18 -7
- data/lib/sentry/propagation_context.rb +134 -0
- data/lib/sentry/puma.rb +11 -4
- data/lib/sentry/rack/capture_exceptions.rb +1 -4
- data/lib/sentry/rake.rb +0 -13
- data/lib/sentry/redis.rb +9 -3
- data/lib/sentry/release_detector.rb +1 -1
- data/lib/sentry/scope.rb +29 -13
- data/lib/sentry/span.rb +39 -2
- data/lib/sentry/test_helper.rb +18 -12
- data/lib/sentry/transaction.rb +18 -19
- data/lib/sentry/transaction_event.rb +0 -3
- data/lib/sentry/transport/configuration.rb +74 -1
- data/lib/sentry/transport/http_transport.rb +68 -37
- data/lib/sentry/transport/spotlight_transport.rb +50 -0
- data/lib/sentry/transport.rb +21 -17
- data/lib/sentry/utils/argument_checking_helper.rb +9 -3
- data/lib/sentry/version.rb +1 -1
- data/lib/sentry-ruby.rb +83 -25
- metadata +10 -3
- data/CODE_OF_CONDUCT.md +0 -74
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "zlib"
|
5
|
+
|
6
|
+
module Sentry
|
7
|
+
# Designed to just report events to Spotlight in development.
|
8
|
+
class SpotlightTransport < HTTPTransport
|
9
|
+
DEFAULT_SIDECAR_URL = "http://localhost:8969/stream"
|
10
|
+
MAX_FAILED_REQUESTS = 3
|
11
|
+
|
12
|
+
def initialize(configuration)
|
13
|
+
super
|
14
|
+
@sidecar_url = configuration.spotlight.is_a?(String) ? configuration.spotlight : DEFAULT_SIDECAR_URL
|
15
|
+
@failed = 0
|
16
|
+
@logged = false
|
17
|
+
|
18
|
+
log_debug("[Spotlight] initialized for url #{@sidecar_url}")
|
19
|
+
end
|
20
|
+
|
21
|
+
def endpoint
|
22
|
+
"/stream"
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_data(data)
|
26
|
+
if @failed >= MAX_FAILED_REQUESTS
|
27
|
+
unless @logged
|
28
|
+
log_debug("[Spotlight] disabling because of too many request failures")
|
29
|
+
@logged = true
|
30
|
+
end
|
31
|
+
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_error
|
39
|
+
@failed += 1
|
40
|
+
end
|
41
|
+
|
42
|
+
# Similar to HTTPTransport connection, but does not support Proxy and SSL
|
43
|
+
def conn
|
44
|
+
sidecar = URI(@sidecar_url)
|
45
|
+
connection = ::Net::HTTP.new(sidecar.hostname, sidecar.port, nil)
|
46
|
+
connection.use_ssl = false
|
47
|
+
connection
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/sentry/transport.rb
CHANGED
@@ -18,7 +18,9 @@ module Sentry
|
|
18
18
|
:network_error,
|
19
19
|
:sample_rate,
|
20
20
|
:before_send,
|
21
|
-
:event_processor
|
21
|
+
:event_processor,
|
22
|
+
:insufficient_data,
|
23
|
+
:backpressure
|
22
24
|
]
|
23
25
|
|
24
26
|
include LoggingHelper
|
@@ -73,7 +75,7 @@ module Sentry
|
|
73
75
|
result, oversized = item.serialize
|
74
76
|
|
75
77
|
if oversized
|
76
|
-
|
78
|
+
log_debug("Envelope item [#{item.type}] is still oversized after size reduction: {#{item.size_breakdown}}")
|
77
79
|
|
78
80
|
next
|
79
81
|
end
|
@@ -118,16 +120,8 @@ module Sentry
|
|
118
120
|
!!delay && delay > Time.now
|
119
121
|
end
|
120
122
|
|
121
|
-
def
|
122
|
-
|
123
|
-
fields = {
|
124
|
-
'sentry_version' => PROTOCOL_VERSION,
|
125
|
-
'sentry_client' => USER_AGENT,
|
126
|
-
'sentry_timestamp' => now,
|
127
|
-
'sentry_key' => @dsn.public_key
|
128
|
-
}
|
129
|
-
fields['sentry_secret'] = @dsn.secret_key if @dsn.secret_key
|
130
|
-
'Sentry ' + fields.map { |key, value| "#{key}=#{value}" }.join(', ')
|
123
|
+
def any_rate_limited?
|
124
|
+
@rate_limits.values.any? { |t| t && t > Time.now }
|
131
125
|
end
|
132
126
|
|
133
127
|
def envelope_from_event(event)
|
@@ -143,7 +137,7 @@ module Sentry
|
|
143
137
|
sent_at: Sentry.utc_now.iso8601
|
144
138
|
}
|
145
139
|
|
146
|
-
if event.is_a?(
|
140
|
+
if event.is_a?(Event) && event.dynamic_sampling_context
|
147
141
|
envelope_headers[:trace] = event.dynamic_sampling_context
|
148
142
|
end
|
149
143
|
|
@@ -174,18 +168,27 @@ module Sentry
|
|
174
168
|
@discarded_events[[reason, item_type]] += 1
|
175
169
|
end
|
176
170
|
|
171
|
+
def flush
|
172
|
+
client_report_headers, client_report_payload = fetch_pending_client_report(force: true)
|
173
|
+
return unless client_report_headers
|
174
|
+
|
175
|
+
envelope = Envelope.new
|
176
|
+
envelope.add_item(client_report_headers, client_report_payload)
|
177
|
+
send_envelope(envelope)
|
178
|
+
end
|
179
|
+
|
177
180
|
private
|
178
181
|
|
179
|
-
def fetch_pending_client_report
|
182
|
+
def fetch_pending_client_report(force: false)
|
180
183
|
return nil unless @send_client_reports
|
181
|
-
return nil if @last_client_report_sent > Time.now - CLIENT_REPORT_INTERVAL
|
184
|
+
return nil if !force && @last_client_report_sent > Time.now - CLIENT_REPORT_INTERVAL
|
182
185
|
return nil if @discarded_events.empty?
|
183
186
|
|
184
187
|
discarded_events_hash = @discarded_events.map do |key, val|
|
185
188
|
reason, type = key
|
186
189
|
|
187
190
|
# 'event' has to be mapped to 'error'
|
188
|
-
category = type == '
|
191
|
+
category = type == 'event' ? 'error' : type
|
189
192
|
|
190
193
|
{ reason: reason, category: category, quantity: val }
|
191
194
|
end
|
@@ -205,7 +208,7 @@ module Sentry
|
|
205
208
|
def reject_rate_limited_items(envelope)
|
206
209
|
envelope.items.reject! do |item|
|
207
210
|
if is_rate_limited?(item.type)
|
208
|
-
|
211
|
+
log_debug("[Transport] Envelope item [#{item.type}] not sent: rate limiting")
|
209
212
|
record_lost_event(:ratelimit_backoff, item.type)
|
210
213
|
|
211
214
|
true
|
@@ -219,3 +222,4 @@ end
|
|
219
222
|
|
220
223
|
require "sentry/transport/dummy_transport"
|
221
224
|
require "sentry/transport/http_transport"
|
225
|
+
require "sentry/transport/spotlight_transport"
|
@@ -4,9 +4,15 @@ module Sentry
|
|
4
4
|
module ArgumentCheckingHelper
|
5
5
|
private
|
6
6
|
|
7
|
-
def check_argument_type!(argument,
|
8
|
-
unless argument.is_a?(
|
9
|
-
raise ArgumentError, "expect the argument to be a #{
|
7
|
+
def check_argument_type!(argument, *expected_types)
|
8
|
+
unless expected_types.any? { |t| argument.is_a?(t) }
|
9
|
+
raise ArgumentError, "expect the argument to be a #{expected_types.join(' or ')}, got #{argument.class} (#{argument.inspect})"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_argument_includes!(argument, values)
|
14
|
+
unless values.include?(argument)
|
15
|
+
raise ArgumentError, "expect the argument to be one of #{values.map(&:inspect).join(' or ')}, got #{argument.inspect}"
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
data/lib/sentry/version.rb
CHANGED
data/lib/sentry-ruby.rb
CHANGED
@@ -15,11 +15,14 @@ require "sentry/logger"
|
|
15
15
|
require "sentry/event"
|
16
16
|
require "sentry/error_event"
|
17
17
|
require "sentry/transaction_event"
|
18
|
+
require "sentry/check_in_event"
|
18
19
|
require "sentry/span"
|
19
20
|
require "sentry/transaction"
|
20
21
|
require "sentry/hub"
|
21
22
|
require "sentry/background_worker"
|
22
23
|
require "sentry/session_flusher"
|
24
|
+
require "sentry/backpressure_monitor"
|
25
|
+
require "sentry/cron/monitor_check_ins"
|
23
26
|
|
24
27
|
[
|
25
28
|
"sentry/rake",
|
@@ -63,25 +66,29 @@ module Sentry
|
|
63
66
|
end
|
64
67
|
|
65
68
|
# @!attribute [rw] background_worker
|
66
|
-
# @return [BackgroundWorker
|
69
|
+
# @return [BackgroundWorker]
|
67
70
|
attr_accessor :background_worker
|
68
71
|
|
69
72
|
# @!attribute [r] session_flusher
|
70
73
|
# @return [SessionFlusher, nil]
|
71
74
|
attr_reader :session_flusher
|
72
75
|
|
76
|
+
# @!attribute [r] backpressure_monitor
|
77
|
+
# @return [BackpressureMonitor, nil]
|
78
|
+
attr_reader :backpressure_monitor
|
79
|
+
|
73
80
|
##### Patch Registration #####
|
74
81
|
|
75
82
|
# @!visibility private
|
76
|
-
def register_patch(patch = nil, target = nil, &block)
|
83
|
+
def register_patch(key, patch = nil, target = nil, &block)
|
77
84
|
if patch && block
|
78
85
|
raise ArgumentError.new("Please provide either a patch and its target OR a block, but not both")
|
79
86
|
end
|
80
87
|
|
81
88
|
if block
|
82
|
-
registered_patches
|
89
|
+
registered_patches[key] = block
|
83
90
|
else
|
84
|
-
registered_patches
|
91
|
+
registered_patches[key] = proc do
|
85
92
|
target.send(:prepend, patch) unless target.ancestors.include?(patch)
|
86
93
|
end
|
87
94
|
end
|
@@ -89,14 +96,14 @@ module Sentry
|
|
89
96
|
|
90
97
|
# @!visibility private
|
91
98
|
def apply_patches(config)
|
92
|
-
registered_patches.each do |patch|
|
93
|
-
patch.call(config)
|
99
|
+
registered_patches.each do |key, patch|
|
100
|
+
patch.call(config) if config.enabled_patches.include?(key)
|
94
101
|
end
|
95
102
|
end
|
96
103
|
|
97
104
|
# @!visibility private
|
98
105
|
def registered_patches
|
99
|
-
@registered_patches ||=
|
106
|
+
@registered_patches ||= {}
|
100
107
|
end
|
101
108
|
|
102
109
|
##### Integrations #####
|
@@ -215,17 +222,9 @@ module Sentry
|
|
215
222
|
Thread.current.thread_variable_set(THREAD_LOCAL, hub)
|
216
223
|
@main_hub = hub
|
217
224
|
@background_worker = Sentry::BackgroundWorker.new(config)
|
218
|
-
|
219
|
-
@
|
220
|
-
|
221
|
-
else
|
222
|
-
nil
|
223
|
-
end
|
224
|
-
|
225
|
-
if config.include_local_variables
|
226
|
-
exception_locals_tp.enable
|
227
|
-
end
|
228
|
-
|
225
|
+
@session_flusher = config.auto_session_tracking ? Sentry::SessionFlusher.new(config, client) : nil
|
226
|
+
@backpressure_monitor = config.enable_backpressure_handling ? Sentry::BackpressureMonitor.new(config, client) : nil
|
227
|
+
exception_locals_tp.enable if config.include_local_variables
|
229
228
|
at_exit { close }
|
230
229
|
end
|
231
230
|
|
@@ -234,20 +233,27 @@ module Sentry
|
|
234
233
|
#
|
235
234
|
# @return [void]
|
236
235
|
def close
|
237
|
-
if @background_worker
|
238
|
-
@background_worker.shutdown
|
239
|
-
@background_worker = nil
|
240
|
-
end
|
241
|
-
|
242
236
|
if @session_flusher
|
237
|
+
@session_flusher.flush
|
243
238
|
@session_flusher.kill
|
244
239
|
@session_flusher = nil
|
245
240
|
end
|
246
241
|
|
247
|
-
if
|
248
|
-
|
242
|
+
if @backpressure_monitor
|
243
|
+
@backpressure_monitor.kill
|
244
|
+
@backpressure_monitor = nil
|
249
245
|
end
|
250
246
|
|
247
|
+
if client = get_current_client
|
248
|
+
client.transport.flush
|
249
|
+
|
250
|
+
if client.configuration.include_local_variables
|
251
|
+
exception_locals_tp.disable
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
@background_worker.shutdown
|
256
|
+
|
251
257
|
@main_hub = nil
|
252
258
|
Thread.current.thread_variable_set(THREAD_LOCAL, nil)
|
253
259
|
end
|
@@ -430,6 +436,22 @@ module Sentry
|
|
430
436
|
get_current_hub.capture_event(event)
|
431
437
|
end
|
432
438
|
|
439
|
+
# Captures a check-in and sends it to Sentry via the currently active hub.
|
440
|
+
#
|
441
|
+
# @param slug [String] identifier of this monitor
|
442
|
+
# @param status [Symbol] status of this check-in, one of {CheckInEvent::VALID_STATUSES}
|
443
|
+
#
|
444
|
+
# @param [Hash] options extra check-in options
|
445
|
+
# @option options [String] check_in_id for updating the status of an existing monitor
|
446
|
+
# @option options [Integer] duration seconds elapsed since this monitor started
|
447
|
+
# @option options [Cron::MonitorConfig] monitor_config configuration for this monitor
|
448
|
+
#
|
449
|
+
# @return [String, nil] The {CheckInEvent#check_in_id} to use for later updates on the same slug
|
450
|
+
def capture_check_in(slug, status, **options)
|
451
|
+
return unless initialized?
|
452
|
+
get_current_hub.capture_check_in(slug, status, **options)
|
453
|
+
end
|
454
|
+
|
433
455
|
# Takes or initializes a new Sentry::Transaction and makes a sampling decision for it.
|
434
456
|
#
|
435
457
|
# @return [Transaction, nil]
|
@@ -489,6 +511,42 @@ module Sentry
|
|
489
511
|
Scope.add_global_event_processor(&block)
|
490
512
|
end
|
491
513
|
|
514
|
+
# Returns the traceparent (sentry-trace) header for distributed tracing.
|
515
|
+
# Can be either from the currently active span or the propagation context.
|
516
|
+
#
|
517
|
+
# @return [String, nil]
|
518
|
+
def get_traceparent
|
519
|
+
return nil unless initialized?
|
520
|
+
get_current_hub.get_traceparent
|
521
|
+
end
|
522
|
+
|
523
|
+
# Returns the baggage header for distributed tracing.
|
524
|
+
# Can be either from the currently active span or the propagation context.
|
525
|
+
#
|
526
|
+
# @return [String, nil]
|
527
|
+
def get_baggage
|
528
|
+
return nil unless initialized?
|
529
|
+
get_current_hub.get_baggage
|
530
|
+
end
|
531
|
+
|
532
|
+
# Returns the a Hash containing sentry-trace and baggage.
|
533
|
+
# Can be either from the currently active span or the propagation context.
|
534
|
+
#
|
535
|
+
# @return [Hash, nil]
|
536
|
+
def get_trace_propagation_headers
|
537
|
+
return nil unless initialized?
|
538
|
+
get_current_hub.get_trace_propagation_headers
|
539
|
+
end
|
540
|
+
|
541
|
+
# Continue an incoming trace from a rack env like hash.
|
542
|
+
#
|
543
|
+
# @param env [Hash]
|
544
|
+
# @return [Transaction, nil]
|
545
|
+
def continue_trace(env, **options)
|
546
|
+
return nil unless initialized?
|
547
|
+
get_current_hub.continue_trace(env, **options)
|
548
|
+
end
|
549
|
+
|
492
550
|
##### Helpers #####
|
493
551
|
|
494
552
|
# @!visibility private
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sentry-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.16.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sentry Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -42,7 +42,6 @@ files:
|
|
42
42
|
- ".rspec"
|
43
43
|
- ".yardopts"
|
44
44
|
- CHANGELOG.md
|
45
|
-
- CODE_OF_CONDUCT.md
|
46
45
|
- Gemfile
|
47
46
|
- LICENSE.txt
|
48
47
|
- Makefile
|
@@ -52,15 +51,21 @@ files:
|
|
52
51
|
- bin/setup
|
53
52
|
- lib/sentry-ruby.rb
|
54
53
|
- lib/sentry/background_worker.rb
|
54
|
+
- lib/sentry/backpressure_monitor.rb
|
55
55
|
- lib/sentry/backtrace.rb
|
56
56
|
- lib/sentry/baggage.rb
|
57
57
|
- lib/sentry/breadcrumb.rb
|
58
58
|
- lib/sentry/breadcrumb/sentry_logger.rb
|
59
59
|
- lib/sentry/breadcrumb_buffer.rb
|
60
|
+
- lib/sentry/check_in_event.rb
|
60
61
|
- lib/sentry/client.rb
|
61
62
|
- lib/sentry/configuration.rb
|
62
63
|
- lib/sentry/core_ext/object/deep_dup.rb
|
63
64
|
- lib/sentry/core_ext/object/duplicable.rb
|
65
|
+
- lib/sentry/cron/configuration.rb
|
66
|
+
- lib/sentry/cron/monitor_check_ins.rb
|
67
|
+
- lib/sentry/cron/monitor_config.rb
|
68
|
+
- lib/sentry/cron/monitor_schedule.rb
|
64
69
|
- lib/sentry/dsn.rb
|
65
70
|
- lib/sentry/envelope.rb
|
66
71
|
- lib/sentry/error_event.rb
|
@@ -79,6 +84,7 @@ files:
|
|
79
84
|
- lib/sentry/logger.rb
|
80
85
|
- lib/sentry/net/http.rb
|
81
86
|
- lib/sentry/profiler.rb
|
87
|
+
- lib/sentry/propagation_context.rb
|
82
88
|
- lib/sentry/puma.rb
|
83
89
|
- lib/sentry/rack.rb
|
84
90
|
- lib/sentry/rack/capture_exceptions.rb
|
@@ -96,6 +102,7 @@ files:
|
|
96
102
|
- lib/sentry/transport/configuration.rb
|
97
103
|
- lib/sentry/transport/dummy_transport.rb
|
98
104
|
- lib/sentry/transport/http_transport.rb
|
105
|
+
- lib/sentry/transport/spotlight_transport.rb
|
99
106
|
- lib/sentry/utils/argument_checking_helper.rb
|
100
107
|
- lib/sentry/utils/custom_inspection.rb
|
101
108
|
- lib/sentry/utils/encoding_helper.rb
|
data/CODE_OF_CONDUCT.md
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
2
|
-
|
3
|
-
## Our Pledge
|
4
|
-
|
5
|
-
In the interest of fostering an open and welcoming environment, we as
|
6
|
-
contributors and maintainers pledge to making participation in our project and
|
7
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
-
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
-
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
-
orientation.
|
11
|
-
|
12
|
-
## Our Standards
|
13
|
-
|
14
|
-
Examples of behavior that contributes to creating a positive environment
|
15
|
-
include:
|
16
|
-
|
17
|
-
* Using welcoming and inclusive language
|
18
|
-
* Being respectful of differing viewpoints and experiences
|
19
|
-
* Gracefully accepting constructive criticism
|
20
|
-
* Focusing on what is best for the community
|
21
|
-
* Showing empathy towards other community members
|
22
|
-
|
23
|
-
Examples of unacceptable behavior by participants include:
|
24
|
-
|
25
|
-
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
-
advances
|
27
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
-
* Public or private harassment
|
29
|
-
* Publishing others' private information, such as a physical or electronic
|
30
|
-
address, without explicit permission
|
31
|
-
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
-
professional setting
|
33
|
-
|
34
|
-
## Our Responsibilities
|
35
|
-
|
36
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
-
behavior and are expected to take appropriate and fair corrective action in
|
38
|
-
response to any instances of unacceptable behavior.
|
39
|
-
|
40
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
-
threatening, offensive, or harmful.
|
45
|
-
|
46
|
-
## Scope
|
47
|
-
|
48
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
-
when an individual is representing the project or its community. Examples of
|
50
|
-
representing a project or community include using an official project e-mail
|
51
|
-
address, posting via an official social media account, or acting as an appointed
|
52
|
-
representative at an online or offline event. Representation of a project may be
|
53
|
-
further defined and clarified by project maintainers.
|
54
|
-
|
55
|
-
## Enforcement
|
56
|
-
|
57
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
-
reported by contacting the project team at stan001212@gmail.com. All
|
59
|
-
complaints will be reviewed and investigated and will result in a response that
|
60
|
-
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
-
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
-
Further details of specific enforcement policies may be posted separately.
|
63
|
-
|
64
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
-
faith may face temporary or permanent repercussions as determined by other
|
66
|
-
members of the project's leadership.
|
67
|
-
|
68
|
-
## Attribution
|
69
|
-
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
-
available at [https://contributor-covenant.org/version/1/4][version]
|
72
|
-
|
73
|
-
[homepage]: https://contributor-covenant.org
|
74
|
-
[version]: https://contributor-covenant.org/version/1/4/
|