ndr_support 5.9.6 → 5.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7447cd235fe9715cc6e6c868b0f0048c7ec516b70ea88e323dcdc1fd01e24f11
4
- data.tar.gz: 16b4237428fdf1258327ebc86928c4f3cc8db292289ff8151db364f77c505439
3
+ metadata.gz: 452da481cc47dceb02b62e7eb832db07ba61985fb2cdc8267a40b6194d0ef108
4
+ data.tar.gz: e06b9a9845389b639c2fbe55aab1f4008d6dad69843a24113bf55b2b88fd7d56
5
5
  SHA512:
6
- metadata.gz: 186d4b1f8f053e9fa2cba311d7f9760e496ea8597dbea5c7e3e1d34c62fe6237df8c51692ff40a18f98085b58dc9a98942a54b94854b0e32ea30e4033e9d9aa3
7
- data.tar.gz: 68ada778e3d6d7b9187f5b95398f408ff08940e0c77f5019a99611279ff4e1bbb9a5bfacd32ed3c0082bfb607ecc93df158ef2399b414d53a0e0bc7c53c0727a
6
+ metadata.gz: 7d06a0fb2e4adae1cbc71b7e89fd4fc45b527a419ad313d6440dd199ddb845df637b4dd505dce4220dae16bc6f059e96a2faddc455c1901a54bd8acba86b4b3e
7
+ data.tar.gz: d5abcaa621cf18823123cd1241a519c2c2a9dd856ac6659a9f4d4497adcd11ec4b57beeade25c7e799b9924de02736344b91ef079b2bef5a65785a41a6d20333
data/CHANGELOG.md CHANGED
@@ -1,6 +1,17 @@
1
1
  ## [Unreleased]
2
2
  * No unreleased changes
3
3
 
4
+ ## 5.10.0 / 2023-11-17
5
+ ## Changed
6
+ * Generate UTF-8 encoded YAML by default. Disable with `utf8_storage = false`
7
+ * Use `YAML.safe_load` by default. Override with
8
+ `self.yaml_safe_classes = yaml_safe_classes + [Klass1, Klass2]` and revert to
9
+ unsafe loading with `yaml_safe_classes = :unsafe` and `gem 'psych', '< 4'`
10
+
11
+ ## 5.9.7 / 2023-11-16
12
+ ## Fixed
13
+ * YAMLSupport should preserve escaped backslashes in YAML text
14
+
4
15
  ## 5.9.6 / 2023-11-14
5
16
  ## Fixed
6
17
  * YAMLSupport should preserve escape sequences in JSON text
data/code_safety.yml CHANGED
@@ -23,7 +23,7 @@ file safety:
23
23
  CHANGELOG.md:
24
24
  comments:
25
25
  reviewed_by: brian.shand
26
- safe_revision: '09ad2e0c210d3e4377de68dac3d54932df6c1994'
26
+ safe_revision: 646eaebdf824490150e991225f9e15abb67dd4c1
27
27
  CODE_OF_CONDUCT.md:
28
28
  comments:
29
29
  reviewed_by: timgentry
@@ -171,7 +171,7 @@ file safety:
171
171
  lib/ndr_support/version.rb:
172
172
  comments:
173
173
  reviewed_by: brian.shand
174
- safe_revision: 26236a310377036e1a27eb9534b4167430da6f3c
174
+ safe_revision: 765520ebaf3652bed7105995c815afe681dd5363
175
175
  lib/ndr_support/working_days.rb:
176
176
  comments:
177
177
  reviewed_by: josh.pencheon
@@ -179,7 +179,7 @@ file safety:
179
179
  lib/ndr_support/yaml/serialization_migration.rb:
180
180
  comments:
181
181
  reviewed_by: brian.shand
182
- safe_revision: '09ad2e0c210d3e4377de68dac3d54932df6c1994'
182
+ safe_revision: 646eaebdf824490150e991225f9e15abb67dd4c1
183
183
  ndr_support.gemspec:
184
184
  comments:
185
185
  reviewed_by: brian.shand
@@ -283,4 +283,4 @@ file safety:
283
283
  test/yaml/serialization_test.rb:
284
284
  comments:
285
285
  reviewed_by: brian.shand
286
- safe_revision: '09ad2e0c210d3e4377de68dac3d54932df6c1994'
286
+ safe_revision: 646eaebdf824490150e991225f9e15abb67dd4c1
@@ -3,5 +3,5 @@
3
3
  # This defines the NdrSupport version. If you change it, rebuild and commit the gem.
4
4
  # Use "rake build" to build the gem, see rake -T for all bundler rake tasks.
5
5
  module NdrSupport
6
- VERSION = '5.9.6'
6
+ VERSION = '5.10.0'
7
7
  end
@@ -12,8 +12,29 @@ module NdrSupport
12
12
  # accepted by load_yaml
13
13
  YAML_SAFE_CLASSES = [Date, DateTime, Time, Symbol].freeze
14
14
 
15
+ # Set list of YAML safe classes, or :unsafe to use unsafe load
16
+ def yaml_safe_classes=(yaml_safe_classes)
17
+ @yaml_safe_classes = yaml_safe_classes
18
+ end
19
+
20
+ def yaml_safe_classes
21
+ @yaml_safe_classes || YAML_SAFE_CLASSES
22
+ end
23
+
24
+ # Allow emitted YAML to contain UTF-8 characters
25
+ # Defaults to true. (Defaulted to false in ndr_support versions < 6)
26
+ def utf8_storage=(utf8_storage)
27
+ @utf8_storage = utf8_storage
28
+ end
29
+
30
+ def utf8_storage
31
+ return @utf8_storage if @utf8_storage == false
32
+
33
+ true # New ndr_support default for versions >= 6, previously false
34
+ end
35
+
15
36
  # Wrapper around: YAML.load(string)
16
- def load_yaml(string, coerce_invalid_chars = false)
37
+ def load_yaml(string, coerce_invalid_chars = false) # rubocop:disable Style/OptionalBooleanParameter
17
38
  fix_encoding!(string, coerce_invalid_chars)
18
39
 
19
40
  # Achieve same behaviour using `syck` and `psych`:
@@ -21,10 +42,14 @@ module NdrSupport
21
42
  fix_encoding!(string, coerce_invalid_chars)
22
43
 
23
44
  # TODO: Bump NdrSupport major version, and switch to safe_load by default
24
- object = if Psych::VERSION.start_with?('3.')
45
+ object = if yaml_safe_classes == :unsafe
46
+ unless Psych::VERSION.start_with?('3.')
47
+ raise(SecurityError, 'Unsafe YAML no longer supported')
48
+ end
49
+
25
50
  Psych.load(string)
26
51
  else
27
- Psych.safe_load(string, permitted_classes: YAML_SAFE_CLASSES)
52
+ Psych.safe_load(string, permitted_classes: yaml_safe_classes)
28
53
  end
29
54
 
30
55
  # Ensure that any string related to the object
@@ -37,8 +62,10 @@ module NdrSupport
37
62
 
38
63
  # Wrapper around: YAML.dump(object)
39
64
  def dump_yaml(object)
40
- # Psych produces UTF-8 encoded output; we'd rather
41
- # have YAML that can be safely stored in stores with
65
+ return Psych.dump(object) if utf8_storage
66
+
67
+ # Psych produces UTF-8 encoded output; historically we
68
+ # preferred YAML that can be safely stored in stores with
42
69
  # other encodings. If #load_yaml is used, the binary
43
70
  # encoding of the object will be reversed on load.
44
71
  Psych.dump binary_encode_any_high_ascii(object)
@@ -56,14 +83,17 @@ module NdrSupport
56
83
  # Within double quotes, YAML allows special characters.
57
84
  # While `psych` emits UTF-8 YAML, `syck` double escapes
58
85
  # higher characters. We need to unescape any we find:
86
+ # Both `psych` and `syck` escape lower control characters.
59
87
  def handle_special_characters!(string, coerce_invalid_chars)
60
- # TODO: Change to only handle syck control characters
61
88
  return unless string.start_with?('---') # Only handle YAML that is not JSON
62
89
 
63
90
  # Replace any encoded hex chars with their actual value:
64
- string.gsub!(/((?:\\x[0-9A-F]{2})+)/) do
65
- byte_sequence = $1.scan(/[0-9A-F]{2}/)
66
- byte_sequence.pack('H2' * byte_sequence.length).tap do |sequence|
91
+ string.gsub!(/(?<!\\)((?:\\\\)*)((?:\\x[0-9A-F]{2})+)/) do
92
+ # We use negative lookbehind and the first capturing group to skip over
93
+ # properly escaped backslashes
94
+ prefix = ::Regexp.last_match(1) # Prefix is an even number of backslashes
95
+ byte_sequence = ::Regexp.last_match(2).scan(/[0-9A-F]{2}/)
96
+ prefix + byte_sequence.pack('H2' * byte_sequence.length).tap do |sequence|
67
97
  fix_encoding!(sequence, coerce_invalid_chars)
68
98
  end
69
99
  end
@@ -29,8 +29,14 @@ class SerializationTest < Minitest::Test
29
29
  assert_equal "control 0x01 char \n whoops!", load_yaml(chr_1_yaml)
30
30
  end
31
31
 
32
+ test 'should handle non-binary yaml with escaped things that look like control chars' do
33
+ # irb> Psych.dump(['\\x01 \\xAF \\\\xAF', "\x01 \\\x01 \x01\\\x01"])
34
+ escaped_yaml = "---\n- \"\\\\x01 \\\\xAF \\\\\\\\xAF\"\n- \"\\x01 \\\\\\x01 \\x01\\\\\\x01\"\n"
35
+ assert_equal ['\\x01 \\xAF \\\\xAF', '0x01 \\0x01 0x01\\0x01'], load_yaml(escaped_yaml)
36
+ end
37
+
32
38
  test 'should leave non-binary JSON with things that look like control chars unchanged' do
33
- hash = { 'report' => ' \x09 ' }
39
+ hash = { 'report' => ' \x01 ' }
34
40
  assert_equal hash, load_yaml(hash.to_json)
35
41
  end
36
42
 
@@ -38,26 +44,60 @@ class SerializationTest < Minitest::Test
38
44
  assert_yaml_coercion_behaviour
39
45
  end
40
46
 
41
- test 'dump_yaml should produce encoding-portable YAML' do
42
- original_object = { :basic => 'manana', :complex => 'mañana' }
47
+ test 'dump_yaml with utf8_storage = false should produce encoding-portable YAML' do
48
+ self.utf8_storage = false
49
+ original_object = { basic: 'manana', complex: 'mañana' }
43
50
  yaml_produced = dump_yaml(original_object)
44
51
  reloaded_object = load_yaml(yaml_produced)
45
52
 
46
- assert yaml_produced =~ /basic: manana/, 'binary-encoded more than was necessary'
53
+ assert_match(/basic: manana/, yaml_produced, 'binary-encoded more than was necessary')
47
54
 
48
55
  refute yaml_produced.bytes.detect { |byte| byte > 127 }, 'yaml has high-ascii'
49
56
  assert reloaded_object.inspect.bytes.detect { |byte| byte > 127 }
50
57
  assert_equal original_object, reloaded_object
51
58
  end
52
59
 
53
- test 'encoding-portable YAML should be loadable' do
54
- original_object = { :basic => 'manana', :complex => 'mañana' }
60
+ test 'encoding-portable YAML with utf8_storage = false should be loadable' do
61
+ self.utf8_storage = false
62
+ original_object = { basic: 'manana', complex: 'mañana' }
63
+ yaml_produced = dump_yaml(original_object)
64
+
65
+ assert_equal("---\n:basic: manana\n:complex: !binary |-\n bWHDsWFuYQ==\n", yaml_produced)
66
+
67
+ reloaded_object = load_yaml(yaml_produced)
68
+ assert_equal original_object, reloaded_object
69
+ end
70
+
71
+ test 'non-encoding-portable YAML with utf8_storage = true should be loadable' do
72
+ self.utf8_storage = true
73
+ original_object = { basic: 'manana', complex: 'mañana' }
55
74
  yaml_produced = dump_yaml(original_object)
75
+ assert_equal("---\n:basic: manana\n:complex: mañana\n", yaml_produced)
56
76
 
57
77
  reloaded_object = load_yaml(yaml_produced)
58
78
  assert_equal original_object, reloaded_object
59
79
  end
60
80
 
81
+ test 'yaml_safe_classes should filter which classes can be loaded' do
82
+ original_object = { basic: 'manana', complex: 'mañana' }
83
+ yaml_produced = dump_yaml(original_object)
84
+ self.yaml_safe_classes = []
85
+ assert_raises Psych::DisallowedClass, 'Load should fail without Symbol in yaml_safe_classes' do
86
+ load_yaml(yaml_produced)
87
+ end
88
+
89
+ self.yaml_safe_classes = [Symbol]
90
+ reloaded_object = load_yaml(yaml_produced)
91
+ assert_equal original_object, reloaded_object, 'Safe reload with Symbol class specified'
92
+
93
+ if Psych::VERSION.start_with?('3.')
94
+ # Not supported with Ruby >= 3.1 unless you force psych version < 4
95
+ self.yaml_safe_classes = :unsafe
96
+ reloaded_object = load_yaml(yaml_produced)
97
+ assert_equal original_object, reloaded_object, 'Unsafe reload with Symbol class'
98
+ end
99
+ end
100
+
61
101
  test 'time-like objects should serialise correctly with psych' do
62
102
  assert_timey_wimey_stuff
63
103
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ndr_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.9.6
4
+ version: 5.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - NCRS Development Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-14 00:00:00.000000000 Z
11
+ date: 2023-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord