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.
@@ -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.1 drops the newest item when full and does not persist to disk.
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.1 does not retry failed deliveries or persist a backlog.
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.1.
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
@@ -1,4 +1,4 @@
1
1
  module Chronos
2
2
  # Current version of the legacy Chronos Ruby agent.
3
- VERSION = "0.1.0.pre.2".freeze
3
+ VERSION = "0.2.0.pre.1".freeze
4
4
  end
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.1 captures Ruby exceptions only; integrations arrive later.
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.1.0.pre.2
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: '10.0'
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: '10.0'
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.47.1
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.47.1
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.0.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: []