chronos-ruby 0.1.0.pre.2 → 0.2.0.pre.1
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/CHANGELOG.md +31 -0
- data/README.md +32 -19
- data/docs/adr/ADR-005-sanitize-before-backlog.md +2 -2
- data/docs/architecture.md +2 -2
- data/docs/compatibility.md +1 -1
- data/docs/configuration.md +10 -1
- data/docs/data-collected.md +10 -7
- data/docs/examples/plain-ruby.md +8 -0
- data/docs/modules/async-queue.md +1 -1
- data/docs/modules/notice-pipeline.md +5 -3
- data/docs/modules/sanitization.md +19 -0
- data/docs/modules/serialization.md +9 -0
- data/docs/modules/transport.md +1 -1
- data/docs/performance.md +14 -2
- data/docs/privacy-lgpd.md +78 -10
- data/docs/troubleshooting.md +2 -2
- data/lib/chronos/adapters/net_http_transport.rb +2 -2
- data/lib/chronos/application/capture_exception.rb +2 -2
- data/lib/chronos/configuration.rb +79 -4
- data/lib/chronos/core/notice.rb +1 -1
- data/lib/chronos/core/payload_serializer.rb +35 -87
- data/lib/chronos/core/runtime_info.rb +1 -1
- data/lib/chronos/core/safe_serializer.rb +119 -0
- data/lib/chronos/core/sanitizer.rb +161 -0
- data/lib/chronos/core/sensitive_value_filter.rb +118 -0
- data/lib/chronos/internal/bounded_queue.rb +1 -1
- data/lib/chronos/internal/worker_pool.rb +1 -1
- data/lib/chronos/ports/transport.rb +1 -1
- data/lib/chronos/version.rb +1 -1
- data/lib/chronos.rb +4 -1
- metadata +22 -11
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module Chronos
|
|
2
|
+
module Core
|
|
3
|
+
# Redacts recognized secret and personal-data patterns inside strings.
|
|
4
|
+
#
|
|
5
|
+
# @responsibility Detect bounded sensitive value formats independently of hash-key policy.
|
|
6
|
+
# @motivation Protect exception messages and allowlisted fields where no sensitive key exists.
|
|
7
|
+
# @limits Detection is conservative, validates documents and cards, and does not cover every format.
|
|
8
|
+
# @collaborators Sanitizer.
|
|
9
|
+
# @thread_safety Immutable after construction and safe to share between capture calls.
|
|
10
|
+
# @compatibility Ruby 2.2.10 through Ruby 2.6.
|
|
11
|
+
# @example
|
|
12
|
+
# filter.call("person@example.com") #=> "[FILTERED_EMAIL]"
|
|
13
|
+
# @errors Invalid encodings become a filtered placeholder.
|
|
14
|
+
# @performance Applies a fixed set of regular expressions to each bounded string.
|
|
15
|
+
class SensitiveValueFilter
|
|
16
|
+
FILTERED = "[FILTERED]".freeze
|
|
17
|
+
FILTERED_EMAIL = "[FILTERED_EMAIL]".freeze
|
|
18
|
+
FILTERED_DOCUMENT = "[FILTERED_DOCUMENT]".freeze
|
|
19
|
+
FILTERED_CARD = "[FILTERED_CARD]".freeze
|
|
20
|
+
FILTERED_JWT = "[FILTERED_JWT]".freeze
|
|
21
|
+
|
|
22
|
+
EMAIL_PATTERN = /\b[A-Z0-9._%+\-]+@[A-Z0-9.\-]+\.[A-Z]{2,}\b/i
|
|
23
|
+
JWT_PATTERN = /\b[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/
|
|
24
|
+
BEARER_PATTERN = /\bBearer\s+[^\s,;]+/i
|
|
25
|
+
CPF_PATTERN = /\b\d{3}\.?\d{3}\.?\d{3}-?\d{2}\b/
|
|
26
|
+
CNPJ_PATTERN = %r{\b\d{2}\.?\d{3}\.?\d{3}/?\d{4}-?\d{2}\b}
|
|
27
|
+
IPV4_PATTERN = /\b(?:\d{1,3}\.){3}\d{1,3}\b/
|
|
28
|
+
CARD_PATTERN = /\b(?:\d[ -]?){12,18}\d\b/
|
|
29
|
+
|
|
30
|
+
def initialize(anonymize_ip)
|
|
31
|
+
@anonymize_ip = anonymize_ip
|
|
32
|
+
freeze
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def call(value)
|
|
36
|
+
result = safe_string(value)
|
|
37
|
+
result = result.gsub(BEARER_PATTERN, "Bearer #{FILTERED}") if result =~ BEARER_PATTERN
|
|
38
|
+
result = result.gsub(JWT_PATTERN, FILTERED_JWT) if result.count(".") >= 2
|
|
39
|
+
result = result.gsub(EMAIL_PATTERN, FILTERED_EMAIL) if result.include?("@")
|
|
40
|
+
result = redact_numeric_values(result) if result.count("0-9") >= 11
|
|
41
|
+
@anonymize_ip && result.count(".") >= 3 ? anonymize_ipv4(result) : result
|
|
42
|
+
rescue StandardError
|
|
43
|
+
FILTERED
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def redact_numeric_values(value)
|
|
49
|
+
result = redact_documents(value)
|
|
50
|
+
value.count("0-9") >= 13 ? redact_cards(result) : result
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def redact_cards(value)
|
|
54
|
+
value.gsub(CARD_PATTERN) do |candidate|
|
|
55
|
+
luhn_valid?(candidate) ? FILTERED_CARD : candidate
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def redact_documents(value)
|
|
60
|
+
result = value.gsub(CNPJ_PATTERN) do |candidate|
|
|
61
|
+
valid_cnpj?(candidate) ? FILTERED_DOCUMENT : candidate
|
|
62
|
+
end
|
|
63
|
+
result.gsub(CPF_PATTERN) do |candidate|
|
|
64
|
+
valid_cpf?(candidate) ? FILTERED_DOCUMENT : candidate
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def valid_cpf?(candidate)
|
|
69
|
+
digits = candidate.gsub(/\D/, "").chars.map(&:to_i)
|
|
70
|
+
return false if digits.uniq.size == 1
|
|
71
|
+
|
|
72
|
+
digits[9] == document_digit(digits.first(9), (2..10).to_a.reverse) &&
|
|
73
|
+
digits[10] == document_digit(digits.first(10), (2..11).to_a.reverse)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def valid_cnpj?(candidate)
|
|
77
|
+
digits = candidate.gsub(/\D/, "").chars.map(&:to_i)
|
|
78
|
+
return false if digits.uniq.size == 1
|
|
79
|
+
|
|
80
|
+
first_weights = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
|
|
81
|
+
second_weights = [6] + first_weights
|
|
82
|
+
digits[12] == document_digit(digits.first(12), first_weights) &&
|
|
83
|
+
digits[13] == document_digit(digits.first(13), second_weights)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def document_digit(digits, weights)
|
|
87
|
+
remainder = digits.each_with_index.inject(0) do |sum, (digit, index)|
|
|
88
|
+
sum + (digit * weights[index])
|
|
89
|
+
end % 11
|
|
90
|
+
remainder < 2 ? 0 : 11 - remainder
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def luhn_valid?(candidate)
|
|
94
|
+
digits = candidate.gsub(/\D/, "").chars.map(&:to_i)
|
|
95
|
+
return false unless digits.length.between?(13, 19)
|
|
96
|
+
|
|
97
|
+
sum = digits.reverse.each_with_index.inject(0) do |total, (digit, index)|
|
|
98
|
+
doubled = index.odd? ? digit * 2 : digit
|
|
99
|
+
total + (doubled > 9 ? doubled - 9 : doubled)
|
|
100
|
+
end
|
|
101
|
+
(sum % 10).zero?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def anonymize_ipv4(value)
|
|
105
|
+
value.gsub(IPV4_PATTERN) do |candidate|
|
|
106
|
+
octets = candidate.split(".").map(&:to_i)
|
|
107
|
+
octets.all? { |octet| octet.between?(0, 255) } ? "#{octets[0, 3].join('.')}.0" : candidate
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def safe_string(value)
|
|
112
|
+
value.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "�")
|
|
113
|
+
rescue StandardError
|
|
114
|
+
FILTERED
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -4,7 +4,7 @@ module Chronos
|
|
|
4
4
|
#
|
|
5
5
|
# @responsibility Accept events up to a limit and count accepted and dropped items.
|
|
6
6
|
# @motivation Prevent telemetry bursts from growing application memory indefinitely.
|
|
7
|
-
# @limits Version 0.
|
|
7
|
+
# @limits Version 0.2 drops the newest item when full and does not persist to disk.
|
|
8
8
|
# @collaborators WorkerPool.
|
|
9
9
|
# @thread_safety Mutex and condition variable protect all mutable state.
|
|
10
10
|
# @compatibility Ruby 2.2.10 through Ruby 2.6 and fork-aware callers.
|
|
@@ -4,7 +4,7 @@ module Chronos
|
|
|
4
4
|
#
|
|
5
5
|
# @responsibility Start workers on first use, deliver events, flush, and shut down predictably.
|
|
6
6
|
# @motivation Keep serialization and network delivery outside the caller's critical path.
|
|
7
|
-
# @limits Version 0.
|
|
7
|
+
# @limits Version 0.2 does not retry failed deliveries or persist a backlog.
|
|
8
8
|
# @collaborators BoundedQueue, Transport, and SafeLogger.
|
|
9
9
|
# @thread_safety Internal state is synchronized and active delivery is counted.
|
|
10
10
|
# @compatibility Ruby 2.2.10 through Ruby 2.6; workers are recreated after fork.
|
|
@@ -4,7 +4,7 @@ module Chronos
|
|
|
4
4
|
#
|
|
5
5
|
# @responsibility Describe delivery outcome and retry classification.
|
|
6
6
|
# @motivation Keep HTTP implementation details outside the application layer.
|
|
7
|
-
# @limits It does not schedule retries; retry is outside version 0.
|
|
7
|
+
# @limits It does not schedule retries; retry is outside version 0.2.
|
|
8
8
|
# @thread_safety Immutable after construction.
|
|
9
9
|
# @compatibility Ruby 2.2.10 through Ruby 2.6.
|
|
10
10
|
class TransportResult
|
data/lib/chronos/version.rb
CHANGED
data/lib/chronos.rb
CHANGED
|
@@ -11,6 +11,9 @@ require "chronos/core/backtrace_parser"
|
|
|
11
11
|
require "chronos/core/exception_cause_collector"
|
|
12
12
|
require "chronos/core/runtime_info"
|
|
13
13
|
require "chronos/core/notice_builder"
|
|
14
|
+
require "chronos/core/sensitive_value_filter"
|
|
15
|
+
require "chronos/core/sanitizer"
|
|
16
|
+
require "chronos/core/safe_serializer"
|
|
14
17
|
require "chronos/core/payload_serializer"
|
|
15
18
|
require "chronos/ports/transport"
|
|
16
19
|
require "chronos/internal/safe_logger"
|
|
@@ -24,7 +27,7 @@ require "chronos/agent"
|
|
|
24
27
|
#
|
|
25
28
|
# @responsibility Configure the agent and expose its small lifecycle API.
|
|
26
29
|
# @motivation Give applications a stable entry point while internals evolve.
|
|
27
|
-
# @limits Version 0.
|
|
30
|
+
# @limits Version 0.2 captures Ruby exceptions manually; integrations arrive later.
|
|
28
31
|
# @collaborators Configuration and Agent.
|
|
29
32
|
# @thread_safety Agent replacement and lookup are protected by a mutex.
|
|
30
33
|
# @compatibility Ruby 2.2.10 through Ruby 2.6.
|
metadata
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chronos-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0.pre.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Antonio Jefferson
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2026-07-20 00:00:00.000000000 Z
|
|
@@ -30,14 +30,20 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '12.3'
|
|
34
|
+
- - ">="
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: 12.3.3
|
|
34
37
|
type: :development
|
|
35
38
|
prerelease: false
|
|
36
39
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
40
|
requirements:
|
|
38
41
|
- - "~>"
|
|
39
42
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
43
|
+
version: '12.3'
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 12.3.3
|
|
41
47
|
- !ruby/object:Gem::Dependency
|
|
42
48
|
name: rspec
|
|
43
49
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -56,16 +62,16 @@ dependencies:
|
|
|
56
62
|
name: rubocop
|
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
|
58
64
|
requirements:
|
|
59
|
-
- -
|
|
65
|
+
- - "~>"
|
|
60
66
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0.
|
|
67
|
+
version: 0.49.0
|
|
62
68
|
type: :development
|
|
63
69
|
prerelease: false
|
|
64
70
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
71
|
requirements:
|
|
66
|
-
- -
|
|
72
|
+
- - "~>"
|
|
67
73
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: 0.
|
|
74
|
+
version: 0.49.0
|
|
69
75
|
description: Base do cliente Chronos para excecoes, telemetria e observabilidade em
|
|
70
76
|
aplicacoes Ruby legadas.
|
|
71
77
|
email:
|
|
@@ -95,6 +101,8 @@ files:
|
|
|
95
101
|
- docs/modules/async-queue.md
|
|
96
102
|
- docs/modules/configuration.md
|
|
97
103
|
- docs/modules/notice-pipeline.md
|
|
104
|
+
- docs/modules/sanitization.md
|
|
105
|
+
- docs/modules/serialization.md
|
|
98
106
|
- docs/modules/transport.md
|
|
99
107
|
- docs/performance.md
|
|
100
108
|
- docs/privacy-lgpd.md
|
|
@@ -113,6 +121,9 @@ files:
|
|
|
113
121
|
- lib/chronos/core/notice_builder.rb
|
|
114
122
|
- lib/chronos/core/payload_serializer.rb
|
|
115
123
|
- lib/chronos/core/runtime_info.rb
|
|
124
|
+
- lib/chronos/core/safe_serializer.rb
|
|
125
|
+
- lib/chronos/core/sanitizer.rb
|
|
126
|
+
- lib/chronos/core/sensitive_value_filter.rb
|
|
116
127
|
- lib/chronos/errors.rb
|
|
117
128
|
- lib/chronos/internal.rb
|
|
118
129
|
- lib/chronos/internal/bounded_queue.rb
|
|
@@ -131,7 +142,7 @@ metadata:
|
|
|
131
142
|
homepage_uri: https://github.com/antoniojefferson/chronos-ruby
|
|
132
143
|
source_code_uri: https://github.com/antoniojefferson/chronos-ruby
|
|
133
144
|
changelog_uri: https://github.com/antoniojefferson/chronos-ruby/blob/main/CHANGELOG.md
|
|
134
|
-
post_install_message:
|
|
145
|
+
post_install_message:
|
|
135
146
|
rdoc_options: []
|
|
136
147
|
require_paths:
|
|
137
148
|
- lib
|
|
@@ -149,8 +160,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
149
160
|
- !ruby/object:Gem::Version
|
|
150
161
|
version: 1.3.1
|
|
151
162
|
requirements: []
|
|
152
|
-
rubygems_version: 3.
|
|
153
|
-
signing_key:
|
|
163
|
+
rubygems_version: 3.4.22
|
|
164
|
+
signing_key:
|
|
154
165
|
specification_version: 4
|
|
155
166
|
summary: Cliente Ruby para captura de eventos do Chronos
|
|
156
167
|
test_files: []
|