ndr_support 5.9.6 → 5.10.0

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: 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