julewire-redaction 1.0.1 → 1.1.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 +10 -0
- data/julewire-redaction.gemspec +1 -1
- data/lib/julewire/redaction/processor.rb +12 -13
- data/lib/julewire/redaction/string_redactor.rb +13 -19
- data/lib/julewire/redaction/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a86f67b65bb42fc7873df8effd2319e85afca0fa93519902c11d61d824398a4b
|
|
4
|
+
data.tar.gz: 3a26f5d4761d4e81e0791a229e44111712293c7fcd50c5572c391824c551599a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4f521e8774ef159420c20a00d144e6abcec54e2f4b31769c63dd7c3a98e6276b58225550b5e29bf554d55ab914cc1d89859cd0ed3cf98fc047e260cda50d66f6
|
|
7
|
+
data.tar.gz: b8dfed70ac1559d9c596d4fb9470cd1656924e273be0f8f7de9b56dd8d936889b064550e8e5af17a64d161c4859afa35b2ec0458016028fcb0dee941d45d097c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
## 1.1.1 - 2026-07-26
|
|
4
|
+
|
|
5
|
+
- Refresh the tested dependency lockset.
|
|
6
|
+
|
|
7
|
+
## 1.1.0 - 2026-07-20
|
|
8
|
+
|
|
9
|
+
- Match path filters against both section-prefixed and section-relative paths.
|
|
10
|
+
- Keep bounded redaction metadata aligned with core truncation contracts.
|
|
11
|
+
- Require julewire-core 1.1.0.
|
|
12
|
+
|
|
3
13
|
## 1.0.1 - 2026-06-25
|
|
4
14
|
|
|
5
15
|
- Require julewire-core 1.0.1.
|
data/julewire-redaction.gemspec
CHANGED
|
@@ -32,9 +32,7 @@ module Julewire
|
|
|
32
32
|
authorization_header: authorization_header
|
|
33
33
|
)
|
|
34
34
|
end
|
|
35
|
-
@
|
|
36
|
-
@redact_scalars = @string_redactor || !@blocks.empty?
|
|
37
|
-
@enabled = @redact_keys || @redact_scalars
|
|
35
|
+
@enabled = !@matcher.empty? || @string_redactor || !@blocks.empty?
|
|
38
36
|
@record_transform = Core::Processing::RecordFieldTransform.new(
|
|
39
37
|
max_array_items: @max_array_items,
|
|
40
38
|
max_depth: @max_depth,
|
|
@@ -72,29 +70,30 @@ module Julewire
|
|
|
72
70
|
end
|
|
73
71
|
end
|
|
74
72
|
|
|
75
|
-
def redact_item(item, key:,
|
|
73
|
+
def redact_item(item, key:, original:, path:, prefixed_path:, **)
|
|
76
74
|
return @mask if redacted_key?(key, path: path, prefixed_path: prefixed_path)
|
|
77
|
-
if @redact_scalars && !item.is_a?(Hash) && !item.is_a?(Array)
|
|
78
|
-
return redact_scalar(item, key: key, original: original)
|
|
79
|
-
end
|
|
80
75
|
|
|
81
|
-
|
|
76
|
+
if !item.instance_of?(Hash) && !item.instance_of?(Array)
|
|
77
|
+
redact_scalar(item, key: key, original: original)
|
|
78
|
+
else
|
|
79
|
+
Core::Serialization::BoundedTransform::CONTINUE
|
|
80
|
+
end
|
|
82
81
|
end
|
|
83
82
|
|
|
84
83
|
def redacted_key?(key, path:, prefixed_path:)
|
|
85
|
-
return
|
|
86
|
-
return true if @matcher.match?(key, path: path)
|
|
84
|
+
return true if key && @matcher.match?(key, path: path)
|
|
87
85
|
|
|
88
|
-
prefixed_path && @matcher.match?(
|
|
86
|
+
prefixed_path && @matcher.match?(nil, path: prefixed_path)
|
|
89
87
|
end
|
|
90
88
|
|
|
91
89
|
def redact_scalar(value, key:, original:)
|
|
92
90
|
value = apply_block_filters(key, value, original) if key && !@blocks.empty?
|
|
93
|
-
|
|
91
|
+
@string_redactor ? @string_redactor.call(value) : value
|
|
94
92
|
end
|
|
95
93
|
|
|
96
94
|
def apply_block_filters(key, value, original)
|
|
97
|
-
key_copy =
|
|
95
|
+
key_copy = +""
|
|
96
|
+
key_copy.concat(key.to_s)
|
|
98
97
|
value_copy = duplicate_filter_value(value)
|
|
99
98
|
@blocks.each do |block|
|
|
100
99
|
block.arity == 2 ? block.call(key_copy, value_copy) : block.call(key_copy, value_copy, original)
|
|
@@ -7,7 +7,6 @@ module Julewire
|
|
|
7
7
|
@matcher = matcher
|
|
8
8
|
@mask = mask.to_s
|
|
9
9
|
@authorization_header = authorization_header
|
|
10
|
-
@redact_headers = @authorization_header || !@matcher.empty?
|
|
11
10
|
@redact_pairs = !@matcher.empty?
|
|
12
11
|
end
|
|
13
12
|
|
|
@@ -19,12 +18,10 @@ module Julewire
|
|
|
19
18
|
return value unless redaction_possible?(has_colon, has_equals)
|
|
20
19
|
|
|
21
20
|
redacted = value.dup
|
|
22
|
-
redact_header_lines!(redacted) if
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
redact_json_pairs!(redacted) if json_pair_possible?(value, has_colon)
|
|
27
|
-
redact_form_pairs!(redacted) if form_pair_possible?(has_equals)
|
|
21
|
+
redact_header_lines!(redacted) if has_colon
|
|
22
|
+
if @redact_pairs && @matcher.string_key_possible?(value)
|
|
23
|
+
redact_pair_values!(value, redacted, has_colon: has_colon, has_equals: has_equals)
|
|
24
|
+
end
|
|
28
25
|
redacted
|
|
29
26
|
end
|
|
30
27
|
|
|
@@ -35,23 +32,20 @@ module Julewire
|
|
|
35
32
|
end
|
|
36
33
|
|
|
37
34
|
def header_redaction_possible?(has_colon)
|
|
38
|
-
@
|
|
35
|
+
@authorization_header && has_colon
|
|
39
36
|
end
|
|
40
37
|
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def form_pair_possible?(has_equals)
|
|
46
|
-
@redact_pairs && has_equals
|
|
38
|
+
def redact_pair_values!(value, redacted, has_colon:, has_equals:)
|
|
39
|
+
redact_json_pairs!(redacted) if has_colon && (value.include?('"') || value.include?("'"))
|
|
40
|
+
redact_form_pairs!(redacted) if has_equals
|
|
47
41
|
end
|
|
48
42
|
|
|
49
43
|
def redact_header_lines!(value)
|
|
50
|
-
value.gsub!(/(
|
|
51
|
-
name = Regexp.last_match(2)
|
|
44
|
+
value.gsub!(/(\A|[\r\n])([A-Za-z0-9-]+)(:\s*)[^\r\n]*/) do |line|
|
|
45
|
+
name = Regexp.last_match(2)
|
|
52
46
|
next line unless redact_header?(name)
|
|
53
47
|
|
|
54
|
-
"#{Regexp.last_match(1)}#{Regexp.last_match(2)}#{@mask}"
|
|
48
|
+
"#{Regexp.last_match(1)}#{Regexp.last_match(2)}#{Regexp.last_match(3)}#{@mask}"
|
|
55
49
|
end
|
|
56
50
|
end
|
|
57
51
|
|
|
@@ -63,7 +57,7 @@ module Julewire
|
|
|
63
57
|
|
|
64
58
|
def redact_json_pairs!(value)
|
|
65
59
|
# Defense-in-depth for short log strings; large bodies should stay bounded.
|
|
66
|
-
value.gsub!(/(["'])([^"']+)\1(\s*:\s*)(["'])(
|
|
60
|
+
value.gsub!(/(["'])([^"']+)\1(\s*:\s*)(["'])(?:.*?)\4/) do |pair|
|
|
67
61
|
next pair unless @matcher.match?(Regexp.last_match(2))
|
|
68
62
|
|
|
69
63
|
"#{Regexp.last_match(1)}#{Regexp.last_match(2)}#{Regexp.last_match(1)}" \
|
|
@@ -72,7 +66,7 @@ module Julewire
|
|
|
72
66
|
end
|
|
73
67
|
|
|
74
68
|
def redact_form_pairs!(value)
|
|
75
|
-
value.gsub!(/(
|
|
69
|
+
value.gsub!(/(\A|[?&\s])([^?&\s"=]+)(=)(?:[^&\s"]+)/) do |pair|
|
|
76
70
|
next pair unless @matcher.match?(Regexp.last_match(2))
|
|
77
71
|
|
|
78
72
|
"#{Regexp.last_match(1)}#{Regexp.last_match(2)}#{Regexp.last_match(3)}#{@mask}"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: julewire-redaction
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Grebennik
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 1.0
|
|
18
|
+
version: 1.1.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 1.0
|
|
25
|
+
version: 1.1.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: zeitwerk
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -83,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
83
83
|
- !ruby/object:Gem::Version
|
|
84
84
|
version: '0'
|
|
85
85
|
requirements: []
|
|
86
|
-
rubygems_version: 4.0.
|
|
86
|
+
rubygems_version: 4.0.16
|
|
87
87
|
specification_version: 4
|
|
88
88
|
summary: Structured redaction processor for Julewire.
|
|
89
89
|
test_files: []
|