inspec 0.26.0 → 0.27.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -2
- data/Gemfile +3 -0
- data/docs/ctl_inspec.rst +27 -0
- data/docs/resources.rst +147 -6
- data/inspec.gemspec +1 -1
- data/lib/bundles/inspec-compliance/README.md +105 -1
- data/lib/bundles/inspec-compliance/images/cc-token.png +0 -0
- data/lib/bundles/inspec-init/README.md +31 -0
- data/lib/bundles/inspec-supermarket/README.md +33 -0
- data/lib/inspec/cli.rb +27 -10
- data/lib/inspec/profile.rb +2 -1
- data/lib/inspec/rspec_json_formatter.rb +4 -2
- data/lib/inspec/rule.rb +4 -3
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +11 -0
- data/lib/resources/file.rb +12 -0
- data/lib/resources/service.rb +2 -1
- data/lib/resources/wmi.rb +55 -16
- data/lib/utils/base_cli.rb +2 -4
- data/test/cookbooks/os_prepare/recipes/file.rb +7 -0
- data/test/functional/inspec_exec_json_test.rb +2 -2
- data/test/functional/inspec_exec_test.rb +6 -6
- data/test/functional/inspec_json_profile_test.rb +2 -1
- data/test/functional/inspec_test.rb +5 -4
- data/test/helper.rb +1 -1
- data/test/integration/default/{compare_matcher_spec.rb → cmp_matcher_spec.rb} +12 -0
- data/test/integration/default/file_spec.rb +9 -0
- data/test/integration/default/wmi_spec.rb +43 -8
- data/test/unit/mock/cmd/get-wmiobject +5 -6
- data/test/unit/mock/cmd/systemctl-show-all-sshd +1 -0
- data/test/unit/resources/service_test.rb +6 -6
- data/test/unit/resources/wmi_test.rb +6 -9
- metadata +16 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46a196f44aef946778a2c1551727b83826eaaede
|
4
|
+
data.tar.gz: b351a6fddd347b9f951818ad3332270f3d399139
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70da720dd36b4df18aca90293777b169ee25df1ebbb679500104e191ecdfa203d2136223e063e37c7ab0b5d5eed44029f65d2331bcd5d3eb825376c9e63f344f
|
7
|
+
data.tar.gz: d09acee41a988495d4bec78a6a02409a89c89e8b527b5b3475ba622d2e6ab0da9751236bf1af7c6059c8e51a9193940b24cab6ef1f86cb66db80a174d5f4b8be
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,34 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [0.
|
4
|
-
[Full Changelog](https://github.com/chef/inspec/compare/v0.
|
3
|
+
## [0.27.0](https://github.com/chef/inspec/tree/0.27.0) (2016-07-10)
|
4
|
+
[Full Changelog](https://github.com/chef/inspec/compare/v0.26.0...0.27.0)
|
5
|
+
|
6
|
+
**Implemented enhancements:**
|
7
|
+
|
8
|
+
- inspec report source\_location data type [\#807](https://github.com/chef/inspec/issues/807)
|
9
|
+
- Additional fields in inspec reports [\#806](https://github.com/chef/inspec/issues/806)
|
10
|
+
- api: report source location with field identifiers [\#808](https://github.com/chef/inspec/pull/808) ([arlimus](https://github.com/arlimus))
|
11
|
+
- add boolean support for cmp matcher [\#801](https://github.com/chef/inspec/pull/801) ([chris-rock](https://github.com/chris-rock))
|
12
|
+
- improve wmi resource [\#800](https://github.com/chef/inspec/pull/800) ([chris-rock](https://github.com/chris-rock))
|
13
|
+
- Update documentation for bundles [\#716](https://github.com/chef/inspec/pull/716) ([chris-rock](https://github.com/chris-rock))
|
14
|
+
|
15
|
+
**Fixed bugs:**
|
16
|
+
|
17
|
+
- `os` resource not accessible within a `describe` [\#451](https://github.com/chef/inspec/issues/451)
|
18
|
+
- add suid sgid and sticky support for file resource [\#819](https://github.com/chef/inspec/pull/819) ([arlimus](https://github.com/arlimus))
|
19
|
+
- pin gem version for ffi due to appveyor failures [\#816](https://github.com/chef/inspec/pull/816) ([arlimus](https://github.com/arlimus))
|
20
|
+
- check service running by ActiveState [\#814](https://github.com/chef/inspec/pull/814) ([arlimus](https://github.com/arlimus))
|
21
|
+
|
22
|
+
**Merged pull requests:**
|
23
|
+
|
24
|
+
- small fix for postgres\_session documentation \(Test for risky database entries example\) [\#815](https://github.com/chef/inspec/pull/815) ([atomic111](https://github.com/atomic111))
|
25
|
+
- Add array documentation to yaml / json resource [\#803](https://github.com/chef/inspec/pull/803) ([bigbam505](https://github.com/bigbam505))
|
26
|
+
- Updating ctl docs to include the init command [\#802](https://github.com/chef/inspec/pull/802) ([ChefRycar](https://github.com/ChefRycar))
|
27
|
+
- add documentation for bash resource [\#799](https://github.com/chef/inspec/pull/799) ([chris-rock](https://github.com/chris-rock))
|
28
|
+
- align inspec's check, detect, and exec cli formatters [\#797](https://github.com/chef/inspec/pull/797) ([arlimus](https://github.com/arlimus))
|
29
|
+
|
30
|
+
## [v0.26.0](https://github.com/chef/inspec/tree/v0.26.0) (2016-06-16)
|
31
|
+
[Full Changelog](https://github.com/chef/inspec/compare/v0.25.0...v0.26.0)
|
5
32
|
|
6
33
|
**Implemented enhancements:**
|
7
34
|
|
data/Gemfile
CHANGED
data/docs/ctl_inspec.rst
CHANGED
@@ -171,6 +171,33 @@ Use ``inspec help`` to print help for the |ctl inspec| from the command shell.
|
|
171
171
|
|
172
172
|
|
173
173
|
|
174
|
+
init
|
175
|
+
=====================================================
|
176
|
+
Use ``inspec init`` to initialize a new inspec profile
|
177
|
+
|
178
|
+
Syntax
|
179
|
+
-----------------------------------------------------
|
180
|
+
This command has the following syntax:
|
181
|
+
.. code-block:: bash
|
182
|
+
|
183
|
+
$ inspec init profile PROFILE (options)
|
184
|
+
|
185
|
+
where:
|
186
|
+
|
187
|
+
* ``PROFILE`` is the name of the profile you wish to create
|
188
|
+
|
189
|
+
Options
|
190
|
+
-----------------------------------------------------
|
191
|
+
This subcommand has additional options:
|
192
|
+
|
193
|
+
``--overwrite``
|
194
|
+
Overwite directory if it exists
|
195
|
+
|
196
|
+
``--no-overwrite``
|
197
|
+
Converse of ``--overwrite``. (default)
|
198
|
+
|
199
|
+
|
200
|
+
|
174
201
|
json
|
175
202
|
=====================================================
|
176
203
|
Use ``inspec json`` to read all tests at the specified path, and then generate a |json| profile to standard output (stdout).
|
data/docs/resources.rst
CHANGED
@@ -9,6 +9,7 @@ The following InSpec audit resources are available:
|
|
9
9
|
* `audit_policy`_
|
10
10
|
* `auditd_conf`_
|
11
11
|
* `auditd_rules`_
|
12
|
+
* `bash`_
|
12
13
|
* `bond`_
|
13
14
|
* `bridge`_
|
14
15
|
* `csv`_
|
@@ -398,6 +399,130 @@ Note that filters can be chained, for example:
|
|
398
399
|
end
|
399
400
|
|
400
401
|
|
402
|
+
|
403
|
+
|
404
|
+
bash
|
405
|
+
=====================================================
|
406
|
+
Use the ``bash`` |inspec resource| to test an arbitrary command in BASH on the system.
|
407
|
+
|
408
|
+
**Stability: Stable**
|
409
|
+
|
410
|
+
Syntax
|
411
|
+
-----------------------------------------------------
|
412
|
+
A ``bash`` |inspec resource| block declares a command to be run, one (or more) expected outputs, and the location to which that output is sent:
|
413
|
+
|
414
|
+
.. code-block:: ruby
|
415
|
+
|
416
|
+
describe bash('command') do
|
417
|
+
it { should exist }
|
418
|
+
its('matcher') { should eq 'output' }
|
419
|
+
end
|
420
|
+
|
421
|
+
where
|
422
|
+
|
423
|
+
* ``'command'`` must specify a command to be run
|
424
|
+
* ``'matcher'`` is one of ``exit_status``, ``stderr``, or ``stdout``
|
425
|
+
* ``'output'`` tests the output of the command run on the system versus the output value stated in the test
|
426
|
+
|
427
|
+
Matchers
|
428
|
+
-----------------------------------------------------
|
429
|
+
This InSpec audit resource has the following matchers.
|
430
|
+
|
431
|
+
exist
|
432
|
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
433
|
+
The ``exist`` matcher tests if a command may be run on the system:
|
434
|
+
|
435
|
+
.. code-block:: ruby
|
436
|
+
|
437
|
+
it { should exist }
|
438
|
+
|
439
|
+
exit_status
|
440
|
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
441
|
+
The ``exit_status`` matcher tests the exit status for the command:
|
442
|
+
|
443
|
+
.. code-block:: ruby
|
444
|
+
|
445
|
+
its('exit_status') { should eq 123 }
|
446
|
+
|
447
|
+
stderr
|
448
|
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
449
|
+
The ``stderr`` matcher tests results of the command as returned in standard error (stderr):
|
450
|
+
|
451
|
+
.. code-block:: ruby
|
452
|
+
|
453
|
+
its('stderr') { should eq 'error' }
|
454
|
+
|
455
|
+
stdout
|
456
|
+
+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
457
|
+
The ``stdout`` matcher tests results of the command as returned in standard output (stdout):
|
458
|
+
|
459
|
+
.. code-block:: ruby
|
460
|
+
|
461
|
+
its('stdout') { should match /^1$/ }
|
462
|
+
|
463
|
+
Examples
|
464
|
+
-----------------------------------------------------
|
465
|
+
The following examples show how to use this InSpec audit resource.
|
466
|
+
|
467
|
+
**List content of a directorye**
|
468
|
+
|
469
|
+
.. code-block:: ruby
|
470
|
+
|
471
|
+
describe bash('ls -al /') do
|
472
|
+
its('stdout') { should match /bin/ }
|
473
|
+
its('stderr') { should eq '' }
|
474
|
+
its('exit_status') { should eq 0 }
|
475
|
+
end
|
476
|
+
|
477
|
+
**Test standard output (stdout)**
|
478
|
+
|
479
|
+
.. code-block:: ruby
|
480
|
+
|
481
|
+
describe bash('echo hello') do
|
482
|
+
its('stdout') { should eq 'hello\n' }
|
483
|
+
its('stderr') { should eq '' }
|
484
|
+
its('exit_status') { should eq 0 }
|
485
|
+
end
|
486
|
+
|
487
|
+
**Test standard error (stderr)**
|
488
|
+
|
489
|
+
.. code-block:: ruby
|
490
|
+
|
491
|
+
describe bash('>&2 echo error') do
|
492
|
+
its('stdout') { should eq '' }
|
493
|
+
its('stderr') { should eq 'error\n' }
|
494
|
+
its('exit_status') { should eq 0 }
|
495
|
+
end
|
496
|
+
|
497
|
+
**Test an exit status code**
|
498
|
+
|
499
|
+
.. code-block:: ruby
|
500
|
+
|
501
|
+
describe bash('exit 123') do
|
502
|
+
its('stdout') { should eq '' }
|
503
|
+
its('stderr') { should eq '' }
|
504
|
+
its('exit_status') { should eq 123 }
|
505
|
+
end
|
506
|
+
|
507
|
+
**Specify the path of the bash executable**
|
508
|
+
|
509
|
+
.. code-block:: ruby
|
510
|
+
|
511
|
+
describe bash('echo hello', path: '/bin/bash') do
|
512
|
+
its('stdout') { should eq 'hello\n' }
|
513
|
+
end
|
514
|
+
|
515
|
+
**Specify bash arguments (defaults to -c)**
|
516
|
+
|
517
|
+
.. code-block:: ruby
|
518
|
+
|
519
|
+
describe bash('echo hello', args: '-x -c') do
|
520
|
+
its('stdout') { should eq 'hello\n' }
|
521
|
+
end
|
522
|
+
|
523
|
+
|
524
|
+
|
525
|
+
|
401
526
|
bond
|
402
527
|
=====================================================
|
403
528
|
Use the ``bond`` |inspec resource| to test a logical, bonded network interface (i.e. "two or more network interfaces aggregated into a single, logical network interface"). On |linux| platforms, any value in the ``/proc/net/bonding`` directory may be tested.
|
@@ -1913,7 +2038,11 @@ A ``json`` |inspec resource| block declares the data to be tested. Assume the fo
|
|
1913
2038
|
"name" : "hello",
|
1914
2039
|
"meta" : {
|
1915
2040
|
"creator" : "John Doe"
|
1916
|
-
}
|
2041
|
+
},
|
2042
|
+
"array": [
|
2043
|
+
"zero",
|
2044
|
+
"one"
|
2045
|
+
]
|
1917
2046
|
}
|
1918
2047
|
|
1919
2048
|
|
@@ -1924,6 +2053,7 @@ This file can be queried via:
|
|
1924
2053
|
describe json('/paht/to/name.json') do
|
1925
2054
|
its('name') { should eq 'hello' }
|
1926
2055
|
its(['meta','creator']) { should eq 'John Doe' }
|
2056
|
+
its(['array', 1]) { should eq 'one' }
|
1927
2057
|
end
|
1928
2058
|
|
1929
2059
|
where
|
@@ -3562,11 +3692,11 @@ The following examples show how to use this InSpec audit resource.
|
|
3562
3692
|
.. code-block:: ruby
|
3563
3693
|
|
3564
3694
|
describe postgres_session('my_user', 'password').query('SELECT count (*)
|
3565
|
-
|
3566
|
-
|
3567
|
-
|
3568
|
-
|
3569
|
-
its('output') { should eq
|
3695
|
+
FROM pg_language
|
3696
|
+
WHERE lanpltrusted = \'f\'
|
3697
|
+
AND lanname!=\'internal\'
|
3698
|
+
AND lanname!=\'c\';') do
|
3699
|
+
its('output') { should eq '0' }
|
3570
3700
|
end
|
3571
3701
|
|
3572
3702
|
|
@@ -4344,10 +4474,21 @@ Syntax
|
|
4344
4474
|
-----------------------------------------------------
|
4345
4475
|
A ``yaml`` |inspec resource| block declares the configuration data to be tested:
|
4346
4476
|
|
4477
|
+
.. code-block:: yaml
|
4478
|
+
|
4479
|
+
name: foo
|
4480
|
+
array:
|
4481
|
+
- zero
|
4482
|
+
- one
|
4483
|
+
|
4484
|
+
|
4485
|
+
This file can be queried via:
|
4486
|
+
|
4347
4487
|
.. code-block:: ruby
|
4348
4488
|
|
4349
4489
|
describe yaml do
|
4350
4490
|
its('name') { should eq 'foo' }
|
4491
|
+
its(['array', 1]) { should eq 'one' }
|
4351
4492
|
end
|
4352
4493
|
|
4353
4494
|
where
|
data/inspec.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
25
25
|
spec.require_paths = ['lib']
|
26
26
|
|
27
|
-
spec.add_dependency 'train', '
|
27
|
+
spec.add_dependency 'train', '>=0.15.1', '<1.0'
|
28
28
|
spec.add_dependency 'thor', '~> 0.19'
|
29
29
|
spec.add_dependency 'json', '~> 1.8'
|
30
30
|
spec.add_dependency 'rainbow', '~> 2'
|
@@ -8,7 +8,6 @@ This extensions offers the following features:
|
|
8
8
|
|
9
9
|
To use the CLI, this InSpec add-on adds the following commands:
|
10
10
|
|
11
|
-
* `$ inspec compliance api_token server --token TOKEN --user USER` - save the Chef Compliance API token for user
|
12
11
|
* `$ inspec compliance login` - authentication of the API token against Chef Compliance
|
13
12
|
* `$ inspec compliance profiles` - list all available Chef Compliance profiles
|
14
13
|
* `$ inspec compliance exec profile` - runs a Chef Compliance profile
|
@@ -20,6 +19,111 @@ Compliance profiles can be executed in two mays:
|
|
20
19
|
- via compliance exec: `inspec compliance exec profile`
|
21
20
|
- via compliance scheme: `inspec exec compliance://profile`
|
22
21
|
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
Before you start using the compliance plugin, you need a running [Chef Compliance](https://www.chef.io/compliance/) server. Please login and gather the access token:
|
25
|
+
|
26
|
+
![Chef Compliance Token](images/cc-token.png)
|
27
|
+
|
28
|
+
You can choose the access token (`--token`) or the refresh token (`--refresh_token`)
|
29
|
+
|
30
|
+
```
|
31
|
+
$ inspec compliance
|
32
|
+
Commands:
|
33
|
+
inspec compliance exec PROFILE # executes a Chef Compliance profile
|
34
|
+
inspec compliance help [COMMAND] # Describe subcommands or one specific subcommand
|
35
|
+
inspec compliance login SERVER # Log in to a Chef Compliance SERVER
|
36
|
+
inspec compliance logout # user logout from Chef Compliance
|
37
|
+
inspec compliance profiles # list all available profiles in Chef Compliance
|
38
|
+
inspec compliance upload PATH # uploads a local profile to Chef Compliance
|
39
|
+
inspec compliance version # displays the version of the Chef Compliance server
|
40
|
+
|
41
|
+
# login to chef compliance server
|
42
|
+
$ inspec compliance login https://compliance.test --user admin --insecure --token '...'
|
43
|
+
|
44
|
+
# display the chef compliance server version
|
45
|
+
$ inspec compliance version
|
46
|
+
Chef Compliance version: 1.0.11
|
47
|
+
|
48
|
+
# list available profiles via Chef Compliance
|
49
|
+
$ inspec compliance profiles
|
50
|
+
Available profiles:
|
51
|
+
-------------------
|
52
|
+
* base/apache
|
53
|
+
* base/linux
|
54
|
+
* base/mysql
|
55
|
+
* base/postgres
|
56
|
+
* base/ssh
|
57
|
+
* base/windows
|
58
|
+
* cis/cis-centos6-level1
|
59
|
+
* cis/cis-centos6-level2
|
60
|
+
* cis/cis-centos7-level1
|
61
|
+
* cis/cis-centos7-level2
|
62
|
+
* cis/cis-rhel7-level1
|
63
|
+
* cis/cis-rhel7-level2
|
64
|
+
* cis/cis-ubuntu12.04lts-level1
|
65
|
+
* cis/cis-ubuntu12.04lts-level2
|
66
|
+
* cis/cis-ubuntu14.04lts-level1
|
67
|
+
* cis/cis-ubuntu14.04lts-level2
|
68
|
+
|
69
|
+
# upload a profile to chef Compliance
|
70
|
+
$ inspec compliance version
|
71
|
+
Chef Compliance version: 1.0.11
|
72
|
+
➜ inspec git:(chris-rock/cc-error-not-loggedin) ✗ b inspec compliance upload examples/profile
|
73
|
+
I, [2016-05-06T14:27:20.907547 #37592] INFO -- : Checking profile in examples/profile
|
74
|
+
I, [2016-05-06T14:27:20.907668 #37592] INFO -- : Metadata OK.
|
75
|
+
I, [2016-05-06T14:27:20.968584 #37592] INFO -- : Found 4 controls.
|
76
|
+
I, [2016-05-06T14:27:20.968638 #37592] INFO -- : Control definitions OK.
|
77
|
+
Profile is valid
|
78
|
+
Generate temporary profile archive at /var/folders/jy/2bnrfb4s36jbjtzllvhhyqhw0000gn/T/profile20160506-37592-1tf326f.tar.gz
|
79
|
+
I, [2016-05-06T14:27:21.020017 #37592] INFO -- : Generate archive /var/folders/jy/2bnrfb4s36jbjtzllvhhyqhw0000gn/T/profile20160506-37592-1tf326f.tar.gz.
|
80
|
+
I, [2016-05-06T14:27:21.024837 #37592] INFO -- : Finished archive generation.
|
81
|
+
Start upload to admin/profile
|
82
|
+
Uploading to Chef Compliance
|
83
|
+
Successfully uploaded profile
|
84
|
+
|
85
|
+
# display all profiles
|
86
|
+
$ inspec compliance profiles
|
87
|
+
Available profiles:
|
88
|
+
-------------------
|
89
|
+
* admin/profile
|
90
|
+
* base/apache
|
91
|
+
* base/linux
|
92
|
+
* base/mysql
|
93
|
+
* base/postgres
|
94
|
+
* base/ssh
|
95
|
+
* base/windows
|
96
|
+
* cis/cis-centos6-level1
|
97
|
+
* cis/cis-centos6-level2
|
98
|
+
* cis/cis-centos7-level1
|
99
|
+
* cis/cis-centos7-level2
|
100
|
+
* cis/cis-rhel7-level1
|
101
|
+
* cis/cis-rhel7-level2
|
102
|
+
* cis/cis-ubuntu12.04lts-level1
|
103
|
+
* cis/cis-ubuntu12.04lts-level2
|
104
|
+
* cis/cis-ubuntu14.04lts-level1
|
105
|
+
* cis/cis-ubuntu14.04lts-level2
|
106
|
+
|
107
|
+
# run a profile from Chef Compliance locally
|
108
|
+
$ inspec exec compliance://admin/profile
|
109
|
+
.*...
|
110
|
+
|
111
|
+
Pending: (Failures listed here are expected and do not affect your suite's status)
|
112
|
+
|
113
|
+
1) gordon_config Can't find file "/tmp/gordon/config.yaml"
|
114
|
+
# Not yet implemented
|
115
|
+
# ./lib/inspec/runner.rb:157
|
116
|
+
|
117
|
+
|
118
|
+
Finished in 0.02862 seconds (files took 0.62628 seconds to load)
|
119
|
+
5 examples, 0 failures, 1 pending
|
120
|
+
|
121
|
+
# logout from Chef Compliance
|
122
|
+
```
|
123
|
+
$ inspec compliance logout
|
124
|
+
Successfully logged out
|
125
|
+
```
|
126
|
+
|
23
127
|
## Integration Tests
|
24
128
|
|
25
129
|
At this point of time, InSpec is not able to pick up the token directly, therefore the integration test is semi-automatic at this point of time:
|
Binary file
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# InSpec Extension to create new profiles
|
2
|
+
|
3
|
+
This extensions helps you to easily create a new profile
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```
|
8
|
+
$ inspec init profile examples/new-profile
|
9
|
+
Create new profile at /Users/chartmann/Development/compliance/inspec/examples/new-profile
|
10
|
+
* Create directory controls
|
11
|
+
* Create file controls/example.rb
|
12
|
+
* Create file inspec.yml
|
13
|
+
* Create directory libraries
|
14
|
+
* Create file README.md
|
15
|
+
* Create file libraries/.gitkeep
|
16
|
+
|
17
|
+
$ inspec check examples/new-profile
|
18
|
+
Summary
|
19
|
+
-------
|
20
|
+
Location: examples/new-profile
|
21
|
+
Profile: examples/new-profile
|
22
|
+
Controls: 2
|
23
|
+
Timestamp: 2016-05-06T14:39:47+02:00
|
24
|
+
Valid: true
|
25
|
+
|
26
|
+
Errors
|
27
|
+
------
|
28
|
+
|
29
|
+
Warnings
|
30
|
+
--------
|
31
|
+
```
|
@@ -10,3 +10,36 @@ To use the CLI, this InSpec add-on adds the following commands:
|
|
10
10
|
|
11
11
|
- via supermarket exec: `inspec supermarket exec nathenharvey/tmp-compliance-profile`
|
12
12
|
- via supermarket scheme: `inspec exec supermarket://nathenharvey/tmp-compliance-profile`
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
```
|
17
|
+
$ inspec supermarket
|
18
|
+
Commands:
|
19
|
+
inspec supermarket exec PROFILE # execute a Supermarket profile
|
20
|
+
inspec supermarket help [COMMAND] # Describe subcommands or one specific subcommand
|
21
|
+
inspec supermarket info PROFILE # display Supermarket profile details
|
22
|
+
inspec supermarket profiles # list all available profiles in Chef Supermarket
|
23
|
+
|
24
|
+
$ inspec supermarket profiles
|
25
|
+
Available profiles:
|
26
|
+
-------------------
|
27
|
+
* nathenharvey/tmp-compliance-profile
|
28
|
+
* hardening/os-hardening
|
29
|
+
* hardening/ssh-hardening
|
30
|
+
|
31
|
+
$ inspec supermarket info hardening/os-hardening
|
32
|
+
name: os-hardening
|
33
|
+
owner: hardening
|
34
|
+
url: https://github.com/dev-sec/tests-os-hardening
|
35
|
+
|
36
|
+
description: Base Linux Compliance profile, used for Security + DevOps. More Information is available at http://dev-sec.io/
|
37
|
+
|
38
|
+
$ inspec exec supermarket://hardening/os-hardening
|
39
|
+
........F.F.................F......FFF.....FFFF.F........FF....FFFFFFF...FF.FFFFFF.FFFFFFFFFFF.F...
|
40
|
+
|
41
|
+
...
|
42
|
+
|
43
|
+
Finished in 3.81 seconds (files took 5.69 seconds to load)
|
44
|
+
99 examples, 40 failures
|
45
|
+
```
|
data/lib/inspec/cli.rb
CHANGED
@@ -57,19 +57,35 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
57
57
|
if opts['format'] == 'json'
|
58
58
|
puts JSON.generate(result)
|
59
59
|
else
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
60
|
+
%w{location profile controls timestamp valid}.each do |item|
|
61
|
+
puts format('%-12s %s', item.to_s.capitalize + ':',
|
62
|
+
mark_text(result[:summary][item.to_sym]))
|
63
|
+
end
|
64
64
|
puts
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
if result[:errors].empty? and result[:warnings].empty?
|
67
|
+
puts 'No errors or warnings'
|
68
|
+
else
|
69
|
+
red = "\033[31m"
|
70
|
+
yellow = "\033[33m"
|
71
|
+
rst = "\033[0m"
|
72
|
+
|
73
|
+
item_msg = lambda { |item|
|
74
|
+
pos = [item[:file], item[:line], item[:column]].compact.join(':')
|
75
|
+
pos.empty? ? item[:msg] : pos + ': ' + item[:msg]
|
70
76
|
}
|
77
|
+
result[:errors].each do |item|
|
78
|
+
puts "#{red} ✖ #{item_msg.call(item)}#{rst}"
|
79
|
+
end
|
80
|
+
result[:warnings].each do |item|
|
81
|
+
puts "#{yellow} ! #{item_msg.call(item)}#{rst}"
|
82
|
+
end
|
83
|
+
|
71
84
|
puts
|
72
|
-
|
85
|
+
puts format('Summary: %s%d errors%s, %s%d warnings%s',
|
86
|
+
red, result[:errors].length, rst,
|
87
|
+
yellow, result[:warnings].length, rst)
|
88
|
+
end
|
73
89
|
end
|
74
90
|
exit 1 unless result[:summary][:valid]
|
75
91
|
end
|
@@ -127,7 +143,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|
127
143
|
else
|
128
144
|
headline('Operating System Details')
|
129
145
|
%w{name family release arch}.each { |item|
|
130
|
-
puts
|
146
|
+
puts format('%-10s %s', item.to_s.capitalize + ':',
|
147
|
+
mark_text(res[item.to_sym]))
|
131
148
|
}
|
132
149
|
end
|
133
150
|
end
|
data/lib/inspec/profile.rb
CHANGED
@@ -145,7 +145,8 @@ module Inspec
|
|
145
145
|
|
146
146
|
# iterate over hash of groups
|
147
147
|
params[:controls].each { |id, control|
|
148
|
-
sfile
|
148
|
+
sfile = control[:source_location][:ref]
|
149
|
+
sline = control[:source_location][:line]
|
149
150
|
error.call(sfile, sline, nil, id, 'Avoid controls with empty IDs') if id.nil? or id.empty?
|
150
151
|
next if id.start_with? '(generated '
|
151
152
|
warn.call(sfile, sline, nil, id, "Control #{id} has no title") if control[:title].to_s.empty?
|
@@ -202,8 +202,10 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
202
202
|
|
203
203
|
res = @output_hash[:summary]
|
204
204
|
passed = res[:example_count] - res[:failure_count] - res[:skip_count]
|
205
|
-
s = format('Summary: %
|
206
|
-
passed,
|
205
|
+
s = format('Summary: %s%d successful%s, %s%d failures%s, %s%d skipped%s',
|
206
|
+
COLORS['passed'], passed, COLORS['reset'],
|
207
|
+
COLORS['failed'], res[:failure_count], COLORS['reset'],
|
208
|
+
COLORS['skipped'], res[:skip_count], COLORS['reset'])
|
207
209
|
output.puts(s)
|
208
210
|
end
|
209
211
|
|
data/lib/inspec/rule.rb
CHANGED
@@ -199,10 +199,11 @@ module Inspec
|
|
199
199
|
|
200
200
|
# get the source location of the block
|
201
201
|
def __get_block_source_location(&block)
|
202
|
-
return
|
203
|
-
block.source_location
|
202
|
+
return {} unless block_given?
|
203
|
+
r, l = block.source_location
|
204
|
+
{ ref: r, line: l }
|
204
205
|
rescue MethodSource::SourceNotFoundError
|
205
|
-
|
206
|
+
{}
|
206
207
|
end
|
207
208
|
end
|
208
209
|
end
|
data/lib/inspec/version.rb
CHANGED
data/lib/matchers/matchers.rb
CHANGED
@@ -247,6 +247,15 @@ RSpec::Matchers.define :cmp do |first_expected|
|
|
247
247
|
!(value =~ /\A0+\d+\Z/).nil?
|
248
248
|
end
|
249
249
|
|
250
|
+
def boolean?(value)
|
251
|
+
%w{true false}.include?(value.downcase)
|
252
|
+
end
|
253
|
+
|
254
|
+
# expects that the values have been checked with boolean?
|
255
|
+
def to_boolean(value)
|
256
|
+
value.casecmp('true') == 0
|
257
|
+
end
|
258
|
+
|
250
259
|
def try_match(actual, op, expected) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
|
251
260
|
# if actual and expected are strings
|
252
261
|
if expected.is_a?(String) && actual.is_a?(String)
|
@@ -255,6 +264,8 @@ RSpec::Matchers.define :cmp do |first_expected|
|
|
255
264
|
return !actual.to_s.match(expected).nil?
|
256
265
|
elsif expected.is_a?(String) && integer?(expected) && actual.is_a?(Integer)
|
257
266
|
return actual.method(op).call(expected.to_i)
|
267
|
+
elsif expected.is_a?(String) && boolean?(expected) && [true, false].include?(actual)
|
268
|
+
return actual.method(op).call(to_boolean(expected))
|
258
269
|
elsif expected.is_a?(Integer) && integer?(actual)
|
259
270
|
return actual.to_i.method(op).call(expected)
|
260
271
|
elsif expected.is_a?(Float) && float?(actual)
|
data/lib/resources/file.rb
CHANGED
data/lib/resources/service.rb
CHANGED
@@ -248,7 +248,8 @@ module Inspec::Resources
|
|
248
248
|
installed = params['LoadState'] == 'loaded'
|
249
249
|
# test via 'systemctl is-active service'
|
250
250
|
# SubState values running
|
251
|
-
running = params['
|
251
|
+
running = (params['ActiveState'] == 'active') ||
|
252
|
+
(params['SubState'] == 'running')
|
252
253
|
# test via systemctl --quiet is-enabled
|
253
254
|
# ActiveState values eg.g inactive, active
|
254
255
|
enabled = %w{enabled static}.include? params['UnitFileState']
|
data/lib/resources/wmi.rb
CHANGED
@@ -13,7 +13,8 @@ module Inspec::Resources
|
|
13
13
|
name 'wmi'
|
14
14
|
desc 'request wmi information'
|
15
15
|
example "
|
16
|
-
describe wmi(
|
16
|
+
describe wmi({
|
17
|
+
class: 'RSOP_SecuritySettingNumeric',
|
17
18
|
namespace: 'root\\rsop\\computer',
|
18
19
|
filter: 'KeyName = \'MinimumPasswordAge\' And precedence=1'
|
19
20
|
}) do
|
@@ -24,13 +25,18 @@ module Inspec::Resources
|
|
24
25
|
include ObjectTraverser
|
25
26
|
attr_accessor :content
|
26
27
|
|
27
|
-
def initialize(wmiclass, opts =
|
28
|
+
def initialize(wmiclass = nil, opts = nil)
|
28
29
|
# verify that this resource is only supported on Windows
|
29
30
|
return skip_resource 'The `windows_feature` resource is not supported on your OS.' unless inspec.os.windows?
|
30
31
|
|
31
|
-
@
|
32
|
-
|
33
|
-
|
32
|
+
@options = opts || {}
|
33
|
+
# if wmiclass is not a hash, we have to handle deprecation behavior
|
34
|
+
if wmiclass.is_a?(Hash)
|
35
|
+
@options.merge!(wmiclass)
|
36
|
+
else
|
37
|
+
warn '[DEPRECATION] `wmi(\'wmiclass\')` is deprecated. Please use `wmi({class: \'wmiclass\'})` instead.'
|
38
|
+
@options[:class] = wmiclass
|
39
|
+
end
|
34
40
|
end
|
35
41
|
|
36
42
|
# returns nil, if not existant or value
|
@@ -40,36 +46,69 @@ module Inspec::Resources
|
|
40
46
|
keys.shift if keys.is_a?(Array) && keys[0] == :[]
|
41
47
|
|
42
48
|
# map all symbols to strings
|
43
|
-
keys = keys.map
|
49
|
+
keys = keys.map { |x| x.to_s.downcase } if keys.is_a?(Array)
|
44
50
|
|
45
51
|
value(keys)
|
46
52
|
end
|
47
53
|
|
48
54
|
def value(key)
|
49
|
-
extract_value(key,
|
55
|
+
extract_value(key, params)
|
50
56
|
end
|
51
57
|
|
52
|
-
def
|
58
|
+
def params
|
53
59
|
return @content if defined?(@content)
|
54
60
|
@content = {}
|
55
61
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
62
|
+
# abort if no options are available
|
63
|
+
return @content unless defined?(@options)
|
64
|
+
|
65
|
+
# filter for supported options
|
66
|
+
args = @options.select { |key, _value| [:class, :namespace, :query, :filter].include?(key) }
|
59
67
|
|
60
|
-
#
|
61
|
-
|
62
|
-
|
68
|
+
# convert to Get-WmiObject arguments
|
69
|
+
params = ''
|
70
|
+
args.each { |key, value| params += " -#{key} \"#{value}\"" }
|
71
|
+
|
72
|
+
# run wmi command and filter empty wmi
|
73
|
+
script = <<-EOH
|
74
|
+
Filter Aggregate
|
75
|
+
{
|
76
|
+
$arr = @{}
|
77
|
+
$_.properties | % {
|
78
|
+
$arr.Add($_.name, $_.value)
|
79
|
+
}
|
80
|
+
$arr
|
81
|
+
}
|
82
|
+
Get-WmiObject #{params} | Aggregate | ConvertTo-Json
|
83
|
+
EOH
|
63
84
|
|
64
85
|
# run wmi command
|
65
|
-
cmd = inspec.
|
86
|
+
cmd = inspec.powershell(script)
|
66
87
|
@content = JSON.parse(cmd.stdout)
|
88
|
+
|
89
|
+
# make all keys case-insensitive
|
90
|
+
@content = lowercase_keys(@content)
|
67
91
|
rescue JSON::ParserError => _e
|
68
92
|
@content
|
69
93
|
end
|
70
94
|
|
71
95
|
def to_s
|
72
|
-
"WMI
|
96
|
+
"WMI with #{@options}"
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def lowercase_keys(content)
|
102
|
+
if content.is_a?(Hash)
|
103
|
+
content.keys.each do |key|
|
104
|
+
new_key = key.to_s.downcase
|
105
|
+
content[new_key] = content.delete(key)
|
106
|
+
lowercase_keys(content[new_key])
|
107
|
+
end
|
108
|
+
elsif content.respond_to?(:each)
|
109
|
+
content.each { |item| lowercase_keys(item) }
|
110
|
+
end
|
111
|
+
content
|
73
112
|
end
|
74
113
|
end
|
75
114
|
end
|
data/lib/utils/base_cli.rb
CHANGED
@@ -136,13 +136,11 @@ module Inspec
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def mark_text(text)
|
139
|
-
"\e[0;
|
139
|
+
"\e[0;36m#{text}\e[0m"
|
140
140
|
end
|
141
141
|
|
142
142
|
def headline(title)
|
143
|
-
puts title
|
144
|
-
title.each_char { print '-' }
|
145
|
-
puts
|
143
|
+
puts "\n== #{title}\n\n"
|
146
144
|
end
|
147
145
|
|
148
146
|
def li(entry)
|
@@ -25,6 +25,13 @@ if node['platform_family'] != 'windows'
|
|
25
25
|
content 'hello world'
|
26
26
|
end
|
27
27
|
|
28
|
+
file '/tmp/sfile' do
|
29
|
+
mode '7765'
|
30
|
+
owner 'root'
|
31
|
+
group gid
|
32
|
+
content 'hello suid/sgid/sticky'
|
33
|
+
end
|
34
|
+
|
28
35
|
directory '/tmp/folder' do
|
29
36
|
mode '0567'
|
30
37
|
owner 'root'
|
@@ -80,8 +80,8 @@ describe 'inspec exec with json formatter' do
|
|
80
80
|
actual = ex1.dup
|
81
81
|
|
82
82
|
src = actual.delete('source_location')
|
83
|
-
src[
|
84
|
-
src[
|
83
|
+
src['ref'].must_match %r{examples/profile/controls/example.rb$}
|
84
|
+
src['line'].must_equal 8
|
85
85
|
|
86
86
|
result = actual.delete('results')[0]
|
87
87
|
result.wont_be :nil?
|
@@ -18,7 +18,7 @@ describe 'inspec exec' do
|
|
18
18
|
\e[37m ○ gordon-1.0: Verify the version number of Gordon (1 skipped)\e[0m
|
19
19
|
\e[37m Can't find file \"/tmp/gordon/config.yaml\"\e[0m
|
20
20
|
"
|
21
|
-
stdout.must_include "\nSummary:
|
21
|
+
stdout.must_include "\nSummary: \e[32m4 successful\e[0m, \e[31m0 failures\e[0m, \e[37m1 skipped\e[0m\n"
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'executes a minimum metadata-only profile' do
|
@@ -32,7 +32,7 @@ Target: local://
|
|
32
32
|
|
33
33
|
No tests executed.\e[0m
|
34
34
|
|
35
|
-
Summary:
|
35
|
+
Summary: \e[32m0 successful\e[0m, \e[31m0 failures\e[0m, \e[37m0 skipped\e[0m
|
36
36
|
"
|
37
37
|
end
|
38
38
|
|
@@ -47,7 +47,7 @@ Target: local://
|
|
47
47
|
|
48
48
|
No tests executed.\e[0m
|
49
49
|
|
50
|
-
Summary:
|
50
|
+
Summary: \e[32m0 successful\e[0m, \e[31m0 failures\e[0m, \e[37m0 skipped\e[0m
|
51
51
|
"
|
52
52
|
end
|
53
53
|
|
@@ -66,7 +66,7 @@ Target: local://
|
|
66
66
|
\n (compared using ==)
|
67
67
|
\e[0m
|
68
68
|
|
69
|
-
Summary:
|
69
|
+
Summary: \e[32m1 successful\e[0m, \e[31m1 failures\e[0m, \e[37m1 skipped\e[0m
|
70
70
|
"
|
71
71
|
end
|
72
72
|
|
@@ -74,14 +74,14 @@ Summary: 1 successful 1 failures 1 skipped
|
|
74
74
|
out = inspec('exec ' + example_profile + ' --controls tmp-1.0')
|
75
75
|
out.stderr.must_equal ''
|
76
76
|
out.exit_status.must_equal 0
|
77
|
-
out.stdout.must_include "\nSummary:
|
77
|
+
out.stdout.must_include "\nSummary: \e[32m1 successful\e[0m, \e[31m0 failures\e[0m, \e[37m0 skipped\e[0m\n"
|
78
78
|
end
|
79
79
|
|
80
80
|
it 'can execute a simple file with the default formatter' do
|
81
81
|
out = inspec('exec ' + example_control)
|
82
82
|
out.stderr.must_equal ''
|
83
83
|
out.exit_status.must_equal 0
|
84
|
-
out.stdout.must_include
|
84
|
+
out.stdout.must_include "\nSummary: \e[32m2 successful\e[0m, \e[31m0 failures\e[0m, \e[37m0 skipped\e[0m\n"
|
85
85
|
end
|
86
86
|
|
87
87
|
describe 'with a profile that is not supported on this OS/platform' do
|
@@ -67,7 +67,8 @@ describe 'inspec json' do
|
|
67
67
|
|
68
68
|
it 'has a source location' do
|
69
69
|
loc = File.join(example_profile, '/controls/example.rb')
|
70
|
-
control['source_location'].must_equal
|
70
|
+
control['source_location']['ref'].must_equal loc
|
71
|
+
control['source_location']['line'].must_equal 8
|
71
72
|
end
|
72
73
|
|
73
74
|
it 'has a the source code' do
|
@@ -26,10 +26,11 @@ describe 'command tests' do
|
|
26
26
|
out.stderr.must_equal ''
|
27
27
|
out.exit_status.must_equal 0
|
28
28
|
std = out.stdout
|
29
|
-
std.must_include
|
30
|
-
std.must_include
|
31
|
-
std.must_include
|
32
|
-
std.must_include
|
29
|
+
std.must_include "\n== Operating System Details\n\n"
|
30
|
+
std.must_include "\nName: \e[0;36m"
|
31
|
+
std.must_include "\nFamily: \e[0;36m"
|
32
|
+
std.must_include "\nArch: \e[0;36m"
|
33
|
+
std.must_include "\nRelease: \e[0;36m"
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
data/test/helper.rb
CHANGED
@@ -243,7 +243,7 @@ class MockLoader
|
|
243
243
|
# xinetd configuration
|
244
244
|
'find /etc/xinetd.d -type f' => cmd.call('find-xinetd.d'),
|
245
245
|
# wmi test
|
246
|
-
"
|
246
|
+
"4762fab9e8180997634ae70aae6d5f59e641084111fb9f5e5bf2848a583aa5f5" => cmd.call('get-wmiobject'),
|
247
247
|
#user info on hpux
|
248
248
|
"logins -x -l root" => cmd.call('logins-x'),
|
249
249
|
#packages on hpux
|
@@ -100,4 +100,16 @@ if os.linux?
|
|
100
100
|
it { should_not cmp < 3 }
|
101
101
|
it { should_not cmp /something/ }
|
102
102
|
end
|
103
|
+
|
104
|
+
describe true do
|
105
|
+
it { should cmp 'true' }
|
106
|
+
it { should cmp 'True' }
|
107
|
+
it { should cmp true }
|
108
|
+
end
|
109
|
+
|
110
|
+
describe false do
|
111
|
+
it { should cmp 'false' }
|
112
|
+
it { should cmp 'False' }
|
113
|
+
it { should cmp false }
|
114
|
+
end
|
103
115
|
end
|
@@ -61,6 +61,9 @@ if os.unix?
|
|
61
61
|
it { should be_mode 00765 }
|
62
62
|
its('mode') { should cmp 0765 }
|
63
63
|
its('mode') { should_not cmp 0777 }
|
64
|
+
its('suid') { should eq false }
|
65
|
+
its('sgid') { should eq false }
|
66
|
+
its('sticky') { should eq false }
|
64
67
|
|
65
68
|
it { should be_readable }
|
66
69
|
it { should be_readable.by('owner') }
|
@@ -107,6 +110,12 @@ if os.unix?
|
|
107
110
|
its('type') { should eq :file }
|
108
111
|
end
|
109
112
|
|
113
|
+
describe file('/tmp/file') do
|
114
|
+
its('suid') { should eq true }
|
115
|
+
its('sgid') { should eq true }
|
116
|
+
its('sticky') { should eq true }
|
117
|
+
end
|
118
|
+
|
110
119
|
describe file('/tmp/folder') do
|
111
120
|
it { should exist }
|
112
121
|
it { should be_directory }
|
@@ -2,27 +2,62 @@
|
|
2
2
|
|
3
3
|
return unless os.windows?
|
4
4
|
|
5
|
-
# Get-WmiObject win32_service
|
6
|
-
# Get-WmiObject -class win32_service
|
5
|
+
# Get-WmiObject win32_service or Get-WmiObject -class win32_service
|
7
6
|
# returns an array of service objects
|
8
|
-
describe wmi('win32_service') do
|
9
|
-
its(['Path','ClassName']) { should include 'Win32_Service' }
|
7
|
+
describe wmi({class: 'win32_service'}) do
|
10
8
|
its('DisplayName') { should include 'Windows Remote Management (WS-Management)'}
|
11
9
|
end
|
12
10
|
|
13
|
-
# Use win32_service with filter
|
14
|
-
|
15
|
-
|
11
|
+
# Use win32_service with filter, it returns a single service object
|
12
|
+
describe wmi({
|
13
|
+
class: 'win32_service',
|
16
14
|
filter: "name like '%winrm%'"
|
17
15
|
}) do
|
18
|
-
its(
|
16
|
+
its('Status') { should cmp 'ok' }
|
17
|
+
its('State') { should cmp 'Running' }
|
18
|
+
its('ExitCode') { should cmp 0 }
|
19
19
|
its('DisplayName') { should eq 'Windows Remote Management (WS-Management)'}
|
20
20
|
end
|
21
21
|
|
22
22
|
# TODO: this works on domain controllers only
|
23
|
+
describe wmi({
|
24
|
+
class: 'RSOP_SecuritySettingNumeric',
|
25
|
+
namespace: 'root\\rsop\\computer',
|
26
|
+
filter: 'KeyName = \'MinimumPasswordAge\' And precedence=1'
|
27
|
+
}) do
|
28
|
+
its('Setting') { should eq 1 }
|
29
|
+
end
|
30
|
+
|
31
|
+
# new syntax
|
32
|
+
describe wmi({
|
33
|
+
namespace: 'root\rsop\computer',
|
34
|
+
query: "SELECT Setting FROM RSOP_SecuritySettingBoolean WHERE KeyName='LSAAnonymousNameLookup' AND Precedence=1"
|
35
|
+
}) do
|
36
|
+
its('Setting') { should eq false }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe wmi({
|
40
|
+
namespace: 'root\cimv2',
|
41
|
+
query: 'SELECT filesystem FROM win32_logicaldisk WHERE drivetype=3'
|
42
|
+
}).params.values.join do
|
43
|
+
it { should eq 'NTFS' }
|
44
|
+
end
|
45
|
+
|
46
|
+
# deprecated syntax
|
47
|
+
describe wmi('win32_service') do
|
48
|
+
its('DisplayName') { should include 'Windows Remote Management (WS-Management)'}
|
49
|
+
end
|
50
|
+
|
23
51
|
describe wmi('RSOP_SecuritySettingNumeric', {
|
24
52
|
namespace: 'root\\rsop\\computer',
|
25
53
|
filter: 'KeyName = \'MinimumPasswordAge\' And precedence=1'
|
26
54
|
}) do
|
27
55
|
its('Setting') { should eq 1 }
|
56
|
+
its('setting') { should eq 1 }
|
57
|
+
end
|
58
|
+
|
59
|
+
describe wmi('win32_service', {
|
60
|
+
filter: "name like '%winrm%'"
|
61
|
+
}) do
|
62
|
+
its('DisplayName') { should eq 'Windows Remote Management (WS-Management)'}
|
28
63
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
{
|
2
|
-
"Path": {
|
3
|
-
"ClassName": "Win32_Service"
|
4
|
-
},
|
5
|
-
"Caption": "Windows Remote Management (WS-Management)",
|
6
|
-
"CreationClassName": "Win32_Service",
|
7
2
|
"DisplayName": "Windows Remote Management (WS-Management)",
|
3
|
+
"Caption": "Windows Remote Management (WS-Management)",
|
4
|
+
"DesktopInteract": false,
|
8
5
|
"Name": "WinRM",
|
9
|
-
"
|
6
|
+
"StartMode": "Auto",
|
7
|
+
"ExitCode": 0,
|
8
|
+
"Status": "OK"
|
10
9
|
}
|
@@ -51,7 +51,7 @@ describe 'Inspec::Resources::Service' do
|
|
51
51
|
# ubuntu 15.04 with systemd
|
52
52
|
it 'verify ubuntu package parsing' do
|
53
53
|
resource = MockLoader.new(:ubuntu1504).load_resource('service', 'sshd')
|
54
|
-
params = Hashie::Mash.new({ 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
54
|
+
params = Hashie::Mash.new({ 'ActiveState' => 'active', 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
55
55
|
_(resource.type).must_equal 'systemd'
|
56
56
|
_(resource.name).must_equal 'sshd.service'
|
57
57
|
_(resource.description).must_equal 'OpenSSH server daemon'
|
@@ -64,7 +64,7 @@ describe 'Inspec::Resources::Service' do
|
|
64
64
|
|
65
65
|
it 'verify ubuntu package parsing with default systemd_service' do
|
66
66
|
resource = MockLoader.new(:ubuntu1504).load_resource('systemd_service', 'sshd')
|
67
|
-
params = Hashie::Mash.new({ 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
67
|
+
params = Hashie::Mash.new({ 'ActiveState' => 'active', 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
68
68
|
_(resource.type).must_equal 'systemd'
|
69
69
|
_(resource.name).must_equal 'sshd.service'
|
70
70
|
_(resource.description).must_equal 'OpenSSH server daemon'
|
@@ -103,7 +103,7 @@ describe 'Inspec::Resources::Service' do
|
|
103
103
|
# centos 7 with systemd
|
104
104
|
it 'verify centos 7 package parsing' do
|
105
105
|
resource = MockLoader.new(:centos7).load_resource('service', 'sshd')
|
106
|
-
params = Hashie::Mash.new({ 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
106
|
+
params = Hashie::Mash.new({ 'ActiveState' => 'active', 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
107
107
|
_(resource.type).must_equal 'systemd'
|
108
108
|
_(resource.name).must_equal 'sshd.service'
|
109
109
|
_(resource.description).must_equal 'OpenSSH server daemon'
|
@@ -115,7 +115,7 @@ describe 'Inspec::Resources::Service' do
|
|
115
115
|
|
116
116
|
it 'verify centos 7 package parsing with systemd_service and service_ctl override' do
|
117
117
|
resource = MockLoader.new(:centos7).load_resource('systemd_service', 'sshd', '/path/to/systemctl')
|
118
|
-
params = Hashie::Mash.new({ 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', '
|
118
|
+
params = Hashie::Mash.new({ 'ActiveState' => 'active', 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'UnitFileState' => 'enabled', 'SubState' => 'running' })
|
119
119
|
_(resource.type).must_equal 'systemd'
|
120
120
|
_(resource.name).must_equal 'sshd.service'
|
121
121
|
_(resource.description).must_equal 'OpenSSH server daemon'
|
@@ -166,7 +166,7 @@ describe 'Inspec::Resources::Service' do
|
|
166
166
|
# arch linux with systemd
|
167
167
|
it 'verify arch linux package parsing' do
|
168
168
|
resource = MockLoader.new(:arch).load_resource('service', 'sshd')
|
169
|
-
params = Hashie::Mash.new({ 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
169
|
+
params = Hashie::Mash.new({ 'ActiveState' => 'active', 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
170
170
|
_(resource.type).must_equal 'systemd'
|
171
171
|
_(resource.name).must_equal 'sshd.service'
|
172
172
|
_(resource.description).must_equal 'OpenSSH server daemon'
|
@@ -192,7 +192,7 @@ describe 'Inspec::Resources::Service' do
|
|
192
192
|
# debian 8 with systemd
|
193
193
|
it 'verify debian 8 package parsing' do
|
194
194
|
resource = MockLoader.new(:debian8).load_resource('service', 'sshd')
|
195
|
-
params = Hashie::Mash.new({ 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
195
|
+
params = Hashie::Mash.new({ 'ActiveState' => 'active', 'Description' => 'OpenSSH server daemon', 'Id' => 'sshd.service', 'LoadState' => 'loaded', 'Names' => 'sshd.service', 'SubState' => 'running', 'UnitFileState' => 'enabled' })
|
196
196
|
_(resource.type).must_equal 'systemd'
|
197
197
|
_(resource.name).must_equal 'sshd.service'
|
198
198
|
_(resource.description).must_equal 'OpenSSH server daemon'
|
@@ -8,7 +8,8 @@ require 'inspec/resource'
|
|
8
8
|
describe 'Inspec::Resources::WMI' do
|
9
9
|
|
10
10
|
# Check the following as unit test
|
11
|
-
# describe wmi(
|
11
|
+
# describe wmi({
|
12
|
+
# class: 'win32_service',
|
12
13
|
# filter: "name like '%winrm%'"
|
13
14
|
# }) do
|
14
15
|
# its(['Path','ClassName']) { should eq 'Win32_Service' }
|
@@ -17,29 +18,25 @@ describe 'Inspec::Resources::WMI' do
|
|
17
18
|
|
18
19
|
# windows
|
19
20
|
it 'verify wmi parsing on windows' do
|
20
|
-
resource = MockLoader.new(:windows).load_resource('wmi', 'win32_service',
|
21
|
+
resource = MockLoader.new(:windows).load_resource('wmi', {class: 'win32_service', filter: "name like '%winrm%'" })
|
21
22
|
_(resource.send('DisplayName')).must_equal 'Windows Remote Management (WS-Management)'
|
22
|
-
_(resource.send('method_missing', 'Path', 'ClassName')).must_equal 'Win32_Service'
|
23
23
|
end
|
24
24
|
|
25
25
|
# ubuntu 14.04 with upstart
|
26
26
|
it 'fail wmi on ubuntu' do
|
27
|
-
resource = MockLoader.new(:ubuntu1404).load_resource('wmi', 'win32_service',
|
27
|
+
resource = MockLoader.new(:ubuntu1404).load_resource('wmi', {class: 'win32_service', filter: "name like '%winrm%'" })
|
28
28
|
_(resource.send('DisplayName')).must_equal nil
|
29
|
-
_(resource.send('method_missing', 'Path', 'ClassName')).must_equal nil
|
30
29
|
end
|
31
30
|
|
32
31
|
# centos 7 with systemd
|
33
32
|
it 'fail wmi on centos' do
|
34
|
-
resource = MockLoader.new(:centos7).load_resource('wmi', 'win32_service',
|
33
|
+
resource = MockLoader.new(:centos7).load_resource('wmi', {class: 'win32_service', filter: "name like '%winrm%'" })
|
35
34
|
_(resource.send('DisplayName')).must_equal nil
|
36
|
-
_(resource.send('method_missing', 'Path', 'ClassName')).must_equal nil
|
37
35
|
end
|
38
36
|
|
39
37
|
# unknown OS
|
40
38
|
it 'fail wmi on unknown os' do
|
41
|
-
resource = MockLoader.new(:undefined).load_resource('wmi', 'win32_service',
|
39
|
+
resource = MockLoader.new(:undefined).load_resource('wmi', {class: 'win32_service', filter: "name like '%winrm%'" })
|
42
40
|
_(resource.send('DisplayName')).must_equal nil
|
43
|
-
_(resource.send('method_missing', 'Path', 'ClassName')).must_equal nil
|
44
41
|
end
|
45
42
|
end
|
metadata
CHANGED
@@ -1,29 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.27.0
|
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-
|
11
|
+
date: 2016-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: train
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.15.1
|
20
|
+
- - "<"
|
18
21
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0
|
22
|
+
version: '1.0'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
|
-
- - "
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.15.1
|
30
|
+
- - "<"
|
25
31
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0
|
32
|
+
version: '1.0'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: thor
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -240,10 +246,12 @@ files:
|
|
240
246
|
- lib/bundles/inspec-compliance/cli.rb
|
241
247
|
- lib/bundles/inspec-compliance/configuration.rb
|
242
248
|
- lib/bundles/inspec-compliance/http.rb
|
249
|
+
- lib/bundles/inspec-compliance/images/cc-token.png
|
243
250
|
- lib/bundles/inspec-compliance/support.rb
|
244
251
|
- lib/bundles/inspec-compliance/target.rb
|
245
252
|
- lib/bundles/inspec-compliance/test/integration/default/cli.rb
|
246
253
|
- lib/bundles/inspec-init.rb
|
254
|
+
- lib/bundles/inspec-init/README.md
|
247
255
|
- lib/bundles/inspec-init/cli.rb
|
248
256
|
- lib/bundles/inspec-init/templates/profile/README.md
|
249
257
|
- lib/bundles/inspec-init/templates/profile/controls/example.rb
|
@@ -413,7 +421,7 @@ files:
|
|
413
421
|
- test/integration/default/apache_conf_spec.rb
|
414
422
|
- test/integration/default/apt_spec.rb
|
415
423
|
- test/integration/default/auditd_rules_spec.rb
|
416
|
-
- test/integration/default/
|
424
|
+
- test/integration/default/cmp_matcher_spec.rb
|
417
425
|
- test/integration/default/csv_spec.rb
|
418
426
|
- test/integration/default/etc_group_spec.rb
|
419
427
|
- test/integration/default/file_spec.rb
|
@@ -697,7 +705,7 @@ test_files:
|
|
697
705
|
- test/integration/default/apache_conf_spec.rb
|
698
706
|
- test/integration/default/apt_spec.rb
|
699
707
|
- test/integration/default/auditd_rules_spec.rb
|
700
|
-
- test/integration/default/
|
708
|
+
- test/integration/default/cmp_matcher_spec.rb
|
701
709
|
- test/integration/default/csv_spec.rb
|
702
710
|
- test/integration/default/etc_group_spec.rb
|
703
711
|
- test/integration/default/file_spec.rb
|