Skip to content

Commit

Permalink
Whitelist serialized symbols when parsing YAML
Browse files Browse the repository at this point in the history
RuboCop config can now contain serialized symbols in its YAML.

Closes houndci#1370
  • Loading branch information
Greg Lazarev committed Jun 2, 2017
1 parent 38f93fe commit 4384e3b
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 103 deletions.
2 changes: 1 addition & 1 deletion app/models/config/parser.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Config
class Parser
def self.yaml(content)
YAML.safe_load(content, [Regexp])
YAML.safe_load(content, [Regexp, Symbol])
end

def self.json(content)
Expand Down
216 changes: 114 additions & 102 deletions spec/models/config/ruby_spec.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
require "app/models/config/base"
require "app/models/config/ruby"
require "app/models/hound_config"
require "app/models/config/parser"
require "app/models/config/parser_error"
require "app/models/config_content"
require "app/models/missing_owner"
require "rails_helper"

describe Config::Ruby do
describe "#content" do
it "dumps the config content to yaml" do
raw_config = <<~EOS
Style/Encoding:
Enabled: true
EOS
config = build_config(raw_config)

expect(config.content.to_yaml).to eq <<~YML
---
Style/Encoding:
Enabled: true
YML
end

context "when the hound config is a legacy config" do
it "returns the HoundConfig's content as a hash" do
hound_config = instance_double(
Expand Down Expand Up @@ -43,124 +51,128 @@
end
end

it "dumps the config content to yaml" do
raw_config = <<~EOS
Style/Encoding:
Enabled: true
EOS
config = build_config(raw_config)

expect(config.content.to_yaml).to eq <<~YML
---
Style/Encoding:
Enabled: true
YML
end
end

context "when the configuration uses `inherit_from`" do
it "returns the merged configuration using `inherit_from`" do
repo_config = <<~EOS
inherit_from:
- config/base.yml
- config/overrides.yml
Style/StringLiterals:
EnforcedStyle: single_quotes
EOS
base = <<~EOS
LineLength:
Max: 40
EOS
overrides = <<~EOS
Style/HashSyntax:
EnforcedStyle: hash_rockets
EOS
commit = stub_commit(
"config/rubocop.yml" => repo_config,
"config/base.yml" => base,
"config/overrides.yml" => overrides,
)
owner_config = {
"Style/StringLiterals" => {
"EnforcedStyle" => "double_quotes",
},
"Style/HashSyntax" => {
"EnforcedStyle" => "ruby19",
},
}
owner = instance_double("Owner", config_content: owner_config)
hound_config = build_hound_config(commit, "config/rubocop.yml")
config = Config::Ruby.new(hound_config, owner: owner)

expect(config.content).to eq(
"LineLength" => { "Max" => 40 },
"Style/HashSyntax" => { "EnforcedStyle" => "hash_rockets" },
"Style/StringLiterals" => { "EnforcedStyle" => "single_quotes" },
)
end

context "with an empty `inherit_from`" do
context "when the configuration uses `inherit_from`" do
it "returns the merged configuration using `inherit_from`" do
rubocop = <<~EOS
inherit_from: config/rubocop_todo.yml
Style/Encoding:
Enabled: true
repo_config = <<~EOS
inherit_from:
- config/base.yml
- config/overrides.yml
Style/StringLiterals:
EnforcedStyle: single_quotes
EOS
base = <<~EOS
LineLength:
Max: 40
EOS
overrides = <<~EOS
Style/HashSyntax:
EnforcedStyle: hash_rockets
EOS
rubocop_todo = "# this is an empty file"
commit = stub_commit(
"config/rubocop.yml" => rubocop,
"config/rubocop_todo.yml" => rubocop_todo,
"config/rubocop.yml" => repo_config,
"config/base.yml" => base,
"config/overrides.yml" => overrides,
)
owner_config = {
"Style/StringLiterals" => {
"EnforcedStyle" => "double_quotes",
},
"Style/HashSyntax" => {
"EnforcedStyle" => "ruby19",
},
}
owner = instance_double("Owner", config_content: owner_config)
hound_config = build_hound_config(commit, "config/rubocop.yml")
config = described_class.new(hound_config)
config = Config::Ruby.new(hound_config, owner: owner)

expect(config.content).to eq(
"Style/Encoding" => { "Enabled" => true },
"LineLength" => { "Max" => 40 },
"Style/HashSyntax" => { "EnforcedStyle" => "hash_rockets" },
"Style/StringLiterals" => { "EnforcedStyle" => "single_quotes" },
)
end
end

context "with invalid `inherit_from` content" do
it "raises a parser error" do
rubocop = "inherit_from: config/rubocop_todo.yml"
rubocop_todo = "foo: bar: "
commit = stub_commit(
"config/rubocop.yml" => rubocop,
"config/rubocop_todo.yml" => rubocop_todo,
)
hound_config = build_hound_config(commit, "config/rubocop.yml")
config = described_class.new(hound_config)
context "with an empty `inherit_from`" do
it "returns the merged configuration using `inherit_from`" do
rubocop = <<~EOS
inherit_from: config/rubocop_todo.yml
Style/Encoding:
Enabled: true
EOS
rubocop_todo = "# this is an empty file"
commit = stub_commit(
"config/rubocop.yml" => rubocop,
"config/rubocop_todo.yml" => rubocop_todo,
)
hound_config = build_hound_config(commit, "config/rubocop.yml")
config = described_class.new(hound_config)

expect { config.content }.to raise_error(Config::ParserError)
expect(config.content).to eq(
"Style/Encoding" => { "Enabled" => true },
)
end
end
end
end

context "when the given content is invalid" do
context "when the result is not a hash" do
it "raises a type exception" do
config = build_config("[]")
context "with invalid `inherit_from` content" do
it "raises a parser error" do
rubocop = "inherit_from: config/rubocop_todo.yml"
rubocop_todo = "foo: bar: "
commit = stub_commit(
"config/rubocop.yml" => rubocop,
"config/rubocop_todo.yml" => rubocop_todo,
)
hound_config = build_hound_config(commit, "config/rubocop.yml")
config = described_class.new(hound_config)

expect { config.content }.to raise_error(
Config::ParserError,
%r("config/.+\..+" must be a Hash),
)
expect { config.content }.to raise_error(Config::ParserError)
end
end
end

context "when the content is invalid yaml" do
it "raises an exception" do
context "with serialized symbols in yaml" do
it "returns the config" do
raw_config = <<~EOS
ruby: !ruby/object
;foo:
Style/InverseMethods:
Enabled: true
:any?: :none?
EOS
config = build_config(raw_config)

expect { config.content }.to raise_error(
Config::ParserError,
/Tried to load unspecified class: Object/,
expect(config.content).to eq(
"Style/InverseMethods" => {
"Enabled" => true,
any?: :none?,
},
)
end
end

context "when the given content is invalid" do
context "when the result is not a hash" do
it "raises a type exception" do
config = build_config("[]")

expect { config.content }.to raise_error(
Config::ParserError,
%r("config/.+\..+" must be a Hash),
)
end
end

context "when the content is invalid yaml" do
it "raises an exception" do
raw_config = <<~EOS
ruby: !ruby/object
;foo:
EOS
config = build_config(raw_config)

expect { config.content }.to raise_error(
Config::ParserError,
/Tried to load unspecified class: Object/,
)
end
end
end
end
end

0 comments on commit 4384e3b

Please sign in to comment.