inspec 0.16.3 → 0.16.4
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 +4 -4
- data/CHANGELOG.md +26 -2
- data/docs/dsl_inspec.rst +43 -0
- data/examples/inheritance/controls/example.rb +1 -1
- data/examples/inheritance/inspec.yml +1 -1
- data/examples/profile/README.md +26 -8
- data/examples/profile/controls/gordon.rb +4 -2
- data/examples/profile/controls/meta.rb +34 -0
- data/examples/profile/inspec.yml +1 -1
- data/examples/profile/libraries/gordon_config.rb +28 -2
- data/lib/bundles/inspec-compliance/cli.rb +3 -1
- data/lib/inspec/backend.rb +5 -0
- data/lib/inspec/cli.rb +2 -0
- data/lib/inspec/profile_context.rb +2 -0
- data/lib/inspec/runner.rb +1 -1
- data/lib/inspec/shell.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/test/functional/helper.rb +36 -0
- data/test/functional/inheritance_test.rb +49 -0
- data/test/functional/inspec_archive_test.rb +80 -0
- data/test/functional/inspec_exec_test.rb +141 -0
- data/test/functional/inspec_json_test.rb +104 -0
- data/test/functional/inspec_test.rb +54 -0
- data/test/unit/profile_context_test.rb +3 -3
- metadata +15 -7
- data/examples/resource/controls/tiny.rb +0 -3
- data/examples/resource/inspec.yml +0 -10
- data/examples/resource/libraries/tiny.rb +0 -3
- data/test/functional/command_test.rb +0 -390
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
require 'functional/helper'
|
6
|
+
|
7
|
+
describe 'inspec archive' do
|
8
|
+
include FunctionalHelper
|
9
|
+
|
10
|
+
it 'archive is successful' do
|
11
|
+
out = inspec('archive ' + example_profile + ' --overwrite')
|
12
|
+
out.exit_status.must_equal 0
|
13
|
+
out.stdout.must_match /Generate archive [^ ]*profile.tar.gz/
|
14
|
+
out.stdout.must_include 'Finished archive generation.'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'archives to output file' do
|
18
|
+
out = inspec('archive ' + example_profile + ' --output ' + dst.path)
|
19
|
+
out.stderr.must_equal ''
|
20
|
+
out.stdout.must_include 'Generate archive '+dst.path
|
21
|
+
out.stdout.must_include 'Finished archive generation.'
|
22
|
+
out.exit_status.must_equal 0
|
23
|
+
File.exist?(dst.path).must_equal true
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'auto-archives when no --output is given' do
|
27
|
+
auto_dst = File.join(repo_path, 'profile.tar.gz')
|
28
|
+
out = inspec('archive ' + example_profile + ' --overwrite')
|
29
|
+
out.stderr.must_equal ''
|
30
|
+
out.stdout.must_include 'Generate archive '+auto_dst
|
31
|
+
out.stdout.must_include 'Finished archive generation.'
|
32
|
+
out.exit_status.must_equal 0
|
33
|
+
File.exist?(auto_dst).must_equal true
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'archive on invalid archive' do
|
37
|
+
out = inspec('archive /proc --output ' + dst.path)
|
38
|
+
# out.stdout.must_equal '' => we have partial stdout output right now
|
39
|
+
out.stderr.must_include "Don't understand inspec profile in \"/proc\""
|
40
|
+
out.exit_status.must_equal 1
|
41
|
+
File.exist?(dst.path).must_equal false
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'archive wont overwrite existing files' do
|
45
|
+
x = rand.to_s
|
46
|
+
File.write(dst.path, x)
|
47
|
+
out = inspec('archive ' + example_profile + ' --output ' + dst.path)
|
48
|
+
out.stderr.must_equal '' # uh...
|
49
|
+
out.stdout.must_include "Archive #{dst.path} exists already. Use --overwrite."
|
50
|
+
out.exit_status.must_equal 1
|
51
|
+
File.read(dst.path).must_equal x
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'archive will overwrite files if necessary' do
|
55
|
+
x = rand.to_s
|
56
|
+
File.write(dst.path, x)
|
57
|
+
out = inspec('archive ' + example_profile + ' --output ' + dst.path + ' --overwrite')
|
58
|
+
out.stderr.must_equal ''
|
59
|
+
out.stdout.must_include 'Generate archive '+dst.path
|
60
|
+
out.exit_status.must_equal 0
|
61
|
+
File.read(dst.path).wont_equal x
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'creates valid tar.gz archives' do
|
65
|
+
out = inspec('archive ' + example_profile + ' --output ' + dst.path + ' --tar')
|
66
|
+
out.stderr.must_equal ''
|
67
|
+
out.stdout.must_include 'Generate archive '+dst.path
|
68
|
+
out.exit_status.must_equal 0
|
69
|
+
t = Zlib::GzipReader.open(dst.path)
|
70
|
+
Gem::Package::TarReader.new(t).entries.map(&:header).map(&:name).must_include 'inspec.yml'
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'creates valid zip archives' do
|
74
|
+
out = inspec('archive ' + example_profile + ' --output ' + dst.path + ' --zip')
|
75
|
+
out.stderr.must_equal ''
|
76
|
+
out.stdout.must_include 'Generate archive '+dst.path
|
77
|
+
out.exit_status.must_equal 0
|
78
|
+
Zip::File.new(dst.path).entries.map(&:name).must_include 'inspec.yml'
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
require 'functional/helper'
|
6
|
+
|
7
|
+
describe 'inspec exec' do
|
8
|
+
include FunctionalHelper
|
9
|
+
|
10
|
+
it 'can execute the profile' do
|
11
|
+
out = inspec('exec ' + example_profile)
|
12
|
+
out.stderr.must_equal ''
|
13
|
+
out.exit_status.must_equal 0
|
14
|
+
out.stdout.must_match /^Pending: /
|
15
|
+
out.stdout.must_include '4 examples, 0 failures, 1 pending'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'executes only specified controls' do
|
19
|
+
out = inspec('exec ' + example_profile + ' --controls tmp-1.0')
|
20
|
+
out.stderr.must_equal ''
|
21
|
+
out.exit_status.must_equal 0
|
22
|
+
out.stdout.must_include '1 example, 0 failures'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can execute the profile with the json formatter' do
|
26
|
+
out = inspec('exec ' + example_profile + ' --format json')
|
27
|
+
out.stderr.must_equal ''
|
28
|
+
out.exit_status.must_equal 0
|
29
|
+
JSON.load(out.stdout).must_be_kind_of Hash
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'execute a profile with json formatting' do
|
33
|
+
let(:json) { JSON.load(inspec('exec ' + example_profile + ' --format json').stdout) }
|
34
|
+
let(:examples) { json['examples'] }
|
35
|
+
let(:ex1) { examples.find{|x| x['id'] == 'tmp-1.0'} }
|
36
|
+
let(:ex2) { examples.find{|x| x['id'] =~ /generated/} }
|
37
|
+
let(:ex3) { examples.find{|x| x['id'] == 'gordon-1.0'} }
|
38
|
+
|
39
|
+
it 'must have 4 examples' do
|
40
|
+
json['examples'].length.must_equal 4
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'id in json' do
|
44
|
+
examples.find { |ex| !ex.key? 'id' }.must_be :nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'impact in json' do
|
48
|
+
ex1['impact'].must_equal 0.7
|
49
|
+
ex2['impact'].must_be :nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'status in json' do
|
53
|
+
ex1['status'].must_equal 'passed'
|
54
|
+
ex3['status'].must_equal 'pending'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'pending message in json' do
|
58
|
+
ex1['pending_message'].must_be :nil?
|
59
|
+
ex3['pending_message'].must_equal 'Not yet implemented'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'execute a profile with fulljson formatting' do
|
64
|
+
let(:json) { JSON.load(inspec('exec ' + example_profile + ' --format fulljson').stdout) }
|
65
|
+
let(:examples) { json['examples'] }
|
66
|
+
let(:metadata) { json['profiles'][0] }
|
67
|
+
let(:ex1) { examples.find{|x| x['id'] == 'tmp-1.0'} }
|
68
|
+
let(:ex2) { examples.find{|x| x['id'] =~ /generated/} }
|
69
|
+
let(:ex3) { examples.find{|x| x['id'] == 'gordon-1.0'} }
|
70
|
+
|
71
|
+
it 'has all the metadata' do
|
72
|
+
metadata.must_equal({
|
73
|
+
"name" => "profile",
|
74
|
+
"title" => "InSpec Example Profile",
|
75
|
+
"maintainer" => "Chef Software, Inc.",
|
76
|
+
"copyright" => "Chef Software, Inc.",
|
77
|
+
"copyright_email" => "support@chef.io",
|
78
|
+
"license" => "Apache 2 license",
|
79
|
+
"summary" => "Demonstrates the use of InSpec Compliance Profile",
|
80
|
+
"version" => "1.0.0",
|
81
|
+
"supports" => [{"os-family" => "unix"}]
|
82
|
+
})
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'must have 4 examples' do
|
86
|
+
json['examples'].length.must_equal 4
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'id in json' do
|
90
|
+
examples.find { |ex| !ex.key? 'id' }.must_be :nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'title in json' do
|
94
|
+
ex3['title'].must_equal 'Verify the version number of Gordon'
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'desc in json' do
|
98
|
+
ex3['desc'].must_equal 'An optional description...'
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'code in json' do
|
102
|
+
ex3['code'].wont_be :nil?
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'code_desc in json' do
|
106
|
+
ex3['code_desc'].wont_be :nil?
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'impact in json' do
|
110
|
+
ex1['impact'].must_equal 0.7
|
111
|
+
ex2['impact'].must_be :nil?
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'status in json' do
|
115
|
+
ex1['status'].must_equal 'passed'
|
116
|
+
ex3['status'].must_equal 'pending'
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'ref in json' do
|
120
|
+
ex1['ref'].must_match %r{examples/profile/controls/example.rb$}
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'ref_line in json' do
|
124
|
+
ex1['ref_line'].must_equal 14
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'run_time in json' do
|
128
|
+
ex1['run_time'].wont_be :nil?
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'start_time in json' do
|
132
|
+
ex1['start_time'].wont_be :nil?
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'pending message in json' do
|
136
|
+
ex1['pending'].must_be :nil?
|
137
|
+
ex3['pending'].must_equal "Can't find file \"/tmp/gordon/config.yaml\""
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
require 'functional/helper'
|
6
|
+
|
7
|
+
describe 'inspec json' do
|
8
|
+
include FunctionalHelper
|
9
|
+
|
10
|
+
it 'read the profile json' do
|
11
|
+
out = inspec('json ' + example_profile)
|
12
|
+
out.stderr.must_equal ''
|
13
|
+
out.exit_status.must_equal 0
|
14
|
+
s = out.stdout
|
15
|
+
JSON.load(s).must_be_kind_of Hash
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'json profile data' do
|
19
|
+
let(:json) { JSON.load(inspec('json ' + example_profile).stdout) }
|
20
|
+
|
21
|
+
it 'has a name' do
|
22
|
+
json['name'].must_equal 'profile'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has a title' do
|
26
|
+
json['title'].must_equal 'InSpec Example Profile'
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'has a summary' do
|
30
|
+
json['summary'].must_equal 'Demonstrates the use of InSpec Compliance Profile'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'has a version' do
|
34
|
+
json['version'].must_equal '1.0.0'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'has a maintainer' do
|
38
|
+
json['maintainer'].must_equal 'Chef Software, Inc.'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'has a copyright' do
|
42
|
+
json['copyright'].must_equal 'Chef Software, Inc.'
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'has rules' do
|
46
|
+
json['rules'].length.must_equal 3 # TODO: flatten out or search deeper!
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'a rule' do
|
50
|
+
let(:rule) { json['rules']['controls/example.rb']['rules']['tmp-1.0'] }
|
51
|
+
|
52
|
+
it 'has a title' do
|
53
|
+
rule['title'].must_equal 'Create /tmp directory'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'has a description' do
|
57
|
+
rule['desc'].must_equal 'An optional description...'
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'has an impact' do
|
61
|
+
rule['impact'].must_equal 0.7
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'has a ref' do
|
65
|
+
rule['refs'].must_equal([{'ref' => 'Document A-12', 'url' => 'http://...'}])
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'has a source location' do
|
69
|
+
loc = File.join(example_profile, '/controls/example.rb')
|
70
|
+
rule['source_location'].must_equal [loc, 8]
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'has a the source code' do
|
74
|
+
rule['code'].must_match /\Acontrol \"tmp-1.0\" do.*end\n\Z/m
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'filter with --controls' do
|
80
|
+
let(:out) { inspec('json ' + example_profile + ' --controls tmp-1.0') }
|
81
|
+
|
82
|
+
it 'still succeeds' do
|
83
|
+
out.stderr.must_equal ''
|
84
|
+
out.exit_status.must_equal 0
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'only has one control included' do
|
88
|
+
json = JSON.load(out.stdout)
|
89
|
+
grps = json['rules']
|
90
|
+
grps.keys.must_equal ['controls/example.rb']
|
91
|
+
rules = grps.values[0]['rules']
|
92
|
+
rules.keys.must_equal ['tmp-1.0']
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'writes json to file' do
|
97
|
+
out = inspec('json ' + example_profile + ' --output ' + dst.path)
|
98
|
+
out.stderr.must_equal ''
|
99
|
+
out.exit_status.must_equal 0
|
100
|
+
hm = JSON.load(File.read(dst.path))
|
101
|
+
hm['name'].must_equal 'profile'
|
102
|
+
hm['rules'].length.must_equal 3 # TODO: flatten out or search deeper!
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
require 'functional/helper'
|
6
|
+
|
7
|
+
describe 'command tests' do
|
8
|
+
include FunctionalHelper
|
9
|
+
|
10
|
+
describe 'detect' do
|
11
|
+
it 'runs well on all nodes' do
|
12
|
+
out = inspec('detect')
|
13
|
+
out.stderr.must_equal ''
|
14
|
+
out.exit_status.must_equal 0
|
15
|
+
j = JSON.load(out.stdout)
|
16
|
+
j.keys.must_include 'name'
|
17
|
+
j.keys.must_include 'family'
|
18
|
+
j.keys.must_include 'arch'
|
19
|
+
j.keys.must_include 'release'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'version' do
|
24
|
+
it 'provides the version number on stdout' do
|
25
|
+
out = inspec('version')
|
26
|
+
out.stderr.must_equal ''
|
27
|
+
out.exit_status.must_equal 0
|
28
|
+
out.stdout.must_equal Inspec::VERSION+"\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'shell' do
|
33
|
+
it 'provides a help command' do
|
34
|
+
out = CMD.run_command("echo \"help\nexit\" | #{exec_inspec} shell")
|
35
|
+
out.exit_status.must_equal 0
|
36
|
+
out.stdout.must_include 'Available commands:'
|
37
|
+
out.stdout.must_include 'You are currently running on:'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'exposes all resources' do
|
41
|
+
out = CMD.run_command("echo \"os\nexit\" | #{exec_inspec} shell")
|
42
|
+
out.exit_status.must_equal 0
|
43
|
+
out.stdout.must_match /^=> .*Operating.* .*System.* .*Detection.*$/
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'check' do
|
48
|
+
it 'verifies that a profile is ok' do
|
49
|
+
out = inspec('check ' + example_profile)
|
50
|
+
out.stdout.must_match /Valid.*true/
|
51
|
+
out.exit_status.must_equal 0
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -91,7 +91,7 @@ describe Inspec::ProfileContext do
|
|
91
91
|
it 'supports empty describe calls' do
|
92
92
|
load('describe').must_output ''
|
93
93
|
profile.rules.keys.length.must_equal 1
|
94
|
-
profile.rules.keys[0].must_match /^\(generated from
|
94
|
+
profile.rules.keys[0].must_match /^\(generated from \(eval\):1 [0-9a-f]+\)$/
|
95
95
|
profile.rules.values[0].must_be_kind_of Inspec::Rule
|
96
96
|
end
|
97
97
|
|
@@ -99,7 +99,7 @@ describe Inspec::ProfileContext do
|
|
99
99
|
load('describe true do; it { should_eq true }; end')
|
100
100
|
.must_output ''
|
101
101
|
profile.rules.keys.length.must_equal 1
|
102
|
-
profile.rules.keys[0].must_match /^\(generated from
|
102
|
+
profile.rules.keys[0].must_match /^\(generated from \(eval\):1 [0-9a-f]+\)$/
|
103
103
|
profile.rules.values[0].must_be_kind_of Inspec::Rule
|
104
104
|
end
|
105
105
|
|
@@ -108,7 +108,7 @@ describe Inspec::ProfileContext do
|
|
108
108
|
.must_output ''
|
109
109
|
profile.rules.keys.length.must_equal 3
|
110
110
|
[0, 1, 2].each do |i|
|
111
|
-
profile.rules.keys[i].must_match /^\(generated from
|
111
|
+
profile.rules.keys[i].must_match /^\(generated from \(eval\):2 [0-9a-f]+\)$/
|
112
112
|
profile.rules.values[i].must_be_kind_of Inspec::Rule
|
113
113
|
end
|
114
114
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.16.
|
4
|
+
version: 0.16.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominik Richter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: r-train
|
@@ -208,11 +208,9 @@ files:
|
|
208
208
|
- examples/profile/README.md
|
209
209
|
- examples/profile/controls/example.rb
|
210
210
|
- examples/profile/controls/gordon.rb
|
211
|
+
- examples/profile/controls/meta.rb
|
211
212
|
- examples/profile/inspec.yml
|
212
213
|
- examples/profile/libraries/gordon_config.rb
|
213
|
-
- examples/resource/controls/tiny.rb
|
214
|
-
- examples/resource/inspec.yml
|
215
|
-
- examples/resource/libraries/tiny.rb
|
216
214
|
- inspec.gemspec
|
217
215
|
- lib/bundles/README.md
|
218
216
|
- lib/bundles/inspec-compliance.rb
|
@@ -360,7 +358,12 @@ files:
|
|
360
358
|
- test/cookbooks/os_prepare/templates/default/sv-default-svlog-run.erb
|
361
359
|
- test/docker_run.rb
|
362
360
|
- test/docker_test.rb
|
363
|
-
- test/functional/
|
361
|
+
- test/functional/helper.rb
|
362
|
+
- test/functional/inheritance_test.rb
|
363
|
+
- test/functional/inspec_archive_test.rb
|
364
|
+
- test/functional/inspec_exec_test.rb
|
365
|
+
- test/functional/inspec_json_test.rb
|
366
|
+
- test/functional/inspec_test.rb
|
364
367
|
- test/helper.rb
|
365
368
|
- test/integration/default/_debug_spec.rb
|
366
369
|
- test/integration/default/apache_conf_spec.rb
|
@@ -617,7 +620,12 @@ test_files:
|
|
617
620
|
- test/cookbooks/os_prepare/templates/default/sv-default-svlog-run.erb
|
618
621
|
- test/docker_run.rb
|
619
622
|
- test/docker_test.rb
|
620
|
-
- test/functional/
|
623
|
+
- test/functional/helper.rb
|
624
|
+
- test/functional/inheritance_test.rb
|
625
|
+
- test/functional/inspec_archive_test.rb
|
626
|
+
- test/functional/inspec_exec_test.rb
|
627
|
+
- test/functional/inspec_json_test.rb
|
628
|
+
- test/functional/inspec_test.rb
|
621
629
|
- test/helper.rb
|
622
630
|
- test/integration/default/_debug_spec.rb
|
623
631
|
- test/integration/default/apache_conf_spec.rb
|