puppet 3.2.1 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (78) hide show
  1. data/install.rb +1 -1
  2. data/lib/puppet.rb +11 -0
  3. data/lib/puppet/indirector/report/processor.rb +1 -1
  4. data/lib/puppet/indirector/report/rest.rb +7 -0
  5. data/lib/puppet/indirector/resource/rest.rb +8 -0
  6. data/lib/puppet/indirector/rest.rb +80 -52
  7. data/lib/puppet/indirector/run/rest.rb +6 -0
  8. data/lib/puppet/network/formats.rb +20 -10
  9. data/lib/puppet/network/http/handler.rb +1 -1
  10. data/lib/puppet/node.rb +1 -1
  11. data/lib/puppet/node/facts.rb +23 -4
  12. data/lib/puppet/resource.rb +2 -4
  13. data/lib/puppet/resource/status.rb +28 -0
  14. data/lib/puppet/run.rb +24 -2
  15. data/lib/puppet/status.rb +6 -2
  16. data/lib/puppet/transaction/event.rb +19 -0
  17. data/lib/puppet/transaction/report.rb +40 -0
  18. data/lib/puppet/util/log.rb +19 -0
  19. data/lib/puppet/util/metric.rb +6 -0
  20. data/lib/puppet/util/monkey_patches.rb +0 -15
  21. data/lib/puppet/vendor.rb +55 -0
  22. data/lib/puppet/vendor/load_safe_yaml.rb +1 -0
  23. data/lib/puppet/vendor/require_vendored.rb +5 -0
  24. data/lib/puppet/vendor/safe_yaml/CHANGES.md +104 -0
  25. data/lib/puppet/vendor/safe_yaml/Gemfile +11 -0
  26. data/lib/puppet/vendor/safe_yaml/LICENSE.txt +22 -0
  27. data/lib/puppet/vendor/safe_yaml/README.md +179 -0
  28. data/lib/puppet/vendor/safe_yaml/Rakefile +6 -0
  29. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml.rb +253 -0
  30. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/deep.rb +34 -0
  31. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/parse/date.rb +27 -0
  32. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/parse/hexadecimal.rb +12 -0
  33. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/parse/sexagesimal.rb +26 -0
  34. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/psych_handler.rb +92 -0
  35. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/psych_resolver.rb +52 -0
  36. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/resolver.rb +94 -0
  37. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/safe_to_ruby_visitor.rb +17 -0
  38. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/syck_hack.rb +36 -0
  39. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/syck_node_monkeypatch.rb +43 -0
  40. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/syck_resolver.rb +38 -0
  41. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/transform.rb +41 -0
  42. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/transform/to_boolean.rb +21 -0
  43. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/transform/to_date.rb +11 -0
  44. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/transform/to_float.rb +33 -0
  45. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/transform/to_integer.rb +25 -0
  46. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/transform/to_nil.rb +18 -0
  47. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/transform/to_symbol.rb +13 -0
  48. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/transform/transformation_map.rb +47 -0
  49. data/lib/puppet/vendor/safe_yaml/lib/safe_yaml/version.rb +3 -0
  50. data/lib/puppet/vendor/safe_yaml/run_specs_all_ruby_versions.sh +21 -0
  51. data/lib/puppet/vendor/safe_yaml/safe_yaml.gemspec +18 -0
  52. data/lib/puppet/vendor/safe_yaml/spec/exploit.1.9.2.yaml +2 -0
  53. data/lib/puppet/vendor/safe_yaml/spec/exploit.1.9.3.yaml +2 -0
  54. data/lib/puppet/vendor/safe_yaml/spec/psych_resolver_spec.rb +10 -0
  55. data/lib/puppet/vendor/safe_yaml/spec/resolver_specs.rb +250 -0
  56. data/lib/puppet/vendor/safe_yaml/spec/safe_yaml_spec.rb +702 -0
  57. data/lib/puppet/vendor/safe_yaml/spec/spec_helper.rb +18 -0
  58. data/lib/puppet/vendor/safe_yaml/spec/support/exploitable_back_door.rb +29 -0
  59. data/lib/puppet/vendor/safe_yaml/spec/syck_resolver_spec.rb +10 -0
  60. data/lib/puppet/vendor/safe_yaml/spec/transform/base64_spec.rb +11 -0
  61. data/lib/puppet/vendor/safe_yaml/spec/transform/to_date_spec.rb +34 -0
  62. data/lib/puppet/vendor/safe_yaml/spec/transform/to_float_spec.rb +42 -0
  63. data/lib/puppet/vendor/safe_yaml/spec/transform/to_integer_spec.rb +59 -0
  64. data/lib/puppet/vendor/safe_yaml/spec/transform/to_symbol_spec.rb +49 -0
  65. data/lib/puppet/vendor/safe_yaml_patches.rb +9 -0
  66. data/lib/puppet/version.rb +1 -1
  67. data/spec/lib/puppet_spec/matchers.rb +8 -0
  68. data/spec/unit/application/facts_spec.rb +1 -0
  69. data/spec/unit/file_serving/metadata_spec.rb +20 -28
  70. data/spec/unit/indirector/report/rest_spec.rb +41 -0
  71. data/spec/unit/indirector/rest_spec.rb +307 -334
  72. data/spec/unit/network/formats_spec.rb +36 -27
  73. data/spec/unit/network/http/handler_spec.rb +3 -12
  74. data/spec/unit/node_spec.rb +14 -0
  75. data/spec/unit/resource_spec.rb +5 -35
  76. data/spec/unit/run_spec.rb +25 -6
  77. data/spec/unit/status_spec.rb +6 -0
  78. metadata +2566 -2521
data/lib/puppet/status.rb CHANGED
@@ -14,8 +14,12 @@ class Puppet::Status
14
14
  @status.to_pson
15
15
  end
16
16
 
17
- def self.from_pson( pson )
18
- self.new( pson )
17
+ def self.from_pson(pson)
18
+ if pson.include?('status')
19
+ self.new(pson['status'])
20
+ else
21
+ self.new(pson)
22
+ end
19
23
  end
20
24
 
21
25
  def name
@@ -18,12 +18,31 @@ class Puppet::Transaction::Event
18
18
 
19
19
  EVENT_STATUSES = %w{noop success failure audit}
20
20
 
21
+ def self.from_pson(data)
22
+ obj = self.allocate
23
+ obj.initialize_from_hash(data)
24
+ obj
25
+ end
26
+
21
27
  def initialize(options = {})
22
28
  @audited = false
23
29
  set_options(options)
24
30
  @time = Time.now
25
31
  end
26
32
 
33
+ def initialize_from_hash(data)
34
+ @audited = data['audited']
35
+ @property = data['property']
36
+ @previous_value = data['previous_value']
37
+ @desired_value = data['desired_value']
38
+ @historical_value = data['historical_value']
39
+ @message = data['message']
40
+ @name = data['name'].intern
41
+ @status = data['status']
42
+ @time = data['time']
43
+ @time = Time.parse(@time) if @time.is_a? String
44
+ end
45
+
27
46
  def property=(prop)
28
47
  @property = prop.to_s
29
48
  end
@@ -102,6 +102,12 @@ class Puppet::Transaction::Report
102
102
  :yaml
103
103
  end
104
104
 
105
+ def self.from_pson(data)
106
+ obj = self.allocate
107
+ obj.initialize_from_hash(data)
108
+ obj
109
+ end
110
+
105
111
  # @api private
106
112
  def <<(msg)
107
113
  @logs << msg
@@ -174,6 +180,40 @@ class Puppet::Transaction::Report
174
180
  @status = 'failed' # assume failed until the report is finalized
175
181
  end
176
182
 
183
+ # @api private
184
+ def initialize_from_hash(data)
185
+ @puppet_version = data['puppet_version']
186
+ @report_format = data['report_format']
187
+ @configuration_version = data['configuration_version']
188
+ @environment = data['environment']
189
+ @status = data['status']
190
+ @host = data['host']
191
+ @time = data['time']
192
+ if @time.is_a? String
193
+ @time = Time.parse(@time)
194
+ end
195
+ @kind = data['kind']
196
+
197
+ @metrics = {}
198
+ data['metrics'].each do |name, hash|
199
+ @metrics[name] = Puppet::Util::Metric.from_pson(hash)
200
+ end
201
+
202
+ @logs = data['logs'].map do |record|
203
+ Puppet::Util::Log.from_pson(record)
204
+ end
205
+
206
+ @resource_statuses = {}
207
+ data['resource_statuses'].map do |record|
208
+ if record[1] == {}
209
+ status = nil
210
+ else
211
+ status = Puppet::Resource::Status.from_pson(record[1])
212
+ end
213
+ @resource_statuses[record[0]] = status
214
+ end
215
+ end
216
+
177
217
  # @return [String] the host name
178
218
  # @api public
179
219
  #
@@ -220,6 +220,12 @@ class Puppet::Util::Log
220
220
  @levels.include?(level)
221
221
  end
222
222
 
223
+ def self.from_pson(data)
224
+ obj = allocate
225
+ obj.initialize_from_hash(data)
226
+ obj
227
+ end
228
+
223
229
  attr_accessor :time, :remote, :file, :line, :source
224
230
  attr_reader :level, :message
225
231
 
@@ -242,6 +248,19 @@ class Puppet::Util::Log
242
248
  Log.newmessage(self)
243
249
  end
244
250
 
251
+ def initialize_from_hash(data)
252
+ @level = data['level'].intern
253
+ @message = data['message']
254
+ @source = data['source']
255
+ @tags = data['tags']
256
+ @time = data['time']
257
+ if @time.is_a? String
258
+ @time = Time.parse(@time)
259
+ end
260
+ @file = data['file'] if data['file']
261
+ @line = data['line'] if data['line']
262
+ end
263
+
245
264
  def message=(msg)
246
265
  raise ArgumentError, "Puppet::Util::Log requires a message" unless msg
247
266
  @message = msg.to_s
@@ -9,6 +9,12 @@ class Puppet::Util::Metric
9
9
 
10
10
  attr_writer :basedir
11
11
 
12
+ def self.from_pson(data)
13
+ metric = new(data['name'], data['label'])
14
+ metric.values = data['values']
15
+ metric
16
+ end
17
+
12
18
  # Return a specific value
13
19
  def [](name)
14
20
  if value = @values.find { |v| v[0] == name }
@@ -41,21 +41,6 @@ end
41
41
  end
42
42
  }
43
43
 
44
- if defined?(YAML::ENGINE) and YAML::ENGINE.yamler == 'psych'
45
- def Psych.safely_load(str)
46
- result = Psych.parse(str)
47
- if invalid_node = result.find { |node| node.tag =~ /!map:(.*)/ || node.tag =~ /!ruby\/hash:(.*)/ }
48
- raise ArgumentError, "Illegal YAML mapping found with tag #{invalid_node.tag}; please use !ruby/object:#{$1} instead"
49
- else
50
- result.to_ruby
51
- end
52
- end
53
- else
54
- def YAML.safely_load(str)
55
- self.load(str)
56
- end
57
- end
58
-
59
44
  def YAML.dump(*args)
60
45
  ZAML.dump(*args)
61
46
  end
@@ -0,0 +1,55 @@
1
+ module Puppet
2
+ # Simple module to manage vendored code.
3
+ #
4
+ # To vendor a library:
5
+ #
6
+ # * Download its whole git repo or untar into `lib/puppet/vendor/<libname>`
7
+ # * Create a lib/puppetload_libraryname.rb file to add its libdir into the $:.
8
+ # (Look at existing load_xxx files, they should all follow the same pattern).
9
+ # * To load the vendored lib upfront, add a `require '<vendorlib>'`line to
10
+ # `vendor/require_vendored.rb`.
11
+ # * To load the vendored lib on demand, add a comment to `vendor/require_vendored.rb`
12
+ # to make it clear it should not be loaded upfront.
13
+ #
14
+ # At runtime, the #load_vendored method should be called. It will ensure
15
+ # all vendored libraries are added to the global `$:` path, and
16
+ # will then call execute the up-front loading specified in `vendor/require_vendored.rb`.
17
+ #
18
+ # The intention is to not change vendored libraries and to eventually
19
+ # make adding them in optional so that distros can simply adjust their
20
+ # packaging to exclude this directory and the various load_xxx.rb scripts
21
+ # if they wish to install these gems as native packages.
22
+ #
23
+ class Vendor
24
+ class << self
25
+ # @api private
26
+ def vendor_dir
27
+ File.join([File.dirname(File.expand_path(__FILE__)), "vendor"])
28
+ end
29
+
30
+ # @api private
31
+ def load_entry(entry)
32
+ Puppet.debug("Loading vendored #{$1}")
33
+ load "#{vendor_dir}/#{entry}"
34
+ end
35
+
36
+ # @api private
37
+ def require_libs
38
+ require 'puppet/vendor/require_vendored'
39
+ end
40
+
41
+ # Configures the path for all vendored libraries and loads required libraries.
42
+ # (This is the entry point for loading vendored libraries).
43
+ #
44
+ def load_vendored
45
+ Dir.entries(vendor_dir).each do |entry|
46
+ if entry.match(/load_(\w+?)\.rb$/)
47
+ load_entry entry
48
+ end
49
+ end
50
+
51
+ require_libs
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1 @@
1
+ $: << File.join([File.dirname(__FILE__), "safe_yaml/lib"])
@@ -0,0 +1,5 @@
1
+ # This adds upfront requirements on vendored code found under lib/vendor/x
2
+ # Add one requirement per vendored package (or a comment if it is loaded on demand).
3
+
4
+ require 'safe_yaml'
5
+ require 'puppet/vendor/safe_yaml_patches'
@@ -0,0 +1,104 @@
1
+ 0.9.2
2
+ -----
3
+
4
+ - fixed error w/ parsing "!" when whitelisting tags
5
+ - fixed parsing of the number 0 (d'oh!)
6
+
7
+ 0.9.1
8
+ -----
9
+
10
+ - added Yecht support (JRuby)
11
+ - more bug fixes
12
+
13
+ 0.9.0
14
+ -----
15
+
16
+ - added `whitelist!` method for easily whitelisting tags
17
+ - added support for call-specific options
18
+ - removed deprecated methods
19
+
20
+ 0.8.6
21
+ -----
22
+
23
+ - fixed bug in float matcher
24
+
25
+ 0.8.5
26
+ -----
27
+
28
+ - performance improvements
29
+ - made less verbose by default
30
+ - bug fixes
31
+
32
+ 0.8.4
33
+ -----
34
+
35
+ - enhancements to parsing of integers, floats, and dates
36
+ - updated built-in whitelist
37
+ - more bug fixes
38
+
39
+ 0.8.3
40
+ -----
41
+
42
+ - fixed exception on parsing empty document
43
+ - fixed handling of octal & hexadecimal numbers
44
+
45
+ 0.8.2
46
+ -----
47
+
48
+ - bug fixes
49
+
50
+ 0.8.1
51
+ -----
52
+
53
+ - added `:raise_on_unknown_tag` option
54
+ - renamed `reset_defaults!` to `restore_defaults!`
55
+
56
+ 0.8
57
+ ---
58
+
59
+ - added tag whitelisting
60
+ - more API changes
61
+
62
+ 0.7
63
+ ---
64
+
65
+ - separated YAML engine support from Ruby version
66
+ - added support for binary scalars
67
+ - numerous bug fixes and enhancements
68
+
69
+ 0.6
70
+ ---
71
+
72
+ - several API changes
73
+ - added `SafeYAML::OPTIONS` for specifying default behavior
74
+
75
+ 0.5
76
+ ---
77
+
78
+ Added support for dates
79
+
80
+ 0.4
81
+ ---
82
+
83
+ - efficiency improvements
84
+ - made `YAML.load` use `YAML.safe_load` by default
85
+ - made symbol deserialization optional
86
+
87
+ 0.3
88
+ ---
89
+
90
+ Added Syck support
91
+
92
+ 0.2
93
+ ---
94
+
95
+ Added support for:
96
+
97
+ - anchors & aliases
98
+ - booleans
99
+ - nils
100
+
101
+ 0.1
102
+ ---
103
+
104
+ Initial release
@@ -0,0 +1,11 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem "hashie"
7
+ gem "heredoc_unindent"
8
+ gem "rake"
9
+ gem "rspec"
10
+ gem "travis-lint"
11
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Dan Tao
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,179 @@
1
+ SafeYAML
2
+ ========
3
+
4
+ [![Build Status](https://travis-ci.org/dtao/safe_yaml.png)](http://travis-ci.org/dtao/safe_yaml)
5
+
6
+ The **SafeYAML** gem provides an alternative implementation of `YAML.load` suitable for accepting user input in Ruby applications. Unlike Ruby's built-in implementation of `YAML.load`, SafeYAML's version will not expose apps to arbitrary code execution exploits (such as [the ones discovered](http://www.reddit.com/r/netsec/comments/167c11/serious_vulnerability_in_ruby_on_rails_allowing/) [in Rails in early 2013](http://www.h-online.com/open/news/item/Rails-developers-close-another-extremely-critical-flaw-1793511.html)).
7
+
8
+ **If you encounter any issues with SafeYAML, check out the 'Common Issues' section below.** If you don't see anything that addresses the problem you're experiencing, by all means, [create an issue](https://github.com/dtao/safe_yaml/issues/new)!
9
+
10
+ Installation
11
+ ------------
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem "safe_yaml"
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install safe_yaml
24
+
25
+ Configuration
26
+ -------------
27
+
28
+ Configuring SafeYAML should be quick. In most cases, you will probably only have to think about two things:
29
+
30
+ 1. What do you want the `YAML` module's *default* behavior to be? Set the `SafeYAML::OPTIONS[:default_mode]` option to either `:safe` or `:unsafe` to control this. If you do neither, SafeYAML will default to `:safe` mode but will issue a warning the first time you call `YAML.load`.
31
+ 2. Do you want to allow symbols by default? Set the `SafeYAML::OPTIONS[:deserialize_symbols]` option to `true` or `false` to control this. The default is `false`, which means that SafeYAML will deserialize symbols in YAML documents as strings.
32
+
33
+ For more information on these and other options, see the "Usage" section down below.
34
+
35
+ Explanation
36
+ -----------
37
+
38
+ Suppose your application were to use a popular open source library which contained code like this:
39
+
40
+ ```ruby
41
+ class ClassBuilder
42
+ def []=(key, value)
43
+ @class ||= Class.new
44
+
45
+ @class.class_eval <<-EOS
46
+ def #{key}
47
+ #{value}
48
+ end
49
+ EOS
50
+ end
51
+
52
+ def create
53
+ @class.new
54
+ end
55
+ end
56
+ ```
57
+
58
+ Now, if you were to use `YAML.load` on user input anywhere in your application without the SafeYAML gem installed, an attacker who suspected you were using this library could send a request with a carefully-crafted YAML string to execute arbitrary code (yes, including `system("unix command")`) on your servers.
59
+
60
+ This simple example demonstrates the vulnerability:
61
+
62
+ ```ruby
63
+ yaml = <<-EOYAML
64
+ --- !ruby/hash:ClassBuilder
65
+ "foo; end; puts %(I'm in yr system!); def bar": "baz"
66
+ EOYAML
67
+ ```
68
+
69
+ > YAML.load(yaml)
70
+ I'm in yr system!
71
+ => #<ClassBuilder:0x007fdbbe2e25d8 @class=#<Class:0x007fdbbe2e2510>>
72
+
73
+ With SafeYAML, the same attacker would be thwarted:
74
+
75
+ > require "safe_yaml"
76
+ => true
77
+ > YAML.load(yaml, :safe => true)
78
+ => {"foo; end; puts %(I'm in yr system!); def bar"=>"baz"}
79
+
80
+ Usage
81
+ -----
82
+
83
+ When you require the safe_yaml gem in your project, `YAML.load` is patched to accept one additional (optional) `options` parameter. This changes the method signature as follows:
84
+
85
+ - for Syck and Psych prior to Ruby 1.9.3: `YAML.load(yaml, options={})`
86
+ - for Psych in 1.9.3 and later: `YAML.load(yaml, filename=nil, options={})`
87
+
88
+ The most important option is the `:safe` option (default: `true`), which controls whether or not to deserialize arbitrary objects when parsing a YAML document. The other options, along with explanations, are as follows.
89
+
90
+ - `:deserialize_symbols` (default: `false`): Controls whether or not YAML will deserialize symbols. It is probably best to only enable this option where necessary, e.g. to make trusted libraries work. Symbols receive special treatment in Ruby and are not garbage collected, which means deserializing them indiscriminately may render your site vulnerable to a DOS attack (hence `false` as a default value).
91
+
92
+ - `:whitelisted_tags`: Accepts an array of YAML tags that designate trusted types, e.g., ones that can be deserialized without worrying about any resulting security vulnerabilities. When any of the given tags are encountered in a YAML document, the associated data will be parsed by the underlying YAML engine (Syck or Psych) for the version of Ruby you are using. See the "Whitelisting Trusted Types" section below for more information.
93
+
94
+ - `:custom_initializers`: Similar to the `:whitelisted_tags` option, but allows you to provide your own initializers for specified tags rather than using Syck or Psyck. Accepts a hash with string tags for keys and lambdas for values.
95
+
96
+ - `:raise_on_unknown_tag` (default: `false`): Represents the highest possible level of paranoia (not necessarily a bad thing); if the YAML engine encounters any tag other than ones that are automatically trusted by SafeYAML or that you've explicitly whitelisted, it will raise an exception. This may be a good choice if you expect to always be dealing with perfectly safe YAML and want your application to fail loudly upon encountering questionable data.
97
+
98
+ All of the above options can be set at the global level via `SafeYAML::OPTIONS`. You can also set each one individually per call to `YAML.load`; an option explicitly passed to `load` will take precedence over an option specified globally.
99
+
100
+ Supported Types
101
+ ---------------
102
+
103
+ The way that SafeYAML works is by restricting the kinds of objects that can be deserialized via `YAML.load`. More specifically, only the following types of objects can be deserialized by default:
104
+
105
+ - Hashes
106
+ - Arrays
107
+ - Strings
108
+ - Numbers
109
+ - Dates
110
+ - Times
111
+ - Booleans
112
+ - Nils
113
+
114
+ Again, deserialization of symbols can be enabled globally by setting `SafeYAML::OPTIONS[:deserialize_symbols] = true`, or in a specific call to `YAML.load([some yaml], :deserialize_symbols => true)`.
115
+
116
+ Whitelisting Trusted Types
117
+ --------------------------
118
+
119
+ SafeYAML supports whitelisting certain YAML tags for trusted types. This is handy when your application uses YAML to serialize and deserialize certain types not listed above, which you know to be free of any deserialization-related vulnerabilities.
120
+
121
+ The easiest way to whitelist types is by calling `SafeYAML.whitelist!`, which can accept a variable number of safe types, e.g.:
122
+
123
+ ```ruby
124
+ SafeYAML.whitelist!(FrobDispenser, GobbleFactory)
125
+ ```
126
+
127
+ You can also whitelist YAML *tags* via the `:whitelisted_tags` option:
128
+
129
+ ```ruby
130
+ # Using Syck
131
+ SafeYAML::OPTIONS[:whitelisted_tags] = ["tag:ruby.yaml.org,2002:object:OpenStruct"]
132
+
133
+ # Using Psych
134
+ SafeYAML::OPTIONS[:whitelisted_tags] = ["!ruby/object:OpenStruct"]
135
+ ```
136
+
137
+ And in case you were wondering: no, this feature will *not* allow would-be attackers to embed untrusted types within trusted types:
138
+
139
+ ```ruby
140
+ yaml = <<-EOYAML
141
+ --- !ruby/object:OpenStruct
142
+ table:
143
+ :backdoor: !ruby/hash:ClassBuilder
144
+ "foo; end; puts %(I'm in yr system!); def bar": "baz"
145
+ EOYAML
146
+ ```
147
+
148
+ > YAML.safe_load(yaml)
149
+ => #<OpenStruct :backdoor={"foo; end; puts %(I'm in yr system!); def bar"=>"baz"}>
150
+
151
+ Known Issues
152
+ ------------
153
+
154
+ If you add SafeYAML to your project and start seeing any errors about missing keys, or you notice mysterious strings that look like `":foo"` (i.e., start with a colon), it's likely you're seeing errors from symbols being saved in YAML format. If you are able to modify the offending code, you might want to consider changing your YAML content to use plain vanilla strings instead of symbols. If not, you may need to set the `:deserialize_symbols` option to `true`, either in calls to `YAML.load` or--as a last resort--globally, with `SafeYAML::OPTIONS[:deserialize_symbols]`.
155
+
156
+ Also be aware that some Ruby libraries, particularly those requiring inter-process communication, leverage YAML's object deserialization functionality and therefore may break or otherwise be impacted by SafeYAML. The following list includes known instances of SafeYAML's interaction with other Ruby gems:
157
+
158
+ - [**ActiveRecord**](https://github.com/rails/rails/tree/master/activerecord): uses YAML to control serialization of model objects using the `serialize` class method. If you find that accessing serialized properties on your ActiveRecord models is causing errors, chances are you may need to:
159
+ 1. set the `:deserialize_symbols` option to `true`,
160
+ 2. whitelist some of the types in your serialized data via `SafeYAML.whitelist!` or the `:whitelisted_tags` option, or
161
+ 3. both
162
+ - [**Guard**](https://github.com/guard/guard): Uses YAML as a serialization format for notifications. The data serialized uses symbolic keys, so setting `SafeYAML::OPTIONS[:deserialize_symbols] = true` is necessary to allow Guard to work.
163
+ - [**sidekiq**](https://github.com/mperham/sidekiq): Uses a YAML configiuration file with symbolic keys, so setting `SafeYAML::OPTIONS[:deserialize_symbols] = true` should allow it to work.
164
+
165
+ The above list will grow over time, as more issues are discovered.
166
+
167
+ Caveat
168
+ ------
169
+
170
+ My intention is to eventually adopt [semantic versioning](http://semver.org/) with this gem, if it ever gets to version 1.0 (i.e., doesn't become obsolete by then). Since it isn't there yet, that means that API may well change from one version to the next. Please keep that in mind if you are using it in your application.
171
+
172
+ To be clear: my *goal* is for SafeYAML to make it as easy as possible to protect existing applications from object deserialization exploits. Any and all feedback is more than welcome!
173
+
174
+ Requirements
175
+ ------------
176
+
177
+ SafeYAML requires Ruby 1.8.7 or newer and works with both [Syck](http://www.ruby-doc.org/stdlib-1.8.7/libdoc/yaml/rdoc/YAML.html) and [Psych](http://github.com/tenderlove/psych).
178
+
179
+ If you are using a version of Ruby where Psych is the default YAML engine (e.g., 1.9.3) but you want to use Syck, be sure to set `YAML::ENGINE.yamler = "syck"` **before** requiring the safe_yaml gem.