mirror of
https://github.com/inspec/inspec
synced 2024-11-22 20:53:11 +00:00
Merge branch 'main' into inspec-6
This commit is contained in:
commit
1c6bfa8f24
154 changed files with 4575 additions and 582 deletions
69
CHANGELOG.md
69
CHANGELOG.md
|
@ -1,37 +1,59 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
|
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
|
||||||
<!-- latest_release 5.18.3 -->
|
<!-- latest_release 5.20.1 -->
|
||||||
## [v5.18.3](https://github.com/inspec/inspec/tree/v5.18.3) (2022-06-10)
|
## [v5.20.1](https://github.com/inspec/inspec/tree/v5.20.1) (2022-08-04)
|
||||||
|
|
||||||
#### Merged Pull Requests
|
#### Merged Pull Requests
|
||||||
- Dk/matchers rewrite [#6007](https://github.com/inspec/inspec/pull/6007) ([dkumaras](https://github.com/dkumaras))
|
- Fix the dependabot adding ffi (1.15.5-x64-unknown) to omnibus bump [#6213](https://github.com/inspec/inspec/pull/6213) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
<!-- latest_release -->
|
<!-- latest_release -->
|
||||||
|
|
||||||
<!-- release_rollup since=5.17.4 -->
|
<!-- release_rollup since=5.18.14 -->
|
||||||
### Changes since 5.17.4 release
|
### Changes since 5.18.14 release
|
||||||
|
|
||||||
#### Merged Pull Requests
|
#### Merged Pull Requests
|
||||||
- Dk/matchers rewrite [#6007](https://github.com/inspec/inspec/pull/6007) ([dkumaras](https://github.com/dkumaras)) <!-- 5.18.3 -->
|
- Fix the dependabot adding ffi (1.15.5-x64-unknown) to omnibus bump [#6213](https://github.com/inspec/inspec/pull/6213) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.20.1 -->
|
||||||
- Fixed Lint/DuplicateMethods: Method Inspec::Resources::Service#resource_id is defined at both [#6132](https://github.com/inspec/inspec/pull/6132) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.18.2 -->
|
- Adds podman resources. [#6183](https://github.com/inspec/inspec/pull/6183) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.20.0 -->
|
||||||
- CFINSPEC-291: Fix `processes` resource to consider processes without `path` on Windows [#6100](https://github.com/inspec/inspec/pull/6100) ([ahasunos](https://github.com/ahasunos)) <!-- 5.18.1 -->
|
- CFINSPEC-237 Added enhanced_outcomes option [#6145](https://github.com/inspec/inspec/pull/6145) ([Nik08](https://github.com/Nik08)) <!-- 5.19.0 -->
|
||||||
- CFINSPEC-167: Profile Signing Rollup [#5995](https://github.com/inspec/inspec/pull/5995) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.18.0 -->
|
- CFINSPEC-400 Fix for verify pipeline failure [#6218](https://github.com/inspec/inspec/pull/6218) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.18.17 -->
|
||||||
- Bump berkshelf from 8.0.0 to 8.0.2 in /omnibus [#6114](https://github.com/inspec/inspec/pull/6114) ([dependabot[bot]](https://github.com/dependabot[bot])) <!-- 5.17.18 -->
|
- Docs spellcheck [#6214](https://github.com/inspec/inspec/pull/6214) ([IanMadd](https://github.com/IanMadd)) <!-- 5.18.16 -->
|
||||||
- CFINSPEC-262 - Handle resource_id in error situation [#6119](https://github.com/inspec/inspec/pull/6119) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.17.17 -->
|
- Trivial README change to trigger new omnibus build [#6203](https://github.com/inspec/inspec/pull/6203) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 5.18.15 -->
|
||||||
- Handle resource_id in error situations [#6118](https://github.com/inspec/inspec/pull/6118) ([ahasunos](https://github.com/ahasunos)) <!-- 5.17.16 -->
|
|
||||||
- CFINSPEC-273 Adds resource_id group 12 [#6112](https://github.com/inspec/inspec/pull/6112) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.17.15 -->
|
|
||||||
- CFINSPEC-270 Adds resource_id group9 [#6111](https://github.com/inspec/inspec/pull/6111) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.17.14 -->
|
|
||||||
- CFINSPEC-265 Group 4 - Added resource_id in resources [#6109](https://github.com/inspec/inspec/pull/6109) ([Nik08](https://github.com/Nik08)) <!-- 5.17.13 -->
|
|
||||||
- CFINSPEC-269 Adds resource_id group 8 [#6107](https://github.com/inspec/inspec/pull/6107) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.17.12 -->
|
|
||||||
- CFINSPEC-268 Adds resource_id group 7 [#6105](https://github.com/inspec/inspec/pull/6105) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.17.11 -->
|
|
||||||
- Fix the key duplication error warning in the mock_loader.rb [#6120](https://github.com/inspec/inspec/pull/6120) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.17.10 -->
|
|
||||||
- CFINSPEC-266: resource_ids group 5 [#6103](https://github.com/inspec/inspec/pull/6103) ([ahasunos](https://github.com/ahasunos)) <!-- 5.17.9 -->
|
|
||||||
- CFINSPEC-262 Adds resource_id group 1 [#6102](https://github.com/inspec/inspec/pull/6102) ([Vasu1105](https://github.com/Vasu1105)) <!-- 5.17.8 -->
|
|
||||||
- CFINSPEC-267: resource_ids group 6 [#6101](https://github.com/inspec/inspec/pull/6101) ([ahasunos](https://github.com/ahasunos)) <!-- 5.17.7 -->
|
|
||||||
- CFINSPEC-95: Enhance `x509_certificate` resource [#6041](https://github.com/inspec/inspec/pull/6041) ([ahasunos](https://github.com/ahasunos)) <!-- 5.17.6 -->
|
|
||||||
- Bump rack from 2.2.3 to 2.2.3.1 in /omnibus [#6098](https://github.com/inspec/inspec/pull/6098) ([dependabot[bot]](https://github.com/dependabot[bot])) <!-- 5.17.5 -->
|
|
||||||
<!-- release_rollup -->
|
<!-- release_rollup -->
|
||||||
|
|
||||||
<!-- latest_stable_release -->
|
<!-- latest_stable_release -->
|
||||||
|
## [v5.18.14](https://github.com/inspec/inspec/tree/v5.18.14) (2022-07-13)
|
||||||
|
|
||||||
|
#### Merged Pull Requests
|
||||||
|
- Bump rack from 2.2.3 to 2.2.3.1 in /omnibus [#6098](https://github.com/inspec/inspec/pull/6098) ([dependabot[bot]](https://github.com/dependabot[bot]))
|
||||||
|
- CFINSPEC-95: Enhance `x509_certificate` resource [#6041](https://github.com/inspec/inspec/pull/6041) ([ahasunos](https://github.com/ahasunos))
|
||||||
|
- CFINSPEC-267: resource_ids group 6 [#6101](https://github.com/inspec/inspec/pull/6101) ([ahasunos](https://github.com/ahasunos))
|
||||||
|
- CFINSPEC-262 Adds resource_id group 1 [#6102](https://github.com/inspec/inspec/pull/6102) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- CFINSPEC-266: resource_ids group 5 [#6103](https://github.com/inspec/inspec/pull/6103) ([ahasunos](https://github.com/ahasunos))
|
||||||
|
- Fix the key duplication error warning in the mock_loader.rb [#6120](https://github.com/inspec/inspec/pull/6120) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- CFINSPEC-268 Adds resource_id group 7 [#6105](https://github.com/inspec/inspec/pull/6105) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- CFINSPEC-269 Adds resource_id group 8 [#6107](https://github.com/inspec/inspec/pull/6107) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- CFINSPEC-265 Group 4 - Added resource_id in resources [#6109](https://github.com/inspec/inspec/pull/6109) ([Nik08](https://github.com/Nik08))
|
||||||
|
- CFINSPEC-270 Adds resource_id group9 [#6111](https://github.com/inspec/inspec/pull/6111) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- CFINSPEC-273 Adds resource_id group 12 [#6112](https://github.com/inspec/inspec/pull/6112) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- Handle resource_id in error situations [#6118](https://github.com/inspec/inspec/pull/6118) ([ahasunos](https://github.com/ahasunos))
|
||||||
|
- CFINSPEC-262 - Handle resource_id in error situation [#6119](https://github.com/inspec/inspec/pull/6119) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- Bump berkshelf from 8.0.0 to 8.0.2 in /omnibus [#6114](https://github.com/inspec/inspec/pull/6114) ([dependabot[bot]](https://github.com/dependabot[bot]))
|
||||||
|
- CFINSPEC-167: Profile Signing Rollup [#5995](https://github.com/inspec/inspec/pull/5995) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- CFINSPEC-291: Fix `processes` resource to consider processes without `path` on Windows [#6100](https://github.com/inspec/inspec/pull/6100) ([ahasunos](https://github.com/ahasunos))
|
||||||
|
- Fixed Lint/DuplicateMethods: Method Inspec::Resources::Service#resource_id is defined at both [#6132](https://github.com/inspec/inspec/pull/6132) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- Dk/matchers rewrite [#6007](https://github.com/inspec/inspec/pull/6007) ([dkumaras](https://github.com/dkumaras))
|
||||||
|
- Add inspec-6 branch as release branch [#6136](https://github.com/inspec/inspec/pull/6136) ([clintoncwolfe](https://github.com/clintoncwolfe))
|
||||||
|
- add ruby test 3.1 in verify pipeline [#5892](https://github.com/inspec/inspec/pull/5892) ([jayashrig158](https://github.com/jayashrig158))
|
||||||
|
- Updated plugins doc with send_report functionality [#6144](https://github.com/inspec/inspec/pull/6144) ([Nik08](https://github.com/Nik08))
|
||||||
|
- Bump octokit from 4.23.0 to 4.25.0 in /omnibus [#6146](https://github.com/inspec/inspec/pull/6146) ([dependabot[bot]](https://github.com/dependabot[bot]))
|
||||||
|
- Fixes for Buildkite Issues [#6161](https://github.com/inspec/inspec/pull/6161) ([Nik08](https://github.com/Nik08))
|
||||||
|
- CFINSPEC-238 Enhanced Outcomes Design Doc [#6152](https://github.com/inspec/inspec/pull/6152) ([clintoncwolfe](https://github.com/clintoncwolfe))
|
||||||
|
- Add k8s section to resources index page [#6167](https://github.com/inspec/inspec/pull/6167) ([IanMadd](https://github.com/IanMadd))
|
||||||
|
- Windows fix for dependent profiles [#6173](https://github.com/inspec/inspec/pull/6173) ([Nik08](https://github.com/Nik08))
|
||||||
|
- Bump omnibus-software from `a9b13a0` to `7bb8c7b` in /omnibus [#6191](https://github.com/inspec/inspec/pull/6191) ([dependabot[bot]](https://github.com/dependabot[bot]))
|
||||||
|
- Trial - Update the omnibus/Gemfile.lock (can be the reason for omnibus build failure) [#6195](https://github.com/inspec/inspec/pull/6195) ([Vasu1105](https://github.com/Vasu1105))
|
||||||
|
- CFINSPEC-239 Attestations Design Doc [#6188](https://github.com/inspec/inspec/pull/6188) ([clintoncwolfe](https://github.com/clintoncwolfe))
|
||||||
|
<!-- latest_stable_release -->
|
||||||
|
|
||||||
## [v5.17.4](https://github.com/inspec/inspec/tree/v5.17.4) (2022-05-25)
|
## [v5.17.4](https://github.com/inspec/inspec/tree/v5.17.4) (2022-05-25)
|
||||||
|
|
||||||
#### Merged Pull Requests
|
#### Merged Pull Requests
|
||||||
|
@ -52,7 +74,6 @@
|
||||||
- fixing bad markdown syntax [#6066](https://github.com/inspec/inspec/pull/6066) ([replicajune](https://github.com/replicajune))
|
- fixing bad markdown syntax [#6066](https://github.com/inspec/inspec/pull/6066) ([replicajune](https://github.com/replicajune))
|
||||||
- Add vale config to docs in inspec repository [#6065](https://github.com/inspec/inspec/pull/6065) ([IanMadd](https://github.com/IanMadd))
|
- Add vale config to docs in inspec repository [#6065](https://github.com/inspec/inspec/pull/6065) ([IanMadd](https://github.com/IanMadd))
|
||||||
- Remove Hugo version from Netlify config [#6075](https://github.com/inspec/inspec/pull/6075) ([IanMadd](https://github.com/IanMadd))
|
- Remove Hugo version from Netlify config [#6075](https://github.com/inspec/inspec/pull/6075) ([IanMadd](https://github.com/IanMadd))
|
||||||
<!-- latest_stable_release -->
|
|
||||||
|
|
||||||
## [v5.14.0](https://github.com/inspec/inspec/tree/v5.14.0) (2022-04-21)
|
## [v5.14.0](https://github.com/inspec/inspec/tree/v5.14.0) (2022-04-21)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
FROM ubuntu:18.04
|
FROM ubuntu:18.04
|
||||||
LABEL maintainer="Chef Software, Inc. <docker@chef.io>"
|
LABEL maintainer="Chef Software, Inc. <docker@chef.io>"
|
||||||
|
|
||||||
ARG VERSION=5.17.4
|
ARG VERSION=5.18.14
|
||||||
ARG CHANNEL=stable
|
ARG CHANNEL=stable
|
||||||
|
|
||||||
ENV PATH=/opt/inspec/bin:/opt/inspec/embedded/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
ENV PATH=/opt/inspec/bin:/opt/inspec/embedded/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -25,7 +25,7 @@ end
|
||||||
group :test do
|
group :test do
|
||||||
gem "chefstyle", "~> 2.0.3"
|
gem "chefstyle", "~> 2.0.3"
|
||||||
gem "concurrent-ruby", "~> 1.0"
|
gem "concurrent-ruby", "~> 1.0"
|
||||||
gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
|
gem "html-proofer", "~> 3.19.4", platforms: :ruby # do not attempt to run proofer on windows. Pinned to 3.19.4 as test is breaking in updated versions.
|
||||||
gem "json_schemer", ">= 0.2.1", "< 0.2.19"
|
gem "json_schemer", ">= 0.2.1", "< 0.2.19"
|
||||||
gem "m"
|
gem "m"
|
||||||
gem "minitest-sprint", "~> 1.0"
|
gem "minitest-sprint", "~> 1.0"
|
||||||
|
|
|
@ -56,7 +56,7 @@ inspec exec test.rb -t docker://container_id
|
||||||
|
|
||||||
Chef InSpec requires Ruby ( >= 2.7 ).
|
Chef InSpec requires Ruby ( >= 2.7 ).
|
||||||
|
|
||||||
Note: Versions of Chef InSpec 4.0 and later require accepting the EULA to use. Please visit the [license acceptance page](https://docs.chef.io/chef_license_accept.html) on the Chef docs site for more information.
|
All currently supported versions of Chef InSpec (4.0 and later) require accepting the EULA to use. Please visit the [license acceptance page](https://docs.chef.io/chef_license_accept.html) on the Chef docs site for more information.
|
||||||
|
|
||||||
### Install as package
|
### Install as package
|
||||||
|
|
||||||
|
|
82
dev-docs/attestations.md
Normal file
82
dev-docs/attestations.md
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
# Attestations
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
As a compliance officer,
|
||||||
|
I want to mark skipped controls as manually passed or failed
|
||||||
|
so that I can manually complete the profile.
|
||||||
|
|
||||||
|
As a compliance officer,
|
||||||
|
I want to set an expiration date and a justification for my attestations
|
||||||
|
so that I can control their application.
|
||||||
|
|
||||||
|
As a compliance officer,
|
||||||
|
I want flexibility in the file format accepted by the attestations system (XLSX, YAML, CSV, JSON),
|
||||||
|
so that I can use a familiar file format.
|
||||||
|
|
||||||
|
When used with Enhanced Outcomes, this becomes handling `Not Reviewed` controls.
|
||||||
|
|
||||||
|
## Mechanism
|
||||||
|
|
||||||
|
### CLI option desirable
|
||||||
|
|
||||||
|
`inspec exec profilename --attestation-file file.???`
|
||||||
|
|
||||||
|
The new option is named like `--waiver-file` - singular, with `-file`. You may provide multiple arguments for the option.
|
||||||
|
|
||||||
|
The file can be any of the following formats: `YAML`, `XLSX`, `CSV`, or `JSON`.
|
||||||
|
|
||||||
|
#### YAML and JSON
|
||||||
|
|
||||||
|
An array of Hashes.
|
||||||
|
|
||||||
|
#### XLSX and CSV
|
||||||
|
|
||||||
|
XLSX is the first sheet in the file.
|
||||||
|
|
||||||
|
Both formats assume a header row.
|
||||||
|
|
||||||
|
### Fields in the file
|
||||||
|
|
||||||
|
#### control_id
|
||||||
|
|
||||||
|
_Required_. Matches control ID of the control.
|
||||||
|
|
||||||
|
#### justification
|
||||||
|
|
||||||
|
_Required_. Free text field, used as an explanation for the control when displayed.
|
||||||
|
|
||||||
|
#### evidence_url
|
||||||
|
|
||||||
|
_Optional_. URL to some evidence, determined by the user, supports the justification.
|
||||||
|
|
||||||
|
#### expiration_date
|
||||||
|
|
||||||
|
_Optional_. If present, the attestation expires at the end of the date given.
|
||||||
|
|
||||||
|
#### status
|
||||||
|
|
||||||
|
_Optional_.
|
||||||
|
|
||||||
|
Default `passed`. If the attestation should indicate that the control is a failure, set this to `failed`.
|
||||||
|
|
||||||
|
### Implementation
|
||||||
|
|
||||||
|
When running, at the **RunData** stage, attestations are handled by the following process:
|
||||||
|
|
||||||
|
1. Locate matching controls by matching the control ID.
|
||||||
|
|
||||||
|
2. Inject an artificial test result into the control. Use the attestation justification as the result message.
|
||||||
|
|
||||||
|
3. If the attestation is expired, set the new test result to Skip.
|
||||||
|
|
||||||
|
4. If the attestation is not expired, set the new test result to the status given on the attestation data (default pass).
|
||||||
|
|
||||||
|
5. Record a copy of the attestation data structure in the Control RunData structure.
|
||||||
|
|
||||||
|
### Compatibility
|
||||||
|
|
||||||
|
To support backward compatibility with existing MITRE work, support will be added (but not otherwise documented) for the following fields:
|
||||||
|
|
||||||
|
* explanation - the equivalent of justification
|
||||||
|
* updated (Date) and frequency (string enum) - together, the equivalent of the expiration date.
|
54
dev-docs/enhanced-outcomes.md
Normal file
54
dev-docs/enhanced-outcomes.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# Enhanced Outcomes
|
||||||
|
|
||||||
|
Enhanced Outcomes refers to the addition of new control outcomes to the InSpec vocabulary.
|
||||||
|
|
||||||
|
## Test Outcomes vs. Control Outcomes
|
||||||
|
|
||||||
|
It is essential to understand that Enhanced Outcomes refers to new **control outcomes**, the results of running a control.
|
||||||
|
|
||||||
|
The results of running a test, a `describe block` are determined by RSpec and are limited to `Pass`, `Fail`, and `Skip`.
|
||||||
|
|
||||||
|
Test outcomes are much more difficult to extend than control outcomes.
|
||||||
|
|
||||||
|
## New Control Outcomes
|
||||||
|
|
||||||
|
Enhanced Outcomes adds three new control outcomes to the existing `Pass`, `Fail`, and `Skip` outcomes.
|
||||||
|
|
||||||
|
### Error
|
||||||
|
|
||||||
|
In the first iteration of Enhanced Outcomes, the Error outcome is detected:
|
||||||
|
|
||||||
|
* if the message of any test includes the text "Control source error" OR
|
||||||
|
* the result of any test includes a backtrace
|
||||||
|
|
||||||
|
Then the entire control should be marked `Error`.
|
||||||
|
|
||||||
|
Additional means of detecting error may be developed in the future.
|
||||||
|
|
||||||
|
Error's abbreviation is `ERR`. Error's UI color assignment is `Indigo`.
|
||||||
|
|
||||||
|
### Not Applicable
|
||||||
|
|
||||||
|
If the control is not in `Error` and the impact of the control is `0.0`, then the control's outcome is `Not Applicable`.
|
||||||
|
|
||||||
|
Not Applicable's abbreviation is `N/A`. Not Applicable's UI color assignment is `Sky Blue`.
|
||||||
|
|
||||||
|
### Not Reviewed
|
||||||
|
|
||||||
|
If the control is not in `Error` or `Not Applicable`, and all test results are `Skipped`, then the control outcome is `Not Reviewed`.
|
||||||
|
|
||||||
|
Not Reviewed replaces `Skipped` as a control outcome.
|
||||||
|
|
||||||
|
Not Reviewed's abbreviation is `N/R`. Not Reviewed's UI color assignment is `Amber`.
|
||||||
|
|
||||||
|
## The `--enhanced-outcomes` option
|
||||||
|
|
||||||
|
A new CLI option will be introduced for `inspec exec`, `inspec shell`, and `inspec schema` that controls the Enhanced Outcomes functionality.
|
||||||
|
|
||||||
|
### InSpec 5
|
||||||
|
|
||||||
|
In InSpec 5.x, a user must request the enhanced outcomes functionality explicitly by adding the `--enhanced-outcomes` option.
|
||||||
|
|
||||||
|
### InSpec 6
|
||||||
|
|
||||||
|
In InSpec 6.x, --enhanced-outcomes will default to `true`. A user may request disabling the enhanced outcomes functionality by adding the `--no-enhanced-outcomes` option.
|
|
@ -493,6 +493,24 @@ v0.1.0 - Initial version
|
||||||
v0.2.0 - added `run_data.profiles[0].inputs[0].options.sensitive`
|
v0.2.0 - added `run_data.profiles[0].inputs[0].options.sensitive`
|
||||||
v0.3.0 - added resource_name && params
|
v0.3.0 - added resource_name && params
|
||||||
|
|
||||||
|
#### Implement send_report
|
||||||
|
|
||||||
|
The primary responsibilty of this function is to implement a logic for sending reporter output through email invocations or making API calls. When this is defined in a reporter, rendering of output is skipped.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
module InspecPlugins::Sweeten
|
||||||
|
class Reporter < Inspec.plugin(2, :reporter)
|
||||||
|
def send_report
|
||||||
|
# logic for sending reporter output using email invocations or API calls.
|
||||||
|
end
|
||||||
|
|
||||||
|
def render
|
||||||
|
# this will be skipped, will only run send_report
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
## Implementing Streaming Reporter Plugins
|
## Implementing Streaming Reporter Plugins
|
||||||
|
|
||||||
Streaming Reporter plugins offer the opportunity to customize or create a plugin which operates real-time as the Chef Inspec tests runs. Streaming reporters perform streaming using RSpec custom formatters.
|
Streaming Reporter plugins offer the opportunity to customize or create a plugin which operates real-time as the Chef Inspec tests runs. Streaming reporters perform streaming using RSpec custom formatters.
|
||||||
|
|
|
@ -62,7 +62,7 @@ inspec automate SUBCOMMAND
|
||||||
|
|
||||||
## check
|
## check
|
||||||
|
|
||||||
Verify the metadata in the `inspec.yml` file, verify that control blocks have the correct fields (title, description, impact) defined that all controls have visible tests, and the controls are not using deprecated InSpec DSL code.
|
Verify the metadata in the `inspec.yml` file, verify that control blocks have the correct fields (title, description, impact), and define that all controls have visible tests and the controls are not using deprecated InSpec DSL code.
|
||||||
|
|
||||||
### Syntax
|
### Syntax
|
||||||
|
|
||||||
|
@ -118,9 +118,9 @@ This subcommand has the following additional options:
|
||||||
* `--client-key-pass=CLIENT_CERT_PASSWORD`
|
* `--client-key-pass=CLIENT_CERT_PASSWORD`
|
||||||
Specify client certificate password, if required for SSL authentication (WinRM).
|
Specify client certificate password, if required for SSL authentication (WinRM).
|
||||||
* `--config=CONFIG`
|
* `--config=CONFIG`
|
||||||
Read configuration from JSON file (`-` reads from stdin).
|
Read configuration from the JSON file (`-` reads from stdin).
|
||||||
* `--docker-url`
|
* `--docker-url`
|
||||||
Provides path to Docker API endpoint (Docker).
|
Provides a path to the Docker API endpoint (Docker).
|
||||||
* `--enable-password=ENABLE_PASSWORD`
|
* `--enable-password=ENABLE_PASSWORD`
|
||||||
Password for enable mode on Cisco IOS devices.
|
Password for enable mode on Cisco IOS devices.
|
||||||
* `--format=FORMAT`
|
* `--format=FORMAT`
|
||||||
|
@ -152,7 +152,7 @@ This subcommand has the following additional options:
|
||||||
* `--ssl`, `--no-ssl`
|
* `--ssl`, `--no-ssl`
|
||||||
Use SSL for transport layer encryption (WinRM).
|
Use SSL for transport layer encryption (WinRM).
|
||||||
* `--ssl-peer-fingerprint`
|
* `--ssl-peer-fingerprint`
|
||||||
Specify ssl peer fingerprint in lieu of certificates, for SSL authentication (WinRM).
|
Specify SSL peer fingerprint in place of certificates for SSL authentication (WinRM).
|
||||||
* `--sudo`, `--no-sudo`
|
* `--sudo`, `--no-sudo`
|
||||||
Run scans with sudo. Only activates on Unix and non-root user.
|
Run scans with sudo. Only activates on Unix and non-root user.
|
||||||
* `--sudo-command=SUDO_COMMAND`
|
* `--sudo-command=SUDO_COMMAND`
|
||||||
|
@ -174,7 +174,7 @@ This subcommand has the following additional options:
|
||||||
* `--winrm-transport=WINRM_TRANSPORT`
|
* `--winrm-transport=WINRM_TRANSPORT`
|
||||||
Specify which transport to use, defaults to negotiate (WinRM).
|
Specify which transport to use, defaults to negotiate (WinRM).
|
||||||
* `--winrm-shell-type=WINRM_SHELL_TYPE`
|
* `--winrm-shell-type=WINRM_SHELL_TYPE`
|
||||||
Specify which shell type to use (powershell,elevated or cmd), defaults to powershell (WinRM).
|
Specify which shell type to use (powershell, elevated, or cmd), which defaults to powershell (WinRM).
|
||||||
|
|
||||||
## env
|
## env
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ inspec env
|
||||||
|
|
||||||
Run all test files at the specified locations.
|
Run all test files at the specified locations.
|
||||||
|
|
||||||
The subcommand loads the given profiles, fetches their dependencies if needed, then connects to the target and executes any controls contained in the profiles. One or more reporters are used to generate the output.
|
The subcommand loads the given profiles, fetches their dependencies if needed, then connects to the target and executes any controls in the profiles. One or more reporters are used to generate the output.
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
exit codes:
|
exit codes:
|
||||||
|
@ -314,13 +314,13 @@ This subcommand has the following additional options:
|
||||||
* `--command-timeout=SECONDS`
|
* `--command-timeout=SECONDS`
|
||||||
Maximum seconds to allow a command to run.
|
Maximum seconds to allow a command to run.
|
||||||
* `--config=CONFIG`
|
* `--config=CONFIG`
|
||||||
Read configuration from JSON file (`-` reads from stdin).
|
Read configuration from the JSON file (`-` reads from stdin).
|
||||||
* `--controls=one two three`
|
* `--controls=one two three`
|
||||||
A list of control names to run, or a list of /regexes/ to match against control names. Ignore all other tests.
|
A list of control names to run or a list of /regexes/ to match against control names. Ignore all other tests.
|
||||||
* `--create-lockfile`, `--no-create-lockfile`
|
* `--create-lockfile`, `--no-create-lockfile`
|
||||||
Write out a lockfile based on this execution (unless one already exists).
|
Write out a lockfile based on this execution (unless one already exists).
|
||||||
* `--distinct-exit`, `--no-distinct-exit`
|
* `--distinct-exit`, `--no-distinct-exit`
|
||||||
Exit with code 101 if any tests fail, and 100 if any are skipped (default). If disabled, exit 0 on skips and 1 for failures.
|
Exit with code 101 if any tests fail and 100 if any are skipped (default). If disabled, exit 0 on skips and 1 for failures.
|
||||||
* `--docker-url`
|
* `--docker-url`
|
||||||
Provides path to Docker API endpoint (Docker). Defaults to unix:///var/run/docker.sock on Unix systems and tcp://localhost:2375 on Windows.
|
Provides path to Docker API endpoint (Docker). Defaults to unix:///var/run/docker.sock on Unix systems and tcp://localhost:2375 on Windows.
|
||||||
* `--enable-password=ENABLE_PASSWORD`
|
* `--enable-password=ENABLE_PASSWORD`
|
||||||
|
@ -328,7 +328,7 @@ This subcommand has the following additional options:
|
||||||
* `--filter-empty-profiles`, `--no-filter-empty-profiles`
|
* `--filter-empty-profiles`, `--no-filter-empty-profiles`
|
||||||
Filter empty profiles (profiles without controls) from the report.
|
Filter empty profiles (profiles without controls) from the report.
|
||||||
* `--filter-waived-controls`
|
* `--filter-waived-controls`
|
||||||
Do not execute waived controls in InSpec at all. Must use with --waiver-file. Ignores `run` setting of waiver file.
|
Do not execute waived controls in InSpec at all. Must use with --waiver-file. Ignores the `run` setting of the waiver file.
|
||||||
* `--host=HOST`
|
* `--host=HOST`
|
||||||
Specify a remote host which is tested.
|
Specify a remote host which is tested.
|
||||||
* `--input=name1=value1 name2=value2`
|
* `--input=name1=value1 name2=value2`
|
||||||
|
@ -352,13 +352,13 @@ This subcommand has the following additional options:
|
||||||
* `--proxy-command=PROXY_COMMAND`
|
* `--proxy-command=PROXY_COMMAND`
|
||||||
Specifies the command to use to connect to the server.
|
Specifies the command to use to connect to the server.
|
||||||
* `--reporter=one two:/output/file/path`
|
* `--reporter=one two:/output/file/path`
|
||||||
Enable one or more output reporters: cli, documentation, html, progress, progress-bar, json, json-min, json-rspec, junit, yaml.
|
Enable one or more output reporters: cli, documentation, html2, progress, progress-bar, json, json-min, json-rspec, junit2, yaml.
|
||||||
* `--reporter-backtrace-inclusion`, `--no-reporter-backtrace-inclusion`
|
* `--reporter-backtrace-inclusion`, `--no-reporter-backtrace-inclusion`
|
||||||
Include a code backtrace in report data (default: true).
|
Include a code backtrace in report data (default: true).
|
||||||
* `--reporter-include-source`
|
* `--reporter-include-source`
|
||||||
Include full source code of controls in the CLI report.
|
Include full source code of controls in the CLI report.
|
||||||
* `--reporter-message-truncation=REPORTER_MESSAGE_TRUNCATION`
|
* `--reporter-message-truncation=REPORTER_MESSAGE_TRUNCATION`
|
||||||
Number of characters to truncate failure messages in report data to (default: no truncation).
|
Number of characters to truncate failure messages in report data (default: no truncation).
|
||||||
* `--self-signed`, `--no-self-signed`
|
* `--self-signed`, `--no-self-signed`
|
||||||
Allow remote scans with self-signed certificates (WinRM).
|
Allow remote scans with self-signed certificates (WinRM).
|
||||||
* `--shell`, `--no-shell`
|
* `--shell`, `--no-shell`
|
||||||
|
@ -370,13 +370,13 @@ This subcommand has the following additional options:
|
||||||
* `--show-progress`, `--no-show-progress`
|
* `--show-progress`, `--no-show-progress`
|
||||||
Show progress while executing tests.
|
Show progress while executing tests.
|
||||||
* `--silence-deprecations=all|GROUP GROUP...`
|
* `--silence-deprecations=all|GROUP GROUP...`
|
||||||
Suppress deprecation warnings. See install_dir/etc/deprecations.json for list of GROUPs or use 'all'.
|
Suppress deprecation warnings. See install_dir/etc/deprecations.json for a list of GROUPs or use 'all'.
|
||||||
* `--ssh-config-file=one two three`
|
* `--ssh-config-file=one two three`
|
||||||
A list of paths to the SSH configuration file, for example: `~/.ssh/config` or `/etc/ssh/ssh_config`.
|
A list of paths to the SSH configuration file, for example: `~/.ssh/config` or `/etc/ssh/ssh_config`.
|
||||||
* `--ssl`, `--no-ssl`
|
* `--ssl`, `--no-ssl`
|
||||||
Use SSL for transport layer encryption (WinRM).
|
Use SSL for transport layer encryption (WinRM).
|
||||||
* `--ssl-peer-fingerprint`
|
* `--ssl-peer-fingerprint`
|
||||||
Specify ssl peer fingerprint in lieu of certificates, for SSL authentication (WinRM).
|
Specify SSL peer fingerprint in place of certificates for SSL authentication (WinRM).
|
||||||
* `--sudo`, `--no-sudo`
|
* `--sudo`, `--no-sudo`
|
||||||
Run scans with sudo. Only activates on Unix and non-root user.
|
Run scans with sudo. Only activates on Unix and non-root user.
|
||||||
* `--sudo-command=SUDO_COMMAND`
|
* `--sudo-command=SUDO_COMMAND`
|
||||||
|
@ -388,9 +388,9 @@ This subcommand has the following additional options:
|
||||||
* `-t`, `--target=TARGET`
|
* `-t`, `--target=TARGET`
|
||||||
Simple targeting option using URIs, e.g. ssh://user:pass@host:port.
|
Simple targeting option using URIs, e.g. ssh://user:pass@host:port.
|
||||||
* `--target-id=TARGET_ID`
|
* `--target-id=TARGET_ID`
|
||||||
Provide a ID which will be included on reports - deprecated.
|
Provide an ID that is included on reports - deprecated.
|
||||||
* `--tags=one two three`
|
* `--tags=one two three`
|
||||||
A list of tags or a list of regular expressions that match tags. `exec` will run controls referenced by the listed or matching tags.
|
A list of tags or regular expressions that match tags. `exec` will run controls referenced by the listed or matching tags.
|
||||||
* `--user=USER`
|
* `--user=USER`
|
||||||
The login user for a remote scan.
|
The login user for a remote scan.
|
||||||
* `--vendor-cache=VENDOR_CACHE`
|
* `--vendor-cache=VENDOR_CACHE`
|
||||||
|
@ -403,6 +403,8 @@ This subcommand has the following additional options:
|
||||||
Whether to use disable sspi authentication, defaults to false (WinRM).
|
Whether to use disable sspi authentication, defaults to false (WinRM).
|
||||||
* `--winrm-transport=WINRM_TRANSPORT`
|
* `--winrm-transport=WINRM_TRANSPORT`
|
||||||
Specify which transport to use, defaults to negotiate (WinRM).
|
Specify which transport to use, defaults to negotiate (WinRM).
|
||||||
|
* `--enhanced-outcomes`
|
||||||
|
Includes enhanced outcome of controls in report data.
|
||||||
|
|
||||||
## habitat
|
## habitat
|
||||||
|
|
||||||
|
@ -442,7 +444,7 @@ inspec init TEMPLATE
|
||||||
|
|
||||||
## json
|
## json
|
||||||
|
|
||||||
Read all tests in path and generate a json summary.
|
Read all tests in the path and generate a json summary.
|
||||||
|
|
||||||
### Syntax
|
### Syntax
|
||||||
|
|
||||||
|
@ -463,7 +465,7 @@ This subcommand has the following additional options:
|
||||||
* `--profiles-path=PROFILES_PATH`
|
* `--profiles-path=PROFILES_PATH`
|
||||||
Folder which contains referenced profiles.
|
Folder which contains referenced profiles.
|
||||||
* `--tags=one two three`
|
* `--tags=one two three`
|
||||||
A list of tags that reference certain controls. Other controls are ignored.
|
A list of tags that reference specific controls. Other controls are ignored.
|
||||||
* `--vendor-cache=VENDOR_CACHE`
|
* `--vendor-cache=VENDOR_CACHE`
|
||||||
Use the given path for caching dependencies. (default: `~/.inspec/cache`).
|
Use the given path for caching dependencies. (default: `~/.inspec/cache`).
|
||||||
|
|
||||||
|
@ -503,6 +505,13 @@ This subcommand has the following syntax:
|
||||||
inspec schema NAME
|
inspec schema NAME
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
This subcommand has the following additional option:
|
||||||
|
|
||||||
|
* `--enhanced-outcomes`
|
||||||
|
Includes enhanced outcome of controls in report data.
|
||||||
|
|
||||||
## shell
|
## shell
|
||||||
|
|
||||||
Open an interactive debugging shell.
|
Open an interactive debugging shell.
|
||||||
|
@ -540,11 +549,11 @@ This subcommand has the following additional options:
|
||||||
* `--client-key-pass=CLIENT_CERT_PASSWORD`
|
* `--client-key-pass=CLIENT_CERT_PASSWORD`
|
||||||
Specify client certificate password, if required for SSL authentication (WinRM).
|
Specify client certificate password, if required for SSL authentication (WinRM).
|
||||||
* `--config=CONFIG`
|
* `--config=CONFIG`
|
||||||
Read configuration from JSON file (`-` reads from stdin).
|
Read configuration from the JSON file (`-` reads from stdin).
|
||||||
* `--depends=one two three`
|
* `--depends=one two three`
|
||||||
A space-delimited list of local folders containing profiles whose libraries and resources will be loaded into the new shell.
|
A space-delimited list of local folders containing profiles whose libraries and resources will be loaded into the new shell.
|
||||||
* `--distinct-exit`, `--no-distinct-exit`
|
* `--distinct-exit`, `--no-distinct-exit`
|
||||||
Exit with code 100 if any tests fail, and 101 if any are skipped but none failed (default). If disabled, exit 0 on skips and 1 for failures.
|
Exit with code 100 if any tests fail and 101 if any are skipped, but none failed (default). If disabled, exit 0 on skips and 1 for failures.
|
||||||
* `--docker-url`
|
* `--docker-url`
|
||||||
Provides path to Docker API endpoint (Docker). Defaults to unix:///var/run/docker.sock on Unix systems and tcp://localhost:2375 on Windows.
|
Provides path to Docker API endpoint (Docker). Defaults to unix:///var/run/docker.sock on Unix systems and tcp://localhost:2375 on Windows.
|
||||||
* `--enable-password=ENABLE_PASSWORD`
|
* `--enable-password=ENABLE_PASSWORD`
|
||||||
|
@ -568,7 +577,7 @@ This subcommand has the following additional options:
|
||||||
* `--proxy-command=PROXY_COMMAND`
|
* `--proxy-command=PROXY_COMMAND`
|
||||||
Specifies the command to use to connect to the server.
|
Specifies the command to use to connect to the server.
|
||||||
* `--reporter=one two:/output/file/path`
|
* `--reporter=one two:/output/file/path`
|
||||||
Enable one or more output reporters: cli, documentation, html, progress, json, json-min, json-rspec, junit.
|
Enable one or more output reporters: cli, documentation, html2, progress, json, json-min, json-rspec, junit2.
|
||||||
* `--self-signed`, `--no-self-signed`
|
* `--self-signed`, `--no-self-signed`
|
||||||
Allow remote scans with self-signed certificates (WinRM).
|
Allow remote scans with self-signed certificates (WinRM).
|
||||||
* `--shell`, `--no-shell`
|
* `--shell`, `--no-shell`
|
||||||
|
@ -582,7 +591,7 @@ This subcommand has the following additional options:
|
||||||
* `--ssl`, `--no-ssl`
|
* `--ssl`, `--no-ssl`
|
||||||
Use SSL for transport layer encryption (WinRM).
|
Use SSL for transport layer encryption (WinRM).
|
||||||
* `--ssl-peer-fingerprint=SSL_PEER_FINGERPRINT`
|
* `--ssl-peer-fingerprint=SSL_PEER_FINGERPRINT`
|
||||||
Specify ssl peer fingerprint in lieu of certificates, for SSL authentication (WinRM).
|
Specify SSL peer fingerprint in place of certificates for SSL authentication (WinRM).
|
||||||
* `--sudo`, `--no-sudo`
|
* `--sudo`, `--no-sudo`
|
||||||
Run scans with sudo. Only activates on Unix and non-root user.
|
Run scans with sudo. Only activates on Unix and non-root user.
|
||||||
* `--sudo-command=SUDO_COMMAND`
|
* `--sudo-command=SUDO_COMMAND`
|
||||||
|
@ -603,6 +612,8 @@ This subcommand has the following additional options:
|
||||||
Whether to use disable sspi authentication, defaults to false (WinRM).
|
Whether to use disable sspi authentication, defaults to false (WinRM).
|
||||||
* `--winrm-transport=WINRM_TRANSPORT`
|
* `--winrm-transport=WINRM_TRANSPORT`
|
||||||
Specify which transport to use, defaults to negotiate (WinRM).
|
Specify which transport to use, defaults to negotiate (WinRM).
|
||||||
|
* `--enhanced-outcomes`
|
||||||
|
Includes enhanced outcome of controls in report data.
|
||||||
|
|
||||||
## supermarket
|
## supermarket
|
||||||
|
|
||||||
|
@ -640,7 +651,7 @@ inspec vendor PATH
|
||||||
This subcommand has additional options:
|
This subcommand has additional options:
|
||||||
|
|
||||||
* `--overwrite`, `--no-overwrite`
|
* `--overwrite`, `--no-overwrite`
|
||||||
Overwrite existing vendored dependencies and lockfile.
|
Overwrite existing vendored dependencies and lockfiles.
|
||||||
|
|
||||||
## version
|
## version
|
||||||
|
|
||||||
|
|
|
@ -249,6 +249,7 @@ end
|
||||||
```
|
```
|
||||||
|
|
||||||
This example checks for if certain pip packages are installed, but only if '/root/.aws' exists:
|
This example checks for if certain pip packages are installed, but only if '/root/.aws' exists:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
control 'pip-packages-installed' do
|
control 'pip-packages-installed' do
|
||||||
title 'Check if essential pips are installed'
|
title 'Check if essential pips are installed'
|
||||||
|
@ -269,14 +270,37 @@ certain controls, which would 100% fail due to the way servers are prepared, but
|
||||||
you know that the same control suites are reused later in different circumstances
|
you know that the same control suites are reused later in different circumstances
|
||||||
by different teams.
|
by different teams.
|
||||||
|
|
||||||
|
This example checks whether the Gnome Desktop is installed. If not installed, it resets the impact of the control to the new value which is passed as a hash with the impact key.
|
||||||
|
|
||||||
|
Here, it resets it to 0:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
control 'gnome-destkop-settings' do
|
||||||
|
impact 0.5
|
||||||
|
desc 'some good settings'
|
||||||
|
desc 'check', 'check the settings file for good things'
|
||||||
|
desc 'fix', 'set the good things in the file /etc/gnome/settings'
|
||||||
|
tag nist: 'CM-6'
|
||||||
|
|
||||||
|
only_if("The Gnome Desktop is not installed, this control is Not Applicable", impact: 0) {
|
||||||
|
package('gnome-desktop').installed?
|
||||||
|
}
|
||||||
|
|
||||||
|
describe gnome_settings do
|
||||||
|
it should_be set_well
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
Some notes about `only_if`:
|
Some notes about `only_if`:
|
||||||
|
|
||||||
- `only_if` applies to the entire `control`. If the results of the `only_if`
|
* `only_if` applies to the entire `control`. If the results of the `only_if`
|
||||||
block evaluate to false, any Chef InSpec resources mentioned as part of a
|
block evaluate to false, any Chef InSpec resources mentioned as part of a
|
||||||
`describe` block will not be run. Additionally, the contents of the describe
|
`describe` block will not be run. Additionally, the contents of the describe
|
||||||
blocks will not be run. However, bare Ruby expressions and bare Chef InSpec
|
blocks will not be run. However, bare Ruby expressions and bare Chef InSpec
|
||||||
resources (not assocated with a describe block) preceding the only_if statement
|
resources (not assocated with a describe block) preceding the only_if statement
|
||||||
will run
|
will run
|
||||||
|
* `only_if` also accepts hash with impact key to reset the impact value of the control. Control's impact is helpful in determining it is enhanced outcome.
|
||||||
|
|
||||||
To illustrate:
|
To illustrate:
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ is a standalone structure with its own distribution and execution flow.
|
||||||
|
|
||||||
A profile should have the following structure:
|
A profile should have the following structure:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
examples/profile
|
examples/profile
|
||||||
├── README.md
|
├── README.md
|
||||||
├── controls
|
├── controls
|
||||||
|
@ -67,7 +67,7 @@ Each profile must have an `inspec.yml` file that defines the following informati
|
||||||
|
|
||||||
`name` is required; all other profile settings are optional. For example:
|
`name` is required; all other profile settings are optional. For example:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: ssh
|
name: ssh
|
||||||
title: Basic SSH
|
title: Basic SSH
|
||||||
maintainer: Chef Software, Inc.
|
maintainer: Chef Software, Inc.
|
||||||
|
@ -89,7 +89,7 @@ inspec_version: "~> 2.1"
|
||||||
|
|
||||||
The `inspec.yml` also supports embedded ERB in the file. For example:
|
The `inspec.yml` also supports embedded ERB in the file. For example:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: dummy
|
name: dummy
|
||||||
title: InSpec Profile
|
title: InSpec Profile
|
||||||
maintainer: The Authors
|
maintainer: The Authors
|
||||||
|
@ -130,7 +130,7 @@ platforms. The new families can restrict the platform family to `os`, `aws`, `az
|
||||||
|
|
||||||
For example, to target anything running Debian Linux, use:
|
For example, to target anything running Debian Linux, use:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: ssh
|
name: ssh
|
||||||
supports:
|
supports:
|
||||||
- platform-name: debian
|
- platform-name: debian
|
||||||
|
@ -138,7 +138,7 @@ supports:
|
||||||
|
|
||||||
To target only Ubuntu version 20.04, use:
|
To target only Ubuntu version 20.04, use:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: ssh
|
name: ssh
|
||||||
supports:
|
supports:
|
||||||
- platform-name: ubuntu
|
- platform-name: ubuntu
|
||||||
|
@ -147,7 +147,7 @@ supports:
|
||||||
|
|
||||||
To target the entire release of Ubuntu version 20.x, use:
|
To target the entire release of Ubuntu version 20.x, use:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: ssh
|
name: ssh
|
||||||
supports:
|
supports:
|
||||||
- platform-name: ubuntu
|
- platform-name: ubuntu
|
||||||
|
@ -156,7 +156,7 @@ supports:
|
||||||
|
|
||||||
To target the Red Hat and derivative platforms such as CentOS and Oracle Linux, use:
|
To target the Red Hat and derivative platforms such as CentOS and Oracle Linux, use:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: ssh
|
name: ssh
|
||||||
supports:
|
supports:
|
||||||
- platform-family: redhat
|
- platform-family: redhat
|
||||||
|
@ -164,7 +164,7 @@ supports:
|
||||||
|
|
||||||
To target the entire Windows 2019 platform family, including Datacenter and Core Servers, use:
|
To target the entire Windows 2019 platform family, including Datacenter and Core Servers, use:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: ssh
|
name: ssh
|
||||||
supports:
|
supports:
|
||||||
- platform-name: windows_server_2019*
|
- platform-name: windows_server_2019*
|
||||||
|
@ -172,7 +172,7 @@ supports:
|
||||||
|
|
||||||
To target anything running on Amazon AWS, use:
|
To target anything running on Amazon AWS, use:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: ssh
|
name: ssh
|
||||||
supports:
|
supports:
|
||||||
- platform: aws
|
- platform: aws
|
||||||
|
@ -180,7 +180,7 @@ supports:
|
||||||
|
|
||||||
To target all of these examples in a single `inspec.yml` file, use:
|
To target all of these examples in a single `inspec.yml` file, use:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
name: ssh
|
name: ssh
|
||||||
supports:
|
supports:
|
||||||
- platform-name: debian
|
- platform-name: debian
|
||||||
|
@ -206,7 +206,7 @@ needs to be specified in the including profile’s `inspec.yml` file in the `dep
|
||||||
section. For each profile to be included, a location for the profile from where
|
section. For each profile to be included, a location for the profile from where
|
||||||
to be fetched and a name for the profile should be included. For example:
|
to be fetched and a name for the profile should be included. For example:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
depends:
|
depends:
|
||||||
- name: linux-baseline
|
- name: linux-baseline
|
||||||
url: https://github.com/dev-sec/linux-baseline/archive/master.tar.gz
|
url: https://github.com/dev-sec/linux-baseline/archive/master.tar.gz
|
||||||
|
@ -221,7 +221,7 @@ Chef InSpec supports a number of dependency sources.
|
||||||
The `path` setting defines a profile that is located on disk. This setting is
|
The `path` setting defines a profile that is located on disk. This setting is
|
||||||
typically used during development of profiles and when debugging profiles.
|
typically used during development of profiles and when debugging profiles.
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
depends:
|
depends:
|
||||||
- name: my-profile
|
- name: my-profile
|
||||||
path: /absolute/path
|
path: /absolute/path
|
||||||
|
@ -235,17 +235,17 @@ The `url` setting specifies a profile that is located at an HTTP- or HTTPS-based
|
||||||
URL. The profile must be accessible via a HTTP GET operation and must be a valid
|
URL. The profile must be accessible via a HTTP GET operation and must be a valid
|
||||||
profile archive (zip, tar, or tar.gz format).
|
profile archive (zip, tar, or tar.gz format).
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
depends:
|
depends:
|
||||||
- name: my-profile
|
- name: my-profile
|
||||||
url: https://my.domain/path/to/profile.tgz
|
url: https://my.domain/path/to/profile.tgz
|
||||||
- name: profile-via-git
|
- name: profile-via-git
|
||||||
url: https://github.com/myusername/myprofile-repo/archive/master.tar.gz
|
url: https://github.com/username/myprofile-repo/archive/master.tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
`url` also supports basic authentication.
|
`url` also supports basic authentication.
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
depends:
|
depends:
|
||||||
- name: my-profile
|
- name: my-profile
|
||||||
url: https://my.domain/path/to/profile.tgz
|
url: https://my.domain/path/to/profile.tgz
|
||||||
|
@ -260,7 +260,7 @@ optional settings for branch, tag, commit, version, and relative_path. The sourc
|
||||||
location is translated into a URL upon resolution. This type of dependency supports
|
location is translated into a URL upon resolution. This type of dependency supports
|
||||||
version constraints via semantic versioning as git tags.
|
version constraints via semantic versioning as git tags.
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
depends:
|
depends:
|
||||||
- name: git-profile
|
- name: git-profile
|
||||||
git: http://url/to/repo
|
git: http://url/to/repo
|
||||||
|
@ -278,7 +278,7 @@ on Chef Supermarket. The source location is translated into a URL upon resolutio
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
depends:
|
depends:
|
||||||
- name: supermarket-profile
|
- name: supermarket-profile
|
||||||
supermarket: supermarket-username/supermarket-profile
|
supermarket: supermarket-username/supermarket-profile
|
||||||
|
@ -293,7 +293,7 @@ or Chef Compliance server.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
depends:
|
depends:
|
||||||
- name: linux
|
- name: linux
|
||||||
compliance: base/linux
|
compliance: base/linux
|
||||||
|
@ -304,8 +304,7 @@ Any profile with ruby gem dependencies that need to be installed can be specifie
|
||||||
|
|
||||||
For example, if you required any ruby library in a custom resource that needs a specific gem to be installed, then you can specify those gems in the metadata file. Chef InSpec will prompt to install the gems to `~/.inspec/gems` when you run your profile the first time. To skip the prompt and automatically install, pass the `--auto-install-gems` option to `inspec exec`.
|
For example, if you required any ruby library in a custom resource that needs a specific gem to be installed, then you can specify those gems in the metadata file. Chef InSpec will prompt to install the gems to `~/.inspec/gems` when you run your profile the first time. To skip the prompt and automatically install, pass the `--auto-install-gems` option to `inspec exec`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
```YAML
|
|
||||||
gem_dependencies:
|
gem_dependencies:
|
||||||
- name: "mongo"
|
- name: "mongo"
|
||||||
version: ">= 2.3.12"
|
version: ">= 2.3.12"
|
||||||
|
@ -412,7 +411,7 @@ for use in your profile. If two of your dependencies provide a resource with
|
||||||
the same name, you can use the `require_resource` DSL function to
|
the same name, you can use the `require_resource` DSL function to
|
||||||
disambiguate the two:
|
disambiguate the two:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
require_resource(profile: 'my_dep', resource: 'my_res',
|
require_resource(profile: 'my_dep', resource: 'my_res',
|
||||||
as: 'my_res2')
|
as: 'my_res2')
|
||||||
```
|
```
|
||||||
|
@ -436,7 +435,7 @@ of a profile. They are accessed by their name relative to this folder with
|
||||||
|
|
||||||
Here is an example for reading and testing a list of ports. The folder structure is:
|
Here is an example for reading and testing a list of ports. The folder structure is:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
examples/profile
|
examples/profile
|
||||||
├── controls
|
├── controls
|
||||||
│ ├── example.rb
|
│ ├── example.rb
|
||||||
|
@ -447,7 +446,7 @@ examples/profile
|
||||||
|
|
||||||
With `services.yml` containing:
|
With `services.yml` containing:
|
||||||
|
|
||||||
```YAML
|
```yaml
|
||||||
- service_name: httpd-alpha
|
- service_name: httpd-alpha
|
||||||
port: 80
|
port: 80
|
||||||
- service_name: httpd-beta
|
- service_name: httpd-beta
|
||||||
|
|
|
@ -11,17 +11,17 @@ gh_repo = "inspec"
|
||||||
weight = 50
|
weight = 50
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Introduced in Chef InSpec 1.51.6
|
A `reporter` is a facility for formatting and delivering the results of a Chef InSpec auditing run. Reporters were introduced in Chef InSpec 1.51.6.
|
||||||
|
|
||||||
A `reporter` is a facility for formatting and delivering the results of a Chef InSpec auditing run.
|
Chef InSpec allows you to output your test results to one or more reporters.
|
||||||
|
|
||||||
Chef InSpec allows you to output your test results to one or more reporters. Configure the reporter(s) using either the `--reporter` option or as part of the general config file using the `--config` (or `--json-config`, prior to v3.6) option. While you can configure multiple reporters to write to different files, only one reporter can output to the screen(stdout).
|
Configure the reporter(s) using either the `--reporter` option or as part of the general configuration file using the `--config` (or `--json-config`, prior to v3.6) option. While you can configure multiple reporters to write to different files, only one reporter can output to the screen(stdout).
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
You can specify one or more reporters using the `--reporter` cli flag. You can also specify a output by appending a path separated by a colon.
|
You can specify one or more reporters using the `--reporter` CLI flag. You can also specify an output by appending a path separated by a colon.
|
||||||
|
|
||||||
Output json to screen.
|
**Output json to screen**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
inspec exec example_profile --reporter json
|
inspec exec example_profile --reporter json
|
||||||
|
@ -29,7 +29,7 @@ inspec exec example_profile --reporter json
|
||||||
inspec exec example_profile --reporter json:-
|
inspec exec example_profile --reporter json:-
|
||||||
```
|
```
|
||||||
|
|
||||||
Output yaml to screen
|
**Output yaml to screen.**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
inspec exec example_profile --reporter yaml
|
inspec exec example_profile --reporter yaml
|
||||||
|
@ -37,33 +37,33 @@ inspec exec example_profile --reporter yaml
|
||||||
inspec exec example_profile --reporter yaml:-
|
inspec exec example_profile --reporter yaml:-
|
||||||
```
|
```
|
||||||
|
|
||||||
Output cli to screen and write json to a file.
|
**Output cli to screen and write json to a file.**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
inspec exec example_profile --reporter cli json:/tmp/output.json
|
inspec exec example_profile --reporter cli json:/tmp/output.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Output nothing to screen and write junit and html to a file.
|
**Output nothing to screen and write junit and html to a file.**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
inspec exec example_profile --reporter junit2:/tmp/junit.xml html:www/index.html
|
inspec exec example_profile --reporter junit2:/tmp/junit.xml html:www/index.html
|
||||||
```
|
```
|
||||||
|
|
||||||
Output json to screen and write to a file. Write junit to a file.
|
**Output json to screen and write to a file. Write junit to a file.**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
inspec exec example_profile --reporter json junit2:/tmp/junit.xml | tee out.json
|
inspec exec example_profile --reporter json junit2:/tmp/junit.xml | tee out.json
|
||||||
```
|
```
|
||||||
|
|
||||||
If you wish to pass the profiles directly after specifying the reporters you will need to use the end of options flag `--`.
|
If you wish to pass the profiles directly after specifying the reporters, you must use the end of options flag `--`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
inspec exec --reporter json junit2:/tmp/junit.xml -- profile1 profile2
|
inspec exec --reporter json junit2:/tmp/junit.xml -- profile1 profile2
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are using the cli option `--config`, you can also set reporters.
|
Using the CLI option `--config`, you can also set reporters.
|
||||||
|
|
||||||
Output cli to screen.
|
**Output cli to screen.**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -75,7 +75,7 @@ Output cli to screen.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Output cli to screen and write json to a file.
|
**Output cli to screen and write json to a file.**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -91,24 +91,25 @@ Output cli to screen and write json to a file.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Output real-time progress to screen with a progress bar.
|
**Output real-time progress to screen with a progress bar.**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
inspec exec example_profile --reporter progress-bar
|
inspec exec example_profile --reporter progress-bar
|
||||||
```
|
```
|
||||||
|
|
||||||
## Reporter Options
|
## Reporter Options
|
||||||
|
|
||||||
The following are CLI options that may be used to modify reporter behavior. Many of these options allow you to limit the size of the report, because some reporters (such as the json-automate reporter) have a limit on the total size of the report that can be processed.
|
The following are CLI options that are used to modify reporter behavior. Many of these options allow you to limit the report size because some reporters (such as the json-automate reporter) limit on the total size of the report that can be processed.
|
||||||
|
|
||||||
`--diff`, `--no-diff`
|
`--diff`, `--no-diff`
|
||||||
|
|
||||||
: Include a `diff` comparison of textual differences in failed test output (default: `true`).
|
: Include a `diff` comparison of textual differences in the failed test output (default: `true`).
|
||||||
|
|
||||||
: Use `--no-diff` to limit the size of the report output when tests contain large amounts of text output.
|
: Use `--no-diff` to limit the size of the report output when tests contain large amounts of text output.
|
||||||
|
|
||||||
`--filter-empty-profiles`
|
`--filter-empty-profiles`
|
||||||
|
|
||||||
: Remove empty profiles (those containing zero controls, such as resource packs) from the output of the reporter.
|
: Remove empty profiles (those containing zero controls, such as resource packs) from the reporter's output.
|
||||||
|
|
||||||
`--reporter-backtrace-inclusion`, `--no-reporter-backtrace-inclusion`
|
`--reporter-backtrace-inclusion`, `--no-reporter-backtrace-inclusion`
|
||||||
|
|
||||||
|
@ -126,13 +127,21 @@ The following are CLI options that may be used to modify reporter behavior. Many
|
||||||
|
|
||||||
: This may be used to limit the size of reports when failure messages are exceptionally large.
|
: This may be used to limit the size of reports when failure messages are exceptionally large.
|
||||||
|
|
||||||
|
`--enhanced-outcomes`
|
||||||
|
|
||||||
|
: Includes enhanced outcome of controls in report data.
|
||||||
|
|
||||||
|
: The control level status outcomes are `Passed`, `Failed`, `Not Applicable (N/A)`, `Not Reviewed (N/R)`, or `Error (ERR)`.
|
||||||
|
|
||||||
|
: Only supported for cli, progress-bar, html2, json, json-automate, automate, and yaml reporters.
|
||||||
|
|
||||||
## Supported Reporters
|
## Supported Reporters
|
||||||
|
|
||||||
The following are the current supported reporters:
|
The following are the currently supported reporters:
|
||||||
|
|
||||||
### cli
|
### cli
|
||||||
|
|
||||||
This is the basic text base report. It includes details about which tests passed and failed and includes an overall summary at the end.
|
This is the basic text based report. It includes details about tests that passed and failed and an overall summary at the end.
|
||||||
|
|
||||||
### json
|
### json
|
||||||
|
|
||||||
|
@ -172,29 +181,39 @@ This reporter outputs the standard JUnit spec in XML format and is recommended f
|
||||||
|
|
||||||
#### junit
|
#### junit
|
||||||
|
|
||||||
This legacy reporter outputs nonstandard JUnit XML and is provided only for backwards compatibility.
|
This legacy reporter outputs nonstandard JUnit XML and is provided only for backward compatibility.
|
||||||
|
|
||||||
### progress
|
### progress
|
||||||
|
|
||||||
This reporter is very condensed and gives you a `.`(pass), `f`(fail), or `*`(skip) character per test and a small summary at the end.
|
This reporter is very condensed and provides you a `.`(pass), `f`(fail), or `*`(skip) character per test and a small summary at the end.
|
||||||
|
|
||||||
### progress-bar
|
### progress-bar
|
||||||
|
|
||||||
This reporter outputs real-time progress of a running InSpec profile using a progress bar and prints running control's ID with an indicator of control's status (Passed, failed or skipped).
|
This reporter outputs the real-time progress of a running InSpec profile using a progress bar and prints the running control's ID with an indicator of the control's status (`Passed`, `failed`, or `skipped`).
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
![Progress Bar Reporter Outcome](/images/inspec/reporter_outcome_progress_bar.png)
|
||||||
|
|
||||||
|
And reporter outcome with `--enhanced-outcomes` option:
|
||||||
|
|
||||||
|
![Progress Bar Reporter Outcome with enhanced outcomes](/images/inspec/reporter_outcome_progress_bar_enhanced_outcomes.png)
|
||||||
|
|
||||||
### json-rspec
|
### json-rspec
|
||||||
|
|
||||||
This reporter includes all information from the rspec runner. Unlike the json reporter this includes rspec specific details.
|
This reporter includes all information from the Rspec runner. Unlike the json reporter, this includes Rspec-specific details.
|
||||||
|
|
||||||
### html
|
### html
|
||||||
|
|
||||||
This reporter is the legacy RSpec HTML reporter, which is retained for backwards compatibility. The report generated is not aware of profiles or controls, and only contains unsorted test information. Most users should migrate to the `html2` reporter for more complete data.
|
This reporter is the legacy RSpec HTML reporter retained for backward compatibility. The report generated is unaware of profiles or controls and only contains unsorted test information. Most users should migrate to the `html2` reporter for more complete data.
|
||||||
|
|
||||||
### html2
|
### html2
|
||||||
|
|
||||||
This reporter is an improved HTML reporter that contains full data about the structure of the profile, controls, and tests. The generated report renders HTML code for viewing your tests in a browser.
|
This reporter is an improved HTML reporter that contains full data about the structure of the profile, controls, and tests. The generated report renders HTML code for viewing your tests in a browser.
|
||||||
|
|
||||||
The `html2` reporter requires no configuration to function. However, two options--`alternate_css_file` and `alternate_js_file`--are available for customization. The options are set in the JSON-formatted configuration file that Chef InSpec consumes. For details, see [our configuration file documentation](/inspec/config/).
|
The `html2` reporter requires no configuration to function. However, options `--alternate_css_file` and `--alternate_js_file` are available for customization. The options are set in the JSON-formatted configuration file that Chef InSpec consumes.
|
||||||
|
|
||||||
|
For details, see [our configuration file documentation](/inspec/config/).
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
|
@ -212,17 +231,17 @@ For example:
|
||||||
|
|
||||||
#### alternate_css_file
|
#### alternate_css_file
|
||||||
|
|
||||||
Specifies the full path to the location of a CSS file that will be read and inlined into the HTML report. The default CSS will not be included.
|
Specifies the full path to the location of a CSS file that is read and inlined into the HTML report. The default CSS is not included.
|
||||||
|
|
||||||
#### alternate_js_file
|
#### alternate_js_file
|
||||||
|
|
||||||
Specifies the full path to the location of a JavaScript file that will be read and inlined into the HTML report. The default JavaScript will not be included. The JavaScript file should implement at least a `pageLoaded()` function, which will be called by the `onload` event of the HTML `body` element.
|
Specifies the full path to the location of a JavaScript file that is read and inlined into the HTML report. The default JavaScript is included. The JavaScript file should implement at least a `pageLoaded()` function, which is called by the `onload` event of the HTML `body` element.
|
||||||
|
|
||||||
## Automate Reporter
|
## Automate Reporter
|
||||||
|
|
||||||
The `automate` reporter type is a special reporter which will send its results over the network to [Chef Automate]({{< relref "/automate/">}}). To use this reporter you must pass in the correct configuration via a json config `--config`.
|
The `automate` reporter type is a special reporter which sends its results over the network to [Chef Automate]({{< relref "/automate/">}}). To use this reporter, you must pass in the correct configuration via a json configuration `--config`.
|
||||||
|
|
||||||
Example config:
|
Example Configuration:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -241,44 +260,34 @@ Example config:
|
||||||
|
|
||||||
### Mandatory fields
|
### Mandatory fields
|
||||||
|
|
||||||
#### stdout
|
`stdout`
|
||||||
|
: Either suppress or shows the automate report in the CLI screen on completion.
|
||||||
|
|
||||||
This will either suppress or show the automate report in the CLI screen on completion
|
`url`
|
||||||
|
: Automate 2 url. Append `data-collector/v0/` at the end.
|
||||||
|
|
||||||
#### url
|
`token`
|
||||||
|
: Automate 2 tokens. You can generate this token by navigating to the **admin** tab of A2 and then clicking **API keys**.
|
||||||
This is your Automate 2 url. Append `data-collector/v0/` at the end.
|
|
||||||
|
|
||||||
#### token
|
|
||||||
|
|
||||||
This is your Automate 2 token. You can generate this token by navigating to the admin tab of A2 and then api keys.
|
|
||||||
|
|
||||||
### Optional fields
|
### Optional fields
|
||||||
|
|
||||||
#### insecure
|
`insecure`
|
||||||
|
: Disables or enables the SSL check when accessing the Automate 2 instance.
|
||||||
|
|
||||||
This will disable or enable the ssl check when accessing the Automate 2 instance.
|
`node_name`
|
||||||
|
: Node name which shows up in Automate.
|
||||||
|
|
||||||
#### node_name
|
`node_uuid`
|
||||||
|
: Node UUID, which shows up in Chef Automate. Use a single static UUID per node for all your reports. You must specify a `node_uuid` in the Chef InSpec configuration file if running Chef InSpec outside of an audit cookbook or another environment where a `chef_guid` or `node_uuid` is already known to Chef InSpec.
|
||||||
|
|
||||||
This will be the node name which shows up in Automate.
|
`environment`
|
||||||
|
: Sets the environment metadata for Automate.
|
||||||
|
|
||||||
#### node_uuid
|
## json-Automate Reporter
|
||||||
|
|
||||||
This will be the node UUID which shows up in Chef Automate. Use a single static UUID
|
The `json-automate` reporter is a special reporter that prepares the data format used by the Automate reporter. `json-automate` does not communicate on the network; instead, it simply produces the JSON report format that Automate would be consuming. Notably, the report is based on the `json` reporter, with the following modifications:
|
||||||
per node for all your reports. You must specify a `node_uuid` in the Chef InSpec
|
|
||||||
configuration file if running Chef InSpec outside of an audit cookbook or another
|
|
||||||
environment where a `chef_guid` or `node_uuid` is already known to Chef InSpec.
|
|
||||||
|
|
||||||
#### environment
|
- Controls appearing in child profiles are de-duplicated by ID, merging into the parent profile.
|
||||||
|
- Child profiles are deleted, flattening the report.
|
||||||
|
|
||||||
This will set the environment metadata for Automate.
|
The `json-automate` reporter is primarily used for internal needs, but some users may find it helpful if they want a JSON-based reporter that merges controls.
|
||||||
|
|
||||||
## JSON-Automate Reporter
|
|
||||||
|
|
||||||
The `json-automate` reporter is a special reporter that prepares the data format used by the Automate reporter. `json-automate` does not communicate on the network; rather it simply produces the JSON report format that Automate would be consuming. Notably, the report is based on the `json` reporter, with the following modifications:
|
|
||||||
|
|
||||||
* Controls that appear in child profiles are de-duplicated by ID, merging up into the parent profile.
|
|
||||||
* Child profiles are deleted, flattening the report.
|
|
||||||
|
|
||||||
The `json-automate` reporter is primarily used for internal needs, but some users may find it useful if they want a JSON based reporter that merges controls.
|
|
||||||
|
|
|
@ -56,3 +56,7 @@ The following resources work on Windows operating systems.
|
||||||
## Habitat
|
## Habitat
|
||||||
|
|
||||||
{{< inspec/inspec_resources platform="habitat" >}}
|
{{< inspec/inspec_resources platform="habitat" >}}
|
||||||
|
|
||||||
|
## Kubernetes
|
||||||
|
|
||||||
|
{{< inspec/inspec_resources platform="k8s" >}}
|
||||||
|
|
|
@ -11,7 +11,7 @@ platform = "linux"
|
||||||
parent = "inspec/resources/os"
|
parent = "inspec/resources/os"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Use the `auditd` Chef InSpec audit resource to test the rules for logging that exist on the system. The audit.rules file is typically located under /etc/audit/ and contains the list of rules that define what is captured in log files. These rules are output using the auditctl -l command. This resource supports versions of `audit` >= 2.3.
|
Use the `auditd` Chef InSpec audit resource to test the rules for logging that exist on the system. The audit.rules file is typically located under /etc/audit/ and contains the list of rules that define what is captured in log files. These rules are output using the `auditctl -l` command. This resource supports versions of `audit` >= 2.3.
|
||||||
|
|
||||||
## Availability
|
## Availability
|
||||||
|
|
||||||
|
|
|
@ -1,226 +0,0 @@
|
||||||
+++
|
|
||||||
title = "azure_virtual_machine_data_disk resource"
|
|
||||||
draft = false
|
|
||||||
gh_repo = "inspec"
|
|
||||||
platform = "azure"
|
|
||||||
|
|
||||||
[menu]
|
|
||||||
[menu.inspec]
|
|
||||||
title = "azure_virtual_machine_data_disk"
|
|
||||||
identifier = "inspec/resources/azure/azure_virtual_machine_data_disk.md azure_virtual_machine_data_disk resource"
|
|
||||||
parent = "inspec/resources/azure"
|
|
||||||
+++
|
|
||||||
|
|
||||||
Use this resource to ensure that a specific data disk attached to a machine has been created properly.
|
|
||||||
|
|
||||||
## Availability
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
|
|
||||||
{{% inspec/inspec_installation %}}
|
|
||||||
|
|
||||||
### Version
|
|
||||||
|
|
||||||
This resource first became available in v2.0.16 of InSpec.
|
|
||||||
|
|
||||||
## Syntax
|
|
||||||
|
|
||||||
The name of the resource group and machine are required to use this resource.
|
|
||||||
|
|
||||||
describe azure_virtual_machine_data_disk(group_name: 'InSpec-Azure', name: 'MyVM') do
|
|
||||||
its('property') { should eq 'value' }
|
|
||||||
end
|
|
||||||
|
|
||||||
where:
|
|
||||||
|
|
||||||
- `MyVm` is the name of the virtual machine as seen in Azure. (It is **not** the hostname of the machine)
|
|
||||||
- `InSpec-Azure` is the name of the resource group that the machine is in.
|
|
||||||
- `property` is a resource property
|
|
||||||
- `value` is the expected output from the matcher
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
The following examples show to use this Chef InSpec audit resource.
|
|
||||||
|
|
||||||
### Check that the first data disk is of the correct size
|
|
||||||
|
|
||||||
describe azure_virtual_machine_data_disk(group_name: 'InSpec-Azure', name: 'Linux-Internal-VM').where(number: 1) do
|
|
||||||
its('size') { should cmp >= 15 }
|
|
||||||
end
|
|
||||||
|
|
||||||
## Resource Parameters
|
|
||||||
|
|
||||||
- `group_name`
|
|
||||||
- `name`
|
|
||||||
- `apiversion`
|
|
||||||
|
|
||||||
## Parameter Examples
|
|
||||||
|
|
||||||
The options that can be passed to the resource are as follows.
|
|
||||||
|
|
||||||
### `group_name` (required)
|
|
||||||
|
|
||||||
Use this parameter to define the Azure Resource Group to be tested.
|
|
||||||
|
|
||||||
describe azure_virtual_machine_data_disk(group_name: 'InSpec-Azure') do
|
|
||||||
...
|
|
||||||
end
|
|
||||||
|
|
||||||
### name
|
|
||||||
|
|
||||||
Use this parameter to define the name of the Azure resource to test.
|
|
||||||
|
|
||||||
describe azure_virtual_machine_data_disk(group_name: 'InSpec-Azure', name: 'Windows-Internal-VM') do
|
|
||||||
...
|
|
||||||
end
|
|
||||||
|
|
||||||
### apiversion
|
|
||||||
|
|
||||||
The API Version to use when querying the resource. Defaults to the latest version for the resource.
|
|
||||||
|
|
||||||
describe azure_virtual_machine_data_disk(group_name: 'InSpec-Azure', name: 'Windows-Internal-VM', apiversion: '2.0') do
|
|
||||||
...
|
|
||||||
end
|
|
||||||
|
|
||||||
These options can also be set using the environment variables:
|
|
||||||
|
|
||||||
- `AZURE_RESOURCE_GROUP_NAME`
|
|
||||||
- `AZURE_RESOURCE_NAME`
|
|
||||||
- `AZURE_RESOURCE_API_VERSION`
|
|
||||||
|
|
||||||
When the options have been set as well as the environment variables, the environment variables take priority.
|
|
||||||
|
|
||||||
## Filter Criteria
|
|
||||||
|
|
||||||
- `number`
|
|
||||||
- `disk`
|
|
||||||
|
|
||||||
## Filter Examples
|
|
||||||
|
|
||||||
### disk
|
|
||||||
|
|
||||||
The zero based index of the disk attached to the machine.
|
|
||||||
|
|
||||||
describe azure_virtual_machine_data_disk(group_name: 'InSpec-Azure', name: 'Windows-Internal-VM').where(disk: 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
### number
|
|
||||||
|
|
||||||
The '1' based index of the disk attached to the machine.
|
|
||||||
|
|
||||||
describe azure_virtual_machine_data_disk(group_name: 'InSpec-Azure', name: 'Windows-Internal-VM').where(number: 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
|
|
||||||
- `count`, `disk`, `number`, `name`, `size`, `lun`, `caching`, `create_option`, `is_managed_disk?`, `vhd_uri`, `storage_account_name`, `storage_account_type`, `id`, `subscription_id`, `resource_group`
|
|
||||||
|
|
||||||
## Property Examples
|
|
||||||
|
|
||||||
### count
|
|
||||||
|
|
||||||
Returns the number of data disks attached to the machine
|
|
||||||
|
|
||||||
its('count') { should eq 1 }
|
|
||||||
|
|
||||||
### name
|
|
||||||
|
|
||||||
Returns a string of the name of the disk.
|
|
||||||
|
|
||||||
its('name') { should cmp 'linux-external-datadisk-1' }
|
|
||||||
|
|
||||||
### size
|
|
||||||
|
|
||||||
Returns an integer of size of this disk in GB.
|
|
||||||
|
|
||||||
its('size') { should cmp >= 15 }
|
|
||||||
|
|
||||||
### lun
|
|
||||||
|
|
||||||
The disk number as reported by Azure. Has a zero-based index value.
|
|
||||||
|
|
||||||
its('lun') { should cmp 0 }
|
|
||||||
|
|
||||||
### caching
|
|
||||||
|
|
||||||
String stating the caching that has been set on the disk.
|
|
||||||
|
|
||||||
its('caching') { should cmp 'none' }
|
|
||||||
|
|
||||||
### create_option
|
|
||||||
|
|
||||||
How the disk was created. Typically for data disks, this will be the string value 'Empty'.
|
|
||||||
|
|
||||||
its('create_option') { should cmp 'Empty' }
|
|
||||||
|
|
||||||
### is_managed_disk?
|
|
||||||
|
|
||||||
Boolean stating if the disk is a managed disk or not. If it is not a managed disk then it is one that is stored in a Storage Account.
|
|
||||||
|
|
||||||
its('is_managed_disk?') { should cmp 'false' }
|
|
||||||
|
|
||||||
### vhd_uri
|
|
||||||
|
|
||||||
If this is _not_ a managed disk, then the `vhd_uri` will be the full URI to the disk in the storage account.
|
|
||||||
|
|
||||||
its('vhd_uri') { should cmp 'https://primary_storage.blob.core.windows.net/container_name/vm_name.vhd' }
|
|
||||||
|
|
||||||
### storage_account_name
|
|
||||||
|
|
||||||
If this is _not_ a managed disk this will be the storage account name in which the disk is stored.
|
|
||||||
|
|
||||||
This derived from the `vhd_uri`.
|
|
||||||
|
|
||||||
its('storage_account_name') { should cmp 'primary_storage' }
|
|
||||||
|
|
||||||
### storage_account_type
|
|
||||||
|
|
||||||
If this is a managed disk this is the storage account type, e.g. `Standard_LRS`.
|
|
||||||
|
|
||||||
its('storage_account_type') { should cmp 'Standard_LRS' }
|
|
||||||
|
|
||||||
### id
|
|
||||||
|
|
||||||
If this is a managed disk then this is the fully qualified id for the disk in Azure.
|
|
||||||
|
|
||||||
its('id') { should cmp '/subscriptions/1234abcd-e567-890f-g123-456h78i9jkl0/resourceGroups/InSpec-Azure' }
|
|
||||||
|
|
||||||
### subscription_id
|
|
||||||
|
|
||||||
If this is a managed disk, this returns the subscription id of where the disk is stored.
|
|
||||||
|
|
||||||
This is derived from the `id`.
|
|
||||||
|
|
||||||
its('subscription_id') { should cmp '1234abcd-e567-890f-g123-456h78i9jkl0' }
|
|
||||||
|
|
||||||
### resource_group
|
|
||||||
|
|
||||||
If this is a managed disk, this returns the resource group in which the disk is stored.
|
|
||||||
|
|
||||||
This is derived from the `id`.
|
|
||||||
|
|
||||||
its('resource_group') { should cmp 'InSpec-Azure' }
|
|
||||||
|
|
||||||
## Matchers
|
|
||||||
|
|
||||||
This Chef InSpec audit resource has the following special matchers. For a full list of available matchers, please visit our [matchers page](/inspec/matchers/).
|
|
||||||
|
|
||||||
The following properties are applied to the virtual machine itself and not specific disks.
|
|
||||||
|
|
||||||
### have_data_disks
|
|
||||||
|
|
||||||
Returns a boolean denoting if any data disks are attached to the machine.
|
|
||||||
|
|
||||||
it { should have_data_disks }
|
|
||||||
|
|
||||||
### have_managed_disks
|
|
||||||
|
|
||||||
Returns a boolean stating if the machine has Managed Disks for data disks.
|
|
||||||
|
|
||||||
it { should have_managed_disks }
|
|
||||||
|
|
||||||
## References
|
|
||||||
|
|
||||||
- [Azure Ruby SDK - Compute](https://github.com/Azure/azure-sdk-for-ruby/tree/master/management/azure_mgmt_compute)
|
|
||||||
- [Linux Internal Data Disks](https://github.com/inspec/inspec/blob/main/test/integration/azure/verify/controls/virtual_machine_linux_external_vm_datadisk.rb)
|
|
||||||
- [Windows Internal Data Disk](https://github.com/inspec/inspec/blob/main/test/integration/azure/verify/controls/virtual_machine_windows_internal_vm_datadisk.rb)
|
|
|
@ -82,7 +82,7 @@ The following examples show how to use this InSpec audit resource.
|
||||||
Filters the results to include only those Users that match the given
|
Filters the results to include only those Users that match the given
|
||||||
name. This is a string value.
|
name. This is a string value.
|
||||||
|
|
||||||
describe azurerm_ad_users.where{ displayName.eql?('Joe Bloggs') } do
|
describe azurerm_ad_users.where{ displayName.eql?('Haris Shefu') } do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ Indicates the type of database account, e.g. `GlobalDocumentDB`, `MongoDB`
|
||||||
|
|
||||||
### tags
|
### tags
|
||||||
|
|
||||||
Resource tags applied to the ComsosDb Account.
|
Resource tags applied to the Cosmos DB Account.
|
||||||
|
|
||||||
### properties
|
### properties
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ This resource first became available in 1.11.0 of the inspec-azure resource pack
|
||||||
|
|
||||||
The `resource_group`, `namespace_name`, `event_hub_name` and `authorization_rule_name` must be given as a parameter.
|
The `resource_group`, `namespace_name`, `event_hub_name` and `authorization_rule_name` must be given as a parameter.
|
||||||
|
|
||||||
describe azurerm_event_hub_authorization_rule(resource_group: 'my-rg', namespace_name 'my-event-hub-ns', event_hub_name: 'myeventhub', authorization_rule_name: 'my-auth-rule') do
|
describe azurerm_event_hub_authorization_rule(resource_group: 'my-rg', namespace_name 'event-hub-namespace', event_hub_name: 'event-hub', authorization_rule_name: 'my-auth-rule') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -57,13 +57,13 @@ The `resource_group`, `namespace_name`, `event_hub_name` and `authorization_rule
|
||||||
|
|
||||||
If an Event Hub Authorization Rule is referenced with a valid `Resource Group`, `Namespace Name`, `Event Hub Name` and `Authorization Rule Name`
|
If an Event Hub Authorization Rule is referenced with a valid `Resource Group`, `Namespace Name`, `Event Hub Name` and `Authorization Rule Name`
|
||||||
|
|
||||||
describe azurerm_event_hub_authorization_rule(resource_group: 'my-rg', namespace_name: 'my-event-hub-ns', event_hub_endpoint: 'myeventhub', authorization_rule: 'my-auth-rule') do
|
describe azurerm_event_hub_authorization_rule(resource_group: 'my-rg', namespace_name: 'event-hub-namespace', event_hub_endpoint: 'event-hub', authorization_rule: 'my-auth-rule') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
If a Event Hub Authorization Rule is referenced with an invalid `Resource Group`, `Namespace Name`, `Event Hub Name` or `Authorization Rule Name`
|
If a Event Hub Authorization Rule is referenced with an invalid `Resource Group`, `Namespace Name`, `Event Hub Name` or `Authorization Rule Name`
|
||||||
|
|
||||||
describe azurerm_event_hub_namespace(resource_group: 'invalid-rg', namespace_name: 'i-dont-exist', event_hub_endpoint: 'fakeendpoint', authorization_rule: 'fake-auth-rule') do
|
describe azurerm_event_hub_namespace(resource_group: 'invalid-rg', namespace_name: 'i-do-not-exist', event_hub_endpoint: 'fake-endpoint', authorization_rule: 'fake-auth-rule') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ requests are always welcome.
|
||||||
|
|
||||||
### exists
|
### exists
|
||||||
|
|
||||||
describe azurerm_event_hub_authorization_rule(resource_group: 'my-rg', namespace_name 'my-event-hub-ns', event_hub_name: 'myeventhub', authorization_rule_name: 'my-auth-rule') do
|
describe azurerm_event_hub_authorization_rule(resource_group: 'my-rg', namespace_name 'event-hub-namespace', event_hub_name: 'event-hub', authorization_rule_name: 'my-auth-rule') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ This resource first became available in 1.11.0 of the inspec-azure resource pack
|
||||||
|
|
||||||
The `resource_group`, `namespace_name` and `event_hub_name` must be given as a parameter.
|
The `resource_group`, `namespace_name` and `event_hub_name` must be given as a parameter.
|
||||||
|
|
||||||
describe azurerm_event_hub_event_hub(resource_group: 'my-rg', namespace_name 'my-event-hub-ns', event_hub_name 'myeventhub') do
|
describe azurerm_event_hub_event_hub(resource_group: 'my-rg', namespace_name 'my-event-hub-ns', event_hub_name 'event-hub') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -57,13 +57,13 @@ The `resource_group`, `namespace_name` and `event_hub_name` must be given as a p
|
||||||
|
|
||||||
If an Event Hub Event Hub is referenced with a valid `Resource Group`, `Namespace Name` and `Event Hub Name`
|
If an Event Hub Event Hub is referenced with a valid `Resource Group`, `Namespace Name` and `Event Hub Name`
|
||||||
|
|
||||||
describe azurerm_event_hub_event_hub(resource_group: 'my-rg', namespace_name: 'my-event-hub-ns', event_hub_name 'myeventhub') do
|
describe azurerm_event_hub_event_hub(resource_group: 'my-rg', namespace_name: 'my-event-hub-ns', event_hub_name 'event-hub') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
If a Event Hub Event Hub is referenced with an invalid `Resource Group`, `Namespace Name` and `Event Hub Name`
|
If a Event Hub Event Hub is referenced with an invalid `Resource Group`, `Namespace Name` and `Event Hub Name`
|
||||||
|
|
||||||
describe azurerm_event_hub_event_hub(resource_group: 'invalid-rg', namespace_name: 'i-dont-exist', event_hub_name 'i-dont-exist') do
|
describe azurerm_event_hub_event_hub(resource_group: 'invalid-rg', namespace_name: 'i-do-not-exist', event_hub_name 'i-do-not-exist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ Azure resource ID.
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
Event Hub name, e.g. `myeventhub`.
|
Event Hub name, e.g. `event-hub`.
|
||||||
|
|
||||||
### type
|
### type
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ requests are always welcome.
|
||||||
|
|
||||||
### exists
|
### exists
|
||||||
|
|
||||||
describe azurerm_event_hub_event_hub(resource_group: 'my-rg', namespace_name: 'my-event-hub-ns', event_hub_name: 'myeventhub') do
|
describe azurerm_event_hub_event_hub(resource_group: 'my-rg', namespace_name: 'my-event-hub-ns', event_hub_name: 'event-hub') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ If an Event Hub Namespace is referenced with a valid `Resource Group` and `Names
|
||||||
|
|
||||||
If an Event Hub Namespace is referenced with an invalid `Resource Group` or `Namespace Name`
|
If an Event Hub Namespace is referenced with an invalid `Resource Group` or `Namespace Name`
|
||||||
|
|
||||||
describe azurerm_event_hub_namespace(resource_group: 'invalid-rg', namespace_name: 'i-dont-exist') do
|
describe azurerm_event_hub_namespace(resource_group: 'invalid-rg', namespace_name: 'i-do-not-exist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ If an IoT Hub is referenced with a valid `Resource Group` and `Resource Name`
|
||||||
|
|
||||||
If an IoT Hub is referenced with an invalid `Resource Group` or `Resource Name`
|
If an IoT Hub is referenced with an invalid `Resource Group` or `Resource Name`
|
||||||
|
|
||||||
describe azurerm_iothub(resource_group: 'invalid-rg', resource_name: 'i-dont-exist') do
|
describe azurerm_iothub(resource_group: 'invalid-rg', resource_name: 'i-do-not-exist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ This resource first became available in 1.11.0 of the inspec-azure resource pack
|
||||||
|
|
||||||
The `resource_group`, `resource_name`, `event_hub_endpoint` and `consumer_group` must be given as a parameter.
|
The `resource_group`, `resource_name`, `event_hub_endpoint` and `consumer_group` must be given as a parameter.
|
||||||
|
|
||||||
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'myeventhub', consumer_group: 'my-consumer-group') do
|
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'event-hub', consumer_group: 'my-consumer-group') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,13 +58,13 @@ The `resource_group`, `resource_name`, `event_hub_endpoint` and `consumer_group`
|
||||||
|
|
||||||
If an IoT Hub Event Hub Consumer Group is referenced with a valid `Resource Group`, `Resource Name`, `Event Hub Endpoint` and `Consumer Group`
|
If an IoT Hub Event Hub Consumer Group is referenced with a valid `Resource Group`, `Resource Name`, `Event Hub Endpoint` and `Consumer Group`
|
||||||
|
|
||||||
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'myeventhub', consumer_group: 'my-consumer-group') do
|
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'event-hub', consumer_group: 'my-consumer-group') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
If an IoT Hub Event Hub Consumer Group is referenced with an invalid `Resource Group`, `Resource Name`, `Event Hub Endpoint` or `Consumer Group`
|
If an IoT Hub Event Hub Consumer Group is referenced with an invalid `Resource Group`, `Resource Name`, `Event Hub Endpoint` or `Consumer Group`
|
||||||
|
|
||||||
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'invalid-rg', resource_name: 'invalid-resource', event_hub_endpoint: 'invalideventhub', consumer_group: 'invalid-consumer-group') do
|
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'invalid-rg', resource_name: 'invalid-resource', event_hub_endpoint: 'invalid-event-hub', consumer_group: 'invalid-consumer-group') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ requests are always welcome.
|
||||||
|
|
||||||
### exists
|
### exists
|
||||||
|
|
||||||
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'myeventhub', consumer_group: 'my-consumer-group') do
|
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'event-hub', consumer_group: 'my-consumer-group') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ This resource first became available in 1.11.0 of the inspec-azure resource pack
|
||||||
|
|
||||||
The `resource_group`, `resource_name` and `event_hub_endpoint` must be given as a parameter.
|
The `resource_group`, `resource_name` and `event_hub_endpoint` must be given as a parameter.
|
||||||
|
|
||||||
describe azurerm_iothub_event_hub_consumer_groups(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'myeventhub') do
|
describe azurerm_iothub_event_hub_consumer_groups(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'event-hub') do
|
||||||
its('names') { should include "my-consumer-group"}
|
its('names') { should include "my-consumer-group"}
|
||||||
its('types') { should include 'Microsoft.Devices/IotHubs/EventHubEndpoints/ConsumerGroups' }
|
its('types') { should include 'Microsoft.Devices/IotHubs/EventHubEndpoints/ConsumerGroups' }
|
||||||
end
|
end
|
||||||
|
@ -58,7 +58,7 @@ The `resource_group`, `resource_name` and `event_hub_endpoint` must be given as
|
||||||
|
|
||||||
If a IoT Hub Event Hub Consumer Groups is referenced with a valid `Resource Group`, `Resource Name` and `Event Hub Endpoint`
|
If a IoT Hub Event Hub Consumer Groups is referenced with a valid `Resource Group`, `Resource Name` and `Event Hub Endpoint`
|
||||||
|
|
||||||
describe azurerm_iothub_event_hub_consumer_groups(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'myeventhub') do
|
describe azurerm_iothub_event_hub_consumer_groups(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'event-hub') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ requests are always welcome.
|
||||||
|
|
||||||
### exists
|
### exists
|
||||||
|
|
||||||
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'myeventhub') do
|
describe azurerm_iothub_event_hub_consumer_group(resource_group: 'my-rg', resource_name 'my-iot-hub', event_hub_endpoint: 'event-hub') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ If a Load Balancer is referenced with a valid `Resource Group` and `Load balance
|
||||||
|
|
||||||
If a Load Balancer is referenced with an invalid `Resource Group` or `Load balancer Name`
|
If a Load Balancer is referenced with an invalid `Resource Group` or `Load balancer Name`
|
||||||
|
|
||||||
describe azurerm_load_balancer(resource_group: 'invalid-rg', loadbalancer_name: 'i-dont-exist') do
|
describe azurerm_load_balancer(resource_group: 'invalid-rg', loadbalancer_name: 'i-do-not-exist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -256,12 +256,12 @@ requests are always welcome.
|
||||||
### exists
|
### exists
|
||||||
|
|
||||||
# If a management group is found it will exist
|
# If a management group is found it will exist
|
||||||
describe azurerm_management_group(groupd_id: 'MyGroupId') do
|
describe azurerm_management_group(group_id: 'MyGroupId') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
# management groups that aren't found will not exist
|
# management groups that aren't found will not exist
|
||||||
describe azurerm_management_group(groupd_id: 'DoesNotExist') do
|
describe azurerm_management_group(group_id: 'DoesNotExist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ This resource first became available in 1.6.0 of the inspec-azure resource pack.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
An `azurerm_mysql_databases` resource block returns all MySQL Databases on a MySQL Server, within a Rsource Group.
|
An `azurerm_mysql_databases` resource block returns all MySQL Databases on a MySQL Server, within a resource group.
|
||||||
|
|
||||||
describe azurerm_mysql_databases(resource_group: ..., server_name: ...) do
|
describe azurerm_mysql_databases(resource_group: ..., server_name: ...) do
|
||||||
...
|
...
|
||||||
|
|
|
@ -63,7 +63,7 @@ If a SQL Server is referenced with a valid `Resource Group` and `Server Name`
|
||||||
|
|
||||||
If a SQL Server is referenced with an invalid `Resource Group` or `Server Name`
|
If a SQL Server is referenced with an invalid `Resource Group` or `Server Name`
|
||||||
|
|
||||||
describe azurerm_sql_server(resource_group: 'invalid-rg', server_name: 'i-dont-exist') do
|
describe azurerm_sql_server(resource_group: 'invalid-rg', server_name: 'i-do-not-exist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ If a Network Interface is referenced with a valid `Resource Group` and `Name`
|
||||||
|
|
||||||
If a Network Interface is referenced with an invalid `Resource Group` or `Name`
|
If a Network Interface is referenced with an invalid `Resource Group` or `Name`
|
||||||
|
|
||||||
describe azurerm_network_interface(resource_group: 'invalid-rg', name: 'i-dont-exist') do
|
describe azurerm_network_interface(resource_group: 'invalid-rg', name: 'i-do-not-exist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ If a PostgreSQL Server is referenced with a valid `Resource Group` and `Server N
|
||||||
|
|
||||||
If a PostgreSQL Server is referenced with an invalid `Resource Group` or `Server Name`
|
If a PostgreSQL Server is referenced with an invalid `Resource Group` or `Server Name`
|
||||||
|
|
||||||
describe azurerm_postgresql_server(resource_group: 'invalid-rg', server_name: 'i-dont-exist') do
|
describe azurerm_postgresql_server(resource_group: 'invalid-rg', server_name: 'i-do-not-exist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ This resource first became available in 1.2.0 of the inspec-azure resource pack.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
An `azurerm_sql_databases` resource block returns all SQL Databases on a SQL Server, within a Rsource Group.
|
An `azurerm_sql_databases` resource block returns all SQL Databases on a SQL Server, within a resource group.
|
||||||
|
|
||||||
describe azurerm_sql_databases(resource_group: ..., server_name: ...) do
|
describe azurerm_sql_databases(resource_group: ..., server_name: ...) do
|
||||||
...
|
...
|
||||||
|
|
|
@ -63,7 +63,7 @@ If a SQL Server is referenced with a valid `Resource Group` and `Server Name`
|
||||||
|
|
||||||
If a SQL Server is referenced with an invalid `Resource Group` or `Server Name`
|
If a SQL Server is referenced with an invalid `Resource Group` or `Server Name`
|
||||||
|
|
||||||
describe azurerm_sql_server(resource_group: 'invalid-rg', server_name: 'i-dont-exist') do
|
describe azurerm_sql_server(resource_group: 'invalid-rg', server_name: 'i-do-not-exist') do
|
||||||
it { should_not exist }
|
it { should_not exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -123,13 +123,13 @@ The subnet's id.
|
||||||
Id will be in
|
Id will be in
|
||||||
format:
|
format:
|
||||||
|
|
||||||
'/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/Inspec-Azure-mmclane/providers/Microsoft.Network/virtualNetworks/Inspec-VNet/subnets/Inspec-Subnet'
|
'/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Network/virtualNetworks/Inspec-VNet/subnets/Inspec-Subnet'
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
The subnets's name.
|
The subnets's name.
|
||||||
|
|
||||||
its('name') { should eq('MySubnetName') }
|
its('name') { should eq('SubnetName') }
|
||||||
|
|
||||||
### type
|
### type
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ The `resource_group` and 'vnet' must be given as a parameter.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
# Exists if any subnetss exist for a given virtual network in the resource group
|
# Exists if any subnets exist for a given virtual network in the resource group
|
||||||
describe azurerm_subnets(resource_group: 'MyResourceGroup', vnet: 'MyVnetName') do
|
describe azurerm_subnets(resource_group: 'MyResourceGroup', vnet: 'MyVnetName') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
|
@ -121,7 +121,7 @@ The virtual network's id.
|
||||||
Id will be in
|
Id will be in
|
||||||
format:
|
format:
|
||||||
|
|
||||||
'/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/Inspec-Azure-mmclane/providers/Microsoft.Network/virtualNetworks/MyVnetName'
|
'/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Network/virtualNetworks/MyVnetName'
|
||||||
|
|
||||||
### name
|
### name
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ The Resource Group as well as the Webapp name.
|
||||||
- `auth_settings`
|
- `auth_settings`
|
||||||
- `configuration`
|
- `configuration`
|
||||||
|
|
||||||
All of the attributes are avialable via dot notation. This is an example of the currently available attributes.
|
All of the attributes are available via dot notation. This is an example of the currently available attributes.
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
control 'azurerm_webapp' do
|
control 'azurerm_webapp' do
|
||||||
|
|
|
@ -167,7 +167,7 @@ By default the command that is ran is shown in the Chef InSpec output. This can
|
||||||
The following examples show how to use `redact_regex`:
|
The following examples show how to use `redact_regex`:
|
||||||
|
|
||||||
# Example without capture groups
|
# Example without capture groups
|
||||||
describe command('myapp -p secretpassword -d no_redact', redact_regex: /-p .* -d/) do
|
describe command('myapp -p secret_password -d no_redact', redact_regex: /-p .* -d/) do
|
||||||
its('exit_status') { should cmp 0 }
|
its('exit_status') { should cmp 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ The following examples show how to use `redact_regex`:
|
||||||
# Example with capture groups
|
# Example with capture groups
|
||||||
# Each set of parenthesis is a capture group.
|
# Each set of parenthesis is a capture group.
|
||||||
# Anything in the two capture groups will not be 'REDACTED'
|
# Anything in the two capture groups will not be 'REDACTED'
|
||||||
describe command('myapp -p secretpassword -d no_redact', redact_regex: /(-p ).*( -d)/) do
|
describe command('myapp -p secret_password -d no_redact', redact_regex: /(-p ).*( -d)/) do
|
||||||
its('exit_status') { should cmp 0 }
|
its('exit_status') { should cmp 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ This resource uses package names and perl library paths as resource parameters.
|
||||||
Hint: You can pass multiple paths separated with a colon
|
Hint: You can pass multiple paths separated with a colon
|
||||||
`/path/to/perl5/lib:/usr/share/perl5/vendor_perl/lib/perl5`
|
`/path/to/perl5/lib:/usr/share/perl5/vendor_perl/lib/perl5`
|
||||||
|
|
||||||
describe cpan('DBD::Pg', '/home/jdoe/perl5/lib/perl5') do
|
describe cpan('DBD::Pg', '/home/username/perl5/lib/perl5') do
|
||||||
it { should be_installed }
|
it { should be_installed }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ The following examples show how to use this audit resource.
|
||||||
it { should have_entry "5 * * * * /some/scheduled/task.sh" }
|
it { should have_entry "5 * * * * /some/scheduled/task.sh" }
|
||||||
end
|
end
|
||||||
|
|
||||||
### Test to ensure myuser's crontab has a particular cron entry
|
### Test to ensure a user's crontab has a particular cron entry
|
||||||
|
|
||||||
describe cron('MY_USER') do
|
describe cron('MY_USER') do
|
||||||
it { should have_entry "5 * * * * /some/scheduled/task.sh" }
|
it { should have_entry "5 * * * * /some/scheduled/task.sh" }
|
||||||
|
|
|
@ -55,9 +55,9 @@ The following examples show how to use this Chef InSpec audit resource.
|
||||||
its('commands') { should include '/path/to/some/script -option arg' }
|
its('commands') { should include '/path/to/some/script -option arg' }
|
||||||
end
|
end
|
||||||
|
|
||||||
### Test that myuser's crontab entry for command '/home/myuser/build.sh' runs every minute
|
### Test that username's crontab entry for command '/home/username/build.sh' runs every minute
|
||||||
|
|
||||||
describe crontab('myuser').commands('/home/myuser/build.sh') do
|
describe crontab('username').commands('/home/username/build.sh') do
|
||||||
its('hours') { should cmp '*' }
|
its('hours') { should cmp '*' }
|
||||||
its('minutes') { should cmp '*' }
|
its('minutes') { should cmp '*' }
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,7 +25,7 @@ This resource first became available in v1.21.0 of InSpec.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
A `docker` resource block declares allows you to write test for many containers:
|
A `docker` resource block allows you to write tests for many containers:
|
||||||
|
|
||||||
describe docker.containers do
|
describe docker.containers do
|
||||||
its('images') { should_not include 'u12:latest' }
|
its('images') { should_not include 'u12:latest' }
|
||||||
|
@ -33,7 +33,7 @@ A `docker` resource block declares allows you to write test for many containers:
|
||||||
|
|
||||||
or:
|
or:
|
||||||
|
|
||||||
describe docker.containers.where { names == 'flamboyant_colden' } do
|
describe docker.containers.where { names == 'flamboyant_allen' } do
|
||||||
it { should be_running }
|
it { should be_running }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ where
|
||||||
The `docker` resource block also declares allows you to write test for many images:
|
The `docker` resource block also declares allows you to write test for many images:
|
||||||
|
|
||||||
describe docker.images do
|
describe docker.images do
|
||||||
its('repositories') { should_not include 'inssecure_image' }
|
its('repositories') { should_not include 'insecure_image' }
|
||||||
end
|
end
|
||||||
|
|
||||||
or if you want to query specific images:
|
or if you want to query specific images:
|
||||||
|
|
|
@ -29,7 +29,7 @@ A `docker_service` resource block declares the service by name:
|
||||||
|
|
||||||
describe docker_service('foo') do
|
describe docker_service('foo') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
its('id') { should eq '2ghswegspre1' }
|
its('id') { should eq 'docker-service-id' }
|
||||||
its('repo') { should eq 'alpine' }
|
its('repo') { should eq 'alpine' }
|
||||||
its('tag') { should eq 'latest' }
|
its('tag') { should eq 'latest' }
|
||||||
end
|
end
|
||||||
|
@ -38,7 +38,7 @@ A `docker_service` resource block declares the service by name:
|
||||||
|
|
||||||
The resource allows you to pass in a service id:
|
The resource allows you to pass in a service id:
|
||||||
|
|
||||||
describe docker_service(id: '2ghswegspre1') do
|
describe docker_service(id: 'docker-service-id') do
|
||||||
...
|
...
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ The following examples show how to use Chef InSpec `docker_service` resource.
|
||||||
|
|
||||||
The `id` property returns the service id:
|
The `id` property returns the service id:
|
||||||
|
|
||||||
its('id') { should eq '2ghswegspre1' }
|
its('id') { should eq 'docker-service-id' }
|
||||||
|
|
||||||
### image
|
### image
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ The `tag` property tests the value of image tag:
|
||||||
|
|
||||||
describe docker_service('foo') do
|
describe docker_service('foo') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
its('id') { should eq '2ghswegspre1' }
|
its('id') { should eq 'docker-service-id' }
|
||||||
its('repo') { should eq 'alpine' }
|
its('repo') { should eq 'alpine' }
|
||||||
its('tag') { should eq 'latest' }
|
its('tag') { should eq 'latest' }
|
||||||
end
|
end
|
||||||
|
|
|
@ -77,7 +77,8 @@ The `all_host_names` property returns a two-dimensional string array where each
|
||||||
its('ip_address') { should cmp '127.0.1.154' }
|
its('ip_address') { should cmp '127.0.1.154' }
|
||||||
end
|
end
|
||||||
|
|
||||||
### Test the primay name for where ip address is '::1'
|
### Test the primary name for where IP address is '::1'
|
||||||
|
|
||||||
describe etc_hosts.where { ip_address == '::1' } do
|
describe etc_hosts.where { ip_address == '::1' } do
|
||||||
its('primary_name') { should cmp 'localhost' }
|
its('primary_name') { should cmp 'localhost' }
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,7 +61,7 @@ The `free_kb` property returns the size of available space on the partition in k
|
||||||
|
|
||||||
its('size_kb') { should be >= 32000 }
|
its('size_kb') { should be >= 32000 }
|
||||||
|
|
||||||
## percent_free (Integrer)
|
## percent_free (Integer)
|
||||||
|
|
||||||
The `percent_free` property returns the available free space on the partition, ranges from 0 to 100.
|
The `percent_free` property returns the available free space on the partition, ranges from 0 to 100.
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ You can include the username and password in the `proxy` parameter:
|
||||||
|
|
||||||
The `proxy` parameter also accepts proxy options in hash format:
|
The `proxy` parameter also accepts proxy options in hash format:
|
||||||
|
|
||||||
describe http('http://localhost:8080/ping', proxy: { uri: 'http://www.example.com:3128', user: 'username', password: 'proxypassword'}) do
|
describe http('http://localhost:8080/ping', proxy: { uri: 'http://www.example.com:3128', user: 'username', password: 'proxy-password'}) do
|
||||||
...
|
...
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ For example:
|
||||||
|
|
||||||
`physical_path` property returns the physical path of the application, such as `'C:\\inetpub\\wwwroot\\myapp'`.
|
`physical_path` property returns the physical path of the application, such as `'C:\\inetpub\\wwwroot\\myapp'`.
|
||||||
|
|
||||||
its('phyiscal_path') { should eq 'C:\\inetpub\\wwwroot\\myapp' }
|
its('physical_path') { should eq 'C:\\inetpub\\wwwroot\\myapp' }
|
||||||
|
|
||||||
### protocols
|
### protocols
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ Settings inside of sections, such as the following:
|
||||||
|
|
||||||
In the event a section or setting name has a period in it, the alternate syntax can be used:
|
In the event a section or setting name has a period in it, the alternate syntax can be used:
|
||||||
|
|
||||||
its(['section.with.a.dot.in.it', 'setting.name.with.dots']) { should cmp 'lotsadots' }
|
its(['section.with.a.dot.in.it', 'setting.name.with.dots']) { should cmp 'lots-of-dots' }
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,6 @@ For a full list of available matchers, please visit our [matchers page](/inspec/
|
||||||
|
|
||||||
### have_rule
|
### have_rule
|
||||||
|
|
||||||
The `have_rule` matcher tests the named rule against the information in the output rule of `'ipftstat -io'`:
|
The `have_rule` matcher tests the named rule against the information in the output rule of `'ipfstat -io'`:
|
||||||
|
|
||||||
it { should have_rule("RULE") }
|
it { should have_rule("RULE") }
|
||||||
|
|
|
@ -29,16 +29,16 @@ This resource first became available in v1.18.0 of InSpec.
|
||||||
|
|
||||||
An `key_rsa` resource block declares a `key file` to be tested.
|
An `key_rsa` resource block declares a `key file` to be tested.
|
||||||
|
|
||||||
describe key_rsa('mycertificate.key') do
|
describe key_rsa('certificate.key') do
|
||||||
it { should be_private }
|
it { should be_private }
|
||||||
it { should be_public }
|
it { should be_public }
|
||||||
its('public_key') { should match "-----BEGIN PUBLIC KEY-----\n3597459df9f3982" }
|
its('public_key') { should match "PUBLIC_KEY" }
|
||||||
its('key_length') { should eq 2048 }
|
its('key_length') { should eq 2048 }
|
||||||
end
|
end
|
||||||
|
|
||||||
You can use an optional passphrase with `key_rsa`
|
You can use an optional passphrase with `key_rsa`
|
||||||
|
|
||||||
describe key_rsa('mycertificate.key', 'passphrase') do
|
describe key_rsa('certificate.key', 'passphrase') do
|
||||||
it { should be_private }
|
it { should be_private }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,23 +48,23 @@ You can use an optional passphrase with `key_rsa`
|
||||||
|
|
||||||
The `public_key` property returns the public part of the RSA key pair
|
The `public_key` property returns the public part of the RSA key pair
|
||||||
|
|
||||||
describe key_rsa('/etc/pki/www.mywebsite.com.key') do
|
describe key_rsa('/etc/pki/www.example.com.key') do
|
||||||
its('public_key') { should match "-----BEGIN PUBLIC KEY-----\n3597459df9f3982......" }
|
its('public_key') { should match "RSA_PUBLIC_KEY" }
|
||||||
end
|
end
|
||||||
|
|
||||||
### private_key (String)
|
### private_key (String)
|
||||||
|
|
||||||
The `private_key` property returns the private key or the RSA key pair.
|
The `private_key` property returns the private key or the RSA key pair.
|
||||||
|
|
||||||
describe key_rsa('/etc/pki/www.mywebsite.com.key') do
|
describe key_rsa('/etc/pki/www.example.com.key') do
|
||||||
its('private_key') { should match "-----BEGIN RSA PRIVATE KEY-----\nMIIJJwIBAAK......" }
|
its('private_key') { should match "RSA_PRIVATE_KEY" }
|
||||||
end
|
end
|
||||||
|
|
||||||
### key_length
|
### key_length
|
||||||
|
|
||||||
The `key_length` property allows testing the number of bits in the key pair.
|
The `key_length` property allows testing the number of bits in the key pair.
|
||||||
|
|
||||||
describe key_rsa('/etc/pki/www.mywebsite.com.key') do
|
describe key_rsa('/etc/pki/www.example.com.key') do
|
||||||
its('key_length') { should eq 2048 }
|
its('key_length') { should eq 2048 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ For a full list of available matchers, please visit our [matchers page](/inspec/
|
||||||
|
|
||||||
To verify if a key is public use the following:
|
To verify if a key is public use the following:
|
||||||
|
|
||||||
describe key_rsa('/etc/pki/www.mywebsite.com.key') do
|
describe key_rsa('/etc/pki/www.example.com.key') do
|
||||||
it { should be_public }
|
it { should be_public }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -84,6 +84,6 @@ To verify if a key is public use the following:
|
||||||
|
|
||||||
This property verifies that the key includes a private key:
|
This property verifies that the key includes a private key:
|
||||||
|
|
||||||
describe key_rsa('/etc/pki/www.mywebsite.com.key') do
|
describe key_rsa('/etc/pki/www.example.com.key') do
|
||||||
it { should be_private }
|
it { should be_private }
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,7 +59,7 @@ The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
### Test a specific host and instance
|
### Test a specific host and instance
|
||||||
|
|
||||||
sql = mssql_session(user: 'my_user', password: 'password', host: 'mssqlserver', instance: 'foo')
|
sql = mssql_session(user: 'my_user', password: 'password', host: 'ms-sql-server', instance: 'foo')
|
||||||
|
|
||||||
describe sql.query("SELECT SERVERPROPERTY('ProductVersion') as result").row(0).column('result') do
|
describe sql.query("SELECT SERVERPROPERTY('ProductVersion') as result").row(0).column('result') do
|
||||||
its("value") { should cmp > '12.00.4457' }
|
its("value") { should cmp > '12.00.4457' }
|
||||||
|
|
|
@ -25,15 +25,15 @@ This resource first became available in v1.0.0 of InSpec.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
A `oracledb_session` resource block declares the username and password to use for the session with an optional service to connect to, and then the command to be run:
|
A `oracledb_session` resource block declares the username and PASSWORD to use for the session with an optional service to connect to, and then the command to be run:
|
||||||
|
|
||||||
describe oracledb_session(user: 'username', password: 'password', service: 'ORCL.localdomain').query('QUERY').row(0).column('result') do
|
describe oracledb_session(user: 'username', PASSWORD: 'PASSWORD', service: 'ORCL.localdomain').query('QUERY').row(0).column('result') do
|
||||||
its('value') { should eq('') }
|
its('value') { should eq('') }
|
||||||
end
|
end
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
- `oracledb_session` declares a username and password with permission to run the query (required), and an optional parameters for host (default: `localhost`), SID (default: `nil`, which uses the default SID, and path to the sqlplus binary (default: `sqlplus`).
|
- `oracledb_session` declares a username and PASSWORD with permission to run the query (required), and an optional parameters for host (default: `localhost`), system identifier (SID) (default: `nil`), which uses the default SID, and path to the sqlplus binary (default: `sqlplus`).
|
||||||
- it is possible to run queries as sysdba/sysoper by using `as_db_role option`, see examples
|
- it is possible to run queries as sysdba/sysoper by using `as_db_role option`, see examples
|
||||||
- SQLcl can be used in place of sqlplus. Use the `sqlcl_bin` option to set the sqlcl binary path instead of `sqlplus_bin`.
|
- SQLcl can be used in place of sqlplus. Use the `sqlcl_bin` option to set the sqlcl binary path instead of `sqlplus_bin`.
|
||||||
- `query('QUERY')` contains the query to be run
|
- `query('QUERY')` contains the query to be run
|
||||||
|
@ -51,7 +51,7 @@ The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
### Test for matching databases
|
### Test for matching databases
|
||||||
|
|
||||||
sql = oracledb_session(user: 'my_user', pass: 'password')
|
sql = oracledb_session(user: 'USERNAME', pass: 'PASSWORD')
|
||||||
|
|
||||||
describe sql.query('SELECT NAME AS VALUE FROM v$database;').row(0).column('value') do
|
describe sql.query('SELECT NAME AS VALUE FROM v$database;').row(0).column('value') do
|
||||||
its('value') { should cmp 'ORCL' }
|
its('value') { should cmp 'ORCL' }
|
||||||
|
@ -59,7 +59,7 @@ The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
### Test for matching databases with custom host, SID and sqlplus binary location
|
### Test for matching databases with custom host, SID and sqlplus binary location
|
||||||
|
|
||||||
sql = oracledb_session(user: 'my_user', pass: 'password', host: 'oraclehost', sid: 'mysid', sqlplus_bin: '/u01/app/oracle/product/12.1.0/dbhome_1/bin/sqlplus')
|
sql = oracledb_session(user: 'USERNAME', pass: 'PASSWORD', host: 'ORACLE_HOST', sid: 'ORACLE_SID', sqlplus_bin: '/u01/app/oracle/product/12.1.0/dbhome_1/bin/sqlplus')
|
||||||
|
|
||||||
describe sql.query('SELECT NAME FROM v$database;').row(0).column('name') do
|
describe sql.query('SELECT NAME FROM v$database;').row(0).column('name') do
|
||||||
its('value') { should cmp 'ORCL' }
|
its('value') { should cmp 'ORCL' }
|
||||||
|
@ -67,9 +67,9 @@ The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
### Test for table contains a specified value in any row for the given column name
|
### Test for table contains a specified value in any row for the given column name
|
||||||
|
|
||||||
sql = oracledb_session(user: 'my_user', pass: 'password', service: 'MYSID')
|
sql = oracledb_session(user: 'USERNAME', pass: 'PASSWORD', service: 'ORACLE_SID')
|
||||||
|
|
||||||
describe sql.query('SELECT * FROM my_table;').column('my_column') do
|
describe sql.query('SELECT * FROM my_table;').column('COLUMN') do
|
||||||
it { should include 'my_value' }
|
it { should include 'my_value' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -77,16 +77,16 @@ The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
The check will change user (with su) to specified user and run 'sqlplus / as sysdba' (sysoper, sysasm)
|
The check will change user (with su) to specified user and run 'sqlplus / as sysdba' (sysoper, sysasm)
|
||||||
|
|
||||||
sql = oracledb_session(as_os_user: 'oracle', as_db_role: 'sysdba', service: 'MYSID')
|
sql = oracledb_session(as_os_user: 'oracle', as_db_role: 'sysdba', service: 'ORACLE_SID')
|
||||||
|
|
||||||
describe sql.query('SELECT tablespace_name AS name FROM dba_tablespaces;').column('name') do
|
describe sql.query('SELECT tablespace_name AS name FROM dba_tablespaces;').column('name') do
|
||||||
it { should include 'MYTABLESPACE' }
|
it { should include 'TABLE_SPACE' }
|
||||||
end
|
end
|
||||||
NOTE: option `as_os_user` available only on unix-like systems and not supported on Windows. Also this option requires that you are running inspec as `root` or with `--sudo`
|
NOTE: option `as_os_user` available only on unix-like systems and not supported on Windows. Also this option requires that you are running inspec as `root` or with `--sudo`
|
||||||
|
|
||||||
### Test number of rows in the query result
|
### Test number of rows in the query result
|
||||||
|
|
||||||
sql = oracledb_session(user: 'my_user', pass: 'password')
|
sql = oracledb_session(user: 'USERNAME', pass: 'PASSWORD')
|
||||||
|
|
||||||
describe sql.query('SELECT * FROM my_table;').rows do
|
describe sql.query('SELECT * FROM my_table;').rows do
|
||||||
its('count') { should eq 20 }
|
its('count') { should eq 20 }
|
||||||
|
@ -94,7 +94,7 @@ The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
### Use data out of (remote) DB query to build other tests
|
### Use data out of (remote) DB query to build other tests
|
||||||
|
|
||||||
sql = oracledb_session(user: 'my_user', pass: 'password', host: 'my.remote.db', service: 'MYSID')
|
sql = oracledb_session(user: 'USERNAME', pass: 'PASSWORD', host: 'my.remote.db', service: 'ORACLE_SID')
|
||||||
|
|
||||||
sql.query('SELECT * FROM files;').rows.each do |file_row|
|
sql.query('SELECT * FROM files;').rows.each do |file_row|
|
||||||
describe file(file_row['path']) do
|
describe file(file_row['path']) do
|
||||||
|
|
|
@ -58,7 +58,7 @@ where
|
||||||
|
|
||||||
### gids
|
### gids
|
||||||
|
|
||||||
The `gids` property tests if the group indentifiers in the test match group identifiers in `/etc/passwd`:
|
The `gids` property tests if the group identifiers in the test match group identifiers in `/etc/passwd`:
|
||||||
|
|
||||||
its('gids') { should include 1234 }
|
its('gids') { should include 1234 }
|
||||||
its('gids') { should cmp 0 }
|
its('gids') { should cmp 0 }
|
||||||
|
|
218
docs-chef-io/content/inspec/resources/podman.md
Normal file
218
docs-chef-io/content/inspec/resources/podman.md
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
+++
|
||||||
|
title = "podman resource"
|
||||||
|
draft = false
|
||||||
|
gh_repo = "inspec"
|
||||||
|
platform = "unix"
|
||||||
|
|
||||||
|
[menu]
|
||||||
|
[menu.inspec]
|
||||||
|
title = "podman"
|
||||||
|
identifier = "inspec/resources/os/podman.md podman resource"
|
||||||
|
parent = "inspec/resources/os"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Use the `podman` Chef InSpec audit resource to test the configuration data for the Podman resources.
|
||||||
|
|
||||||
|
## Availability
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
This resource is distributed with Chef InSpec and is automatically available for use.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
A `podman` resource block allows you to write a test for many `containers`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.containers do
|
||||||
|
its('ids') { should include "591270d8d80d26671fd6ed622f367fbe19004d16e3b519c292313feb5f22e7f7" }
|
||||||
|
its('images) { should include "docker.io/library/ubuntu:latest" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, if you want to query a specific `container`:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.containers.where(id: "591270d8d80d26671fd6ed622f367fbe19004d16e3b519c292313feb5f22e7f7") do
|
||||||
|
its('status') { should include "Up 44 hours ago" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
> Where
|
||||||
|
>
|
||||||
|
> - `.where()` specifies a specific item and value to which the resource parameters are compared.
|
||||||
|
> - `commands`, `created_at`, `ids`, `images`, `names`, `status`, `image_ids`, `labels`, `mounts`, `networks`, `pods`, `ports`, `running_for`, and `sizes` are valid parameters for `containers`.
|
||||||
|
|
||||||
|
The `podman` resource block also allows you to write a test for many `images`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.images do
|
||||||
|
its('repositories') { should_not include 'docker.io/library/nginx' }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, if you want to query a specific `image`:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.images.where(id: "c7db653c4397e6a4d1e468bb7c6400c022c62623bdb87c173d54bac7995b6d8f") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
> Where
|
||||||
|
>
|
||||||
|
> - `.where()` specifies a specific filter and expected value, against which parameters are compared.
|
||||||
|
> - `repositories`, `tags`, `sizes`, `digests`, `history`, `created_at`, `history`, and`created_since` are valid parameters for `images`.
|
||||||
|
|
||||||
|
The `podman` resource block also allows you to write a test for many `networks`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.networks do
|
||||||
|
its("names") { should include "podman" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, if you want to query a specific `network`:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.networks.where(id: "c7db653c4397e6a4d1e468bb7c6400c022c62623bdb87c173d54bac7995b6d8f") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
> Where
|
||||||
|
>
|
||||||
|
> - `.where()` specifies a specific filter and expected value, against which parameters are compared.
|
||||||
|
> - `ids`, `names`, `drivers`, `network_interfaces`, `created`, `subnets`, `ipv6_enabled`, `internal`, `dns_enabled`, `options`, `labels`, and `ipam_options` are valid parameters for `networks`.
|
||||||
|
|
||||||
|
The `podman` resource block also allows you to write a test for many `pods`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.pods do
|
||||||
|
its("names") { should include "cranky_allen" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Or, if you want to query a specific `pod`:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.pods.where(id: "95cadbb84df71e6374fceb3fd89ee3b8f2c7e1a831062cd9cea7d0e3e4b1dbcc") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
> Where
|
||||||
|
>
|
||||||
|
> - `.where()` may specify a specific filter and expected value, against which parameters are compared.
|
||||||
|
> - `ids`, `cgroups`, `containers`, `created`, `infraids`, `names`, `namespaces`, `networks`, `status`, and `labels` are valid parameters for `pods`.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
|
### Returns all running containers
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
podman.containers.running?.ids.each do |id|
|
||||||
|
describe podman.object(id) do
|
||||||
|
its('State.Health.Status') { should eq 'healthy' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resource Parameter Examples
|
||||||
|
|
||||||
|
### containers
|
||||||
|
|
||||||
|
`containers` returns information about containers as returned by [podman ps -a](https://docs.podman.io/en/latest/markdown/podman.1.html).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.containers do
|
||||||
|
its("ids") { should include "591270d8d80d26671fd6ed622f367fbe19004d16e3b519c292313feb5f22e7f7" }
|
||||||
|
its("labels") { should include "maintainer" => "NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e" }
|
||||||
|
its('names') { should include "sweet_mendeleev" }
|
||||||
|
its("images") { should include "docker.io/library/nginx:latest" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### images
|
||||||
|
|
||||||
|
`images` returns information about a Podman image as returned by [podman images -a](https://docs.podman.io/en/latest/markdown/podman-images.1.html).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.images do
|
||||||
|
its('ids') { should include 'sha256:c7db653c4397e6a4d1e468bb7c6400c022c62623bdb87c173d54bac7995b6d8f ' }
|
||||||
|
its('sizes') { should_not include '80.3 GB' }
|
||||||
|
its('repositories") { should include "docker.io/library/nginx"}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### pods
|
||||||
|
|
||||||
|
`pods` returns information about pods as returned by [podman pod ps](https://docs.podman.io/en/latest/markdown/podman-pod-ps.1.html).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.pods do
|
||||||
|
its("ids") { should include "95cadbb84df71e6374fceb3fd89ee3b8f2c7e1a831062cd9cea7d0e3e4b1dbcc" }
|
||||||
|
its("containers") { should eq [{ "Id" => "a218dfc58fa28e0c58c55e508e5b57084876b42e894b98073c69c45dea06cbb2", "Names" => "95cadbb84df7-infra", "Status" => "running" } ]}
|
||||||
|
its("names") { should include "cranky_allen" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### networks
|
||||||
|
|
||||||
|
`networks` returns information about a Podman network as returned by [podman network ls](https://docs.podman.io/en/latest/markdown/podman-network-ls.1.html).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.networks do
|
||||||
|
its("names") { should include "podman" }
|
||||||
|
its("ids") { should include "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9" }
|
||||||
|
its("ipv6_enabled") { should eq [false] }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### volumes
|
||||||
|
|
||||||
|
`volumes` returns information about a Podman volume as returned by [podman volume ls](https://docs.podman.io/en/latest/markdown/podman-volume-ls.1.html).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.volumes do
|
||||||
|
its('names') { should include 'ae6be9ba838b9b150de47657229bb9b67142dbdb3d1ddbc5efa245cf1e95536a' }
|
||||||
|
its('drivers') { should include 'local' }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### info
|
||||||
|
|
||||||
|
`info` returns the parsed result of [podman info](https://docs.podman.io/en/latest/markdown/podman-info.1.html).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.info do
|
||||||
|
its("host.os") { should eq "linux" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
`version` returns the parsed result of [podman version](https://docs.podman.io/en/latest/markdown/podman-version.1.html)
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman.version do
|
||||||
|
its("Client.Version") { should eq "4.1.0"}
|
||||||
|
its('Server.Version') { should eq '4.1.0'}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### object('id')
|
||||||
|
|
||||||
|
`object` returns low-level information about Podman objects as returned by [podman inspect](https://docs.podman.io/en/latest/markdown/podman-inspect.1.html).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe docker.object(id) do
|
||||||
|
its('State.Running') { should eq true }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Matchers
|
||||||
|
|
||||||
|
For a full list of available matchers, please visit our [matchers page](/inspec/matchers/).
|
149
docs-chef-io/content/inspec/resources/podman_container.md
Normal file
149
docs-chef-io/content/inspec/resources/podman_container.md
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
+++
|
||||||
|
title = "podman_container resource"
|
||||||
|
draft = false
|
||||||
|
gh_repo = "inspec"
|
||||||
|
platform = "unix"
|
||||||
|
|
||||||
|
[menu]
|
||||||
|
[menu.inspec]
|
||||||
|
title = "podman_container"
|
||||||
|
identifier = "inspec/resources/os/podman_container.md podman_container resource"
|
||||||
|
parent = "inspec/resources/os"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Use the `podman_container` Chef InSpec audit resource to test the ...
|
||||||
|
|
||||||
|
## Availability
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
This resource is distributed with Chef InSpec and is automatically available for use.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
A `podman_container` Chef InSpec audit resource ...
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_container("sweet_mendeleev") do
|
||||||
|
it { should exist }
|
||||||
|
it { should be_running }
|
||||||
|
its("id") { should eq "591270d8d80d26671fd6ed622f367fbe19004d16e3b519c292313feb5f22e7f7" }
|
||||||
|
its("image") { should eq "docker.io/library/nginx:latest" }
|
||||||
|
its("labels") { should include "maintainer"=>"NGINX Docker Maintainers <docker-maint@nginx.com>" }
|
||||||
|
its("ports") { should eq nil }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Resource Parameter Examples
|
||||||
|
|
||||||
|
### name
|
||||||
|
|
||||||
|
The container name can be provided with the `name` resource parameter.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_container(name: 'an-echo-server') do
|
||||||
|
it { should exist }
|
||||||
|
it { should be_running }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### container ID
|
||||||
|
|
||||||
|
Alternatively, you can pass the container ID.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_container(id: '71b5df59442b') do
|
||||||
|
it { should exist }
|
||||||
|
it { should be_running }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
## Property Examples
|
||||||
|
|
||||||
|
The following examples show how to use this Chef InSpec resource.
|
||||||
|
|
||||||
|
### id
|
||||||
|
|
||||||
|
The `id` property tests the container ID.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its('id') { should eq '71b5df59...442b' }
|
||||||
|
```
|
||||||
|
|
||||||
|
### image
|
||||||
|
|
||||||
|
The `image` property tests the value of the container image.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its('image') { should eq 'docker.io/library/nginx:latest' }
|
||||||
|
```
|
||||||
|
|
||||||
|
### labels
|
||||||
|
|
||||||
|
The `labels` property tests the value of container image labels.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its('labels') { should eq "maintainer" => "NGINX Docker Maintainers <docker-maint@nginx.com>" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### ports
|
||||||
|
|
||||||
|
The `ports` property tests the value of the Podmans ports.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its('ports') { should eq '0.0.0.0:1234->1234/tcp' }
|
||||||
|
```
|
||||||
|
|
||||||
|
### command
|
||||||
|
|
||||||
|
The `command` property tests the value of the container run command.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its('command') { should eq 'nc -ll -p 1234 -e /bin/cat' }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Matchers
|
||||||
|
|
||||||
|
For a full list of available matchers, please visit our [matchers page](/inspec/matchers/). The specific matchers of this resource are: `exist` and `be_running`.
|
||||||
|
|
||||||
|
### exist
|
||||||
|
|
||||||
|
The `exist` matcher specifies if the container exists.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
it { should exist }
|
||||||
|
```
|
||||||
|
|
||||||
|
### be_running
|
||||||
|
|
||||||
|
The `be_running` matcher checks if the container is running.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
it { should be_running }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
The following examples show how to use this Chef InSpec audit resource.
|
||||||
|
|
||||||
|
### Ensures container exists
|
||||||
|
|
||||||
|
The below test passes if the container `sweet_mendeleev` exists as part of the Podman instances.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_container('sweet_mendeleev') do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ensures container is in running status
|
||||||
|
|
||||||
|
The below test passes if the container `sweet_mendeleev` exists as part of the Podman instances and the status is running.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_container('sweet_mendeleev') do
|
||||||
|
it { should be_running }
|
||||||
|
end
|
||||||
|
```
|
189
docs-chef-io/content/inspec/resources/podman_image.md
Normal file
189
docs-chef-io/content/inspec/resources/podman_image.md
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
+++
|
||||||
|
title = "podman_image resource"
|
||||||
|
draft = false
|
||||||
|
gh_repo = "inspec"
|
||||||
|
platform = "unix"
|
||||||
|
|
||||||
|
[menu]
|
||||||
|
[menu.inspec]
|
||||||
|
title = "podman_image"
|
||||||
|
identifier = "inspec/resources/os/podman_image.md podman_image resource"
|
||||||
|
parent = "inspec/resources/os"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Use the `podman_image` Chef InSpec audit resource to test the properties of a container image on Podman.
|
||||||
|
|
||||||
|
## Availability
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
This resource is distributed with Chef InSpec and is automatically available for use.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
A `podman_image` Chef InSpec audit resource aids in testing the properties of a container image on Podman.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_image("docker.io/library/busybox") do
|
||||||
|
it { should exist }
|
||||||
|
its("id") { should eq "3c19bafed22355e11a608c4b613d87d06b9cdd37d378e6e0176cbc8e7144d5c6" }
|
||||||
|
its("repo_tags") { should include "docker.io/library/busybox:latest" }
|
||||||
|
its("size") { should eq 1636053 }
|
||||||
|
its("os") { should eq "linux" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
> where
|
||||||
|
>
|
||||||
|
> - `id`, `repo_tags`, `size`, and `os` are properties of this resource to fetch the respective value of the container image.
|
||||||
|
> - `exist` is a matcher of this resource.
|
||||||
|
|
||||||
|
### Resource Parameter Examples
|
||||||
|
|
||||||
|
- The resource allows you to pass an image name. If the tag is missing for an image, `latest` is assumed as default.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_image("docker.io/library/busybox") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- The resource allows you to pass the repository and tag values as separate values.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_image(repo: "docker.io/library/busybox", tag: "latest") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- The resource allows you to pass with an image ID.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_image(id: "8847e9bf6df8") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### id
|
||||||
|
|
||||||
|
The `id` property returns the full image ID.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("id") { should eq "3c19bafed22355e11a608c4b613d87d06b9cdd37d378e6e0176cbc8e7144d5c6" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### repo_tags
|
||||||
|
|
||||||
|
The `repo_tags` property tests the value of the repository name.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("repo_tags") { should include "docker.io/library/busybox:latest" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### size
|
||||||
|
|
||||||
|
The `size` property tests the size of the image in bytes
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("size") { should eq 1636053 }
|
||||||
|
```
|
||||||
|
|
||||||
|
### digest
|
||||||
|
|
||||||
|
The `digest` property tests the value of the image digest.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("digest") { should eq "sha256:3614ca5eacf0a3a1bcc361c939202a974b4902b9334ff36eb29ffe9011aaad83" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### created_at
|
||||||
|
|
||||||
|
The `created_at` property tests the time of the image creation.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("created_at") { should eq "2022-06-08T00:39:28.175020858Z" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
The `version` property tests the version of the image.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("version") { should eq "20.10.12" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### names_history
|
||||||
|
|
||||||
|
The `names_history` property tests the names history of the image.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("names_history") { should include "docker.io/library/busybox:latest" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### repo_digests
|
||||||
|
|
||||||
|
The `repo_digests` tests the digest of the repository of the given image.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("repo_digests") { should include "docker.io/library/busybox@sha256:2c5e2045f35086c019e80c86880fd5b7c7a619878b59e3b7592711e1781df51a" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### architecture
|
||||||
|
|
||||||
|
The `architecture` tests the architecture of the given image.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("architecture") { should eq "arm64" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### os
|
||||||
|
|
||||||
|
The `os` property tests the operating system of the given image.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("os") { should eq "linux" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### virtual_size
|
||||||
|
|
||||||
|
The `virtual_size` property tests the virtual size of the given image.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("virtual_size") { should eq 1636053 }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Matchers
|
||||||
|
|
||||||
|
For a full list of available matchers, please visit our [matchers page](/inspec/matchers/).
|
||||||
|
|
||||||
|
### exist
|
||||||
|
|
||||||
|
The `exist` matcher tests if the image is available on Podman.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
it { should exist }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Test if an image exists on Podman and verify the various image properties
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_image("docker.io/library/busybox") do
|
||||||
|
it { should exist }
|
||||||
|
its("id") { should eq "3c19bafed22355e11a608c4b613d87d06b9cdd37d378e6e0176cbc8e7144d5c6" }
|
||||||
|
its("repo_tags") { should include "docker.io/library/busybox:latest" }
|
||||||
|
its("size") { should eq 1636053 }
|
||||||
|
its("digest") { should eq "sha256:3614ca5eacf0a3a1bcc361c939202a974b4902b9334ff36eb29ffe9011aaad83" }
|
||||||
|
its("created_at") { should eq "2022-06-08T00:39:28.175020858Z" }
|
||||||
|
its("version") { should eq "20.10.12" }
|
||||||
|
its("names_history") { should include "docker.io/library/busybox:latest" }
|
||||||
|
its("repo_digests") { should include "docker.io/library/busybox@sha256:2c5e2045f35086c019e80c86880fd5b7c7a619878b59e3b7592711e1781df51a" }
|
||||||
|
its("architecture") { should eq "arm64" }
|
||||||
|
its("os") { should eq "linux" }
|
||||||
|
its("virtual_size") { should eq 1636053 }
|
||||||
|
its("resource_id") { should eq "docker.io/library/busybox:latest" }
|
||||||
|
end
|
||||||
|
```
|
189
docs-chef-io/content/inspec/resources/podman_network.md
Normal file
189
docs-chef-io/content/inspec/resources/podman_network.md
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
+++
|
||||||
|
title = "podman_network resource"
|
||||||
|
draft = false
|
||||||
|
gh_repo = "inspec"
|
||||||
|
platform = "unix"
|
||||||
|
|
||||||
|
[menu]
|
||||||
|
[menu.inspec]
|
||||||
|
title = "podman_network"
|
||||||
|
identifier = "inspec/resources/os/podman_network.md podman_network resource"
|
||||||
|
parent = "inspec/resources/os"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Use the `podman_network` Chef InSpec audit resource to test the properties of existing Podman networks.
|
||||||
|
|
||||||
|
## Availability
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
This resource is distributed with Chef InSpec and is automatically available for use.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
A `podman_network` Chef InSpec audit resource aids in testing the properties of a Podman network.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_network("minikube") do
|
||||||
|
it { should exist }
|
||||||
|
its("id") { should eq "3a7c94d937d5f3a0f1a9b1610589945aedfbe56207fd5d32fc8154aa1a8b007f" }
|
||||||
|
its("name") { should eq "minikube" }
|
||||||
|
its("ipv6_enabled") { should eq false }
|
||||||
|
its("network_interface") { should eq "podman1" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
> where
|
||||||
|
>
|
||||||
|
> - `id`, `name`, `ipv6_enabled`, and `network_interface` are properties of this resource to fetch the respective value of the Podman network.
|
||||||
|
> - `exist` is a matcher of this resource.
|
||||||
|
|
||||||
|
### Resource Parameter Examples
|
||||||
|
|
||||||
|
- The resource allows you to pass a network name.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_network("minikube") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- The resource allows you to pass with a Network ID.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_network("3a7c94d937d5") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### id
|
||||||
|
|
||||||
|
The `id` property returns the full Podman Network ID.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("id") { should eq "3c19bafed22355e11a608c4b613d87d06b9cdd37d378e6e0176cbc8e7144d5c6" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### name
|
||||||
|
|
||||||
|
The `name` property tests the value of the Podman network name.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("name") { should eq "minikube" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### ipv6_enabled
|
||||||
|
|
||||||
|
The `ipv6_enabled` property tests whether ipv6 is enabled on the Podman network.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("ipv6_enabled") { should eq true }
|
||||||
|
```
|
||||||
|
|
||||||
|
### network_interface
|
||||||
|
|
||||||
|
The `network_interface` property tests the value of the network interface settings on the Podman network.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("network_interface") { should eq "podman0" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### created
|
||||||
|
|
||||||
|
The `created` property tests the timestamp when the Podman network was created.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("created") { should eq "2022-07-06T08:51:11.735432521+05:30" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### subnets
|
||||||
|
|
||||||
|
The `subnets` property tests the list of subnets on the Podman network.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("subnets") { should inclue "gateway"=>"192.168.49.1", "subnet"=>"192.168.49.0/24" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### dns_enabled
|
||||||
|
|
||||||
|
The `dns_enabled` property tests whether the Podman network has DNS enabled.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("dns_enabled") { should be false }
|
||||||
|
```
|
||||||
|
|
||||||
|
### internal
|
||||||
|
|
||||||
|
The `internal` property tests whether the specified Podman network is internal.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("internal") { should eq true }
|
||||||
|
```
|
||||||
|
|
||||||
|
### ipam_options
|
||||||
|
|
||||||
|
The `ipam_options` property tests the IPAM options of the given Podman network.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("ipam_options") { should eq "driver" => "host-local" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### labels
|
||||||
|
|
||||||
|
The `labels` property tests the labels set for the specified Podman network.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("labels") { should eq "created_by.minikube.sigs.k8s.io"=>"true", "name.minikube.sigs.k8s.io"=>"minikube" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### driver
|
||||||
|
|
||||||
|
The `driver` property tests the value of the Podman network driver.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("driver") { should eq "bridge" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### options
|
||||||
|
|
||||||
|
The `options` property tests the network options for the specified Podman network.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("options") { should eq nil }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Matchers
|
||||||
|
|
||||||
|
For a full list of available matchers, please visit our [matchers page](/inspec/matchers/).
|
||||||
|
|
||||||
|
### exist
|
||||||
|
|
||||||
|
The `exist` matcher tests if the specified network is available on Podman.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
it { should exist }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Tests if a given Podman network exists and verifies the various network properties
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_network("minikube") do
|
||||||
|
it { should exist }
|
||||||
|
its("id") { should eq "3a7c94d937d5f3a0f1a9b1610589945aedfbe56207fd5d32fc8154aa1a8b007f" }
|
||||||
|
its("name") { should eq "minikube" }
|
||||||
|
its("ipv6_enabled") { should eq false }
|
||||||
|
its("network_interface") { should eq "podman1" }
|
||||||
|
its("subnets") { should include "gateway"=>"192.168.49.1", "subnet"=>"192.168.49.0/24" }
|
||||||
|
its("dns_enabled") { should eq true }
|
||||||
|
its("internal") { should eq false }
|
||||||
|
its("created") { should eq "2022-07-06T08:51:11.735432521+05:30" }
|
||||||
|
its("ipam_options") { should eq "driver" => "host-local" }
|
||||||
|
its("labels") { should eq "created_by.minikube.sigs.k8s.io"=>"true", "name.minikube.sigs.k8s.io"=>"minikube" }
|
||||||
|
its("driver") { should eq "bridge" }
|
||||||
|
its("options") { should eq nil }
|
||||||
|
end
|
||||||
|
```
|
210
docs-chef-io/content/inspec/resources/podman_pod.md
Normal file
210
docs-chef-io/content/inspec/resources/podman_pod.md
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
+++
|
||||||
|
title = "podman_pod resource"
|
||||||
|
draft = false
|
||||||
|
gh_repo = "inspec"
|
||||||
|
platform = "unix"
|
||||||
|
|
||||||
|
[menu]
|
||||||
|
[menu.inspec]
|
||||||
|
title = "podman_pod"
|
||||||
|
identifier = "inspec/resources/os/podman_pod.md podman_pod resource"
|
||||||
|
parent = "inspec/resources/os"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Use the `podman_pod` Chef InSpec audit resource to test the properties of a pod on Podman.
|
||||||
|
|
||||||
|
## Availability
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
This resource is distributed with Chef InSpec and is automatically available for use.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
A `podman_pod` Chef InSpec audit resource aids in testing the properties of a pod on Podman.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_pod("nginx-frontend") do
|
||||||
|
it { should exist }
|
||||||
|
its("id") { should eq "fcfe4d471cfface0d1b39bce23af7d31ab8736cd68c0360ade0b4afe364f79d4" }
|
||||||
|
its("name") { should eq "nginx-frontend" }
|
||||||
|
its("created_at") { should eq "2022-07-14T15:47:47.978078124+05:30" }
|
||||||
|
its("create_command") { should include "new:nginx-frontend" }
|
||||||
|
its("state") { should eq "Running" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
> where
|
||||||
|
>
|
||||||
|
> - `'nginx-frontend'` is the name of the pod. Pod ID and Pod names are valid parameters accepted by `podman_pod`.
|
||||||
|
> - `'id'`, `'name'`, `'created_at'`, `'create_command'`, and `'state'`, are properties of this resource to fetch the respective value of the podman pod.
|
||||||
|
> - `exist` is a matcher of this resource.
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
- Properties of the resources are: `'id'`, `'name'`, `'created_at'`, `'create_command'`, `'state'`, `'hostname'`, `'create_cgroup'`, `'cgroup_parent'`, `cgroup_path`, `'create_infra'`, `'infra_container_id'`, `'infra_config'`, `'shared_namespaces'`, `'num_containers'`, and `'containers'`
|
||||||
|
|
||||||
|
### `id`
|
||||||
|
|
||||||
|
The `id` property returns the id of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("id") { should eq "fcfe4d471cfface0d1b39bce23af7d31ab8736cd68c0360ade0b4afe364f79d4" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `name`
|
||||||
|
|
||||||
|
The `name` property returns the name of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("name") { should eq "nginx-frontend" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `created_at`
|
||||||
|
|
||||||
|
The `created_at` property returns the creation date of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("created_at") { should eq "2022-07-14T15:47:47.978078124+05:30" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `create_command`
|
||||||
|
|
||||||
|
The `create_command` property returns an array of commands used to create the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("create_command") { should include "new:nginx-frontend" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `state`
|
||||||
|
|
||||||
|
The `state` property returns the state of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("state") { should eq "Running" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `hostname`
|
||||||
|
|
||||||
|
The `hostname` property returns the hostname of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("hostname") { should eq "" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `create_cgroup`
|
||||||
|
|
||||||
|
The `create_cgroup` property returns a boolean value for cgroup creation of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("create_cgroup") { should eq true }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `cgroup_parent`
|
||||||
|
|
||||||
|
The `cgroup_parent` property returns the name of the cgroup parent of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("cgroup_parent") { should eq "user.slice" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `cgroup_path`
|
||||||
|
|
||||||
|
The `cgroup_path` property returns the path of the cgroup parent of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("cgroup_path") { should eq "user.slice/user-libpod_pod_fcfe4d471cfface0d1b39bce23af7d31ab8736cd68c0360ade0b4afe364f79d4.slice" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `create_infra`
|
||||||
|
|
||||||
|
The `create_infra` property returns a boolean value for the pod infra creation.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("create_infra") { should eq true }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `infra_container_id`
|
||||||
|
|
||||||
|
The `infra_container_id` property returns the infra container ID of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("infra_container_id") { should eq "727538044b32a165934729dc2d47d9d5e981b6496aebfad7de470f7e76ea4251" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `infra_config`
|
||||||
|
|
||||||
|
The `infra_config` property returns a hash of the infra configuration of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("infra_config") { should include "DNSOption" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `shared_namespaces`
|
||||||
|
|
||||||
|
The `shared_namespaces` property returns an array of shared namespaces of the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("shared_namespaces") { should include "ipc" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `num_containers`
|
||||||
|
|
||||||
|
The `num_containers` property returns the number of containers in the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("num_containers") { should eq 2 }
|
||||||
|
```
|
||||||
|
|
||||||
|
### `containers`
|
||||||
|
|
||||||
|
The `containers` property returns an array of hashes about the information of containers in the pod.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("containers") { should_not be nil }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Matchers
|
||||||
|
|
||||||
|
For a full list of available matchers, please visit our [matchers page](/inspec/matchers/).
|
||||||
|
|
||||||
|
### exist
|
||||||
|
|
||||||
|
The `exist` matcher tests if the pod is available on Podman.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
it { should exist }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Test if a pod exists on Podman and verifies pod properties
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_pod("nginx-frontend") do
|
||||||
|
it { should exist }
|
||||||
|
its("id") { should eq "fcfe4d471cfface0d1b39bce23af7d31ab8736cd68c0360ade0b4afe364f79d4" }
|
||||||
|
its("name") { should eq "nginx-frontend" }
|
||||||
|
its("created_at") { should eq "2022-07-14T15:47:47.978078124+05:30" }
|
||||||
|
its("create_command") { should include "new:nginx-frontend" }
|
||||||
|
its("state") { should eq "Running" }
|
||||||
|
its("hostname") { should eq "" }
|
||||||
|
its("create_cgroup") { should eq true }
|
||||||
|
its("cgroup_parent") { should eq "user.slice" }
|
||||||
|
its("cgroup_path") { should eq "user.slice/user-libpod_pod_fcfe4d471cfface0d1b39bce23af7d31ab8736cd68c0360ade0b4afe364f79d4.slice" }
|
||||||
|
its("create_infra") { should eq true }
|
||||||
|
its("infra_container_id") { should eq "727538044b32a165934729dc2d47d9d5e981b6496aebfad7de470f7e76ea4251" }
|
||||||
|
its("infra_config") { should include "DNSOption" }
|
||||||
|
its("shared_namespaces") { should include "ipc" }
|
||||||
|
its("num_containers") { should eq 2 }
|
||||||
|
its("containers") { should_not be nil }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test if a pod does not exist on Podman
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_pod("non_existing_pod") do
|
||||||
|
it { should_not exist }
|
||||||
|
end
|
||||||
|
```
|
155
docs-chef-io/content/inspec/resources/podman_volume.md
Normal file
155
docs-chef-io/content/inspec/resources/podman_volume.md
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
+++
|
||||||
|
title = "podman_volume resource"
|
||||||
|
draft = false
|
||||||
|
gh_repo = "inspec"
|
||||||
|
platform = "unix"
|
||||||
|
|
||||||
|
[menu]
|
||||||
|
[menu.inspec]
|
||||||
|
title = "podman_volume"
|
||||||
|
identifier = "inspec/resources/os/podman_volume.md podman_volume resource"
|
||||||
|
parent = "inspec/resources/os"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Use the `podman_volume` Chef InSpec audit resource to test the properties of a volume on Podman.
|
||||||
|
|
||||||
|
## Availability
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
This resource is distributed with Chef InSpec and is automatically available for use.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
A `podman_volume` Chef InSpec audit resource aids in testing the properties of a volume on Podman.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_volume("my_volume") do
|
||||||
|
it { should exist }
|
||||||
|
its("name") { should eq "my_volume" }
|
||||||
|
its("driver") { should eq "local" }
|
||||||
|
its("mountpoint") { should eq "/var/home/core/.local/share/containers/storage/volumes/my_volume/_data" }
|
||||||
|
its("created_at") { should eq "2022-07-14T13:21:19.965421792+05:30" }
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
> where
|
||||||
|
>
|
||||||
|
> - `'name'`, `'driver'`, `'mountpoint'`, and `'created_at'` are properties of this resource to fetch the respective value of the podman volume.
|
||||||
|
> - `exist` is a matcher of this resource.
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
- Properties of the resources: `name`, `driver`, `mountpoint`, `created_at`, `labels`, `scope`, `options`, `mount_count`, `needs_copy_up`, and `needs_chown`.
|
||||||
|
|
||||||
|
### name
|
||||||
|
|
||||||
|
The `name` property returns the name of the volume.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("name") { should eq "my_volume" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### driver
|
||||||
|
|
||||||
|
The `driver` property returns the value for the volume's driver environment.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("driver") { should eq "local" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### mountpoint
|
||||||
|
|
||||||
|
The `mountpoint` property returns the value for the volume's mount path.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("mountpoint") { should eq "/var/home/core/.local/share/containers/storage/volumes/my_volume/_data" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### created_at
|
||||||
|
|
||||||
|
The `created_at` property returns the creation date of the volume.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("created_at") { should eq "2022-07-14T13:21:19.965421792+05:30" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### labels
|
||||||
|
|
||||||
|
The `labels` property returns the labels associated with the volume.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("labels") { should eq({}) }
|
||||||
|
```
|
||||||
|
|
||||||
|
### scope
|
||||||
|
|
||||||
|
The `scope` property returns the scope of the volume.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("scope") { should eq "local" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### options
|
||||||
|
|
||||||
|
The `options` property returns the options associated with the volume.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("options") { should eq({}) }
|
||||||
|
```
|
||||||
|
|
||||||
|
### mount_count
|
||||||
|
|
||||||
|
The `mount_count` property returns the **MountCount** value from the volume's inspect information.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("mount_count") { should eq 0 }
|
||||||
|
```
|
||||||
|
|
||||||
|
### needs_copy_up
|
||||||
|
|
||||||
|
The `needs_copy_up` property returns the **NeedsCopyUp** value from the volume's inspect information.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("needs_copy_up") { should eq true }
|
||||||
|
```
|
||||||
|
|
||||||
|
### needs_chown
|
||||||
|
|
||||||
|
The `needs_chown` property returns the **NeedsChown** value from the volume's inspect information.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
its("needs_chown") { should eq true }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Matchers
|
||||||
|
|
||||||
|
For a full list of available matchers, please visit our [matchers page](/inspec/matchers/).
|
||||||
|
|
||||||
|
### exist
|
||||||
|
|
||||||
|
The `exist` matcher tests if the volume is available on Podman.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
it { should exist }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Test if a volume exists on Podman and verifies volume properties
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
describe podman_volume("my_volume") do
|
||||||
|
it { should exist }
|
||||||
|
its("name") { should eq "my_volume" }
|
||||||
|
its("driver") { should eq "local" }
|
||||||
|
its("mountpoint") { should eq "/var/home/core/.local/share/containers/storage/volumes/my_volume/_data" }
|
||||||
|
its("created_at") { should eq "2022-07-14T13:21:19.965421792+05:30" }
|
||||||
|
its("labels") { should eq({}) }
|
||||||
|
its("scope") { should eq "local" }
|
||||||
|
its("options") { should eq({}) }
|
||||||
|
its("mount_count") { should eq 0 }
|
||||||
|
its("needs_copy_up") { should eq true }
|
||||||
|
its("needs_chown") { should eq true }
|
||||||
|
end
|
||||||
|
```
|
|
@ -42,7 +42,7 @@ When using `postfix_conf` with a custom configuration directory, the following s
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
- `'path'` is the path to your Postfix configuration (ex. '/etc/my/postfix/path/main.cf')
|
- `'path'` is the path to your Postfix configuration (ex. '/etc/path/to/postfix/main.cf')
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ where
|
||||||
|
|
||||||
The following examples show how to use this Chef InSpec resource.
|
The following examples show how to use this Chef InSpec resource.
|
||||||
|
|
||||||
### Verify that the Admnistrator user has a SID
|
### Verify that the Administrator user has a SID
|
||||||
|
|
||||||
describe security_identifier(user: 'Administrator') do
|
describe security_identifier(user: 'Administrator') do
|
||||||
it { should exist }
|
it { should exist }
|
||||||
|
|
|
@ -26,7 +26,7 @@ The format for `/etc/shadow` includes:
|
||||||
|
|
||||||
These entries are defined as a colon-delimited row in the file, one row per user:
|
These entries are defined as a colon-delimited row in the file, one row per user:
|
||||||
|
|
||||||
dannos:Gb7crrO5CDF.:10063:0:99999:7:::
|
username:Gb7crrO5CDF.:10063:0:99999:7:::
|
||||||
|
|
||||||
The `shadow` resource understands this format, allows you to search on the fields, and exposes the selected users' properties.
|
The `shadow` resource understands this format, allows you to search on the fields, and exposes the selected users' properties.
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ The `badpasswordattempts` property tests the count of bad password attempts for
|
||||||
|
|
||||||
where `0` is the count of bad passwords for a user.
|
where `0` is the count of bad passwords for a user.
|
||||||
On Linux based operating systems it relies on `lastb` and for Windows it uses information stored for the user object.
|
On Linux based operating systems it relies on `lastb` and for Windows it uses information stored for the user object.
|
||||||
These settings will be resetted to `0` depending on your operating system configuration.
|
These settings will reset to `0` depending on your operating system configuration.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ This helper returns, if any of the supported virtualization platforms was detect
|
||||||
|
|
||||||
### virtualization.physical_system? Helper
|
### virtualization.physical_system? Helper
|
||||||
|
|
||||||
If no virtualization platform is detected, this will return `true`. For unsupported virtualization platforms this can result in false posititves.
|
If no virtualization platform is detected, this will return `true`. For unsupported virtualization platforms this can result in false positives.
|
||||||
|
|
||||||
### virtualization.system names
|
### virtualization.system names
|
||||||
|
|
||||||
|
|
|
@ -70,9 +70,9 @@ The following examples show how to use this Chef InSpec resource.
|
||||||
it { should exist }
|
it { should exist }
|
||||||
end
|
end
|
||||||
|
|
||||||
## Gathering Tasknames
|
## Gathering Task Names
|
||||||
|
|
||||||
Rather then use the GUI you can use the `schtasks.exe` to output a full list of tasks available on the system
|
Rather than use the GUI, you can use the `schtasks.exe` to output a full list of tasks available on the system
|
||||||
|
|
||||||
`schtasks /query /FO list`
|
`schtasks /query /FO list`
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,13 @@ This resource is available from InSpec version 1.18.
|
||||||
|
|
||||||
An `x509_certificate` resource block declares a certificate `key file` to be tested.
|
An `x509_certificate` resource block declares a certificate `key file` to be tested.
|
||||||
|
|
||||||
describe x509_certificate('mycertificate.pem') do
|
describe x509_certificate('certificate.pem') do
|
||||||
its('validity_in_days') { should be > 30 }
|
its('validity_in_days') { should be > 30 }
|
||||||
end
|
end
|
||||||
|
|
||||||
The `filepath` property can also be used.
|
The `filepath` property can also be used.
|
||||||
|
|
||||||
describe x509_certificate(filepath: 'mycertificate.pem') do
|
describe x509_certificate(filepath: 'certificate.pem') do
|
||||||
its('validity_in_days') { should be > 30 }
|
its('validity_in_days') { should be > 30 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -55,8 +55,8 @@ The `content` value is used if the `content` and `filepath` are specified.
|
||||||
|
|
||||||
The `subject` (string) property accesses the individual subject elements.
|
The `subject` (string) property accesses the individual subject elements.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('subject.CN') { should eq "www.mywebsite.com" }
|
its('subject.CN') { should eq "www.example.com" }
|
||||||
end
|
end
|
||||||
|
|
||||||
### subject_dn
|
### subject_dn
|
||||||
|
@ -65,15 +65,15 @@ The `subject_dn` (string) property returns the distinguished name of the subject
|
||||||
|
|
||||||
For example, `/C=US/L=Seattle/O=Chef Software Inc/OU=Chefs/CN=Richard Nixon`
|
For example, `/C=US/L=Seattle/O=Chef Software Inc/OU=Chefs/CN=Richard Nixon`
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('subject_dn') { should match "CN=www.mywebsite.com" }
|
its('subject_dn') { should match "CN=www.example.com" }
|
||||||
end
|
end
|
||||||
|
|
||||||
### issuer.XX
|
### issuer.XX
|
||||||
|
|
||||||
The `issuer` (string) property accesses the individual issuer elements.
|
The `issuer` (string) property accesses the individual issuer elements.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('issuer.CN') { should eq "Acme Trust CA" }
|
its('issuer.CN') { should eq "Acme Trust CA" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ During the certificate signing process, the `issuer_dn` (string) property is the
|
||||||
|
|
||||||
For example, `/C=US/L=Seattle/CN=Acme Trust CA/emailAddress=support@acmetrust.org`
|
For example, `/C=US/L=Seattle/CN=Acme Trust CA/emailAddress=support@acmetrust.org`
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('issuer_cn') { should match "CN=NAME CA" }
|
its('issuer_cn') { should match "CN=NAME CA" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ For example, `/C=US/L=Seattle/CN=Acme Trust CA/emailAddress=support@acmetrust.or
|
||||||
|
|
||||||
The `public_key` (string) property returns a base64 encoded public key in PEM format.
|
The `public_key` (string) property returns a base64 encoded public key in PEM format.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('public_key') { should match "-----BEGIN PUBLIC KEY-----\nblah blah blah..." }
|
its('public_key') { should match "-----BEGIN PUBLIC KEY-----\nblah blah blah..." }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ The `public_key` (string) property returns a base64 encoded public key in PEM fo
|
||||||
|
|
||||||
The `key_length` (integer) property calculates the number of bits in the public key. If the length of bits in the public key increases, the public keys are secure. However, at the cost of speed and compatibility.
|
The `key_length` (integer) property calculates the number of bits in the public key. If the length of bits in the public key increases, the public keys are secure. However, at the cost of speed and compatibility.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('key_length') { should be 2048 }
|
its('key_length') { should be 2048 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ The `key_length` (integer) property calculates the number of bits in the public
|
||||||
|
|
||||||
The `keylength` (integer) property is an alias of the `key_length` property.
|
The `keylength` (integer) property is an alias of the `key_length` property.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('keylength') { should be 2048 }
|
its('keylength') { should be 2048 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ The `keylength` (integer) property is an alias of the `key_length` property.
|
||||||
|
|
||||||
The `signature_algorithm` (string) property describes the CA's hash function to sign the certificate.
|
The `signature_algorithm` (string) property describes the CA's hash function to sign the certificate.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('signature_algorithm') { should be 'sha256WithRSAEncryption' }
|
its('signature_algorithm') { should be 'sha256WithRSAEncryption' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ The `signature_algorithm` (string) property describes the CA's hash function to
|
||||||
|
|
||||||
The `validity_in_days` (float) property is used to check the validity of the certificates.
|
The `validity_in_days` (float) property is used to check the validity of the certificates.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('validity_in_days') { should be > 30 }
|
its('validity_in_days') { should be > 30 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ The `validity_in_days` (float) property is used to check the validity of the cer
|
||||||
|
|
||||||
The `not_before` and `not_after` (time) properties expose the start and end dates of certificate validity. These dates are exposed as Ruby **Time** class and perform date calculations.
|
The `not_before` and `not_after` (time) properties expose the start and end dates of certificate validity. These dates are exposed as Ruby **Time** class and perform date calculations.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('not_before') { should be <= Time.utc.now }
|
its('not_before') { should be <= Time.utc.now }
|
||||||
its('not_after') { should be >= Time.utc.now }
|
its('not_after') { should be >= Time.utc.now }
|
||||||
end
|
end
|
||||||
|
@ -140,7 +140,7 @@ The `not_before` and `not_after` (time) properties expose the start and end date
|
||||||
|
|
||||||
The `serial` (integer) property exposes the certificate's serial number. The CA sets the serial number during the signing process and should be unique within that CA.
|
The `serial` (integer) property exposes the certificate's serial number. The CA sets the serial number during the signing process and should be unique within that CA.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('serial') { should eq 9623283588743302433 }
|
its('serial') { should eq 9623283588743302433 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ The `serial` (integer) property exposes the certificate's serial number. The CA
|
||||||
|
|
||||||
The `version` (integer) property exposes the certificate version.
|
The `version` (integer) property exposes the certificate version.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('version') { should eq 2 }
|
its('version') { should eq 2 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ The `version` (integer) property exposes the certificate version.
|
||||||
|
|
||||||
The `extensions` (hash) property is mainly used to determine the purpose of the certificate.
|
The `extensions` (hash) property is mainly used to determine the purpose of the certificate.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
# Check what extension categories we have
|
# Check what extension categories we have
|
||||||
its('extensions') { should include 'keyUsage' }
|
its('extensions') { should include 'keyUsage' }
|
||||||
its('extensions') { should include 'extendedKeyUsage' }
|
its('extensions') { should include 'extendedKeyUsage' }
|
||||||
|
@ -179,16 +179,16 @@ The `extensions` (hash) property is mainly used to determine the purpose of the
|
||||||
|
|
||||||
The `email` (string) property checks for the email address of the certificate. This is equivalent to invoking the property `subject.emailAddress`.
|
The `email` (string) property checks for the email address of the certificate. This is equivalent to invoking the property `subject.emailAddress`.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('email') { should_not be_empty }
|
its('email') { should_not be_empty }
|
||||||
its('email') { should eq 'admin@mywebsite.com' }
|
its('email') { should eq 'admin@example.com' }
|
||||||
end
|
end
|
||||||
|
|
||||||
### subject_alt_names
|
### subject_alt_names
|
||||||
|
|
||||||
The `subject_alt_names` (string) property checks for the subject alternative names (additional host names) of the certificate.
|
The `subject_alt_names` (string) property checks for the subject alternative names (additional host names) of the certificate.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
its('subject_alt_names') { should include 'DNS:example.com' }
|
its('subject_alt_names') { should include 'DNS:example.com' }
|
||||||
its('subject_alt_names') { should include 'DNS:www.example.com' }
|
its('subject_alt_names') { should include 'DNS:www.example.com' }
|
||||||
end
|
end
|
||||||
|
@ -203,7 +203,7 @@ The specific matchers of this resource are: `be_valid`, `be_certificate` and `ha
|
||||||
|
|
||||||
The `be_valid` matcher tests if the specified certificate is valid.
|
The `be_valid` matcher tests if the specified certificate is valid.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
it { should be_valid }
|
it { should be_valid }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ The `be_valid` matcher tests if the specified certificate is valid.
|
||||||
|
|
||||||
The `be_certificate` matcher tests if the specified content or file is a certificate.
|
The `be_certificate` matcher tests if the specified content or file is a certificate.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
it { should be_certificate }
|
it { should be_certificate }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ The `be_certificate` matcher tests if the specified content or file is a certifi
|
||||||
|
|
||||||
The `have_purpose` matcher tests if the certificate meets the specified purpose.
|
The `have_purpose` matcher tests if the certificate meets the specified purpose.
|
||||||
|
|
||||||
describe x509_certificate('/etc/pki/www.mywebsite.com.pem') do
|
describe x509_certificate('/etc/pki/www.example.com.pem') do
|
||||||
it { should have_purpose('SSL client CA : Yes') }
|
it { should have_purpose('SSL client CA : Yes') }
|
||||||
it { should have_purpose('SSL server CA : Yes') }
|
it { should have_purpose('SSL server CA : Yes') }
|
||||||
end
|
end
|
||||||
|
|
|
@ -112,12 +112,12 @@ $ inspec shell
|
||||||
Welcome to the interactive InSpec Shell
|
Welcome to the interactive InSpec Shell
|
||||||
To find out how to use it, type: help
|
To find out how to use it, type: help
|
||||||
|
|
||||||
inspec> file('/Users/myuser').directory?
|
inspec> file('/Users/username').directory?
|
||||||
=> true
|
=> true
|
||||||
inspec> os_env('HOME')
|
inspec> os_env('HOME')
|
||||||
=> Environment variable HOME
|
=> Environment variable HOME
|
||||||
inspec> os_env('HOME').content
|
inspec> os_env('HOME').content
|
||||||
=> /Users/myuser
|
=> /Users/username
|
||||||
inspec> exit
|
inspec> exit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -141,10 +141,10 @@ replaced with the redefinition and the control is re-run.
|
||||||
```bash
|
```bash
|
||||||
inspec> control 'my_control' do
|
inspec> control 'my_control' do
|
||||||
inspec> describe os_env('HOME') do
|
inspec> describe os_env('HOME') do
|
||||||
inspec> its('content') { should eq '/Users/myuser' }
|
inspec> its('content') { should eq '/Users/username' }
|
||||||
inspec> end
|
inspec> end
|
||||||
inspec> end
|
inspec> end
|
||||||
✔ my_control: Environment variable HOME content should eq "/Users/myuser"
|
✔ my_control: Environment variable HOME content should eq "/Users/username"
|
||||||
|
|
||||||
Summary: 1 successful, 0 failures, 0 skipped
|
Summary: 1 successful, 0 failures, 0 skipped
|
||||||
```
|
```
|
||||||
|
@ -173,10 +173,10 @@ If you wish to run a single Chef InSpec command and fetch its results, you
|
||||||
may use the `-c` flag. This is similar to using `bash -c`.
|
may use the `-c` flag. This is similar to using `bash -c`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ inspec shell -c 'describe file("/Users/myuser") do it { should exist } end'
|
$ inspec shell -c 'describe file("/Users/username") do it { should exist } end'
|
||||||
Target: local://
|
Target: local://
|
||||||
|
|
||||||
✔ File /Users/myuser should exist
|
✔ File /Users/username should exist
|
||||||
|
|
||||||
Summary: 1 successful, 0 failures, 0 skipped
|
Summary: 1 successful, 0 failures, 0 skipped
|
||||||
```
|
```
|
||||||
|
|
|
@ -12,8 +12,7 @@ gh_repo = "inspec"
|
||||||
+++
|
+++
|
||||||
|
|
||||||
Waivers is a mechanism to mark controls as "waived" for various reasons, and to
|
Waivers is a mechanism to mark controls as "waived" for various reasons, and to
|
||||||
control the running and/or reporting of those controls. It uses a YAML input file
|
control the running and/or reporting of those controls. A waiver file identifies:
|
||||||
that identifies:
|
|
||||||
|
|
||||||
1. which controls are waived
|
1. which controls are waived
|
||||||
1. a description of why it is waived
|
1. a description of why it is waived
|
||||||
|
@ -31,7 +30,7 @@ inspec exec path/to/profile --waiver-file waivers.yaml
|
||||||
|
|
||||||
## File Format
|
## File Format
|
||||||
|
|
||||||
Waiver files are [input files](/inspec/inputs/) with a specific format:
|
Waiver files support YAML, JSON, CSV, XLSX & XLS format.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
control_id:
|
control_id:
|
||||||
|
@ -40,6 +39,18 @@ control_id:
|
||||||
justification: "reason for waiving this control"
|
justification: "reason for waiving this control"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
OR
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"control_id": {
|
||||||
|
"expiration_date": "YYYY-MM-DD",
|
||||||
|
"run": false,
|
||||||
|
"justification": "reason for waiving this control"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- `expiration_date` sets the day that the waiver file will expire in YYYY-MM-DD format. Waiver files expire at 00:00 at the local time of the system on the specified date. Waiver files without an expiration date are permanent. `expiration_date` is optional.
|
- `expiration_date` sets the day that the waiver file will expire in YYYY-MM-DD format. Waiver files expire at 00:00 at the local time of the system on the specified date. Waiver files without an expiration date are permanent. `expiration_date` is optional.
|
||||||
- `run` is optional. If absent or true, the control will run and be
|
- `run` is optional. If absent or true, the control will run and be
|
||||||
reported, but failures in it won't make the overall run fail. If present and false, the control will not be run. You may use any of yes, no, true or false. To avoid confusion, it is good practice to explicitly specify whether the control should run.
|
reported, but failures in it won't make the overall run fail. If present and false, the control will not be run. You may use any of yes, no, true or false. To avoid confusion, it is good practice to explicitly specify whether the control should run.
|
||||||
|
@ -48,6 +59,8 @@ control_id:
|
||||||
|
|
||||||
### Examples:
|
### Examples:
|
||||||
|
|
||||||
|
Example in YAML:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
waiver_control_1_2_3:
|
waiver_control_1_2_3:
|
||||||
expiration_date: 2019-10-15
|
expiration_date: 2019-10-15
|
||||||
|
@ -58,3 +71,34 @@ xccdf_org.cisecurity.benchmarks_rule_1.1.1.4_Ensure_mounting_of_hfs_filesystems_
|
||||||
justification: "This might be a bug in the test. @qateam"
|
justification: "This might be a bug in the test. @qateam"
|
||||||
run: false
|
run: false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Example in JSON:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"waiver_control_1_2_3": {
|
||||||
|
"expiration_date": "2019-10-15T00:00:00.000Z",
|
||||||
|
"justification": "Not needed until Q3. @secteam"
|
||||||
|
},
|
||||||
|
"xccdf_org.cisecurity.benchmarks_rule_1.1.1.4_Ensure_mounting_of_hfs_filesystems_is_disabled": {
|
||||||
|
"expiration_date": "2020-03-01T00:00:00.000Z",
|
||||||
|
"justification": "This might be a bug in the test. @qateam",
|
||||||
|
"run": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example in CSV/XLSX/XLS:
|
||||||
|
|
||||||
|
These file formats support the following fields in a file:
|
||||||
|
|
||||||
|
* `control_id`
|
||||||
|
_Required_.
|
||||||
|
* `justification`
|
||||||
|
_Required_.
|
||||||
|
* `run`
|
||||||
|
_Optional_.
|
||||||
|
* `expiration_date`
|
||||||
|
_Optional_.
|
||||||
|
|
||||||
|
![Waiver File Excel Example](/images/inspec/waivers_file_excel.png)
|
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
BIN
docs-chef-io/static/images/inspec/waivers_file_excel.png
Normal file
BIN
docs-chef-io/static/images/inspec/waivers_file_excel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -34,6 +34,10 @@ Gem::Specification.new do |spec|
|
||||||
# progress bar streaming reporter plugin support
|
# progress bar streaming reporter plugin support
|
||||||
spec.add_dependency "progress_bar", "~> 1.3.3"
|
spec.add_dependency "progress_bar", "~> 1.3.3"
|
||||||
|
|
||||||
|
# roo support for reading excel waiver files
|
||||||
|
spec.add_dependency "roo", "~> 2.9.0"
|
||||||
|
spec.add_dependency "roo-xls" # extension for roo to read xls files
|
||||||
|
|
||||||
# Used for Azure profile until integrated into train
|
# Used for Azure profile until integrated into train
|
||||||
spec.add_dependency "faraday_middleware", ">= 0.12.2", "< 1.1"
|
spec.add_dependency "faraday_middleware", ">= 0.12.2", "< 1.1"
|
||||||
|
|
||||||
|
|
|
@ -205,6 +205,8 @@ module Inspec
|
||||||
long_desc: "Maximum seconds to allow commands to run during execution. A timed out command is considered an error."
|
long_desc: "Maximum seconds to allow commands to run during execution. A timed out command is considered an error."
|
||||||
option :reporter_include_source, type: :boolean, default: false,
|
option :reporter_include_source, type: :boolean, default: false,
|
||||||
desc: "Include full source code of controls in the CLI report"
|
desc: "Include full source code of controls in the CLI report"
|
||||||
|
option :enhanced_outcomes, type: :boolean,
|
||||||
|
desc: "Show enhanced outcomes in output"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.help(*args)
|
def self.help(*args)
|
||||||
|
|
|
@ -415,6 +415,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
||||||
desc: "Load one or more input files, a YAML file with values for the shell to use"
|
desc: "Load one or more input files, a YAML file with values for the shell to use"
|
||||||
option :input, type: :array, banner: "name1=value1 name2=value2",
|
option :input, type: :array, banner: "name1=value1 name2=value2",
|
||||||
desc: "Specify one or more inputs directly on the command line to the shell, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures."
|
desc: "Specify one or more inputs directly on the command line to the shell, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures."
|
||||||
|
option :enhanced_outcomes, type: :boolean,
|
||||||
|
desc: "Show enhanced outcomes in output"
|
||||||
def shell_func
|
def shell_func
|
||||||
o = config
|
o = config
|
||||||
deprecate_target_id(config)
|
deprecate_target_id(config)
|
||||||
|
@ -461,11 +463,13 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
||||||
pretty_handle_exception(e)
|
pretty_handle_exception(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
option :enhanced_outcomes, type: :boolean,
|
||||||
|
desc: "Show enhanced outcomes output"
|
||||||
desc "schema NAME", "print the JSON schema", hide: true
|
desc "schema NAME", "print the JSON schema", hide: true
|
||||||
def schema(name)
|
def schema(name)
|
||||||
require "inspec/schema/output_schema"
|
require "inspec/schema/output_schema"
|
||||||
|
o = config
|
||||||
puts Inspec::Schema::OutputSchema.json(name)
|
puts Inspec::Schema::OutputSchema.json(name, o)
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
puts e
|
puts e
|
||||||
puts "Valid schemas are #{Inspec::Schema::OutputSchema.names.join(", ")}"
|
puts "Valid schemas are #{Inspec::Schema::OutputSchema.names.join(", ")}"
|
||||||
|
|
18
lib/inspec/enhanced_outcomes.rb
Normal file
18
lib/inspec/enhanced_outcomes.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
module Inspec
|
||||||
|
module EnhancedOutcomes
|
||||||
|
|
||||||
|
def self.determine_status(results, impact)
|
||||||
|
if results.any? { |r| !r[:exception].nil? && !r[:backtrace].nil? }
|
||||||
|
"error"
|
||||||
|
elsif !impact.nil? && impact.to_f == 0.0
|
||||||
|
"not_applicable"
|
||||||
|
elsif results.all? { |r| r[:status] == "skipped" }
|
||||||
|
"not_reviewed"
|
||||||
|
elsif results.any? { |r| r[:status] == "failed" }
|
||||||
|
"failed"
|
||||||
|
else
|
||||||
|
"passed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,5 +10,7 @@ module Inspec
|
||||||
class SecretsBackendNotFound < ArgumentError; end
|
class SecretsBackendNotFound < ArgumentError; end
|
||||||
class ProfileValidationKeyNotFound < ArgumentError; end
|
class ProfileValidationKeyNotFound < ArgumentError; end
|
||||||
class ProfileSigningKeyNotFound < ArgumentError; end
|
class ProfileSigningKeyNotFound < ArgumentError; end
|
||||||
|
class WaiversFileNotReadable < ArgumentError; end
|
||||||
|
class WaiversFileDoesNotExist < ArgumentError; end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
require "rspec/core"
|
require "rspec/core"
|
||||||
require "rspec/core/formatters/base_formatter"
|
require "rspec/core/formatters/base_formatter"
|
||||||
require "set" unless defined?(Set)
|
require "set" unless defined?(Set)
|
||||||
|
require "inspec/enhanced_outcomes"
|
||||||
|
|
||||||
module Inspec::Formatters
|
module Inspec::Formatters
|
||||||
class Base < RSpec::Core::Formatters::BaseFormatter
|
class Base < RSpec::Core::Formatters::BaseFormatter
|
||||||
RSpec::Core::Formatters.register self, :close, :dump_summary, :stop
|
RSpec::Core::Formatters.register self, :close, :dump_summary, :stop
|
||||||
|
|
||||||
attr_accessor :backend, :run_data
|
attr_accessor :backend, :run_data, :enhanced_outcomes
|
||||||
|
|
||||||
def initialize(output)
|
def initialize(output)
|
||||||
super(output)
|
super(output)
|
||||||
|
@ -17,6 +18,7 @@ module Inspec::Formatters
|
||||||
@backend = nil
|
@backend = nil
|
||||||
@all_controls_count = nil
|
@all_controls_count = nil
|
||||||
@control_checks_count_map = {}
|
@control_checks_count_map = {}
|
||||||
|
@enhanced_outcomes = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# RSpec Override: #dump_summary
|
# RSpec Override: #dump_summary
|
||||||
|
@ -50,7 +52,6 @@ module Inspec::Formatters
|
||||||
else
|
else
|
||||||
hash[:message] = exception_message(e)
|
hash[:message] = exception_message(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
next if e.is_a? RSpec::Expectations::ExpectationNotMetError
|
next if e.is_a? RSpec::Expectations::ExpectationNotMetError
|
||||||
|
|
||||||
hash[:exception] = e.class.name
|
hash[:exception] = e.class.name
|
||||||
|
@ -68,6 +69,8 @@ module Inspec::Formatters
|
||||||
# flesh out the profiles key with additional profile information
|
# flesh out the profiles key with additional profile information
|
||||||
run_data[:profiles] = profiles_info
|
run_data[:profiles] = profiles_info
|
||||||
|
|
||||||
|
add_enhanced_outcomes_to_controls if enhanced_outcomes
|
||||||
|
|
||||||
# add the platform information for this particular target
|
# add the platform information for this particular target
|
||||||
run_data[:platform] = {
|
run_data[:platform] = {
|
||||||
name: platform(:name),
|
name: platform(:name),
|
||||||
|
@ -110,6 +113,20 @@ module Inspec::Formatters
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def add_enhanced_outcomes_to_controls
|
||||||
|
all_unique_controls.each do |control|
|
||||||
|
control[:status] = determine_control_enhanced_outcome(control)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def determine_control_enhanced_outcome(control)
|
||||||
|
if control[:results]
|
||||||
|
Inspec::EnhancedOutcomes.determine_status(control[:results], control[:impact])
|
||||||
|
else
|
||||||
|
"passed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def all_unique_controls
|
def all_unique_controls
|
||||||
unique_controls = Set.new
|
unique_controls = Set.new
|
||||||
run_data[:profiles].each do |profile|
|
run_data[:profiles].each do |profile|
|
||||||
|
@ -120,10 +137,45 @@ module Inspec::Formatters
|
||||||
end
|
end
|
||||||
|
|
||||||
def statistics
|
def statistics
|
||||||
|
error = 0
|
||||||
|
not_applicable = 0
|
||||||
|
not_reviewed = 0
|
||||||
failed = 0
|
failed = 0
|
||||||
skipped = 0
|
|
||||||
passed = 0
|
passed = 0
|
||||||
|
skipped = 0
|
||||||
|
enhanced_outcomes_summary = {}
|
||||||
|
if enhanced_outcomes
|
||||||
|
all_unique_controls.each do |control|
|
||||||
|
|
||||||
|
if control[:status] == "error"
|
||||||
|
error += 1
|
||||||
|
elsif control[:status] == "not_applicable"
|
||||||
|
not_applicable += 1
|
||||||
|
elsif control[:status] == "not_reviewed"
|
||||||
|
not_reviewed += 1
|
||||||
|
elsif control[:status] == "failed"
|
||||||
|
failed += 1
|
||||||
|
elsif control[:status] == "passed"
|
||||||
|
passed += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
# added this additionally because stats summary is also used for determining exit code in runner rspec
|
||||||
|
skipped += 1 if control[:results].any? { |r| r[:status] == "skipped" }
|
||||||
|
|
||||||
|
end
|
||||||
|
total = error + not_applicable + not_reviewed + failed + passed
|
||||||
|
enhanced_outcomes_summary = {
|
||||||
|
not_applicable: {
|
||||||
|
total: not_applicable,
|
||||||
|
},
|
||||||
|
not_reviewed: {
|
||||||
|
total: not_reviewed,
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
total: error,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
else
|
||||||
all_unique_controls.each do |control|
|
all_unique_controls.each do |control|
|
||||||
next unless control[:results]
|
next unless control[:results]
|
||||||
|
|
||||||
|
@ -135,10 +187,9 @@ module Inspec::Formatters
|
||||||
passed += 1
|
passed += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
total = failed + passed + skipped
|
total = failed + passed + skipped
|
||||||
|
end
|
||||||
{
|
final_summary = {
|
||||||
total: total,
|
total: total,
|
||||||
passed: {
|
passed: {
|
||||||
total: passed,
|
total: passed,
|
||||||
|
@ -150,6 +201,8 @@ module Inspec::Formatters
|
||||||
total: failed,
|
total: failed,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final_summary.merge!(enhanced_outcomes_summary)
|
||||||
end
|
end
|
||||||
|
|
||||||
def exception_message(exception)
|
def exception_message(exception)
|
||||||
|
|
|
@ -7,6 +7,7 @@ module Inspec::Plugin::V2::PluginType
|
||||||
include Inspec::Utils::RunDataFilters
|
include Inspec::Utils::RunDataFilters
|
||||||
|
|
||||||
attr_reader :run_data
|
attr_reader :run_data
|
||||||
|
attr_accessor :enhanced_outcomes
|
||||||
|
|
||||||
def initialize(config)
|
def initialize(config)
|
||||||
@config = config
|
@config = config
|
||||||
|
|
|
@ -11,6 +11,7 @@ module Inspec::Plugin::V2::PluginType
|
||||||
@running_controls_list = []
|
@running_controls_list = []
|
||||||
@control_checks_count_map = {}
|
@control_checks_count_map = {}
|
||||||
@controls_count = nil
|
@controls_count = nil
|
||||||
|
@notifications = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -49,5 +50,58 @@ module Inspec::Plugin::V2::PluginType
|
||||||
@control_checks_count_map = RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.get_control_checks_count_map
|
@control_checks_count_map = RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.get_control_checks_count_map
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def enhanced_outcomes
|
||||||
|
@enhanced_outcomes ||= RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.enhanced_outcomes
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_enhanced_outcomes(control_id)
|
||||||
|
if control_has_error(@notifications[control_id])
|
||||||
|
"error"
|
||||||
|
elsif control_has_impact_zero(@notifications[control_id])
|
||||||
|
"not_applicable"
|
||||||
|
elsif control_has_all_tests_skipped(@notifications[control_id])
|
||||||
|
"not_reviewed"
|
||||||
|
elsif control_has_any_tests_failed(@notifications[control_id])
|
||||||
|
"failed"
|
||||||
|
else
|
||||||
|
"passed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def control_has_error(notifications)
|
||||||
|
notifications.any? do |notification_data|
|
||||||
|
notification, _status = notification_data
|
||||||
|
!notification.example.exception.nil? && !(notification.example.exception.is_a? RSpec::Expectations::ExpectationNotMetError) && !notification.example.exception.backtrace.nil?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def control_has_all_tests_skipped(notifications)
|
||||||
|
notifications.all? do |notification_data|
|
||||||
|
_notification, status = notification_data
|
||||||
|
status == "skipped"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def control_has_any_tests_failed(notifications)
|
||||||
|
notifications.any? do |notification_data|
|
||||||
|
_notification, status = notification_data
|
||||||
|
status == "failed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def control_has_impact_zero(notifications)
|
||||||
|
notification_data = notifications.first
|
||||||
|
notification_impact = notification_data.first.example.metadata[:impact]
|
||||||
|
notification_data && !notification_impact.nil? && notification_impact.to_f == 0.0
|
||||||
|
end
|
||||||
|
|
||||||
|
def collect_notifications(notification, control_id, status)
|
||||||
|
if @notifications[control_id].nil?
|
||||||
|
@notifications[control_id] = [[notification, status]]
|
||||||
|
else
|
||||||
|
@notifications[control_id].push([notification, status])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -350,22 +350,24 @@ module Inspec
|
||||||
def load_libraries
|
def load_libraries
|
||||||
return @runner_context if @libraries_loaded
|
return @runner_context if @libraries_loaded
|
||||||
|
|
||||||
locked_dependencies.dep_list.each_with_index do |(_name, dep), i|
|
locked_dependencies.dep_list.each_with_index do |(_name, dep), index|
|
||||||
d = dep.profile
|
d = dep.profile
|
||||||
# this will force a dependent profile load so we are only going to add
|
# this will force a dependent profile load so we are only going to add
|
||||||
# this metadata if the parent profile is supported.
|
# this metadata if the parent profile is supported.
|
||||||
if @supports_platform && !d.supports_platform?
|
if @supports_platform && !d.supports_platform?
|
||||||
# since ruby 1.9 hashes are ordered so we can just use index values here
|
# since ruby 1.9 hashes are ordered so we can just use index values here
|
||||||
# TODO: NO! this is a violation of encapsulation to an extreme
|
# TODO: NO! this is a violation of encapsulation to an extreme
|
||||||
metadata.dependencies[i][:status] = "skipped"
|
if metadata.dependencies[index]
|
||||||
|
metadata.dependencies[index][:status] = "skipped"
|
||||||
msg = "Skipping profile: '#{d.name}' on unsupported platform: '#{d.backend.platform.name}/#{d.backend.platform.release}'."
|
msg = "Skipping profile: '#{d.name}' on unsupported platform: '#{d.backend.platform.name}/#{d.backend.platform.release}'."
|
||||||
metadata.dependencies[i][:status_message] = msg
|
metadata.dependencies[index][:status_message] = msg
|
||||||
metadata.dependencies[i][:skip_message] = msg # Repeat as skip_message for backward compatibility
|
metadata.dependencies[index][:skip_message] = msg # Repeat as skip_message for backward compatibility
|
||||||
|
end
|
||||||
next
|
next
|
||||||
elsif metadata.dependencies[i]
|
elsif metadata.dependencies[index]
|
||||||
# Currently wrapper profiles will load all dependencies, and then we
|
# Currently wrapper profiles will load all dependencies, and then we
|
||||||
# load them again when we dive down. This needs to be re-done.
|
# load them again when we dive down. This needs to be re-done.
|
||||||
metadata.dependencies[i][:status] = "loaded"
|
metadata.dependencies[index][:status] = "loaded"
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Layout/ExtraSpacing
|
# rubocop:disable Layout/ExtraSpacing
|
||||||
|
|
|
@ -7,7 +7,7 @@ require "inspec/reporters/yaml"
|
||||||
|
|
||||||
module Inspec::Reporters
|
module Inspec::Reporters
|
||||||
# rubocop:disable Metrics/CyclomaticComplexity
|
# rubocop:disable Metrics/CyclomaticComplexity
|
||||||
def self.render(reporter, run_data)
|
def self.render(reporter, run_data, enhanced_outcomes = false)
|
||||||
name, config = reporter.dup
|
name, config = reporter.dup
|
||||||
config[:run_data] = run_data
|
config[:run_data] = run_data
|
||||||
case name
|
case name
|
||||||
|
@ -29,6 +29,7 @@ module Inspec::Reporters
|
||||||
activator.activate!
|
activator.activate!
|
||||||
reporter = activator.implementation_class.new(config)
|
reporter = activator.implementation_class.new(config)
|
||||||
end
|
end
|
||||||
|
reporter.enhanced_outcomes = enhanced_outcomes
|
||||||
|
|
||||||
# optional send_report method on reporter
|
# optional send_report method on reporter
|
||||||
return reporter.send_report if defined?(reporter.send_report)
|
return reporter.send_report if defined?(reporter.send_report)
|
||||||
|
|
|
@ -5,6 +5,7 @@ module Inspec::Reporters
|
||||||
include Inspec::Utils::RunDataFilters
|
include Inspec::Utils::RunDataFilters
|
||||||
|
|
||||||
attr_reader :run_data
|
attr_reader :run_data
|
||||||
|
attr_accessor :enhanced_outcomes
|
||||||
|
|
||||||
def initialize(config)
|
def initialize(config)
|
||||||
@config = config
|
@config = config
|
||||||
|
|
|
@ -9,6 +9,9 @@ module Inspec::Reporters
|
||||||
"passed" => "\033[0;1;32m",
|
"passed" => "\033[0;1;32m",
|
||||||
"skipped" => "\033[0;37m",
|
"skipped" => "\033[0;37m",
|
||||||
"reset" => "\033[0m",
|
"reset" => "\033[0m",
|
||||||
|
"error" => "\033[34m",
|
||||||
|
"not_applicable" => "\033[36m",
|
||||||
|
"not_reviewed" => "\033[33m",
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# Most currently available Windows terminals have poor support
|
# Most currently available Windows terminals have poor support
|
||||||
|
@ -18,6 +21,9 @@ module Inspec::Reporters
|
||||||
"skipped" => "[SKIP]",
|
"skipped" => "[SKIP]",
|
||||||
"passed" => "[PASS]",
|
"passed" => "[PASS]",
|
||||||
"unknown" => "[UNKN]",
|
"unknown" => "[UNKN]",
|
||||||
|
"error" => "[ERR]",
|
||||||
|
"not_applicable" => "[N/A]",
|
||||||
|
"not_reviewed" => "[N/R]",
|
||||||
}.freeze
|
}.freeze
|
||||||
else
|
else
|
||||||
# Extended colors for everyone else
|
# Extended colors for everyone else
|
||||||
|
@ -26,6 +32,9 @@ module Inspec::Reporters
|
||||||
"passed" => "\033[38;5;41m",
|
"passed" => "\033[38;5;41m",
|
||||||
"skipped" => "\033[38;5;247m",
|
"skipped" => "\033[38;5;247m",
|
||||||
"reset" => "\033[0m",
|
"reset" => "\033[0m",
|
||||||
|
"error" => "\033[0;38;5;21m",
|
||||||
|
"not_applicable" => "\033[0;38;5;117m",
|
||||||
|
"not_reviewed" => "\033[0;38;5;214m",
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
# Groovy UTF-8 characters for everyone else...
|
# Groovy UTF-8 characters for everyone else...
|
||||||
|
@ -35,6 +44,9 @@ module Inspec::Reporters
|
||||||
"skipped" => "↺",
|
"skipped" => "↺",
|
||||||
"passed" => "✔",
|
"passed" => "✔",
|
||||||
"unknown" => "?",
|
"unknown" => "?",
|
||||||
|
"error" => "ERR",
|
||||||
|
"not_applicable" => "N/A",
|
||||||
|
"not_reviewed" => "N/R",
|
||||||
}.freeze
|
}.freeze
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,7 +75,11 @@ module Inspec::Reporters
|
||||||
end
|
end
|
||||||
|
|
||||||
output("")
|
output("")
|
||||||
|
if enhanced_outcomes
|
||||||
|
print_control_outcomes_summary
|
||||||
|
else
|
||||||
print_profile_summary
|
print_profile_summary
|
||||||
|
end
|
||||||
print_tests_summary
|
print_tests_summary
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -88,6 +104,7 @@ module Inspec::Reporters
|
||||||
def print_standard_control_results(profile)
|
def print_standard_control_results(profile)
|
||||||
standard_controls_from_profile(profile).each do |control_from_profile|
|
standard_controls_from_profile(profile).each do |control_from_profile|
|
||||||
control = Control.new(control_from_profile)
|
control = Control.new(control_from_profile)
|
||||||
|
control.enhanced_outcomes = enhanced_outcomes
|
||||||
next if control.results.nil?
|
next if control.results.nil?
|
||||||
|
|
||||||
output(format_control_header(control))
|
output(format_control_header(control))
|
||||||
|
@ -122,7 +139,7 @@ module Inspec::Reporters
|
||||||
end
|
end
|
||||||
|
|
||||||
def format_control_header(control)
|
def format_control_header(control)
|
||||||
impact = control.impact_string
|
impact = enhanced_outcomes ? control.impact_string_for_enhanced_outcomes : control.impact_string
|
||||||
format_message(
|
format_message(
|
||||||
color: impact,
|
color: impact,
|
||||||
indicator: impact,
|
indicator: impact,
|
||||||
|
@ -292,6 +309,68 @@ module Inspec::Reporters
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def control_outcomes_summary
|
||||||
|
failed = 0
|
||||||
|
passed = 0
|
||||||
|
error = 0
|
||||||
|
not_reviewed = 0
|
||||||
|
not_applicable = 0
|
||||||
|
|
||||||
|
all_unique_controls.each do |control|
|
||||||
|
next if control[:status].empty?
|
||||||
|
|
||||||
|
if control[:status] == "failed"
|
||||||
|
failed += 1
|
||||||
|
elsif control[:status] == "error"
|
||||||
|
error += 1
|
||||||
|
elsif control[:status] == "not_reviewed"
|
||||||
|
not_reviewed += 1
|
||||||
|
elsif control[:status] == "not_applicable"
|
||||||
|
not_applicable += 1
|
||||||
|
else
|
||||||
|
passed += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
total = failed + passed + error + not_reviewed + not_applicable
|
||||||
|
|
||||||
|
{
|
||||||
|
"total" => total,
|
||||||
|
"failed" => failed,
|
||||||
|
"passed" => passed,
|
||||||
|
"error" => error,
|
||||||
|
"not_reviewed" => not_reviewed,
|
||||||
|
"not_applicable" => not_applicable,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def print_control_outcomes_summary
|
||||||
|
summary = control_outcomes_summary
|
||||||
|
return unless summary["total"] > 0
|
||||||
|
|
||||||
|
success_str = summary["passed"] == 1 ? "1 successful control" : "#{summary["passed"]} successful controls"
|
||||||
|
failed_str = summary["failed"] == 1 ? "1 control failure" : "#{summary["failed"]} control failures"
|
||||||
|
error_str = summary["error"] == 1 ? "1 control has error" : "#{summary["error"]} controls have error"
|
||||||
|
not_rev_str = summary["not_reviewed"] == 1 ? "1 control not reviewed" : "#{summary["not_reviewed"]} controls not reviewed"
|
||||||
|
not_app_str = summary["not_applicable"] == 1 ? "1 control not applicable" : "#{summary["not_applicable"]} controls not applicable"
|
||||||
|
|
||||||
|
success_color = summary["passed"] > 0 ? "passed" : "no_color"
|
||||||
|
failed_color = summary["failed"] > 0 ? "failed" : "no_color"
|
||||||
|
error_color = summary["error"] > 0 ? "error" : "no_color"
|
||||||
|
not_rev_color = summary["not_reviewed"] > 0 ? "not_reviewed" : "no_color"
|
||||||
|
not_app_color = summary["not_applicable"] > 0 ? "not_applicable" : "no_color"
|
||||||
|
|
||||||
|
s = format(
|
||||||
|
"Profile Summary: %s, %s, %s, %s, %s",
|
||||||
|
format_with_color(success_color, success_str),
|
||||||
|
format_with_color(failed_color, failed_str),
|
||||||
|
format_with_color(not_rev_color, not_rev_str),
|
||||||
|
format_with_color(not_app_color, not_app_str),
|
||||||
|
format_with_color(error_color, error_str)
|
||||||
|
)
|
||||||
|
output(s) if summary["total"] > 0
|
||||||
|
end
|
||||||
|
|
||||||
def print_profile_summary
|
def print_profile_summary
|
||||||
summary = profile_summary
|
summary = profile_summary
|
||||||
return unless summary["total"] > 0
|
return unless summary["total"] > 0
|
||||||
|
@ -350,6 +429,7 @@ module Inspec::Reporters
|
||||||
|
|
||||||
class Control
|
class Control
|
||||||
attr_reader :data
|
attr_reader :data
|
||||||
|
attr_accessor :enhanced_outcomes
|
||||||
|
|
||||||
def initialize(control_hash)
|
def initialize(control_hash)
|
||||||
@data = control_hash
|
@data = control_hash
|
||||||
|
@ -379,6 +459,10 @@ module Inspec::Reporters
|
||||||
id.start_with?("(generated from ")
|
id.start_with?("(generated from ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
data[:status]
|
||||||
|
end
|
||||||
|
|
||||||
def title_for_report
|
def title_for_report
|
||||||
# if this is an anonymous control, just grab the resource title from any result entry
|
# if this is an anonymous control, just grab the resource title from any result entry
|
||||||
return results.first[:resource_title] if anonymous?
|
return results.first[:resource_title] if anonymous?
|
||||||
|
@ -392,10 +476,17 @@ module Inspec::Reporters
|
||||||
# append a failure summary if appropriate.
|
# append a failure summary if appropriate.
|
||||||
title_for_report += " (#{failure_count} failed)" if failure_count > 0
|
title_for_report += " (#{failure_count} failed)" if failure_count > 0
|
||||||
title_for_report += " (#{skipped_count} skipped)" if skipped_count > 0
|
title_for_report += " (#{skipped_count} skipped)" if skipped_count > 0
|
||||||
|
|
||||||
title_for_report
|
title_for_report
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def impact_string_for_enhanced_outcomes
|
||||||
|
if impact.nil?
|
||||||
|
"unknown"
|
||||||
|
else
|
||||||
|
status
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def impact_string
|
def impact_string
|
||||||
if anonymous?
|
if anonymous?
|
||||||
nil
|
nil
|
||||||
|
|
|
@ -114,7 +114,7 @@ module Inspec::Reporters
|
||||||
|
|
||||||
def profile_controls(profile)
|
def profile_controls(profile)
|
||||||
(profile[:controls] || []).map { |c|
|
(profile[:controls] || []).map { |c|
|
||||||
{
|
control_hash = {
|
||||||
id: c[:id],
|
id: c[:id],
|
||||||
title: c[:title],
|
title: c[:title],
|
||||||
desc: c.dig(:descriptions, :default),
|
desc: c.dig(:descriptions, :default),
|
||||||
|
@ -130,6 +130,8 @@ module Inspec::Reporters
|
||||||
waiver_data: c[:waiver_data] || {},
|
waiver_data: c[:waiver_data] || {},
|
||||||
results: profile_results(c),
|
results: profile_results(c),
|
||||||
}
|
}
|
||||||
|
control_hash.merge!({ status: c[:status] }) if enhanced_outcomes
|
||||||
|
control_hash
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@ require "yaml"
|
||||||
module Inspec::Reporters
|
module Inspec::Reporters
|
||||||
class Yaml < Base
|
class Yaml < Base
|
||||||
def render
|
def render
|
||||||
output(Inspec::Reporters::Json.new({ run_data: run_data }).report.to_yaml, false)
|
json_reporter_obj = Inspec::Reporters::Json.new({ run_data: run_data })
|
||||||
|
json_reporter_obj.enhanced_outcomes = enhanced_outcomes
|
||||||
|
output(json_reporter_obj.report.to_yaml, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def report
|
def report
|
||||||
|
|
353
lib/inspec/resources/podman.rb
Normal file
353
lib/inspec/resources/podman.rb
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
require "inspec/resources/command"
|
||||||
|
require "inspec/utils/filter"
|
||||||
|
require "hashie/mash"
|
||||||
|
|
||||||
|
module Inspec::Resources
|
||||||
|
class Podman < Inspec.resource(1)
|
||||||
|
# Resource requires an internal name.
|
||||||
|
name "podman"
|
||||||
|
|
||||||
|
# Restrict to only run on the below platforms (if none were given,
|
||||||
|
# all OS's and cloud API's supported)
|
||||||
|
supports platform: "unix"
|
||||||
|
|
||||||
|
desc "A resource to retrieve information about podman"
|
||||||
|
|
||||||
|
example <<~EXAMPLE
|
||||||
|
describe podman.containers do
|
||||||
|
its('images') { should include "docker.io/library/ubuntu:latest" }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman.images do
|
||||||
|
its('names') { should_not include "docker.io/library/ubuntu:latest" }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman.pods do
|
||||||
|
its("ids") { should include "95cadbb84df71e6374fceb3fd89ee3b8f2c7e1a831062cd9cea7d0e3e4b1dbcc" }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman.info.host do
|
||||||
|
its("os") { should eq "linux"}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman.version do
|
||||||
|
its("Client.Version") { should eq "4.1.0"}
|
||||||
|
end
|
||||||
|
|
||||||
|
podman.containers.ids.each do |id|
|
||||||
|
# call podman inspect for a specific container id
|
||||||
|
describe podman.object(id) do
|
||||||
|
its("State.OciVersion") { should eq "1.0.2-dev" }
|
||||||
|
its("State.Running") { should eq true}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EXAMPLE
|
||||||
|
|
||||||
|
def containers
|
||||||
|
PodmanContainerFilter.new(parse_containers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def images
|
||||||
|
PodmanImageFilter.new(parse_images)
|
||||||
|
end
|
||||||
|
|
||||||
|
def networks
|
||||||
|
PodmanNetworkFilter.new(parse_networks)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pods
|
||||||
|
PodmanPodFilter.new(parse_pods)
|
||||||
|
end
|
||||||
|
|
||||||
|
def volumes
|
||||||
|
PodmanVolumeFilter.new(parse_volumes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def version
|
||||||
|
return @version if defined?(@version)
|
||||||
|
|
||||||
|
sub_cmd = "version --format json"
|
||||||
|
output = run_command(sub_cmd)
|
||||||
|
@version = Hashie::Mash.new(JSON.parse(output))
|
||||||
|
rescue JSON::ParserError => _e
|
||||||
|
Hashie::Mash.new({})
|
||||||
|
end
|
||||||
|
|
||||||
|
def info
|
||||||
|
return @info if defined?(@info)
|
||||||
|
|
||||||
|
sub_cmd = "info --format json"
|
||||||
|
output = run_command(sub_cmd)
|
||||||
|
@info = Hashie::Mash.new(JSON.parse(output))
|
||||||
|
rescue JSON::ParserError => _e
|
||||||
|
Hashie::Mash.new({})
|
||||||
|
end
|
||||||
|
|
||||||
|
# returns information about podman objects
|
||||||
|
def object(id)
|
||||||
|
return @inspect if defined?(@inspect)
|
||||||
|
|
||||||
|
output = run_command("inspect #{id} --format json")
|
||||||
|
data = JSON.parse(output)
|
||||||
|
data = data[0] if data.is_a?(Array)
|
||||||
|
@inspect = Hashie::Mash.new(data)
|
||||||
|
rescue JSON::ParserError => _e
|
||||||
|
Hashie::Mash.new({})
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"Podman"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Calls the run_command method to get all podman containers and parse the command output.
|
||||||
|
# Returns the parsed command output.
|
||||||
|
def parse_containers
|
||||||
|
labels = %w{ID Image ImageID Command CreatedAt RunningFor Status Pod Ports Size Names Networks Labels Mounts}
|
||||||
|
parse_json_command(labels, "ps -a --no-trunc --size")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Calls the run_command method to get all podman images and parse the command output.
|
||||||
|
# Returns the parsed command output.
|
||||||
|
def parse_images
|
||||||
|
labels = %w{ID Repository Tag Size Digest CreatedAt CreatedSince History}
|
||||||
|
parse_json_command(labels, "images -a --no-trunc")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Calls the run_command method to get all podman network list and parse the command output.
|
||||||
|
# Returns the parsed command output.
|
||||||
|
def parse_networks
|
||||||
|
labels = %w{ID Name Driver Labels Options IPAMOptions Created Internal IPv6Enabled DNSEnabled NetworkInterface Subnets}
|
||||||
|
parse_json_command(labels, "network ls --no-trunc")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Calls the run_command method to get all podman pod list and parse the command output.
|
||||||
|
# Returns the parsed command output.
|
||||||
|
def parse_pods
|
||||||
|
sub_cmd = "pod ps --no-trunc --format json"
|
||||||
|
output = run_command(sub_cmd)
|
||||||
|
parse(output)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Calls the run_command method to get all podman volume list and parse the command output.
|
||||||
|
# Returns the parsed command output.
|
||||||
|
def parse_volumes
|
||||||
|
sub_cmd = "volume ls --format json"
|
||||||
|
output = run_command(sub_cmd)
|
||||||
|
parse(output)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Runs the given podman command on the host machine on which podman is installed
|
||||||
|
# Returns the command output or raises the command execution error.
|
||||||
|
def run_command(subcommand)
|
||||||
|
result = inspec.command("podman #{subcommand}")
|
||||||
|
if result.stderr.empty?
|
||||||
|
result.stdout
|
||||||
|
else
|
||||||
|
raise "Error while running command \'podman #{subcommand}\' : #{result.stderr}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_json_command(labels, subcommand)
|
||||||
|
# build command
|
||||||
|
format = labels.map { |label| "\"#{label}\": {{json .#{label}}}" }
|
||||||
|
raw = inspec.command("podman #{subcommand} --format '{#{format.join(", ")}}'").stdout
|
||||||
|
output = []
|
||||||
|
|
||||||
|
raw.each_line do |entry|
|
||||||
|
# convert all keys to lower_case to work well with ruby and filter table
|
||||||
|
row = JSON.parse(entry).map do |key, value|
|
||||||
|
[key.downcase, value]
|
||||||
|
end.to_h
|
||||||
|
|
||||||
|
# ensure all keys are there
|
||||||
|
row = ensure_keys(row, labels)
|
||||||
|
output.push(row)
|
||||||
|
end
|
||||||
|
|
||||||
|
output
|
||||||
|
rescue JSON::ParserError => _e
|
||||||
|
warn "Could not parse `podman #{subcommand}` output"
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
def ensure_keys(entry, labels)
|
||||||
|
labels.each do |key|
|
||||||
|
entry[key.downcase] = nil unless entry.key?(key.downcase)
|
||||||
|
end
|
||||||
|
entry
|
||||||
|
end
|
||||||
|
|
||||||
|
# Method to parse JDON content.
|
||||||
|
# Returns: Parsed data.
|
||||||
|
def parse(content)
|
||||||
|
require "json" unless defined?(JSON)
|
||||||
|
output = JSON.parse(content)
|
||||||
|
parsed_output = []
|
||||||
|
output.each do |entry|
|
||||||
|
entry = entry.map do |k, v|
|
||||||
|
[k.downcase, v]
|
||||||
|
end.to_h
|
||||||
|
parsed_output << entry
|
||||||
|
end
|
||||||
|
parsed_output
|
||||||
|
rescue => e
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Unable to parse command JSON output: #{e.message}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# class for podman.containers plural resource
|
||||||
|
class PodmanContainerFilter
|
||||||
|
filter = FilterTable.create
|
||||||
|
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
||||||
|
filter.register_column(:commands, field: "command")
|
||||||
|
.register_column(:ids, field: "id")
|
||||||
|
.register_column(:created_at, field: "createdat")
|
||||||
|
.register_column(:images, field: "image")
|
||||||
|
.register_column(:names, field: "names")
|
||||||
|
.register_column(:status, field: "status")
|
||||||
|
.register_column(:image_ids, field: "image_id")
|
||||||
|
.register_column(:labels, field: "labels", style: :simple)
|
||||||
|
.register_column(:mounts, field: "mounts")
|
||||||
|
.register_column(:networks, field: "networks")
|
||||||
|
.register_column(:pods, field: "pod")
|
||||||
|
.register_column(:ports, field: "ports")
|
||||||
|
.register_column(:sizes, field: "size")
|
||||||
|
.register_column(:running_for, field: "running_for")
|
||||||
|
.register_custom_matcher(:running?) do |x|
|
||||||
|
x.where { status.downcase.start_with?("up") }
|
||||||
|
end
|
||||||
|
filter.install_filter_methods_on_resource(self, :containers)
|
||||||
|
|
||||||
|
attr_reader :containers
|
||||||
|
def initialize(containers)
|
||||||
|
@containers = containers
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"Podman Containers"
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
"Podman Containers"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# class for podman.images plural resource
|
||||||
|
class PodmanImageFilter
|
||||||
|
filter = FilterTable.create
|
||||||
|
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
||||||
|
filter.register_column(:ids, field: "id")
|
||||||
|
.register_column(:repositories, field: "repository")
|
||||||
|
.register_column(:tags, field: "tag")
|
||||||
|
.register_column(:sizes, field: "size")
|
||||||
|
.register_column(:digests, field: "digest")
|
||||||
|
.register_column(:created_at, field: "createdat")
|
||||||
|
.register_column(:created_since, field: "createdsince")
|
||||||
|
.register_column(:history, field: "history")
|
||||||
|
filter.install_filter_methods_on_resource(self, :images)
|
||||||
|
|
||||||
|
attr_reader :images
|
||||||
|
def initialize(images)
|
||||||
|
@images = images
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"Podman Images"
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
"Podman Images"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PodmanNetworkFilter
|
||||||
|
filter = FilterTable.create
|
||||||
|
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
||||||
|
.register_column(:ids, field: "id")
|
||||||
|
.register_column(:names, field: "name")
|
||||||
|
.register_column(:drivers, field: "driver")
|
||||||
|
.register_column(:network_interfaces, field: "networkinterface")
|
||||||
|
.register_column(:created, field: "created")
|
||||||
|
.register_column(:subnets, field: "subnets")
|
||||||
|
.register_column(:ipv6_enabled, field: "ipv6enabled")
|
||||||
|
.register_column(:internal, field: "internal")
|
||||||
|
.register_column(:dns_enabled, field: "dnsenabled")
|
||||||
|
.register_column(:ipam_options, field: "ipamoptions")
|
||||||
|
.register_column(:options, field: "options")
|
||||||
|
.register_column(:labels, field: "labels")
|
||||||
|
filter.install_filter_methods_on_resource(self, :networks)
|
||||||
|
|
||||||
|
attr_reader :networks
|
||||||
|
def initialize(networks)
|
||||||
|
@networks = networks
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"Podman Networks"
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
"Podman Networks"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PodmanPodFilter
|
||||||
|
filter = FilterTable.create
|
||||||
|
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
||||||
|
.register_column(:ids, field: "id")
|
||||||
|
.register_column(:cgroups, field: "cgroup")
|
||||||
|
.register_column(:containers, field: "containers")
|
||||||
|
.register_column(:created, field: "created")
|
||||||
|
.register_column(:infraids, field: "infraid")
|
||||||
|
.register_column(:names, field: "name")
|
||||||
|
.register_column(:namespaces, field: "namespace")
|
||||||
|
.register_column(:networks, field: "networks")
|
||||||
|
.register_column(:status, field: "status")
|
||||||
|
.register_column(:labels, field: "labels")
|
||||||
|
filter.install_filter_methods_on_resource(self, :pods)
|
||||||
|
|
||||||
|
attr_reader :pods
|
||||||
|
def initialize(pods)
|
||||||
|
@pods = pods
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"Podman Pods"
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
"Podman Pods"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class PodmanVolumeFilter
|
||||||
|
filter = FilterTable.create
|
||||||
|
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
||||||
|
.register_column(:names, field: "name")
|
||||||
|
.register_column(:drivers, field: "driver")
|
||||||
|
.register_column(:mountpoints, field: "mountpoint")
|
||||||
|
.register_column(:createdat, field: "createdat")
|
||||||
|
.register_column(:labels, field: "labels")
|
||||||
|
.register_column(:scopes, field: "scope")
|
||||||
|
.register_column(:options, field: "options")
|
||||||
|
.register_column(:mountcount, field: "mountcount")
|
||||||
|
.register_column(:needscopyup, field: "needscopyup")
|
||||||
|
.register_column(:needschown, field: "needschown")
|
||||||
|
filter.install_filter_methods_on_resource(self, :volumes)
|
||||||
|
|
||||||
|
attr_reader :volumes
|
||||||
|
def initialize(volumes)
|
||||||
|
@volumes = volumes
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"Podman Volumes"
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
"Podman Volumes"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
84
lib/inspec/resources/podman_container.rb
Normal file
84
lib/inspec/resources/podman_container.rb
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
require "inspec/resources/podman"
|
||||||
|
require_relative "docker_object"
|
||||||
|
|
||||||
|
# Change module if required
|
||||||
|
module Inspec::Resources
|
||||||
|
class PodmanContainer < Inspec.resource(1)
|
||||||
|
include Inspec::Resources::DockerObject
|
||||||
|
name "podman_container"
|
||||||
|
supports platform: "unix"
|
||||||
|
|
||||||
|
desc "Inspec core resource to retrieve information about podman container"
|
||||||
|
|
||||||
|
example <<~EXAMPLE
|
||||||
|
describe podman_container("sweet_mendeleev") do
|
||||||
|
it { should exist }
|
||||||
|
it { should be_running }
|
||||||
|
its("id") { should eq "591270d8d80d26671fd6ed622f367fbe19004d16e3b519c292313feb5f22e7f7" }
|
||||||
|
its("image") { should eq "docker.io/library/nginx:latest" }
|
||||||
|
its("labels") { should include "maintainer"=>"NGINX Docker Maintainers <docker-maint@nginx.com>" }
|
||||||
|
its("ports") { should eq nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman_container(id: "591270d8d80d2667") do
|
||||||
|
it { should exist }
|
||||||
|
it { should be_running }
|
||||||
|
end
|
||||||
|
EXAMPLE
|
||||||
|
|
||||||
|
def initialize(opts = {})
|
||||||
|
skip_resource "The `podman_container` resource is not yet available on your OS." unless inspec.os.unix?
|
||||||
|
|
||||||
|
# if a string is provided, we expect it is the name
|
||||||
|
if opts.is_a?(String)
|
||||||
|
@opts = { name: opts }
|
||||||
|
else
|
||||||
|
@opts = opts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def running?
|
||||||
|
status.downcase.start_with?("up") if object_info.entries.length == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
object_info.status[0] if object_info.entries.length == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def labels
|
||||||
|
object_info.labels
|
||||||
|
end
|
||||||
|
|
||||||
|
def ports
|
||||||
|
object_info.ports[0] if object_info.entries.length == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def command
|
||||||
|
return unless object_info.entries.length == 1
|
||||||
|
|
||||||
|
object_info.commands[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
def image
|
||||||
|
object_info.images[0] if object_info.entries.length == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
object_info.ids[0] || @opts[:id] || @opts[:name] || ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
name = @opts[:name] || @opts[:id]
|
||||||
|
"Podman Container #{name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def object_info
|
||||||
|
return @info if defined?(@info)
|
||||||
|
|
||||||
|
opts = @opts
|
||||||
|
@info = inspec.podman.containers.where { names == opts[:name] || (!id.nil? && !opts[:id].nil? && (id == opts[:id] || id.start_with?(opts[:id]))) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
108
lib/inspec/resources/podman_image.rb
Normal file
108
lib/inspec/resources/podman_image.rb
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
require "inspec/resources/command"
|
||||||
|
require_relative "docker_object"
|
||||||
|
require "inspec/utils/podman"
|
||||||
|
|
||||||
|
module Inspec::Resources
|
||||||
|
class PodmanImage < Inspec.resource(1)
|
||||||
|
include Inspec::Resources::DockerObject
|
||||||
|
include Inspec::Utils::Podman
|
||||||
|
|
||||||
|
name "podman_image"
|
||||||
|
supports platform: "unix"
|
||||||
|
|
||||||
|
desc "InSpec core resource to retrieve information about podman image"
|
||||||
|
|
||||||
|
example <<~EXAMPLE
|
||||||
|
describe podman_image("docker.io/library/busybox") do
|
||||||
|
it { should exist }
|
||||||
|
its("repo_tags") { should include "docker.io/library/busybox:latest" }
|
||||||
|
its("size") { should eq 1636053 }
|
||||||
|
its("resource_id") { should eq "docker.io/library/busybox:latest" }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman_image("docker.io/library/busybox:latest") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman_image(repo: "docker.io/library/busybox", tag: "latest") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman_image(id: "3c19bafed223") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
EXAMPLE
|
||||||
|
|
||||||
|
attr_reader :opts, :image_info
|
||||||
|
|
||||||
|
def initialize(opts)
|
||||||
|
skip_resource "The `podman_image` resource is not yet available on your OS." unless inspec.os.unix?
|
||||||
|
opts = { image: opts } if opts.is_a?(String)
|
||||||
|
@opts = sanitize_options(opts)
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Podman is not running. Please make sure it is installed and running." unless podman_running?
|
||||||
|
|
||||||
|
@image_info = get_image_info
|
||||||
|
end
|
||||||
|
|
||||||
|
LABELS = {
|
||||||
|
"id" => "ID",
|
||||||
|
"repo_tags" => "RepoTags",
|
||||||
|
"size" => "Size",
|
||||||
|
"digest" => "Digest",
|
||||||
|
"created_at" => "Created",
|
||||||
|
"version" => "Version",
|
||||||
|
"names_history" => "NamesHistory",
|
||||||
|
"repo_digests" => "RepoDigests",
|
||||||
|
"architecture" => "Architecture",
|
||||||
|
"os" => "Os",
|
||||||
|
"virtual_size" => "VirtualSize",
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
## This creates all the required properties methods dynamically.
|
||||||
|
LABELS.each do |k, v|
|
||||||
|
define_method(k) do
|
||||||
|
image_info[k.to_s]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exist?
|
||||||
|
! image_info.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
opts[:id] || opts[:image] || ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"podman_image #{resource_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def sanitize_options(opts)
|
||||||
|
opts.merge!(parse_components_from_image(opts[:image]))
|
||||||
|
|
||||||
|
# assume a "latest" tag if we don't have one
|
||||||
|
opts[:tag] ||= "latest"
|
||||||
|
|
||||||
|
# Assemble/reassemble the image from the repo and tag
|
||||||
|
opts[:image] = "#{opts[:repo]}:#{opts[:tag]}" unless opts[:repo].nil?
|
||||||
|
|
||||||
|
opts
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_image_info
|
||||||
|
current_image = opts[:id] || opts[:image] || opts[:repo] + ":" + opts[:tag]
|
||||||
|
json_key_label = generate_go_template(LABELS)
|
||||||
|
podman_inspect_cmd = inspec.command("podman image inspect #{current_image} --format '{#{json_key_label}}'")
|
||||||
|
|
||||||
|
if podman_inspect_cmd.exit_status == 0
|
||||||
|
parse_command_output(podman_inspect_cmd.stdout)
|
||||||
|
elsif podman_inspect_cmd.stderr =~ /failed to find image/
|
||||||
|
{}
|
||||||
|
else
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Unable to retrieve podman image information for #{current_image}.\nError message: #{podman_inspect_cmd.stderr}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
81
lib/inspec/resources/podman_network.rb
Normal file
81
lib/inspec/resources/podman_network.rb
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
require "inspec/resources/command"
|
||||||
|
require "inspec/utils/podman"
|
||||||
|
module Inspec::Resources
|
||||||
|
class PodmanNetwork < Inspec.resource(1)
|
||||||
|
include Inspec::Utils::Podman
|
||||||
|
|
||||||
|
name "podman_network"
|
||||||
|
|
||||||
|
supports platform: "unix"
|
||||||
|
|
||||||
|
desc "InSpec core resource to retrive information about the given Podman network"
|
||||||
|
|
||||||
|
example <<~EXAMPLE
|
||||||
|
describe podman_network("podman") do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
describe podman_network("3a7c94d937d5f3a0f1a9b1610589945aedfbe56207fd5d32fc8154aa1a8b007f") do
|
||||||
|
its("driver") { should eq bridge }
|
||||||
|
end
|
||||||
|
EXAMPLE
|
||||||
|
|
||||||
|
LABELS = {
|
||||||
|
id: "ID",
|
||||||
|
name: "Name",
|
||||||
|
driver: "Driver",
|
||||||
|
labels: "Labels",
|
||||||
|
options: "Options",
|
||||||
|
ipam_options: "IPAMOptions",
|
||||||
|
internal: "Internal",
|
||||||
|
created: "Created",
|
||||||
|
ipv6_enabled: "IPv6Enabled",
|
||||||
|
dns_enabled: "DNSEnabled",
|
||||||
|
network_interface: "NetworkInterface",
|
||||||
|
subnets: "Subnets",
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
attr_reader :param, :network_info
|
||||||
|
def initialize(param)
|
||||||
|
skip_resource "The `podman_network` resource is not yet available on your OS." unless inspec.os.unix?
|
||||||
|
|
||||||
|
@param = param
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Podman is not running. Please make sure it is installed and running." unless podman_running?
|
||||||
|
|
||||||
|
@network_info = get_network_info
|
||||||
|
end
|
||||||
|
|
||||||
|
## This creates all the required properties methods dynamically.
|
||||||
|
LABELS.each do |k, v|
|
||||||
|
define_method(k) do
|
||||||
|
network_info[k.to_s]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exist?
|
||||||
|
!network_info.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
id || param || ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"podman_network #{resource_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_network_info
|
||||||
|
go_template_format = generate_go_template(LABELS)
|
||||||
|
result = inspec.command("podman network inspect #{param} --format '{#{go_template_format}}'")
|
||||||
|
|
||||||
|
if result.exit_status == 0
|
||||||
|
parse_command_output(result.stdout)
|
||||||
|
elsif result.stderr =~ /network not found/
|
||||||
|
{}
|
||||||
|
else
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Unable to retrieve podman network information for #{param}.\nError message: #{result.stderr}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
101
lib/inspec/resources/podman_pod.rb
Normal file
101
lib/inspec/resources/podman_pod.rb
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
require "inspec/resources/command"
|
||||||
|
require "inspec/utils/podman"
|
||||||
|
|
||||||
|
module Inspec::Resources
|
||||||
|
class PodmanPod < Inspec.resource(1)
|
||||||
|
include Inspec::Utils::Podman
|
||||||
|
|
||||||
|
name "podman_pod"
|
||||||
|
supports platform: "unix"
|
||||||
|
|
||||||
|
desc "InSpec core resource to retrieve information about podman pod"
|
||||||
|
|
||||||
|
example <<~EXAMPLE
|
||||||
|
describe podman_pod("nginx-frontend") do
|
||||||
|
it { should exist }
|
||||||
|
its("id") { should eq "fcfe4d471cfface0d1b39bce23af7d31ab8736cd68c0360ade0b4afe364f79d4" }
|
||||||
|
its("name") { should eq "nginx-frontend" }
|
||||||
|
its("created_at") { should eq "2022-07-14T15:47:47.978078124+05:30" }
|
||||||
|
its("create_command") { should include "new:nginx-frontend" }
|
||||||
|
its("state") { should eq "Running" }
|
||||||
|
its("hostname") { should eq "" }
|
||||||
|
its("create_cgroup") { should eq true }
|
||||||
|
its("cgroup_parent") { should eq "user.slice" }
|
||||||
|
its("cgroup_path") { should eq "user.slice/user-libpod_pod_fcfe4d471cfface0d1b39bce23af7d31ab8736cd68c0360ade0b4afe364f79d4.slice" }
|
||||||
|
its("create_infra") { should eq true }
|
||||||
|
its("infra_container_id") { should eq "727538044b32a165934729dc2d47d9d5e981b6496aebfad7de470f7e76ea4251" }
|
||||||
|
its("infra_config") { should include "DNSOption" }
|
||||||
|
its("shared_namespaces") { should include "ipc" }
|
||||||
|
its("num_containers") { should eq 2 }
|
||||||
|
its("containers") { should_not be nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe podman_pod("non-existing-pod") do
|
||||||
|
it { should_not exist }
|
||||||
|
end
|
||||||
|
EXAMPLE
|
||||||
|
|
||||||
|
attr_reader :pod_info, :pod_id
|
||||||
|
|
||||||
|
def initialize(pod_id)
|
||||||
|
skip_resource "The `podman_pod` resource is not yet available on your OS." unless inspec.os.unix?
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Podman is not running. Please make sure it is installed and running." unless podman_running?
|
||||||
|
|
||||||
|
@pod_id = pod_id
|
||||||
|
@pod_info = get_pod_info
|
||||||
|
end
|
||||||
|
|
||||||
|
LABELS = {
|
||||||
|
"id" => "ID",
|
||||||
|
"name" => "Name",
|
||||||
|
"created_at" => "Created",
|
||||||
|
"create_command" => "CreateCommand",
|
||||||
|
"state" => "State",
|
||||||
|
"hostname" => "Hostname",
|
||||||
|
"create_cgroup" => "CreateCgroup",
|
||||||
|
"cgroup_parent" => "CgroupParent",
|
||||||
|
"cgroup_path" => "CgroupPath",
|
||||||
|
"create_infra" => "CreateInfra",
|
||||||
|
"infra_container_id" => "InfraContainerID",
|
||||||
|
"infra_config" => "InfraConfig",
|
||||||
|
"shared_namespaces" => "SharedNamespaces",
|
||||||
|
"num_containers" => "NumContainers",
|
||||||
|
"containers" => "Containers",
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
# This creates all the required properties methods dynamically.
|
||||||
|
LABELS.each do |k, _|
|
||||||
|
define_method(k) do
|
||||||
|
pod_info[k.to_s]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exist?
|
||||||
|
!pod_info.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
pod_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"Podman Pod #{resource_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_pod_info
|
||||||
|
json_key_label = generate_go_template(LABELS)
|
||||||
|
|
||||||
|
inspect_pod_cmd = inspec.command("podman pod inspect #{pod_id} --format '{#{json_key_label}}'")
|
||||||
|
|
||||||
|
if inspect_pod_cmd.exit_status == 0
|
||||||
|
parse_command_output(inspect_pod_cmd.stdout)
|
||||||
|
elsif inspect_pod_cmd.stderr =~ /no pod with name or ID/
|
||||||
|
{}
|
||||||
|
else
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Unable to retrieve podman pod information for #{pod_id}.\nError message: #{inspect_pod_cmd.stderr}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
87
lib/inspec/resources/podman_volume.rb
Normal file
87
lib/inspec/resources/podman_volume.rb
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
require "inspec/resources/command"
|
||||||
|
require "inspec/utils/podman"
|
||||||
|
|
||||||
|
module Inspec::Resources
|
||||||
|
class PodmanVolume < Inspec.resource(1)
|
||||||
|
include Inspec::Utils::Podman
|
||||||
|
|
||||||
|
name "podman_volume"
|
||||||
|
supports platform: "unix"
|
||||||
|
|
||||||
|
desc "InSpec core resource to retrieve information about podman volume"
|
||||||
|
|
||||||
|
example <<~EXAMPLE
|
||||||
|
describe podman_volume("my_volume") do
|
||||||
|
it { should exist }
|
||||||
|
its("name") { should eq "my_volume" }
|
||||||
|
its("driver") { should eq "local" }
|
||||||
|
its("mountpoint") { should eq "/var/home/core/.local/share/containers/storage/volumes/my_volume/_data" }
|
||||||
|
its("created_at") { should eq "2022-07-14T13:21:19.965421792+05:30" }
|
||||||
|
its("labels") { should eq({}) }
|
||||||
|
its("scope") { should eq "local" }
|
||||||
|
its("options") { should eq({}) }
|
||||||
|
its("mount_count") { should eq 0 }
|
||||||
|
its("needs_copy_up") { should eq true }
|
||||||
|
its("needs_chown") { should eq true }
|
||||||
|
end
|
||||||
|
EXAMPLE
|
||||||
|
|
||||||
|
attr_reader :volume_info, :volume_name
|
||||||
|
|
||||||
|
def initialize(volume_name)
|
||||||
|
skip_resource "The `podman_volume` resource is not yet available on your OS." unless inspec.os.unix?
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Podman is not running. Please make sure it is installed and running." unless podman_running?
|
||||||
|
|
||||||
|
@volume_name = volume_name
|
||||||
|
@volume_info = get_volume_info
|
||||||
|
end
|
||||||
|
|
||||||
|
LABELS = {
|
||||||
|
"name" => "Name",
|
||||||
|
"driver" => "Driver",
|
||||||
|
"mountpoint" => "Mountpoint",
|
||||||
|
"created_at" => "CreatedAt",
|
||||||
|
"labels" => "Labels",
|
||||||
|
"scope" => "Scope",
|
||||||
|
"options" => "Options",
|
||||||
|
"mount_count" => "MountCount",
|
||||||
|
"needs_copy_up" => "NeedsCopyUp",
|
||||||
|
"needs_chown" => "NeedsChown",
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
# This creates all the required properties methods dynamically.
|
||||||
|
LABELS.each do |k, _|
|
||||||
|
define_method(k) do
|
||||||
|
volume_info[k.to_s]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exist?
|
||||||
|
!volume_info.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def resource_id
|
||||||
|
volume_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"podman_volume #{resource_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_volume_info
|
||||||
|
json_key_label = generate_go_template(LABELS)
|
||||||
|
|
||||||
|
inspect_volume_cmd = inspec.command("podman volume inspect #{volume_name} --format '{#{json_key_label}}'")
|
||||||
|
|
||||||
|
if inspect_volume_cmd.exit_status == 0
|
||||||
|
parse_command_output(inspect_volume_cmd.stdout)
|
||||||
|
elsif inspect_volume_cmd.stderr =~ /inspecting object: no such/
|
||||||
|
{}
|
||||||
|
else
|
||||||
|
raise Inspec::Exceptions::ResourceFailed, "Unable to retrieve podman volume information for #{volume_name}.\nError message: #{inspect_volume_cmd.stderr}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,6 +8,8 @@ require "inspec/impact"
|
||||||
require "inspec/resource"
|
require "inspec/resource"
|
||||||
require "inspec/resources/os"
|
require "inspec/resources/os"
|
||||||
require "inspec/input_registry"
|
require "inspec/input_registry"
|
||||||
|
require "inspec/waiver_file_reader"
|
||||||
|
require "inspec/utils/convert"
|
||||||
|
|
||||||
module Inspec
|
module Inspec
|
||||||
class Rule
|
class Rule
|
||||||
|
@ -133,10 +135,11 @@ module Inspec
|
||||||
#
|
#
|
||||||
# @param [Type] &block returns true if tests are added, false otherwise
|
# @param [Type] &block returns true if tests are added, false otherwise
|
||||||
# @return [nil]
|
# @return [nil]
|
||||||
def only_if(message = nil)
|
def only_if(message = nil, impact: nil)
|
||||||
return unless block_given?
|
return unless block_given?
|
||||||
return if @__skip_only_if_eval == true
|
return if @__skip_only_if_eval == true
|
||||||
|
|
||||||
|
self.impact(impact) if impact && !yield
|
||||||
@__skip_rule[:result] ||= !yield
|
@__skip_rule[:result] ||= !yield
|
||||||
@__skip_rule[:type] = :only_if
|
@__skip_rule[:type] = :only_if
|
||||||
@__skip_rule[:message] = message
|
@__skip_rule[:message] = message
|
||||||
|
@ -337,17 +340,20 @@ module Inspec
|
||||||
# only_if mechanism)
|
# only_if mechanism)
|
||||||
# Double underscore: not intended to be called as part of the DSL
|
# Double underscore: not intended to be called as part of the DSL
|
||||||
def __apply_waivers
|
def __apply_waivers
|
||||||
input_name = @__rule_id # TODO: control ID slugging
|
control_id = @__rule_id # TODO: control ID slugging
|
||||||
registry = Inspec::InputRegistry.instance
|
waiver_files = Inspec::Config.cached.final_options["waiver_file"] if Inspec::Config.cached.respond_to?(:final_options)
|
||||||
input = registry.inputs_by_profile.dig(__profile_id, input_name)
|
|
||||||
return unless input && input.has_value? && input.value.is_a?(Hash)
|
waiver_data_by_profile = Inspec::WaiverFileReader.fetch_waivers_by_profile(__profile_id, waiver_files) unless waiver_files.nil?
|
||||||
|
|
||||||
|
return unless waiver_data_by_profile && waiver_data_by_profile[control_id] && waiver_data_by_profile[control_id].is_a?(Hash)
|
||||||
|
|
||||||
# An InSpec Input is a datastructure that tracks a profile parameter
|
# An InSpec Input is a datastructure that tracks a profile parameter
|
||||||
# over time. Its value can be set by many sources, and it keeps a
|
# over time. Its value can be set by many sources, and it keeps a
|
||||||
# log of each "set" event so that when it is collapsed to a value,
|
# log of each "set" event so that when it is collapsed to a value,
|
||||||
# it can determine the correct (highest priority) value.
|
# it can determine the correct (highest priority) value.
|
||||||
# Store in an instance variable for.. later reading???
|
# Store in an instance variable for.. later reading???
|
||||||
@__waiver_data = input.value
|
@__waiver_data = waiver_data_by_profile[control_id]
|
||||||
|
|
||||||
__waiver_data["skipped_due_to_waiver"] = false
|
__waiver_data["skipped_due_to_waiver"] = false
|
||||||
__waiver_data["message"] = ""
|
__waiver_data["message"] = ""
|
||||||
|
|
||||||
|
@ -376,6 +382,7 @@ module Inspec
|
||||||
# expiration_date. We only care here if it has a "run" key and it
|
# expiration_date. We only care here if it has a "run" key and it
|
||||||
# is false-like, since all non-skipped waiver operations are handled
|
# is false-like, since all non-skipped waiver operations are handled
|
||||||
# during reporting phase.
|
# during reporting phase.
|
||||||
|
__waiver_data["run"] = Converter.to_boolean(__waiver_data["run"]) if __waiver_data.key?("run")
|
||||||
return unless __waiver_data.key?("run") && !__waiver_data["run"]
|
return unless __waiver_data.key?("run") && !__waiver_data["run"]
|
||||||
|
|
||||||
# OK, apply a skip.
|
# OK, apply a skip.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require "inspec/enhanced_outcomes"
|
||||||
|
|
||||||
module Inspec
|
module Inspec
|
||||||
class RunData
|
class RunData
|
||||||
Control = Struct.new(
|
Control = Struct.new(
|
||||||
|
@ -31,6 +33,10 @@ module Inspec
|
||||||
].each do |field|
|
].each do |field|
|
||||||
self[field] = raw_ctl_data[field]
|
self[field] = raw_ctl_data[field]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
Inspec::EnhancedOutcomes.determine_status(results, impact)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,20 @@ module Inspec
|
||||||
:total,
|
:total,
|
||||||
:passed,
|
:passed,
|
||||||
:skipped,
|
:skipped,
|
||||||
:failed
|
:failed,
|
||||||
|
:not_reviewed,
|
||||||
|
:not_applicable,
|
||||||
|
:error
|
||||||
) do
|
) do
|
||||||
include HashLikeStruct
|
include HashLikeStruct
|
||||||
def initialize(raw_stat_ctl_data)
|
def initialize(raw_stat_ctl_data)
|
||||||
self.total = raw_stat_ctl_data[:total]
|
self.total = raw_stat_ctl_data[:total]
|
||||||
self.passed = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:passed][:total])
|
self.passed = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:passed][:total])
|
||||||
self.skipped = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:skipped][:total])
|
|
||||||
self.failed = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:failed][:total])
|
self.failed = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:failed][:total])
|
||||||
|
self.skipped = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:skipped][:total]) if raw_stat_ctl_data[:skipped]
|
||||||
|
self.not_reviewed = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:not_reviewed][:total]) if raw_stat_ctl_data[:not_reviewed]
|
||||||
|
self.not_applicable = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:not_applicable][:total]) if raw_stat_ctl_data[:not_applicable]
|
||||||
|
self.error = Inspec::RunData::Statistics::Controls::Total.new(raw_stat_ctl_data[:error][:total]) if raw_stat_ctl_data[:error]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
class Controls
|
class Controls
|
||||||
|
|
|
@ -60,9 +60,11 @@ module Inspec
|
||||||
end
|
end
|
||||||
|
|
||||||
if @conf[:waiver_file]
|
if @conf[:waiver_file]
|
||||||
waivers = @conf.delete(:waiver_file)
|
@conf[:waiver_file].each do |file|
|
||||||
@conf[:input_file] ||= []
|
unless File.file?(file)
|
||||||
@conf[:input_file].concat waivers
|
raise Inspec::Exceptions::WaiversFileDoesNotExist, "Waiver file #{file} does not exist."
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# About reading inputs:
|
# About reading inputs:
|
||||||
|
@ -133,12 +135,20 @@ module Inspec
|
||||||
all_controls.each do |rule|
|
all_controls.each do |rule|
|
||||||
unless rule.nil?
|
unless rule.nil?
|
||||||
register_rule(rule)
|
register_rule(rule)
|
||||||
checks = ::Inspec::Rule.prepare_checks(rule)
|
total_checks = 0
|
||||||
unless checks.empty?
|
control_describe_checks = ::Inspec::Rule.prepare_checks(rule)
|
||||||
|
|
||||||
|
examples = control_describe_checks.flat_map do |m, a, b|
|
||||||
|
get_check_example(m, a, b)
|
||||||
|
end.compact
|
||||||
|
|
||||||
|
examples.map { |example| total_checks += example.examples.count }
|
||||||
|
|
||||||
|
unless control_describe_checks.empty?
|
||||||
# controls with empty tests are avoided
|
# controls with empty tests are avoided
|
||||||
# checks represent tests within control
|
# checks represent tests within control
|
||||||
controls_count += 1
|
controls_count += 1 if control_checks_count_map[rule.to_s].nil?
|
||||||
control_checks_count_map[rule.to_s] = checks.count
|
control_checks_count_map[rule.to_s] = control_checks_count_map[rule.to_s].to_i + total_checks
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -158,7 +168,7 @@ module Inspec
|
||||||
return if @conf["reporter"].nil?
|
return if @conf["reporter"].nil?
|
||||||
|
|
||||||
@conf["reporter"].each do |reporter|
|
@conf["reporter"].each do |reporter|
|
||||||
result = Inspec::Reporters.render(reporter, run_data)
|
result = Inspec::Reporters.render(reporter, run_data, @conf["enhanced_outcomes"])
|
||||||
raise Inspec::ReporterError, "Error generating reporter '#{reporter[0]}'" if result == false
|
raise Inspec::ReporterError, "Error generating reporter '#{reporter[0]}'" if result == false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -107,11 +107,11 @@ module Inspec
|
||||||
stats = @formatter.results[:statistics][:controls]
|
stats = @formatter.results[:statistics][:controls]
|
||||||
load_failures = @formatter.results[:profiles]&.select { |p| p[:status] == "failed" }&.any?
|
load_failures = @formatter.results[:profiles]&.select { |p| p[:status] == "failed" }&.any?
|
||||||
skipped = @formatter.results.dig(:profiles, 0, :status) == "skipped"
|
skipped = @formatter.results.dig(:profiles, 0, :status) == "skipped"
|
||||||
if stats[:failed][:total] == 0 && stats[:skipped][:total] == 0 && !skipped && !load_failures
|
if stats[:failed][:total] == 0 && stats[:skipped][:total] == 0 && !skipped && !load_failures && (stats[:error] && stats[:error][:total] == 0) # placed error count condition because of enhanced outcomes
|
||||||
0
|
0
|
||||||
elsif load_failures
|
elsif load_failures
|
||||||
@conf["distinct_exit"] ? 102 : 1
|
@conf["distinct_exit"] ? 102 : 1
|
||||||
elsif stats[:failed][:total] > 0
|
elsif stats[:failed][:total] > 0 || (stats[:error] && stats[:error][:total] > 0)
|
||||||
@conf["distinct_exit"] ? 100 : 1
|
@conf["distinct_exit"] ? 100 : 1
|
||||||
elsif stats[:skipped][:total] > 0 || skipped
|
elsif stats[:skipped][:total] > 0 || skipped
|
||||||
@conf["distinct_exit"] ? 101 : 0
|
@conf["distinct_exit"] ? 101 : 0
|
||||||
|
@ -196,6 +196,7 @@ module Inspec
|
||||||
def configure_output
|
def configure_output
|
||||||
RSpec.configuration.output_stream = $stdout
|
RSpec.configuration.output_stream = $stdout
|
||||||
@formatter = RSpec.configuration.add_formatter(Inspec::Formatters::Base)
|
@formatter = RSpec.configuration.add_formatter(Inspec::Formatters::Base)
|
||||||
|
@formatter.enhanced_outcomes = @conf.final_options["enhanced_outcomes"]
|
||||||
RSpec.configuration.add_formatter(Inspec::Formatters::ShowProgress, $stderr) if @conf[:show_progress]
|
RSpec.configuration.add_formatter(Inspec::Formatters::ShowProgress, $stderr) if @conf[:show_progress]
|
||||||
set_optional_formatters
|
set_optional_formatters
|
||||||
RSpec.configuration.color = @conf["color"]
|
RSpec.configuration.color = @conf["color"]
|
||||||
|
|
|
@ -111,6 +111,43 @@ module Inspec
|
||||||
},
|
},
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
CONTROL_ENHANCED_OUTCOME = {
|
||||||
|
"type" => "object",
|
||||||
|
"additionalProperties" => false,
|
||||||
|
"properties" => {
|
||||||
|
"id" => { "type" => "string" },
|
||||||
|
"title" => { "type" => %w{string null} },
|
||||||
|
"desc" => { "type" => %w{string null} },
|
||||||
|
"descriptions" => { "type" => %w{array} },
|
||||||
|
"impact" => { "type" => "number" },
|
||||||
|
"status" => {
|
||||||
|
"enum" => %w{passed failed not_applicable not_reviewed error},
|
||||||
|
"description" => Primitives.desc(Primitives::STRING, "The enhanced outcome status of the control"),
|
||||||
|
},
|
||||||
|
"refs" => REFS,
|
||||||
|
"tags" => TAGS,
|
||||||
|
"code" => { "type" => "string" },
|
||||||
|
"source_location" => {
|
||||||
|
"type" => "object",
|
||||||
|
"properties" => {
|
||||||
|
"ref" => { "type" => "string" },
|
||||||
|
"line" => { "type" => "number" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"results" => { "type" => "array", "items" => RESULT },
|
||||||
|
"waiver_data" => {
|
||||||
|
"type" => "object",
|
||||||
|
"properties" => {
|
||||||
|
"skipped_due_to_waiver" => { "type" => "string" },
|
||||||
|
"run" => { "type" => "boolean" },
|
||||||
|
"message" => { "type" => "string" },
|
||||||
|
"expiration_date" => { "type" => "string" },
|
||||||
|
"justification" => { "type" => "string" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}.freeze
|
||||||
|
|
||||||
SUPPORTS = {
|
SUPPORTS = {
|
||||||
"type" => "object",
|
"type" => "object",
|
||||||
"additionalProperties" => false,
|
"additionalProperties" => false,
|
||||||
|
@ -173,6 +210,45 @@ module Inspec
|
||||||
},
|
},
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
PROFILE_ENHANCED_OUTCOME = {
|
||||||
|
"type" => "object",
|
||||||
|
"additionalProperties" => false,
|
||||||
|
"properties" => {
|
||||||
|
"name" => { "type" => "string" },
|
||||||
|
"version" => { "type" => "string", "optional" => true },
|
||||||
|
"sha256" => { "type" => "string", "optional" => false },
|
||||||
|
|
||||||
|
"title" => { "type" => "string", "optional" => true },
|
||||||
|
"maintainer" => { "type" => "string", "optional" => true },
|
||||||
|
"copyright" => { "type" => "string", "optional" => true },
|
||||||
|
"copyright_email" => { "type" => "string", "optional" => true },
|
||||||
|
"license" => { "type" => "string", "optional" => true },
|
||||||
|
"summary" => { "type" => "string", "optional" => true },
|
||||||
|
"status" => { "type" => "string", "optional" => false },
|
||||||
|
"status_message" => { "type" => "string", "optional" => true },
|
||||||
|
# skip_message is deprecated, status_message should be used to store the reason for skipping
|
||||||
|
"skip_message" => { "type" => "string", "optional" => true },
|
||||||
|
|
||||||
|
"supports" => {
|
||||||
|
"type" => "array",
|
||||||
|
"items" => SUPPORTS,
|
||||||
|
"optional" => true,
|
||||||
|
},
|
||||||
|
"controls" => {
|
||||||
|
"type" => "array",
|
||||||
|
"items" => CONTROL_ENHANCED_OUTCOME,
|
||||||
|
},
|
||||||
|
"groups" => {
|
||||||
|
"type" => "array",
|
||||||
|
"items" => CONTROL_GROUP,
|
||||||
|
},
|
||||||
|
"attributes" => { # TODO: rename to inputs, refs #3802
|
||||||
|
"type" => "array",
|
||||||
|
# TODO: more detailed specification needed
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}.freeze
|
||||||
|
|
||||||
EXEC_JSON = {
|
EXEC_JSON = {
|
||||||
"type" => "object",
|
"type" => "object",
|
||||||
"additionalProperties" => false,
|
"additionalProperties" => false,
|
||||||
|
@ -187,6 +263,20 @@ module Inspec
|
||||||
},
|
},
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
EXEC_JSON_ENHANCED_OUTCOME = {
|
||||||
|
"type" => "object",
|
||||||
|
"additionalProperties" => false,
|
||||||
|
"properties" => {
|
||||||
|
"platform" => PLATFORM,
|
||||||
|
"profiles" => {
|
||||||
|
"type" => "array",
|
||||||
|
"items" => PROFILE_ENHANCED_OUTCOME,
|
||||||
|
},
|
||||||
|
"statistics" => STATISTICS,
|
||||||
|
"version" => { "type" => "string" },
|
||||||
|
},
|
||||||
|
}.freeze
|
||||||
|
|
||||||
MIN_CONTROL = {
|
MIN_CONTROL = {
|
||||||
"type" => "object",
|
"type" => "object",
|
||||||
"additionalProperties" => false,
|
"additionalProperties" => false,
|
||||||
|
@ -228,6 +318,7 @@ module Inspec
|
||||||
LIST = {
|
LIST = {
|
||||||
"exec-json" => EXEC_JSON,
|
"exec-json" => EXEC_JSON,
|
||||||
"exec-jsonmin" => EXEC_JSONMIN,
|
"exec-jsonmin" => EXEC_JSONMIN,
|
||||||
|
"exec-json-enhanced-outcome" => EXEC_JSON_ENHANCED_OUTCOME,
|
||||||
"platforms" => PLATFORMS,
|
"platforms" => PLATFORMS,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ module Inspec
|
||||||
# Lists the potential values for a control result
|
# Lists the potential values for a control result
|
||||||
CONTROL_RESULT_STATUS = Primitives::SchemaType.new("Control Result Status", {
|
CONTROL_RESULT_STATUS = Primitives::SchemaType.new("Control Result Status", {
|
||||||
"type" => "string",
|
"type" => "string",
|
||||||
"enum" => %w{passed failed skipped error},
|
"enum" => %w{passed failed skipped},
|
||||||
}, [], "The status of a control. Should be one of 'passed', 'failed', 'skipped', or 'error'.")
|
}, [], "The status of a control. Should be one of 'passed', 'failed', or 'skipped'.")
|
||||||
|
|
||||||
# Represents the statistics/result of a control"s execution
|
# Represents the statistics/result of a control"s execution
|
||||||
CONTROL_RESULT = Primitives::SchemaType.new("Control Result", {
|
CONTROL_RESULT = Primitives::SchemaType.new("Control Result", {
|
||||||
|
@ -75,6 +75,36 @@ module Inspec
|
||||||
},
|
},
|
||||||
}, [CONTROL_DESCRIPTION, Primitives::REFERENCE, Primitives::SOURCE_LOCATION, CONTROL_RESULT], "Describes a control and any findings it has.")
|
}, [CONTROL_DESCRIPTION, Primitives::REFERENCE, Primitives::SOURCE_LOCATION, CONTROL_RESULT], "Describes a control and any findings it has.")
|
||||||
|
|
||||||
|
# Represents a control produced with enhanced outcomes option
|
||||||
|
ENHANCED_OUTCOME_CONTROL = Primitives::SchemaType.new("Exec JSON Control", {
|
||||||
|
"type" => "object",
|
||||||
|
"additionalProperties" => true,
|
||||||
|
"required" => %w{id title desc impact refs tags code source_location results},
|
||||||
|
"properties" => {
|
||||||
|
"id" => Primitives.desc(Primitives::STRING, "The id."),
|
||||||
|
"title" => Primitives.desc({ "type" => %w{string null} }, "The title - is nullable."), # Nullable string
|
||||||
|
"desc" => Primitives.desc({ "type" => %w{string null} }, "The description for the overarching control."),
|
||||||
|
"descriptions" => Primitives.desc(Primitives.array(CONTROL_DESCRIPTION.ref), "A set of additional descriptions. Example: the 'fix' text."),
|
||||||
|
"impact" => Primitives.desc(Primitives::IMPACT, "The impactfulness or severity."),
|
||||||
|
"status" => {
|
||||||
|
"enum" => %w{passed failed not_applicable not_reviewed error},
|
||||||
|
"description" => Primitives.desc(Primitives::STRING, "The enhanced outcome status of the control"),
|
||||||
|
},
|
||||||
|
"refs" => Primitives.desc(Primitives.array(Primitives::REFERENCE.ref), "The set of references to external documents."),
|
||||||
|
"tags" => Primitives.desc(Primitives::TAGS, "A set of tags - usually metadata."),
|
||||||
|
"code" => Primitives.desc(Primitives::STRING, "The raw source code of the control. Note that if this is an overlay control, it does not include the underlying source code."),
|
||||||
|
"source_location" => Primitives.desc(Primitives::SOURCE_LOCATION.ref, "The explicit location of the control within the source code."),
|
||||||
|
"results" => Primitives.desc(Primitives.array(CONTROL_RESULT.ref), %q(
|
||||||
|
The set of all tests within the control and their results and findings. Example:
|
||||||
|
For Chef Inspec, if in the control's code we had the following:
|
||||||
|
describe sshd_config do
|
||||||
|
its('Port') { should cmp 22 }
|
||||||
|
end
|
||||||
|
The findings from this block would be appended to the results, as well as those of any other blocks within the control.
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
}, [CONTROL_DESCRIPTION, Primitives::REFERENCE, Primitives::SOURCE_LOCATION, CONTROL_RESULT], "Describes a control and any findings it has.")
|
||||||
|
|
||||||
# Based loosely on https://docs.chef.io/inspec/profiles/ as of July 3, 2019
|
# Based loosely on https://docs.chef.io/inspec/profiles/ as of July 3, 2019
|
||||||
# However, concessions were made to the reality of current reporters, specifically
|
# However, concessions were made to the reality of current reporters, specifically
|
||||||
# with how description is omitted and version/inspec_version aren't as advertised online
|
# with how description is omitted and version/inspec_version aren't as advertised online
|
||||||
|
@ -112,6 +142,40 @@ module Inspec
|
||||||
},
|
},
|
||||||
}, [CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::SUPPORT], "Information on the set of controls assessed. Example: it can include the name of the Inspec profile and any findings.")
|
}, [CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::SUPPORT], "Information on the set of controls assessed. Example: it can include the name of the Inspec profile and any findings.")
|
||||||
|
|
||||||
|
ENHANCED_OUTCOME_PROFILE = Primitives::SchemaType.new("Exec JSON Profile", {
|
||||||
|
"type" => "object",
|
||||||
|
"additionalProperties" => true,
|
||||||
|
"required" => %w{name sha256 supports attributes groups controls},
|
||||||
|
# Name is mandatory in inspec.yml.
|
||||||
|
# supports, controls, groups, and attributes are always present, even if empty
|
||||||
|
# sha256, status, status_message
|
||||||
|
"properties" => {
|
||||||
|
# These are provided in inspec.yml
|
||||||
|
"name" => Primitives.desc(Primitives::STRING, "The name - must be unique."),
|
||||||
|
"title" => Primitives.desc(Primitives::STRING, "The title - should be human readable."),
|
||||||
|
"maintainer" => Primitives.desc(Primitives::STRING, "The maintainer(s)."),
|
||||||
|
"copyright" => Primitives.desc(Primitives::STRING, "The copyright holder(s)."),
|
||||||
|
"copyright_email" => Primitives.desc(Primitives::STRING, "The email address or other contact information of the copyright holder(s)."),
|
||||||
|
"depends" => Primitives.desc(Primitives.array(Primitives::DEPENDENCY.ref), "The set of dependencies this profile depends on. Example: an overlay profile is dependent on another profile."),
|
||||||
|
"parent_profile" => Primitives.desc(Primitives::STRING, "The name of the parent profile if the profile is a dependency of another."),
|
||||||
|
"license" => Primitives.desc(Primitives::STRING, "The copyright license. Example: the full text or the name, such as 'Apache License, Version 2.0'."),
|
||||||
|
"summary" => Primitives.desc(Primitives::STRING, "The summary. Example: the Security Technical Implementation Guide (STIG) header."),
|
||||||
|
"version" => Primitives.desc(Primitives::STRING, "The version of the profile."),
|
||||||
|
"supports" => Primitives.desc(Primitives.array(Primitives::SUPPORT.ref), "The set of supported platform targets."),
|
||||||
|
"description" => Primitives.desc(Primitives::STRING, "The description - should be more detailed than the summary."),
|
||||||
|
"inspec_version" => Primitives.desc(Primitives::STRING, "The version of Inspec."),
|
||||||
|
|
||||||
|
# These are generated at runtime, and all except status_message and skip_message are guaranteed
|
||||||
|
"sha256" => Primitives.desc(Primitives::STRING, "The checksum of the profile."),
|
||||||
|
"status" => Primitives.desc(Primitives::STRING, "The status. Example: loaded."), # enum? loaded, failed, skipped
|
||||||
|
"status_message" => Primitives.desc(Primitives::STRING, "The reason for the status. Example: why it was skipped or failed to load."),
|
||||||
|
"skip_message" => Primitives.desc(Primitives::STRING, "The reason for skipping if it was skipped."), # Deprecated field - status_message should be used instead.
|
||||||
|
"controls" => Primitives.desc(Primitives.array(CONTROL.ref), "The set of controls including any findings."),
|
||||||
|
"groups" => Primitives.desc(Primitives.array(Primitives::CONTROL_GROUP.ref), "A set of descriptions for the control groups. Example: the ids of the controls."),
|
||||||
|
"attributes" => Primitives.desc(Primitives.array(Primitives::INPUT), "The input(s) or attribute(s) used in the run."),
|
||||||
|
},
|
||||||
|
}, [ENHANCED_OUTCOME_CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::SUPPORT], "Information on the set of controls assessed. Example: it can include the name of the Inspec profile and any findings.")
|
||||||
|
|
||||||
# Result of exec json. Top level value
|
# Result of exec json. Top level value
|
||||||
# TODO: Include the format of top level controls. This was omitted for lack of sufficient examples
|
# TODO: Include the format of top level controls. This was omitted for lack of sufficient examples
|
||||||
OUTPUT = Primitives::SchemaType.new("Exec JSON Output", {
|
OUTPUT = Primitives::SchemaType.new("Exec JSON Output", {
|
||||||
|
@ -125,6 +189,18 @@ module Inspec
|
||||||
"version" => Primitives.desc(Primitives::STRING, "Version number of the tool that generated the findings. Example: '4.18.108' is a version of Chef InSpec."),
|
"version" => Primitives.desc(Primitives::STRING, "Version number of the tool that generated the findings. Example: '4.18.108' is a version of Chef InSpec."),
|
||||||
},
|
},
|
||||||
}, [Primitives::PLATFORM, PROFILE, Primitives::STATISTICS], "The top level value containing all of the results.")
|
}, [Primitives::PLATFORM, PROFILE, Primitives::STATISTICS], "The top level value containing all of the results.")
|
||||||
|
|
||||||
|
ENHANCED_OUTCOME_OUTPUT = Primitives::SchemaType.new("Exec JSON Output", {
|
||||||
|
"type" => "object",
|
||||||
|
"additionalProperties" => true,
|
||||||
|
"required" => %w{platform profiles statistics version},
|
||||||
|
"properties" => {
|
||||||
|
"platform" => Primitives.desc(Primitives::PLATFORM.ref, "Information on the platform the run from the tool that generated the findings was from. Example: the name of the operating system."),
|
||||||
|
"profiles" => Primitives.desc(Primitives.array(PROFILE.ref), "Information on the run(s) from the tool that generated the findings. Example: the findings."),
|
||||||
|
"statistics" => Primitives.desc(Primitives::STATISTICS.ref, "Statistics for the run(s) from the tool that generated the findings. Example: the runtime duration."),
|
||||||
|
"version" => Primitives.desc(Primitives::STRING, "Version number of the tool that generated the findings. Example: '4.18.108' is a version of Chef InSpec."),
|
||||||
|
},
|
||||||
|
}, [Primitives::PLATFORM, ENHANCED_OUTCOME_PROFILE, Primitives::STATISTICS], "The top level value containing all of the results.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,6 +30,8 @@ module Inspec
|
||||||
"profile-json" => OutputSchema.finalize(Schema::ProfileJson::PROFILE),
|
"profile-json" => OutputSchema.finalize(Schema::ProfileJson::PROFILE),
|
||||||
"exec-json" => OutputSchema.finalize(Schema::ExecJson::OUTPUT),
|
"exec-json" => OutputSchema.finalize(Schema::ExecJson::OUTPUT),
|
||||||
"exec-jsonmin" => OutputSchema.finalize(Schema::ExecJsonMin::OUTPUT),
|
"exec-jsonmin" => OutputSchema.finalize(Schema::ExecJsonMin::OUTPUT),
|
||||||
|
"profile-json-enhanced-outcomes" => OutputSchema.finalize(Schema::ProfileJson::ENHANCED_OUTCOME_PROFILE),
|
||||||
|
"exec-json-enhanced-outcomes" => OutputSchema.finalize(Schema::ExecJson::ENHANCED_OUTCOME_OUTPUT),
|
||||||
"platforms" => PLATFORMS,
|
"platforms" => PLATFORMS,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
@ -37,7 +39,8 @@ module Inspec
|
||||||
LIST.keys
|
LIST.keys
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.json(name)
|
def self.json(name, opts)
|
||||||
|
name += "-enhanced-outcomes" if opts["enhanced_outcomes"]
|
||||||
if !LIST.key?(name)
|
if !LIST.key?(name)
|
||||||
raise("Cannot find schema #{name.inspect}.")
|
raise("Cannot find schema #{name.inspect}.")
|
||||||
elsif LIST[name].is_a?(Proc)
|
elsif LIST[name].is_a?(Proc)
|
||||||
|
|
|
@ -31,6 +31,28 @@ module Inspec
|
||||||
},
|
},
|
||||||
}, [CONTROL_DESCRIPTIONS, Primitives::REFERENCE, Primitives::SOURCE_LOCATION], "The set of all tests within the control.")
|
}, [CONTROL_DESCRIPTIONS, Primitives::REFERENCE, Primitives::SOURCE_LOCATION], "The set of all tests within the control.")
|
||||||
|
|
||||||
|
# Represents a control with enhanced outcomes status information
|
||||||
|
ENHANCED_OUTCOME_CONTROL = Primitives::SchemaType.new("Profile JSON Control", {
|
||||||
|
"type" => "object",
|
||||||
|
"additionalProperties" => true,
|
||||||
|
"required" => %w{id title desc impact tags code},
|
||||||
|
"properties" => {
|
||||||
|
"id" => Primitives.desc(Primitives::STRING, "The id."),
|
||||||
|
"title" => Primitives.desc({ "type" => %w{string null} }, "The title - is nullable."),
|
||||||
|
"desc" => Primitives.desc({ "type" => %w{string null} }, "The description for the overarching control."),
|
||||||
|
"descriptions" => Primitives.desc(CONTROL_DESCRIPTIONS.ref, "A set of additional descriptions. Example: the 'fix' text."),
|
||||||
|
"impact" => Primitives.desc(Primitives::IMPACT, "The impactfulness or severity."),
|
||||||
|
"status" => {
|
||||||
|
"enum" => %w{passed failed not_applicable not_reviewed error},
|
||||||
|
"description" => Primitives.desc(Primitives::STRING, "The enhanced outcome status of the control"),
|
||||||
|
},
|
||||||
|
"refs" => Primitives.desc(Primitives.array(Primitives::REFERENCE.ref), "The set of references to external documents."),
|
||||||
|
"tags" => Primitives.desc(Primitives::TAGS, "A set of tags - usually metadata."),
|
||||||
|
"code" => Primitives.desc(Primitives::STRING, "The raw source code of the control. Note that if this is an overlay control, it does not include the underlying source code."),
|
||||||
|
"source_location" => Primitives.desc(Primitives::SOURCE_LOCATION.ref, "The explicit location of the control within the source code."),
|
||||||
|
},
|
||||||
|
}, [CONTROL_DESCRIPTIONS, Primitives::REFERENCE, Primitives::SOURCE_LOCATION], "The set of all tests within the control.")
|
||||||
|
|
||||||
# A profile that has not been run.
|
# A profile that has not been run.
|
||||||
PROFILE = Primitives::SchemaType.new("Profile JSON Profile", {
|
PROFILE = Primitives::SchemaType.new("Profile JSON Profile", {
|
||||||
"type" => "object",
|
"type" => "object",
|
||||||
|
@ -55,6 +77,30 @@ module Inspec
|
||||||
"depends" => Primitives.desc(Primitives.array(Primitives::DEPENDENCY.ref), "The set of dependencies this profile depends on. Example: an overlay profile is dependent on another profile."), # Can have depends, but NOT a parentprofile
|
"depends" => Primitives.desc(Primitives.array(Primitives::DEPENDENCY.ref), "The set of dependencies this profile depends on. Example: an overlay profile is dependent on another profile."), # Can have depends, but NOT a parentprofile
|
||||||
},
|
},
|
||||||
}, [Primitives::SUPPORT, CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::GENERATOR], "Information on the set of controls that can be assessed. Example: it can include the name of the Inspec profile.")
|
}, [Primitives::SUPPORT, CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::GENERATOR], "Information on the set of controls that can be assessed. Example: it can include the name of the Inspec profile.")
|
||||||
|
|
||||||
|
ENHANCED_OUTCOME_PROFILE = Primitives::SchemaType.new("Profile JSON Profile", {
|
||||||
|
"type" => "object",
|
||||||
|
"additionalProperties" => true, # Anything in the yaml will be put in here. LTTODO: Make this stricter!
|
||||||
|
"required" => %w{name supports controls groups sha256},
|
||||||
|
"properties" => {
|
||||||
|
"name" => Primitives.desc(Primitives::STRING, "The name - must be unique."),
|
||||||
|
"supports" => Primitives.desc(Primitives.array(Primitives::SUPPORT.ref), "The set of supported platform targets."),
|
||||||
|
"controls" => Primitives.desc(Primitives.array(CONTROL.ref), "The set of controls - contains no findings as the assessment has not yet occurred."),
|
||||||
|
"groups" => Primitives.desc(Primitives.array(Primitives::CONTROL_GROUP.ref), "A set of descriptions for the control groups. Example: the ids of the controls."),
|
||||||
|
"inputs" => Primitives.desc(Primitives.array(Primitives::INPUT), "The input(s) or attribute(s) used to be in the run."),
|
||||||
|
"sha256" => Primitives.desc(Primitives::STRING, "The checksum of the profile."),
|
||||||
|
"status" => Primitives.desc(Primitives::STRING, "The status. Example: skipped."),
|
||||||
|
"generator" => Primitives.desc(Primitives::GENERATOR.ref, "The tool that generated this file. Example: Chef Inspec."),
|
||||||
|
"version" => Primitives.desc(Primitives::STRING, "The version of the profile."),
|
||||||
|
|
||||||
|
# Other properties possible in inspec docs, but that aren"t guaranteed
|
||||||
|
"title" => Primitives.desc(Primitives::STRING, "The title - should be human readable."),
|
||||||
|
"maintainer" => Primitives.desc(Primitives::STRING, "The maintainer(s)."),
|
||||||
|
"copyright" => Primitives.desc(Primitives::STRING, "The copyright holder(s)."),
|
||||||
|
"copyright_email" => Primitives.desc(Primitives::STRING, "The email address or other contract information of the copyright holder(s)."),
|
||||||
|
"depends" => Primitives.desc(Primitives.array(Primitives::DEPENDENCY.ref), "The set of dependencies this profile depends on. Example: an overlay profile is dependent on another profile."), # Can have depends, but NOT a parentprofile
|
||||||
|
},
|
||||||
|
}, [Primitives::SUPPORT, ENHANCED_OUTCOME_CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::GENERATOR], "Information on the set of controls that can be assessed. Example: it can include the name of the Inspec profile.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,4 +5,12 @@ module Converter
|
||||||
val = val.to_i if val =~ /^\d+$/
|
val = val.to_i if val =~ /^\d+$/
|
||||||
val
|
val
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.to_boolean(value)
|
||||||
|
if ["true", "True", "TRUE", true, "yes", "y", "YES", "Y"].include? value
|
||||||
|
true
|
||||||
|
elsif ["false", "False", "FALSE", false, "no", "n", "NO", "N"].include? value
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
24
lib/inspec/utils/podman.rb
Normal file
24
lib/inspec/utils/podman.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
require "inspec/resources/command"
|
||||||
|
|
||||||
|
module Inspec
|
||||||
|
module Utils
|
||||||
|
module Podman
|
||||||
|
def podman_running?
|
||||||
|
inspec.command("podman version").exit_status == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# Generates the template in this format using labels hash: "\"id\": {{json .ID}}, \"name\": {{json .Name}}",
|
||||||
|
def generate_go_template(labels)
|
||||||
|
(labels.map { |k, v| "\"#{k}\": {{json .#{v}}}" }).join(", ")
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_command_output(output)
|
||||||
|
require "json" unless defined?(JSON)
|
||||||
|
JSON.parse(output)
|
||||||
|
rescue JSON::ParserError => _e
|
||||||
|
warn "Could not parse the command output"
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
34
lib/inspec/utils/waivers/csv_file_reader.rb
Normal file
34
lib/inspec/utils/waivers/csv_file_reader.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
require "csv" unless defined?(CSV)
|
||||||
|
|
||||||
|
module Waivers
|
||||||
|
class CSVFileReader
|
||||||
|
def self.resolve(path)
|
||||||
|
return nil unless File.file?(path)
|
||||||
|
|
||||||
|
@headers ||= []
|
||||||
|
fetch_data(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.fetch_data(path)
|
||||||
|
waiver_data_hash = {}
|
||||||
|
CSV.foreach(path, headers: true) do |row|
|
||||||
|
row_hash = row.to_hash
|
||||||
|
@headers = row_hash.keys if @headers.empty?
|
||||||
|
control_id = row_hash["control_id"]
|
||||||
|
# delete keys and values not required in final hash
|
||||||
|
row_hash.delete("control_id")
|
||||||
|
row_hash.delete_if { |k, v| k.nil? || v.nil? }
|
||||||
|
|
||||||
|
waiver_data_hash[control_id] = row_hash if control_id && !row_hash.blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
waiver_data_hash
|
||||||
|
rescue CSV::MalformedCSVError => e
|
||||||
|
raise "Error reading InSpec waivers in CSV: #{e}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.headers
|
||||||
|
@headers
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue