logstruct 0.1.11 → 0.1.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90d690080da4286690ca86f0d9eb5b9514483f2324898f07912d66015ec4269d
4
- data.tar.gz: df38c5f2434cc5afae25606f77ab2d9a532c9d77c58f81bd558824907ed66418
3
+ metadata.gz: 3aec4782f7bcf89ea8cba8792210e1e5f04165221250178ed283196d7ac89c9d
4
+ data.tar.gz: 4b1d1ffc34a814f4131a43074a598fca7a14acb4ac4cc1ae41cb51f3f35125c2
5
5
  SHA512:
6
- metadata.gz: f654b8b6b7ecf8114c08d4c2b3f9d0f97160bfbd44f60b89ffb08001fed4b186bf7c9697ea8ca1b9ac2d25071f481637e4b050ab4be01efac286d793c12cb7ff
7
- data.tar.gz: 88f8fcf0c87b5e2ccd96152d8abb3de94aaeb952879a37c4cb4fdb84fa9fa858d7fb230f50a8e4d440e30e3a6746cb6bb7b0dc3abdd1dc5f7d95ddfbfed18f0b
6
+ metadata.gz: ab3a907bc346e681caefe09e8a5abda86b4724221722460a6376f13601c2c10dd6d066f5e523b7b1d6088afbb6db60b6a506d57c25b2c762aacb9e7a602ca2cc
7
+ data.tar.gz: 64812fee369aa713104846f69dea5ac17b93c12258ef619ff63c7c9726f51b79fc6d449e45e026d7cd46cc24441ed6a820386346be4df6655ae73974742c2bb9
data/CHANGELOG.md CHANGED
@@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
+ ## [0.1.12] - 2026-01-30
13
+
14
+ ### Added
15
+
16
+ - **Security**: Default regex filter matchers for sensitive keys (password, token, secret, auth, cred, api_key, etc.)
17
+ - **Security**: Job argument filtering for GoodJob/ActiveJob - respects `log_arguments?` class method
18
+ - **Security**: SQL bind parameter filtering now detects JWT tokens and Bearer tokens
19
+
20
+ ### Fixed
21
+
22
+ - **Security**: Reserved keys (src, evt, lvl, ts) in `additional_data` are now protected from being overwritten
23
+ - **CI**: Fixed Ruby 4.0 bundler security error on GitHub Actions (world-writable gem directory)
24
+
12
25
  ## [0.1.11] - 2026-01-28
13
26
 
14
27
  ### Changed
@@ -21,9 +21,12 @@ module LogStruct
21
21
  job.respond_to?(:executions) ? job.executions : nil
22
22
  end
23
23
 
24
+ # Respect log_arguments? setting on job classes.
25
+ # Arguments are logged by default but can be opted-out per job class.
26
+ # When logged, sensitive keys are filtered by Formatter.process_values.
24
27
  sig { params(job: T.untyped).returns(T.nilable(T::Array[T.untyped])) }
25
28
  def self.safe_arguments(job)
26
- return nil unless job.class.respond_to?(:log_arguments?)
29
+ return job.arguments unless job.class.respond_to?(:log_arguments?)
27
30
  job.class.log_arguments? ? job.arguments : nil
28
31
  end
29
32
 
@@ -88,11 +88,32 @@ module LogStruct
88
88
  # Default: false
89
89
  prop :mac_addresses, T::Boolean, default: false
90
90
 
91
+ # Default regex pattern for matching sensitive keys.
92
+ # Matches keys containing: password, token, secret, auth, cred
93
+ # Also matches specific key patterns: api_key, secret_key, private_key, access_key, encryption_key
94
+ # Examples: access_token, api_key, auth_header, credentials
95
+ # Uses start/end of string or underscore/hyphen boundaries to prevent
96
+ # false positives like "keyboard" or "turkey" (which contain "key" mid-word)
97
+ # Note: "key" alone is too broad (matches cron_key, primary_key), so we only match
98
+ # specific sensitive key patterns
99
+ DEFAULT_SENSITIVE_KEY_PATTERN = T.let(
100
+ /(^|[_-])(password|token|secret|auth|cred)([_-]|$)|(^|[_-])(api|secret|private|access|encryption)_key([_-]|$)/i,
101
+ Regexp
102
+ )
103
+
91
104
  # Additional filter matchers built from Rails filter_parameters entries that aren't simple symbols.
92
105
  # Each matcher receives the key (String) and optional value, returning true when the pair should be filtered.
106
+ # By default, includes a regex matcher for common sensitive key patterns.
93
107
  prop :filter_matchers,
94
108
  T::Array[FilterMatcher],
95
- factory: -> { [] }
109
+ factory: -> {
110
+ [
111
+ FilterMatcher.new(
112
+ callable: ->(key, _value) { DEFAULT_SENSITIVE_KEY_PATTERN.match?(key) },
113
+ label: "default_sensitive_pattern"
114
+ )
115
+ ]
116
+ }
96
117
  end
97
118
  end
98
119
  end
@@ -31,8 +31,8 @@ module LogStruct
31
31
  LogStruct.info(
32
32
  LogStruct::Log::ActiveModelSerializers.new(
33
33
  message: "ams.render",
34
- serializer: serializer&.to_s,
35
- adapter: adapter&.to_s,
34
+ serializer: serializer&.name,
35
+ adapter: adapter&.class&.name,
36
36
  resource_class: resource&.class&.name,
37
37
  duration_ms: duration_ms,
38
38
  timestamp: started
@@ -281,6 +281,12 @@ module LogStruct
281
281
  return true if value.match?(/\A[A-Za-z0-9+\/]{20,}={0,2}\z/) # Base64
282
282
  return true if value.match?(/(password|secret|token|key|auth)/i)
283
283
 
284
+ # Filter JWT tokens (header.payload.signature format, starts with "ey")
285
+ return true if value.match?(/\Aey[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\z/)
286
+
287
+ # Filter Bearer tokens
288
+ return true if value.match?(/\ABearer\s+/i)
289
+
284
290
  false
285
291
  end
286
292
  end
@@ -148,11 +148,21 @@ module LogStruct
148
148
  job_id: job&.job_id,
149
149
  job_class: job&.job_class,
150
150
  queue_name: job&.queue_name&.to_sym,
151
- arguments: job&.arguments,
151
+ arguments: safe_arguments(job),
152
152
  executions: execution&.executions
153
153
  )
154
154
  end
155
155
 
156
+ # Respect log_arguments? setting on job classes (consistent with ActiveJob behavior).
157
+ # Arguments are logged by default but can be opted-out per job class.
158
+ # When logged, sensitive keys are filtered by Formatter.process_values.
159
+ sig { params(job: T.untyped).returns(T.nilable(T::Array[T.untyped])) }
160
+ def safe_arguments(job)
161
+ return nil unless job
162
+ return job.arguments unless job.class.respond_to?(:log_arguments?)
163
+ job.class.log_arguments? ? job.arguments : nil
164
+ end
165
+
156
166
  # Calculate wait time from job creation to execution start
157
167
  sig { params(execution: T.untyped).returns(T.nilable(Float)) }
158
168
  def calculate_wait_time(execution)
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative "interfaces/additional_data_field"
5
+ require_relative "../enums/source"
5
6
 
6
7
  module LogStruct
7
8
  module Log
@@ -13,12 +14,24 @@ module LogStruct
13
14
  requires_ancestor { T::Struct }
14
15
  requires_ancestor { Interfaces::AdditionalDataField }
15
16
 
17
+ # Reserved keys that cannot be overwritten by additional_data.
18
+ # These are the core log structure fields that must not be modified.
19
+ RESERVED_KEYS = T.let(%i[src evt lvl ts].freeze, T::Array[Symbol])
20
+
16
21
  sig { params(hash: T::Hash[Symbol, T.untyped]).void }
17
22
  def merge_additional_data_fields(hash)
18
23
  ad = additional_data
19
24
  return unless ad
20
25
  ad.each do |key, value|
21
- hash[key.to_sym] = value
26
+ sym_key = key.to_sym
27
+ if RESERVED_KEYS.include?(sym_key)
28
+ LogStruct.handle_exception(
29
+ ArgumentError.new("additional_data attempted to overwrite reserved key: #{sym_key}"),
30
+ source: Source::Internal
31
+ )
32
+ next
33
+ end
34
+ hash[sym_key] = value
22
35
  end
23
36
  end
24
37
  end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module LogStruct
5
- VERSION = "0.1.11"
5
+ VERSION = "0.1.12"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstruct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - DocSpring