mirror of
https://github.com/inspec/inspec
synced 2024-11-26 22:50:36 +00:00
Merge pull request #6559 from inspec/inspec-6-from-prime-2
Add chef-licensing, syncing from inspec-prime repo inspec-6 branch
This commit is contained in:
commit
d64488f333
96 changed files with 1640 additions and 1171 deletions
182
.expeditor/config.yml.public
Normal file
182
.expeditor/config.yml.public
Normal file
|
@ -0,0 +1,182 @@
|
|||
# Documentation available at https://expeditor.chef.io/docs/getting-started/
|
||||
---
|
||||
|
||||
product_key: inspec
|
||||
|
||||
rubygems:
|
||||
- inspec
|
||||
- inspec-core
|
||||
- inspec-bin:
|
||||
gemspec_path: ./inspec-bin/
|
||||
- inspec-core-bin:
|
||||
gemspec_path: ./inspec-bin/
|
||||
|
||||
pipelines:
|
||||
- habitat/build:
|
||||
env:
|
||||
- HAB_NONINTERACTIVE: "true"
|
||||
- HAB_NOCOLORING: "true"
|
||||
- HAB_STUDIO_SECRET_HAB_NONINTERACTIVE: "true"
|
||||
- docker/build
|
||||
- omnibus/release:
|
||||
env:
|
||||
# The git cache is corrupt more often than not. This always purges the cache.
|
||||
# https://chefio.atlassian.net/wiki/spaces/RELENGKB/pages/2204336129/Resolving+git+cache+build+errors+in+Omnibus
|
||||
- EXPIRE_CACHE: 1
|
||||
- IGNORE_ARTIFACTORY_RUBY_PROXY: true # Artifactory is throwing 500's when downloading some gems like ffi.
|
||||
- omnibus/adhoc:
|
||||
definition: .expeditor/release.omnibus.yml
|
||||
env:
|
||||
- ADHOC: true
|
||||
- EXPIRE_CACHE: 1
|
||||
- verify:
|
||||
description: Pull Request validation tests
|
||||
public: true
|
||||
env:
|
||||
- LANG: "C.UTF-8"
|
||||
- SLOW: 1
|
||||
- NO_AWS: 1
|
||||
- MT_CPU: 5
|
||||
- coverage:
|
||||
description: Unit test coverage
|
||||
# Private due to use of tokens
|
||||
trigger: pull_request
|
||||
env:
|
||||
- LANG: "C.UTF-8"
|
||||
- SLOW: 1
|
||||
- NO_AWS: 1
|
||||
- MT_CPU: 5
|
||||
# This has been disabled because it regularly hits Docker API rate limits and fails
|
||||
# - integration/resources:
|
||||
# description: Test core resources with test-kitchen.
|
||||
# definition: .expeditor/integration.resources.yml
|
||||
# trigger: pull_request
|
||||
- artifact/habitat:
|
||||
description: Execute tests against the habitat artifact
|
||||
definition: .expeditor/artifact.habitat.yml
|
||||
env:
|
||||
- HAB_NONINTERACTIVE: "true"
|
||||
- HAB_NOCOLORING: "true"
|
||||
- HAB_STUDIO_SECRET_HAB_NONINTERACTIVE: "true"
|
||||
trigger: pull_request
|
||||
|
||||
schedules:
|
||||
- name: integration_schedule
|
||||
description: Periodic Integration Testing
|
||||
cronline: "0 8 * * *"
|
||||
|
||||
slack:
|
||||
notify_channel: inspec-notify
|
||||
|
||||
github:
|
||||
delete_branch_on_merge: true
|
||||
version_tag_format: v{{version}}
|
||||
minor_bump_labels:
|
||||
- "Expeditor: Bump Minor Version"
|
||||
# allow bumping the major release via label
|
||||
major_bump_labels:
|
||||
- "Expeditor: Bump Major Version"
|
||||
|
||||
release_branches:
|
||||
- inspec-6:
|
||||
version_constraint: 6.*
|
||||
- main:
|
||||
version_constraint: 5.*
|
||||
- inspec-4:
|
||||
version_constraint: 4.*
|
||||
|
||||
changelog:
|
||||
categories:
|
||||
- "Type: New Resource": "New Resources"
|
||||
- "Type: New Feature": "New Features"
|
||||
- "Type: Enhancement": "Enhancements"
|
||||
- "Type: Bug": "Bug Fixes"
|
||||
|
||||
subscriptions:
|
||||
- workload: pull_request_merged:{{github_repo}}:{{release_branch}}:*
|
||||
actions:
|
||||
- built_in:bump_version:
|
||||
ignore_labels:
|
||||
- "Expeditor: Skip All"
|
||||
- "Expeditor: Skip Version Bump"
|
||||
only_if_modified:
|
||||
- .expeditor/*
|
||||
- docs-chef-io/*
|
||||
- etc/*
|
||||
- habitat/*
|
||||
- inspec-bin/*
|
||||
- lib/*
|
||||
- omnibus/*
|
||||
- support/*
|
||||
- tasks/*
|
||||
- test/*
|
||||
- Gemfile*
|
||||
- LICENSE
|
||||
- "*.gemspec"
|
||||
- "*.md"
|
||||
- bash:.expeditor/update_version.sh:
|
||||
only_if: built_in:bump_version
|
||||
- built_in:update_changelog:
|
||||
ignore_labels:
|
||||
- "Expeditor: Skip All"
|
||||
- "Expeditor: Skip Changelog"
|
||||
- trigger_pipeline:omnibus/adhoc:
|
||||
not_if: built_in:bump_version
|
||||
ignore_labels:
|
||||
- "Expeditor: Skip Omnibus"
|
||||
- "Expeditor: Skip All"
|
||||
- trigger_pipeline:artifact/habitat:
|
||||
only_if: built_in:bump_version
|
||||
ignore_labels:
|
||||
- "Expeditor: Skip Habitat"
|
||||
- "Expeditor: Skip All"
|
||||
- trigger_pipeline:omnibus/release:
|
||||
only_if: built_in:bump_version
|
||||
ignore_labels:
|
||||
- "Expeditor: Skip Omnibus"
|
||||
- "Expeditor: Skip All"
|
||||
- trigger_pipeline:habitat/build:
|
||||
only_if: built_in:bump_version
|
||||
ignore_labels:
|
||||
- "Expeditor: Skip Habitat"
|
||||
- "Expeditor: Skip All"
|
||||
- built_in:build_gem:
|
||||
only_if:
|
||||
- built_in:bump_version
|
||||
- workload: artifact_published:unstable:inspec:{{version_constraint}}
|
||||
actions:
|
||||
- trigger_pipeline:docker/build
|
||||
- bash:.expeditor/buildkite/wwwrelease.sh:
|
||||
post_commit: true
|
||||
- workload: artifact_published:current:inspec:{{version_constraint}}
|
||||
actions:
|
||||
- built_in:promote_docker_images
|
||||
- built_in:promote_habitat_packages
|
||||
- workload: project_promoted:{{agent_id}}:*
|
||||
actions:
|
||||
- built_in:promote_artifactory_artifact
|
||||
- workload: artifact_published:stable:inspec:{{version_constraint}}
|
||||
actions:
|
||||
- bash:.expeditor/update_dockerfile.sh
|
||||
- built_in:rollover_changelog
|
||||
- built_in:publish_rubygems
|
||||
- built_in:create_github_release
|
||||
- built_in:promote_docker_images
|
||||
- built_in:promote_habitat_packages
|
||||
- bash:.expeditor/publish-release-notes.sh:
|
||||
post_commit: true
|
||||
- purge_packages_chef_io_fastly:{{target_channel}}/inspec/latest:
|
||||
post_commit: true
|
||||
- bash:.expeditor/announce-release.sh:
|
||||
post_commit: true
|
||||
- built_in:notify_chefio_slack_channels
|
||||
- workload: pull_request_opened:{{github_repo}}:{{release_branch}}:*
|
||||
actions:
|
||||
- post_github_comment:.expeditor/templates/pull_request.mustache:
|
||||
ignore_team_members:
|
||||
- inspec/owners
|
||||
- inspec/inspec-core-team
|
||||
- built_in:github_auto_assign_author:
|
||||
only_if_team_member:
|
||||
- inspec/owners
|
||||
- inspec/inspec-core-team
|
|
@ -9,26 +9,20 @@ expeditor:
|
|||
|
||||
steps:
|
||||
|
||||
- label: lint-ruby-3.0
|
||||
- label: lint-ruby-3.1
|
||||
command:
|
||||
- RAKE_TASK=test:lint /workdir/.expeditor/buildkite/verify.sh
|
||||
expeditor:
|
||||
secrets: true
|
||||
executor:
|
||||
docker:
|
||||
image: ruby:3.0
|
||||
|
||||
- label: run-tests-ruby-2.7
|
||||
command:
|
||||
- /workdir/.expeditor/buildkite/verify.sh
|
||||
expeditor:
|
||||
executor:
|
||||
docker:
|
||||
image: ruby:2.7
|
||||
image: ruby:3.1
|
||||
|
||||
- label: run-tests-ruby-3.0
|
||||
command:
|
||||
- /workdir/.expeditor/buildkite/verify.sh
|
||||
expeditor:
|
||||
secrets: true
|
||||
executor:
|
||||
docker:
|
||||
image: ruby:3.0
|
||||
|
@ -37,6 +31,7 @@ steps:
|
|||
command:
|
||||
- /workdir/.expeditor/buildkite/verify.sh
|
||||
expeditor:
|
||||
secrets: true
|
||||
executor:
|
||||
docker:
|
||||
image: ruby:3.1
|
||||
|
@ -45,6 +40,7 @@ steps:
|
|||
command:
|
||||
- RAKE_TASK=test:isolated /workdir/.expeditor/buildkite/verify.sh
|
||||
expeditor:
|
||||
secrets: true
|
||||
executor:
|
||||
docker:
|
||||
image: ruby:3.0
|
||||
|
@ -53,6 +49,7 @@ steps:
|
|||
command:
|
||||
- RAKE_TASK=test:isolated /workdir/.expeditor/buildkite/verify.sh
|
||||
expeditor:
|
||||
secrets: true
|
||||
executor:
|
||||
docker:
|
||||
image: ruby:3.1
|
||||
|
@ -61,6 +58,7 @@ steps:
|
|||
command:
|
||||
- /workdir/.expeditor/buildkite/verify.ps1
|
||||
expeditor:
|
||||
secrets: true
|
||||
executor:
|
||||
docker:
|
||||
environment:
|
||||
|
|
58
CHANGELOG.md
58
CHANGELOG.md
|
@ -1,21 +1,61 @@
|
|||
# Change Log
|
||||
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
|
||||
<!-- latest_release unreleased -->
|
||||
## Unreleased
|
||||
|
||||
<!-- latest_release 6.4.33 -->
|
||||
## [v6.4.33](https://github.com/inspec/inspec-prime/tree/v6.4.33) (2023-07-07)
|
||||
|
||||
#### Merged Pull Requests
|
||||
- inspec-6 CI - Add secrets: true to private verify pipeline, delete ruby 2.7 config [#6558](https://github.com/inspec/inspec/pull/6558) ([clintoncwolfe](https://github.com/clintoncwolfe))
|
||||
- forcing private in the configuration file [#6556](https://github.com/inspec/inspec/pull/6556) ([sean-simmons-progress](https://github.com/sean-simmons-progress))
|
||||
- Adds test for licensing_config [#57](https://github.com/inspec/inspec-prime/pull/57) ([Vasu1105](https://github.com/Vasu1105))
|
||||
|
||||
<!-- latest_release -->
|
||||
|
||||
<!-- release_rollup since=5.18.14 -->
|
||||
### Changes since 5.18.14 release
|
||||
|
||||
#### Merged Pull Requests
|
||||
- inspec-6 CI - Add secrets: true to private verify pipeline, delete ruby 2.7 config [#6558](https://github.com/inspec/inspec/pull/6558) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.2.46 -->
|
||||
- forcing private in the configuration file [#6556](https://github.com/inspec/inspec/pull/6556) ([sean-simmons-progress](https://github.com/sean-simmons-progress)) <!-- 6.2.46 -->
|
||||
- Privatize verify pipeline [#6555](https://github.com/inspec/inspec/pull/6555) ([sean-simmons-progress](https://github.com/sean-simmons-progress)) <!-- 6.2.46 -->
|
||||
- Prep CI system for inspec-prime merge [#6553](https://github.com/inspec/inspec/pull/6553) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.2.45 -->
|
||||
- inspec-6 CI - Add secrets: true to private verify pipeline, delete ruby 2.7 config [#6558](https://github.com/inspec/inspec/pull/6558) ([clintoncwolfe](https://github.com/clintoncwolfe))
|
||||
- forcing private in the configuration file [#6556](https://github.com/inspec/inspec/pull/6556) ([sean-simmons-progress](https://github.com/sean-simmons-progress))
|
||||
- Adds test for licensing_config [#57](https://github.com/inspec/inspec-prime/pull/57) ([Vasu1105](https://github.com/Vasu1105)) <!-- 6.4.33 -->
|
||||
- Configure to use `Inspec::Log` in Chef Licensing [#67](https://github.com/inspec/inspec-prime/pull/67) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.32 -->
|
||||
- Crossport public 6549: Drop testing on EOL ruby 2.7, and run linter on Ruby 3.1 [#76](https://github.com/inspec/inspec-prime/pull/76) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.31 -->
|
||||
- Case correction of product name in licensing config [#78](https://github.com/inspec/inspec-prime/pull/78) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.30 -->
|
||||
- Foreport - Add postgres support for custom port with a socket connection [#40](https://github.com/inspec/inspec-prime/pull/40) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.29 -->
|
||||
- Bump omnibus-software from `88169e3` to `4b08f0b` in /omnibus [#73](https://github.com/inspec/inspec-prime/pull/73) ([dependabot[bot]](https://github.com/dependabot[bot])) <!-- 6.4.28 -->
|
||||
- CHEF-3759 Crossport public 6540 Fix for inspec parallel on windows crashing due to error log rename [#74](https://github.com/inspec/inspec-prime/pull/74) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.27 -->
|
||||
- Foreports #6526 and #6541: Update Docker base image to be ubuntu 22.04 [#64](https://github.com/inspec/inspec-prime/pull/64) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.26 -->
|
||||
- Crossport Public 6545 Fix for InSpec Parallel hangs on certain CIS profiles [#71](https://github.com/inspec/inspec-prime/pull/71) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.26 -->
|
||||
- Bump omnibus from `15122f2` to `9c0643a` in /omnibus [#70](https://github.com/inspec/inspec-prime/pull/70) ([dependabot[bot]](https://github.com/dependabot[bot])) <!-- 6.4.25 -->
|
||||
- Bump berkshelf from 8.0.2 to 8.0.7 in /omnibus [#63](https://github.com/inspec/inspec-prime/pull/63) ([dependabot[bot]](https://github.com/dependabot[bot])) <!-- 6.4.24 -->
|
||||
- Foreport #6523: Update RSpec to 3.12 [#65](https://github.com/inspec/inspec-prime/pull/65) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.23 -->
|
||||
- Bump omnibus from `cf97613` to `15122f2` in /omnibus [#62](https://github.com/inspec/inspec-prime/pull/62) ([dependabot[bot]](https://github.com/dependabot[bot])) <!-- 6.4.22 -->
|
||||
- Bump omnibus-software from `225e357` to `88169e3` in /omnibus [#61](https://github.com/inspec/inspec-prime/pull/61) ([dependabot[bot]](https://github.com/dependabot[bot])) <!-- 6.4.21 -->
|
||||
- CHEF-3704 Modify help for local licensing service mode and other distros [#59](https://github.com/inspec/inspec-prime/pull/59) ([Nik08](https://github.com/Nik08)) <!-- 6.4.20 -->
|
||||
- restrict license commands only to inspec distro [#58](https://github.com/inspec/inspec-prime/pull/58) ([sathish-progress](https://github.com/sathish-progress)) <!-- 6.4.19 -->
|
||||
- CHEF-3184 Error handling for inspec license add command - disabled in local mode [#52](https://github.com/inspec/inspec-prime/pull/52) ([Nik08](https://github.com/Nik08)) <!-- 6.4.18 -->
|
||||
- CHEF-3403: Default server URL to production value [#50](https://github.com/inspec/inspec-prime/pull/50) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.17 -->
|
||||
- CHEF-3186: Remove fetching of bearer auth token from vault [#48](https://github.com/inspec/inspec-prime/pull/48) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.16 -->
|
||||
- CHEF 83 Revert attestations changes [#47](https://github.com/inspec/inspec-prime/pull/47) ([sathish-progress](https://github.com/sathish-progress)) <!-- 6.4.15 -->
|
||||
- Foreports 6489 (CHEF-1458 Multiple values changes in SimpleConfig library) [#28](https://github.com/inspec/inspec-prime/pull/28) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.14 -->
|
||||
- Foreport - Add nftables resources (#6499) [#44](https://github.com/inspec/inspec-prime/pull/44) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.13 -->
|
||||
- Foreport - Update host resource to resolve all ipaddresses (#6481) [#39](https://github.com/inspec/inspec-prime/pull/39) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.12 -->
|
||||
- Foreport - Bump rack from 2.2.6.2 to 2.2.6.4 in /omnibus (#6490) [#42](https://github.com/inspec/inspec-prime/pull/42) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.11 -->
|
||||
- Foreport - fix: ensure Invoke-WebRequest headers can be configured (#6484) [#41](https://github.com/inspec/inspec-prime/pull/41) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.10 -->
|
||||
- Foreport - CHEF-2438 Add train-kubernetes to inspec gemspec (#6512) [#43](https://github.com/inspec/inspec-prime/pull/43) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.9 -->
|
||||
- Foreport - Clarify key_rsa docs regarding SSH keys (#6507) [#45](https://github.com/inspec/inspec-prime/pull/45) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.8 -->
|
||||
- CHEF-3105 Fix windows openssl issue [#37](https://github.com/inspec/inspec-prime/pull/37) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.4.7 -->
|
||||
- CHEF-2743: Set chef executable name to display in help messages of chef-licensing [#34](https://github.com/inspec/inspec-prime/pull/34) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.6 -->
|
||||
- CHEF-2994: Add license command to list of allowed commands [#35](https://github.com/inspec/inspec-prime/pull/35) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.5 -->
|
||||
- CHEF-1957: Update chef-licesing api call `license_keys` to `fetch_and_persist` [#30](https://github.com/inspec/inspec-prime/pull/30) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.4 -->
|
||||
- Remove kitchen group from Gemfile [#31](https://github.com/inspec/inspec-prime/pull/31) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.3 -->
|
||||
- CHEF-52: Add licensing information to help output [#27](https://github.com/inspec/inspec-prime/pull/27) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.2 -->
|
||||
- Add command to list license information [#10](https://github.com/inspec/inspec-prime/pull/10) ([ahasunos](https://github.com/ahasunos)) <!-- 6.4.1 -->
|
||||
- Licensing - Integrates Software Entitlement [#13](https://github.com/inspec/inspec-prime/pull/13) ([Vasu1105](https://github.com/Vasu1105)) <!-- 6.4.0 -->
|
||||
- Integration of chef licensing with inspec [#12](https://github.com/inspec/inspec-prime/pull/12) ([Nik08](https://github.com/Nik08)) <!-- 6.3.0 -->
|
||||
- CI - Use License Key and API Key Secrets from Vault [#26](https://github.com/inspec/inspec-prime/pull/26) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.2.49 -->
|
||||
- Update Gemfile to add artifactory as source for chef-licensing gem dependency [#25](https://github.com/inspec/inspec-prime/pull/25) ([Vasu1105](https://github.com/Vasu1105)) <!-- 6.2.48 -->
|
||||
- testing version bump and pipeline creation [#16](https://github.com/inspec/inspec-prime/pull/16) ([sean-simmons-progress](https://github.com/sean-simmons-progress)) <!-- 6.2.47 -->
|
||||
- CHEF-1267 Add omnibus release and adhoc pipelines [#15](https://github.com/inspec/inspec-prime/pull/15) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 6.2.46 -->
|
||||
- testing version bump [#9](https://github.com/inspec/inspec-prime/pull/9) ([sean-simmons-progress](https://github.com/sean-simmons-progress)) <!-- 6.2.45 -->
|
||||
- Forport 6388 [#6477](https://github.com/inspec/inspec/pull/6477) ([Vasu1105](https://github.com/Vasu1105)) <!-- 6.2.44 -->
|
||||
- Foreport 6360 [#6476](https://github.com/inspec/inspec/pull/6476) ([Vasu1105](https://github.com/Vasu1105)) <!-- 6.2.43 -->
|
||||
- Foreport-6423 [#6474](https://github.com/inspec/inspec/pull/6474) ([Vasu1105](https://github.com/Vasu1105)) <!-- 6.2.42 -->
|
||||
|
@ -5171,4 +5211,4 @@
|
|||
- make default rake tasks test+lint [\#108](https://github.com/chef/inspec/pull/108) ([arlimus](https://github.com/arlimus))
|
||||
- Improve unit tests [\#106](https://github.com/chef/inspec/pull/106) ([chris-rock](https://github.com/chris-rock))
|
||||
- add to\_s methods to resources, fixes \#98 [\#105](https://github.com/chef/inspec/pull/105) ([chris-rock](https://github.com/chris-rock))
|
||||
- 0.7.0 release [\#104](https://github.com/chef/inspec/pull/104) ([chris-rock](https://github.com/chris-rock))
|
||||
- 0.7.0 release [\#104](https://github.com/chef/inspec/pull/104) ([chris-rock](https://github.com/chris-rock))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM ubuntu:18.04
|
||||
FROM --platform=linux/amd64 ubuntu:22.04
|
||||
LABEL maintainer="Chef Software, Inc. <docker@chef.io>"
|
||||
|
||||
ARG VERSION=5.18.14
|
||||
|
|
17
Gemfile
17
Gemfile
|
@ -48,19 +48,6 @@ group :deploy do
|
|||
gem "inquirer"
|
||||
end
|
||||
|
||||
group :kitchen do
|
||||
gem "berkshelf"
|
||||
|
||||
# Chef 18 requires ruby 3
|
||||
if Gem.ruby_version >= Gem::Version.new("3.0.0")
|
||||
gem "chef", ">= 17.0"
|
||||
else
|
||||
# Ruby 2.7 presumably - TODO remove this when 2.7 is sunsetted
|
||||
gem "chef", "~> 16.0"
|
||||
end
|
||||
|
||||
gem "test-kitchen", ">= 2.8"
|
||||
gem "kitchen-inspec", ">= 2.0"
|
||||
gem "kitchen-dokken", ">= 2.11"
|
||||
gem "git"
|
||||
source "https://artifactory-internal.ps.chef.co/artifactory/api/gems/omnibus-gems-local/" do
|
||||
gem "chef-licensing"
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Chef InSpec: Inspect Your Infrastructure
|
||||
|
||||
|
||||
* **Project State: Active**
|
||||
* **Issues Response SLA: 14 business days**
|
||||
* **Pull Request Response SLA: 14 business days**
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
6.2.46
|
||||
6.4.33
|
|
@ -1,82 +0,0 @@
|
|||
# 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`, `CSV`, or `JSON`.
|
||||
|
||||
#### YAML and JSON
|
||||
|
||||
An array of Hashes.
|
||||
|
||||
#### CSV
|
||||
|
||||
CSV 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.
|
|
@ -1,179 +0,0 @@
|
|||
+++
|
||||
title = "Attestations"
|
||||
draft = false
|
||||
gh_repo = "inspec"
|
||||
|
||||
[menu]
|
||||
[menu.inspec]
|
||||
title = "Attestations"
|
||||
identifier = "inspec/reference/attestations.md Attestations"
|
||||
parent = "inspec/reference"
|
||||
weight = 140
|
||||
+++
|
||||
|
||||
Attestations is a mechanism to mark the `Not Reviewed (N/R)` tests as `passed` or `failed` manually using an attestations file.
|
||||
|
||||
## Example
|
||||
|
||||
A fire alarm needs to be audited, but it cannot be reviewed (N/R) through automation. Hence, to audit the fire alarm using an InSpec profile, the outcome of its working must be marked as `passed` or `failed` in a test through manual intervention. By using attestations and passing the status using an attestations file, we can audit the fire alarm.
|
||||
|
||||
### Attestations File to an audit fire alarm
|
||||
|
||||
```yaml
|
||||
fire-alarm-1:
|
||||
expiration_date: 2090-10-1
|
||||
status: passed
|
||||
justification: "Fire alarm 1 was tested manually and it works."
|
||||
fire-alarm-2:
|
||||
expiration_date: 2090-10-1
|
||||
status: failed
|
||||
justification: "Fire alarm 2 was tested manually and it does not work."
|
||||
```
|
||||
|
||||
### InSpec Test
|
||||
|
||||
```ruby
|
||||
control "fire-alarm-1" do
|
||||
only_if("Fire alarm 1 needs to be tested manually") {
|
||||
false
|
||||
}
|
||||
end
|
||||
|
||||
control "fire-alarm-2" do
|
||||
only_if("Fire alarm 2 needs to be tested manually") {
|
||||
false
|
||||
}
|
||||
end
|
||||
```
|
||||
|
||||
### Running attestations to an audit fire alarm
|
||||
|
||||
```bash
|
||||
inspec exec path/to/fire-alarm-audit-profile --attestation-file attestation.yaml
|
||||
|
||||
Profile: InSpec Profile (attestation)
|
||||
Version: 0.1.0
|
||||
Target: local://
|
||||
Target ID: fa3923b9-f806-4cc2-960d-1ddefb4c7654
|
||||
|
||||
✔ fire-alarm-1: No-op (1 skipped)
|
||||
↺ Skipped control due to only_if condition: Fire alarm 1 needs to be tested manually
|
||||
✔ Control Attested : Fire alarm 1 was tested manually and it works.
|
||||
× fire-alarm-2: No-op (1 failed) (1 skipped)
|
||||
↺ Skipped control due to only_if condition: Fire alarm 2 needs to be tested manually
|
||||
× Control Attested : Fire alarm 2 was tested manually and it does not work.
|
||||
|
||||
|
||||
Profile Summary: 1 successful control, 1 control failure, 0 controls not reviewed, 0 controls not applicable, 0 controls have error
|
||||
Test Summary: 1 successful, 1 failure, 2 skipped
|
||||
```
|
||||
|
||||
## Attestations Fields
|
||||
|
||||
An attestations file identifies:
|
||||
|
||||
1. the controls need to be attested.
|
||||
1. an explanation of why it is manually attested.
|
||||
1. control status `passed` or `failed` to attest controls.
|
||||
1. (optional) an URL pointing to a website containing information on control attestation.
|
||||
1. (optional) an expiration date of attestation.
|
||||
|
||||
## Usage
|
||||
|
||||
To use attestations, you must have a correctly formatted attestations file and
|
||||
invoke `inspec exec` with `--attestation-file [path]`.
|
||||
|
||||
```bash
|
||||
inspec exec path/to/profile --attestation-file attestation.yaml
|
||||
```
|
||||
|
||||
## File Format
|
||||
|
||||
Attestations files support YAML, JSON, and CSV formats.
|
||||
|
||||
```yaml
|
||||
control_id:
|
||||
expiration_date: YYYY-MM-DD
|
||||
status: passed
|
||||
justification: "reason for attesting this control"
|
||||
evidence_url: "URL pointing to a website containing information on control attestation"
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
```json
|
||||
{
|
||||
"control_id": {
|
||||
"expiration_date": "YYYY-MM-DD",
|
||||
"status": "passed",
|
||||
"justification": "reason for attesting this control",
|
||||
"evidence_url": "URL pointing to a website containing information on control attestation"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `status` is mandatory. If absent, the control will not be attested. It can only be `passed` or `failed`.
|
||||
- `expiration_date` sets the day the attestations file expires in **YYYY-MM-DD** format. Attestations files expire at 00:00 at the local time of the system on the specified date. Attestations files without expiration date are permanent. `expiration_date` is optional.
|
||||
- `justification` is a text containing the reason why attestations is required. It might as well as include information on who initiated the attestation. If it is absent, it shows a warning message to include justification in the attestations file.
|
||||
- `evidence_url` is an URL of a website containing information on control attestation. It is optional.
|
||||
|
||||
### File Format Examples
|
||||
|
||||
#### Example in YAML
|
||||
|
||||
```yaml
|
||||
example-3.0.1:
|
||||
justification: "Passed by the auditor manually"
|
||||
evidence_url: "https://www.attestation-info-chef-example/"
|
||||
expiration_date: 2050-06-01
|
||||
status: passed
|
||||
example-3.0.2:
|
||||
justification: "Failed by the auditor manually"
|
||||
evidence_url: "https://www.attestation-info-chef-example/"
|
||||
expiration_date: 2050-07-01
|
||||
status: failed
|
||||
```
|
||||
|
||||
#### Example in JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"example-3.0.1": {
|
||||
"justification": "Passed by the auditor manually",
|
||||
"evidence_url": "https://www.attestation-info-chef-example/",
|
||||
"expiration_date": "2050-06-01",
|
||||
"status": "passed"
|
||||
},
|
||||
"example-3.0.2": {
|
||||
"justification": "Failed by the auditor manually",
|
||||
"evidence_url": "https://www.attestation-info-chef-example/",
|
||||
"expiration_date": "2050-07-01",
|
||||
"status": "failed"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Example in CSV
|
||||
|
||||
These file formats support the following fields in a file:
|
||||
|
||||
- `control_id`
|
||||
_Required_.
|
||||
- `justification`
|
||||
_Required_.
|
||||
- `status`
|
||||
_Required_.
|
||||
- `evidence_url`
|
||||
_Optional_.
|
||||
- `expiration_date`
|
||||
_Optional_.
|
||||
|
||||
![Attestations File Example](/images/inspec/attestations_file_excel.png)
|
||||
|
||||
{{< note >}}
|
||||
|
||||
How is the Attestations mechanism different than Waivers?
|
||||
|
||||
The waivers mechanism skips the controls for various reasons which are required for waiving. Whereas attestations mark the skipped controls which are not reviewed as `passed` or `failed` using the status passed through the attestations file by the auditor.
|
||||
|
||||
{{< /note >}}
|
|
@ -13,7 +13,7 @@ platform = "os"
|
|||
|
||||
Use the `key_rsa` Chef InSpec audit resource to test RSA public/private keypairs.
|
||||
|
||||
This resource is mainly useful when used in conjunction with the x509_certificate resource but it can also be used for checking SSH keys.
|
||||
This resource is mainly useful when used in conjunction with the x509_certificate resource, but it can also be used for checking RSA-based SSH keys.
|
||||
|
||||
## Availability
|
||||
|
||||
|
|
140
docs-chef-io/content/inspec/resources/nftables.md
Normal file
140
docs-chef-io/content/inspec/resources/nftables.md
Normal file
|
@ -0,0 +1,140 @@
|
|||
+++
|
||||
title = "nftables resource"
|
||||
draft = false
|
||||
gh_repo = "inspec"
|
||||
platform = "linux"
|
||||
|
||||
[menu]
|
||||
[menu.inspec]
|
||||
title = "nftables"
|
||||
identifier = "inspec/resources/os/nftables.md nftables resource"
|
||||
parent = "inspec/resources/os"
|
||||
+++
|
||||
|
||||
Use the `nftables` Chef InSpec audit resource to test rules and sets that are defined using `nftables`, which maintains tables of IP packet filtering rules. There may be more than one table. Each table contains one (or more) chains. A chain is a list of rules that match packets. When a rule matches a packet, the rule defines what target to assign to the packet.
|
||||
|
||||
## Availability
|
||||
|
||||
### Installation
|
||||
|
||||
{{% inspec/inspec_installation %}}
|
||||
|
||||
### Version
|
||||
|
||||
This resource first became available in v5.21.30 of InSpec.
|
||||
|
||||
## Syntax
|
||||
|
||||
A `nftables` resource block declares tests for rules in IP tables:
|
||||
|
||||
```ruby
|
||||
describe nftables(family:'name', table:'name', chain: 'name') do
|
||||
its('PROPERTY') { should eq 'value' }
|
||||
it { should have_rule('RULE') }
|
||||
end
|
||||
|
||||
describe nftables(family:'name', table:'name', set: 'name') do
|
||||
its('PROPERTY') { should eq 'value' }
|
||||
it { should have_element('ELEMENT') }
|
||||
end
|
||||
```
|
||||
|
||||
where
|
||||
|
||||
- `nftables()` has to specify `family` and `table`. It also has to specify one of `chain` or `set` (exclusively).
|
||||
- `family:'name'` is the name of the `family` the table belongs to, one of `ip`, `ip6`, `inet`, `arp`, `bridge`, `netdev`.
|
||||
- `table:'name'` is the packet matching table against which the test is run.
|
||||
- `chain: 'name'` is the name of a user-defined chain.
|
||||
- `set: 'name'` is the name of a user-defined named set.
|
||||
- `have_rule('RULE')` tests that the chain has a given rule in the nftables ruleset. This must match the entire line taken from `nftables -nn list chain FAMILY TABLE CHAIN`.
|
||||
- `have_element('ELEMENT')` tests that element is a member of the nftables named set.
|
||||
|
||||
See the [NFT man page](https://www.netfilter.org/projects/nftables/manpage.html) and [nftables wiki](https://wiki.nftables.org/wiki-nftables/index.php/Main_Page) for more information about nftables.
|
||||
|
||||
## Properties
|
||||
|
||||
### Chain Properties
|
||||
|
||||
`hook`
|
||||
: The hook type. Possible values: `ingress`, `prerouting`, `forward`, `input`, `output`, `postrouting`, and `egress`.
|
||||
|
||||
`prio`
|
||||
: The numerical chain priority.
|
||||
|
||||
`policy`
|
||||
: The policy type. Possible values: `accept`, `drop`.
|
||||
|
||||
`type`
|
||||
: The chain type. Possible values: `filter`, `nat`, and `route`.
|
||||
|
||||
### Set Properties
|
||||
|
||||
`flags`
|
||||
: The set flags. Possible values: `constant`, `dynamic`, `interval`, and `timeout`.
|
||||
|
||||
`size`
|
||||
: The maximum number of elements in the set.
|
||||
|
||||
`type`
|
||||
: The data type of set elements. Possible values: `ipv4_addr`, `ipv6_addr`, `ether_addr`, `inet_proto`, `inet_service`, and `mark`.
|
||||
|
||||
## Examples
|
||||
|
||||
The following examples show how to use this Chef InSpec audit resource.
|
||||
|
||||
### Test if the `CHAIN_NAME` chain from the `TABLE_NAME` table has the default `accept` policy
|
||||
|
||||
```ruby
|
||||
describe nftables(family: 'inet', table: 'TABLE_NAME', chain: 'CHAIN_NAME') do
|
||||
its('policy') { should eq 'accept' }
|
||||
end
|
||||
```
|
||||
|
||||
### Test the attributes of the `CHAIN_NAME` chain from the `TABLE_NAME` table
|
||||
|
||||
```ruby
|
||||
describe nftables(family: 'inet', table: 'mangle', chain: 'INPUT') do
|
||||
its('type') { should eq 'filter' }
|
||||
its('hook') { should eq 'input' }
|
||||
its('prio') { should eq (-150) } # mangle
|
||||
its('policy') { should eq 'accept' }
|
||||
end
|
||||
```
|
||||
|
||||
### Test if there is a rule allowing Postgres (5432/TCP) traffic
|
||||
|
||||
```ruby
|
||||
describe nftables(family: 'inet', table: 'TABLE_NAME', chain: 'CHAIN_NAME') do
|
||||
it { should have_rule('tcp dport 5432 comment "postgres" accept') }
|
||||
end
|
||||
```
|
||||
|
||||
Note that the rule specification must exactly match what's in the output of `nftables -nn list chain inet TABLE_NAME CHAIN_NAME`, which will depend on how you've built your rules.
|
||||
|
||||
### Test if there is an element `1.1.1.1` in the `SET_NAME` named set
|
||||
|
||||
```ruby
|
||||
describe nftables(family: 'inet', table: 'TABLE_NAME', set: 'SET_NAME') do
|
||||
it { should have_element('1.1.1.1') }
|
||||
end
|
||||
```
|
||||
|
||||
## Matchers
|
||||
|
||||
For a full list of available matchers, please visit our [matchers page](/inspec/matchers/).
|
||||
|
||||
### have_rule
|
||||
|
||||
The `have_rule` matcher tests the named rule against the information in the `nftables` ruleset:
|
||||
|
||||
```ruby
|
||||
it { should have_rule('RULE') }
|
||||
```
|
||||
|
||||
### have_element
|
||||
|
||||
The `have_element` matcher tests the named set against the information in the `nftables` ruleset:
|
||||
|
||||
```ruby
|
||||
it { should have_element('SET_ELEMENT') }
|
||||
```
|
|
@ -11,6 +11,7 @@ gh_repo = "inspec"
|
|||
weight = 140
|
||||
+++
|
||||
|
||||
|
||||
Waivers allow you to waive controls and to dictate the running and/or reporting of those controls. A waiver file identifies:
|
||||
|
||||
1. which controls are waived
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
|
@ -1,6 +1,6 @@
|
|||
KsCa3OgmGAdfLvm0JOqzILc2SUL3FKTQ+XCpaFLiiwefhhKirl+ddcpj10g7
|
||||
rtufpHQal6qoQ8PoCP4BBLOtrShyXYhOBqoQXLNiMYQAEdWTobOIz6naicE/
|
||||
z23mweizu3C4qS4yG5hz4BwNhWSTVFrkhQZaF6KS5mMBHrULCV3i7Fs0BFWy
|
||||
lhO3NS9GXaD+1RSKcTsUWTuNlK2R0TWqHgWiDDy+P80XFW3DvBjPweRyghJa
|
||||
sW+5fwMYGyZPULt8lx8U8Ec05XQiIxeneosRGtdvjIh7JzhJr/UXJsIMhJvV
|
||||
eNWfNJrWJkzzeeSXVV3E/VeYBhZGkI5ra5guf05Ifw==
|
||||
wNEzKHmtSf1pIdciEC6DOs5SlOs3IbW1psVFLlmZc0NbnHe6MEahAnKWmHUP
|
||||
9YrDv2JMQo1I8MM/cez8XDxpK4O5y4HT66RqoAlfBkg82LmYC7f1Cy34ByCj
|
||||
LBZg5o/IVBGnY+Ksbhtp0mQYEyU048FnXIfh9uOfbKahU8HkPJssTkIw3fjL
|
||||
Vrd5GQ4ssfW1XXFaxx7DjxWlPmWBVhd8c1Y2RlACZyI+w1DQNYimrWvgiFym
|
||||
0VbnndiSX+2x84AZHE9AmsebcAYk9QlqO1N0VeYqBZj45FXLtpsNwYo0amDa
|
||||
D/wyKGxRQLUYXyd2tDVJMWbeHPHy8UIK17RoSctrEg==
|
||||
|
|
|
@ -82,8 +82,6 @@
|
|||
description: Use JUnit2 reporter.
|
||||
inspec-reporter-html2:
|
||||
description: Use HTML reporter.
|
||||
inspec-attestations:
|
||||
description: Use attestations mechanism with one or more attestations files.
|
||||
inspec-reporter-progress-bar:
|
||||
description: Use progress bar streaming reporter
|
||||
inspec-reporter-child-status:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# This file managed by automation - do not edit manually
|
||||
module InspecBin
|
||||
INSPECBIN_ROOT = File.expand_path("..", __dir__)
|
||||
VERSION = "6.2.46".freeze
|
||||
VERSION = "6.4.33".freeze
|
||||
end
|
||||
|
|
|
@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|||
spec.add_dependency "thor", ">= 0.20", "< 2.0"
|
||||
spec.add_dependency "method_source", ">= 0.8", "< 2.0"
|
||||
spec.add_dependency "rubyzip", ">= 1.2.2", "< 3.0"
|
||||
spec.add_dependency "rspec", ">= 3.9", "<= 3.11"
|
||||
spec.add_dependency "rspec", ">= 3.9", "<= 3.12"
|
||||
spec.add_dependency "rspec-its", "~> 1.2"
|
||||
spec.add_dependency "pry", "~> 0.13"
|
||||
spec.add_dependency "hashie", ">= 3.4", "< 5.0"
|
||||
|
|
|
@ -38,9 +38,11 @@ Gem::Specification.new do |spec|
|
|||
spec.add_dependency "faraday_middleware", ">= 0.12.2", "< 1.1"
|
||||
|
||||
# Train plugins we ship with InSpec
|
||||
spec.add_dependency "train-habitat", "~> 0.1"
|
||||
spec.add_dependency "train-aws", "~> 0.2"
|
||||
spec.add_dependency "train-winrm", "~> 0.2"
|
||||
spec.add_dependency "train-habitat", "~> 0.1"
|
||||
spec.add_dependency "train-aws", "~> 0.2"
|
||||
spec.add_dependency "train-winrm", "~> 0.2"
|
||||
spec.add_dependency "train-kubernetes", "~> 0.1"
|
||||
|
||||
spec.add_dependency "mongo", "= 2.13.2" # 2.14 introduces a broken symlink in mongo-2.14.0/spec/support/ocsp
|
||||
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
driver:
|
||||
name: dokken
|
||||
chef_version: :latest
|
||||
chef_version: 17
|
||||
privileged: true # because Docker and SystemD/Upstart
|
||||
|
||||
transport:
|
||||
|
@ -64,7 +64,7 @@ platforms:
|
|||
- name: opensuse-leap
|
||||
driver:
|
||||
image: dokken/opensuse-leap-15
|
||||
pid_one_command: /bin/systemd
|
||||
pid_one_command: /usr/lib/systemd/systemd
|
||||
|
||||
- name: ubuntu-16.04
|
||||
driver:
|
||||
|
|
|
@ -4,6 +4,7 @@ libdir = File.dirname(__FILE__)
|
|||
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
||||
|
||||
require "inspec/version"
|
||||
require "inspec/utils/licensing_config"
|
||||
require "inspec/exceptions"
|
||||
require "inspec/utils/deprecation"
|
||||
require "inspec/profile"
|
||||
|
@ -30,4 +31,4 @@ require "inspec/source_reader"
|
|||
require "inspec/resource"
|
||||
|
||||
require "inspec/dependency_loader"
|
||||
require "inspec/dependency_installer"
|
||||
require "inspec/dependency_installer"
|
|
@ -1,50 +0,0 @@
|
|||
require "inspec/secrets/yaml"
|
||||
require "inspec/utils/waivers/csv_file_reader"
|
||||
require "inspec/utils/waivers/json_file_reader"
|
||||
# require "inspec/utils/waivers/excel_file_reader"
|
||||
|
||||
module Inspec
|
||||
class AttestationFileReader < WaiverFileReader
|
||||
|
||||
# Invoked from rule.rb and streaming reporter base class to fetch attestation data
|
||||
def self.fetch_attestation_by_profile(profile_id, files)
|
||||
read_attestation_from_file(profile_id, files) if @attestation_data.nil? || @attestation_data[profile_id].nil?
|
||||
@attestation_data[profile_id]
|
||||
end
|
||||
|
||||
def self.read_attestation_from_file(profile_id, files)
|
||||
@attestation_data ||= {}
|
||||
output = {}
|
||||
|
||||
files.each do |file_path|
|
||||
data = read_from_file(file_path)
|
||||
output.merge!(data) if !data.nil? && data.is_a?(Hash)
|
||||
|
||||
if data.nil?
|
||||
raise Inspec::Exceptions::AttestationFileNotReadable,
|
||||
"Cannot find parser for attestation file '#{file_path}'. " \
|
||||
"Check to make sure file has the appropriate extension."
|
||||
end
|
||||
end
|
||||
|
||||
@attestation_data[profile_id] = output
|
||||
end
|
||||
|
||||
# Attestation file has different headers than waiver file
|
||||
# Overriding header validation logic of WaiverFileReader
|
||||
def self.validate_headers(headers, json_yaml = false)
|
||||
required_fields = json_yaml ? %w{status} : %w{control_id status}
|
||||
missing_cols = (required_fields - headers)
|
||||
missing_cols << "justification" if (!headers.include? "justification") && (!headers.include? "explanation")
|
||||
|
||||
Inspec::Log.warn "Missing column headers: #{missing_cols}" unless missing_cols.empty?
|
||||
Inspec::Log.warn "Invalid column header: Column can't be nil" if headers.include? nil
|
||||
Inspec::Log.warn "Extra column headers: #{(headers - all_fields)}" unless (headers - all_fields).empty?
|
||||
end
|
||||
|
||||
# defining all fields used in attestation files of different formats
|
||||
def self.all_fields
|
||||
%w{control_id justification expiration_date evidence_url status explanation frequency updated}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,155 +0,0 @@
|
|||
module Inspec
|
||||
module Attestations
|
||||
|
||||
# Invoked from reporters base classes & run_data.rb to modify run data
|
||||
def self.attest(run_data)
|
||||
run_data[:profiles].each do |profile|
|
||||
profile[:controls].each do |control|
|
||||
# logic for attestation applied for N/R controls here.
|
||||
if control[:status] == "not_reviewed" && !control[:attestation_data].empty?
|
||||
expiry = determine_expiry(control[:attestation_data], control[:id])
|
||||
# if expiration date parsing was successful
|
||||
if expiry
|
||||
control[:attestation_data]["message"] = validate_attestation_expiry(expiry, control[:id])
|
||||
attestation_result = attestation_check(control[:attestation_data]["message"], control[:attestation_data], control[:id])
|
||||
if attestation_result
|
||||
status, attestation_msg = attestation_result
|
||||
|
||||
control[:status] = status # N/R status -> to passed/failed based on attestation logic
|
||||
|
||||
# replicated test result hash to invoke pass/fail test
|
||||
control[:results].push({
|
||||
status: control[:status],
|
||||
code_desc: attestation_msg,
|
||||
expectation_message: attestation_msg,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Invoked from streaming reporter base class
|
||||
def self.attest_streaming_data(attestation_data, status, control_id)
|
||||
# logic check for N/R controls here for streaming reporters
|
||||
if status == "not_reviewed" && !attestation_data.blank?
|
||||
expiry = determine_expiry(attestation_data, control_id)
|
||||
|
||||
# if expiration date parsing was successful
|
||||
if expiry
|
||||
expiry_message = validate_attestation_expiry(expiry, control_id)
|
||||
attestation_check(expiry_message, attestation_data, control_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.validate_attestation_expiry(expiry, control_id)
|
||||
# logic to check for expiry
|
||||
|
||||
if [Date, Time].include?(expiry.class) || (expiry.is_a?(String) && Time.parse(expiry).year != 0)
|
||||
expiry = expiry.to_time if expiry.is_a? Date
|
||||
expiry = Time.parse(expiry) if expiry.is_a? String
|
||||
if expiry < Time.now # If the attestation expired, return - no attestation done
|
||||
expiry_message = "Attestation expired on #{expiry}"
|
||||
expiry_message
|
||||
end
|
||||
else
|
||||
ui = Inspec::UI.new
|
||||
ui.error("Unable to parse attestation expiration date '#{expiry}' for control #{control_id}")
|
||||
ui.exit(:usage_error)
|
||||
end
|
||||
rescue => e
|
||||
ui = Inspec::UI.new
|
||||
ui.error("Unable to parse attestation expiration date '#{expiry}' for control #{control_id}. Error: #{e.message}")
|
||||
ui.exit(:usage_error)
|
||||
end
|
||||
|
||||
def self.attestation_check(expiry_message, attestation_data, control_id)
|
||||
# logic to update enhanced outcome status
|
||||
status, msg = nil
|
||||
if %w{passed failed}.include? attestation_data["status"]
|
||||
if expiry_message
|
||||
status = "failed"
|
||||
msg = "Control not attested : #{expiry_message}"
|
||||
else
|
||||
# use justification and evidence url to show information in msg
|
||||
attestation_message = attestation_data["justification"] || attestation_data["explanation"] || ""
|
||||
|
||||
unless attestation_data["evidence_url"].blank?
|
||||
if attestation_message.blank?
|
||||
attestation_message = "Evidence URL: #{attestation_data["evidence_url"]}"
|
||||
else
|
||||
attestation_message += " | Evidence URL: #{attestation_data["evidence_url"]}"
|
||||
end
|
||||
end
|
||||
|
||||
status = attestation_data["status"]
|
||||
if attestation_message.blank?
|
||||
msg = "Control Attested : No justification provided."
|
||||
else
|
||||
msg = "Control Attested : #{attestation_message}"
|
||||
end
|
||||
end
|
||||
else
|
||||
if attestation_data["status"].blank?
|
||||
Inspec::Log.warn "No attestation status for control #{control_id}. Use 'passed' or 'failed'."
|
||||
else
|
||||
Inspec::Log.warn "Invalid attestation status '#{attestation_data["status"]}' for control #{control_id}. Use 'passed' or 'failed'."
|
||||
end
|
||||
return nil
|
||||
end
|
||||
[status, msg]
|
||||
end
|
||||
|
||||
def self.determine_expiry(attestation_data, control_id)
|
||||
if attestation_data["expiration_date"]
|
||||
attestation_data["expiration_date"]
|
||||
elsif !attestation_data["updated"].blank? && !attestation_data["frequency"].blank?
|
||||
begin
|
||||
calculate_expiry(attestation_data["updated"], attestation_data["frequency"], control_id)
|
||||
rescue => e
|
||||
ui = Inspec::UI.new
|
||||
ui.error("Unable to parse attestation updated date '#{attestation_data["updated"]}' for control #{control_id}. Error: #{e.message}")
|
||||
ui.exit(:usage_error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.calculate_expiry(updated_date, frequency, control_id)
|
||||
# logic to find expiration date using frequency and updated date.
|
||||
if updated_date.is_a?(Date) || (updated_date.is_a?(String) && Date.parse(updated_date).year != 0)
|
||||
updated_date = Date.parse(updated_date) if updated_date.is_a? String
|
||||
if updated_date < Time.now.to_date
|
||||
case frequency
|
||||
when "annually"
|
||||
updated_date.to_date.next_year(1)
|
||||
when "semiannually"
|
||||
updated_date.next_month(6)
|
||||
when "quarterly"
|
||||
updated_date.next_month(3)
|
||||
when "monthly"
|
||||
updated_date.next_month(1)
|
||||
when "every2weeks"
|
||||
updated_date.next_day(14)
|
||||
when "weekly"
|
||||
updated_date.next_day(7)
|
||||
when "every3days"
|
||||
updated_date.next_day(3)
|
||||
when "daily"
|
||||
updated_date.next_day(1)
|
||||
else
|
||||
Inspec::Log.warn "Invalid frequency value '#{frequency}' for control #{control_id}."
|
||||
updated_date
|
||||
end
|
||||
else
|
||||
updated_date
|
||||
end
|
||||
else
|
||||
ui = Inspec::UI.new
|
||||
ui.error("Unable to parse attestation updated date '#{updated_date}' for control #{control_id}")
|
||||
ui.exit(:usage_error)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +1,11 @@
|
|||
require "thor" # rubocop:disable Chef/Ruby/UnlessDefinedRequire
|
||||
require "chef-licensing"
|
||||
require "inspec/log"
|
||||
require "inspec/ui"
|
||||
require "inspec/config"
|
||||
require "inspec/dist"
|
||||
require "inspec/utils/deprecation/global_method"
|
||||
require "inspec/utils/licensing_config"
|
||||
|
||||
# Allow end of options during array type parsing
|
||||
# https://github.com/erikhuda/thor/issues/631
|
||||
|
@ -30,11 +32,34 @@ module Inspec
|
|||
end
|
||||
|
||||
def self.start(given_args = ARGV, config = {})
|
||||
check_license! if config[:enforce_license] || config[:enforce_license].nil?
|
||||
if Inspec::Dist::EXEC_NAME == "inspec"
|
||||
check_license! if config[:enforce_license] || config[:enforce_license].nil?
|
||||
fetch_and_persist_license
|
||||
end
|
||||
|
||||
super(given_args, config)
|
||||
end
|
||||
|
||||
def self.fetch_and_persist_license
|
||||
allowed_commands = ["-h", "--help", "help", "-v", "--version", "version", "license"]
|
||||
begin
|
||||
if (allowed_commands & ARGV.map(&:downcase)).empty? && !ARGV.empty?
|
||||
license_keys = ChefLicensing.fetch_and_persist
|
||||
|
||||
# Only if EULA acceptance or license key args are present. And licenses are successfully persisted, do clean exit.
|
||||
if ARGV.select { |arg| !(arg.include? "--chef-license") }.empty? && !license_keys.blank?
|
||||
Inspec::UI.new.exit
|
||||
end
|
||||
end
|
||||
rescue ChefLicensing::LicenseKeyFetcher::LicenseKeyNotFetchedError
|
||||
Inspec::Log.error "#{Inspec::Dist::PRODUCT_NAME} cannot execute without valid licenses."
|
||||
Inspec::UI.new.exit(:usage_error)
|
||||
rescue ChefLicensing::Error => e
|
||||
Inspec::Log.error e.message
|
||||
Inspec::UI.new.exit(:usage_error)
|
||||
end
|
||||
end
|
||||
|
||||
# EULA acceptance
|
||||
def self.check_license!
|
||||
allowed_commands = ["-h", "--help", "help", "-v", "--version", "version"]
|
||||
|
@ -48,9 +73,6 @@ module Inspec
|
|||
Inspec::VERSION,
|
||||
logger: Inspec::Log
|
||||
)
|
||||
if license_acceptor_output && ARGV.count == 1 && (ARGV.first.include? "--chef-license")
|
||||
Inspec::UI.new.exit
|
||||
end
|
||||
license_acceptor_output
|
||||
end
|
||||
rescue LicenseAcceptance::LicenseNotAcceptedError
|
||||
|
@ -177,8 +199,6 @@ module Inspec
|
|||
desc: "Load one or more input files, a YAML file with values for the profile to use."
|
||||
option :waiver_file, type: :array,
|
||||
desc: "Load one or more waiver files."
|
||||
option :attestation_file, type: :array,
|
||||
desc: "Load one or more attestation files."
|
||||
option :attrs, type: :array,
|
||||
desc: "Legacy name for --input-file - deprecated."
|
||||
option :create_lockfile, type: :boolean,
|
||||
|
@ -213,6 +233,30 @@ module Inspec
|
|||
|
||||
def self.help(*args)
|
||||
super(*args)
|
||||
if Inspec::Dist::EXEC_NAME == "inspec"
|
||||
puts <<~CHEF_LICENSE_HELP
|
||||
Chef Compliance has three tiers of licensing:
|
||||
|
||||
* Free-Tier
|
||||
Users are limited to audit maximum of 10 targets
|
||||
Entitled for personal or non-commercial use
|
||||
|
||||
* Trial
|
||||
Entitled for unlimited number of targets
|
||||
Entitled for 30 days only
|
||||
Entitled for commercial use
|
||||
|
||||
* Commercial
|
||||
Entitled for purchased number of targets
|
||||
Entitled for period of subscription purchased
|
||||
Entitled for commercial use
|
||||
|
||||
inspec license add: This command helps users to generate or add an additional license (not applicable to local licensing service)
|
||||
|
||||
For more information please visit:
|
||||
www.chef.io/licensing/faqs
|
||||
CHEF_LICENSE_HELP
|
||||
end
|
||||
puts "\nAbout #{Inspec::Dist::PRODUCT_NAME}:"
|
||||
puts " Patents: chef.io/patents\n\n"
|
||||
end
|
||||
|
|
|
@ -62,6 +62,11 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|||
require "license_acceptance/cli_flags/thor"
|
||||
include LicenseAcceptance::CLIFlags::Thor
|
||||
|
||||
if Inspec::Dist::EXEC_NAME == "inspec"
|
||||
require "chef-licensing/cli_flags/thor"
|
||||
include ChefLicensing::CLIFlags::Thor
|
||||
end
|
||||
|
||||
desc "json PATH", "read all tests in the PATH and generate a JSON summary."
|
||||
option :output, aliases: :o, type: :string,
|
||||
desc: "Save the created profile to a path."
|
||||
|
|
|
@ -12,7 +12,5 @@ module Inspec
|
|||
class ProfileSigningKeyNotFound < ArgumentError; end
|
||||
class WaiversFileNotReadable < ArgumentError; end
|
||||
class WaiversFileDoesNotExist < ArgumentError; end
|
||||
class AttestationFileNotReadable < ArgumentError; end
|
||||
class AttestationFileDoesNotExist < ArgumentError; end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -236,7 +236,6 @@ module Inspec::Formatters
|
|||
resource_title: example.metadata[:described_class] || example.metadata[:example_group][:description],
|
||||
expectation_message: format_expectation_message(example),
|
||||
waiver_data: example.metadata[:waiver_data],
|
||||
attestation_data: example.metadata[:attestation_data],
|
||||
# This enforces the resource name as expected based off of the class
|
||||
# name. However, if we wanted the `name` attribute against the class
|
||||
# to be canonical for this case (consider edge cases!) we would use
|
||||
|
@ -359,7 +358,6 @@ module Inspec::Formatters
|
|||
# (that is, per-describe-block) basis, because that is the only granularity
|
||||
# available to us in the RSpec report data structure which we use as a vehicle.
|
||||
control[:waiver_data] ||= example[:waiver_data] || {}
|
||||
control[:attestation_data] ||= example[:attestation_data] || {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
require "inspec/attestations"
|
||||
module Inspec::Plugin::V2::PluginType
|
||||
class StreamingReporter < Inspec::Plugin::V2::PluginBase
|
||||
register_plugin_type(:streaming_reporter)
|
||||
|
@ -14,7 +13,6 @@ module Inspec::Plugin::V2::PluginType
|
|||
@controls_count = nil
|
||||
@notifications = {}
|
||||
@enhanced_outcome_control_wise = {}
|
||||
@attestation_message_control_wise = {}
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -37,7 +35,7 @@ module Inspec::Plugin::V2::PluginType
|
|||
unless @control_checks_count_map[control_id].nil?
|
||||
@control_checks_count_map[control_id] -= 1
|
||||
control_ended = @control_checks_count_map[control_id] == 0
|
||||
# after a control has ended it checks for certain operations, like enhanced outcomes & attestations
|
||||
# after a control has ended it checks for certain operations, like enhanced outcomes
|
||||
run_control_operations(notification, control_id) if control_ended
|
||||
control_ended
|
||||
else
|
||||
|
@ -47,7 +45,6 @@ module Inspec::Plugin::V2::PluginType
|
|||
|
||||
def run_control_operations(notification, control_id)
|
||||
check_for_enhanced_outcomes(notification, control_id)
|
||||
check_for_attestation(notification, control_id)
|
||||
end
|
||||
|
||||
def check_for_enhanced_outcomes(notification, control_id)
|
||||
|
@ -57,25 +54,12 @@ module Inspec::Plugin::V2::PluginType
|
|||
end
|
||||
end
|
||||
|
||||
def check_for_attestation(notification, control_id)
|
||||
control_outcome = control_outcome(control_id)
|
||||
if control_outcome
|
||||
attestation_result = attest_control(notification, control_id, control_outcome)
|
||||
unless attestation_result.blank?
|
||||
@enhanced_outcome_control_wise[control_id] = attestation_result[0]
|
||||
@attestation_message_control_wise[control_id] = attestation_result[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def format_message(indicator, control_id, title, full_description)
|
||||
message_to_format = ""
|
||||
message_to_format += "#{indicator} "
|
||||
message_to_format += "#{control_id.to_s.strip.dup.force_encoding(Encoding::UTF_8)} "
|
||||
message_to_format += "#{title.gsub(/\n*\s+/, " ").to_s.force_encoding(Encoding::UTF_8)} " if title
|
||||
message_to_format += "#{full_description.gsub(/\n*\s+/, " ").to_s.force_encoding(Encoding::UTF_8)} " unless title
|
||||
# append attestation message if control is attested
|
||||
message_to_format += "#{@attestation_message_control_wise[control_id].gsub(/\n*\s+/, " ").to_s.force_encoding(Encoding::UTF_8)} " if @attestation_message_control_wise[control_id]
|
||||
message_to_format
|
||||
end
|
||||
|
||||
|
@ -147,23 +131,5 @@ module Inspec::Plugin::V2::PluginType
|
|||
@notifications[control_id].push([notification, status])
|
||||
end
|
||||
end
|
||||
|
||||
def attest_control(notification, control_id, control_outcome)
|
||||
status = control_outcome
|
||||
attestation_data = read_attestation_file(notification, control_id)
|
||||
Inspec::Attestations.attest_streaming_data(attestation_data, status, control_id) unless attestation_data.blank?
|
||||
end
|
||||
|
||||
def read_attestation_file(notification, control_id)
|
||||
# need to re-read the file from config since not using run data for streaming reporters.
|
||||
profile_id = notification.example.metadata[:profile_id]
|
||||
attestation_files = Inspec::Config.cached.final_options["attestation_file"] if Inspec::Config.cached.respond_to?(:final_options)
|
||||
|
||||
attestation_data_by_profile = Inspec::AttestationFileReader.fetch_attestation_by_profile(profile_id, attestation_files) unless attestation_files.nil?
|
||||
|
||||
return unless attestation_data_by_profile && attestation_data_by_profile[control_id] && attestation_data_by_profile[control_id].is_a?(Hash)
|
||||
|
||||
attestation_data_by_profile[control_id]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
require_relative "../utils/run_data_filters"
|
||||
require "inspec/attestations"
|
||||
|
||||
module Inspec::Reporters
|
||||
class Base
|
||||
|
@ -13,8 +12,6 @@ module Inspec::Reporters
|
|||
@run_data = config[:run_data] || {}
|
||||
apply_run_data_filters_to_hash
|
||||
|
||||
# only try for attestation when attestation file is passed
|
||||
Inspec::Attestations.attest(@run_data) if Inspec::Config.cached[:attestation_file]
|
||||
@output = ""
|
||||
end
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ require "inspec/resources/mssql_sys_conf"
|
|||
require "inspec/resources/mysql"
|
||||
require "inspec/resources/mysql_conf"
|
||||
require "inspec/resources/mysql_session"
|
||||
require "inspec/resources/nftables"
|
||||
require "inspec/resources/nginx"
|
||||
require "inspec/resources/nginx_conf"
|
||||
require "inspec/resources/npm"
|
||||
|
|
|
@ -319,15 +319,9 @@ module Inspec::Resources
|
|||
return nil
|
||||
end
|
||||
|
||||
resolve_ipv4 = resolve_ipv4.inject(:merge) if resolve_ipv4.is_a?(Array)
|
||||
|
||||
# Append the ipv4 addresses
|
||||
resolve_ipv4.each_value do |ip|
|
||||
matched = ip.to_s.chomp.match(Resolv::IPv4::Regex)
|
||||
next if matched.nil? || addresses.include?(matched.to_s)
|
||||
|
||||
addresses << matched.to_s
|
||||
end
|
||||
resolve_ipv4 = [resolve_ipv4] unless resolve_ipv4.is_a?(Array)
|
||||
resolve_ipv4.each { |entry| addresses << entry["IPAddress"] }
|
||||
|
||||
# -Type AAAA is the DNS query for IPv6 server Address.
|
||||
cmd = inspec.command("Resolve-DnsName –Type AAAA #{hostname} | ConvertTo-Json")
|
||||
|
@ -337,15 +331,9 @@ module Inspec::Resources
|
|||
return nil
|
||||
end
|
||||
|
||||
resolve_ipv6 = resolve_ipv6.inject(:merge) if resolve_ipv6.is_a?(Array)
|
||||
|
||||
# Append the ipv6 addresses
|
||||
resolve_ipv6.each_value do |ip|
|
||||
matched = ip.to_s.chomp.match(Resolv::IPv6::Regex)
|
||||
next if matched.nil? || addresses.include?(matched.to_s)
|
||||
|
||||
addresses << matched.to_s
|
||||
end
|
||||
resolve_ipv6 = [resolve_ipv6] unless resolve_ipv6.is_a?(Array)
|
||||
resolve_ipv6.each { |entry| addresses << entry["IPAddress"] }
|
||||
|
||||
addresses
|
||||
end
|
||||
|
|
|
@ -304,11 +304,11 @@ module Inspec::Resources
|
|||
# Insecure not supported simply https://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error
|
||||
cmd << "-MaximumRedirection #{max_redirects}" unless max_redirects.nil?
|
||||
request_headers["Authorization"] = """ '\"Basic ' + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(\"#{username}:#{password}\")) +'\"' """ unless username.nil? || password.nil?
|
||||
request_header_string = nil
|
||||
request_header_array = []
|
||||
request_headers.each do |k, v|
|
||||
request_header_string << " #{k} = #{v}"
|
||||
request_header_array << " '#{k}' = '#{v}'"
|
||||
end
|
||||
cmd << "-Headers @{#{request_header_string.join(";")}}" unless request_header_string.nil?
|
||||
cmd << "-Headers @{#{request_header_array.join(";")}}" unless request_header_array.empty?
|
||||
if params.nil?
|
||||
cmd << "'#{url}'"
|
||||
else
|
||||
|
|
251
lib/inspec/resources/nftables.rb
Normal file
251
lib/inspec/resources/nftables.rb
Normal file
|
@ -0,0 +1,251 @@
|
|||
require "inspec/resources/command"
|
||||
require "json" unless defined?(JSON)
|
||||
|
||||
# @see https://wiki.nftables.org/
|
||||
# @see https://www.netfilter.org/projects/nftables/manpage.html
|
||||
|
||||
# rubocop:disable Style/ClassVars
|
||||
|
||||
module Inspec::Resources
|
||||
class NfTables < Inspec.resource(1)
|
||||
name "nftables"
|
||||
supports platform: "linux"
|
||||
desc "Use the nftables InSpec audit resource to test rules and sets that are defined in nftables, which maintains tables of IP packet filtering rules. There may be more than one table. Each table contains one (or more) chains. A chain is a list of rules that match packets. When the rule matches, the rule defines what target to assign to the packet."
|
||||
example <<~EXAMPLE
|
||||
describe nftables(family:'inet', table:'filter', chain: 'INPUT') do
|
||||
its('type') { should eq 'filter' }
|
||||
its('hook') { should eq 'input' }
|
||||
its('prio') { should eq 0 } # filter
|
||||
its('policy') { should eq 'drop' }
|
||||
it { should have_rule('tcp dport { 22, 80, 443 } accept') }
|
||||
end
|
||||
describe nftables(family: 'inet', table: 'filter', set: 'OPEN_PORTS') do
|
||||
its('type') { should eq 'ipv4_addr . inet_proto . inet_service' }
|
||||
its('flags') { should include 'interval' }
|
||||
it { should have_element('1.1.1.1 . tcp . 25-27') }
|
||||
end
|
||||
EXAMPLE
|
||||
|
||||
@@bin = nil
|
||||
@@nft_params = {}
|
||||
@@nft_params["json"] = ""
|
||||
@@nft_params["stateless"] = ""
|
||||
@@nft_params["num"] = ""
|
||||
|
||||
def initialize(params = {})
|
||||
@family = params[:family] || nil
|
||||
@table = params[:table] || nil
|
||||
@chain = params[:chain] || nil
|
||||
@set = params[:set] || nil
|
||||
@ignore_comments = params[:ignore_comments] || false
|
||||
unless @@bin
|
||||
@@bin = find_nftables_or_error
|
||||
end
|
||||
|
||||
# Some old versions of `nft` do not support JSON output or stateless modifier
|
||||
res = inspec.command("#{@@bin} --version").stdout
|
||||
version = Gem::Version.new(/^nftables v(\S+) .*/.match(res)[1])
|
||||
case
|
||||
when version < Gem::Version.new("0.8.0")
|
||||
@@nft_params["num"] = "-nn"
|
||||
when version < Gem::Version.new("0.9.0")
|
||||
@@nft_params["stateless"] = "-s"
|
||||
@@nft_params["num"] = "-nn"
|
||||
when version < Gem::Version.new("0.9.3")
|
||||
@@nft_params["json"] = "-j"
|
||||
@@nft_params["stateless"] = "-s"
|
||||
@@nft_params["num"] = "-nn"
|
||||
when version >= Gem::Version.new("0.9.3")
|
||||
@@nft_params["json"] = "-j"
|
||||
@@nft_params["stateless"] = "-s"
|
||||
@@nft_params["num"] = "-y"
|
||||
## --terse
|
||||
end
|
||||
|
||||
# family and table attributes are mandatory
|
||||
fail_resource "nftables family and table are mandatory." if @family.nil? || @family.empty? || @table.nil? || @table.empty?
|
||||
# chain name or set name has to be specified and are mutually exclusive
|
||||
fail_resource "You must specify either a chain or a set name." if (@chain.nil? || @chain.empty?) && (@set.nil? || @set.empty?)
|
||||
fail_resource "You must specify either a chain or a set name, not both." if !(@chain.nil? || @chain.empty?) && !(@set.nil? || @set.empty?)
|
||||
|
||||
# we're done if we are on linux
|
||||
return if inspec.os.linux?
|
||||
|
||||
# ensures, all calls are aborted for non-supported os
|
||||
@nftables_cache = {}
|
||||
skip_resource "The `nftables` resource is not supported on your OS yet."
|
||||
end
|
||||
|
||||
# Let's have a generic method to retrieve attributes for chains and sets
|
||||
def _get_attr(name)
|
||||
# Some attributes are valid for chains only, for sets only or for both
|
||||
valid = {
|
||||
"chains" => %w{hook policy prio type},
|
||||
"sets" => %w{flags size type},
|
||||
}
|
||||
|
||||
target_obj = @set.nil? ? "chains" : "sets"
|
||||
|
||||
if valid[target_obj].include?(name)
|
||||
attrs = @set.nil? ? retrieve_chain_attrs : retrieve_set_attrs
|
||||
else
|
||||
raise Inspec::Exceptions::ResourceSkipped, "`#{name}` attribute is not valid for #{target_obj}"
|
||||
end
|
||||
# flags attribute is an array, if not retrieved ensure we return an empty array
|
||||
# otherwise return an empty string
|
||||
default = name == "flags" ? [] : ""
|
||||
val = attrs.key?(name) ? attrs[name] : default
|
||||
# When set type is has multiple data types it's retrieved as an array, make humans life easier
|
||||
# by returning a string representation
|
||||
if name == "type" && target_obj == "sets" && val.is_a?(Array)
|
||||
return val.join(" . ")
|
||||
end
|
||||
|
||||
val
|
||||
end
|
||||
|
||||
# Create a method for each attribute
|
||||
%i{flags hook policy prio size type}.each do |attr_method|
|
||||
define_method attr_method do
|
||||
_get_attr(attr_method.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
def has_rule?(rule = nil, _family = nil, _table = nil, _chain = nil)
|
||||
# checks if the rule is part of the chain
|
||||
# for now, we expect an exact match
|
||||
retrieve_chain_rules.any? { |line| line.casecmp(rule) == 0 }
|
||||
end
|
||||
|
||||
def has_element?(element = nil, _family = nil, _table = nil, _chain = nil)
|
||||
# checks if the element is part of the set
|
||||
# for now, we expect an exact match
|
||||
retrieve_set_elements.any? { |line| line.casecmp(element) == 0 }
|
||||
end
|
||||
|
||||
def retrieve_set_elements
|
||||
idx = "set_#{@family}_#{@table}_#{@set}"
|
||||
return @nftables_cache[idx] if defined?(@nftables_cache) && @nftables_cache.key?(idx)
|
||||
|
||||
@nftables_cache = {} unless defined?(@nftables_cache)
|
||||
|
||||
elem_cmd = "list set #{@family} #{@table} #{@set}"
|
||||
nftables_cmd = format("%s %s %s", @@bin, @@nft_params["stateless"], elem_cmd).strip
|
||||
|
||||
cmd = inspec.command(nftables_cmd)
|
||||
return [] if cmd.exit_status.to_i != 0
|
||||
|
||||
@nftables_cache[idx] = cmd.stdout.gsub("\t", "").split("\n").reject { |line| line =~ /^(table|set|type|size|flags|typeof|auto-merge)/ || line =~ /^}$/ }.map { |line| line.sub("elements = {", "").sub("}", "").split(",") }.flatten.map(&:strip)
|
||||
end
|
||||
|
||||
def retrieve_chain_rules
|
||||
idx = "rule_#{@family}_#{@table}_#{@chain}"
|
||||
return @nftables_cache[idx] if defined?(@nftables_cache) && @nftables_cache.key?(idx)
|
||||
|
||||
@nftables_cache = {} unless defined?(@nftables_cache)
|
||||
|
||||
# construct nftables command to read all rules of the given chain
|
||||
chain_cmd = "list chain #{@family} #{@table} #{@chain}"
|
||||
nftables_cmd = format("%s %s %s %s", @@bin, @@nft_params["stateless"], @@nft_params["num"], chain_cmd).strip
|
||||
|
||||
cmd = inspec.command(nftables_cmd)
|
||||
return [] if cmd.exit_status.to_i != 0
|
||||
|
||||
rules = cmd.stdout.gsub("\t", "").split("\n").reject { |line| line =~ /^(table|chain)/ || line =~ /^}$/ }
|
||||
|
||||
if @ignore_comments
|
||||
# split rules, returns array or rules without any comment
|
||||
@nftables_cache[idx] = remove_comments_from_rules(rules)
|
||||
else
|
||||
# split rules, returns array or rules
|
||||
@nftables_cache[idx] = rules.map(&:strip)
|
||||
end
|
||||
end
|
||||
|
||||
def retrieve_chain_attrs
|
||||
idx = "chain_attrs_#{@family}_#{@table}_#{@chain}"
|
||||
return @nftables_cache[idx] if defined?(@nftables_cache) && @nftables_cache.key?(idx)
|
||||
|
||||
@nftables_cache = {} unless defined?(@nftables_cache)
|
||||
|
||||
chain_cmd = "list chain #{@family} #{@table} #{@chain}"
|
||||
nftables_cmd = format("%s %s %s %s", @@bin, @@nft_params["stateless"], @@nft_params["json"], chain_cmd).strip
|
||||
|
||||
cmd = inspec.command(nftables_cmd)
|
||||
return {} if cmd.exit_status.to_i != 0
|
||||
|
||||
if @@nft_params["json"].empty?
|
||||
res = cmd.stdout.gsub("\t", "").split("\n").select { |line| line =~ /^type/ }[0]
|
||||
parsed = /type (\S+) hook (\S+) priority (\S+); policy (\S+);/.match(res)
|
||||
@nftables_cache[idx] = { "type" => parsed[1], "hook" => parsed[2], "prio" => parsed[3].to_i, "policy" => parsed[4] }
|
||||
else
|
||||
@nftables_cache[idx] = JSON.parse(cmd.stdout)["nftables"].select { |line| line.key?("chain") }[0]["chain"]
|
||||
end
|
||||
end
|
||||
|
||||
def retrieve_set_attrs
|
||||
idx = "set_attrs_#{@family}_#{@table}_#{@chain}"
|
||||
return @nftables_cache[idx] if defined?(@nftables_cache) && @nftables_cache.key?(idx)
|
||||
|
||||
@nftables_cache = {} unless defined?(@nftables_cache)
|
||||
|
||||
chain_cmd = "list set #{@family} #{@table} #{@set}"
|
||||
nftables_cmd = format("%s %s %s %s", @@bin, @@nft_params["stateless"], @@nft_params["json"], chain_cmd).strip
|
||||
|
||||
cmd = inspec.command(nftables_cmd)
|
||||
return {} if cmd.exit_status.to_i != 0
|
||||
|
||||
if @@nft_params["json"].empty?
|
||||
type = ""
|
||||
size = 0
|
||||
flags = []
|
||||
res = cmd.stdout.gsub("\t", "").split("\n").select { |line| line =~ /^(type|size|flags)/ }
|
||||
res.each do |line|
|
||||
parsed = /^type (.*)/.match(line)
|
||||
if parsed
|
||||
type = parsed[1]
|
||||
end
|
||||
parsed = /^flags (.*)/.match(line)
|
||||
if parsed
|
||||
flags = parsed[1].split(",")
|
||||
end
|
||||
parsed = /^size (.*)/.match(line)
|
||||
if parsed
|
||||
size = parsed[1].to_i
|
||||
end
|
||||
end
|
||||
@nftables_cache[idx] = { "type" => type, "size" => size, "flags" => flags }
|
||||
else
|
||||
@nftables_cache[idx] = JSON.parse(cmd.stdout)["nftables"].select { |line| line.key?("set") }[0]["set"]
|
||||
end
|
||||
end
|
||||
|
||||
def resource_id
|
||||
to_s || "nftables"
|
||||
end
|
||||
|
||||
def to_s
|
||||
format("nftables (%s %s %s %s)", @family && "family: #{@family}", @table && "table: #{@table}", @chain && "chain: #{@chain}", @set && "set: #{@set}").strip
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def remove_comments_from_rules(rules)
|
||||
rules.each do |rule|
|
||||
next if rule.nil?
|
||||
|
||||
rule.gsub!(/ comment "([^"]*)"/, "")
|
||||
rule.strip
|
||||
end
|
||||
rules
|
||||
end
|
||||
|
||||
def find_nftables_or_error
|
||||
%w{/usr/sbin/nft /sbin/nft nft}.each do |cmd|
|
||||
return cmd if inspec.command(cmd).exist?
|
||||
end
|
||||
|
||||
raise Inspec::Exceptions::ResourceFailed, "Could not find `nft`"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -81,7 +81,8 @@ module Inspec::Resources
|
|||
# Socket path and empty host in the connection string establishes socket connection
|
||||
# Socket connection only enabled for non-windows platforms
|
||||
# Windows does not support unix domain sockets
|
||||
"psql -d postgresql://#{@user}:#{@pass}@/#{dbs}?host=#{@socket_path} -A -t -w -c #{escaped_query(query)}"
|
||||
option_port = @port.nil? ? "" : "-p #{@port}" # add explicit port if specified
|
||||
"psql -d postgresql://#{@user}:#{@pass}@/#{dbs}?host=#{@socket_path} #{option_port} -A -t -w -c #{escaped_query(query)}"
|
||||
else
|
||||
# Host in connection string establishes tcp/ip connection
|
||||
if inspec.os.windows?
|
||||
|
|
|
@ -9,7 +9,6 @@ require "inspec/resource"
|
|||
require "inspec/resources/os"
|
||||
require "inspec/input_registry"
|
||||
require "inspec/waiver_file_reader"
|
||||
require "inspec/attestation_file_reader"
|
||||
require "inspec/utils/convert"
|
||||
|
||||
module Inspec
|
||||
|
@ -17,7 +16,6 @@ module Inspec
|
|||
include ::RSpec::Matchers
|
||||
|
||||
attr_reader :__waiver_data
|
||||
attr_reader :__attestation_data
|
||||
attr_accessor :resource_dsl, :na_impact_freeze
|
||||
attr_reader :__profile_id
|
||||
|
||||
|
@ -53,7 +51,6 @@ module Inspec
|
|||
# By applying waivers *after* the instance eval, we assure that
|
||||
# waivers have higher precedence than only_if.
|
||||
__apply_waivers
|
||||
__add_attestation_data
|
||||
|
||||
rescue SystemStackError, StandardError => e
|
||||
# We've encountered an exception while trying to eval the code inside the
|
||||
|
@ -425,19 +422,6 @@ module Inspec
|
|||
__waiver_data["skipped_due_to_waiver"] = true
|
||||
end
|
||||
|
||||
# fetches attestation data for the rule which is used in runner_rspec.rb to assign it inside metadata
|
||||
def __add_attestation_data
|
||||
# this adds attestation data to a rule, accesible on run data layer.
|
||||
control_id = @__rule_id
|
||||
attestation_files = Inspec::Config.cached.final_options["attestation_file"] if Inspec::Config.cached.respond_to?(:final_options)
|
||||
|
||||
attestation_data_by_profile = Inspec::AttestationFileReader.fetch_attestation_by_profile(__profile_id, attestation_files) unless attestation_files.nil?
|
||||
|
||||
return unless attestation_data_by_profile && attestation_data_by_profile[control_id] && attestation_data_by_profile[control_id].is_a?(Hash)
|
||||
|
||||
@__attestation_data = attestation_data_by_profile[control_id]
|
||||
end
|
||||
|
||||
#
|
||||
# Takes a block and returns a block that will run the given block
|
||||
# with access to the resource_dsl of the current class. This is to
|
||||
|
|
|
@ -29,9 +29,6 @@ module Inspec
|
|||
def initialize(raw_run_data)
|
||||
@raw_run_data = raw_run_data
|
||||
|
||||
# only try for attestation when attestation file is passed
|
||||
Inspec::Attestations.attest(@raw_run_data) if Inspec::Config.cached[:attestation_file]
|
||||
|
||||
self.controls = @raw_run_data[:controls].map { |c| Inspec::RunData::Control.new(c) }
|
||||
self.profiles = @raw_run_data[:profiles].map { |p| Inspec::RunData::Profile.new(p) }
|
||||
self.statistics = Inspec::RunData::Statistics.new(@raw_run_data[:statistics])
|
||||
|
|
|
@ -13,8 +13,7 @@ module Inspec
|
|||
:source_location, # Complex local
|
||||
:tags, # Hash with custom keys
|
||||
:title, # String
|
||||
:waiver_data, # Complex local
|
||||
:attestation_data # Complex local
|
||||
:waiver_data # Complex local
|
||||
) do
|
||||
include HashLikeStruct
|
||||
def initialize(raw_ctl_data)
|
||||
|
@ -22,7 +21,6 @@ module Inspec
|
|||
self.results = (raw_ctl_data[:results] || []).map { |r| Inspec::RunData::Result.new(r) }
|
||||
self.source_location = Inspec::RunData::Control::SourceLocation.new(raw_ctl_data[:source_location] || {})
|
||||
self.waiver_data = Inspec::RunData::Control::WaiverData.new(raw_ctl_data[:waiver_data] || {})
|
||||
self.attestation_data = Inspec::RunData::Control::AttestationData.new(raw_ctl_data[:attestation_data] || {})
|
||||
|
||||
[
|
||||
:code, # String
|
||||
|
@ -86,26 +84,6 @@ module Inspec
|
|||
}.each { |f| self[f] = raw_wv_data[f.to_s] }
|
||||
end
|
||||
end
|
||||
|
||||
AttestationData = Struct.new(
|
||||
:expiration_date,
|
||||
:justification,
|
||||
:evidence_url,
|
||||
:status,
|
||||
:message
|
||||
) do
|
||||
include HashLikeStruct
|
||||
def initialize(raw_attestation_data)
|
||||
# These have string keys in the raw data!
|
||||
%i{
|
||||
expiration_date
|
||||
justification
|
||||
evidence_url
|
||||
status
|
||||
message
|
||||
}.each { |f| self[f] = raw_attestation_data[f.to_s] }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ require "inspec/dependencies/cache"
|
|||
require "inspec/dist"
|
||||
require "inspec/reporters"
|
||||
require "inspec/runner_rspec"
|
||||
require "chef-licensing"
|
||||
# spec requirements
|
||||
|
||||
module Inspec
|
||||
|
@ -69,16 +70,6 @@ module Inspec
|
|||
}
|
||||
end
|
||||
|
||||
if @conf[:attestation_file]
|
||||
Inspec.with_feature("inspec-attestations") {
|
||||
@conf[:attestation_file].each do |file|
|
||||
unless File.file?(file)
|
||||
raise Inspec::Exceptions::AttestationFileDoesNotExist, "Attestation file #{file} does not exist."
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
# About reading inputs:
|
||||
# @conf gets passed around a lot, eventually to
|
||||
# Inspec::InputRegistry.register_external_inputs.
|
||||
|
@ -171,17 +162,23 @@ module Inspec
|
|||
end
|
||||
|
||||
def run(with = nil)
|
||||
ChefLicensing.check_software_entitlement! if Inspec::Dist::EXEC_NAME == "inspec"
|
||||
Inspec::Log.debug "Starting run with targets: #{@target_profiles.map(&:to_s)}"
|
||||
load
|
||||
run_tests(with)
|
||||
rescue ChefLicensing::SoftwareNotEntitled
|
||||
Inspec::Log.error "License is not entitled to use InSpec."
|
||||
Inspec::UI.new.exit(:license_not_entitled)
|
||||
rescue ChefLicensing::Error => e
|
||||
Inspec::Log.error e.message
|
||||
Inspec::UI.new.exit(:usage_error)
|
||||
end
|
||||
|
||||
def render_output(run_data)
|
||||
return if @conf["reporter"].nil?
|
||||
|
||||
@conf["reporter"].each do |reporter|
|
||||
# if attestation file is used then we need enhanced outcomes
|
||||
enhanced_outcome_flag = @conf["attestation_file"] ? true : @conf["enhanced_outcomes"]
|
||||
enhanced_outcome_flag = @conf["enhanced_outcomes"]
|
||||
result = Inspec::Reporters.render(reporter, run_data, enhanced_outcome_flag)
|
||||
raise Inspec::ReporterError, "Error generating reporter '#{reporter[0]}'" if result == false
|
||||
end
|
||||
|
|
|
@ -199,8 +199,7 @@ module Inspec
|
|||
RSpec.configuration.output_stream = $stdout
|
||||
@formatter = RSpec.configuration.add_formatter(Inspec::Formatters::Base)
|
||||
|
||||
# if attestation file is used then we need enhanced outcomes
|
||||
@formatter.enhanced_outcomes = @conf.final_options["attestation_file"] ? true : @conf.final_options["enhanced_outcomes"]
|
||||
@formatter.enhanced_outcomes = @conf.final_options["enhanced_outcomes"]
|
||||
RSpec.configuration.add_formatter(Inspec::Formatters::ShowProgress, $stderr) if @conf[:show_progress]
|
||||
set_optional_formatters
|
||||
RSpec.configuration.color = @conf["color"]
|
||||
|
@ -232,7 +231,6 @@ module Inspec
|
|||
metadata[:code] = rule.instance_variable_get(:@__code)
|
||||
metadata[:source_location] = rule.instance_variable_get(:@__source_location)
|
||||
metadata[:waiver_data] = rule.__waiver_data
|
||||
metadata[:attestation_data] = rule.__attestation_data # data fetched from rule object
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
require "chef-licensing"
|
||||
require "inspec/dist"
|
||||
|
||||
autoload :Pry, "pry"
|
||||
|
||||
module Inspec
|
||||
|
@ -10,6 +13,7 @@ module Inspec
|
|||
end
|
||||
|
||||
def start
|
||||
ChefLicensing.check_software_entitlement! if Inspec::Dist::EXEC_NAME == "inspec"
|
||||
# This will hold a single evaluation binding context as opened within
|
||||
# the instance_eval context of the anonymous class that the profile
|
||||
# context creates to evaluate each individual test file. We want to
|
||||
|
@ -18,6 +22,12 @@ module Inspec
|
|||
@ctx_binding = @runner.eval_with_virtual_profile("binding")
|
||||
configure_pry
|
||||
@ctx_binding.pry
|
||||
rescue ChefLicensing::SoftwareNotEntitled
|
||||
Inspec::Log.error "License is not entitled to use InSpec."
|
||||
Inspec::UI.new.exit(:license_not_entitled)
|
||||
rescue ChefLicensing::Error => e
|
||||
Inspec::Log.error e.message
|
||||
Inspec::UI.new.exit(:usage_error)
|
||||
end
|
||||
|
||||
def configure_pry # rubocop:disable Metrics/AbcSize
|
||||
|
|
|
@ -33,6 +33,8 @@ module Inspec
|
|||
EXIT_GEM_DEPENDENCY_LOAD_ERROR = 4
|
||||
EXIT_BAD_SIGNATURE = 5
|
||||
EXIT_LICENSE_NOT_ACCEPTED = 172
|
||||
EXIT_LICENSE_NOT_ENTITLED = 173
|
||||
EXIT_LICENSE_NOT_SET = 174
|
||||
EXIT_FAILED_TESTS = 100
|
||||
EXIT_SKIPPED_TESTS = 101
|
||||
EXIT_TERMINATED_BY_CTL_C = 130
|
||||
|
|
9
lib/inspec/utils/licensing_config.rb
Normal file
9
lib/inspec/utils/licensing_config.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
require_relative "../log"
|
||||
require "chef-licensing"
|
||||
ChefLicensing.configure do |config|
|
||||
config.chef_product_name = "InSpec"
|
||||
config.chef_entitlement_id = "3ff52c37-e41f-4f6c-ad4d-365192205968"
|
||||
config.chef_executable_name = "inspec"
|
||||
config.license_server_url = "https://licensing.chef.co/License"
|
||||
config.logger = Inspec::Log
|
||||
end
|
|
@ -57,11 +57,18 @@ class SimpleConfig
|
|||
m = opts[:assignment_regex].match(line)
|
||||
return nil if m.nil?
|
||||
|
||||
values = parse_values(m, opts[:key_values])
|
||||
|
||||
if opts[:multiple_values]
|
||||
@vals[m[1]] ||= []
|
||||
@vals[m[1]].push(parse_values(m, opts[:key_values]))
|
||||
if opts[:multiple_value_regex] # can be used only if multiple values is set as true
|
||||
value_to_array = values.split(opts[:multiple_value_regex])
|
||||
@vals[m[1]].concat(value_to_array)
|
||||
else
|
||||
@vals[m[1]].push(values)
|
||||
end
|
||||
else
|
||||
@vals[m[1]] = parse_values(m, opts[:key_values])
|
||||
@vals[m[1]] = values
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -116,6 +123,7 @@ class SimpleConfig
|
|||
key_values: 1, # default for key=value, may require for 'key val1 val2 val3'
|
||||
standalone_comments: false,
|
||||
multiple_values: false,
|
||||
multiple_value_regex: nil,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module Inspec
|
||||
VERSION = "6.2.46".freeze
|
||||
VERSION = "6.4.33".freeze
|
||||
end
|
||||
|
|
|
@ -148,7 +148,7 @@ RSpec::Matchers.define :be_resolvable do
|
|||
end
|
||||
end
|
||||
|
||||
# matcher for iptables and ip6tables
|
||||
# matcher for iptables, ip6tables and nftables
|
||||
RSpec::Matchers.define :have_rule do |rule|
|
||||
match do |tables|
|
||||
tables.has_rule?(rule)
|
||||
|
@ -163,6 +163,13 @@ RSpec::Matchers.define :have_rule do |rule|
|
|||
end
|
||||
end
|
||||
|
||||
# matcher for nftables sets
|
||||
RSpec::Matchers.define :have_element do |elem|
|
||||
match do |sets|
|
||||
sets.has_element?(elem)
|
||||
end
|
||||
end
|
||||
|
||||
# `be_in` matcher
|
||||
# You can use it in the following cases:
|
||||
# - check if an item or array is included in a given array
|
||||
|
|
16
lib/plugins/inspec-license/README.md
Normal file
16
lib/plugins/inspec-license/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# License Plugin
|
||||
|
||||
## license list
|
||||
|
||||
Implements the `inspec license list` CLI command.
|
||||
|
||||
## license add
|
||||
|
||||
Implements the `inspec license add` CLI command.
|
||||
|
||||
### What This Plugin Does
|
||||
|
||||
This plugin consists of the following subcommands:
|
||||
|
||||
1. `add`: helps to add a new license
|
||||
2. `list`: helps to list all the licenses for the current user
|
6
lib/plugins/inspec-license/inspec-license.gemspec
Normal file
6
lib/plugins/inspec-license/inspec-license.gemspec
Normal file
|
@ -0,0 +1,6 @@
|
|||
Gem::Specification.new do |spec|
|
||||
spec.name = "inspec-license"
|
||||
spec.summary = "Plugin to list user licenses."
|
||||
spec.description = ""
|
||||
spec.license = "Apache-2.0"
|
||||
end
|
14
lib/plugins/inspec-license/lib/inspec-license.rb
Normal file
14
lib/plugins/inspec-license/lib/inspec-license.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
module InspecPlugins
|
||||
module License
|
||||
class Plugin < ::Inspec.plugin(2)
|
||||
plugin_name :"inspec-license"
|
||||
|
||||
if Inspec::Dist::EXEC_NAME == "inspec"
|
||||
cli_command :license do
|
||||
require_relative "inspec-license/cli"
|
||||
InspecPlugins::License::CLI
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
23
lib/plugins/inspec-license/lib/inspec-license/cli.rb
Normal file
23
lib/plugins/inspec-license/lib/inspec-license/cli.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
require "chef-licensing"
|
||||
module InspecPlugins::License
|
||||
class CLI < Inspec.plugin(2, :cli_command)
|
||||
include Inspec::Dist
|
||||
|
||||
subcommand_desc "license SUBCOMMAND [options]", "Manage #{PRODUCT_NAME} license"
|
||||
desc "list", "List licenses (not applicable to local licensing service)"
|
||||
def list
|
||||
ChefLicensing.list_license_keys_info
|
||||
end
|
||||
|
||||
desc "add", "Add a new license (not applicable to local licensing service)"
|
||||
def add
|
||||
ChefLicensing.add_license
|
||||
rescue ChefLicensing::LicenseKeyFetcher::LicenseKeyAddNotAllowed => e
|
||||
Inspec::Log.error e.message
|
||||
Inspec::UI.new.exit(Inspec::UI::EXIT_LICENSE_NOT_SET)
|
||||
rescue ChefLicensing::Error => e
|
||||
Inspec::Log.error e.message
|
||||
Inspec::UI.new.exit(Inspec::UI::EXIT_LICENSE_NOT_SET)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
module InspecPlugins::Parallelism
|
||||
class StreamingReporter < Inspec.plugin(2, :streaming_reporter)
|
||||
# Registering these methods with RSpec::Core::Formatters class is mandatory
|
||||
RSpec::Core::Formatters.register self, :example_passed, :example_failed, :example_pending
|
||||
RSpec::Core::Formatters.register self, :example_passed, :example_failed, :example_pending, :close
|
||||
|
||||
def initialize(output)
|
||||
@status_mapping = {}
|
||||
|
@ -21,6 +21,11 @@ module InspecPlugins::Parallelism
|
|||
set_example(notification, "skipped")
|
||||
end
|
||||
|
||||
def close(notification)
|
||||
# HACK: if we've reached the end of the execution, send a special marker, to ease EOF detection on Windows
|
||||
puts "EOF_MARKER"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_example(notification, status)
|
||||
|
@ -46,10 +51,6 @@ module InspecPlugins::Parallelism
|
|||
display_name = control_id.to_s.lstrip.force_encoding(Encoding::UTF_8) unless title
|
||||
|
||||
puts "#{@control_counter}/#{stat}/#{controls_count}/#{display_name}"
|
||||
# HACK: if we've reached the end of the execution, send a special marker, to ease EOF detection on Windows
|
||||
if @control_counter == controls_count
|
||||
puts "EOF_MARKER"
|
||||
end
|
||||
end
|
||||
|
||||
def set_status_mapping(control_id, status)
|
||||
|
|
|
@ -23,8 +23,9 @@ module InspecPlugins
|
|||
def run
|
||||
validate_thor_options
|
||||
validate_invocations!
|
||||
catch_ctl_c_and_exit unless run_in_background
|
||||
Runner.new(invocations, cli_options_to_parallel_cmd, sub_cmd).run
|
||||
runner = Runner.new(invocations, cli_options_to_parallel_cmd, sub_cmd)
|
||||
catch_ctl_c_and_exit(runner) unless run_in_background
|
||||
runner.run
|
||||
end
|
||||
|
||||
def dry_run
|
||||
|
@ -34,11 +35,17 @@ module InspecPlugins
|
|||
|
||||
private
|
||||
|
||||
def catch_ctl_c_and_exit
|
||||
def catch_ctl_c_and_exit(runner)
|
||||
puts "Press CTL+C to stop\n"
|
||||
trap("SIGINT") do
|
||||
puts "\n"
|
||||
puts "Shutting down jobs..."
|
||||
if Inspec.locally_windows?
|
||||
runner.kill_child_processes
|
||||
sleep 1
|
||||
puts "Renaming error log files..."
|
||||
runner.rename_error_log_files
|
||||
end
|
||||
exit Inspec::UI::EXIT_TERMINATED_BY_CTL_C
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,7 @@ module InspecPlugins
|
|||
@sub_cmd = sub_cmd
|
||||
@total_jobs = cli_options["jobs"] || Concurrent.physical_processor_count
|
||||
@child_tracker = {}
|
||||
@child_tracker_persisted = {}
|
||||
@run_in_background = cli_options["bg"]
|
||||
unless run_in_background
|
||||
@ui = InspecPlugins::Parallelism::SuperReporter.make(cli_options["ui"], total_jobs, invocations)
|
||||
|
@ -34,6 +35,10 @@ module InspecPlugins
|
|||
cleanup_child_processes
|
||||
sleep 0.1
|
||||
end
|
||||
|
||||
# Requires renaming operations on windows only
|
||||
# Do Rename and delete operations after all child processes have exited successfully
|
||||
rename_error_log_files if Inspec.locally_windows?
|
||||
cleanup_empty_error_log_files
|
||||
cleanup_daemon_process if run_in_background
|
||||
end
|
||||
|
@ -63,6 +68,36 @@ module InspecPlugins
|
|||
end
|
||||
end
|
||||
|
||||
def kill_child_processes
|
||||
@child_tracker.each do |pid, info|
|
||||
Process.kill("SIGKILL", pid)
|
||||
rescue Exception => e
|
||||
$stderr.puts "Error while shutting down process #{pid}: #{e.message}"
|
||||
end
|
||||
# Waiting for child processes to die after they have been killed
|
||||
wait_for_child_processes_to_die
|
||||
end
|
||||
|
||||
def wait_for_child_processes_to_die
|
||||
until @child_tracker.empty?
|
||||
begin
|
||||
exited_pid = Process.waitpid(-1, Process::WNOHANG)
|
||||
@child_tracker.delete exited_pid if exited_pid && exited_pid > 0
|
||||
sleep 1
|
||||
rescue Errno::ECHILD
|
||||
Inspec::Log.info "Processes shutdown complete!"
|
||||
rescue Exception => e
|
||||
Inspec::Log.debug "Error while waiting for child processes to shutdown: #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def rename_error_log_files
|
||||
@child_tracker_persisted.each do |pid, info|
|
||||
rename_error_log(info[:error_log_file], pid)
|
||||
end
|
||||
end
|
||||
|
||||
def should_start_more_jobs?
|
||||
@child_tracker.length < total_jobs && !invocations.empty?
|
||||
end
|
||||
|
@ -71,22 +106,25 @@ module InspecPlugins
|
|||
invocation = invocations.shift[:value]
|
||||
|
||||
child_reader, parent_writer = IO.pipe
|
||||
|
||||
# Construct command-line invocation
|
||||
child_pid = nil
|
||||
error_log_file_name = "#{Time.now.nsec}.err"
|
||||
|
||||
begin
|
||||
logs_dir_path = log_path || Dir.pwd
|
||||
log_dir = File.join(logs_dir_path, "logs")
|
||||
FileUtils.mkdir_p(log_dir)
|
||||
error_log_file = File.open("#{log_dir}/#{Time.now.nsec}.err", "a+")
|
||||
cmd = "#{$0} #{sub_cmd} #{invocation}"
|
||||
log_msg = "#{Time.now.iso8601} Start Time: #{Time.now}\n#{Time.now.iso8601} Arguments: #{invocation}\n"
|
||||
child_pid = Process.spawn(cmd, out: parent_writer, err: error_log_file_name)
|
||||
# Rename error log file if exist
|
||||
rename_error_log(error_log_file_name, child_pid) if File.exist?(error_log_file_name)
|
||||
child_pid = Process.spawn(cmd, out: parent_writer, err: error_log_file.path)
|
||||
|
||||
# Logging
|
||||
create_logs(child_pid, nil, $stderr)
|
||||
create_logs(child_pid, log_msg)
|
||||
@child_tracker[child_pid] = { io: child_reader }
|
||||
|
||||
# This is used to rename error log files after all child processes are exited
|
||||
@child_tracker_persisted[child_pid] = { error_log_file: error_log_file }
|
||||
@ui.child_spawned(child_pid, invocation)
|
||||
|
||||
# Close the file to unlock the error log files opened by processes
|
||||
error_log_file.close
|
||||
rescue StandardError => e
|
||||
$stderr.puts "#{Time.now.iso8601} Error Message: #{e.message}"
|
||||
$stderr.puts "#{Time.now.iso8601} Error Backtrace: #{e.backtrace}"
|
||||
|
@ -198,7 +236,7 @@ module InspecPlugins
|
|||
def create_logs(child_pid, run_log , stderr = nil)
|
||||
logs_dir_path = log_path || Dir.pwd
|
||||
log_dir = File.join(logs_dir_path, "logs")
|
||||
FileUtils.mkdir_p(log_dir) unless File.directory?(log_dir)
|
||||
FileUtils.mkdir_p(log_dir)
|
||||
|
||||
if stderr
|
||||
log_file = File.join(log_dir, "#{child_pid}.err") unless File.exist?("#{child_pid}.err")
|
||||
|
@ -209,11 +247,18 @@ module InspecPlugins
|
|||
end
|
||||
end
|
||||
|
||||
def rename_error_log(error_log_file_name, child_pid)
|
||||
def rename_error_log(error_log_file, child_pid)
|
||||
logs_dir_path = log_path || Dir.pwd
|
||||
log_dir = File.join(logs_dir_path, "logs")
|
||||
FileUtils.mkdir_p(log_dir) unless File.directory?(log_dir)
|
||||
File.rename(error_log_file_name, "#{log_dir}/#{child_pid}.err")
|
||||
FileUtils.mkdir_p(log_dir)
|
||||
|
||||
if error_log_file.closed? && File.exist?(error_log_file.path)
|
||||
begin
|
||||
File.rename("#{error_log_file.path}", "#{log_dir}/#{child_pid}.err")
|
||||
rescue
|
||||
$stderr.puts "Cannot rename error log file #{error_log_file.path} for child pid #{child_pid}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -89,7 +89,8 @@ module InspecPlugins::Parallelism
|
|||
# Loop over slots
|
||||
slots.each_index do |idx|
|
||||
if slots[idx].nil?
|
||||
line += "idle".center(slot_width)
|
||||
# line += "idle".center(slot_width)
|
||||
# Need to improve UI
|
||||
elsif slots[idx] == "exited"
|
||||
line += "Done".center(slot_width)
|
||||
else
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
GIT
|
||||
remote: https://github.com/chef/omnibus-software.git
|
||||
|
||||
revision: 225e3576c48fcd0155f6049cb032b2370eccf29a
|
||||
revision: 4b08f0bc0688f750bc55a49b8103b2d12815399e
|
||||
branch: main
|
||||
specs:
|
||||
omnibus-software (23.2.286)
|
||||
omnibus-software (23.7.293)
|
||||
omnibus (>= 9.0.0)
|
||||
|
||||
GIT
|
||||
remote: https://github.com/chef/omnibus.git
|
||||
revision: cf9761311577e24819625aa1d932f828740e33b4
|
||||
revision: 9c0643a3a44f3e7119789c2093bfc8edd78c74ff
|
||||
branch: main
|
||||
specs:
|
||||
omnibus (9.0.17)
|
||||
omnibus (9.0.21)
|
||||
aws-sdk-s3 (~> 1.116.0)
|
||||
chef-cleanroom (~> 1.0)
|
||||
chef-utils (>= 15.4)
|
||||
|
@ -30,33 +29,33 @@ GIT
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.8.1)
|
||||
addressable (2.8.4)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
artifactory (3.0.15)
|
||||
awesome_print (1.9.2)
|
||||
aws-eventstream (1.2.0)
|
||||
aws-partitions (1.716.0)
|
||||
aws-sdk-core (3.170.0)
|
||||
aws-partitions (1.783.0)
|
||||
aws-sdk-core (3.176.1)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.62.0)
|
||||
aws-sdk-core (~> 3, >= 3.165.0)
|
||||
aws-sdk-kms (1.68.0)
|
||||
aws-sdk-core (~> 3, >= 3.176.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.116.0)
|
||||
aws-sdk-core (~> 3, >= 3.127.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.4)
|
||||
aws-sdk-secretsmanager (1.64.0)
|
||||
aws-sdk-core (~> 3, >= 3.127.0)
|
||||
aws-sdk-secretsmanager (1.77.0)
|
||||
aws-sdk-core (~> 3, >= 3.174.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.5.2)
|
||||
aws-sigv4 (1.6.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
bcrypt_pbkdf (1.1.0)
|
||||
bcrypt_pbkdf (1.1.0-x64-mingw32)
|
||||
bcrypt_pbkdf (1.1.0-x86-mingw32)
|
||||
berkshelf (8.0.2)
|
||||
berkshelf (8.0.7)
|
||||
chef (>= 15.7.32)
|
||||
chef-config
|
||||
cleanroom (~> 1.0)
|
||||
|
@ -70,54 +69,57 @@ GEM
|
|||
solve (~> 4.0)
|
||||
thor (>= 0.20)
|
||||
builder (3.2.4)
|
||||
chef (17.10.0)
|
||||
chef (18.2.7)
|
||||
addressable
|
||||
aws-sdk-s3 (~> 1.91)
|
||||
aws-sdk-secretsmanager (~> 1.46)
|
||||
chef-config (= 17.10.0)
|
||||
chef-utils (= 17.10.0)
|
||||
chef-config (= 18.2.7)
|
||||
chef-utils (= 18.2.7)
|
||||
chef-vault
|
||||
chef-zero (>= 14.0.11)
|
||||
corefoundation (~> 0.3.4)
|
||||
diff-lcs (>= 1.2.4, < 1.6.0, != 1.4.0)
|
||||
erubis (~> 2.7)
|
||||
ffi (>= 1.5.0)
|
||||
ffi (>= 1.15.5)
|
||||
ffi-libarchive (~> 1.0, >= 1.0.3)
|
||||
ffi-yajl (~> 2.2)
|
||||
iniparse (~> 1.4)
|
||||
inspec-core (~> 4.23)
|
||||
inspec-core (>= 5)
|
||||
license-acceptance (>= 1.0.5, < 3)
|
||||
mixlib-archive (>= 0.4, < 2.0)
|
||||
mixlib-authentication (>= 2.1, < 4)
|
||||
mixlib-cli (>= 2.1.1, < 3.0)
|
||||
mixlib-log (>= 2.0.3, < 4.0)
|
||||
mixlib-shellout (>= 3.1.1, < 4.0)
|
||||
net-sftp (>= 2.1.2, < 4.0)
|
||||
ohai (~> 17.0)
|
||||
net-ftp
|
||||
net-sftp (>= 2.1.2, < 5.0)
|
||||
ohai (~> 18.0)
|
||||
plist (~> 3.2)
|
||||
proxifier (~> 1.0)
|
||||
proxifier2 (~> 1.1)
|
||||
syslog-logger (~> 1.6)
|
||||
train-core (~> 3.2, >= 3.2.28)
|
||||
train-core (~> 3.10)
|
||||
train-rest (>= 0.4.1)
|
||||
train-winrm (>= 0.2.5)
|
||||
unf_ext (>= 0.0.8.2)
|
||||
uuidtools (>= 2.1.5, < 3.0)
|
||||
vault (~> 0.16)
|
||||
chef (17.10.0-universal-mingw32)
|
||||
chef (18.2.7-x64-mingw-ucrt)
|
||||
addressable
|
||||
aws-sdk-s3 (~> 1.91)
|
||||
aws-sdk-secretsmanager (~> 1.46)
|
||||
chef-config (= 17.10.0)
|
||||
chef-powershell (~> 1.0.12)
|
||||
chef-utils (= 17.10.0)
|
||||
chef-config (= 18.2.7)
|
||||
chef-powershell (~> 18.0.0)
|
||||
chef-utils (= 18.2.7)
|
||||
chef-vault
|
||||
chef-zero (>= 14.0.11)
|
||||
corefoundation (~> 0.3.4)
|
||||
diff-lcs (>= 1.2.4, < 1.6.0, != 1.4.0)
|
||||
erubis (~> 2.7)
|
||||
ffi (>= 1.5.0)
|
||||
ffi (>= 1.15.5)
|
||||
ffi-libarchive (~> 1.0, >= 1.0.3)
|
||||
ffi-yajl (~> 2.2)
|
||||
iniparse (~> 1.4)
|
||||
inspec-core (~> 4.23)
|
||||
inspec-core (>= 5)
|
||||
iso8601 (>= 0.12.1, < 0.14)
|
||||
license-acceptance (>= 1.0.5, < 3)
|
||||
mixlib-archive (>= 0.4, < 2.0)
|
||||
|
@ -125,17 +127,20 @@ GEM
|
|||
mixlib-cli (>= 2.1.1, < 3.0)
|
||||
mixlib-log (>= 2.0.3, < 4.0)
|
||||
mixlib-shellout (>= 3.1.1, < 4.0)
|
||||
net-sftp (>= 2.1.2, < 4.0)
|
||||
ohai (~> 17.0)
|
||||
net-ftp
|
||||
net-sftp (>= 2.1.2, < 5.0)
|
||||
ohai (~> 18.0)
|
||||
plist (~> 3.2)
|
||||
proxifier (~> 1.0)
|
||||
proxifier2 (~> 1.1)
|
||||
syslog-logger (~> 1.6)
|
||||
train-core (~> 3.2, >= 3.2.28)
|
||||
train-core (~> 3.10)
|
||||
train-rest (>= 0.4.1)
|
||||
train-winrm (>= 0.2.5)
|
||||
unf_ext (>= 0.0.8.2)
|
||||
uuidtools (>= 2.1.5, < 3.0)
|
||||
vault (~> 0.16)
|
||||
win32-api (~> 1.5.3)
|
||||
win32-certstore (~> 0.6.2)
|
||||
win32-api (~> 1.10.0)
|
||||
win32-certstore (~> 0.6.15)
|
||||
win32-event (~> 0.6.1)
|
||||
win32-eventlog (= 0.6.3)
|
||||
win32-mmap (~> 0.4.1)
|
||||
|
@ -145,22 +150,22 @@ GEM
|
|||
win32-taskscheduler (~> 2.0)
|
||||
wmi-lite (~> 1.0)
|
||||
chef-cleanroom (1.0.5)
|
||||
chef-config (17.10.0)
|
||||
chef-config (18.2.7)
|
||||
addressable
|
||||
chef-utils (= 17.10.0)
|
||||
chef-utils (= 18.2.7)
|
||||
fuzzyurl
|
||||
mixlib-config (>= 2.2.12, < 4.0)
|
||||
mixlib-shellout (>= 2.0, < 4.0)
|
||||
tomlrb (~> 1.2)
|
||||
chef-powershell (1.0.13)
|
||||
chef-powershell (18.0.2)
|
||||
ffi (~> 1.15)
|
||||
ffi-yajl (~> 2.4)
|
||||
chef-telemetry (1.1.1)
|
||||
chef-config
|
||||
concurrent-ruby (~> 1.0)
|
||||
chef-utils (17.10.0)
|
||||
chef-utils (18.2.7)
|
||||
concurrent-ruby
|
||||
chef-vault (4.1.10)
|
||||
chef-vault (4.1.11)
|
||||
chef-zero (15.0.11)
|
||||
ffi-yajl (~> 2.2)
|
||||
hashie (>= 2.0, < 5.0)
|
||||
|
@ -175,25 +180,19 @@ GEM
|
|||
contracts (0.16.1)
|
||||
corefoundation (0.3.13)
|
||||
ffi (>= 1.15.0)
|
||||
date (3.3.3)
|
||||
diff-lcs (1.5.0)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
ed25519 (1.3.0)
|
||||
erubi (1.12.0)
|
||||
erubis (2.7.0)
|
||||
faraday (1.4.3)
|
||||
faraday-em_http (~> 1.0)
|
||||
faraday-em_synchrony (~> 1.0)
|
||||
faraday-excon (~> 1.1)
|
||||
faraday-net_http (~> 1.0)
|
||||
faraday-net_http_persistent (~> 1.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday (2.7.7)
|
||||
faraday-net_http (>= 2.0, < 3.1)
|
||||
ruby2_keywords (>= 0.0.4)
|
||||
faraday-em_http (1.0.0)
|
||||
faraday-em_synchrony (1.0.0)
|
||||
faraday-excon (1.1.0)
|
||||
faraday-net_http (1.0.1)
|
||||
faraday-net_http_persistent (1.2.0)
|
||||
faraday_middleware (1.2.0)
|
||||
faraday (~> 1.0)
|
||||
faraday-follow_redirects (0.3.0)
|
||||
faraday (>= 1, < 3)
|
||||
faraday-net_http (3.0.2)
|
||||
ffi (1.15.5)
|
||||
ffi (1.15.5-x64-mingw-ucrt)
|
||||
ffi (1.15.5-x64-mingw32)
|
||||
|
@ -211,13 +210,16 @@ GEM
|
|||
builder (>= 2.1.2)
|
||||
rexml (~> 3.0)
|
||||
hashie (4.1.0)
|
||||
http-accept (1.7.0)
|
||||
http-cookie (1.0.5)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
iniparse (1.5.0)
|
||||
inspec-core (4.56.20)
|
||||
inspec-core (5.22.3)
|
||||
addressable (~> 2.4)
|
||||
chef-telemetry (~> 1.0, >= 1.0.8)
|
||||
faraday (>= 0.9.0, < 1.5)
|
||||
faraday_middleware (~> 1.0)
|
||||
faraday (>= 1, < 3)
|
||||
faraday-follow_redirects (~> 0.3)
|
||||
hashie (>= 3.4, < 5.0)
|
||||
license-acceptance (>= 0.2.13, < 3.0)
|
||||
method_source (>= 0.8, < 2.0)
|
||||
|
@ -233,7 +235,7 @@ GEM
|
|||
sslshake (~> 1.2)
|
||||
thor (>= 0.20, < 2.0)
|
||||
tomlrb (>= 1.2, < 2.1)
|
||||
train-core (~> 3.0)
|
||||
train-core (~> 3.10)
|
||||
tty-prompt (~> 0.17)
|
||||
tty-table (~> 0.10)
|
||||
iostruct (0.0.5)
|
||||
|
@ -249,7 +251,7 @@ GEM
|
|||
tomlrb (>= 1.2, < 3.0)
|
||||
tty-box (~> 0.6)
|
||||
tty-prompt (~> 0.20)
|
||||
license_scout (1.3.4)
|
||||
license_scout (1.3.6)
|
||||
ffi-yajl (~> 2.2)
|
||||
mixlib-shellout (>= 2.2, < 4.0)
|
||||
toml-rb (>= 1, < 3)
|
||||
|
@ -258,6 +260,9 @@ GEM
|
|||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.14)
|
||||
method_source (1.0.0)
|
||||
mime-types (3.4.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2023.0218.1)
|
||||
minitar (0.9)
|
||||
mixlib-archive (1.1.7)
|
||||
mixlib-log
|
||||
|
@ -288,20 +293,26 @@ GEM
|
|||
molinillo (0.8.0)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.3.0)
|
||||
net-ftp (0.2.0)
|
||||
net-protocol
|
||||
time
|
||||
net-protocol (0.2.1)
|
||||
timeout
|
||||
net-scp (4.0.0)
|
||||
net-ssh (>= 2.6.5, < 8.0.0)
|
||||
net-sftp (3.0.0)
|
||||
net-ssh (>= 5.0.0, < 7.0.0)
|
||||
net-ssh (6.1.0)
|
||||
net-sftp (4.0.0)
|
||||
net-ssh (>= 5.0.0, < 8.0.0)
|
||||
net-ssh (7.1.0)
|
||||
net-ssh-gateway (2.0.0)
|
||||
net-ssh (>= 4.0.0)
|
||||
netrc (0.11.0)
|
||||
nori (2.6.0)
|
||||
octokit (4.25.1)
|
||||
faraday (>= 1, < 3)
|
||||
sawyer (~> 0.9)
|
||||
ohai (17.9.0)
|
||||
chef-config (>= 14.12, < 18)
|
||||
chef-utils (>= 16.0, < 18)
|
||||
ohai (18.1.3)
|
||||
chef-config (>= 14.12, < 19)
|
||||
chef-utils (>= 16.0, < 19)
|
||||
ffi (~> 1.9)
|
||||
ffi-yajl (~> 2.2)
|
||||
ipaddress
|
||||
|
@ -312,24 +323,41 @@ GEM
|
|||
plist (~> 3.1)
|
||||
train-core
|
||||
wmi-lite (~> 1.0)
|
||||
parallel (1.22.1)
|
||||
parallel (1.23.0)
|
||||
parslet (1.8.2)
|
||||
pastel (0.8.0)
|
||||
tty-color (~> 0.5)
|
||||
pedump (0.6.5)
|
||||
pedump (0.6.6)
|
||||
awesome_print
|
||||
iostruct (>= 0.0.4)
|
||||
multipart-post (>= 2.0.0)
|
||||
rainbow
|
||||
zhexdump (>= 0.0.2)
|
||||
plist (3.7.0)
|
||||
proxifier (1.0.3)
|
||||
pry (0.14.1)
|
||||
proxifier2 (1.1.0)
|
||||
pry (0.14.2)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
public_suffix (5.0.1)
|
||||
rack (2.2.6.2)
|
||||
rack (2.2.7)
|
||||
rainbow (3.1.1)
|
||||
rest-client (2.1.0)
|
||||
http-accept (>= 1.7.0, < 2.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
rest-client (2.1.0-x64-mingw32)
|
||||
ffi (~> 1.9)
|
||||
http-accept (>= 1.7.0, < 2.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
rest-client (2.1.0-x86-mingw32)
|
||||
ffi (~> 1.9)
|
||||
http-accept (>= 1.7.0, < 2.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
retryable (3.0.5)
|
||||
rexml (3.2.5)
|
||||
rspec (3.11.0)
|
||||
|
@ -338,17 +366,17 @@ GEM
|
|||
rspec-mocks (~> 3.11.0)
|
||||
rspec-core (3.11.0)
|
||||
rspec-support (~> 3.11.0)
|
||||
rspec-expectations (3.11.0)
|
||||
rspec-expectations (3.11.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.11.0)
|
||||
rspec-its (1.3.0)
|
||||
rspec-core (>= 3.0.0)
|
||||
rspec-expectations (>= 3.0.0)
|
||||
rspec-mocks (3.11.1)
|
||||
rspec-mocks (3.11.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.11.0)
|
||||
rspec-support (3.11.0)
|
||||
ruby-progressbar (1.11.0)
|
||||
rspec-support (3.11.1)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyntlm (0.6.3)
|
||||
rubyzip (2.3.2)
|
||||
|
@ -381,17 +409,24 @@ GEM
|
|||
winrm (~> 2.0)
|
||||
winrm-elevated (~> 1.0)
|
||||
winrm-fs (~> 1.1)
|
||||
thor (1.2.1)
|
||||
thor (1.2.2)
|
||||
time (0.2.2)
|
||||
date
|
||||
timeout (0.4.0)
|
||||
toml-rb (2.2.0)
|
||||
citrus (~> 3.0, > 3.0)
|
||||
tomlrb (1.3.0)
|
||||
train-core (3.10.7)
|
||||
train-core (3.10.8)
|
||||
addressable (~> 2.5)
|
||||
ffi (!= 1.13.0)
|
||||
json (>= 1.8, < 3.0)
|
||||
mixlib-shellout (>= 2.0, < 4.0)
|
||||
net-scp (>= 1.2, < 5.0)
|
||||
net-ssh (>= 2.9, < 8.0)
|
||||
train-rest (0.5.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
rest-client (~> 2.1)
|
||||
train-core (~> 3.0)
|
||||
train-winrm (0.2.13)
|
||||
winrm (>= 2.3.6, < 3.0)
|
||||
winrm-elevated (~> 1.2.2)
|
||||
|
@ -414,13 +449,16 @@ GEM
|
|||
pastel (~> 0.8)
|
||||
strings (~> 0.2.0)
|
||||
tty-screen (~> 0.8)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8.2)
|
||||
unicode-display_width (2.4.2)
|
||||
unicode_utils (1.4.0)
|
||||
uuidtools (2.2.0)
|
||||
vault (0.17.0)
|
||||
aws-sigv4
|
||||
webrick (1.7.0)
|
||||
win32-api (1.5.3-universal-mingw32)
|
||||
webrick (1.8.1)
|
||||
win32-api (1.10.1-universal-mingw32)
|
||||
win32-certstore (0.6.15)
|
||||
chef-powershell (>= 1.0.12)
|
||||
ffi
|
||||
|
|
|
@ -53,6 +53,8 @@ dependency "shebang-cleanup"
|
|||
# Ensure our SSL cert files are accessible to ruby.
|
||||
dependency "openssl-customization"
|
||||
|
||||
dependency "ruby-msys2-devkit" if windows?
|
||||
|
||||
package :rpm do
|
||||
signing_passphrase ENV["OMNIBUS_RPM_SIGNING_PASSPHRASE"]
|
||||
compression_level 1
|
||||
|
|
|
@ -7,3 +7,5 @@ override "ruby", version: "3.1.2"
|
|||
|
||||
# Mac m1
|
||||
override "openssl", version: "1.1.1m" if mac_os_x?
|
||||
|
||||
override "ruby-msys2-devkit", version: "3.1.2-1"
|
442
test/fixtures/cmd/http-windows-remote-get-headers
vendored
Normal file
442
test/fixtures/cmd/http-windows-remote-get-headers
vendored
Normal file
|
@ -0,0 +1,442 @@
|
|||
{
|
||||
"Content": "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style type=\"text/css\">\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</h1>\n <p>This domain is for use in illustrative examples in documents. You may use this\n domain in literature without prior coordination or asking for permission.</p>\n <p><a href=\"https://www.iana.org/domains/example\">More information...</a></p>\n</div>\n</body>\n</html>\n",
|
||||
"ParsedHtml": {
|
||||
"Script": {},
|
||||
"all": [
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject"
|
||||
],
|
||||
"body": {},
|
||||
"activeElement": null,
|
||||
"images": [],
|
||||
"applets": [],
|
||||
"links": [
|
||||
"System.__ComObject"
|
||||
],
|
||||
"forms": [],
|
||||
"anchors": [],
|
||||
"title": "Example Domain",
|
||||
"scripts": [],
|
||||
"designMode": "Inherit",
|
||||
"selection": {},
|
||||
"readyState": "complete",
|
||||
"frames": {},
|
||||
"embeds": [],
|
||||
"plugins": [],
|
||||
"alinkColor": "#0000ff",
|
||||
"bgColor": "#f0f0f2",
|
||||
"fgColor": "#000000",
|
||||
"linkColor": "#0000ff",
|
||||
"vlinkColor": "#800080",
|
||||
"referrer": null,
|
||||
"location": {},
|
||||
"lastModified": "03/07/2021 23:17:45",
|
||||
"url": "about:blank",
|
||||
"domain": null,
|
||||
"cookie": null,
|
||||
"expando": true,
|
||||
"charset": "unicode",
|
||||
"defaultCharset": "windows-1252",
|
||||
"mimeType": "Chrome HTML Document",
|
||||
"fileSize": null,
|
||||
"fileCreatedDate": null,
|
||||
"fileModifiedDate": null,
|
||||
"fileUpdatedDate": null,
|
||||
"security": "This type of document does not have a security certificate.",
|
||||
"protocol": "Unknown Protocol",
|
||||
"nameProp": "Example Domain",
|
||||
"onhelp": null,
|
||||
"onclick": null,
|
||||
"ondblclick": null,
|
||||
"onkeyup": null,
|
||||
"onkeydown": null,
|
||||
"onkeypress": null,
|
||||
"onmouseup": null,
|
||||
"onmousedown": null,
|
||||
"onmousemove": null,
|
||||
"onmouseout": null,
|
||||
"onmouseover": null,
|
||||
"onreadystatechange": null,
|
||||
"onafterupdate": null,
|
||||
"onrowexit": null,
|
||||
"onrowenter": null,
|
||||
"ondragstart": null,
|
||||
"onselectstart": null,
|
||||
"parentWindow": {},
|
||||
"styleSheets": [
|
||||
"System.__ComObject"
|
||||
],
|
||||
"onbeforeupdate": null,
|
||||
"onerrorupdate": null,
|
||||
"documentElement": {},
|
||||
"uniqueID": "ms__id1",
|
||||
"onrowsdelete": null,
|
||||
"onrowsinserted": null,
|
||||
"oncellchange": null,
|
||||
"ondatasetchanged": null,
|
||||
"ondataavailable": null,
|
||||
"ondatasetcomplete": null,
|
||||
"onpropertychange": null,
|
||||
"dir": null,
|
||||
"oncontextmenu": null,
|
||||
"onstop": null,
|
||||
"parentDocument": null,
|
||||
"enableDownload": null,
|
||||
"baseUrl": null,
|
||||
"inheritStyleSheets": null,
|
||||
"onbeforeeditfocus": null,
|
||||
"onselectionchange": null,
|
||||
"namespaces": {},
|
||||
"media": null,
|
||||
"oncontrolselect": null,
|
||||
"URLUnencoded": "about:blank",
|
||||
"onmousewheel": null,
|
||||
"doctype": null,
|
||||
"implementation": {},
|
||||
"onfocusin": null,
|
||||
"onfocusout": null,
|
||||
"onactivate": null,
|
||||
"ondeactivate": null,
|
||||
"onbeforeactivate": null,
|
||||
"onbeforedeactivate": null,
|
||||
"compatMode": "CSS1Compat",
|
||||
"nodeType": 9,
|
||||
"parentNode": null,
|
||||
"childNodes": [
|
||||
"System.__ComObject",
|
||||
"System.__ComObject"
|
||||
],
|
||||
"attributes": null,
|
||||
"nodeName": "#document",
|
||||
"nodeValue": null,
|
||||
"firstChild": {},
|
||||
"lastChild": {},
|
||||
"previousSibling": null,
|
||||
"nextSibling": null,
|
||||
"ownerDocument": null,
|
||||
"IHTMLDocument2_Script": {},
|
||||
"IHTMLDocument2_all": [
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject",
|
||||
"System.__ComObject"
|
||||
],
|
||||
"IHTMLDocument2_body": {},
|
||||
"IHTMLDocument2_activeElement": null,
|
||||
"IHTMLDocument2_images": [],
|
||||
"IHTMLDocument2_applets": [],
|
||||
"IHTMLDocument2_links": [
|
||||
"System.__ComObject"
|
||||
],
|
||||
"IHTMLDocument2_forms": [],
|
||||
"IHTMLDocument2_anchors": [],
|
||||
"IHTMLDocument2_title": "Example Domain",
|
||||
"IHTMLDocument2_scripts": [],
|
||||
"IHTMLDocument2_designMode": "Inherit",
|
||||
"IHTMLDocument2_selection": {},
|
||||
"IHTMLDocument2_readyState": "complete",
|
||||
"IHTMLDocument2_frames": {},
|
||||
"IHTMLDocument2_embeds": [],
|
||||
"IHTMLDocument2_plugins": [],
|
||||
"IHTMLDocument2_alinkColor": "#0000ff",
|
||||
"IHTMLDocument2_bgColor": "#f0f0f2",
|
||||
"IHTMLDocument2_fgColor": "#000000",
|
||||
"IHTMLDocument2_linkColor": "#0000ff",
|
||||
"IHTMLDocument2_vlinkColor": "#800080",
|
||||
"IHTMLDocument2_referrer": null,
|
||||
"IHTMLDocument2_location": null,
|
||||
"IHTMLDocument2_lastModified": "03/07/2021 23:17:45",
|
||||
"IHTMLDocument2_url": "about:blank",
|
||||
"IHTMLDocument2_domain": null,
|
||||
"IHTMLDocument2_cookie": null,
|
||||
"IHTMLDocument2_expando": true,
|
||||
"IHTMLDocument2_charset": "unicode",
|
||||
"IHTMLDocument2_defaultCharset": "windows-1252",
|
||||
"IHTMLDocument2_mimeType": "Chrome HTML Document",
|
||||
"IHTMLDocument2_fileSize": null,
|
||||
"IHTMLDocument2_fileCreatedDate": null,
|
||||
"IHTMLDocument2_fileModifiedDate": null,
|
||||
"IHTMLDocument2_fileUpdatedDate": null,
|
||||
"IHTMLDocument2_security": "This type of document does not have a security certificate.",
|
||||
"IHTMLDocument2_protocol": "Unknown Protocol",
|
||||
"IHTMLDocument2_nameProp": "Example Domain",
|
||||
"IHTMLDocument2_onhelp": null,
|
||||
"IHTMLDocument2_onclick": null,
|
||||
"IHTMLDocument2_ondblclick": null,
|
||||
"IHTMLDocument2_onkeyup": null,
|
||||
"IHTMLDocument2_onkeydown": null,
|
||||
"IHTMLDocument2_onkeypress": null,
|
||||
"IHTMLDocument2_onmouseup": null,
|
||||
"IHTMLDocument2_onmousedown": null,
|
||||
"IHTMLDocument2_onmousemove": null,
|
||||
"IHTMLDocument2_onmouseout": null,
|
||||
"IHTMLDocument2_onmouseover": null,
|
||||
"IHTMLDocument2_onreadystatechange": null,
|
||||
"IHTMLDocument2_onafterupdate": null,
|
||||
"IHTMLDocument2_onrowexit": null,
|
||||
"IHTMLDocument2_onrowenter": null,
|
||||
"IHTMLDocument2_ondragstart": null,
|
||||
"IHTMLDocument2_onselectstart": null,
|
||||
"IHTMLDocument2_parentWindow": {},
|
||||
"IHTMLDocument2_styleSheets": [
|
||||
"System.__ComObject"
|
||||
],
|
||||
"IHTMLDocument2_onbeforeupdate": null,
|
||||
"IHTMLDocument2_onerrorupdate": null,
|
||||
"IHTMLDocument3_documentElement": {},
|
||||
"IHTMLDocument3_uniqueID": "ms__id2",
|
||||
"IHTMLDocument3_onrowsdelete": null,
|
||||
"IHTMLDocument3_onrowsinserted": null,
|
||||
"IHTMLDocument3_oncellchange": null,
|
||||
"IHTMLDocument3_ondatasetchanged": null,
|
||||
"IHTMLDocument3_ondataavailable": null,
|
||||
"IHTMLDocument3_ondatasetcomplete": null,
|
||||
"IHTMLDocument3_onpropertychange": null,
|
||||
"IHTMLDocument3_dir": null,
|
||||
"IHTMLDocument3_oncontextmenu": null,
|
||||
"IHTMLDocument3_onstop": null,
|
||||
"IHTMLDocument3_parentDocument": null,
|
||||
"IHTMLDocument3_enableDownload": null,
|
||||
"IHTMLDocument3_baseUrl": null,
|
||||
"IHTMLDocument3_childNodes": [
|
||||
"System.__ComObject",
|
||||
"System.__ComObject"
|
||||
],
|
||||
"IHTMLDocument3_inheritStyleSheets": null,
|
||||
"IHTMLDocument3_onbeforeeditfocus": null,
|
||||
"IHTMLDocument4_onselectionchange": null,
|
||||
"IHTMLDocument4_namespaces": {},
|
||||
"IHTMLDocument4_media": null,
|
||||
"IHTMLDocument4_oncontrolselect": null,
|
||||
"IHTMLDocument4_URLUnencoded": "about:blank",
|
||||
"IHTMLDocument5_onmousewheel": null,
|
||||
"IHTMLDocument5_doctype": null,
|
||||
"IHTMLDocument5_implementation": {},
|
||||
"IHTMLDocument5_onfocusin": null,
|
||||
"IHTMLDocument5_onfocusout": null,
|
||||
"IHTMLDocument5_onactivate": null,
|
||||
"IHTMLDocument5_ondeactivate": null,
|
||||
"IHTMLDocument5_onbeforeactivate": null,
|
||||
"IHTMLDocument5_onbeforedeactivate": null,
|
||||
"IHTMLDocument5_compatMode": "CSS1Compat",
|
||||
"IHTMLDOMNode_nodeType": null,
|
||||
"IHTMLDOMNode_parentNode": null,
|
||||
"IHTMLDOMNode_childNodes": null,
|
||||
"IHTMLDOMNode_attributes": null,
|
||||
"IHTMLDOMNode_nodeName": null,
|
||||
"IHTMLDOMNode_nodeValue": null,
|
||||
"IHTMLDOMNode_firstChild": null,
|
||||
"IHTMLDOMNode_lastChild": null,
|
||||
"IHTMLDOMNode_previousSibling": null,
|
||||
"IHTMLDOMNode_nextSibling": null,
|
||||
"IHTMLDOMNode2_ownerDocument": null
|
||||
},
|
||||
"Forms": [],
|
||||
"InputFields": [],
|
||||
"Links": [
|
||||
{
|
||||
"innerHTML": "More information...",
|
||||
"innerText": "More information...",
|
||||
"outerHTML": "<A href=\"https://www.iana.org/domains/example\">More information...</A>",
|
||||
"outerText": "More information...",
|
||||
"tagName": "A",
|
||||
"href": "https://www.iana.org/domains/example"
|
||||
}
|
||||
],
|
||||
"Images": [],
|
||||
"Scripts": [],
|
||||
"AllElements": [
|
||||
{
|
||||
"innerHTML": null,
|
||||
"innerText": null,
|
||||
"outerHTML": null,
|
||||
"outerText": null,
|
||||
"tagName": "!"
|
||||
},
|
||||
{
|
||||
"innerHTML": "<HEAD><TITLE>Example Domain</TITLE>\r\n<META charset=utf-8>\r\n<META name=viewport content=\"width=device-width, initial-scale=1\">\r\n<STYLE type=text/css>\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </STYLE>\r\n</HEAD>\r\n<BODY>\r\n<DIV>\r\n<H1>Example Domain</H1>\r\n<P>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</P>\r\n<P><A href=\"https://www.iana.org/domains/example\">More information...</A></P></DIV></BODY>",
|
||||
"innerText": "Example DomainExample Domain\r\nThis domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\r\nMore information...",
|
||||
"outerHTML": "<HTML><HEAD><TITLE>Example Domain</TITLE>\r\n<META charset=utf-8>\r\n<META name=viewport content=\"width=device-width, initial-scale=1\">\r\n<STYLE type=text/css>\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </STYLE>\r\n</HEAD>\r\n<BODY>\r\n<DIV>\r\n<H1>Example Domain</H1>\r\n<P>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</P>\r\n<P><A href=\"https://www.iana.org/domains/example\">More information...</A></P></DIV></BODY></HTML>",
|
||||
"outerText": "Example DomainExample Domain\r\nThis domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\r\nMore information...",
|
||||
"tagName": "HTML"
|
||||
},
|
||||
{
|
||||
"innerHTML": "<TITLE>Example Domain</TITLE>\r\n<META charset=utf-8>\r\n<META name=viewport content=\"width=device-width, initial-scale=1\">\r\n<STYLE type=text/css>\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </STYLE>",
|
||||
"innerText": "Example Domain",
|
||||
"outerHTML": "<HEAD><TITLE>Example Domain</TITLE>\r\n<META charset=utf-8>\r\n<META name=viewport content=\"width=device-width, initial-scale=1\">\r\n<STYLE type=text/css>\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </STYLE>\r\n</HEAD>",
|
||||
"outerText": "Example Domain",
|
||||
"tagName": "HEAD"
|
||||
},
|
||||
{
|
||||
"innerHTML": "Example Domain",
|
||||
"innerText": "Example Domain",
|
||||
"outerHTML": "<TITLE>Example Domain</TITLE>",
|
||||
"outerText": "Example Domain",
|
||||
"tagName": "TITLE"
|
||||
},
|
||||
{
|
||||
"innerHTML": null,
|
||||
"innerText": null,
|
||||
"outerHTML": "\r\n<META charset=utf-8>",
|
||||
"outerText": null,
|
||||
"tagName": "META",
|
||||
"charset": "utf-8"
|
||||
},
|
||||
{
|
||||
"innerHTML": null,
|
||||
"innerText": null,
|
||||
"outerHTML": null,
|
||||
"outerText": null,
|
||||
"tagName": "META"
|
||||
},
|
||||
{
|
||||
"innerHTML": null,
|
||||
"innerText": null,
|
||||
"outerHTML": "\r\n<META name=viewport content=\"width=device-width, initial-scale=1\">",
|
||||
"outerText": null,
|
||||
"tagName": "META",
|
||||
"name": "viewport",
|
||||
"content": "width=device-width, initial-scale=1"
|
||||
},
|
||||
{
|
||||
"innerHTML": "\r\n\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n ",
|
||||
"innerText": null,
|
||||
"outerHTML": "\r\n<STYLE type=text/css>\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </STYLE>",
|
||||
"outerText": null,
|
||||
"tagName": "STYLE",
|
||||
"type": "text/css"
|
||||
},
|
||||
{
|
||||
"innerHTML": "<DIV>\r\n<H1>Example Domain</H1>\r\n<P>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</P>\r\n<P><A href=\"https://www.iana.org/domains/example\">More information...</A></P></DIV>",
|
||||
"innerText": "Example Domain\r\nThis domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\r\nMore information...",
|
||||
"outerHTML": "\r\n<BODY><DIV>\r\n<H1>Example Domain</H1>\r\n<P>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</P>\r\n<P><A href=\"https://www.iana.org/domains/example\">More information...</A></P></DIV></BODY>",
|
||||
"outerText": "Example Domain\r\nThis domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\r\nMore information...",
|
||||
"tagName": "BODY"
|
||||
},
|
||||
{
|
||||
"innerHTML": "<H1>Example Domain</H1>\r\n<P>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</P>\r\n<P><A href=\"https://www.iana.org/domains/example\">More information...</A></P>",
|
||||
"innerText": "Example Domain\r\nThis domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\r\nMore information...",
|
||||
"outerHTML": "\r\n<DIV><H1>Example Domain</H1>\r\n<P>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</P>\r\n<P><A href=\"https://www.iana.org/domains/example\">More information...</A></P></DIV>",
|
||||
"outerText": "Example Domain\r\nThis domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\r\nMore information...",
|
||||
"tagName": "DIV"
|
||||
},
|
||||
{
|
||||
"innerHTML": "Example Domain",
|
||||
"innerText": "Example Domain",
|
||||
"outerHTML": "\r\n<H1>Example Domain</H1>",
|
||||
"outerText": "Example Domain",
|
||||
"tagName": "H1"
|
||||
},
|
||||
{
|
||||
"innerHTML": "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.",
|
||||
"innerText": "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.",
|
||||
"outerHTML": "\r\n<P>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</P>",
|
||||
"outerText": "This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.",
|
||||
"tagName": "P"
|
||||
},
|
||||
{
|
||||
"innerHTML": "<A href=\"https://www.iana.org/domains/example\">More information...</A>",
|
||||
"innerText": "More information...",
|
||||
"outerHTML": "\r\n<P><A href=\"https://www.iana.org/domains/example\">More information...</A></P>",
|
||||
"outerText": "More information...",
|
||||
"tagName": "P"
|
||||
},
|
||||
{
|
||||
"innerHTML": "More information...",
|
||||
"innerText": "More information...",
|
||||
"outerHTML": "<A href=\"https://www.iana.org/domains/example\">More information...</A>",
|
||||
"outerText": "More information...",
|
||||
"tagName": "A",
|
||||
"href": "https://www.iana.org/domains/example"
|
||||
}
|
||||
],
|
||||
"StatusCode": 200,
|
||||
"StatusDescription": "OK",
|
||||
"RawContentStream": {
|
||||
"CanRead": true,
|
||||
"CanSeek": true,
|
||||
"CanTimeout": false,
|
||||
"CanWrite": true,
|
||||
"Length": 1256,
|
||||
"Capacity": 10000,
|
||||
"Position": 0,
|
||||
"ReadTimeout": null,
|
||||
"WriteTimeout": null
|
||||
},
|
||||
"RawContentLength": 1256,
|
||||
"RawContent": "HTTP/1.1 200 OK\r\nAge: 156043\r\nVary: Accept-Encoding\r\nX-Cache: HIT\r\nAccept-Ranges: bytes\r\nContent-Length: 1256\r\nCache-Control: max-age=604800\r\nContent-Type: text/html; charset=UTF-8\r\nDate: Mon, 08 Mar 2021 07:17:44 GMT\r\nExpires: Mon, 15 Mar 2021 07:17:44 GMT\r\nETag: \"3147526947\"\r\nLast-Modified: Thu, 17 Oct 2019 07:18:26 GMT\r\nServer: ECS (oxr/836D)\r\n\r\n<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style type=\"text/css\">\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</h1>\n <p>This domain is for use in illustrative examples in documents. You may use this\n domain in literature without prior coordination or asking for permission.</p>\n <p><a href=\"https://www.iana.org/domains/example\">More information...</a></p>\n</div>\n</body>\n</html>\n",
|
||||
"BaseResponse": {
|
||||
"IsMutuallyAuthenticated": false,
|
||||
"Cookies": [],
|
||||
"Headers": [
|
||||
"Age",
|
||||
"Vary",
|
||||
"X-Cache",
|
||||
"Accept-Ranges",
|
||||
"Content-Length",
|
||||
"Cache-Control",
|
||||
"Content-Type",
|
||||
"Date",
|
||||
"Expires",
|
||||
"ETag",
|
||||
"Last-Modified",
|
||||
"Server"
|
||||
],
|
||||
"SupportsHeaders": true,
|
||||
"ContentLength": 1256,
|
||||
"ContentEncoding": "",
|
||||
"ContentType": "text/html; charset=UTF-8",
|
||||
"CharacterSet": "UTF-8",
|
||||
"Server": "ECS (oxr/836D)",
|
||||
"LastModified": "/Date(1571296706000)/",
|
||||
"StatusCode": 200,
|
||||
"StatusDescription": "OK",
|
||||
"ProtocolVersion": {
|
||||
"Major": 1,
|
||||
"Minor": 1,
|
||||
"Build": -1,
|
||||
"Revision": -1,
|
||||
"MajorRevision": -1,
|
||||
"MinorRevision": -1
|
||||
},
|
||||
"ResponseUri": "https://www.example.com/",
|
||||
"Method": "GET",
|
||||
"IsFromCache": false
|
||||
},
|
||||
"Headers": {
|
||||
"Age": "156043",
|
||||
"Vary": "Accept-Encoding",
|
||||
"X-Cache": "HIT",
|
||||
"Accept-Ranges": "bytes",
|
||||
"Content-Length": "1256",
|
||||
"Cache-Control": "max-age=604800",
|
||||
"Content-Type": "text/html; charset=UTF-8",
|
||||
"Date": "Mon, 08 Mar 2021 07:17:44 GMT",
|
||||
"Expires": "Mon, 15 Mar 2021 07:17:44 GMT",
|
||||
"ETag": "\"3147526947\"",
|
||||
"Last-Modified": "Thu, 17 Oct 2019 07:18:26 GMT",
|
||||
"Server": "ECS (oxr/836D)"
|
||||
}
|
||||
}
|
7
test/fixtures/cmd/nftables-chain
vendored
Normal file
7
test/fixtures/cmd/nftables-chain
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
table inet filter {
|
||||
chain INPUT {
|
||||
type filter hook input priority 0; policy accept;
|
||||
iifname "eth0" tcp dport 80 accept comment "http on 80"
|
||||
jump derby-cognos-web
|
||||
}
|
||||
}
|
1
test/fixtures/cmd/nftables-chain-json
vendored
Normal file
1
test/fixtures/cmd/nftables-chain-json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"nftables": [{"metainfo": {"version": "1.0.2", "release_name": "Lester Gooch", "json_schema_version": 1}}, {"chain": {"family": "inet", "table": "filter", "name": "INPUT", "handle": 1, "type": "filter", "hook": "input", "prio": 0, "policy": "accept"}}, {"rule": {"family": "inet", "table": "filter", "chain": "INPUT", "handle": 4, "comment": "http on 80", "expr": [{"match": {"op": "==", "left": {"meta": {"key": "iifname"}}, "right": "eth0"}}, {"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 80}}, {"accept": null}]}}, {"rule": {"family": "inet", "table": "filter", "chain": "INPUT", "handle": 5, "expr": [{"jump": {"target": "derby-cognos-web"}}]}}]}
|
8
test/fixtures/cmd/nftables-set
vendored
Normal file
8
test/fixtures/cmd/nftables-set
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
table inet filter {
|
||||
set OPEN_PORTS {
|
||||
type ipv4_addr
|
||||
size 65536
|
||||
flags interval
|
||||
elements = { 1.1.1.1 }
|
||||
}
|
||||
}
|
1
test/fixtures/cmd/nftables-set-json
vendored
Normal file
1
test/fixtures/cmd/nftables-set-json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"nftables": [{"metainfo": {"version": "1.0.2", "release_name": "Lester Gooch", "json_schema_version": 1}}, {"set": {"family": "inet", "name": "OPEN_PORTS", "table": "filter", "type": "ipv4_addr", "handle": 3, "size": 65536, "flags": ["interval"], "elem": ["1.1.1.1"]}}]}
|
1
test/fixtures/cmd/nftables-version
vendored
Normal file
1
test/fixtures/cmd/nftables-version
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
nftables v1.0.2 (Lester Gooch)
|
|
@ -1,93 +0,0 @@
|
|||
# Error
|
||||
control "tmp-1.0.1" do
|
||||
impact 0.7
|
||||
describe "a.1" do
|
||||
it { should_bot "a.1" }
|
||||
end
|
||||
end
|
||||
|
||||
control "tmp-1.0.2" do
|
||||
impact 0.0
|
||||
describe "a.2" do
|
||||
it { should_bot "a.2" }
|
||||
end
|
||||
end
|
||||
|
||||
# Not Applicable
|
||||
control "tmp-2.0.1" do
|
||||
impact 0.0
|
||||
describe "b.1" do
|
||||
it { should cmp "b.1" }
|
||||
end
|
||||
end
|
||||
|
||||
control "tmp-2.0.2" do
|
||||
impact 0.0
|
||||
only_if { false }
|
||||
describe "b.2" do
|
||||
it { should cmp "b.2" }
|
||||
end
|
||||
end
|
||||
|
||||
# Not Reviewed
|
||||
control "tmp-3.0.1" do
|
||||
only_if { false }
|
||||
describe "c.1" do
|
||||
it { should cmp "c.1" }
|
||||
end
|
||||
end
|
||||
|
||||
control "tmp-3.0.2" do
|
||||
only_if { false }
|
||||
describe "c.2" do
|
||||
it { should_bot "c.2" }
|
||||
end
|
||||
end
|
||||
|
||||
control "tmp-3.0.3" do
|
||||
only_if { false }
|
||||
describe "c.2" do
|
||||
it { should_bot "c.2" }
|
||||
end
|
||||
end
|
||||
|
||||
control "tmp-3.0.4" do
|
||||
only_if { false }
|
||||
describe "c.2" do
|
||||
it { should_bot "c.2" }
|
||||
end
|
||||
end
|
||||
|
||||
# Failed
|
||||
control "tmp-4.0" do
|
||||
impact 0.7
|
||||
describe "d.1" do
|
||||
it { should_not cmp "d.1" }
|
||||
it { should cmp "d.1" }
|
||||
end
|
||||
end
|
||||
|
||||
# Passed
|
||||
control "tmp-5.0" do
|
||||
impact 0.7
|
||||
describe "e.1" do
|
||||
it { should cmp "e.1" }
|
||||
end
|
||||
end
|
||||
|
||||
# Example of setting impact using code and marking it N/A
|
||||
control "tmp-6.0.1" do
|
||||
impact 0.5
|
||||
only_if("Some reason for N/A", impact: 0.0) { false }
|
||||
describe "f.1" do
|
||||
it { should cmp "f.1" }
|
||||
end
|
||||
end
|
||||
|
||||
# Example of setting impact using code and not marked as N/A
|
||||
control "tmp-6.0.2" do
|
||||
only_if(impact: 0.5) { false }
|
||||
describe "f.2" do
|
||||
it { should cmp "f.2" }
|
||||
end
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
control_id,justification,explanation,evidence_url,status,expiration_date,updated,frequency
|
||||
tmp-3.0.1,Sound reasoning,,Dummy url,failed,2001-06-01T00:00:00.000Z,,,
|
||||
tmp-3.0.2,,Unassailable thinking,Dummy url,failed,,2021-06-01T00:00:00.000Z,semiannually
|
||||
tmp-4.0,Sheer cleverness,,Dummy url,passed,2050-06-01T00:00:00.000Z,,,
|
||||
tmp-6.0.2,Sheer cleverness,,Dummy url,passed,2050-06-01T00:00:00.000Z,,,
|
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"tmp-3.0.1": {
|
||||
"explanation": "Sound reasoning",
|
||||
"evidence_url": "Dummy url",
|
||||
"status": "failed",
|
||||
"updated": "2021-06-01T00:00:00.000Z",
|
||||
"frequency": "semiannually"
|
||||
},
|
||||
"tmp-3.0.2": {
|
||||
"justification": "Unassailable thinking",
|
||||
"evidence_url": "Dummy url",
|
||||
"expiration_date": "2001-06-01T00:00:00.000Z",
|
||||
"status": "passed"
|
||||
},
|
||||
"tmp-4.0": {
|
||||
"justification": "Sheer cleverness",
|
||||
"evidence_url": "Dummy url",
|
||||
"expiration_date": "2050-06-01T00:00:00.000Z",
|
||||
"status": "passed"
|
||||
},
|
||||
"tmp-6.0.2": {
|
||||
"justification": "Sheer cleverness",
|
||||
"evidence_url": "Dummy url",
|
||||
"expiration_date": "2050-06-01T00:00:00.000Z",
|
||||
"status": "passed"
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -1,24 +0,0 @@
|
|||
tmp-3.0.1:
|
||||
explanation: Sound reasoning
|
||||
evidence_url: Dummy url
|
||||
status: failed
|
||||
updated: 2021-06-01
|
||||
frequency: semiannually
|
||||
|
||||
tmp-3.0.2:
|
||||
justification: Unassailable thinking
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2001-06-01
|
||||
status: passed
|
||||
|
||||
tmp-4.0:
|
||||
justification: Sheer cleverness
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2050-06-01
|
||||
status: passed
|
||||
|
||||
tmp-6.0.2:
|
||||
justification: Sheer cleverness
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2050-06-01
|
||||
status: passed
|
|
@ -1,5 +0,0 @@
|
|||
tmp-3.0.2:
|
||||
justification: Unassailable thinking
|
||||
evidence_url: Dummy url
|
||||
expiration_date: bad date
|
||||
status: passed
|
|
@ -1,6 +0,0 @@
|
|||
tmp-3.0.1:
|
||||
justification: Sound reasoning
|
||||
evidence_url: Dummy url
|
||||
status: failed
|
||||
updated: bad date
|
||||
frequency: semiannually
|
|
@ -1,6 +0,0 @@
|
|||
tmp-3.0.4:
|
||||
justification: Sound reasoning
|
||||
evidence_url: Dummy url
|
||||
status: failed
|
||||
updated: 2021-06-01
|
||||
frequency: biweekly
|
|
@ -1,5 +0,0 @@
|
|||
tmp-3.0.3:
|
||||
justification: Unassailable thinking
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2050-06-01
|
||||
status: pass
|
|
@ -1,7 +0,0 @@
|
|||
tmp-3.0.1:
|
||||
expiration_date: 2050-06-01
|
||||
status: passed
|
||||
tmp-3.0.2:
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2050-06-01
|
||||
status: passed
|
|
@ -1,4 +0,0 @@
|
|||
tmp-3.0.3:
|
||||
justification: Unassailable thinking
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2050-06-01
|
|
@ -1,8 +0,0 @@
|
|||
control_id_random,justification_random,run_random,expiration_date_random,,,
|
||||
03_waivered_no_expiry_ran_passes,Sound reasoning,TRUE,,,,
|
||||
04_waivered_no_expiry_ran_fails,Unassailable thinking,TRUE,2077-11-10T00:00:00Z,,,
|
||||
,,,,,,
|
||||
05_waivered_no_expiry_not_ran,Sheer cleverness,FALSE,,,,
|
||||
06_waivered_expiry_in_past_ran_passes,Necessity,TRUE,,,,
|
||||
14_waivered_expiry_in_future_z_not_ran,Lack of imagination,FALSE,2077-11-10T00:00:00Z,,,
|
||||
random contorl id with no data,,,,,,random data in csv!
|
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"tmp-3.0.1": {
|
||||
"justification": "Sound reasoning",
|
||||
"evidence_url": "Dummy url",
|
||||
"expiration_date": "2050-06-01T00:00:00.000Z",
|
||||
"status": "passed",
|
||||
"random": "haha"
|
||||
},
|
||||
"tmp-3.0.2": {
|
||||
"justification": "Unassailable thinking",
|
||||
"evidence_url": "Dummy url",
|
||||
"expiration_date": "2050-06-01T00:00:00.000Z",
|
||||
"status": "passed"
|
||||
},
|
||||
"tmp-4.0": {
|
||||
"justification": "Sheer cleverness",
|
||||
"evidence_url": "Dummy url",
|
||||
"expiration_date": "2050-06-01T00:00:00.000Z",
|
||||
"status": "passed"
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,18 +0,0 @@
|
|||
tmp-3.0.1:
|
||||
justification: Sound reasoning
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2050-06-01
|
||||
status: passed
|
||||
random: haha
|
||||
|
||||
tmp-3.0.2:
|
||||
justification: Unassailable thinking
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2050-06-01
|
||||
status: passed
|
||||
|
||||
tmp-4.0:
|
||||
justification: Sheer cleverness
|
||||
evidence_url: Dummy url
|
||||
expiration_date: 2050-06-01
|
||||
status: passed
|
10
test/fixtures/profiles/attestation/inspec.yml
vendored
10
test/fixtures/profiles/attestation/inspec.yml
vendored
|
@ -1,10 +0,0 @@
|
|||
name: attestation
|
||||
title: InSpec Profile
|
||||
maintainer: The Authors
|
||||
copyright: The Authors
|
||||
copyright_email: you@example.com
|
||||
license: Apache-2.0
|
||||
summary: An InSpec Compliance Profile
|
||||
version: 0.1.0
|
||||
supports:
|
||||
platform: os
|
|
@ -1,177 +0,0 @@
|
|||
require "functional/helper"
|
||||
|
||||
describe "attestations" do
|
||||
include FunctionalHelper
|
||||
|
||||
parallelize_me!
|
||||
|
||||
let(:attestation_profile) { "#{profile_path}/attestation" }
|
||||
let(:run_result) { run_inspec_process(cmd) }
|
||||
let(:cmd) { "exec #{attestation_profile} --attestation-file #{attestation_profile}/files/#{attestation_file}" }
|
||||
|
||||
attr_accessor :out
|
||||
|
||||
def inspec(commandline, prefix = nil)
|
||||
@stdout = @stderr = nil
|
||||
self.out = super
|
||||
end
|
||||
|
||||
def stdout
|
||||
@stdout ||= out.stdout
|
||||
.force_encoding(Encoding::UTF_8)
|
||||
end
|
||||
|
||||
def stderr
|
||||
@stderr ||= out.stderr
|
||||
.force_encoding(Encoding::UTF_8)
|
||||
end
|
||||
|
||||
describe "with a attestation file that does not exist" do
|
||||
let(:attestation_file) { "no_file.yaml" }
|
||||
it "raise file does not exist standard error" do
|
||||
result = run_result
|
||||
assert_includes result.stderr, "no_file.yaml does not exist"
|
||||
assert_equal 1, result.exit_status
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a attestation file that has wrong headers - yaml format" do
|
||||
let(:attestation_file) { "wrong-headers.yaml" }
|
||||
it "raise file does not exist standard error" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "Extra column headers: [\"random\"]"
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a attestation file that has wrong headers - csv format" do
|
||||
let(:attestation_file) { "wrong-headers.csv" }
|
||||
it "raise file does not exist standard error" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "Missing column headers: [\"control_id\", \"status\", \"justification\"]"
|
||||
assert_includes result.stdout, "Extra column headers: [\"control_id_random\", \"justification_random\", \"run_random\", \"expiration_date_random\", nil]\n"
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a attestation file that has wrong headers - json format" do
|
||||
let(:attestation_file) { "wrong-headers.json" }
|
||||
it "raise file does not exist standard error" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "Extra column headers: [\"random\"]"
|
||||
end
|
||||
end
|
||||
|
||||
describe "running attestation on a profile - yaml" do
|
||||
let(:attestation_file) { "attestations.yaml" }
|
||||
|
||||
it "attests N/R controls correctly" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "tmp-3.0.1: No-op (1 failed)"
|
||||
refute_includes result.stdout, "N/R tmp-3.0.2: No-op"
|
||||
refute_includes result.stdout, "N/R tmp-6.0.2: No-op"
|
||||
end
|
||||
|
||||
it "does not attests non N/R controls" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "tmp-4.0: d.1 (1 failed)"
|
||||
end
|
||||
end
|
||||
|
||||
describe "running attestation on a profile - json" do
|
||||
let(:attestation_file) { "attestations.json" }
|
||||
|
||||
it "attests N/R controls correctly" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "tmp-3.0.1: No-op (1 failed)"
|
||||
refute_includes result.stdout, "N/R tmp-3.0.2: No-op"
|
||||
refute_includes result.stdout, "N/R tmp-6.0.2: No-op"
|
||||
end
|
||||
|
||||
it "does not attests non N/R controls" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "tmp-4.0: d.1 (1 failed)"
|
||||
end
|
||||
end
|
||||
|
||||
describe "running attestation on a profile - csv" do
|
||||
let(:attestation_file) { "attestations.csv" }
|
||||
|
||||
it "attests N/R controls correctly" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "tmp-3.0.1: No-op (1 failed)"
|
||||
refute_includes result.stdout, "N/R tmp-3.0.2: No-op"
|
||||
refute_includes result.stdout, "N/R tmp-6.0.2: No-op"
|
||||
end
|
||||
|
||||
it "does not attests non N/R controls" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "tmp-4.0: d.1 (1 failed)"
|
||||
end
|
||||
end
|
||||
|
||||
describe "running attestation on profile with streaming reporter" do
|
||||
let(:attestation_file) { "#{attestation_profile}/files/attestations.yaml" }
|
||||
it "attests controls correctly" do
|
||||
inspec("exec " + "#{attestation_profile}" + " --attestation-file #{attestation_file}" + " --no-create-lockfile" + " --no-color" + " --reporter progress-bar")
|
||||
if windows?
|
||||
_(stderr).must_match(/\[FAIL\]\s*tmp-3.0.1\s*No-op Skipped control due to only_if condition. Control not attested : Attestation expired on 2021-12-01/)
|
||||
_(stderr).must_match(/\[FAIL\]\s*tmp-3.0.2\s*No-op Skipped control due to only_if condition. Control not attested : Attestation expired on 2001-06-01/)
|
||||
_(stderr).must_match(/\[PASS\]\s*tmp-6.0.2\s*No-op Skipped control due to only_if condition. Control Attested : Sheer cleverness | Evidence URL: Dummy url/)
|
||||
_(stderr).must_match(/\[FAIL\]\s*tmp-4.0\s*d.1 is expected to cmp == \"d.1\"/)
|
||||
else
|
||||
_(stderr).must_match(/\[FAILED\]\s*tmp-3.0.1\s*No-op Skipped control due to only_if condition. Control not attested : Attestation expired on 2021-12-01/)
|
||||
_(stderr).must_match(/\[FAILED\]\s*tmp-3.0.2\s*No-op Skipped control due to only_if condition. Control not attested : Attestation expired on 2001-06-01/)
|
||||
_(stderr).must_match(/\[PASSED\]\s*tmp-6.0.2\s*No-op Skipped control due to only_if condition. Control Attested : Sheer cleverness | Evidence URL: Dummy url/)
|
||||
_(stderr).must_match(/\[FAILED\]\s*tmp-4.0\s*d.1 is expected to cmp == \"d.1\"/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "an attestation file with invalid dates" do
|
||||
let(:attestation_file) { "bad-date.yaml" }
|
||||
it "gracefully errors" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "ERROR"
|
||||
end
|
||||
end
|
||||
|
||||
describe "an attestation file with invalid update dates" do
|
||||
let(:attestation_file) { "bad-update-date.yaml" }
|
||||
it "gracefully errors" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "ERROR"
|
||||
end
|
||||
end
|
||||
|
||||
describe "an attestation file with invalid status" do
|
||||
let(:attestation_file) { "invalid-status.yaml" }
|
||||
it "throws warning" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "Invalid attestation status 'pass' for control tmp-3.0.3. Use 'passed' or 'failed'."
|
||||
end
|
||||
end
|
||||
|
||||
describe "an attestation file with no status" do
|
||||
let(:attestation_file) { "no-status.yaml" }
|
||||
it "throws warning" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "No attestation status for control tmp-3.0.3. Use 'passed' or 'failed'."
|
||||
end
|
||||
end
|
||||
|
||||
describe "an attestation file with invalid frequency value" do
|
||||
let(:attestation_file) { "invalid-frequency.yaml" }
|
||||
it "throws warning" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "Invalid frequency value 'biweekly' for control tmp-3.0.4."
|
||||
end
|
||||
end
|
||||
|
||||
describe "an attestation file with no justification" do
|
||||
let(:attestation_file) { "no-justification.yaml" }
|
||||
it "throws warning and shows proper message for justification absence" do
|
||||
result = run_result
|
||||
assert_includes result.stdout, "Missing column headers: [\"justification\"]"
|
||||
assert_includes result.stdout, "Control Attested : No justification provided."
|
||||
end
|
||||
end
|
||||
end
|
|
@ -105,6 +105,7 @@ describe "inputs" do
|
|||
# require inspec
|
||||
require "inspec"
|
||||
require "inspec/runner"
|
||||
require "inspec/utils/licensing_config"
|
||||
|
||||
# inject pretty-printed runner opts
|
||||
runner_args = #{options.inspect}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
require "functional/helper"
|
||||
require "inspec/runner"
|
||||
require "inspec/resources/file"
|
||||
require "inspec/utils/licensing_config"
|
||||
|
||||
describe "inspec report tests" do
|
||||
include FunctionalHelper
|
||||
|
||||
describe "report" do
|
||||
it "loads a json report" do
|
||||
WebMock.allow_net_connect!
|
||||
o = { "reporter" => ["json"], "report" => true }
|
||||
runner = ::Inspec::Runner.new(o)
|
||||
runner.add_target(example_profile)
|
||||
|
|
|
@ -385,6 +385,24 @@ class MockLoader
|
|||
# ip6tables
|
||||
"/usr/sbin/ip6tables -S" => cmd.call("ip6tables-s"),
|
||||
%{sh -c 'type "/usr/sbin/ip6tables"'} => empty.call,
|
||||
# nftables (version)
|
||||
"/usr/sbin/nft --version" => cmd.call("nftables-version"),
|
||||
# nftables (chain with json output)
|
||||
"/usr/sbin/nft -s -j list chain inet filter INPUT" => cmd.call("nftables-chain-json"),
|
||||
"/usr/sbin/nft -j list chain inet filter INPUT" => cmd.call("nftables-chain-json"),
|
||||
# nftables (chain)
|
||||
"/usr/sbin/nft -s list chain inet filter INPUT" => cmd.call("nftables-chain"),
|
||||
"/usr/sbin/nft -s -y list chain inet filter INPUT" => cmd.call("nftables-chain"),
|
||||
"/usr/sbin/nft -s -nn list chain inet filter INPUT" => cmd.call("nftables-chain"),
|
||||
"/usr/sbin/nft -y list chain inet filter INPUT" => cmd.call("nftables-chain"),
|
||||
"/usr/sbin/nft list chain inet filter INPUT" => cmd.call("nftables-chain"),
|
||||
# nftables (set with json output)
|
||||
"/usr/sbin/nft -s -j list set inet filter OPEN_PORTS" => cmd.call("nftables-set-json"),
|
||||
"/usr/sbin/nft -j list set inet filter OPEN_PORTS" => cmd.call("nftables-set-json"),
|
||||
# nftables (set)
|
||||
"/usr/sbin/nft -s list set inet filter OPEN_PORTS" => cmd.call("nftables-set"),
|
||||
"/usr/sbin/nft list set inet filter OPEN_PORTS" => cmd.call("nftables-set"),
|
||||
%{sh -c 'type "/usr/sbin/nft"'} => empty.call,
|
||||
# ipnat
|
||||
"/usr/sbin/ipnat -l" => cmd.call("ipnat-l"),
|
||||
%{type "/usr/sbin/ipnat"} => empty.call,
|
||||
|
@ -631,6 +649,7 @@ class MockLoader
|
|||
# http resource - windows
|
||||
"\n$body = \n $Body = $body | ConvertFrom-Json\n #convert to hashtable\n $HashTable = @{}\n foreach ($property in $Body.PSObject.Properties) {\n $HashTable[$property.Name] = $property.Value\n }\n $response = Invoke-WebRequest -Method HEAD -TimeoutSec 120 'https://www.example.com' -Body $HashTable -UseBasicParsing\n $response | Select-Object -Property * | ConvertTo-json # We use `Select-Object -Property * ` to get around an odd PowerShell error" => cmd.call("http-windows-remote-no-options"),
|
||||
"\n$body = \n $Body = $body | ConvertFrom-Json\n #convert to hashtable\n $HashTable = @{}\n foreach ($property in $Body.PSObject.Properties) {\n $HashTable[$property.Name] = $property.Value\n }\n $response = Invoke-WebRequest -Method GET -TimeoutSec 120 'https://www.example.com' -Body $HashTable -UseBasicParsing\n $response | Select-Object -Property * | ConvertTo-json # We use `Select-Object -Property * ` to get around an odd PowerShell error" => cmd.call("http-windows-remote-head"),
|
||||
"\n$body = \n $Body = $body | ConvertFrom-Json\n #convert to hashtable\n $HashTable = @{}\n foreach ($property in $Body.PSObject.Properties) {\n $HashTable[$property.Name] = $property.Value\n }\n $response = Invoke-WebRequest -Method GET -TimeoutSec 120 -Headers @{ 'X-Test-Header' = 'test/value'; 'foo' = 'bar'} 'https://www.example.com' -Body $HashTable -UseBasicParsing\n $response | Select-Object -Property * | ConvertTo-json # We use `Select-Object -Property * ` to get around an odd PowerShell error" => cmd.call("http-windows-remote-get-headers"),
|
||||
"\n$body = '{ \"a\" : \"1\", \"b\" : \"five\" }'\n $Body = $body | ConvertFrom-Json\n #convert to hashtable\n $HashTable = @{}\n foreach ($property in $Body.PSObject.Properties) {\n $HashTable[$property.Name] = $property.Value\n }\n $response = Invoke-WebRequest -Method POST -TimeoutSec 120 'https://www.example.com' -Body $HashTable -UseBasicParsing\n $response | Select-Object -Property * | ConvertTo-json # We use `Select-Object -Property * ` to get around an odd PowerShell error" => cmd.call("http-windows-remote-head"),
|
||||
# elasticsearch resource
|
||||
"curl -H 'Content-Type: application/json' http://localhost:9200/_nodes" => cmd.call("elasticsearch-cluster-nodes-default"),
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
default["osprepare"]["docker"] = false
|
||||
default["osprepare"]["application"] = true
|
||||
default["osprepare"]["nftables"] = false
|
||||
|
|
|
@ -26,7 +26,11 @@ include_recipe("os_prepare::service")
|
|||
include_recipe("os_prepare::package")
|
||||
include_recipe("os_prepare::registry_key")
|
||||
include_recipe("os_prepare::iis")
|
||||
include_recipe("os_prepare::iptables")
|
||||
if node["osprepare"]["nftables"]
|
||||
include_recipe("os_prepare::nftables")
|
||||
else
|
||||
include_recipe("os_prepare::iptables")
|
||||
end
|
||||
include_recipe("os_prepare::x509")
|
||||
include_recipe("os_prepare::dh_params")
|
||||
|
||||
|
|
12
test/kitchen/cookbooks/os_prepare/recipes/nftables.rb
Normal file
12
test/kitchen/cookbooks/os_prepare/recipes/nftables.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
if platform_family?("rhel", "debian", "fedora", "suse")
|
||||
package "nftables"
|
||||
execute "nft flush ruleset"
|
||||
execute "nft add table inet filter"
|
||||
execute 'nft add chain inet filter INPUT \{ type filter hook input priority 0\; policy accept\; \}'
|
||||
execute "nft add chain inet filter derby-cognos-web"
|
||||
execute 'nft add set inet filter OPEN_PORTS \{ type ipv4_addr\; size 65536\; flags interval\; \}'
|
||||
execute 'nft add rule inet filter INPUT iifname eth0 tcp dport 80 accept comment \"http on 80\"'
|
||||
execute "nft add rule inet filter INPUT jump derby-cognos-web"
|
||||
execute 'nft add rule inet filter derby-cognos-web tcp dport 80 accept comment "derby-cognos-web"'
|
||||
execute 'nft add element inet filter OPEN_PORTS \{ 1.1.1.1/32 \}'
|
||||
end
|
|
@ -2,6 +2,10 @@ unless ENV['IPV6']
|
|||
$stderr.puts "\033[1;33mTODO: Not running #{__FILE__.split("/").last} because we are running without IPv6\033[0m"
|
||||
return
|
||||
end
|
||||
if ENV['NFTABLES']
|
||||
$stderr.puts "\033[1;33mTODO: Not running #{__FILE__.split("/").last} because we are running with nftables\033[0m"
|
||||
return
|
||||
end
|
||||
|
||||
case os[:family]
|
||||
when 'ubuntu', 'fedora', 'debian', 'suse'
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
if ENV['NFTABLES']
|
||||
$stderr.puts "\033[1;33mTODO: Not running #{__FILE__.split("/").last} because we are running with nftables\033[0m"
|
||||
return
|
||||
end
|
||||
|
||||
case os[:family]
|
||||
when 'ubuntu', 'fedora', 'debian', 'suse'
|
||||
describe iptables do
|
||||
|
|
23
test/kitchen/policies/default/controls/nftables_spec.rb
Normal file
23
test/kitchen/policies/default/controls/nftables_spec.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
unless ENV['NFTABLES']
|
||||
$stderr.puts "\033[1;33mTODO: Not running #{__FILE__.split("/").last} because we are running with iptables\033[0m"
|
||||
return
|
||||
end
|
||||
|
||||
case os[:family]
|
||||
when 'ubuntu', 'fedora', 'debian', 'suse', 'redhat', 'centos'
|
||||
describe nftables(family: 'inet', table: 'filter', chain: 'INPUT') do
|
||||
its('type') { should eq 'filter' }
|
||||
its('hook') { should eq 'input' }
|
||||
its('prio') { should eq 0 }
|
||||
its('policy') { should eq 'accept' }
|
||||
it { should have_rule('iifname "eth0" tcp dport 80 accept comment "http on 80"') }
|
||||
it { should_not have_rule('iifname "eth1" tcp dport 80 accept') }
|
||||
end
|
||||
|
||||
describe nftables(family: 'inet', table: 'filter', set: 'OPEN_PORTS') do
|
||||
its('type') { should eq 'ipv4_addr' }
|
||||
its('flags') { should include 'interval' }
|
||||
it { should have_element('1.1.1.1') }
|
||||
it { should_not have_element('2.2.2.2') }
|
||||
end
|
||||
end
|
|
@ -323,7 +323,7 @@ class PluginLoaderTests < Minitest::Test
|
|||
skip "not valid in this env" unless using_bundler?
|
||||
|
||||
with_empty_registry do
|
||||
exp = %i{ train-aws train-habitat train-winrm }
|
||||
exp = %i{ train-aws train-habitat train-kubernetes train-winrm }
|
||||
exp_err = ""
|
||||
|
||||
assert_detect_system_plugins exp, exp_err do |loader|
|
||||
|
|
|
@ -35,7 +35,7 @@ describe "Inspec::Resources::Host" do
|
|||
resource = MockLoader.new(:windows).load_resource("host", "microsoft.com")
|
||||
_(resource.resolvable?).must_equal true
|
||||
_(resource.reachable?).must_equal false
|
||||
_(resource.ipaddress).must_equal ["134.170.188.221", "2404:6800:4009:827::200e"]
|
||||
_(resource.ipaddress).must_equal ["134.170.185.46", "134.170.188.221", "2404:6800:4009:827::200e"]
|
||||
_(resource.to_s).must_equal "Host microsoft.com"
|
||||
_(resource.resource_id).must_equal "microsoft.com"
|
||||
end
|
||||
|
@ -107,7 +107,7 @@ describe "Inspec::Resources::Host" do
|
|||
resource = MockLoader.new(:windows).load_resource("host", "microsoft.com", port: 1234, protocol: "tcp")
|
||||
_(resource.resolvable?).must_equal true
|
||||
_(resource.reachable?).must_equal true
|
||||
_(resource.ipaddress).must_equal ["134.170.188.221", "2404:6800:4009:827::200e"]
|
||||
_(resource.ipaddress).must_equal ["134.170.185.46", "134.170.188.221", "2404:6800:4009:827::200e"]
|
||||
_(resource.to_s).must_equal "Host microsoft.com port 1234 proto tcp"
|
||||
_(resource.resource_id).must_equal "microsoft.com-1234-tcp"
|
||||
end
|
||||
|
@ -379,7 +379,7 @@ describe Inspec::Resources::UnixHostProvider do
|
|||
|
||||
it "checks ipv4_address and ipv6_address properties on windows" do
|
||||
resource = MockLoader.new(:windows).load_resource("host", "microsoft.com")
|
||||
_(resource.ipv4_address).must_equal ["134.170.188.221"]
|
||||
_(resource.ipv4_address).must_equal ["134.170.185.46", "134.170.188.221"]
|
||||
_(resource.ipv4_address).must_include "134.170.188.221"
|
||||
_(resource.ipv6_address).must_equal ["2404:6800:4009:827::200e"]
|
||||
_(resource.ipv6_address).must_include "2404:6800:4009:827::200e"
|
||||
|
|
|
@ -314,4 +314,25 @@ describe "Inspec::Resources::Http" do
|
|||
_(worker.resource_id).must_equal "https://www.example.com"
|
||||
end
|
||||
end
|
||||
|
||||
describe "Windows-Get-With-Headers" do
|
||||
let(:backend) { MockLoader.new(:windows).backend }
|
||||
let(:http_method) { "GET" }
|
||||
let(:url) { "https://www.example.com" }
|
||||
let(:opts) { { headers: { "X-Test-Header" => "test/value", "foo" => "bar" } } }
|
||||
let(:worker) { Inspec::Resources::Http::Worker::Remote.new(backend, http_method, url, opts) }
|
||||
|
||||
describe "simple HTTP request with headers" do
|
||||
it "returns correct data" do
|
||||
Inspec::Resources::Cmd.any_instance
|
||||
.stubs(:exist?)
|
||||
.returns(true)
|
||||
_(worker.status).must_equal 200
|
||||
_(worker.response_headers["Content-Type"]).must_equal "text/html; charset=UTF-8"
|
||||
_(worker.resource_id).must_equal "https://www.example.com"
|
||||
expected_cmd = "Invoke-WebRequest -Method GET -TimeoutSec 120 -Headers @{ 'X-Test-Header' = 'test/value'; 'foo' = 'bar'} 'https://www.example.com' -Body $HashTable -UseBasicParsing"
|
||||
_(worker.send(:load_powershell_command)).must_include expected_cmd
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
27
test/unit/resources/nftables_test.rb
Normal file
27
test/unit/resources/nftables_test.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
require "helper"
|
||||
require "inspec/resource"
|
||||
require "inspec/resources/nftables"
|
||||
|
||||
describe "Inspec::Resources::NfTables" do
|
||||
|
||||
# ubuntu
|
||||
it "verify nftables chain on ubuntu" do
|
||||
resource = MockLoader.new(:ubuntu).load_resource("nftables", { family: "inet", table: "filter", chain: "INPUT" })
|
||||
_(resource.type).must_equal "filter"
|
||||
_(resource.hook).must_equal "input"
|
||||
_(resource.prio).must_equal 0
|
||||
_(resource.policy).must_equal "accept"
|
||||
_(resource.has_rule?('iifname "eth0" tcp dport 80 accept comment "http on 80"')).must_equal true
|
||||
_(resource.has_rule?('iifname "eth1" tcp dport 80 accept')).must_equal false
|
||||
_(resource.resource_id).must_equal "nftables (family: inet table: filter chain: INPUT )"
|
||||
end
|
||||
it "verify nftables set on ubuntu" do
|
||||
resource = MockLoader.new(:ubuntu).load_resource("nftables", { family: "inet", table: "filter", set: "OPEN_PORTS" })
|
||||
_(resource.type).must_equal "ipv4_addr"
|
||||
_(resource.flags).must_include "interval"
|
||||
_(resource.size).must_equal 65536
|
||||
_(resource.has_element?("1.1.1.1")).must_equal true
|
||||
_(resource.has_element?("2.2.2.2")).must_equal false
|
||||
_(resource.resource_id).must_equal "nftables (family: inet table: filter set: OPEN_PORTS)"
|
||||
end
|
||||
end
|
|
@ -39,7 +39,11 @@ describe "Inspec::Resources::PostgresSession" do
|
|||
end
|
||||
it "verify postgres_session create_psql_cmd in socket connection" do
|
||||
resource = load_resource("postgres_session", "myuser", "mypass", "127.0.0.1", 5432, "/var/run/postgresql")
|
||||
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "psql -d postgresql://myuser:mypass@/testdb?host=/var/run/postgresql -A -t -w -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
|
||||
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "psql -d postgresql://myuser:mypass@/testdb?host=/var/run/postgresql -p 5432 -A -t -w -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
|
||||
end
|
||||
it "verify postgres_session create_psql_cmd in socket connection" do
|
||||
resource = load_resource("postgres_session", "myuser", "mypass", "127.0.0.1", 1234, "/var/run/postgresql")
|
||||
_(resource.send(:create_psql_cmd, "SELECT * FROM STUDENTS;", ["testdb"])).must_equal "psql -d postgresql://myuser:mypass@/testdb?host=/var/run/postgresql -p 1234 -A -t -w -c SELECT\\ \\*\\ FROM\\ STUDENTS\\;"
|
||||
end
|
||||
|
||||
it "fails when no connection established in linux" do
|
||||
|
|
|
@ -4,6 +4,7 @@ require "helper"
|
|||
require "inspec/secrets"
|
||||
require "inspec/runner"
|
||||
require "inspec/fetcher/mock"
|
||||
require "inspec/utils/licensing_config"
|
||||
|
||||
describe Inspec::Runner do
|
||||
let(:runner) { Inspec::Runner.new({ command_runner: :generic, reporter: [] }) }
|
||||
|
@ -73,6 +74,7 @@ describe Inspec::Runner do
|
|||
|
||||
describe "testing runner.run exit codes" do
|
||||
it "returns proper exit code when no profile is added" do
|
||||
WebMock.allow_net_connect!
|
||||
_(runner.run).must_equal 0
|
||||
end
|
||||
end
|
||||
|
|
18
test/unit/utils/license_config_test.rb
Normal file
18
test/unit/utils/license_config_test.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
require "helper"
|
||||
require "inspec/utils/licensing_config"
|
||||
|
||||
describe "ChefLicensing::Config" do
|
||||
it "returns the default chef product name as foo" do
|
||||
expect(ChefLicensing::Config.chef_product_name).must_equal("InSpec")
|
||||
end
|
||||
|
||||
it "returns the default chef_entitlement_id" do
|
||||
expect(ChefLicensing::Config.chef_entitlement_id).must_equal("3ff52c37-e41f-4f6c-ad4d-365192205968")
|
||||
end
|
||||
|
||||
it "returns the default chef_executable_name" do
|
||||
expect(ChefLicensing::Config.chef_executable_name).must_equal("inspec")
|
||||
end
|
||||
|
||||
# TODO: Need to add the test for license_server_url.
|
||||
end
|
|
@ -101,4 +101,9 @@ describe "SimpleConfig Default Parser" do
|
|||
cur = SimpleConfig.new("1:2:3", assignment_regex: /^(.*):(.*):(.*)$/, key_values: 4)
|
||||
_(cur.params).must_equal({ "1" => ["2", "3", nil, nil] })
|
||||
end
|
||||
|
||||
it "supports :mulitple values and returns array of values" do
|
||||
cur = SimpleConfig.new("foo: bar\nbiz: baz boz bop\nbiz: cdsdcs cdscs csc\nbiz: ada\nfoz: foo [!deny] bar", assignment_regex: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/, multiple_values: true, multiple_value_regex: /\s+/)
|
||||
_(cur.params).must_equal({ "foo" => ["bar"], "biz" => %w{baz boz bop cdsdcs cdscs csc ada}, "foz" => ["foo", "[!deny]", "bar"] })
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue