mirror of
https://github.com/inspec/inspec
synced 2024-11-14 17:07:09 +00:00
Merge remote-tracking branch 'origin/master' into apache_conf-symlinks
This commit is contained in:
commit
efa1b951ab
183 changed files with 8798 additions and 14992 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -19,3 +19,7 @@ habitat/VERSION
|
|||
habitat/results
|
||||
/.ruby-gemset
|
||||
/.ruby-version
|
||||
|
||||
www/source/index.html.slim
|
||||
|
||||
www/source/index.html.slim
|
||||
|
|
199
CHANGELOG.md
199
CHANGELOG.md
|
@ -1,7 +1,108 @@
|
|||
# Change Log
|
||||
|
||||
## [1.9.0](https://github.com/chef/inspec/tree/1.9.0) (2017-01-06)
|
||||
[Full Changelog](https://github.com/chef/inspec/compare/v1.8.0...1.9.0)
|
||||
## [1.14.1](https://github.com/chef/inspec/tree/1.14.1) (2017-02-10)
|
||||
[Full Changelog](https://github.com/chef/inspec/compare/v1.14.0...1.14.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- go /profiles service modifications [\#1483](https://github.com/chef/inspec/issues/1483)
|
||||
- inspec compliance login\* should support a hostname for the SERVER argument [\#1473](https://github.com/chef/inspec/issues/1473)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Skip packages resource for unsupported OS [\#1484](https://github.com/chef/inspec/pull/1484) ([alexpop](https://github.com/alexpop))
|
||||
- add Alex Pop to the list of maintainers [\#1481](https://github.com/chef/inspec/pull/1481) ([arlimus](https://github.com/arlimus))
|
||||
- remove Jason Reed from the list of maintainers [\#1480](https://github.com/chef/inspec/pull/1480) ([arlimus](https://github.com/arlimus))
|
||||
- Add Adam Leff as a maintainer [\#1479](https://github.com/chef/inspec/pull/1479) ([adamleff](https://github.com/adamleff))
|
||||
|
||||
## [v1.14.0](https://github.com/chef/inspec/tree/v1.14.0) (2017-02-08)
|
||||
[Full Changelog](https://github.com/chef/inspec/compare/v1.13.0...v1.14.0)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- map url to https for compliance plugin [\#1471](https://github.com/chef/inspec/pull/1471) ([arlimus](https://github.com/arlimus))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Display meaningful error message when uploading profiles to a server with self-signed certs [\#1469](https://github.com/chef/inspec/issues/1469)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Use RuboCop 0.39.0 \(same as chefstyle\) [\#1478](https://github.com/chef/inspec/pull/1478) ([tduffield](https://github.com/tduffield))
|
||||
- bugfix: warn users about insecure login requirements [\#1472](https://github.com/chef/inspec/pull/1472) ([arlimus](https://github.com/arlimus))
|
||||
- Add support for "inspec -v" showing the version [\#1470](https://github.com/chef/inspec/pull/1470) ([adamleff](https://github.com/adamleff))
|
||||
- Replace slack invite form on Community, fix surprise code example [\#1468](https://github.com/chef/inspec/pull/1468) ([adamleff](https://github.com/adamleff))
|
||||
|
||||
## [v1.13.0](https://github.com/chef/inspec/tree/v1.13.0) (2017-02-07)
|
||||
[Full Changelog](https://github.com/chef/inspec/compare/v1.12.0...v1.13.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- add "packages" resource [\#1458](https://github.com/chef/inspec/pull/1458) ([jtimberman](https://github.com/jtimberman))
|
||||
- Provide a way to force it vs its for any argument [\#1457](https://github.com/chef/inspec/pull/1457) ([alexpop](https://github.com/alexpop))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Ignore me [\#1464](https://github.com/chef/inspec/issues/1464)
|
||||
- redirect URL downloads.inspec.io to https://downloads.chef.io/inspec [\#1462](https://github.com/chef/inspec/issues/1462)
|
||||
|
||||
## [v1.12.0](https://github.com/chef/inspec/tree/v1.12.0) (2017-02-03)
|
||||
[Full Changelog](https://github.com/chef/inspec/compare/v1.11.0...v1.12.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Allow setting of the tests array [\#1455](https://github.com/chef/inspec/pull/1455) ([alexpop](https://github.com/alexpop))
|
||||
- switch to faraday as http backend [\#1452](https://github.com/chef/inspec/pull/1452) ([chris-rock](https://github.com/chris-rock))
|
||||
- Add FilterTable support to processes resource [\#1451](https://github.com/chef/inspec/pull/1451) ([alexpop](https://github.com/alexpop))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- `skip` parameter ignored inside `describe` block [\#1450](https://github.com/chef/inspec/issues/1450)
|
||||
|
||||
## [v1.11.0](https://github.com/chef/inspec/tree/v1.11.0) (2017-02-01)
|
||||
[Full Changelog](https://github.com/chef/inspec/compare/v1.10.0...v1.11.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- HTTP request resource [\#336](https://github.com/chef/inspec/issues/336)
|
||||
- derive xinetd protocol from socket\_type when not defined in the config file [\#1448](https://github.com/chef/inspec/pull/1448) ([alexpop](https://github.com/alexpop))
|
||||
- Add negate! support for describe.one object [\#1442](https://github.com/chef/inspec/pull/1442) ([alexpop](https://github.com/alexpop))
|
||||
- Version method for kernel\_module [\#1435](https://github.com/chef/inspec/pull/1435) ([postgred](https://github.com/postgred))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Fix xinetd parsing of services from the same file. Expose resource.protocols [\#1444](https://github.com/chef/inspec/pull/1444) ([alexpop](https://github.com/alexpop))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Make minor grammar/style changes to `inspec.io` [\#1441](https://github.com/chef/inspec/pull/1441) ([jerryaldrichiii](https://github.com/jerryaldrichiii))
|
||||
|
||||
## [v1.10.0](https://github.com/chef/inspec/tree/v1.10.0) (2017-01-26)
|
||||
[Full Changelog](https://github.com/chef/inspec/compare/v1.9.0...v1.10.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- fix functional tests [\#1429](https://github.com/chef/inspec/issues/1429)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- 1.10.0 [\#1433](https://github.com/chef/inspec/pull/1433) ([chris-rock](https://github.com/chris-rock))
|
||||
- improve http header handling [\#1432](https://github.com/chef/inspec/pull/1432) ([chris-rock](https://github.com/chris-rock))
|
||||
- use new devsec baseline [\#1431](https://github.com/chef/inspec/pull/1431) ([chris-rock](https://github.com/chris-rock))
|
||||
- 'execution' is spelled correctly [\#1428](https://github.com/chef/inspec/pull/1428) ([nathenharvey](https://github.com/nathenharvey))
|
||||
- Bug fixes + New Elements [\#1426](https://github.com/chef/inspec/pull/1426) ([hannah-radish](https://github.com/hannah-radish))
|
||||
- Docs: fix resource name \('processes' instead of 'process'\) [\#1423](https://github.com/chef/inspec/pull/1423) ([techraf](https://github.com/techraf))
|
||||
- update copyright of the year [\#1422](https://github.com/chef/inspec/pull/1422) ([chris-rock](https://github.com/chris-rock))
|
||||
- Link to the 1.0 release webinar [\#1419](https://github.com/chef/inspec/pull/1419) ([nathenharvey](https://github.com/nathenharvey))
|
||||
- Updated compliance api requests to actually use refresh token correctly [\#1416](https://github.com/chef/inspec/pull/1416) ([brentm5](https://github.com/brentm5))
|
||||
- Docs examples: use double quotes to prevent escaping backslash in the expected string [\#1413](https://github.com/chef/inspec/pull/1413) ([techraf](https://github.com/techraf))
|
||||
- Fixed error in OS docs, added CentOS to redhat family docs. [\#1407](https://github.com/chef/inspec/pull/1407) ([gscho](https://github.com/gscho))
|
||||
- Solicit talks for ChefConf [\#1405](https://github.com/chef/inspec/pull/1405) ([nathenharvey](https://github.com/nathenharvey))
|
||||
- Add an http test method [\#1403](https://github.com/chef/inspec/pull/1403) ([guilhem](https://github.com/guilhem))
|
||||
- new inspec.io frontpage [\#1362](https://github.com/chef/inspec/pull/1362) ([hannah-radish](https://github.com/hannah-radish))
|
||||
|
||||
## [v1.9.0](https://github.com/chef/inspec/tree/v1.9.0) (2017-01-06)
|
||||
[Full Changelog](https://github.com/chef/inspec/compare/v1.8.0...v1.9.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
|
@ -195,7 +296,6 @@
|
|||
|
||||
- Add file integration tests for docker [\#1277](https://github.com/chef/inspec/issues/1277)
|
||||
- Solaris Sudo Not Always In /usr/bin/sudo [\#1265](https://github.com/chef/inspec/issues/1265)
|
||||
- Link to robert\_config.rb is broken on inspec.io [\#1226](https://github.com/chef/inspec/issues/1226)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
|
@ -2001,19 +2101,10 @@
|
|||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- pretty-print resources [\#78](https://github.com/chef/inspec/issues/78)
|
||||
- Add networking resources [\#68](https://github.com/chef/inspec/issues/68)
|
||||
- Add WinRM transport layer [\#64](https://github.com/chef/inspec/issues/64)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- expose all necessary methods in OS resource [\#79](https://github.com/chef/inspec/issues/79)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- script resource [\#74](https://github.com/chef/inspec/issues/74)
|
||||
- add project docs [\#72](https://github.com/chef/inspec/issues/72)
|
||||
- OS detection on debian does not detect versions [\#39](https://github.com/chef/inspec/issues/39)
|
||||
- ensure all resources have a proper to\_s method [\#98](https://github.com/chef/inspec/issues/98)
|
||||
- Escape commands before we execute them [\#70](https://github.com/chef/inspec/issues/70)
|
||||
|
||||
|
@ -2040,90 +2131,6 @@
|
|||
- Improve unit tests [\#106](https://github.com/chef/inspec/pull/106) ([chris-rock](https://github.com/chris-rock))
|
||||
- add to\_s methods to resources, fixes \#98 [\#105](https://github.com/chef/inspec/pull/105) ([chris-rock](https://github.com/chris-rock))
|
||||
- 0.7.0 release [\#104](https://github.com/chef/inspec/pull/104) ([chris-rock](https://github.com/chris-rock))
|
||||
- implement iptables resource [\#103](https://github.com/chef/inspec/pull/103) ([chris-rock](https://github.com/chris-rock))
|
||||
- bugfix: return function if data is already cached [\#102](https://github.com/chef/inspec/pull/102) ([chris-rock](https://github.com/chris-rock))
|
||||
- implement apt resource [\#101](https://github.com/chef/inspec/pull/101) ([chris-rock](https://github.com/chris-rock))
|
||||
- improve shell [\#100](https://github.com/chef/inspec/pull/100) ([chris-rock](https://github.com/chris-rock))
|
||||
- implement host resource [\#99](https://github.com/chef/inspec/pull/99) ([chris-rock](https://github.com/chris-rock))
|
||||
- implement bridge resource [\#97](https://github.com/chef/inspec/pull/97) ([chris-rock](https://github.com/chris-rock))
|
||||
- interactive shell [\#95](https://github.com/chef/inspec/pull/95) ([arlimus](https://github.com/arlimus))
|
||||
- interface resource [\#94](https://github.com/chef/inspec/pull/94) ([chris-rock](https://github.com/chris-rock))
|
||||
- lint: dont use undefined vars [\#93](https://github.com/chef/inspec/pull/93) ([arlimus](https://github.com/arlimus))
|
||||
- fix delivery dependencies [\#92](https://github.com/chef/inspec/pull/92) ([arlimus](https://github.com/arlimus))
|
||||
- improvement: add default print method to resources [\#91](https://github.com/chef/inspec/pull/91) ([arlimus](https://github.com/arlimus))
|
||||
- extend os backend helper [\#90](https://github.com/chef/inspec/pull/90) ([chris-rock](https://github.com/chris-rock))
|
||||
- integrate docs [\#89](https://github.com/chef/inspec/pull/89) ([chris-rock](https://github.com/chris-rock))
|
||||
- integrate docs [\#88](https://github.com/chef/inspec/pull/88) ([chris-rock](https://github.com/chris-rock))
|
||||
- script resource [\#87](https://github.com/chef/inspec/pull/87) ([chris-rock](https://github.com/chris-rock))
|
||||
- implement group resource [\#85](https://github.com/chef/inspec/pull/85) ([chris-rock](https://github.com/chris-rock))
|
||||
- add author header [\#84](https://github.com/chef/inspec/pull/84) ([chris-rock](https://github.com/chris-rock))
|
||||
- Resource bugfix [\#83](https://github.com/chef/inspec/pull/83) ([arlimus](https://github.com/arlimus))
|
||||
- Resource in resource [\#80](https://github.com/chef/inspec/pull/80) ([arlimus](https://github.com/arlimus))
|
||||
- ignore local delivery config [\#77](https://github.com/chef/inspec/pull/77) ([arlimus](https://github.com/arlimus))
|
||||
- bugfix user resource for windows [\#76](https://github.com/chef/inspec/pull/76) ([chris-rock](https://github.com/chris-rock))
|
||||
- activate lint in travis [\#75](https://github.com/chef/inspec/pull/75) ([arlimus](https://github.com/arlimus))
|
||||
- Simplify SSL configuration [\#69](https://github.com/chef/inspec/pull/69) ([arlimus](https://github.com/arlimus))
|
||||
- implement user resource [\#67](https://github.com/chef/inspec/pull/67) ([chris-rock](https://github.com/chris-rock))
|
||||
- switch from open4 -\> mixlib-shellout [\#66](https://github.com/chef/inspec/pull/66) ([arlimus](https://github.com/arlimus))
|
||||
- WinRM path [\#63](https://github.com/chef/inspec/pull/63) ([arlimus](https://github.com/arlimus))
|
||||
- bugfix: catch cases where oneget returns an array [\#62](https://github.com/chef/inspec/pull/62) ([chris-rock](https://github.com/chris-rock))
|
||||
- extend delivery tests to extra docker images [\#61](https://github.com/chef/inspec/pull/61) ([arlimus](https://github.com/arlimus))
|
||||
- rename --key-file to --key on cli [\#60](https://github.com/chef/inspec/pull/60) ([arlimus](https://github.com/arlimus))
|
||||
- Simpleconfig groups [\#57](https://github.com/chef/inspec/pull/57) ([arlimus](https://github.com/arlimus))
|
||||
- OS detection tests [\#56](https://github.com/chef/inspec/pull/56) ([arlimus](https://github.com/arlimus))
|
||||
- Start Linting remaining resources [\#55](https://github.com/chef/inspec/pull/55) ([arlimus](https://github.com/arlimus))
|
||||
- fix various robocop lint issues [\#54](https://github.com/chef/inspec/pull/54) ([chris-rock](https://github.com/chris-rock))
|
||||
- overhaul rule structure [\#53](https://github.com/chef/inspec/pull/53) ([arlimus](https://github.com/arlimus))
|
||||
- Verify ssh transport backend [\#51](https://github.com/chef/inspec/pull/51) ([arlimus](https://github.com/arlimus))
|
||||
- Unit test for service resource [\#50](https://github.com/chef/inspec/pull/50) ([chris-rock](https://github.com/chris-rock))
|
||||
- Ssh backend tests [\#49](https://github.com/chef/inspec/pull/49) ([arlimus](https://github.com/arlimus))
|
||||
- Docker concurrency [\#48](https://github.com/chef/inspec/pull/48) ([arlimus](https://github.com/arlimus))
|
||||
- unit tests for package resource [\#47](https://github.com/chef/inspec/pull/47) ([chris-rock](https://github.com/chris-rock))
|
||||
- Docker runner test [\#46](https://github.com/chef/inspec/pull/46) ([arlimus](https://github.com/arlimus))
|
||||
- add port resource [\#45](https://github.com/chef/inspec/pull/45) ([chris-rock](https://github.com/chris-rock))
|
||||
- bugfix: windows server 2008 detection [\#44](https://github.com/chef/inspec/pull/44) ([arlimus](https://github.com/arlimus))
|
||||
- Add detect command [\#43](https://github.com/chef/inspec/pull/43) ([arlimus](https://github.com/arlimus))
|
||||
- unit test mock os [\#42](https://github.com/chef/inspec/pull/42) ([chris-rock](https://github.com/chris-rock))
|
||||
- let travis do dockerized resource tests [\#41](https://github.com/chef/inspec/pull/41) ([arlimus](https://github.com/arlimus))
|
||||
- docker test run [\#40](https://github.com/chef/inspec/pull/40) ([arlimus](https://github.com/arlimus))
|
||||
- bugfix: detect os via unames [\#38](https://github.com/chef/inspec/pull/38) ([arlimus](https://github.com/arlimus))
|
||||
- run kitchen test instead of converge [\#37](https://github.com/chef/inspec/pull/37) ([arlimus](https://github.com/arlimus))
|
||||
- bugfix: local file owner [\#36](https://github.com/chef/inspec/pull/36) ([arlimus](https://github.com/arlimus))
|
||||
- bugfix: backend description for local + docker [\#35](https://github.com/chef/inspec/pull/35) ([arlimus](https://github.com/arlimus))
|
||||
- implement fake os method for mock backend \(for now\) [\#34](https://github.com/chef/inspec/pull/34) ([chris-rock](https://github.com/chris-rock))
|
||||
- add Windows feature resource [\#33](https://github.com/chef/inspec/pull/33) ([chris-rock](https://github.com/chris-rock))
|
||||
- add linux kernel resources [\#32](https://github.com/chef/inspec/pull/32) ([chris-rock](https://github.com/chris-rock))
|
||||
- Exist vs exists [\#31](https://github.com/chef/inspec/pull/31) ([arlimus](https://github.com/arlimus))
|
||||
- File formats [\#30](https://github.com/chef/inspec/pull/30) ([chris-rock](https://github.com/chris-rock))
|
||||
- OS detection and resource [\#29](https://github.com/chef/inspec/pull/29) ([arlimus](https://github.com/arlimus))
|
||||
- bugfix: fix simplified runner configuration [\#28](https://github.com/chef/inspec/pull/28) ([chris-rock](https://github.com/chris-rock))
|
||||
- improvement: simplify runner configuration [\#27](https://github.com/chef/inspec/pull/27) ([arlimus](https://github.com/arlimus))
|
||||
- bugfix: catch cases, where no service is available [\#26](https://github.com/chef/inspec/pull/26) ([chris-rock](https://github.com/chris-rock))
|
||||
- support package for windows [\#25](https://github.com/chef/inspec/pull/25) ([chris-rock](https://github.com/chris-rock))
|
||||
- implement service for FreeBSD [\#24](https://github.com/chef/inspec/pull/24) ([chris-rock](https://github.com/chris-rock))
|
||||
- move integration dependencies to Gemfile [\#23](https://github.com/chef/inspec/pull/23) ([chris-rock](https://github.com/chris-rock))
|
||||
- add oracle linux docker tests [\#22](https://github.com/chef/inspec/pull/22) ([arlimus](https://github.com/arlimus))
|
||||
- Support FreeBSD [\#21](https://github.com/chef/inspec/pull/21) ([arlimus](https://github.com/arlimus))
|
||||
- Service resource [\#20](https://github.com/chef/inspec/pull/20) ([chris-rock](https://github.com/chris-rock))
|
||||
- Improvements [\#19](https://github.com/chef/inspec/pull/19) ([chris-rock](https://github.com/chris-rock))
|
||||
- bugfix: set host for ssh config in specinfra [\#18](https://github.com/chef/inspec/pull/18) ([chris-rock](https://github.com/chris-rock))
|
||||
- improve readme [\#17](https://github.com/chef/inspec/pull/17) ([chris-rock](https://github.com/chris-rock))
|
||||
- Integration tests for the backend runner [\#16](https://github.com/chef/inspec/pull/16) ([arlimus](https://github.com/arlimus))
|
||||
- Fix specinfra OS detection [\#15](https://github.com/chef/inspec/pull/15) ([arlimus](https://github.com/arlimus))
|
||||
- Os detection [\#14](https://github.com/chef/inspec/pull/14) ([chris-rock](https://github.com/chris-rock))
|
||||
- bugfix: require specinfra backend [\#13](https://github.com/chef/inspec/pull/13) ([chris-rock](https://github.com/chris-rock))
|
||||
- improve docker test runner structure [\#12](https://github.com/chef/inspec/pull/12) ([arlimus](https://github.com/arlimus))
|
||||
- Concurrent integrationtest [\#11](https://github.com/chef/inspec/pull/11) ([arlimus](https://github.com/arlimus))
|
||||
- add oneget resource [\#10](https://github.com/chef/inspec/pull/10) ([chris-rock](https://github.com/chris-rock))
|
||||
- Winrm [\#9](https://github.com/chef/inspec/pull/9) ([chris-rock](https://github.com/chris-rock))
|
||||
- bugfix: linux file stat parameters and mount [\#8](https://github.com/chef/inspec/pull/8) ([arlimus](https://github.com/arlimus))
|
||||
- Mysql conf [\#7](https://github.com/chef/inspec/pull/7) ([arlimus](https://github.com/arlimus))
|
||||
- Lint update [\#6](https://github.com/chef/inspec/pull/6) ([arlimus](https://github.com/arlimus))
|
||||
- SSH PTY [\#5](https://github.com/chef/inspec/pull/5) ([arlimus](https://github.com/arlimus))
|
||||
- Start Docker + SSH backends [\#4](https://github.com/chef/inspec/pull/4) ([arlimus](https://github.com/arlimus))
|
||||
- travis checks [\#3](https://github.com/chef/inspec/pull/3) ([chris-rock](https://github.com/chris-rock))
|
||||
- Package [\#2](https://github.com/chef/inspec/pull/2) ([chris-rock](https://github.com/chris-rock))
|
||||
- shared linux file handling + specinfra config + cleanup [\#1](https://github.com/chef/inspec/pull/1) ([arlimus](https://github.com/arlimus))
|
||||
|
||||
|
||||
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -14,12 +14,13 @@ group :test do
|
|||
gem 'bundler', '~> 1.5'
|
||||
gem 'minitest', '~> 5.5'
|
||||
gem 'rake', '~> 10'
|
||||
gem 'rubocop', '~> 0.36.0'
|
||||
gem 'rubocop', '= 0.39.0'
|
||||
gem 'simplecov', '~> 0.10'
|
||||
gem 'concurrent-ruby', '~> 0.9'
|
||||
gem 'mocha', '~> 1.1'
|
||||
gem 'ruby-progressbar', '~> 1.8'
|
||||
gem 'nokogiri', '~> 1.6'
|
||||
gem 'webmock', '~> 2.3.2'
|
||||
end
|
||||
|
||||
group :integration do
|
||||
|
|
|
@ -27,4 +27,5 @@ To mention the team, use @chef/inspec-maintainers
|
|||
### Maintainers
|
||||
|
||||
* [Christoph Hartmann](https://github.com/chris-rock)
|
||||
* [Jason Reed](https://github.com/jcreedcmu)
|
||||
* [Adam Leff](https://github.com/adamleff)
|
||||
* [Alex Pop](https://github.com/alexpop)
|
||||
|
|
|
@ -25,7 +25,8 @@ project lead.
|
|||
|
||||
maintainers = [
|
||||
"chris-rock",
|
||||
"jcreedcmu"
|
||||
"adamleff",
|
||||
"alexpop"
|
||||
]
|
||||
|
||||
[people]
|
||||
|
@ -37,6 +38,10 @@ project lead.
|
|||
Name = "Christoph Hartmann"
|
||||
GitHub = "chris-rock"
|
||||
|
||||
[people.jcreedcmu]
|
||||
Name = "Jason Reed"
|
||||
GitHub = "jcreedcmu"
|
||||
[people.adamleff]
|
||||
Name = "Adam Leff"
|
||||
GitHub = "adamleff"
|
||||
|
||||
[people.alexpop]
|
||||
Name = "Alex Pop"
|
||||
GitHub = "alexpop"
|
||||
|
|
|
@ -87,7 +87,7 @@ The following examples show how to use this InSpec audit resource.
|
|||
### Test standard output (stdout)
|
||||
|
||||
describe command('echo hello') do
|
||||
its('stdout') { should eq 'hello\n' }
|
||||
its('stdout') { should eq "hello\n" }
|
||||
its('stderr') { should eq '' }
|
||||
its('exit_status') { should eq 0 }
|
||||
end
|
||||
|
@ -96,7 +96,7 @@ The following examples show how to use this InSpec audit resource.
|
|||
|
||||
describe command('>&2 echo error') do
|
||||
its('stdout') { should eq '' }
|
||||
its('stderr') { should eq 'error\n' }
|
||||
its('stderr') { should eq "error\n" }
|
||||
its('exit_status') { should eq 0 }
|
||||
end
|
||||
|
||||
|
|
62
docs/resources/crontab.md.erb
Normal file
62
docs/resources/crontab.md.erb
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
title: About the crontab Resource
|
||||
---
|
||||
|
||||
# crontab
|
||||
|
||||
Use the `crontab` InSpec audit resource to test the crontab entries for a particular user on the system.
|
||||
|
||||
## Syntax
|
||||
|
||||
A `crontab` resource block declares a user (which defaults to the current user, if not specified), and then the details to be tested, such as the schedule elements for each crontab entry or the commands itself:
|
||||
|
||||
describe crontab do
|
||||
its('commands') { should include '/some/scheduled/task.sh' }
|
||||
end
|
||||
|
||||
## Matchers
|
||||
|
||||
This InSpec audit resource has the following matchers:
|
||||
|
||||
### be
|
||||
|
||||
<%= partial "/shared/matcher_be" %>
|
||||
|
||||
### cmp
|
||||
|
||||
<%= partial "/shared/matcher_cmp" %>
|
||||
|
||||
### eq
|
||||
|
||||
<%= partial "/shared/matcher_eq" %>
|
||||
|
||||
### include
|
||||
|
||||
<%= partial "/shared/matcher_include" %>
|
||||
|
||||
### match
|
||||
|
||||
<%= partial "/shared/matcher_match" %>
|
||||
|
||||
## Examples
|
||||
|
||||
The following examples show how to use this InSpec audit resource.
|
||||
|
||||
### Test that root's crontab has a particular command
|
||||
|
||||
describe crontab('root') do
|
||||
its('commands') { should include '/path/to/some/script' }
|
||||
end
|
||||
|
||||
### Test that myuser's crontab entry for command '/home/myuser/build.sh' runs every minute
|
||||
|
||||
describe crontab('myuser').commands('/home/myuser/build.sh') do
|
||||
its('hours') { should cmp '*' }
|
||||
its('minutes') { should cmp '*' }
|
||||
end
|
||||
|
||||
### Test that the logged-in user's crontab has no tasks set to run on every hour and every minute
|
||||
|
||||
describe crontab.where({'hour' => '*', 'minute' => '*'}) do
|
||||
its('entries.length') { should cmp '0' }
|
||||
end
|
97
docs/resources/http.md.erb
Normal file
97
docs/resources/http.md.erb
Normal file
|
@ -0,0 +1,97 @@
|
|||
---
|
||||
title: About the http Resource
|
||||
---
|
||||
|
||||
# http
|
||||
|
||||
Use the `http` InSpec audit resource to test an http endpoint.
|
||||
|
||||
## Syntax
|
||||
|
||||
An `http` resource block declares the configuration settings to be tested:
|
||||
|
||||
describe http('url', auth: {user: 'user', pass: 'test'}, params: {params}, method: 'method', headers: {headers}, body: body) do
|
||||
its('status') { should eq number }
|
||||
its('body') { should eq 'body' }
|
||||
its('headers.name') { should eq 'header' }
|
||||
end
|
||||
|
||||
where
|
||||
|
||||
* `('url')` is the url to test
|
||||
* `{user: 'user', pass: 'test'}` may be specified for basic auth request
|
||||
* `{params}` may be specified for http request parameters
|
||||
* `'method'` may be specified for http request method (default to 'GET')
|
||||
* `{headers}` may be specified for http request headers
|
||||
* `body` may be specified for http request body
|
||||
|
||||
## Matchers
|
||||
|
||||
This InSpec audit resource has the following matchers:
|
||||
|
||||
### be
|
||||
|
||||
<%= partial "/shared/matcher_be" %>
|
||||
|
||||
### body
|
||||
|
||||
The `body` matcher tests body content of http response:
|
||||
|
||||
its('body') { should eq 'hello\n' }
|
||||
|
||||
### cmp
|
||||
|
||||
<%= partial "/shared/matcher_cmp" %>
|
||||
|
||||
### eq
|
||||
|
||||
<%= partial "/shared/matcher_eq" %>
|
||||
|
||||
### headers
|
||||
|
||||
The `headers` matcher returns an hash of all http headers:
|
||||
|
||||
its('headers') { should eq {} }
|
||||
|
||||
Individual headers can be tested via:
|
||||
|
||||
its('headers.Content-Type') { should cmp 'text/html' }
|
||||
|
||||
### include
|
||||
|
||||
<%= partial "/shared/matcher_include" %>
|
||||
|
||||
### match
|
||||
|
||||
<%= partial "/shared/matcher_match" %>
|
||||
|
||||
### status
|
||||
|
||||
The `status` matcher tests status of the http response:
|
||||
|
||||
its('status') { should eq 200 }
|
||||
|
||||
## Examples
|
||||
|
||||
The following examples show how to use this InSpec audit resource.
|
||||
|
||||
### Simple http test
|
||||
|
||||
For example, a service is listening on default http port can be tested like this:
|
||||
|
||||
describe http('http://localhost') do
|
||||
its('status') { should cmp 200 }
|
||||
end
|
||||
|
||||
### Complex http test
|
||||
|
||||
describe http('http://localhost:8080/ping',
|
||||
auth: {user: 'user', pass: 'test'},
|
||||
params: {format: 'html'},
|
||||
method: 'POST',
|
||||
headers: {'Content-Type' => 'application/json'},
|
||||
data: '{"data":{"a":"1","b":"five"}}') do
|
||||
its('status') { should cmp 200 }
|
||||
its('body') { should cmp 'pong' }
|
||||
its('headers.Content-Type') { should cmp 'text/html' }
|
||||
end
|
|
@ -49,6 +49,12 @@ The `be_loaded` matcher tests if the module is a loadable kernel module:
|
|||
|
||||
<%= partial "/shared/matcher_match" %>
|
||||
|
||||
### version
|
||||
|
||||
The `version` matcher tests if the named module version is on the system:
|
||||
|
||||
its(:version) { should eq '3.2.2' }
|
||||
|
||||
## Examples
|
||||
|
||||
The following examples show how to use this InSpec audit resource.
|
||||
|
@ -57,4 +63,5 @@ The following examples show how to use this InSpec audit resource.
|
|||
|
||||
describe kernel_module('bridge') do
|
||||
it { should be_loaded }
|
||||
its(:version) { should cmp >= '2.2.2' }
|
||||
end
|
||||
|
|
|
@ -56,7 +56,7 @@ The `os` audit resource includes a collection of helpers that enable more granul
|
|||
* `debian?`
|
||||
* `hpux?`
|
||||
* `linux?` (including Alpine Linux, Amazon Linux, ArchLinux, CoreOS, Exherbo, Fedora, Gentoo, and Slackware)
|
||||
* `redhat?`
|
||||
* `redhat?` (including CentOS)
|
||||
* `solaris?` (including Nexenta Core, OmniOS, Open Indiana, Solaris Open, and SmartOS)
|
||||
* `suse?`
|
||||
* `unix?`
|
||||
|
@ -103,7 +103,7 @@ Use `os[:family]` to enable more granular testing of platforms, platform names,
|
|||
* `:debian`
|
||||
* `:hpux`
|
||||
* `:linux`. For platforms that are part of the Linux family: `:alpine`, `:amazon`, `:arch`, `:coreos`, `:exherbo`, `:fedora`, `:gentoo`, and `:slackware`.
|
||||
* `:redhat`
|
||||
* `:redhat`. For platforms that are part of the Redhat family: `:centos`.
|
||||
* `:solaris`. For platforms that are part of the Solaris family: `:nexentacore`, `:omnios`, `:openindiana`, `:opensolaris`, and `:smartos`.
|
||||
* `:suse`
|
||||
* `:unix`
|
||||
|
@ -115,7 +115,7 @@ For example, both of the following tests should have the same result:
|
|||
describe port(69) do
|
||||
its('processes') { should include 'in.tftpd' }
|
||||
end
|
||||
elsif os[:family] == 'rhel'
|
||||
elsif os[:family] == 'redhat'
|
||||
describe port(69) do
|
||||
its('processes') { should include 'xinetd' }
|
||||
end
|
||||
|
@ -125,7 +125,7 @@ For example, both of the following tests should have the same result:
|
|||
describe port(69) do
|
||||
its('processes') { should include 'in.tftpd' }
|
||||
end
|
||||
elsif os[:rhel]
|
||||
elsif os[:redhat]
|
||||
describe port(69) do
|
||||
its('processes') { should include 'xinetd' }
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ title: About the sshd_config Resource
|
|||
|
||||
# sshd_config
|
||||
|
||||
Use the `sshd_config` InSpec audit resource to test configuration data for the OpenSSH daemon located at `/etc/ssh/sshd_config` on Linux and Unix platforms. sshd---the OpenSSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command executation, and data exchanges.
|
||||
Use the `sshd_config` InSpec audit resource to test configuration data for the OpenSSH daemon located at `/etc/ssh/sshd_config` on Linux and Unix platforms. sshd---the OpenSSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command execution, and data exchanges.
|
||||
|
||||
## Syntax
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# license: All rights reserved
|
||||
|
||||
# import full profile
|
||||
include_controls 'hardening/ssh-hardening'
|
||||
include_controls 'dev-sec/ssh-baseline'
|
||||
|
||||
# select only individual controls
|
||||
include_controls 'ssl-benchmark' do
|
||||
|
|
|
@ -7,7 +7,7 @@ license: Apache 2
|
|||
summary: InSpec Profile that is only consuming dependencies
|
||||
version: 0.2.0
|
||||
depends:
|
||||
- name: hardening/ssh-hardening # defaults to supermarket
|
||||
- name: dev-sec/ssh-baseline # defaults to supermarket
|
||||
- url: https://github.com/dev-sec/ssl-benchmark
|
||||
- name: windows-patch-benchmark
|
||||
url: https://github.com/chris-rock/windows-patch-benchmark
|
||||
|
|
|
@ -38,4 +38,5 @@ Gem::Specification.new do |spec|
|
|||
spec.add_dependency 'sslshake', '~> 1'
|
||||
spec.add_dependency 'parallel', '~> 1.9'
|
||||
spec.add_dependency 'rspec_junit_formatter', '~> 0.2.3'
|
||||
spec.add_dependency 'faraday', '>=0.9.0'
|
||||
end
|
||||
|
|
|
@ -154,17 +154,17 @@ module Artifact
|
|||
p = Pathname.new(path_to_profile)
|
||||
p = p.join('inspec.yml')
|
||||
if not p.exist?
|
||||
fail "#{path_to_profile} doesn't appear to be a valid Inspec profile"
|
||||
raise "#{path_to_profile} doesn't appear to be a valid Inspec profile"
|
||||
end
|
||||
yaml = YAML.load_file(p.to_s)
|
||||
yaml = yaml.to_hash
|
||||
|
||||
if not yaml.key? 'name'
|
||||
fail 'Profile is invalid, name is not defined'
|
||||
raise 'Profile is invalid, name is not defined'
|
||||
end
|
||||
|
||||
if not yaml.key? 'version'
|
||||
fail 'Profile is invalid, version is not defined'
|
||||
raise 'Profile is invalid, version is not defined'
|
||||
end
|
||||
rescue => e
|
||||
# rewrap it and pass it up to the CLI
|
||||
|
@ -212,15 +212,15 @@ module Artifact
|
|||
public_keyfile = "#{file_keyname}.pem.pub"
|
||||
puts "Looking for #{public_keyfile} to verify artifact"
|
||||
if not File.exist? public_keyfile
|
||||
fail "Can't find #{public_keyfile}"
|
||||
raise "Can't find #{public_keyfile}"
|
||||
end
|
||||
|
||||
if not VALID_PROFILE_DIGESTS.member? file_alg
|
||||
fail 'Invalid artifact digest algorithm detected'
|
||||
raise 'Invalid artifact digest algorithm detected'
|
||||
end
|
||||
|
||||
if not VALID_PROFILE_VERSIONS.member? file_version
|
||||
fail 'Invalid artifact version detected'
|
||||
raise 'Invalid artifact version detected'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ Please login using `inspec compliance login https://compliance.test --user admin
|
|||
[res.is_a?(Net::HTTPSuccess), res.body]
|
||||
end
|
||||
|
||||
# Use username and refresh_toke to get an API access token
|
||||
# Use username and refresh_token to get an API access token
|
||||
def self.get_token_via_refresh_token(url, refresh_token, insecure)
|
||||
uri = URI.parse("#{url}/login")
|
||||
req = Net::HTTP::Post.new(uri.path)
|
||||
|
@ -130,20 +130,27 @@ Please login using `inspec compliance login https://compliance.test --user admin
|
|||
end
|
||||
|
||||
def self.get_headers(config)
|
||||
token = get_token(config)
|
||||
if config['server_type'] == 'automate'
|
||||
headers = { 'chef-delivery-enterprise' => config['automate']['ent'] }
|
||||
if config['automate']['token_type'] == 'dctoken'
|
||||
headers['x-data-collector-token'] = config['token']
|
||||
headers['x-data-collector-token'] = token
|
||||
else
|
||||
headers['chef-delivery-user'] = config['user']
|
||||
headers['chef-delivery-token'] = config['token']
|
||||
headers['chef-delivery-token'] = token
|
||||
end
|
||||
else
|
||||
headers = { 'Authorization' => "Bearer #{config['token']}" }
|
||||
headers = { 'Authorization' => "Bearer #{token}" }
|
||||
end
|
||||
headers
|
||||
end
|
||||
|
||||
def self.get_token(config)
|
||||
return config['token'] unless config['refresh_token']
|
||||
_success, _msg, token = get_token_via_refresh_token(config['server'], config['refresh_token'], config['insecure'])
|
||||
token
|
||||
end
|
||||
|
||||
def self.target_url(config, profile)
|
||||
if config['server_type'] == 'automate'
|
||||
target = "#{config['server']}/#{profile}/tar"
|
||||
|
|
|
@ -179,7 +179,7 @@ module Compliance
|
|||
end
|
||||
|
||||
# determine user information
|
||||
if config['token'].nil? || config['user'].nil?
|
||||
if (config['token'].nil? && config['refresh_token'].nil?) || config['user'].nil?
|
||||
error.call('Please login via `inspec compliance login`')
|
||||
end
|
||||
|
||||
|
@ -287,11 +287,10 @@ module Compliance
|
|||
end
|
||||
|
||||
def login_refreshtoken(url, options)
|
||||
success, msg, access_token = Compliance::API.get_token_via_refresh_token(url, options['refresh_token'], options['insecure'])
|
||||
success, msg, _access_token = Compliance::API.get_token_via_refresh_token(url, options['refresh_token'], options['insecure'])
|
||||
if success
|
||||
config = Compliance::Configuration.new
|
||||
config['server'] = url
|
||||
config['token'] = access_token
|
||||
config['insecure'] = options['insecure']
|
||||
config['version'] = Compliance::API.version(url, options['insecure'])
|
||||
config['server_type'] = 'compliance'
|
||||
|
@ -344,11 +343,10 @@ module Compliance
|
|||
success = true
|
||||
msg = 'API refresh token stored'
|
||||
else
|
||||
success, msg, access_token = Compliance::API.get_token_via_refresh_token(url, refresh_token, insecure)
|
||||
success, msg, _access_token= Compliance::API.get_token_via_refresh_token(url, refresh_token, insecure)
|
||||
if success
|
||||
config['token'] = access_token
|
||||
config.store
|
||||
msg = 'API access token verified and stored'
|
||||
msg = 'API access token verified'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ module Compliance
|
|||
class HTTP
|
||||
# generic get requires
|
||||
def self.get(url, headers = nil, insecure)
|
||||
url = "https://#{url}" if URI.parse(url).scheme.nil?
|
||||
uri = URI.parse(url)
|
||||
req = Net::HTTP::Get.new(uri.path)
|
||||
if !headers.nil?
|
||||
|
@ -38,7 +39,7 @@ module Compliance
|
|||
# post a file
|
||||
def self.post_file(url, headers, file_path, insecure)
|
||||
uri = URI.parse(url)
|
||||
fail "Unable to parse URL: #{url}" if uri.nil? || uri.host.nil?
|
||||
raise "Unable to parse URL: #{url}" if uri.nil? || uri.host.nil?
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
|
||||
# set connection flags
|
||||
|
@ -67,11 +68,18 @@ module Compliance
|
|||
}
|
||||
opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if insecure
|
||||
|
||||
fail "Unable to parse URI: #{uri}" if uri.nil? || uri.host.nil?
|
||||
res = Net::HTTP.start(uri.host, uri.port, opts) {|http|
|
||||
raise "Unable to parse URI: #{uri}" if uri.nil? || uri.host.nil?
|
||||
res = Net::HTTP.start(uri.host, uri.port, opts) { |http|
|
||||
http.request(req)
|
||||
}
|
||||
res
|
||||
|
||||
rescue OpenSSL::SSL::SSLError => e
|
||||
raise e unless e.message.include? 'certificate verify failed'
|
||||
|
||||
puts "Error: Failed to connect to #{uri}."
|
||||
puts 'If the server uses a self-signed certificate, please re-run the login command with the --insecure option.'
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ module Compliance
|
|||
class Fetcher < Fetchers::Url
|
||||
name 'compliance'
|
||||
priority 500
|
||||
def self.resolve(target) # rubocop:disable PerceivedComplexity, Metrics/CyclomaticComplexity
|
||||
def self.resolve(target) # rubocop:disable PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
||||
uri = if target.is_a?(String) && URI(target).scheme == 'compliance'
|
||||
URI(target)
|
||||
elsif target.respond_to?(:key?) && target.key?(:compliance)
|
||||
|
@ -29,7 +29,7 @@ module Compliance
|
|||
else
|
||||
# check if we have a compliance token
|
||||
config = Compliance::Configuration.new
|
||||
if config['token'].nil?
|
||||
if config['token'].nil? && config['refresh_token'].nil?
|
||||
if config['server_type'] == 'automate'
|
||||
server = 'automate'
|
||||
msg = 'inspec compliance login_automate https://your_automate_server --user USER --ent ENT --dctoken DCTOKEN or --usertoken USERTOKEN'
|
||||
|
@ -37,7 +37,7 @@ module Compliance
|
|||
server = 'compliance'
|
||||
msg = "inspec compliance login https://your_compliance_server --user admin --insecure --token 'PASTE TOKEN HERE' "
|
||||
end
|
||||
fail Inspec::FetcherFailure, <<EOF
|
||||
raise Inspec::FetcherFailure, <<EOF
|
||||
|
||||
Cannot fetch #{uri} because your #{server} token has not been
|
||||
configured.
|
||||
|
@ -51,10 +51,13 @@ EOF
|
|||
# verifies that the target e.g base/ssh exists
|
||||
profile = uri.host + uri.path
|
||||
if !Compliance::API.exist?(config, profile)
|
||||
fail Inspec::FetcherFailure, "The compliance profile #{profile} was not found on the configured compliance server"
|
||||
raise Inspec::FetcherFailure, "The compliance profile #{profile} was not found on the configured compliance server"
|
||||
end
|
||||
profile_fetch_url = Compliance::API.target_url(config, profile)
|
||||
end
|
||||
# We need to pass the token to the fetcher
|
||||
config['token'] = Compliance::API.get_token(config)
|
||||
|
||||
new(profile_fetch_url, config)
|
||||
rescue URI::Error => _e
|
||||
nil
|
||||
|
|
|
@ -45,7 +45,7 @@ module Supermarket
|
|||
"#{p['tool_owner']}/#{p['slug']}" == profile
|
||||
}
|
||||
|
||||
if found.length == 0
|
||||
if found.empty?
|
||||
puts "#{mark_text(profile)} is not available on Supermarket"
|
||||
return
|
||||
end
|
||||
|
|
|
@ -86,7 +86,7 @@ module Fetchers
|
|||
cmd = shellout("git ls-remote \"#{@remote_url}\" \"#{ref_name}*\"")
|
||||
ref = parse_ls_remote(cmd.stdout, ref_name)
|
||||
if !ref
|
||||
fail "Unable to resolve #{ref_name} to a specific git commit for #{@remote_url}"
|
||||
raise "Unable to resolve #{ref_name} to a specific git commit for #{@remote_url}"
|
||||
end
|
||||
ref
|
||||
end
|
||||
|
|
|
@ -17,12 +17,12 @@ module Inspec
|
|||
name = Train.validate_backend(conf)
|
||||
transport = Train.create(name, conf)
|
||||
if transport.nil?
|
||||
fail "Can't find transport backend '#{name}'."
|
||||
raise "Can't find transport backend '#{name}'."
|
||||
end
|
||||
|
||||
connection = transport.connection
|
||||
if connection.nil?
|
||||
fail "Can't connect to transport backend '#{name}'."
|
||||
raise "Can't connect to transport backend '#{name}'."
|
||||
end
|
||||
|
||||
cls = Class.new do
|
||||
|
|
|
@ -142,7 +142,7 @@ module Inspec
|
|||
$stderr.puts exception.message
|
||||
exit(1)
|
||||
else
|
||||
raise exception # rubocop:disable Style/SignalException
|
||||
raise exception
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ module Inspec
|
|||
@fetcher = Inspec::Fetcher.resolve(target)
|
||||
|
||||
if @fetcher.nil?
|
||||
fail("Could not fetch inspec profile in #{target.inspect}.")
|
||||
raise("Could not fetch inspec profile in #{target.inspect}.")
|
||||
end
|
||||
|
||||
@cache = cache
|
||||
|
@ -50,7 +50,7 @@ module Inspec
|
|||
def assert_cache_sanity!
|
||||
if target.respond_to?(:key?) && target.key?(:sha256)
|
||||
if fetcher.resolved_source[:sha256] != target[:sha256]
|
||||
fail <<EOF
|
||||
raise <<EOF
|
||||
The remote source #{fetcher} no longer has the requested content:
|
||||
|
||||
Request Content Hash: #{target[:sha256]}
|
||||
|
|
|
@ -230,6 +230,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
|
|||
puts "\nYour version of InSpec is out of date! The latest version is #{latest}."
|
||||
end
|
||||
end
|
||||
map %w{-v --version} => :version
|
||||
|
||||
private
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@ module Inspec
|
|||
# @param profile_context [Inspec::ProfileContext]
|
||||
# @param outer_dsl [OuterDSLClass]
|
||||
# @return [ProfileContextClass]
|
||||
#
|
||||
# rubocop:disable Lint/NestedMethodDefinition
|
||||
def self.create(profile_context, resources_dsl) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
||||
rule_class = rule_context(resources_dsl)
|
||||
profile_context_owner = profile_context
|
||||
|
|
|
@ -18,7 +18,7 @@ module Inspec
|
|||
def self.from_content(content)
|
||||
parsed_content = YAML.load(content)
|
||||
version = parsed_content['lockfile_version']
|
||||
fail "No lockfile_version set in #{path}!" if version.nil?
|
||||
raise "No lockfile_version set in #{path}!" if version.nil?
|
||||
validate_lockfile_version!(version.to_i)
|
||||
new(parsed_content)
|
||||
end
|
||||
|
@ -28,9 +28,10 @@ module Inspec
|
|||
from_content(content)
|
||||
end
|
||||
|
||||
# rubocop:disable Style/GuardClause
|
||||
def self.validate_lockfile_version!(version)
|
||||
if version < MINIMUM_SUPPORTED_VERSION
|
||||
fail <<EOF
|
||||
raise <<EOF
|
||||
This lockfile specifies a lockfile_version of #{version} which is
|
||||
lower than the minimum supported version #{MINIMUM_SUPPORTED_VERSION}.
|
||||
|
||||
|
@ -39,7 +40,7 @@ Please create a new lockfile for this project by running:
|
|||
inspec vendor
|
||||
EOF
|
||||
elsif version > CURRENT_LOCKFILE_VERSION
|
||||
fail <<EOF
|
||||
raise <<EOF
|
||||
This lockfile claims to be version #{version} which is greater than
|
||||
the most recent lockfile version(#{CURRENT_LOCKFILE_VERSION}).
|
||||
|
||||
|
@ -48,6 +49,7 @@ used to create the lockfile.
|
|||
EOF
|
||||
end
|
||||
end
|
||||
# rubocop:enable Style/GuardClause
|
||||
|
||||
attr_reader :version, :deps
|
||||
def initialize(lockfile_content_hash)
|
||||
|
@ -80,7 +82,7 @@ EOF
|
|||
else
|
||||
# If we've gotten here, there is likely a mistake in the
|
||||
# lockfile version validation in the constructor.
|
||||
fail "No lockfile parser for version #{version}"
|
||||
raise "No lockfile parser for version #{version}"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module Inspec
|
|||
#
|
||||
class Requirement
|
||||
def self.from_metadata(dep, cache, opts)
|
||||
fail 'Cannot load empty dependency.' if dep.nil? || dep.empty?
|
||||
raise 'Cannot load empty dependency.' if dep.nil? || dep.empty?
|
||||
new(dep[:name], dep[:version], cache, opts[:cwd], opts.merge(dep))
|
||||
end
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ module Inspec
|
|||
def self.resolve(dependencies, cache, working_dir, backend)
|
||||
reqs = dependencies.map do |dep|
|
||||
req = Inspec::Requirement.from_metadata(dep, cache, cwd: working_dir, backend: backend)
|
||||
req || fail("Cannot initialize dependency: #{req}")
|
||||
req || raise("Cannot initialize dependency: #{req}")
|
||||
end
|
||||
new.resolve(reqs)
|
||||
end
|
||||
|
@ -40,7 +40,7 @@ module Inspec
|
|||
else
|
||||
"the dependency information for #{path_string.split(' ').last}"
|
||||
end
|
||||
fail Inspec::DuplicateDep, "The dependency #{dep.name} is listed twice in #{problem_cookbook}"
|
||||
raise Inspec::DuplicateDep, "The dependency #{dep.name} is listed twice in #{problem_cookbook}"
|
||||
else
|
||||
seen_items_local << dep.name
|
||||
end
|
||||
|
@ -65,13 +65,13 @@ module Inspec
|
|||
end
|
||||
|
||||
if new_seen_items.key?(dep.resolved_source)
|
||||
fail Inspec::CyclicDependencyError, "Dependency #{dep} would cause a dependency cycle (#{new_path_string})"
|
||||
raise Inspec::CyclicDependencyError, "Dependency #{dep} would cause a dependency cycle (#{new_path_string})"
|
||||
else
|
||||
new_seen_items[dep.resolved_source] = true
|
||||
end
|
||||
|
||||
if !dep.source_satisfies_spec?
|
||||
fail Inspec::UnsatisfiedVersionSpecification, "The profile #{dep.name} from #{dep.resolved_source} has a version #{dep.source_version} which doesn't match #{dep.required_version}"
|
||||
raise Inspec::UnsatisfiedVersionSpecification, "The profile #{dep.name} from #{dep.resolved_source} has a version #{dep.source_version} which doesn't match #{dep.required_version}"
|
||||
end
|
||||
|
||||
Inspec::Log.debug("Adding dependency #{dep.name} (#{dep.resolved_source})")
|
||||
|
|
|
@ -19,7 +19,7 @@ module Inspec::DSL
|
|||
alias include_rules include_controls
|
||||
|
||||
def require_resource(options = {})
|
||||
fail 'You must specify a specific resource name when calling require_resource()' if options[:resource].nil?
|
||||
raise 'You must specify a specific resource name when calling require_resource()' if options[:resource].nil?
|
||||
|
||||
from_profile = options[:profile] || profile_name
|
||||
target_name = options[:as] || options[:resource]
|
||||
|
@ -33,7 +33,7 @@ module Inspec::DSL
|
|||
|
||||
dep_entry = dependencies.list[profile_id]
|
||||
if dep_entry.nil?
|
||||
fail <<EOF
|
||||
raise <<EOF
|
||||
Cannot load #{profile_id} since it is not listed as a dependency
|
||||
of #{bind_context.profile_name}.
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ module Inspec
|
|||
|
||||
def self.fetcher(version)
|
||||
if version != 1
|
||||
fail 'Only fetcher version 1 is supported!'
|
||||
raise 'Only fetcher version 1 is supported!'
|
||||
end
|
||||
Inspec::Plugins::Fetcher
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ module Inspec
|
|||
elsif File.exist?(path)
|
||||
DirProvider.new(path)
|
||||
else
|
||||
fail "No file provider for the provided path: #{path}"
|
||||
raise "No file provider for the provided path: #{path}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -25,11 +25,11 @@ module Inspec
|
|||
end
|
||||
|
||||
def read(_file)
|
||||
fail "#{self} does not implement `read(...)`. This is required."
|
||||
raise "#{self} does not implement `read(...)`. This is required."
|
||||
end
|
||||
|
||||
def files
|
||||
fail "Fetcher #{self} does not implement `files()`. This is required."
|
||||
raise "Fetcher #{self} does not implement `files()`. This is required."
|
||||
end
|
||||
|
||||
def relative_provider
|
||||
|
@ -148,7 +148,7 @@ module Inspec
|
|||
@parent = parent_provider
|
||||
@prefix = get_prefix(parent.files)
|
||||
if @prefix.nil?
|
||||
fail "Could not determine path prefix for #{parent}"
|
||||
raise "Could not determine path prefix for #{parent}"
|
||||
end
|
||||
@files = parent.files.find_all { |x| x.start_with?(prefix) && x != prefix }
|
||||
.map { |x| x[prefix.length..-1] }
|
||||
|
|
|
@ -35,7 +35,7 @@ module Inspec
|
|||
|
||||
c3 = Class.new do
|
||||
include Inspec::DSL::RequireOverride
|
||||
def initialize(require_loader) # rubocop:disable Lint/NestedMethodDefinition
|
||||
def initialize(require_loader)
|
||||
@require_loader = require_loader
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
module Inspec
|
||||
class EachLoop < List
|
||||
attr_reader :tests, :variables
|
||||
attr_reader :variables
|
||||
attr_accessor :tests
|
||||
def initialize
|
||||
super
|
||||
@tests = []
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
module Inspec
|
||||
class List < Value
|
||||
def map
|
||||
fail 'Inspec::List.map needs to be called with a block' unless block_given?
|
||||
raise 'Inspec::List.map needs to be called with a block' unless block_given?
|
||||
t = List.new
|
||||
t.qualifier = [['x']]
|
||||
yield(t)
|
||||
|
|
|
@ -5,15 +5,30 @@ module Inspec
|
|||
attr_reader :tests
|
||||
def initialize(tests)
|
||||
@tests = tests
|
||||
@negated = false
|
||||
end
|
||||
|
||||
def skip
|
||||
nil
|
||||
end
|
||||
|
||||
def negate!
|
||||
@negated = !@negated
|
||||
end
|
||||
|
||||
def to_ruby
|
||||
all_tests = @tests.map(&:to_ruby).join("\n").gsub("\n", "\n ")
|
||||
format("describe.one do\n %s\nend", all_tests)
|
||||
if @negated
|
||||
# We don't use the describe.one wrapper when negated because:
|
||||
# !(test1 || test2) same as (!test1 && !test2) where && is implicit in inspec
|
||||
all_tests = @tests.map { |test|
|
||||
test.negate!
|
||||
test
|
||||
}.map(&:to_ruby).join("\n")
|
||||
return all_tests
|
||||
else
|
||||
all_tests = @tests.map(&:to_ruby).join("\n").gsub("\n", "\n ")
|
||||
return format("describe.one do\n %s\nend", all_tests)
|
||||
end
|
||||
end
|
||||
|
||||
def to_hash
|
||||
|
|
|
@ -53,7 +53,7 @@ module Inspec
|
|||
# this will go in its()
|
||||
xres = last_call
|
||||
else
|
||||
res += '.' + ruby_qualifier(last)
|
||||
res += '.' + ruby_qualifier(last) unless last_call.empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -67,7 +67,7 @@ module Inspec
|
|||
itsy = xtra.nil? ? 'it' : 'its(' + xtra.to_s.inspect + ')'
|
||||
naughty = @negated ? '_not' : ''
|
||||
xpect = defined?(@expectation) ? expectation.inspect : ''
|
||||
if matcher == 'match'
|
||||
if @expectation.class == Regexp
|
||||
# without this, xpect values like / \/zones\// will not be parsed properly
|
||||
xpect = "(#{xpect})"
|
||||
elsif xpect != ''
|
||||
|
|
|
@ -51,7 +51,7 @@ module Inspec
|
|||
def load(name)
|
||||
path = @registry[name]
|
||||
if path.nil?
|
||||
fail "Couldn't find plugin #{name}. Searching in #{@home}"
|
||||
raise "Couldn't find plugin #{name}. Searching in #{@home}"
|
||||
end
|
||||
# puts "Loading plugin #{name} from #{path}"
|
||||
require path
|
||||
|
|
|
@ -36,7 +36,7 @@ module Inspec
|
|||
# profile.
|
||||
#
|
||||
def archive_path
|
||||
fail "Fetcher #{self} does not implement `archive_path()`. This is required."
|
||||
raise "Fetcher #{self} does not implement `archive_path()`. This is required."
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -49,7 +49,7 @@ module Inspec
|
|||
# /foo/bar/baz.zip
|
||||
#
|
||||
def fetch(_path)
|
||||
fail "Fetcher #{self} does not implement `fetch()`. This is required."
|
||||
raise "Fetcher #{self} does not implement `fetch()`. This is required."
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -59,14 +59,14 @@ module Inspec
|
|||
# tag will be resolved to an exact revision.
|
||||
#
|
||||
def resolved_source
|
||||
fail "Fetcher #{self} does not implement `resolved_source()`. This is required for terminal fetchers."
|
||||
raise "Fetcher #{self} does not implement `resolved_source()`. This is required for terminal fetchers."
|
||||
end
|
||||
|
||||
#
|
||||
# The unique key based on the content of the remote archive.
|
||||
#
|
||||
def cache_key
|
||||
fail "Fetcher #{self} does not implement `cache_key()`. This is required for terminal fetchers."
|
||||
raise "Fetcher #{self} does not implement `cache_key()`. This is required for terminal fetchers."
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -38,7 +38,6 @@ module Inspec
|
|||
end
|
||||
|
||||
def __register(name, obj)
|
||||
# rubocop:disable Lint/NestedMethodDefinition
|
||||
cl = Class.new(obj) do
|
||||
def initialize(backend, name, *args)
|
||||
# attach the backend to this instance
|
||||
|
|
|
@ -15,7 +15,7 @@ module Inspec
|
|||
#
|
||||
# @return [Inspec::Metadata] profile metadata
|
||||
def metadata
|
||||
fail "SourceReader #{self} does not implement `metadata()`. This method is required"
|
||||
raise "SourceReader #{self} does not implement `metadata()`. This method is required"
|
||||
end
|
||||
|
||||
# Retrieve this profile's tests
|
||||
|
@ -26,14 +26,14 @@ module Inspec
|
|||
#
|
||||
# @return [Hash] Collection with references pointing to test contents
|
||||
def tests
|
||||
fail "SourceReader #{self} does not implement `tests()`. This method is required"
|
||||
raise "SourceReader #{self} does not implement `tests()`. This method is required"
|
||||
end
|
||||
|
||||
# Retrieve this profile's libraries
|
||||
#
|
||||
# @return [Hash] Collection with references pointing to library contents
|
||||
def libraries
|
||||
fail "SourceReader #{self} does not implement `libraries()`. This method is required"
|
||||
raise "SourceReader #{self} does not implement `libraries()`. This method is required"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -57,7 +57,7 @@ module Inspec
|
|||
|
||||
reader = Inspec::SourceReader.resolve(rp)
|
||||
if reader.nil?
|
||||
fail("Don't understand inspec profile in #{path}, it " \
|
||||
raise("Don't understand inspec profile in #{path}, it " \
|
||||
"doesn't look like a supported profile structure.")
|
||||
end
|
||||
new(reader, opts)
|
||||
|
@ -108,7 +108,7 @@ module Inspec
|
|||
metadata.params[:version]
|
||||
end
|
||||
|
||||
def writable? # rubocop:disable Style/TrivialAccessors
|
||||
def writable?
|
||||
@writable
|
||||
end
|
||||
|
||||
|
@ -397,10 +397,10 @@ module Inspec
|
|||
end
|
||||
|
||||
name = params[:name] ||
|
||||
fail('Cannot create an archive without a profile name! Please '\
|
||||
raise('Cannot create an archive without a profile name! Please '\
|
||||
'specify the name in metadata or use --output to create the archive.')
|
||||
version = params[:version] ||
|
||||
fail('Cannot create an archive without a profile version! Please '\
|
||||
raise('Cannot create an archive without a profile version! Please '\
|
||||
'specify the version in metadata or use --output to create the archive.')
|
||||
ext = opts[:zip] ? 'zip' : 'tar.gz'
|
||||
slug = name.downcase.strip.tr(' ', '-').gsub(/[^\w-]/, '_')
|
||||
|
|
|
@ -21,7 +21,7 @@ module Inspec
|
|||
attr_accessor :rules
|
||||
def initialize(profile_id, backend, conf)
|
||||
if backend.nil?
|
||||
fail 'ProfileContext is initiated with a backend == nil. ' \
|
||||
raise 'ProfileContext is initiated with a backend == nil. ' \
|
||||
'This is a backend error which must be fixed upstream.'
|
||||
end
|
||||
@profile_id = profile_id
|
||||
|
|
|
@ -39,7 +39,7 @@ module Inspec
|
|||
profile_context.subcontext_by_name(profile_name)
|
||||
end
|
||||
|
||||
fail ProfileNotFound, "Cannot find profile named: #{profile_name}" if inner_context.nil?
|
||||
raise ProfileNotFound, "Cannot find profile named: #{profile_name}" if inner_context.nil?
|
||||
inner_context.resource_registry[resource_name]
|
||||
end
|
||||
|
||||
|
@ -64,7 +64,7 @@ module Inspec
|
|||
|
||||
def self.validate_resource_dsl_version!(version)
|
||||
if version != 1
|
||||
fail 'Only resource version 1 is supported!'
|
||||
raise 'Only resource version 1 is supported!'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -79,6 +79,7 @@ require 'resources/bash'
|
|||
require 'resources/bond'
|
||||
require 'resources/bridge'
|
||||
require 'resources/command'
|
||||
require 'resources/crontab'
|
||||
require 'resources/directory'
|
||||
require 'resources/etc_group'
|
||||
require 'resources/file'
|
||||
|
@ -86,6 +87,7 @@ require 'resources/gem'
|
|||
require 'resources/groups'
|
||||
require 'resources/grub_conf'
|
||||
require 'resources/host'
|
||||
require 'resources/http'
|
||||
require 'resources/iis_site'
|
||||
require 'resources/inetd_conf'
|
||||
require 'resources/interface'
|
||||
|
@ -106,6 +108,7 @@ require 'resources/oneget'
|
|||
require 'resources/os'
|
||||
require 'resources/os_env'
|
||||
require 'resources/package'
|
||||
require 'resources/packages'
|
||||
require 'resources/parse_config'
|
||||
require 'resources/passwd'
|
||||
require 'resources/pip'
|
||||
|
|
|
@ -166,7 +166,7 @@ module Inspec
|
|||
backend: @backend,
|
||||
controls: @controls,
|
||||
attributes: @conf[:attributes])
|
||||
fail "Could not resolve #{target} to valid input." if profile.nil?
|
||||
raise "Could not resolve #{target} to valid input." if profile.nil?
|
||||
@target_profiles << profile if supports_profile?(profile)
|
||||
end
|
||||
|
||||
|
@ -174,13 +174,13 @@ module Inspec
|
|||
return true if @ignore_supports
|
||||
|
||||
if !profile.supports_runtime?
|
||||
fail 'This profile requires InSpec version '\
|
||||
raise 'This profile requires InSpec version '\
|
||||
"#{profile.metadata.inspec_requirement}. You are running "\
|
||||
"InSpec v#{Inspec::VERSION}.\n"
|
||||
end
|
||||
|
||||
if !profile.supports_os?
|
||||
fail "This OS/platform (#{@backend.os[:name]}) is not supported by this profile."
|
||||
raise "This OS/platform (#{@backend.os[:name]}) is not supported by this profile."
|
||||
end
|
||||
|
||||
true
|
||||
|
@ -249,7 +249,7 @@ module Inspec
|
|||
# otherwise return all working tests
|
||||
return ok_tests
|
||||
else
|
||||
fail "A rule was registered with #{method_name.inspect}, "\
|
||||
raise "A rule was registered with #{method_name.inspect}, "\
|
||||
"which isn't understood and cannot be processed."
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ module Inspec
|
|||
|
||||
def self.secrets(version)
|
||||
if version != 1
|
||||
fail 'Only secrets version 1 is supported!'
|
||||
raise 'Only secrets version 1 is supported!'
|
||||
end
|
||||
Inspec::Plugins::Secret
|
||||
end
|
||||
|
|
|
@ -42,6 +42,8 @@ module Inspec
|
|||
# Add a help menu as the default intro
|
||||
Pry.hooks.add_hook(:before_session, 'inspec_intro') do
|
||||
intro
|
||||
print_target_info
|
||||
puts
|
||||
end
|
||||
|
||||
# Track the rules currently registered and what their merge count is.
|
||||
|
@ -79,7 +81,7 @@ module Inspec
|
|||
# determine min whitespace that can be removed
|
||||
min = nil
|
||||
example.lines.each do |line|
|
||||
if line.strip.length > 0 # ignore empty lines
|
||||
if !line.strip.empty? # ignore empty lines
|
||||
line_whitespace = line.length - line.lstrip.length
|
||||
min = line_whitespace if min.nil? || line_whitespace < min
|
||||
end
|
||||
|
@ -94,10 +96,20 @@ module Inspec
|
|||
puts
|
||||
end
|
||||
|
||||
def print_target_info
|
||||
ctx = @runner.backend
|
||||
puts <<EOF
|
||||
You are currently running on:
|
||||
|
||||
OS platform: #{mark ctx.os[:name] || 'unknown'}
|
||||
OS family: #{mark ctx.os[:family] || 'unknown'}
|
||||
OS release: #{mark ctx.os[:release] || 'unknown'}
|
||||
EOF
|
||||
end
|
||||
|
||||
def help(resource = nil)
|
||||
if resource.nil?
|
||||
|
||||
ctx = @runner.backend
|
||||
puts <<EOF
|
||||
|
||||
Available commands:
|
||||
|
@ -110,14 +122,9 @@ Available commands:
|
|||
You can use resources in this environment to test the target machine. For example:
|
||||
|
||||
command('uname -a').stdout
|
||||
file('/proc/cpuinfo').content => "value",
|
||||
|
||||
You are currently running on:
|
||||
|
||||
OS platform: #{mark ctx.os[:name] || 'unknown'}
|
||||
OS family: #{mark ctx.os[:family] || 'unknown'}
|
||||
OS release: #{mark ctx.os[:release] || 'unknown'}
|
||||
file('/proc/cpuinfo').content => "value"
|
||||
|
||||
#{print_target_info}
|
||||
EOF
|
||||
elsif resource == 'resources'
|
||||
resources
|
||||
|
|
|
@ -19,7 +19,7 @@ module Inspec
|
|||
|
||||
def self.source_reader(version)
|
||||
if version != 1
|
||||
fail 'Only source readers version 1 is supported!'
|
||||
raise 'Only source readers version 1 is supported!'
|
||||
end
|
||||
Inspec::Plugins::SourceReader
|
||||
end
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
# author: Christoph Hartmann
|
||||
|
||||
module Inspec
|
||||
VERSION = '1.9.0'.freeze
|
||||
VERSION = '1.14.1'.freeze
|
||||
end
|
||||
|
|
|
@ -105,7 +105,7 @@ RSpec::Matchers.define :be_installed do
|
|||
end
|
||||
|
||||
chain :by do
|
||||
fail "[UNSUPPORTED] Please use the new resources 'gem', 'npm' or 'pip'."
|
||||
raise "[UNSUPPORTED] Please use the new resources 'gem', 'npm' or 'pip'."
|
||||
end
|
||||
|
||||
chain :with_version do |version|
|
||||
|
@ -121,7 +121,7 @@ RSpec::Matchers.define :be_enabled do
|
|||
end
|
||||
|
||||
chain :with_level do |_level|
|
||||
fail '[UNSUPPORTED] with level is not supported'
|
||||
raise '[UNSUPPORTED] with level is not supported'
|
||||
end
|
||||
|
||||
failure_message do |service|
|
||||
|
@ -137,7 +137,7 @@ RSpec::Matchers.define :be_running do
|
|||
end
|
||||
|
||||
chain :under do |_under|
|
||||
fail '[UNSUPPORTED] under is not supported'
|
||||
raise '[UNSUPPORTED] under is not supported'
|
||||
end
|
||||
|
||||
failure_message do |service|
|
||||
|
@ -178,7 +178,7 @@ RSpec::Matchers.define :be_reachable do
|
|||
end
|
||||
|
||||
chain :with do |_attr|
|
||||
fail '[UNSUPPORTED] `with` is not supported in combination with `be_reachable`'
|
||||
raise '[UNSUPPORTED] `with` is not supported in combination with `be_reachable`'
|
||||
end
|
||||
|
||||
failure_message do |host|
|
||||
|
@ -193,7 +193,7 @@ RSpec::Matchers.define :be_resolvable do
|
|||
end
|
||||
|
||||
chain :by do |_type|
|
||||
fail "[UNSUPPORTED] `by` is not supported in combination with `be_resolvable`. Please use the following syntax `host('example.com', port: 53, proto: 'udp')`."
|
||||
raise "[UNSUPPORTED] `by` is not supported in combination with `be_resolvable`. Please use the following syntax `host('example.com', port: 53, proto: 'udp')`."
|
||||
end
|
||||
|
||||
failure_message do |host|
|
||||
|
@ -208,11 +208,11 @@ RSpec::Matchers.define :have_rule do |rule|
|
|||
end
|
||||
|
||||
chain :with_table do |_table|
|
||||
fail "[UNSUPPORTED] `with_table` is not supported in combination with `have_rule`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`."
|
||||
raise "[UNSUPPORTED] `with_table` is not supported in combination with `have_rule`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`."
|
||||
end
|
||||
|
||||
chain :with_chain do |_chain|
|
||||
fail "[UNSUPPORTED] `with_table` is not supported in combination with `with_chain`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`."
|
||||
raise "[UNSUPPORTED] `with_table` is not supported in combination with `with_chain`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`."
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
raw_conf = file.content
|
||||
if raw_conf.empty? && file.size > 0
|
||||
if raw_conf.empty? && !file.empty?
|
||||
return skip_resource("Can't read file \"#{@conf_path}\"")
|
||||
end
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
content = file.content
|
||||
if content.empty? && file.size > 0
|
||||
if content.empty? && !file.empty?
|
||||
skip_resource "Can't read file '#{@conf_path}'"
|
||||
return @params = {}
|
||||
end
|
||||
|
|
|
@ -93,7 +93,7 @@ module Inspec::Resources
|
|||
# rubocop:disable Style/MethodName
|
||||
def LIST_RULES
|
||||
return @legacy.LIST_RULES if @legacy
|
||||
fail 'Using legacy auditd_rules LIST_RULES interface with non-legacy audit package. Please use the new syntax.'
|
||||
raise 'Using legacy auditd_rules LIST_RULES interface with non-legacy audit package. Please use the new syntax.'
|
||||
end
|
||||
|
||||
def status(name = nil)
|
||||
|
|
|
@ -115,7 +115,7 @@ module Inspec::Resources
|
|||
adapter_collection.push(info) if info[:name].casecmp(bridge_name) == 0
|
||||
end
|
||||
|
||||
return nil if bridges.size == 0
|
||||
return nil if bridges.empty?
|
||||
warn "[Possible Error] detected multiple bridges interfaces with the name #{bridge_name}" if bridges.size > 1
|
||||
bridges[0]
|
||||
end
|
||||
|
|
83
lib/resources/crontab.rb
Normal file
83
lib/resources/crontab.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
# encoding: utf-8
|
||||
# author: Adam Leff
|
||||
|
||||
require 'utils/parser'
|
||||
require 'utils/filter'
|
||||
|
||||
module Inspec::Resources
|
||||
class Crontab < Inspec.resource(1)
|
||||
name 'crontab'
|
||||
desc 'Use the crontab InSpec audit resource to test the contents of the crontab for a given user which contains information about scheduled tasks owned by that user.'
|
||||
example "
|
||||
describe crontab('root') do
|
||||
its('commands') { should include '/path/to/some/script' }
|
||||
end
|
||||
|
||||
describe crontab('myuser').commands('/home/myuser/build.sh') do
|
||||
its('hours') { should cmp '*' }
|
||||
its('minutes') { should cmp '*' }
|
||||
end
|
||||
|
||||
describe crontab.where({'hour' => '*', 'minute' => '*'}) do
|
||||
its('entries.length') { should cmp '0' }
|
||||
end
|
||||
"
|
||||
|
||||
attr_reader :params
|
||||
|
||||
include CommentParser
|
||||
|
||||
def initialize(user = nil)
|
||||
@user = user
|
||||
@params = read_crontab
|
||||
|
||||
return skip_resource 'The `crontab` resource is not supported on your OS.' unless inspec.os.unix?
|
||||
end
|
||||
|
||||
def read_crontab
|
||||
inspec.command(crontab_cmd).stdout.lines.map { |l| parse_crontab_line(l) }.compact
|
||||
end
|
||||
|
||||
def parse_crontab_line(l)
|
||||
data, = parse_comment_line(l, comment_char: '#', standalone_comments: false)
|
||||
return nil if data.nil? || data.empty?
|
||||
|
||||
elements = data.split(/\s+/, 6)
|
||||
{
|
||||
'minute' => elements.at(0),
|
||||
'hour' => elements.at(1),
|
||||
'day' => elements.at(2),
|
||||
'month' => elements.at(3),
|
||||
'weekday' => elements.at(4),
|
||||
'command' => elements.at(5),
|
||||
}
|
||||
end
|
||||
|
||||
def crontab_cmd
|
||||
@user.nil? ? 'crontab -l' : "crontab -l -u #{@user}"
|
||||
end
|
||||
|
||||
filter = FilterTable.create
|
||||
filter.add_accessor(:where)
|
||||
.add_accessor(:entries)
|
||||
.add(:minutes, field: 'minute')
|
||||
.add(:hours, field: 'hour')
|
||||
.add(:days, field: 'day')
|
||||
.add(:months, field: 'month')
|
||||
.add(:weekdays, field: 'weekday')
|
||||
.add(:commands, field: 'command')
|
||||
|
||||
# rebuild the crontab line from raw content
|
||||
filter.add(:content) { |t, _|
|
||||
t.entries.map do |e|
|
||||
[e.minute, e.hour, e.day, e.month, e.weekday, e.command].join(' ')
|
||||
end.join("\n")
|
||||
}
|
||||
|
||||
filter.connect(self, :params)
|
||||
|
||||
def to_s
|
||||
@user.nil? ? 'crontab for current user' : "crontab for user #{@user}"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -107,7 +107,7 @@ module Inspec::Resources
|
|||
# iterate over each line and filter comments
|
||||
@content.split("\n").each_with_object([]) do |line, lines|
|
||||
grp_info = parse_group_line(line)
|
||||
lines.push(grp_info) if !grp_info.nil? && grp_info.size > 0
|
||||
lines.push(grp_info) if !grp_info.nil? && !grp_info.empty?
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -119,7 +119,7 @@ module Inspec::Resources
|
|||
line, _idx_nl = parse_comment_line(line, opts)
|
||||
x = line.split(':')
|
||||
# abort if we have an empty or comment line
|
||||
return nil if x.size == 0
|
||||
return nil if x.empty?
|
||||
# map data
|
||||
{
|
||||
'name' => x.at(0), # Name of the group.
|
||||
|
|
|
@ -61,7 +61,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
def contain(*_)
|
||||
fail 'Contain is not supported. Please use standard RSpec matchers.'
|
||||
raise 'Contain is not supported. Please use standard RSpec matchers.'
|
||||
end
|
||||
|
||||
def readable?(by_usergroup, by_specific_user)
|
||||
|
@ -128,7 +128,7 @@ module Inspec::Resources
|
|||
private
|
||||
|
||||
def file_permission_granted?(access_type, by_usergroup, by_specific_user)
|
||||
fail '`file_permission_granted?` is not supported on your OS' if @perms_provider.nil?
|
||||
raise '`file_permission_granted?` is not supported on your OS' if @perms_provider.nil?
|
||||
if by_specific_user.nil? || by_specific_user.empty?
|
||||
@perms_provider.check_file_permission_by_mask(file, access_type, by_usergroup, by_specific_user)
|
||||
else
|
||||
|
@ -154,7 +154,7 @@ module Inspec::Resources
|
|||
when 'execute'
|
||||
'x'
|
||||
else
|
||||
fail 'Invalid access_type provided'
|
||||
raise 'Invalid access_type provided'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -172,7 +172,7 @@ module Inspec::Resources
|
|||
usergroup = usergroup_for(usergroup, specific_user)
|
||||
flag = permission_flag(access_type)
|
||||
mask = file.unix_mode_mask(usergroup, flag)
|
||||
fail 'Invalid usergroup/owner provided' if mask.nil?
|
||||
raise 'Invalid usergroup/owner provided' if mask.nil?
|
||||
(file.mode & mask) != 0
|
||||
end
|
||||
|
||||
|
@ -197,7 +197,7 @@ module Inspec::Resources
|
|||
|
||||
class WindowsFilePermissions < FilePermissions
|
||||
def check_file_permission_by_mask(_file, _access_type, _usergroup, _specific_user)
|
||||
fail '`check_file_permission_by_mask` is not supported on Windows'
|
||||
raise '`check_file_permission_by_mask` is not supported on Windows'
|
||||
end
|
||||
|
||||
def check_file_permission_by_user(access_type, user, path)
|
||||
|
@ -209,7 +209,7 @@ module Inspec::Resources
|
|||
when 'execute'
|
||||
'@(\'FullControl\', \'Modify\', \'ReadAndExecute\', \'ExecuteFile\')'
|
||||
else
|
||||
fail 'Invalid access_type provided'
|
||||
raise 'Invalid access_type provided'
|
||||
end
|
||||
cmd = inspec.command("@(@((Get-Acl '#{path}').access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -eq '#{user}' }) | Where-Object {($_.FileSystemRights.ToString().Split(',') | % {$_.trim()} | ? {#{access_rule} -contains $_}) -ne $null}) | measure | % { $_.Count }")
|
||||
cmd.stdout.chomp == '0' ? false : true
|
||||
|
|
|
@ -99,18 +99,18 @@ module Inspec::Resources
|
|||
|
||||
# verifies if a group exists
|
||||
def exists?
|
||||
group_info.entries.size > 0
|
||||
!group_info.entries.empty?
|
||||
end
|
||||
|
||||
def gid
|
||||
gids = group_info.gids
|
||||
if gids.size == 0
|
||||
if gids.empty?
|
||||
nil
|
||||
# the default case should be one group
|
||||
elsif gids.size == 1
|
||||
gids.entries[0]
|
||||
else
|
||||
fail 'found more than one group with the same name, please use `groups` resource'
|
||||
raise 'found more than one group with the same name, please use `groups` resource'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -144,7 +144,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
def groups
|
||||
fail 'group provider must implement the `groups` method'
|
||||
raise 'group provider must implement the `groups` method'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -38,11 +38,11 @@ class GrubConfig < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
|
|||
@conf_path = path || '/boot/grub/grub.cfg'
|
||||
@defaults_path = '/etc/default/grub'
|
||||
@version = 'grub2'
|
||||
elsif os[:name] == 'amazon' # rubocop:disable Style/GuardClause
|
||||
elsif os[:name] == 'amazon'
|
||||
@conf_path = path || '/etc/grub.conf'
|
||||
@version = 'legacy'
|
||||
else
|
||||
fail UnknownGrubConfig
|
||||
raise UnknownGrubConfig
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -145,7 +145,7 @@ class GrubConfig < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
|
|||
|
||||
content = file.content
|
||||
|
||||
if content.empty? && file.size > 0
|
||||
if content.empty? && !file.empty?
|
||||
skip_resource "Can't read file '#{@conf_path}'"
|
||||
return @params = {}
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
def reachable?(port = nil, proto = nil, timeout = nil)
|
||||
fail "Use `host` resource with host('#{@hostname}', port: #{port}, proto: '#{proto}') parameters." if !port.nil? || !proto.nil? || !timeout.nil?
|
||||
raise "Use `host` resource with host('#{@hostname}', port: #{port}, proto: '#{proto}') parameters." if !port.nil? || !proto.nil? || !timeout.nil?
|
||||
ping.nil? ? false : ping
|
||||
end
|
||||
|
||||
|
|
70
lib/resources/http.rb
Normal file
70
lib/resources/http.rb
Normal file
|
@ -0,0 +1,70 @@
|
|||
# encoding: utf-8
|
||||
# copyright: 2017, Criteo
|
||||
# copyright: 2017, Chef Software Inc
|
||||
# author: Guilhem Lettron, Christoph Hartmann
|
||||
# license: Apache v2
|
||||
|
||||
require 'faraday'
|
||||
require 'hashie'
|
||||
|
||||
module Inspec::Resources
|
||||
class Http < Inspec.resource(1)
|
||||
name 'http'
|
||||
desc 'Use the http InSpec audit resource to test http call.'
|
||||
example "
|
||||
describe http('http://localhost:8080/ping', auth: {user: 'user', pass: 'test'}, params: {format: 'html'}) do
|
||||
its('status') { should cmp 200 }
|
||||
its('body') { should cmp 'pong' }
|
||||
its('headers.Content-Type') { should cmp 'text/html' }
|
||||
end
|
||||
|
||||
describe http('http://example.com/ping').headers do
|
||||
its('Content-Length') { should cmp 258 }
|
||||
its('Content-Type') { should cmp 'text/html; charset=UTF-8' }
|
||||
end
|
||||
"
|
||||
|
||||
# rubocop:disable ParameterLists
|
||||
def initialize(url, method: 'GET', params: nil, auth: {}, headers: {}, data: nil)
|
||||
@url = url
|
||||
@method = method
|
||||
@params = params
|
||||
@auth = auth
|
||||
@headers = headers
|
||||
@data = data
|
||||
end
|
||||
|
||||
def status
|
||||
response.status
|
||||
end
|
||||
|
||||
def body
|
||||
response.body
|
||||
end
|
||||
|
||||
def headers
|
||||
Hashie::Mash.new(response.headers.to_h)
|
||||
end
|
||||
|
||||
def to_s
|
||||
"http #{@method} on #{@url}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def response
|
||||
conn = Faraday.new url: @url, headers: @headers, params: @params
|
||||
|
||||
# set basic authentication
|
||||
conn.basic_auth @auth[:user], @auth[:pass] unless @auth.empty?
|
||||
|
||||
# set default timeout
|
||||
conn.options.timeout = 5 # open/read timeout in seconds
|
||||
conn.options.open_timeout = 3 # connection open timeout in seconds
|
||||
|
||||
@response = conn.send(@method.downcase) do |req|
|
||||
req.body = @data
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -43,7 +43,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
content = file.content
|
||||
if content.empty? && file.size > 0
|
||||
if content.empty? && !file.empty?
|
||||
skip_resource "Can't read file \"#{@conf_path}\""
|
||||
return @params = {}
|
||||
end
|
||||
|
|
|
@ -121,7 +121,7 @@ module Inspec::Resources
|
|||
adapter_collection.push(info) if info[:name].casecmp(iface) == 0
|
||||
end
|
||||
|
||||
return nil if adapters.size == 0
|
||||
return nil if adapters.empty?
|
||||
warn "[Possible Error] detected multiple network interfaces with the name #{iface}" if adapters.size > 1
|
||||
adapters[0]
|
||||
end
|
||||
|
|
|
@ -49,7 +49,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
# check if file is readable
|
||||
if @file_content.nil? && @file.size > 0
|
||||
if @file_content.nil? && !@file.empty?
|
||||
skip_resource "Can't read file \"#{@path}\""
|
||||
return @params = {}
|
||||
end
|
||||
|
|
|
@ -36,6 +36,17 @@ module Inspec::Resources
|
|||
!found.nil?
|
||||
end
|
||||
|
||||
def version
|
||||
if inspec.os[:name] == 'centos' && inspec.os[:release].to_i == 5
|
||||
modinfo_cmd = "/sbin/modinfo -F version #{@module}"
|
||||
else
|
||||
modinfo_cmd = "modinfo -F version #{@module}"
|
||||
end
|
||||
|
||||
cmd = inspec.command(modinfo_cmd)
|
||||
cmd.exit_status.zero? ? cmd.stdout.delete("\n") : nil
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Kernel Module #{@module}"
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
content = file.content
|
||||
if content.empty? && file.size > 0
|
||||
if content.empty? && !file.empty?
|
||||
skip_resource "Can't read file \"#{@conf_path}\""
|
||||
return @params = {}
|
||||
end
|
||||
|
|
|
@ -47,7 +47,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
content = file.content
|
||||
if content.empty? && file.size > 0
|
||||
if content.empty? && !file.empty?
|
||||
skip_resource "Can't read file \"#{@conf_path}\""
|
||||
return @params = {}
|
||||
end
|
||||
|
|
|
@ -73,7 +73,7 @@ module Inspec::Resources
|
|||
return skip_resource "Can't find file \"#{@conf_path}\""
|
||||
end
|
||||
raw_conf = read_file(@conf_path)
|
||||
if raw_conf.empty? && inspec.file(@conf_path).size > 0
|
||||
if raw_conf.empty? && !inspec.file(@conf_path).empty?
|
||||
return skip_resource("Can't read file \"#{@conf_path}\"")
|
||||
end
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
content = inspec.file(@conf_path).content
|
||||
if content.empty? && inspec.file(@conf_path).size > 0
|
||||
if content.empty? && !inspec.file(@conf_path).empty?
|
||||
skip_resource "Can't read file \"#{@conf_path}\""
|
||||
return @params = {}
|
||||
end
|
||||
|
|
|
@ -29,7 +29,7 @@ module Inspec::Resources
|
|||
os = inspec.os
|
||||
if os.debian?
|
||||
@pkgman = Deb.new(inspec)
|
||||
elsif %w{redhat suse amazon fedora}.include?(os[:family])
|
||||
elsif os.redhat? || %w{suse amazon fedora}.include?(os[:family])
|
||||
@pkgman = Rpm.new(inspec)
|
||||
elsif ['arch'].include?(os[:family])
|
||||
@pkgman = Pacman.new(inspec)
|
||||
|
|
112
lib/resources/packages.rb
Normal file
112
lib/resources/packages.rb
Normal file
|
@ -0,0 +1,112 @@
|
|||
# encoding: utf-8
|
||||
# copyright: 2017, Chef Software, Inc. <legal@chef.io>
|
||||
# author: Joshua Timberman
|
||||
# author: Alex Pop
|
||||
# license: All rights reserved
|
||||
|
||||
require 'utils/filter'
|
||||
|
||||
module Inspec::Resources
|
||||
class Packages < Inspec.resource(1)
|
||||
name 'packages'
|
||||
desc 'Use the packages InSpec audit resource to test properties for multiple packages installed on the system'
|
||||
example "
|
||||
describe packages(/xserver-xorg.*/) do
|
||||
its('entries') { should be_empty }
|
||||
end
|
||||
describe packages('vim').entries.length do
|
||||
it { should be > 1 }
|
||||
end
|
||||
describe packages(/vi.+/).where { status != 'installed' } do
|
||||
its('statuses') { should be_empty }
|
||||
end
|
||||
"
|
||||
|
||||
def initialize(pattern)
|
||||
os = inspec.os
|
||||
if os.debian?
|
||||
@pkgs = Debs.new(inspec)
|
||||
elsif os.redhat? || %w{suse amazon fedora}.include?(os[:family])
|
||||
@pkgs = Rpms.new(inspec)
|
||||
else
|
||||
return skip_resource "The packages resource is not yet supported on OS #{inspec.os.name}"
|
||||
end
|
||||
|
||||
@pattern = pattern_regexp(pattern)
|
||||
all_pkgs = @pkgs.build_package_list
|
||||
@list = all_pkgs.find_all do |hm|
|
||||
hm[:name] =~ @pattern
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Packages #{@pattern.class == String ? @pattern : @pattern.inspect}"
|
||||
end
|
||||
|
||||
filter = FilterTable.create
|
||||
filter.add_accessor(:where)
|
||||
.add_accessor(:entries)
|
||||
.add(:statuses, field: 'status', style: :simple)
|
||||
.add(:names, field: 'name')
|
||||
.add(:versions, field: 'version')
|
||||
.connect(self, :filtered_packages)
|
||||
|
||||
private
|
||||
|
||||
def pattern_regexp(p)
|
||||
if p.class == String
|
||||
Regexp.new(Regexp.escape(p))
|
||||
elsif p.class == Regexp
|
||||
p
|
||||
else
|
||||
raise 'Invalid name argument to packages resource, please use a "string" or /regexp/'
|
||||
end
|
||||
end
|
||||
|
||||
def filtered_packages
|
||||
warn "The packages resource is not yet supported on OS #{inspec.os.name}" if resource_skipped
|
||||
@list
|
||||
end
|
||||
end
|
||||
|
||||
class PkgsManagement
|
||||
PackageStruct = Struct.new(:status, :name, :version)
|
||||
attr_reader :inspec
|
||||
def initialize(inspec)
|
||||
@inspec = inspec
|
||||
end
|
||||
end
|
||||
|
||||
# Debian / Ubuntu
|
||||
class Debs < PkgsManagement
|
||||
def build_package_list
|
||||
# use two spaces as delimiter in case any of the fields has a space in it
|
||||
command = "dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\\n'"
|
||||
cmd = inspec.command(command)
|
||||
all = cmd.stdout.split("\n")
|
||||
return [] if all.nil?
|
||||
all.map do |m|
|
||||
a = m.split(/ {2,}/)
|
||||
a[0] = 'installed' if a[0] =~ /^.i/
|
||||
a[2] = a[2].split(':').last
|
||||
PackageStruct.new(*a)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# RedHat family
|
||||
class Rpms < PkgsManagement
|
||||
def build_package_list
|
||||
# use two spaces as delimiter in case any of the fields has a space in it
|
||||
command = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE}\\n'"
|
||||
cmd = inspec.command(command)
|
||||
all = cmd.stdout.split("\n")
|
||||
return [] if all.nil?
|
||||
all.map do |m|
|
||||
a = m.split(' ')
|
||||
a.unshift('installed')
|
||||
PackageStruct.new(*a)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -76,7 +76,7 @@ module Inspec::Resources
|
|||
return skip_resource "Can't find file \"#{conf_path}\""
|
||||
end
|
||||
@content = read_file(conf_path).to_s
|
||||
if @content.empty? && inspec.file(conf_path).size > 0
|
||||
if @content.empty? && !inspec.file(conf_path).empty?
|
||||
return skip_resource "Can't read file \"#{conf_path}\""
|
||||
end
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ module Inspec::Resources
|
|||
.add(:protocols, field: 'protocol', style: :simple)
|
||||
.add(:processes, field: 'process', style: :simple)
|
||||
.add(:pids, field: 'pid', style: :simple)
|
||||
.add(:listening?) { |x| x.entries.length > 0 }
|
||||
.add(:listening?) { |x| !x.entries.empty? }
|
||||
filter.connect(self, :info)
|
||||
|
||||
def to_s
|
||||
|
@ -169,7 +169,7 @@ module Inspec::Resources
|
|||
ports = []
|
||||
|
||||
# check that lsof is available, otherwise fail
|
||||
fail 'Please ensure `lsof` is available on the machine.' if !inspec.command(@lsof.to_s).exist?
|
||||
raise 'Please ensure `lsof` is available on the machine.' if !inspec.command(@lsof.to_s).exist?
|
||||
|
||||
# -F p=pid, c=command, P=protocol name, t=type, n=internet addresses
|
||||
# see 'OUTPUT FOR OTHER PROGRAMS' in LSOF(8)
|
||||
|
|
|
@ -65,7 +65,7 @@ module Inspec::Resources
|
|||
return skip_resource "Can't find file \"#{@conf_path}\""
|
||||
end
|
||||
raw_conf = read_file(@conf_path)
|
||||
if raw_conf.empty? && inspec.file(@conf_path).size > 0
|
||||
if raw_conf.empty? && !inspec.file(@conf_path).empty?
|
||||
return skip_resource("Can't read file \"#{@conf_path}\"")
|
||||
end
|
||||
|
||||
|
|
|
@ -4,22 +4,23 @@
|
|||
# author: Christoph Hartmann
|
||||
# license: All rights reserved
|
||||
|
||||
require 'utils/filter'
|
||||
|
||||
module Inspec::Resources
|
||||
class Processes < Inspec.resource(1)
|
||||
name 'processes'
|
||||
desc 'Use the processes InSpec audit resource to test properties for programs that are running on the system.'
|
||||
example "
|
||||
describe processes('mysqld') do
|
||||
its('list.length') { should eq 1 }
|
||||
its('entries.length') { should eq 1 }
|
||||
its('users') { should eq ['mysql'] }
|
||||
its('states') { should include 'S' }
|
||||
end
|
||||
describe processes(/.+/).where { label != 'unconfined' && pid < 1000 } do
|
||||
its('users') { should cmp [] }
|
||||
end
|
||||
"
|
||||
|
||||
attr_reader :list,
|
||||
:users,
|
||||
:states
|
||||
|
||||
def initialize(grep)
|
||||
@grep = grep
|
||||
# turn into a regexp if it isn't one yet
|
||||
|
@ -31,19 +32,40 @@ module Inspec::Resources
|
|||
@list = all_cmds.find_all do |hm|
|
||||
hm[:command] =~ grep
|
||||
end
|
||||
|
||||
{ users: :user,
|
||||
states: :stat }.each do |var, key|
|
||||
instance_variable_set("@#{var}", @list.map { |l| l[key] }.uniq)
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Processes #{@grep.class == String ? @grep : @grep.inspect}"
|
||||
end
|
||||
|
||||
def list
|
||||
warn '[DEPRECATION] `processes.list` is deprecated. Please use `processes.entries` instead. It will be removed in version 2.0.0.'
|
||||
@list
|
||||
end
|
||||
|
||||
filter = FilterTable.create
|
||||
filter.add_accessor(:where)
|
||||
.add_accessor(:entries)
|
||||
.add(:labels, field: 'label')
|
||||
.add(:pids, field: 'pid')
|
||||
.add(:cpus, field: 'cpu')
|
||||
.add(:mem, field: 'mem')
|
||||
.add(:vsz, field: 'vsz')
|
||||
.add(:rss, field: 'rss')
|
||||
.add(:tty, field: 'tty')
|
||||
.add(:states, field: 'stat')
|
||||
.add(:start, field: 'start')
|
||||
.add(:time, field: 'time')
|
||||
.add(:users, field: 'user')
|
||||
.add(:commands, field: 'command')
|
||||
.connect(self, :filtered_processes)
|
||||
|
||||
private
|
||||
|
||||
def filtered_processes
|
||||
@list
|
||||
end
|
||||
|
||||
def ps_axo
|
||||
os = inspec.os
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ module Inspec::Resources
|
|||
return skip_resource "Can't read security policy" if cmd.exit_status.to_i != 0
|
||||
@content = cmd.stdout
|
||||
|
||||
if @content.empty? && file.size > 0
|
||||
if @content.empty? && !file.empty?
|
||||
return skip_resource "Can't read security policy"
|
||||
end
|
||||
@content
|
||||
|
|
|
@ -9,7 +9,7 @@ require 'utils/simpleconfig'
|
|||
module Inspec::Resources
|
||||
class SshConf < Inspec.resource(1)
|
||||
name 'ssh_config'
|
||||
desc 'Use the sshd_config InSpec audit resource to test configuration data for the Open SSH daemon located at /etc/ssh/sshd_config on Linux and UNIX platforms. sshd---the Open SSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command executation, and data exchanges.'
|
||||
desc 'Use the sshd_config InSpec audit resource to test configuration data for the Open SSH daemon located at /etc/ssh/sshd_config on Linux and UNIX platforms. sshd---the Open SSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command execution, and data exchanges.'
|
||||
example "
|
||||
describe sshd_config do
|
||||
its('Protocol') { should eq '2' }
|
||||
|
@ -62,7 +62,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
@content = file.content
|
||||
if @content.empty? && file.size > 0
|
||||
if @content.empty? && !file.empty?
|
||||
return skip_resource "Can't read file \"#{@conf_path}\""
|
||||
end
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ class SSL < Inspec.resource(1)
|
|||
elsif inspec.backend.class.to_s == 'Train::Transports::Local::Connection'
|
||||
@host = 'localhost'
|
||||
else
|
||||
fail 'Cannot determine host for SSL test. Please specify it or use a different target.'
|
||||
raise 'Cannot determine host for SSL test. Please specify it or use a different target.'
|
||||
end
|
||||
end
|
||||
@port = opts[:port] || 443
|
||||
|
|
|
@ -57,7 +57,7 @@ module Inspec::Resources
|
|||
name 'users'
|
||||
desc 'Use the users InSpec audit resource to test local user profiles. Users can be filtered by groups to which they belong, the frequency of required password changes, the directory paths to home and shell.'
|
||||
example "
|
||||
describe users.where(uid: 0).entries do
|
||||
describe users.where { uid == 0 }.entries do
|
||||
it { should eq ['root'] }
|
||||
its('uids') { should eq [1234] }
|
||||
its('gids') { should eq [1234] }
|
||||
|
@ -242,7 +242,7 @@ module Inspec::Resources
|
|||
|
||||
def has_authorized_key?(_compare_key)
|
||||
deprecated('has_authorized_key?')
|
||||
fail NotImplementedError
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def deprecated(name, alternative = nil)
|
||||
|
@ -292,7 +292,7 @@ module Inspec::Resources
|
|||
# groups: '',
|
||||
# }
|
||||
def identity(_username)
|
||||
fail 'user provider must implement the `identity` method'
|
||||
raise 'user provider must implement the `identity` method'
|
||||
end
|
||||
|
||||
# returns optional information about a user, eg shell
|
||||
|
@ -313,7 +313,7 @@ module Inspec::Resources
|
|||
|
||||
# returns an array with users
|
||||
def list_users
|
||||
fail 'user provider must implement the `list_users` method'
|
||||
raise 'user provider must implement the `list_users` method'
|
||||
end
|
||||
|
||||
# retuns all aspects of the user as one hash
|
||||
|
@ -556,7 +556,7 @@ module Inspec::Resources
|
|||
def parse_windows_account(username)
|
||||
account = username.split('\\')
|
||||
name = account.pop
|
||||
domain = account.pop if account.size > 0
|
||||
domain = account.pop if !account.empty?
|
||||
[name, domain]
|
||||
end
|
||||
|
||||
|
@ -565,7 +565,7 @@ module Inspec::Resources
|
|||
name, _domain = parse_windows_account(username)
|
||||
return if collect_user_details.nil?
|
||||
res = collect_user_details.select { |user| user[:username] == name }
|
||||
res[0] if res.length > 0
|
||||
res[0] if !res.empty?
|
||||
end
|
||||
|
||||
def list_users
|
||||
|
|
|
@ -41,6 +41,7 @@ module Inspec::Resources
|
|||
.add(:ids, field: 'id')
|
||||
.add(:socket_types, field: 'socket_type')
|
||||
.add(:types, field: 'type')
|
||||
.add(:protocols, field: 'protocol')
|
||||
.add(:wait, field: 'wait')
|
||||
.add(:disabled?) { |x| x.where('disable' => 'no').services.empty? }
|
||||
.add(:enabled?) { |x| x.where('disable' => 'yes').services.empty? }
|
||||
|
@ -56,7 +57,7 @@ module Inspec::Resources
|
|||
end
|
||||
|
||||
@contents[path] = file.content
|
||||
if @contents[path].empty? && file.size > 0
|
||||
if @contents[path].empty? && !file.empty?
|
||||
return skip_resource "Can't read file \"#{path}\""
|
||||
end
|
||||
|
||||
|
@ -91,8 +92,23 @@ module Inspec::Resources
|
|||
params
|
||||
end
|
||||
|
||||
# Method used to derive the default protocol used from the socket_type
|
||||
def default_protocol(type)
|
||||
case type
|
||||
when 'stream'
|
||||
'tcp'
|
||||
when 'dgram'
|
||||
'udp'
|
||||
else
|
||||
'unknown'
|
||||
end
|
||||
end
|
||||
|
||||
def service_lines
|
||||
@services ||= params['services'].values.flatten.map(&:params)
|
||||
@services ||= params['services'].values.flatten.map { |service|
|
||||
service.params['protocol'] ||= default_protocol(service.params['socket_type'])
|
||||
service.params
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,7 +27,7 @@ module SourceReaders
|
|||
|
||||
# This create a new instance of an InSpec profile source reader
|
||||
#
|
||||
# @param [SourceReader] target
|
||||
# @param [FileProvider] target An instance of a FileProvider object that can list files and read them
|
||||
# @param [String] metadata_source eg. inspec.yml or metadata.rb
|
||||
def initialize(target, metadata_source)
|
||||
@target = target
|
||||
|
|
|
@ -9,20 +9,20 @@ class CommandWrapper
|
|||
|
||||
def self.wrap(cmd, options)
|
||||
unless options.is_a?(Hash)
|
||||
fail 'All options for the command wrapper must be provided as a hash. '\
|
||||
raise 'All options for the command wrapper must be provided as a hash. '\
|
||||
"You entered: #{options.inspect}. Please consult the documentation."
|
||||
end
|
||||
|
||||
wrap = options[:wrap]
|
||||
if !wrap.nil? && !wrap.is_a?(Proc)
|
||||
fail "Called command wrapper with wrap: #{wrap.inspect}. It must be called with a Proc."
|
||||
raise "Called command wrapper with wrap: #{wrap.inspect}. It must be called with a Proc."
|
||||
elsif !wrap.nil?
|
||||
return wrap.call(cmd)
|
||||
end
|
||||
|
||||
shell = options[:shell]
|
||||
unless UNIX_SHELLS.include?(shell)
|
||||
fail "Don't know how to wrap commands for shell: #{shell.inspect}."
|
||||
raise "Don't know how to wrap commands for shell: #{shell.inspect}."
|
||||
end
|
||||
|
||||
path = options[:path] || shell
|
||||
|
|
|
@ -70,7 +70,7 @@ module FilterTable
|
|||
end
|
||||
|
||||
def new_entry(*_)
|
||||
fail "#{self.class} must not be used on its own. It must be inherited "\
|
||||
raise "#{self.class} must not be used on its own. It must be inherited "\
|
||||
'and the #new_entry method must be implemented. This is an internal '\
|
||||
'error and should not happen.'
|
||||
end
|
||||
|
|
|
@ -209,7 +209,12 @@ module XinetdParser
|
|||
next if inner_line.empty?
|
||||
|
||||
if inner_line == '}'
|
||||
res[cur_group] = SimpleConfig.new(simple_conf.join("\n"))
|
||||
if cur_group == 'defaults'
|
||||
res[cur_group] = SimpleConfig.new(simple_conf.join("\n"))
|
||||
else
|
||||
res[cur_group] ||= []
|
||||
res[cur_group].push(SimpleConfig.new(simple_conf.join("\n")))
|
||||
end
|
||||
cur_group = nil
|
||||
elsif rest.lstrip[0] == '{'
|
||||
cur_group = inner_line
|
||||
|
@ -224,7 +229,7 @@ module XinetdParser
|
|||
others.each { |ores|
|
||||
ores.each { |k, v|
|
||||
res[k] ||= []
|
||||
res[k].push(v)
|
||||
res[k].concat(v)
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -39,7 +39,7 @@ class PluginRegistry
|
|||
#
|
||||
# @return [PluginRegistry] plugin registry for this plugin
|
||||
def self.plugin_registry
|
||||
fail "Plugin #{self} does not implement `self.plugin_registry()`. This method is required"
|
||||
raise "Plugin #{self} does not implement `self.plugin_registry()`. This method is required"
|
||||
end
|
||||
|
||||
# Register a new plugin by name
|
||||
|
@ -47,7 +47,7 @@ class PluginRegistry
|
|||
# @param [String] the unique name of this plugin
|
||||
# @return [nil] disregard
|
||||
def self.name(name)
|
||||
fail "Trying to register #{self} with name == nil" if name.nil?
|
||||
raise "Trying to register #{self} with name == nil" if name.nil?
|
||||
@name = name
|
||||
plugin_registry.registry[name] = self
|
||||
end
|
||||
|
@ -72,7 +72,7 @@ class PluginRegistry
|
|||
# @param [String] target to try to resolve
|
||||
# @return [Plugin] instance if it can be resolved, nil otherwise
|
||||
def self.resolve(_target)
|
||||
fail "Plugin #{self} does not implement `self.resolve(target)`. This method is required"
|
||||
raise "Plugin #{self} does not implement `self.resolve(target)`. This method is required"
|
||||
end
|
||||
|
||||
# When a plugin's resolve doesn't lead to the final state, it can
|
||||
|
|
|
@ -33,7 +33,7 @@ class SimpleConfig
|
|||
raw_data = raw_data.tr(options[:line_separator], "\n")
|
||||
end
|
||||
rest = raw_data
|
||||
rest = parse_rest(rest, options) while rest.length > 0
|
||||
rest = parse_rest(rest, options) until rest.empty?
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -135,7 +135,7 @@ class ResourceDocs
|
|||
|
||||
def render_path(path)
|
||||
abs = File.join(@root, path)
|
||||
fail "Can't find file to render in #{abs}" unless File.file?(abs)
|
||||
raise "Can't find file to render in #{abs}" unless File.file?(abs)
|
||||
|
||||
ERB.new(File.read(abs)).result(binding)
|
||||
end
|
||||
|
|
|
@ -28,7 +28,7 @@ end
|
|||
module Verify
|
||||
def self.file(path)
|
||||
return print("\033[32m.\033[0m") if File.file?(path)
|
||||
fail "Failed to build this step. Looking for file in #{path} but it doesn't exist."
|
||||
raise "Failed to build this step. Looking for file in #{path} but it doesn't exist."
|
||||
end
|
||||
|
||||
def self.ok
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace :www do
|
|||
task :assemble do
|
||||
Log.section 'Copy only tutorial into middleman build directory'
|
||||
sh('rsync -a --exclude=index.html www/tutorial/dist/* www/build/')
|
||||
sh('cp www/tutorial/dist/index.html www/build/tutorial.html')
|
||||
end
|
||||
|
||||
desc 'Builds the full site locally'
|
||||
|
@ -64,15 +65,15 @@ namespace :www do
|
|||
end
|
||||
|
||||
unless File.directory?(dst) && File.file?(File.join(dst, 'index.html'))
|
||||
fail 'It looks like the site was not build. Aborting.'
|
||||
raise 'It looks like the site was not build. Aborting.'
|
||||
end
|
||||
|
||||
# check if git exists
|
||||
sh('command -v git >/dev/null 2>&1') ||
|
||||
fail("It looks like `git` isn't installed. It is required to run this build task.")
|
||||
raise("It looks like `git` isn't installed. It is required to run this build task.")
|
||||
|
||||
unless sh('git diff-index --quiet HEAD --')
|
||||
fail 'Please make sure you have no uncommitted changes in this repository.'
|
||||
raise 'Please make sure you have no uncommitted changes in this repository.'
|
||||
end
|
||||
|
||||
File.write('www/build/CNAME', 'inspec.io')
|
||||
|
@ -86,7 +87,7 @@ namespace :www do
|
|||
|
||||
current_branch = `git rev-parse --abbrev-ref HEAD`.strip
|
||||
if current_branch.empty?
|
||||
fail 'Cannot determine current branch to go back to! Aborting.'
|
||||
raise 'Cannot determine current branch to go back to! Aborting.'
|
||||
end
|
||||
|
||||
Log.info 'Create empty gh-pages branch'
|
||||
|
|
|
@ -127,6 +127,11 @@ describe 'inspec shell tests' do
|
|||
out
|
||||
end
|
||||
|
||||
it 'displays the target device information for the user without requiring the help command' do
|
||||
out = do_shell('1+1')
|
||||
out.stdout.must_include 'You are currently running on:'
|
||||
end
|
||||
|
||||
it 'provides a help command' do
|
||||
out = do_shell('help')
|
||||
out.stdout.must_include 'Available commands:'
|
||||
|
|
|
@ -58,7 +58,7 @@ describe 'example inheritance profile' do
|
|||
File.exist?(lockfile).must_equal true
|
||||
|
||||
out = inspec('exec ' + meta_path + ' -l debug --no-create-lockfile')
|
||||
out.stdout.force_encoding(Encoding::UTF_8).must_include 'Using cached dependency for {:url=>"https://github.com/dev-sec/tests-ssh-hardening/archive/master.tar.gz"'
|
||||
out.stdout.force_encoding(Encoding::UTF_8).must_include 'Using cached dependency for {:url=>"https://github.com/dev-sec/ssh-baseline/archive/master.tar.gz"'
|
||||
out.stdout.force_encoding(Encoding::UTF_8).must_include 'Using cached dependency for {:url=>"https://github.com/dev-sec/ssl-benchmark/archive/master.tar.gz"'
|
||||
out.stdout.force_encoding(Encoding::UTF_8).must_include 'Using cached dependency for {:url=>"https://github.com/chris-rock/windows-patch-benchmark/archive/master.tar.gz"'
|
||||
out.stdout.force_encoding(Encoding::UTF_8).index('Fetching URL:').must_be_nil
|
||||
|
@ -83,7 +83,7 @@ describe 'example inheritance profile' do
|
|||
out.exit_status.must_equal 0
|
||||
hm = JSON.load(File.read(dst.path))
|
||||
hm['name'].must_equal 'meta-profile'
|
||||
hm['controls'].length.must_equal 78
|
||||
hm['controls'].length.must_be :>=, 78
|
||||
|
||||
# copies = out.stdout.scan(/Copy .* to cache directory/).length
|
||||
# copies.must_equal 3
|
||||
|
@ -124,7 +124,6 @@ describe 'example inheritance profile' do
|
|||
it 'use lockfile in tarball' do
|
||||
# ensure the profile is vendored and packaged as tar
|
||||
out = inspec('vendor ' + meta_path + ' --overwrite')
|
||||
out.exit_status.must_equal 0
|
||||
out = inspec('archive ' + meta_path + ' --overwrite')
|
||||
out.exit_status.must_equal 0
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ end
|
|||
|
||||
require 'minitest/autorun'
|
||||
require 'minitest/spec'
|
||||
require 'webmock/minitest'
|
||||
require 'mocha/setup'
|
||||
require 'fileutils'
|
||||
require 'pathname'
|
||||
|
@ -49,6 +50,7 @@ class MockLoader
|
|||
ubuntu1204: { name: 'ubuntu', family: 'debian', release: '12.04', arch: 'x86_64' },
|
||||
ubuntu1404: { name: 'ubuntu', family: 'debian', release: '14.04', arch: 'x86_64' },
|
||||
ubuntu1504: { name: 'ubuntu', family: 'debian', release: '15.04', arch: 'x86_64' },
|
||||
ubuntu1604: { name: 'ubuntu', family: 'debian', release: '16.04', arch: 'x86_64' },
|
||||
mint17: { name: 'linuxmint', family: 'debian', release: '17.3', arch: 'x86_64' },
|
||||
mint18: { name: 'linuxmint', family: 'debian', release: '18', arch: 'x86_64' },
|
||||
windows: { name: 'windows', family: 'windows', release: '6.2.9200', arch: 'x86_64' },
|
||||
|
@ -127,6 +129,7 @@ class MockLoader
|
|||
'/etc/xinetd.d' => mockfile.call('xinetd.d'),
|
||||
'/etc/xinetd.d/chargen-stream' => mockfile.call('xinetd.d_chargen-stream'),
|
||||
'/etc/xinetd.d/chargen-dgram' => mockfile.call('xinetd.d_chargen-dgram'),
|
||||
'/etc/xinetd.d/echo' => mockfile.call('xinetd.d_echo'),
|
||||
'/etc/sysctl.conf' => mockfile.call('sysctl.conf'),
|
||||
'/etc/postgresql/9.4/main/postgresql.conf' => mockfile.call('postgresql.conf'),
|
||||
}
|
||||
|
@ -247,6 +250,10 @@ class MockLoader
|
|||
'pkginfo -l SUNWzfsr' => cmd.call('pkginfo-l-SUNWzfsr'),
|
||||
# solaris 11 package manager
|
||||
'pkg info system/file-system/zfs' => cmd.call('pkg-info-system-file-system-zfs'),
|
||||
# dpkg-query all packages
|
||||
"dpkg-query -W -f='${db:Status-Abbrev} ${Package} ${Version}\\n'" => cmd.call('dpkg-query-W'),
|
||||
# rpm query all packages
|
||||
"rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE}\\n'" => cmd.call('rpm-qa-queryformat'),
|
||||
# port netstat on solaris 10 & 11
|
||||
'netstat -an -f inet -f inet6' => cmd.call('s11-netstat-an-finet-finet6'),
|
||||
# xinetd configuration
|
||||
|
@ -269,6 +276,11 @@ class MockLoader
|
|||
"schtasks /query /v /fo csv /tn 'does-not-exist' | ConvertFrom-Csv | Select @{N='URI';E={$_.TaskName}},@{N='State';E={$_.Status.ToString()}},'Logon Mode','Last Result','Task To Run','Run As User','Scheduled Task State' | ConvertTo-Json -Compress" => cmd.call('schtasks-error'),
|
||||
# windows_task exist
|
||||
"schtasks /query /v /fo csv /tn 'WeLovePizza' | ConvertFrom-Csv | Select @{N='URI';E={$_.TaskName}},@{N='State';E={$_.Status.ToString()}},'Logon Mode','Last Result','Task To Run','Run As User','Scheduled Task State' | ConvertTo-Json -Compress" => cmd.call('schtasks-success'),
|
||||
'modinfo -F version dhcp' => cmd.call('modinfo-f-version-dhcp'),
|
||||
# crontab display for root / current user
|
||||
'crontab -l' => cmd.call('crontab-root'),
|
||||
# crontab display for non-current user
|
||||
'crontab -l -u foouser' => cmd.call('crontab-foouser')
|
||||
}
|
||||
|
||||
@backend
|
||||
|
|
|
@ -6,60 +6,329 @@ require 'helper'
|
|||
require 'inspec/objects'
|
||||
|
||||
describe 'Objects' do
|
||||
describe 'Test' do
|
||||
describe 'Inspec::Test' do
|
||||
let(:obj) { Inspec::Test.new }
|
||||
it 'constructs a simple resource+argument' do
|
||||
obj.qualifier = [['resource'], ['arg']]
|
||||
obj.to_ruby.must_equal "
|
||||
it 'constructs a simple resource + its("argument")' do
|
||||
obj.qualifier = [['resource'], ['version']]
|
||||
obj.matcher = 'cmp >='
|
||||
obj.expectation = '2.4.2'
|
||||
obj.to_ruby.must_equal '
|
||||
describe resource do
|
||||
its(\"arg\") { should }
|
||||
its("version") { should cmp >= "2.4.2" }
|
||||
end
|
||||
".strip
|
||||
'.strip
|
||||
end
|
||||
|
||||
# same as the above test but with it
|
||||
it 'constructs a simple resource.argument' do
|
||||
# [''] forces an 'it' instead of 'its':
|
||||
obj.qualifier = [['resource'], ['version'], ['']]
|
||||
obj.matcher = 'cmp >='
|
||||
obj.expectation = '2.4.2'
|
||||
obj.to_ruby.must_equal '
|
||||
describe resource.version do
|
||||
it { should cmp >= "2.4.2" }
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a simple resource+argument with to_s' do
|
||||
obj.qualifier = [['resource'], ['to_s']]
|
||||
obj.to_ruby.must_equal "
|
||||
obj.matcher = 'cmp'
|
||||
obj.expectation = Regexp.new('^Desc.+$')
|
||||
obj.to_ruby.must_equal '
|
||||
describe resource.to_s do
|
||||
it { should }
|
||||
it { should cmp(/^Desc.+$/) }
|
||||
end
|
||||
".strip
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a simple resource+argument with to_i' do
|
||||
obj.qualifier = [['resource'], ['to_i']]
|
||||
obj.to_ruby.must_equal "
|
||||
obj.matcher = 'cmp >'
|
||||
obj.expectation = 3
|
||||
obj.to_ruby.must_equal '
|
||||
describe resource.to_i do
|
||||
it { should }
|
||||
it { should cmp > 3 }
|
||||
end
|
||||
".strip
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a simple resource+argument with array accessors' do
|
||||
obj.qualifier = [['resource'], ['name[2]']]
|
||||
obj.to_ruby.must_equal "
|
||||
obj.matcher = 'exist'
|
||||
obj.matcher = 'eq'
|
||||
obj.expectation = 'mytest'
|
||||
obj.to_ruby.must_equal '
|
||||
describe resource.name[2] do
|
||||
it { should }
|
||||
it { should eq "mytest" }
|
||||
end
|
||||
".strip
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a simple resource+argument with method calls' do
|
||||
obj.qualifier = [['resource'], ['hello', 'world']]
|
||||
obj.to_ruby.must_equal "
|
||||
describe resource.hello(\"world\") do
|
||||
it { should }
|
||||
obj.matcher = 'eq'
|
||||
obj.expectation = 'mytest'
|
||||
obj.to_ruby.must_equal '
|
||||
describe resource.hello("world") do
|
||||
it { should eq "mytest" }
|
||||
end
|
||||
".strip
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a simple resource+argument with method calls' do
|
||||
obj.qualifier = [['resource'], [:world]]
|
||||
obj.to_ruby.must_equal "
|
||||
obj.qualifier = [['resource'], [:mode]]
|
||||
obj.matcher = 'cmp'
|
||||
obj.expectation = '0755'
|
||||
obj.to_ruby.must_equal '
|
||||
describe resource do
|
||||
its(\"world\") { should }
|
||||
its("mode") { should cmp "0755" }
|
||||
end
|
||||
".strip
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a resource+argument block with method call, matcher and expectation' do
|
||||
obj.qualifier = [['command','ls /etc'], ['exit_status']]
|
||||
obj.matcher = 'eq'
|
||||
obj.expectation = 0
|
||||
|
||||
obj.to_ruby.must_equal '
|
||||
describe command("ls /etc") do
|
||||
its("exit_status") { should eq 0 }
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a simple describe with static data, negated regex matcher and expectation' do
|
||||
obj.qualifier = [['"aaa"']]
|
||||
obj.matcher = 'match'
|
||||
obj.negate!
|
||||
obj.expectation = Regexp.new('^aa.*')
|
||||
|
||||
obj.to_ruby.must_equal '
|
||||
describe "aaa" do
|
||||
it { should_not match(/^aa.*/) }
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a resource+argument block without a property call' do
|
||||
obj.qualifier = [['service', 'avahi-daemon']]
|
||||
obj.qualifier.push(["info['properties']['UnitFileState']"])
|
||||
obj.expectation = "enabled"
|
||||
obj.matcher = 'eq'
|
||||
obj.to_ruby.must_equal '
|
||||
describe service("avahi-daemon").info[\'properties\'][\'UnitFileState\'] do
|
||||
it { should eq "enabled" }
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe 'Inspec::EachLoop, each_loop' do
|
||||
it 'constructs an each loop to match listening addresses' do
|
||||
loop_obj = Inspec::EachLoop.new
|
||||
loop_obj.qualifier = [['port', 25]]
|
||||
loop_obj.qualifier.push(['addresses'])
|
||||
obj = Inspec::Test.new
|
||||
obj.matcher = 'match'
|
||||
obj.negate!
|
||||
obj.expectation = '0.0.0.0'
|
||||
loop_obj.add_test(obj)
|
||||
loop_obj.to_ruby.must_equal '
|
||||
port(25).addresses.each do |entry|
|
||||
describe entry do
|
||||
it { should_not match "0.0.0.0" }
|
||||
end
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe 'Inspec::List' do
|
||||
it 'constructs a list filtering test' do
|
||||
list_obj = Inspec::List.new([['passwd']])
|
||||
list_obj.qualifier.push(["where { user =~ /^(?!root|sync|shutdown|halt).*$/ }"])
|
||||
|
||||
obj = Inspec::Test.new
|
||||
obj.qualifier = list_obj.qualifier
|
||||
obj.matcher = 'be_empty'
|
||||
obj.qualifier.push(['entries'])
|
||||
obj.negate!
|
||||
obj.to_ruby.must_equal '
|
||||
describe passwd.where { user =~ /^(?!root|sync|shutdown|halt).*$/ } do
|
||||
its("entries") { should_not be_empty }
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe 'Inspec::OrTest and Inspec::Control' do
|
||||
let(:obj1) do
|
||||
obj1 = Inspec::Test.new
|
||||
obj1.qualifier = [['command','ls /etc'], ['exit_status']]
|
||||
obj1.matcher = 'eq'
|
||||
obj1.expectation = 0
|
||||
obj1
|
||||
end
|
||||
let(:obj2) do
|
||||
obj2 = obj1.dup
|
||||
obj2.negate!
|
||||
obj2.expectation = 100
|
||||
obj2
|
||||
end
|
||||
|
||||
it 'constructs a simple describe.one block wrapping two tests' do
|
||||
or_obj = Inspec::OrTest.new([obj1,obj2])
|
||||
or_obj.to_ruby.must_equal '
|
||||
describe.one do
|
||||
describe command("ls /etc") do
|
||||
its("exit_status") { should eq 0 }
|
||||
end
|
||||
describe command("ls /etc") do
|
||||
its("exit_status") { should_not eq 100 }
|
||||
end
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'negates a describe.one block, wow!' do
|
||||
or_obj = Inspec::OrTest.new([obj1,obj2])
|
||||
or_obj.negate!
|
||||
or_obj.to_ruby.must_equal '
|
||||
describe command("ls /etc") do
|
||||
its("exit_status") { should_not eq 0 }
|
||||
end
|
||||
describe command("ls /etc") do
|
||||
its("exit_status") { should eq 100 }
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'loops a describe.one block, ooooooo!' do
|
||||
res = Inspec::EachLoop.new
|
||||
res.qualifier.push(['(1..5)'])
|
||||
# already defined in the let block:
|
||||
obj1.matcher = 'eq entity'
|
||||
obj2.matcher = 'eq entity'
|
||||
obj1.remove_expectation
|
||||
obj2.remove_expectation
|
||||
|
||||
or_obj = Inspec::OrTest.new([obj1,obj2])
|
||||
res.tests = [or_obj]
|
||||
|
||||
res.to_ruby.must_equal '
|
||||
(1..5).each do |entry|
|
||||
describe.one do
|
||||
describe command("ls /etc") do
|
||||
its("exit_status") { should eq entity }
|
||||
end
|
||||
describe command("ls /etc") do
|
||||
its("exit_status") { should_not eq entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
|
||||
it 'constructs a control' do
|
||||
control = Inspec::Control.new
|
||||
control.add_test(obj1)
|
||||
control.id = 'sample.control.id'
|
||||
control.title = 'Sample Control Important Title'
|
||||
control.desc = 'The most critical control the world has ever seen'
|
||||
control.impact = 1.0
|
||||
control.to_ruby.must_equal '
|
||||
control "sample.control.id" do
|
||||
title "Sample Control Important Title"
|
||||
desc "The most critical control the world has ever seen"
|
||||
impact 1.0
|
||||
describe command("ls /etc") do
|
||||
its("exit_status") { should eq 0 }
|
||||
end
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Inspec::Variable, take #1' do
|
||||
it 'constructs a control with variable to instantiate a resource only once' do
|
||||
control = Inspec::Control.new
|
||||
variable = Inspec::Value.new([['command','which grep']])
|
||||
variable_id = variable.name_variable.to_s
|
||||
|
||||
obj1 = Inspec::Test.new
|
||||
obj1.variables.push(variable)
|
||||
obj1.qualifier.push([variable_id])
|
||||
obj1.qualifier.push(['exit_status'])
|
||||
obj1.matcher = 'eq'
|
||||
obj1.expectation = 0
|
||||
control.add_test(obj1)
|
||||
|
||||
obj2 = Inspec::Test.new
|
||||
obj2.qualifier.push([variable_id.to_s])
|
||||
obj2.qualifier.push(['stdout'])
|
||||
obj2.matcher = 'contain'
|
||||
obj2.expectation = 'grep'
|
||||
control.add_test(obj2)
|
||||
|
||||
control.id = 'variable.control.id'
|
||||
control.title = 'Variable Control Important Title'
|
||||
control.desc = 'The most variable control the world has ever seen'
|
||||
control.impact = 1.0
|
||||
control.to_ruby.must_equal '
|
||||
control "variable.control.id" do
|
||||
title "Variable Control Important Title"
|
||||
desc "The most variable control the world has ever seen"
|
||||
impact 1.0
|
||||
a = command("which grep")
|
||||
describe a do
|
||||
its("exit_status") { should eq 0 }
|
||||
end
|
||||
describe a do
|
||||
its("stdout") { should contain "grep" }
|
||||
end
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe 'Inspec::Variable, take #2' do
|
||||
it 'constructs a control with variable, loop and var reference' do
|
||||
control = Inspec::Control.new
|
||||
command_value = /^\/usr\/bin\/chrony/
|
||||
pid_filter = '>'
|
||||
pid_value = 0
|
||||
loopy = Inspec::EachLoop.new
|
||||
loopy.qualifier = [['processes', command_value]]
|
||||
loopy.qualifier.push(["where { pid #{pid_filter} #{pid_value} }.entries"])
|
||||
obj = loopy.add_test
|
||||
|
||||
variable = Inspec::Value.new([['passwd.where { user == "_chrony" }.uids.first']])
|
||||
variable_id = variable.name_variable.to_s
|
||||
obj.variables.push(variable)
|
||||
obj.qualifier = [['user(entry.user)'], ['uid']]
|
||||
obj.matcher = "cmp #{variable_id}"
|
||||
|
||||
control.add_test(obj)
|
||||
control.id = 'variable.control.id'
|
||||
control.impact = 0.1
|
||||
control.to_ruby.must_equal '
|
||||
control "variable.control.id" do
|
||||
impact 0.1
|
||||
a = passwd.where { user == "_chrony" }.uids.first
|
||||
describe user(entry.user) do
|
||||
its("uid") { should cmp a }
|
||||
end
|
||||
end
|
||||
'.strip
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
5
test/unit/mock/cmd/crontab-foouser
Normal file
5
test/unit/mock/cmd/crontab-foouser
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# This is a sample crontab file for unit testing, for user 'foouser'
|
||||
#
|
||||
|
||||
* * * * * /path/to/script3
|
10
test/unit/mock/cmd/crontab-root
Normal file
10
test/unit/mock/cmd/crontab-root
Normal file
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# This is a sample crontab file for unit testing
|
||||
#
|
||||
|
||||
|
||||
# entry number 1
|
||||
0 2 11 9 4 /path/to/script1
|
||||
|
||||
# entry number 2
|
||||
1 3 12 10 5 /path/to/script2 arg1 arg2
|
12
test/unit/mock/cmd/dpkg-query-W
Normal file
12
test/unit/mock/cmd/dpkg-query-W
Normal file
|
@ -0,0 +1,12 @@
|
|||
ii bash 4.3-14ubuntu1.1
|
||||
rc fakeroot 1.20.2-1ubuntu1
|
||||
rc libfakeroot 1.20.2-1ubuntu1
|
||||
ii overlayroot 0.27ubuntu1.2
|
||||
ii vim 2:7.4.1689-3ubuntu1.2
|
||||
ii vim-common 2:7.4.1689-3ubuntu1.2
|
||||
ii xorg 1:7.7+13ubuntu3
|
||||
ii xorg-docs-core 1:1.7.1-1ubuntu1
|
||||
ii xserver-common 2:1.18.4-0ubuntu0.2
|
||||
ii xserver-xorg 1:7.7+13ubuntu3
|
||||
ii xserver-xorg-core 2:1.18.4-0ubuntu0.2
|
||||
ii xserver-xorg-input-all 1:7.7+13ubuntu3
|
|
@ -1,2 +1,3 @@
|
|||
/etc/xinetd.d/chargen-stream
|
||||
/etc/xinetd.d/chargen-dgram
|
||||
/etc/xinetd.d/echo
|
||||
|
|
1
test/unit/mock/cmd/modinfo-f-version-dhcp
Normal file
1
test/unit/mock/cmd/modinfo-f-version-dhcp
Normal file
|
@ -0,0 +1 @@
|
|||
3.2.2
|
10
test/unit/mock/cmd/rpm-qa-queryformat
Normal file
10
test/unit/mock/cmd/rpm-qa-queryformat
Normal file
|
@ -0,0 +1,10 @@
|
|||
attr 2.4.44-7.el6
|
||||
perl-Pod-Escapes 1.04-141.el6_7.1
|
||||
perl-version 0.77-141.el6_7.1
|
||||
perl-Pod-Simple 3.13-141.el6_7.1
|
||||
vim-filesystem 7.4.629-5.el6
|
||||
gpm-libs 1.20.6-12.el6
|
||||
mlocate 0.22.2-6.el6
|
||||
ntpdate 4.2.6p5-10.el6.centos.1
|
||||
chef-compliance 1.3.1-1.el6
|
||||
nc 1.84-24.el6
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue