summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/chef/node/attribute.rb8
-rw-r--r--spec/unit/node_spec.rb33
2 files changed, 37 insertions, 4 deletions
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index 46683d9405..05b625dd02 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -403,11 +403,11 @@ class Chef
end
def combined_override(*path)
- immutablize(merge_overrides(path))
+ merge_overrides(path)
end
def combined_default(*path)
- immutablize(merge_defaults(path))
+ merge_defaults(path)
end
def normal_unless(*args)
@@ -599,9 +599,9 @@ class Chef
# In all other cases, replace merge_onto with merge_with
else
if merge_with.kind_of?(Hash)
- Chef::Node::VividMash.new(merge_with)
+ Chef::Node::ImmutableMash.new(merge_with)
elsif merge_with.kind_of?(Array)
- Chef::Node::AttrArray.new(merge_with)
+ Chef::Node::ImmutableArray.new(merge_with)
else
merge_with
end
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb
index 0ca5f83adc..ff912ee7a6 100644
--- a/spec/unit/node_spec.rb
+++ b/spec/unit/node_spec.rb
@@ -1818,4 +1818,37 @@ describe Chef::Node do
expect(node["a"]["key"]).to eql(1)
end
end
+
+ describe "when abusing the deep merge cache" do
+ # https://github.com/chef/chef/issues/7738
+ it "do not corrupt VividMashes that are part of the merge set and not the merge_onto set" do
+ # need to have a merge two-deep (not at the top-level) between at least two default (or two override)
+ # levels where the lowest priority one is the one that is going to be corrupted
+ node.default["foo"]["bar"]["baz"] = "fizz"
+ node.env_default["foo"]["bar"]["quux"] = "buzz"
+ node.default["foo"]["bar"].tap do |bar|
+ bar["test"] = "wrong"
+ # this triggers a deep merge
+ node["foo"]["bar"]["test"]
+ # this should correctly write and dirty the cache so the next read does another deep merge on the correct __root__
+ bar["test"] = "right"
+ end
+ expect(node["foo"]["bar"]["test"]).to eql("right")
+ end
+
+ it "do not corrupt VividMashes that are part of the merge set and not the merge_onto set (when priorities are reversed)" do
+ # need to have a merge two-deep (not at the top-level) between at least two default (or two override)
+ # levels where the *HIGHEST* priority one is the one that is going to be corrupted
+ node.env_default["foo"]["bar"]["baz"] = "fizz"
+ node.default["foo"]["bar"]["quux"] = "buzz"
+ node.env_default["foo"]["bar"].tap do |bar|
+ bar["test"] = "wrong"
+ # this triggers a deep merge
+ node["foo"]["bar"]["test"]
+ # this should correctly write and dirty the cache so the next read does another deep merge on the correct __root__
+ bar["test"] = "right"
+ end
+ expect(node["foo"]["bar"]["test"]).to eql("right")
+ end
+ end
end