summaryrefslogtreecommitdiff
path: root/spec/unit/compliance/runner_spec.rb
blob: d46d756b0effb9f4818212263e5aeb5710c91518 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
require "spec_helper"

describe Chef::Compliance::Runner do
  let(:logger) { double(:logger).as_null_object }
  let(:node) { Chef::Node.new(logger: logger) }

  let(:runner) do
    described_class.new.tap do |r|
      r.node = node
      r.run_id = "my_run_id"
    end
  end

  describe "#enabled?" do

    it "is true if the node attributes have audit profiles and the audit cookbook is not present" do
      node.normal["audit"]["profiles"]["ssh"] = { 'compliance': "base/ssh" }

      expect(runner).to be_enabled
    end

    it "is false if the node attributes have audit profiles and the audit cookbook is not present, and the compliance mode attribute is unset" do
      node.normal["audit"]["profiles"]["ssh"] = { 'compliance': "base/ssh" }
      node.normal["audit"]["compliance_mode"] = false

      expect(runner).to be_enabled
    end

    it "is false if the node attributes have audit profiles and the audit cookbook is present" do
      stub_const("::Reporter::ChefAutomate", true)
      node.normal["audit"]["profiles"]["ssh"] = { 'compliance': "base/ssh" }

      expect(runner).not_to be_enabled
    end

    it "is false if the node attributes do not have audit profiles and the audit cookbook is not present" do
      node.normal["audit"]["profiles"] = {}

      expect(runner).not_to be_enabled
    end

    it "is false if the node attributes do not have audit profiles and the audit cookbook is present" do
      stub_const("::Reporter::ChefAutomate", true)
      node.automatic["recipes"] = %w{ audit::default fancy_cookbook::fanciness tacobell::nachos }

      expect(runner).not_to be_enabled
    end

    it "is false if the node attributes do not have audit attributes and the audit cookbook is not present" do
      node.automatic["recipes"] = %w{ fancy_cookbook::fanciness tacobell::nachos }
      expect(runner).not_to be_enabled
    end
  end

  describe "#inspec_profiles" do
    it "returns an empty list with no profiles defined" do
      expect(runner.inspec_profiles).to eq([])
    end

    it "converts from the attribute format to the format Inspec expects" do
      node.normal["audit"]["profiles"]["linux-baseline"] = {
        'compliance': "user/linux-baseline",
        'version': "2.1.0",
      }

      node.normal["audit"]["profiles"]["ssh"] = {
        'supermarket': "hardening/ssh-hardening",
      }

      expected = [
        {
          compliance: "user/linux-baseline",
          name: "linux-baseline",
          version: "2.1.0",
        },
        {
          name: "ssh",
          supermarket: "hardening/ssh-hardening",
        },
      ]

      expect(runner.inspec_profiles).to eq(expected)
    end

    it "raises an error when the profiles are in the old audit-cookbook format" do
      node.normal["audit"]["profiles"] = [
        {
          name: "Windows 2019 Baseline",
          compliance: "admin/windows-2019-baseline",
        },
      ]

      expect { runner.inspec_profiles }.to raise_error(/profiles specified in an unrecognized format, expected a hash of hashes./)
    end
  end

  describe "#warn_for_deprecated_config_values!" do
    it "logs a warning when deprecated config values are present" do
      node.normal["audit"]["owner"] = "my_org"
      node.normal["audit"]["inspec_version"] = "90210"

      expect(logger).to receive(:warn).with(/config values 'inspec_version', 'owner' are not supported/)

      runner.warn_for_deprecated_config_values!
    end

    it "does not log a warning with no deprecated config values" do
      node.normal["audit"]["profiles"]["linux-baseline"] = {
        'compliance': "user/linux-baseline",
        'version': "2.1.0",
      }

      expect(logger).not_to receive(:warn)

      runner.warn_for_deprecated_config_values!
    end
  end

  describe "#reporter" do
    context "chef-server-automate reporter" do
      it "uses the correct URL when 'server' attribute is set" do
        Chef::Config[:chef_server_url] = "https://chef_config_url.example.com/my_org"
        node.normal["audit"]["server"] = "https://server_attribute_url.example.com/application/sub_application"

        reporter = runner.reporter("chef-server-automate")

        expect(reporter).to be_kind_of(Chef::Compliance::Reporter::ChefServerAutomate)
        expect(reporter.url).to eq(URI("https://server_attribute_url.example.com/application/sub_application/organizations/my_org/data-collector"))
      end

      it "falls back to chef_server_url for URL when 'server' attribute is not set" do
        Chef::Config[:chef_server_url] = "https://chef_config_url.example.com/my_org"

        reporter = runner.reporter("chef-server-automate")

        expect(reporter).to be_kind_of(Chef::Compliance::Reporter::ChefServerAutomate)
        expect(reporter.url).to eq(URI("https://chef_config_url.example.com/organizations/my_org/data-collector"))
      end
    end

    it "fails with unexpected reporter value" do
      expect { runner.reporter("tacos") }.to raise_error(/'tacos' is not a supported reporter for Compliance Phase/)
    end
  end

  describe "#inspec_opts" do
    it "does not include chef_node in inputs by default" do
      node.normal["audit"]["attributes"] = {
        "tacos" => "lunch",
        "nachos" => "dinner",
      }

      inputs = runner.inspec_opts[:inputs]

      expect(inputs["tacos"]).to eq("lunch")
      expect(inputs.key?("chef_node")).to eq(false)
    end

    it "includes chef_node in inputs with chef_node_attribute_enabled set" do
      node.normal["audit"]["chef_node_attribute_enabled"] = true
      node.normal["audit"]["attributes"] = {
        "tacos" => "lunch",
        "nachos" => "dinner",
      }

      inputs = runner.inspec_opts[:inputs]

      expect(inputs["tacos"]).to eq("lunch")
      expect(inputs["chef_node"]["audit"]["reporter"]).to eq("json-file")
      expect(inputs["chef_node"]["chef_environment"]).to eq("_default")
    end
  end
end