inspec 0.26.0 → 0.27.0
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 +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
|
+

|
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
|