inspec-core 4.22.8 → 4.23.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +2 -1
- data/inspec-core.gemspec +3 -5
- data/lib/bundles/inspec-supermarket/cli.rb +1 -1
- data/lib/inspec/base_cli.rb +11 -1
- data/lib/inspec/cli.rb +4 -2
- data/lib/inspec/config.rb +19 -1
- data/lib/inspec/input.rb +4 -3
- data/lib/inspec/input_registry.rb +7 -1
- data/lib/inspec/plugin/v2/plugin_types/reporter.rb +4 -31
- data/lib/inspec/reporters.rb +0 -3
- data/lib/inspec/reporters/automate.rb +3 -3
- data/lib/inspec/reporters/base.rb +7 -29
- data/lib/inspec/resources/apt.rb +5 -5
- data/lib/inspec/resources/bridge.rb +1 -1
- data/lib/inspec/resources/host.rb +1 -1
- data/lib/inspec/resources/mysql_session.rb +9 -5
- data/lib/inspec/resources/postgres.rb +1 -1
- data/lib/inspec/resources/postgres_session.rb +5 -3
- data/lib/inspec/resources/processes.rb +1 -1
- data/lib/inspec/resources/windows_firewall.rb +110 -0
- data/lib/inspec/resources/windows_firewall_rule.rb +137 -0
- data/lib/inspec/rule.rb +8 -8
- data/lib/inspec/run_data/profile.rb +3 -2
- data/lib/inspec/schema/exec_json.rb +1 -1
- data/lib/inspec/shell.rb +3 -3
- data/lib/inspec/utils/parser.rb +1 -1
- data/lib/inspec/utils/run_data_filters.rb +104 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-compliance/lib/inspec-compliance/api.rb +4 -4
- data/lib/plugins/inspec-compliance/lib/inspec-compliance/cli.rb +1 -1
- data/lib/plugins/inspec-init/templates/profiles/aws/README.md +1 -1
- data/lib/plugins/inspec-reporter-html2/README.md +1 -1
- data/lib/plugins/inspec-reporter-junit/README.md +17 -0
- data/lib/plugins/inspec-reporter-junit/lib/inspec-reporter-junit.rb +21 -0
- data/lib/plugins/inspec-reporter-junit/lib/inspec-reporter-junit/reporter.rb +155 -0
- data/lib/plugins/inspec-reporter-junit/lib/inspec-reporter-junit/version.rb +5 -0
- data/lib/plugins/shared/core_plugin_test_helper.rb +0 -16
- metadata +17 -34
- data/README.md +0 -474
- data/lib/inspec/reporters/junit.rb +0 -77
| @@ -19,7 +19,7 @@ module Inspec::Resources | |
| 19 19 | 
             
                    @conf_path = File.join @conf_dir, "postgresql.conf"
         | 
| 20 20 | 
             
                  else
         | 
| 21 21 | 
             
                    @conf_path = nil
         | 
| 22 | 
            -
                     | 
| 22 | 
            +
                    skip_resource "Seems like PostgreSQL is not installed on your system"
         | 
| 23 23 | 
             
                  end
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| @@ -26,12 +26,13 @@ module Inspec::Resources | |
| 26 26 | 
             
                supports platform: "windows"
         | 
| 27 27 | 
             
                desc "Use the postgres_session InSpec audit resource to test SQL commands run against a PostgreSQL database."
         | 
| 28 28 | 
             
                example <<~EXAMPLE
         | 
| 29 | 
            -
                  sql = postgres_session('username', 'password', 'host')
         | 
| 29 | 
            +
                  sql = postgres_session('username', 'password', 'host', 'port')
         | 
| 30 30 | 
             
                  query('sql_query', ['database_name'])` contains the query and (optional) database to execute
         | 
| 31 31 |  | 
| 32 32 | 
             
                  # default values:
         | 
| 33 33 | 
             
                  # username: 'postgres'
         | 
| 34 34 | 
             
                  # host: 'localhost'
         | 
| 35 | 
            +
                  # port: 5432
         | 
| 35 36 | 
             
                  # db: databse == db_user running the sql query
         | 
| 36 37 |  | 
| 37 38 | 
             
                  describe sql.query('SELECT * FROM pg_shadow WHERE passwd IS NULL;') do
         | 
| @@ -39,10 +40,11 @@ module Inspec::Resources | |
| 39 40 | 
             
                  end
         | 
| 40 41 | 
             
                EXAMPLE
         | 
| 41 42 |  | 
| 42 | 
            -
                def initialize(user, pass, host = nil)
         | 
| 43 | 
            +
                def initialize(user, pass, host = nil, port = nil)
         | 
| 43 44 | 
             
                  @user = user || "postgres"
         | 
| 44 45 | 
             
                  @pass = pass
         | 
| 45 46 | 
             
                  @host = host || "localhost"
         | 
| 47 | 
            +
                  @port = port || 5432
         | 
| 46 48 | 
             
                end
         | 
| 47 49 |  | 
| 48 50 | 
             
                def query(query, db = [])
         | 
| @@ -64,7 +66,7 @@ module Inspec::Resources | |
| 64 66 |  | 
| 65 67 | 
             
                def create_psql_cmd(query, db = [])
         | 
| 66 68 | 
             
                  dbs = db.map { |x| "-d #{x}" }.join(" ")
         | 
| 67 | 
            -
                  "PGPASSWORD='#{@pass}' psql -U #{@user} #{dbs} -h #{@host} -A -t -c #{escaped_query(query)}"
         | 
| 69 | 
            +
                  "PGPASSWORD='#{@pass}' psql -U #{@user} #{dbs} -h #{@host} -p #{@port} -A -t -c #{escaped_query(query)}"
         | 
| 68 70 | 
             
                end
         | 
| 69 71 | 
             
              end
         | 
| 70 72 | 
             
            end
         | 
| @@ -138,7 +138,7 @@ module Inspec::Resources | |
| 138 138 | 
             
                      command: 8,
         | 
| 139 139 | 
             
                    }
         | 
| 140 140 | 
             
                  else
         | 
| 141 | 
            -
                    command = "ps  | 
| 141 | 
            +
                    command = "ps wwaxo label,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user:32,command"
         | 
| 142 142 | 
             
                    regex = /^(.+?)\s+(\d+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(\w{3} \d{2}|\d{2}:\d{2}:\d{2})\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
         | 
| 143 143 | 
             
                    field_map = {
         | 
| 144 144 | 
             
                      label: 1,
         | 
| @@ -0,0 +1,110 @@ | |
| 1 | 
            +
            module Inspec::Resources
         | 
| 2 | 
            +
              class WindowsFirewall < Inspec.resource(1)
         | 
| 3 | 
            +
                name "windows_firewall"
         | 
| 4 | 
            +
                supports platform: "windows"
         | 
| 5 | 
            +
                desc "Check properties of the Windows Firewall for a specific profile."
         | 
| 6 | 
            +
                example <<~EXAMPLE
         | 
| 7 | 
            +
                  describe windows_firewall("Public") do
         | 
| 8 | 
            +
                    it { should be_enabled }
         | 
| 9 | 
            +
                    its("default_inbound_action") { should_not cmp "NotConfigured" }
         | 
| 10 | 
            +
                    its("num_rules") { should be 19 }
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                EXAMPLE
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def initialize(profile = "Public")
         | 
| 15 | 
            +
                  @profile = profile
         | 
| 16 | 
            +
                  @state = {}
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  load_profile_cmd = load_firewall_profile(profile)
         | 
| 19 | 
            +
                  cmd = inspec.powershell(load_profile_cmd)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  @state = JSON.load(cmd.stdout) unless cmd.stdout.empty?
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def to_s
         | 
| 25 | 
            +
                  "Windows Firewall (Profile #{@profile})"
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def exist?
         | 
| 29 | 
            +
                  !@state.empty?
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def enabled?
         | 
| 33 | 
            +
                  @state["enabled"]
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def default_inbound_allowed?
         | 
| 37 | 
            +
                  @state["default_inbound_action"] == "Allow"
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def default_outbound_allowed?
         | 
| 41 | 
            +
                  @state["default_outbound_action"] == "Allow"
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                # Access to return values from Powershell via `its("PROPERTY")` and `have_PROPERTY "VALUE"`
         | 
| 45 | 
            +
                def method_missing(method_name, *arguments, &_block)
         | 
| 46 | 
            +
                  property = normalize_for_have_access(method_name)
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  if method_name.to_s.start_with? "has_"
         | 
| 49 | 
            +
                    expected_value = arguments.first
         | 
| 50 | 
            +
                    respond_to_have(property, expected_value)
         | 
| 51 | 
            +
                  else
         | 
| 52 | 
            +
                    access_property(property)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def respond_to_missing?(method_name, _include_private = false)
         | 
| 57 | 
            +
                  property = normalize_for_have_access(method_name)
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  @state.key? property
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                private
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def normalize_for_have_access(property)
         | 
| 65 | 
            +
                  property.to_s
         | 
| 66 | 
            +
                    .delete_prefix("has_")
         | 
| 67 | 
            +
                    .delete_suffix("?")
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def access_property(property)
         | 
| 71 | 
            +
                  @state[property]
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def respond_to_have(property, value)
         | 
| 75 | 
            +
                  @state[property] == value
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                def load_firewall_profile(profile_name)
         | 
| 79 | 
            +
                  <<-EOH
         | 
| 80 | 
            +
                    Remove-TypeData System.Array # workaround for PS bug here: https://bit.ly/2SRMQ8M
         | 
| 81 | 
            +
                    $profile = Get-NetFirewallProfile -Name "#{profile_name}"
         | 
| 82 | 
            +
                    $count = @($profile | Get-NetFirewallRule).Count
         | 
| 83 | 
            +
                    ([PSCustomObject]@{
         | 
| 84 | 
            +
                      profile_name = $profile.Name
         | 
| 85 | 
            +
                      profile = $profile.Profile.ToString()
         | 
| 86 | 
            +
                      description = $profile.Description
         | 
| 87 | 
            +
                      enabled = [bool]::Parse($profile.Enabled.ToString())
         | 
| 88 | 
            +
                      default_inbound_action = $profile.DefaultInboundAction.ToString()
         | 
| 89 | 
            +
                      default_outbound_action = $profile.DefaultOutboundAction.ToString()
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                      allow_inbound_rules = $profile.AllowInboundRules.ToString()
         | 
| 92 | 
            +
                      allow_local_firewall_rules = $profile.AllowLocalFirewallRules.ToString()
         | 
| 93 | 
            +
                      allow_local_ipsec_rules = $profile.AllowLocalIPsecRules.ToString()
         | 
| 94 | 
            +
                      allow_user_apps = $profile.AllowUserApps.ToString()
         | 
| 95 | 
            +
                      allow_user_ports = $profile.AllowUserPorts.ToString()
         | 
| 96 | 
            +
                      allow_unicast_response_to_multicast = $profile.AllowUnicastResponseToMulticast.ToString()
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                      notify_on_listen = $profile.NotifyOnListen.ToString()
         | 
| 99 | 
            +
                      enable_stealth_mode_for_ipsec = $profile.EnableStealthModeForIPsec.ToString()
         | 
| 100 | 
            +
                      log_max_size_kilobytes = $profile.LogMaxSizeKilobytes
         | 
| 101 | 
            +
                      log_allowed = $profile.LogAllowed.ToString()
         | 
| 102 | 
            +
                      log_blocked = $profile.LogBlocked.ToString()
         | 
| 103 | 
            +
                      log_ignored = $profile.LogIgnored.ToString()
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                      num_rules = $count
         | 
| 106 | 
            +
                    }) | ConvertTo-Json
         | 
| 107 | 
            +
                  EOH
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
            end
         | 
| @@ -0,0 +1,137 @@ | |
| 1 | 
            +
            module Inspec::Resources
         | 
| 2 | 
            +
              class WindowsFirewallRule < Inspec.resource(1)
         | 
| 3 | 
            +
                name "windows_firewall_rule"
         | 
| 4 | 
            +
                supports platform: "windows"
         | 
| 5 | 
            +
                desc "Check properties of a Windows Firewall rule."
         | 
| 6 | 
            +
                example <<~EXAMPLE
         | 
| 7 | 
            +
                  describe windows_firewall_rule("Name") do
         | 
| 8 | 
            +
                    it { should exist }
         | 
| 9 | 
            +
                    it { should be_enabled }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    it { should be_outbound}
         | 
| 12 | 
            +
                    it { should be_tcp }
         | 
| 13 | 
            +
                    it { should have_remote_port 80 }
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                EXAMPLE
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def initialize(name)
         | 
| 18 | 
            +
                  @name = name
         | 
| 19 | 
            +
                  @state = {}
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  query = load_firewall_state(name)
         | 
| 22 | 
            +
                  cmd = inspec.powershell(query)
         | 
| 23 | 
            +
                  @state = JSON.load(cmd.stdout) unless cmd.stdout.empty?
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def to_s
         | 
| 27 | 
            +
                  "Windows Firewall Rule #{@name}"
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def exist?
         | 
| 31 | 
            +
                  !@state.empty?
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def enabled?
         | 
| 35 | 
            +
                  @state["enabled"]
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def allowed?
         | 
| 39 | 
            +
                  @state["action"] == "Allow"
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def inbound?
         | 
| 43 | 
            +
                  @state["direction"] == "Inbound"
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def outbound?
         | 
| 47 | 
            +
                  ! inbound?
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def tcp?
         | 
| 51 | 
            +
                  @state["protocol"] == "TCP"
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def udp?
         | 
| 55 | 
            +
                  @state["protocol"] == "UDP"
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def icmp?
         | 
| 59 | 
            +
                  @state["protocol"].start_with? "ICMP"
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def icmpv4?
         | 
| 63 | 
            +
                  @state["protocol"] == "ICMPv4"
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def icmpv6?
         | 
| 67 | 
            +
                  @state["protocol"] == "ICMPv6"
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                # Access to return values from Powershell via `its("PROPERTY")` and `have_PROPERTY? "VALUE"`
         | 
| 71 | 
            +
                def method_missing(method_name, *arguments, &_block)
         | 
| 72 | 
            +
                  property = normalize_for_have_access(method_name)
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                  if method_name.to_s.start_with? "has_"
         | 
| 75 | 
            +
                    expected_value = arguments.first
         | 
| 76 | 
            +
                    respond_to_have(property, expected_value)
         | 
| 77 | 
            +
                  else
         | 
| 78 | 
            +
                    access_property(property)
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def respond_to_missing?(method_name, _include_private = false)
         | 
| 83 | 
            +
                  property = normalize_for_have_access(method_name)
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  @state.key? property
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                private
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                def normalize_for_have_access(property)
         | 
| 91 | 
            +
                  property.to_s
         | 
| 92 | 
            +
                    .delete_prefix("has_")
         | 
| 93 | 
            +
                    .delete_suffix("?")
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                def access_property(property)
         | 
| 97 | 
            +
                  @state[property]
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                def respond_to_have(property, value)
         | 
| 101 | 
            +
                  @state[property] == value
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                # Taken from Chef, but changed `firewall_action` to `action` for consistency
         | 
| 105 | 
            +
                # @see https://github.com/chef/chef/blob/master/lib/chef/resource/windows_firewall_rule.rb
         | 
| 106 | 
            +
                def load_firewall_state(rule_name)
         | 
| 107 | 
            +
                  <<-EOH
         | 
| 108 | 
            +
                    Remove-TypeData System.Array # workaround for PS bug here: https://bit.ly/2SRMQ8M
         | 
| 109 | 
            +
                    $rule = Get-NetFirewallRule -Name "#{rule_name}"
         | 
| 110 | 
            +
                    $addressFilter = $rule | Get-NetFirewallAddressFilter
         | 
| 111 | 
            +
                    $portFilter = $rule | Get-NetFirewallPortFilter
         | 
| 112 | 
            +
                    $applicationFilter = $rule | Get-NetFirewallApplicationFilter
         | 
| 113 | 
            +
                    $serviceFilter = $rule | Get-NetFirewallServiceFilter
         | 
| 114 | 
            +
                    $interfaceTypeFilter = $rule | Get-NetFirewallInterfaceTypeFilter
         | 
| 115 | 
            +
                    ([PSCustomObject]@{
         | 
| 116 | 
            +
                      rule_name = $rule.Name
         | 
| 117 | 
            +
                      description = $rule.Description
         | 
| 118 | 
            +
                      displayname = $rule.DisplayName
         | 
| 119 | 
            +
                      group = $rule.Group
         | 
| 120 | 
            +
                      local_address = $addressFilter.LocalAddress
         | 
| 121 | 
            +
                      local_port = $portFilter.LocalPort
         | 
| 122 | 
            +
                      remote_address = $addressFilter.RemoteAddress
         | 
| 123 | 
            +
                      remote_port = $portFilter.RemotePort
         | 
| 124 | 
            +
                      direction = $rule.Direction.ToString()
         | 
| 125 | 
            +
                      protocol = $portFilter.Protocol
         | 
| 126 | 
            +
                      icmp_type = $portFilter.IcmpType
         | 
| 127 | 
            +
                      action = $rule.Action.ToString()
         | 
| 128 | 
            +
                      profile = $rule.Profile.ToString()
         | 
| 129 | 
            +
                      program = $applicationFilter.Program
         | 
| 130 | 
            +
                      service = $serviceFilter.Service
         | 
| 131 | 
            +
                      interface_type = $interfaceTypeFilter.InterfaceType.ToString()
         | 
| 132 | 
            +
                      enabled = [bool]::Parse($rule.Enabled.ToString())
         | 
| 133 | 
            +
                    }) | ConvertTo-Json
         | 
| 134 | 
            +
                  EOH
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
              end
         | 
| 137 | 
            +
            end
         | 
    
        data/lib/inspec/rule.rb
    CHANGED
    
    | @@ -343,14 +343,8 @@ module Inspec | |
| 343 343 | 
             
                  __waiver_data["skipped_due_to_waiver"] = false
         | 
| 344 344 | 
             
                  __waiver_data["message"] = ""
         | 
| 345 345 |  | 
| 346 | 
            -
                  #  | 
| 347 | 
            -
                  #  | 
| 348 | 
            -
                  # is false-like, since all non-skipped waiver operations are handled
         | 
| 349 | 
            -
                  # during reporting phase.
         | 
| 350 | 
            -
                  return unless __waiver_data.key?("run") && !__waiver_data["run"]
         | 
| 351 | 
            -
             | 
| 352 | 
            -
                  # OK, the intent is to skip. Does it have an expiration date, and
         | 
| 353 | 
            -
                  # if so, is it in the future?
         | 
| 346 | 
            +
                  # Does it have an expiration date, and if so, is it in the future?
         | 
| 347 | 
            +
                  # This sets a waiver message before checking `run: true`
         | 
| 354 348 | 
             
                  expiry = __waiver_data["expiration_date"]
         | 
| 355 349 | 
             
                  if expiry
         | 
| 356 350 | 
             
                    # YAML will automagically give us a Date or a Time.
         | 
| @@ -370,6 +364,12 @@ module Inspec | |
| 370 364 | 
             
                    end
         | 
| 371 365 | 
             
                  end
         | 
| 372 366 |  | 
| 367 | 
            +
                  # Waivers should have a hash value with keys possibly including "run" and
         | 
| 368 | 
            +
                  # expiration_date. We only care here if it has a "run" key and it
         | 
| 369 | 
            +
                  # is false-like, since all non-skipped waiver operations are handled
         | 
| 370 | 
            +
                  # during reporting phase.
         | 
| 371 | 
            +
                  return unless __waiver_data.key?("run") && !__waiver_data["run"]
         | 
| 372 | 
            +
             | 
| 373 373 | 
             
                  # OK, apply a skip.
         | 
| 374 374 | 
             
                  @__skip_rule[:result] = true
         | 
| 375 375 | 
             
                  @__skip_rule[:type] = :waiver
         | 
| @@ -96,11 +96,12 @@ module Inspec | |
| 96 96 | 
             
                      # There are probably others
         | 
| 97 97 | 
             
                      :value,
         | 
| 98 98 | 
             
                      :type,
         | 
| 99 | 
            -
                      :required
         | 
| 99 | 
            +
                      :required,
         | 
| 100 | 
            +
                      :sensitive
         | 
| 100 101 | 
             
                    ) do
         | 
| 101 102 | 
             
                      include HashLikeStruct
         | 
| 102 103 | 
             
                      def initialize(raw_opts_data)
         | 
| 103 | 
            -
                        %i{value type required}.each { |f| self[f] = raw_opts_data[f] }
         | 
| 104 | 
            +
                        %i{value type required sensitive}.each { |f| self[f] = raw_opts_data[f] }
         | 
| 104 105 | 
             
                      end
         | 
| 105 106 | 
             
                    end
         | 
| 106 107 | 
             
                  end
         | 
| @@ -74,7 +74,7 @@ module Inspec | |
| 74 74 | 
             
                    },
         | 
| 75 75 | 
             
                  }, [CONTROL_DESCRIPTION, Primitives::REFERENCE, Primitives::SOURCE_LOCATION, CONTROL_RESULT])
         | 
| 76 76 |  | 
| 77 | 
            -
                  # Based loosely on https:// | 
| 77 | 
            +
                  # Based loosely on https://docs.chef.io/inspec/profiles/ as of July 3, 2019
         | 
| 78 78 | 
             
                  # However, concessions were made to the reality of current reporters, specifically
         | 
| 79 79 | 
             
                  # with how description is omitted and version/inspec_version aren't as advertised online
         | 
| 80 80 | 
             
                  PROFILE = Primitives::SchemaType.new("Exec JSON Profile", {
         | 
    
        data/lib/inspec/shell.rb
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            autoload :Pry, "pry"
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Inspec
         | 
| 4 4 | 
             
              # A pry based shell for inspec. Given a runner (with a configured backend and
         | 
| @@ -137,7 +137,7 @@ module Inspec | |
| 137 137 | 
             
                    end
         | 
| 138 138 |  | 
| 139 139 | 
             
                    info += "#{mark "Web Reference:"}\n\n"
         | 
| 140 | 
            -
                    info += "https:// | 
| 140 | 
            +
                    info += "https://docs.chef.io/inspec/resources/#{topic}\n\n"
         | 
| 141 141 | 
             
                    puts info
         | 
| 142 142 | 
             
                  else
         | 
| 143 143 | 
             
                    begin
         | 
| @@ -208,7 +208,7 @@ module Inspec | |
| 208 208 |  | 
| 209 209 | 
             
                      its('content') { should_not match /^MyKey:\\s+some value/ }
         | 
| 210 210 |  | 
| 211 | 
            -
                    For more examples, see: https:// | 
| 211 | 
            +
                    For more examples, see: https://docs.chef.io/inspec/matchers/
         | 
| 212 212 |  | 
| 213 213 | 
             
                  EOL
         | 
| 214 214 | 
             
                end
         | 
    
        data/lib/inspec/utils/parser.rb
    CHANGED
    
    
| @@ -0,0 +1,104 @@ | |
| 1 | 
            +
            module Inspec
         | 
| 2 | 
            +
              module Utils
         | 
| 3 | 
            +
                #   RunDataFilters is a mixin for core Reporters and plugin reporters.
         | 
| 4 | 
            +
                # The methods operate on the run_data Hash (prior to any conversion to a
         | 
| 5 | 
            +
                # full RunData object).
         | 
| 6 | 
            +
                #   All methods here operate using the run_data accessor and modify
         | 
| 7 | 
            +
                # its contents in place (if needed).
         | 
| 8 | 
            +
                module RunDataFilters
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  # Long name, but we want to be clear this operates on the Hash
         | 
| 11 | 
            +
                  # This is the only method that client libraries need to call; any future
         | 
| 12 | 
            +
                  # feature growth should be handled internally here.
         | 
| 13 | 
            +
                  def apply_run_data_filters_to_hash
         | 
| 14 | 
            +
                    @config[:runtime_config] = Inspec::Config.cached || {}
         | 
| 15 | 
            +
                    apply_report_resize_options
         | 
| 16 | 
            +
                    redact_sensitive_inputs
         | 
| 17 | 
            +
                    suppress_diff_output
         | 
| 18 | 
            +
                    sort_controls
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  # Apply options such as message truncation and removal of backtraces
         | 
| 22 | 
            +
                  def apply_report_resize_options
         | 
| 23 | 
            +
                    runtime_config = @config[:runtime_config]
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    message_truncation = runtime_config[:reporter_message_truncation] || "ALL"
         | 
| 26 | 
            +
                    @trunc = message_truncation == "ALL" ? -1 : message_truncation.to_i
         | 
| 27 | 
            +
                    include_backtrace = runtime_config[:reporter_backtrace_inclusion].nil? ? true : runtime_config[:reporter_backtrace_inclusion]
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    @run_data[:profiles]&.each do |p|
         | 
| 30 | 
            +
                      p[:controls].each do |c|
         | 
| 31 | 
            +
                        c[:results]&.map! do |r|
         | 
| 32 | 
            +
                          r.delete(:backtrace) unless include_backtrace
         | 
| 33 | 
            +
                          process_message_truncation(r)
         | 
| 34 | 
            +
                        end
         | 
| 35 | 
            +
                      end
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  # Find any inputs with :sensitive = true and replace their values with "***"
         | 
| 40 | 
            +
                  def redact_sensitive_inputs
         | 
| 41 | 
            +
                    @run_data[:profiles]&.each do |p|
         | 
| 42 | 
            +
                      p[:inputs]&.each do |i|
         | 
| 43 | 
            +
                        next unless i[:options][:sensitive]
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                        i[:options][:value] = "***"
         | 
| 46 | 
            +
                      end
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  # Optionally suppress diff output in the message field
         | 
| 51 | 
            +
                  def suppress_diff_output
         | 
| 52 | 
            +
                    return if @config[:runtime_config][:diff]
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    @run_data[:profiles]&.each do |p|
         | 
| 55 | 
            +
                      p[:controls]&.each do |c|
         | 
| 56 | 
            +
                        c[:results]&.each do |r|
         | 
| 57 | 
            +
                          next unless r[:message] # :message only set on failure
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                          pos = r[:message].index("\n\nDiff:")
         | 
| 60 | 
            +
                          next unless pos # Only textual tests get Diffs
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                          r[:message] = r[:message].slice(0, pos)
         | 
| 63 | 
            +
                        end
         | 
| 64 | 
            +
                      end
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  # Optionally sort controls within each profile in report
         | 
| 69 | 
            +
                  def sort_controls
         | 
| 70 | 
            +
                    sort_type = @config[:runtime_config][:sort_results_by]
         | 
| 71 | 
            +
                    return unless sort_type
         | 
| 72 | 
            +
                    return if sort_type == "none"
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    @run_data[:profiles]&.each do |p|
         | 
| 75 | 
            +
                      p[:controls] ||= []
         | 
| 76 | 
            +
                      p[:groups] ||= []
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                      case sort_type
         | 
| 79 | 
            +
                      when "control"
         | 
| 80 | 
            +
                        p[:controls].sort_by! { |c| c[:id] }
         | 
| 81 | 
            +
                      when "random"
         | 
| 82 | 
            +
                        p[:controls].shuffle!
         | 
| 83 | 
            +
                      when "file"
         | 
| 84 | 
            +
                        # Sort the controls by file, but preserve order within the file.
         | 
| 85 | 
            +
                        # Files are called "groups" in the run_data, and the filename is in the id.
         | 
| 86 | 
            +
                        sorted_control_ids = p[:groups].sort_by { |g| g[:id] }.map { |g| g[:controls] }.flatten
         | 
| 87 | 
            +
                        controls_by_id = {}
         | 
| 88 | 
            +
                        p[:controls].each { |c| controls_by_id[c[:id]] = c }
         | 
| 89 | 
            +
                        p[:controls] = sorted_control_ids.map { |cid| controls_by_id[cid] }
         | 
| 90 | 
            +
                      end
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  private
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  def process_message_truncation(result)
         | 
| 97 | 
            +
                    if result.key?(:message) && result[:message] != "" && @trunc > -1 && result[:message].length > @trunc
         | 
| 98 | 
            +
                      result[:message] = result[:message][0...@trunc] + "[Truncated to #{@trunc} characters]"
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
                    result
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
            end
         |