diff --git a/lib/plugins/inspec-compliance/lib/inspec-compliance/api.rb b/lib/plugins/inspec-compliance/lib/inspec-compliance/api.rb index b2833305a..bc2b7bf2b 100644 --- a/lib/plugins/inspec-compliance/lib/inspec-compliance/api.rb +++ b/lib/plugins/inspec-compliance/lib/inspec-compliance/api.rb @@ -24,16 +24,8 @@ module InspecPlugins # the username of the account is used that is logged in def self.profiles(config, profile_filter = nil) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength owner = config["owner"] || config["user"] - - # Chef Compliance - if is_compliance_server?(config) - url = "#{config["server"]}/user/compliance" - # Chef Automate2 - elsif is_automate2_server?(config) + if is_automate2_server?(config) url = "#{config["server"]}/compliance/profiles/search" - # Chef Automate - elsif is_automate_server?(config) - url = "#{config["server"]}/profiles/#{owner}" else raise ServerConfigurationMissing end @@ -45,12 +37,9 @@ module InspecPlugins id, ver = nil end - if is_automate2_server?(config) - body = { owner: owner, name: id }.to_json - response = InspecPlugins::Compliance::HTTP.post_with_headers(url, headers, body, config["insecure"]) - else - response = InspecPlugins::Compliance::HTTP.get(url, headers, config["insecure"]) - end + body = { owner: owner, name: id }.to_json + response = InspecPlugins::Compliance::HTTP.post_with_headers(url, headers, body, config["insecure"]) + data = response.body response_code = response.code case response_code @@ -58,25 +47,12 @@ module InspecPlugins msg = "success" profiles = JSON.parse(data) # iterate over profiles - if is_compliance_server?(config) - mapped_profiles = [] - profiles.values.each do |org| - mapped_profiles += org.values - end - # Chef Automate pre 0.8.0 - elsif is_automate_server_pre_080?(config) - mapped_profiles = profiles.values.flatten - elsif is_automate2_server?(config) - mapped_profiles = [] - profiles["profiles"].each do |p| - mapped_profiles << p - end - else - mapped_profiles = profiles.map do |e| - e["owner_id"] = owner - e - end + + mapped_profiles = [] + profiles["profiles"].each do |p| + mapped_profiles << p end + # filter by name and version if they were specified in profile_filter mapped_profiles.select! do |p| (!ver || p["version"] == ver) && (!id || p["name"] == id) @@ -120,26 +96,9 @@ module InspecPlugins end def self.upload(config, owner, profile_name, archive_path) - # Chef Compliance - if is_compliance_server?(config) - url = "#{config["server"]}/owners/#{owner}/compliance/#{profile_name}/tar" - # Chef Automate pre 0.8.0 - elsif is_automate_server_pre_080?(config) - url = "#{config["server"]}/#{owner}" - elsif is_automate2_server?(config) - url = "#{config["server"]}/compliance/profiles?owner=#{owner}" - # Chef Automate - else - url = "#{config["server"]}/profiles/#{owner}" - end - + url = "#{config["server"]}/compliance/profiles?owner=#{owner}" headers = get_headers(config) - if is_automate2_server?(config) - res = InspecPlugins::Compliance::HTTP.post_multipart_file(url, headers, archive_path, config["insecure"]) - else - res = InspecPlugins::Compliance::HTTP.post_file(url, headers, archive_path, config["insecure"]) - end - + res = InspecPlugins::Compliance::HTTP.post_multipart_file(url, headers, archive_path, config["insecure"]) [res.is_a?(Net::HTTPSuccess), res.body] end @@ -210,16 +169,12 @@ module InspecPlugins def self.get_headers(config) token = get_token(config) - if is_automate_server?(config) || is_automate2_server?(config) - headers = { "chef-delivery-enterprise" => config["automate"]["ent"] } - if config["automate"]["token_type"] == "dctoken" - headers["x-data-collector-token"] = token - else - headers["chef-delivery-user"] = config["user"] - headers["chef-delivery-token"] = token - end + headers = { "chef-delivery-enterprise" => config["automate"]["ent"] } + if config["automate"]["token_type"] == "dctoken" + headers["x-data-collector-token"] = token else - headers = { "Authorization" => "Bearer #{token}" } + headers["chef-delivery-user"] = config["user"] + headers["chef-delivery-token"] = token end headers end @@ -232,16 +187,7 @@ module InspecPlugins end def self.target_url(config, profile) - owner, id, ver = profile_split(profile) - - return "#{config["server"]}/compliance/profiles/tar" if is_automate2_server?(config) - return "#{config["server"]}/owners/#{owner}/compliance/#{id}/tar" unless is_automate_server?(config) - - if ver.nil? - "#{config["server"]}/profiles/#{owner}/#{id}/tar" - else - "#{config["server"]}/profiles/#{owner}/#{id}/version/#{ver}/tar" - end + "#{config["server"]}/compliance/profiles/tar" end def self.profile_split(profile) @@ -260,33 +206,6 @@ module InspecPlugins uri.to_s.sub(%r{^compliance:\/\/}, "") end - def self.is_compliance_server?(config) - config["server_type"] == "compliance" - end - - def self.is_automate_server_pre_080?(config) - # Automate versions before 0.8.x do not have a valid version in the config - return false unless config["server_type"] == "automate" - - server_version_from_config(config).nil? - end - - def self.is_automate_server_080_and_later?(config) - # Automate versions 0.8.x and later will have a "version" key in the config - # that is properly parsed out via server_version_from_config below - return false unless config["server_type"] == "automate" - - !server_version_from_config(config).nil? - end - - def self.is_automate2_server?(config) - config["server_type"] == "automate2" - end - - def self.is_automate_server?(config) - config["server_type"] == "automate" - end - def self.server_version_from_config(config) # Automate versions 0.8.x and later will have a "version" key in the config # that looks like: "version":{"api":"compliance","version":"0.8.24"} @@ -296,87 +215,8 @@ module InspecPlugins config["version"]["version"] end - def self.determine_server_type(url, insecure) - if target_is_automate2_server?(url, insecure) - :automate2 - elsif target_is_automate_server?(url, insecure) - :automate - elsif target_is_compliance_server?(url, insecure) - :compliance - else - Inspec::Log.debug("Could not determine server type using known endpoints") - nil - end - end - - def self.target_is_automate2_server?(url, insecure) - automate_endpoint = "/dex/auth" - response = InspecPlugins::Compliance::HTTP.get(url + automate_endpoint, nil, insecure) - if response.code == "400" - Inspec::Log.debug( - "Received 400 from #{url}#{automate_endpoint} - " \ - "assuming target is a #{AUTOMATE_PRODUCT_NAME}2 instance" - ) - true - else - Inspec::Log.debug( - "Received #{response.code} from #{url}#{automate_endpoint} - " \ - "assuming target is not an #{AUTOMATE_PRODUCT_NAME}2 instance" - ) - false - end - end - - def self.target_is_automate_server?(url, insecure) - automate_endpoint = "/compliance/version" - response = InspecPlugins::Compliance::HTTP.get(url + automate_endpoint, nil, insecure) - case response.code - when "401" - Inspec::Log.debug( - "Received 401 from #{url}#{automate_endpoint} - " \ - "assuming target is a #{AUTOMATE_PRODUCT_NAME} instance" - ) - true - when "200" - # Chef Automate currently returns 401 for `/compliance/version` but some - # versions of OpsWorks Chef Automate return 200 and a Chef Manage page - # when unauthenticated requests are received. - if response.body.include?("Are You Looking For the #{SERVER_PRODUCT_NAME}?") - Inspec::Log.debug( - "Received 200 from #{url}#{automate_endpoint} - " \ - "assuming target is an #{AUTOMATE_PRODUCT_NAME} instance" - ) - true - else - Inspec::Log.debug( - "Received 200 from #{url}#{automate_endpoint} " \ - "but did not receive the Chef Manage page - " \ - "assuming target is not a #{AUTOMATE_PRODUCT_NAME} instance" - ) - false - end - else - Inspec::Log.debug( - "Received unexpected status code #{response.code} " \ - "from #{url}#{automate_endpoint} - " \ - "assuming target is not a #{AUTOMATE_PRODUCT_NAME} instance" - ) - false - end - end - - def self.target_is_compliance_server?(url, insecure) - # All versions of Chef Compliance return 200 for `/api/version` - compliance_endpoint = "/api/version" - - response = InspecPlugins::Compliance::HTTP.get(url + compliance_endpoint, nil, insecure) - return false unless response.code == "200" - - Inspec::Log.debug( - "Received 200 from #{url}#{compliance_endpoint} - " \ - "assuming target is a #{AUTOMATE_PRODUCT_NAME} server" - ) - true + def self.is_automate2_server?(config) + config["server_type"] == "automate2" end end end diff --git a/lib/plugins/inspec-compliance/lib/inspec-compliance/api/login.rb b/lib/plugins/inspec-compliance/lib/inspec-compliance/api/login.rb index 3b743c200..9bd29301c 100644 --- a/lib/plugins/inspec-compliance/lib/inspec-compliance/api/login.rb +++ b/lib/plugins/inspec-compliance/lib/inspec-compliance/api/login.rb @@ -11,20 +11,10 @@ module InspecPlugins def login(options) raise ArgumentError, "Please specify a server using `#{EXEC_NAME} automate login https://SERVER` or `#{EXEC_NAME} compliance login https://SERVER`" unless options["server"] + options["server_type"] = "automate2" options["server"] = URI("https://#{options["server"]}").to_s if URI(options["server"]).scheme.nil? - options["server_type"] = InspecPlugins::Compliance::API.determine_server_type(options["server"], options["insecure"]) - - case options["server_type"] - when :automate2 - Login::Automate2Server.login(options) - when :automate - Login::AutomateServer.login(options) - when :compliance - Login::ComplianceServer.login(options) - else - raise CannotDetermineServerType, "Unable to determine if #{options["server"]} is a #{AUTOMATE_PRODUCT_NAME} or #{COMPLIANCE_PRODUCT_NAME} server" - end + Login::Automate2Server.login(options) end module Automate2Server @@ -48,7 +38,7 @@ module InspecPlugins config["user"] = options["user"] config["owner"] = options["user"] config["insecure"] = options["insecure"] || false - config["server_type"] = options["server_type"].to_s + config["server_type"] = options["server_type"] config["token"] = token config["version"] = "0" @@ -69,133 +59,6 @@ module InspecPlugins end end - module AutomateServer - def self.login(options) - verify_thor_options(options) - - options["url"] = options["server"] + "/compliance" - token = options["dctoken"] || options["token"] - success, msg = API::Login.authenticate_login(options) - success ? store_access_token(options, token) : msg - end - - def self.store_access_token(options, token) - token_type = if options["token"] - "usertoken" - else - "dctoken" - end - - config = InspecPlugins::Compliance::Configuration.new - - config.clean - - config["automate"] = {} - config["automate"]["ent"] = options["ent"] - config["automate"]["token_type"] = token_type - config["server"] = options["url"] - config["user"] = options["user"] - config["insecure"] = options["insecure"] || false - config["server_type"] = options["server_type"].to_s - config["token"] = token - config["version"] = InspecPlugins::Compliance::API.version(config) - - config.store - API::Login.configuration_stored_message(config) - end - - # Automate login requires `--ent`, `--user`, and either `--token` or `--dctoken` - def self.verify_thor_options(o) - error_msg = [] - - error_msg.push("Please specify a user using `--user='USER'`") if o["user"].nil? - error_msg.push("Please specify an enterprise using `--ent='automate'`") if o["ent"].nil? - - if o["token"].nil? && o["dctoken"].nil? - error_msg.push("Please specify a token using `--token='AUTOMATE_TOKEN'` or `--dctoken='DATA_COLLECTOR_TOKEN'`") - end - - raise ArgumentError, error_msg.join("\n") unless error_msg.empty? - end - end - - module ComplianceServer - include Inspec::Dist - - def self.login(options) - compliance_verify_thor_options(options) - - options["url"] = options["server"] + "/api" - - if options["user"] && options["token"] - success, msg = API::Login.authenticate_login(options) - success ? compliance_store_access_token(options, options["token"]) : msg - elsif options["user"] && options["password"] - compliance_login_user_pass(options) - elsif options["refresh_token"] - compliance_login_refresh_token(options) - end - end - - def self.compliance_login_user_pass(options) - success, msg, token = InspecPlugins::Compliance::API.get_token_via_password( - options["url"], - options["user"], - options["password"], - options["insecure"] - ) - - raise msg unless success - - compliance_store_access_token(options, token) - end - - def self.compliance_login_refresh_token(options) - success, msg, token = InspecPlugins::Compliance::API.get_token_via_refresh_token( - options["url"], - options["refresh_token"], - options["insecure"] - ) - - raise msg unless success - - compliance_store_access_token(options, token) - end - - def self.compliance_store_access_token(options, token) - config = InspecPlugins::Compliance::Configuration.new - config.clean - - config["user"] = options["user"] if options["user"] - config["server"] = options["url"] - config["insecure"] = options["insecure"] || false - config["server_type"] = options["server_type"].to_s - config["token"] = token - config["version"] = InspecPlugins::Compliance::API.version(config) - - config.store - API::Login.configuration_stored_message(config) - end - - # Compliance login requires `--user` or `--refresh_token` - # If `--user` then either `--password`, `--token`, or `--refresh-token`, is required - def self.compliance_verify_thor_options(o) - error_msg = [] - - error_msg.push("Please specify a server using `#{EXEC_NAME} automate login https://SERVER` or `#{EXEC_NAME} compliance login https://SERVER`") if o["server"].nil? - - if o["user"].nil? && o["refresh_token"].nil? - error_msg.push("Please specify a `--user='USER'` or a `--refresh-token='TOKEN'`") - end - - if o["user"] && o["password"].nil? && o["token"].nil? && o["refresh_token"].nil? - error_msg.push("Please specify either a `--password`, `--token`, or `--refresh-token`") - end - - raise ArgumentError, error_msg.join("\n") unless error_msg.empty? - end - end - def self.authenticate_login(options) InspecPlugins::Compliance::API.authenticate_login_using_version_api( options["url"], diff --git a/lib/plugins/inspec-compliance/lib/inspec-compliance/target.rb b/lib/plugins/inspec-compliance/lib/inspec-compliance/target.rb index 0c2be3ba4..c349c39b1 100644 --- a/lib/plugins/inspec-compliance/lib/inspec-compliance/target.rb +++ b/lib/plugins/inspec-compliance/lib/inspec-compliance/target.rb @@ -32,16 +32,8 @@ module InspecPlugins def self.check_compliance_token(uri, config) if config["token"].nil? && config["refresh_token"].nil? - if config["server_type"] == "automate" - server = "automate" - msg = "#{EXEC_NAME} [automate|compliance] login https://your_automate_server --user USER --ent ENT --dctoken DCTOKEN or --token USERTOKEN" - elsif config["server_type"] == "automate2" - server = "automate2" - msg = "#{EXEC_NAME} [automate|compliance] login https://your_automate2_server --user USER --token APITOKEN" - else - server = "compliance" - msg = "#{EXEC_NAME} [automate|compliance] login https://your_compliance_server --user admin --insecure --token 'PASTE TOKEN HERE' " - end + server = "automate2" + msg = "#{EXEC_NAME} [automate|compliance] login https://your_automate2_server --user USER --token APITOKEN" raise Inspec::FetcherFailure, <<~EOF Cannot fetch #{uri} because your #{server} token has not been @@ -119,19 +111,9 @@ module InspecPlugins # determine the owner_id and the profile name from the url def compliance_profile_name - m = if InspecPlugins::Compliance::API.is_automate_server_pre_080?(@config) - %r{^#{@config['server']}/(?[^/]+)/(?[^/]+)/tar$} - elsif InspecPlugins::Compliance::API.is_automate_server_080_and_later?(@config) - %r{^#{@config['server']}/profiles/(?[^/]+)/(?[^/]+)/tar$} - else - %r{^#{@config['server']}/owners/(?[^/]+)/compliance/(?[^/]+)/tar$} - end.match(@target) - - if InspecPlugins::Compliance::API.is_automate2_server?(@config) - m = {} - m[:owner] = @config["profile"][0] - m[:id] = @config["profile"][1] - end + m = {} + m[:owner] = @config["profile"][0] + m[:id] = @config["profile"][1] if m.nil? raise "Unable to determine compliance profile name. This can be caused by " \ diff --git a/lib/plugins/inspec-compliance/test/unit/api/login_test.rb b/lib/plugins/inspec-compliance/test/unit/api/login_test.rb index 564bb1eb0..b076dd080 100644 --- a/lib/plugins/inspec-compliance/test/unit/api/login_test.rb +++ b/lib/plugins/inspec-compliance/test/unit/api/login_test.rb @@ -13,16 +13,6 @@ describe InspecPlugins::Compliance::API do } end - let(:compliance_options) do - { - "server" => "https://compliance.example.com", - "user" => "someone", - "password" => "password", - "token" => "token", - "refresh_token" => "refresh_token", - } - end - let(:fake_config) do class FakeConfig def initialize @@ -51,9 +41,6 @@ describe InspecPlugins::Compliance::API do describe ".login" do describe "when target is a Chef Automate2 server" do - before do - InspecPlugins::Compliance::API.expects(:determine_server_type).returns(:automate2) - end it "raises an error if `--user` is missing" do options = automate_options @@ -99,114 +86,6 @@ describe InspecPlugins::Compliance::API do end end - describe "when target is a Chef Automate server" do - before do - InspecPlugins::Compliance::API.expects(:determine_server_type).returns(:automate) - end - - it "raises an error if `--user` is missing" do - options = automate_options - options.delete("user") - err = _ { InspecPlugins::Compliance::API.login(options) }.must_raise(ArgumentError) - _(err.message).must_match(/Please specify a user.*/) - _(err.message.lines.length).must_equal(1) - end - - it "raises an error if `--ent` is missing" do - options = automate_options - options.delete("ent") - err = _ { InspecPlugins::Compliance::API.login(options) }.must_raise(ArgumentError) - _(err.message).must_match(/Please specify an enterprise.*/) - _(err.message.lines.length).must_equal(1) - end - - it "raises an error if `--token` and `--dctoken` are missing" do - options = automate_options - options.delete("token") - options.delete("dctoken") - err = _ { InspecPlugins::Compliance::API.login(options) }.must_raise(ArgumentError) - _(err.message).must_match(/Please specify a token.*/) - _(err.message.lines.length).must_equal(1) - end - - it "stores an access token" do - stub_request(:get, automate_options["server"] + "/compliance/version") - .to_return(status: 200, body: "", headers: {}) - options = automate_options - InspecPlugins::Compliance::Configuration.expects(:new).returns(fake_config) - - InspecPlugins::Compliance::API.login(options) - _(fake_config["automate"]["ent"]).must_equal("automate") - _(fake_config["automate"]["token_type"]).must_equal("usertoken") - _(fake_config["user"]).must_equal("someone") - _(fake_config["server"]).must_equal("https://automate.example.com/compliance") - _(fake_config["server_type"]).must_equal("automate") - _(fake_config["token"]).must_equal("token") - end - - it "puts error message when api-token is invalid" do - stub_body = { "error": "request not authenticated", "code": 16, "message": "request not authenticated", "details": [] }.to_json - stub_request(:get, automate_options["server"] + "/compliance/version") - .to_return(status: 401, body: stub_body, headers: {}) - options = automate_options - res = InspecPlugins::Compliance::API.login(options) - _(res).must_equal( - "Failed to authenticate to https://automate.example.com/compliance \n"\ - "Response code: 401\nBody: {\"error\":\"request not authenticated\",\"code\":16,\"message\":\"request not authenticated\",\"details\":[]}" - ) - end - end - - describe "when target is a Chef Compliance server" do - before do - InspecPlugins::Compliance::API.expects(:determine_server_type).returns(:compliance) - end - - it "raises an error if `--user` and `--refresh-token` are missing" do - options = automate_options - options.delete("user") - options.delete("refresh_token") - err = _ { InspecPlugins::Compliance::API.login(options) }.must_raise(ArgumentError) - _(err.message).must_match(/Please specify a.*--user.*--refresh-token.*/) - _(err.message.lines.length).must_equal(1) - end - - it "raises an error if `--user` is present but authentication method missing" do - options = automate_options - options.delete("password") - options.delete("token") - options.delete("refresh_token") - err = _ { InspecPlugins::Compliance::API.login(options) }.must_raise(ArgumentError) - _(err.message).must_match(/Please specify.*--password.*--token.*--refresh-token.*/) - _(err.message.lines.length).must_equal(1) - end - - it "stores an access token" do - stub_request(:get, compliance_options["server"] + "/api/version") - .to_return(status: 200, body: "", headers: {}) - options = compliance_options - InspecPlugins::Compliance::Configuration.expects(:new).returns(fake_config) - - InspecPlugins::Compliance::API.login(options) - _(fake_config["user"]).must_equal("someone") - _(fake_config["server"]).must_equal("https://compliance.example.com/api") - _(fake_config["server_type"]).must_equal("compliance") - _(fake_config["token"]).must_equal("token") - end - - it "puts error message when api-token is invalid" do - stub_body = { "error": "request not authenticated", "code": 16, "message": "request not authenticated", "details": [] }.to_json - stub_request(:get, automate_options["server"] + "/api/version") - .to_return(status: 401, body: stub_body, headers: {}) - options = automate_options - res = InspecPlugins::Compliance::API.login(options) - _(res).must_equal( - "Failed to authenticate to https://automate.example.com/api \n"\ - "Response code: 401\nBody: {\"error\":\"request not authenticated\",\"code\":16,\"message\":\"request not authenticated\",\"details\":[]}" - ) - end - end - describe "when target is neither a Chef Compliance nor Chef Automate server" do it "raises an error if `https://SERVER` is missing" do options = {} @@ -214,12 +93,6 @@ describe InspecPlugins::Compliance::API do _(err.message).must_match(/Please specify a server.*/) _(err.message.lines.length).must_equal(1) end - - it "rasies a `CannotDetermineServerType` error" do - InspecPlugins::Compliance::API.expects(:determine_server_type).returns(nil) - err = _ { InspecPlugins::Compliance::API.login(automate_options) }.must_raise(StandardError) - _(err.message).must_match(/Unable to determine/) - end end end end diff --git a/lib/plugins/inspec-compliance/test/unit/api_test.rb b/lib/plugins/inspec-compliance/test/unit/api_test.rb index f7ee31d34..0194d0656 100644 --- a/lib/plugins/inspec-compliance/test/unit/api_test.rb +++ b/lib/plugins/inspec-compliance/test/unit/api_test.rb @@ -5,41 +5,43 @@ require_relative "../../lib/inspec-compliance/api" describe InspecPlugins::Compliance::API do let(:profiles_response) do - [{ "name" => "apache-baseline", - "title" => "DevSec Apache Baseline", - "maintainer" => "DevSec Hardening Framework Team", - "copyright" => "DevSec Hardening Framework Team", - "copyright_email" => "hello@dev-sec.io", - "license" => "Apache 2 license", - "summary" => "Test-suite for best-practice apache hardening", - "version" => "2.0.2", - "supports" => [{ "os-family" => "unix" }], - "depends" => nil, - "owner_id" => "admin" }, - { "name" => "apache-baseline", - "title" => "DevSec Apache Baseline", - "maintainer" => "Hardening Framework Team", - "copyright" => "Hardening Framework Team", - "copyright_email" => "hello@dev-sec.io", - "license" => "Apache 2 license", - "summary" => "Test-suite for best-practice apache hardening", - "version" => "2.0.1", - "supports" => [{ "os-family" => "unix" }], - "depends" => nil, - "latest_version" => "2.0.2", - "owner_id" => "admin" }, - { "name" => "cis-aix-5.3-6.1-level1", - "title" => "CIS AIX 5.3 and AIX 6.1 Benchmark Level 1", - "maintainer" => "Chef Software, Inc.", - "copyright" => "Chef Software, Inc.", - "copyright_email" => "support@chef.io", - "license" => "Proprietary, All rights reserved", - "summary" => "CIS AIX 5.3 and AIX 6.1 Benchmark Level 1 translated from SCAP", - "version" => "1.1.0", - "supports" => nil, - "depends" => nil, - "latest_version" => "1.1.0-3", - "owner_id" => "admin" }] + { "profiles": + [{ "name" => "apache-baseline", + "title" => "DevSec Apache Baseline", + "maintainer" => "DevSec Hardening Framework Team", + "copyright" => "DevSec Hardening Framework Team", + "copyright_email" => "hello@dev-sec.io", + "license" => "Apache 2 license", + "summary" => "Test-suite for best-practice apache hardening", + "version" => "2.0.2", + "supports" => [{ "os-family" => "unix" }], + "depends" => nil, + "owner_id" => "admin" }, + { "name" => "apache-baseline", + "title" => "DevSec Apache Baseline", + "maintainer" => "Hardening Framework Team", + "copyright" => "Hardening Framework Team", + "copyright_email" => "hello@dev-sec.io", + "license" => "Apache 2 license", + "summary" => "Test-suite for best-practice apache hardening", + "version" => "2.0.1", + "supports" => [{ "os-family" => "unix" }], + "depends" => nil, + "latest_version" => "2.0.2", + "owner_id" => "admin" }, + { "name" => "cis-aix-5.3-6.1-level1", + "title" => "CIS AIX 5.3 and AIX 6.1 Benchmark Level 1", + "maintainer" => "Chef Software, Inc.", + "copyright" => "Chef Software, Inc.", + "copyright_email" => "support@chef.io", + "license" => "Proprietary, All rights reserved", + "summary" => "CIS AIX 5.3 and AIX 6.1 Benchmark Level 1 translated from SCAP", + "version" => "1.1.0", + "supports" => nil, + "depends" => nil, + "latest_version" => "1.1.0-3", + "owner_id" => "admin" }], + } end describe ".version" do @@ -115,87 +117,6 @@ describe InspecPlugins::Compliance::API do end end - describe "automate/compliance is? checks" do - describe "when the config has a compliance server_type" do - it "automate/compliance server is? methods return correctly" do - config = InspecPlugins::Compliance::Configuration.new - config.clean - config["server_type"] = "compliance" - _(InspecPlugins::Compliance::API.is_compliance_server?(config)).must_equal true - _(InspecPlugins::Compliance::API.is_automate_server?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server_pre_080?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server_080_and_later?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate2_server?(config)).must_equal false - end - end - - describe "when the config has a automate2 server_type" do - it "automate/compliance server is? methods return correctly" do - config = InspecPlugins::Compliance::Configuration.new - config.clean - config["server_type"] = "automate2" - _(InspecPlugins::Compliance::API.is_compliance_server?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server_pre_080?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server_080_and_later?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate2_server?(config)).must_equal true - end - end - - describe "when the config has an automate server_type and no version key" do - it "automate/compliance server is? methods return correctly" do - config = InspecPlugins::Compliance::Configuration.new - config.clean - config["server_type"] = "automate" - _(InspecPlugins::Compliance::API.is_compliance_server?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server?(config)).must_equal true - _(InspecPlugins::Compliance::API.is_automate_server_pre_080?(config)).must_equal true - _(InspecPlugins::Compliance::API.is_automate_server_080_and_later?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate2_server?(config)).must_equal false - end - end - - describe "when the config has an automate server_type and a version key that is not a hash" do - it "automate/compliance server is? methods return correctly" do - config = InspecPlugins::Compliance::Configuration.new - config.clean - config["server_type"] = "automate" - config["version"] = "1.2.3" - _(InspecPlugins::Compliance::API.is_compliance_server?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server?(config)).must_equal true - _(InspecPlugins::Compliance::API.is_automate_server_pre_080?(config)).must_equal true - _(InspecPlugins::Compliance::API.is_automate_server_080_and_later?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate2_server?(config)).must_equal false - end - end - - describe "when the config has an automate server_type and a version hash with no version" do - it "automate/compliance server is? methods return correctly" do - config = InspecPlugins::Compliance::Configuration.new - config.clean - config["server_type"] = "automate" - config["version"] = {} - _(InspecPlugins::Compliance::API.is_compliance_server?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server?(config)).must_equal true - _(InspecPlugins::Compliance::API.is_automate_server_pre_080?(config)).must_equal true - _(InspecPlugins::Compliance::API.is_automate_server_080_and_later?(config)).must_equal false - end - end - - describe "when the config has an automate server_type and a version hash with a version" do - it "automate/compliance server is? methods return correctly" do - config = InspecPlugins::Compliance::Configuration.new - config.clean - config["server_type"] = "automate" - config["version"] = { "version" => "0.8.1" } - _(InspecPlugins::Compliance::API.is_compliance_server?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server?(config)).must_equal true - _(InspecPlugins::Compliance::API.is_automate_server_pre_080?(config)).must_equal false - _(InspecPlugins::Compliance::API.is_automate_server_080_and_later?(config)).must_equal true - end - end - end - describe ".server_version_from_config" do it "returns nil when the config has no version key" do config = {} @@ -229,29 +150,19 @@ describe InspecPlugins::Compliance::API do end describe "target_url" do - it "handles a automate profile with and without version" do + it "handles a automate2 profile with and without version" do config = InspecPlugins::Compliance::Configuration.new config.clean - config["server_type"] = "automate" - config["server"] = "https://myautomate" + config["server_type"] = "automate2" + config["server"] = "https://myautomate2" config["version"] = "1.6.99" - _(InspecPlugins::Compliance::API.target_url(config, "admin/apache-baseline")).must_equal "https://myautomate/profiles/admin/apache-baseline/tar" - _(InspecPlugins::Compliance::API.target_url(config, "admin/apache-baseline#2.0.2")).must_equal "https://myautomate/profiles/admin/apache-baseline/version/2.0.2/tar" - end - - it "handles a chef-compliance profile with and without version" do - config = InspecPlugins::Compliance::Configuration.new - config.clean - config["server_type"] = "compliance" - config["server"] = "https://mychefcompliance" - config["version"] = "1.1.2" - _(InspecPlugins::Compliance::API.target_url(config, "admin/apache-baseline")).must_equal "https://mychefcompliance/owners/admin/compliance/apache-baseline/tar" - _(InspecPlugins::Compliance::API.target_url(config, "admin/apache-baseline#2.0.2")).must_equal "https://mychefcompliance/owners/admin/compliance/apache-baseline/tar" + _(InspecPlugins::Compliance::API.target_url(config, "admin/apache-baseline")).must_equal "https://myautomate2/compliance/profiles/tar" + _(InspecPlugins::Compliance::API.target_url(config, "admin/apache-baseline#2.0.2")).must_equal "https://myautomate2/compliance/profiles/tar" end end describe "exist?" do - it "works with profiles returned by Automate" do + it "works with profiles returned by Automate 2" do # ruby 2.3.3 has issues running stub_requests properly # skipping for that specific version return if RUBY_VERSION == "2.3.3" @@ -259,14 +170,36 @@ describe InspecPlugins::Compliance::API do config = InspecPlugins::Compliance::Configuration.new config.clean config["owner"] = "admin" - config["server_type"] = "automate" - config["server"] = "https://myautomate" + config["server_type"] = "automate2" + config["server"] = "https://myautomate2" config["version"] = "1.6.99" config["automate"] = { "ent" => "automate", "token_type" => "dctoken" } config["version"] = { "api" => "compliance", "version" => "0.8.24" } - stub_request(:get, "https://myautomate/profiles/admin") - .with(headers: { "Accept" => "*/*", "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", "Chef-Delivery-Enterprise" => "automate", "User-Agent" => "Ruby", "X-Data-Collector-Token" => "" }) + stub_request(:post, "https://myautomate2/compliance/profiles/search") + .with( + body: "{\"owner\":\"admin\",\"name\":\"apache-baseline\"}", + headers: { + "Accept" => "*/*", + "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", + "Chef-Delivery-Enterprise" => "automate", + "User-Agent" => "Ruby", + "X-Data-Collector-Token" => "", + } + ) + .to_return(status: 200, body: profiles_response.to_json, headers: {}) + + stub_request(:post, "https://myautomate2/compliance/profiles/search") + .with( + body: "{\"owner\":\"admin\",\"name\":\"missing-in-action\"}", + headers: { + "Accept" => "*/*", + "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3", + "Chef-Delivery-Enterprise" => "automate", + "User-Agent" => "Ruby", + "X-Data-Collector-Token" => "", + } + ) .to_return(status: 200, body: profiles_response.to_json, headers: {}) _(InspecPlugins::Compliance::API.exist?(config, "admin/apache-baseline")).must_equal true @@ -276,111 +209,12 @@ describe InspecPlugins::Compliance::API do end end - describe ".determine_server_type" do - let(:url) { "https://someserver.onthe.net/" } - - let(:compliance_endpoint) { "/api/version" } - let(:automate_endpoint) { "/compliance/version" } - let(:automate2_endpoint) { "/dex/auth" } - let(:headers) { nil } - let(:insecure) { true } - - let(:good_response) { mock } - let(:bad_response) { mock } - - it "returns `:automate2` when a 400 is received from `https://URL/dex/auth`" do - good_response.stubs(:code).returns("400") - - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate2_endpoint, headers, insecure) - .returns(good_response) - - _(InspecPlugins::Compliance::API.determine_server_type(url, insecure)).must_equal(:automate2) - end - - it "returns `:automate` when a 401 is received from `https://URL/compliance/version`" do - good_response.stubs(:code).returns("401") - bad_response.stubs(:code).returns("404") - - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate2_endpoint, headers, insecure) - .returns(bad_response) - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate_endpoint, headers, insecure) - .returns(good_response) - - _(InspecPlugins::Compliance::API.determine_server_type(url, insecure)).must_equal(:automate) - end - - # Chef Automate currently returns 401 for `/compliance/version` but some - # versions of OpsWorks Chef Automate return 200 and a Chef Manage page when - # unauthenticated requests are received. - it "returns `:automate` when a 200 is received from `https://URL/compliance/version`" do - bad_response.stubs(:code).returns("404") - good_response.stubs(:code).returns("200") - good_response.stubs(:body).returns("Are You Looking For the Chef Server?") - - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate2_endpoint, headers, insecure) - .returns(bad_response) - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate_endpoint, headers, insecure) - .returns(good_response) - - _(InspecPlugins::Compliance::API.determine_server_type(url, insecure)).must_equal(:automate) - end - - it "returns `nil` if a 200 is received from `https://URL/compliance/version` but not redirected to Chef Manage" do - bad_response.stubs(:code).returns("200") - bad_response.stubs(:body).returns("No Chef Manage here") - - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate_endpoint, headers, insecure) - .returns(bad_response) - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate2_endpoint, headers, insecure) - .returns(bad_response) - - mock_compliance_response = mock - mock_compliance_response.stubs(:code).returns("404") - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + compliance_endpoint, headers, insecure) - .returns(mock_compliance_response) - - _(InspecPlugins::Compliance::API.determine_server_type(url, insecure)).must_be_nil - end - - it "returns `:compliance` when a 200 is received from `https://URL/api/version`" do - good_response.stubs(:code).returns("200") - bad_response.stubs(:code).returns("404") - - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate_endpoint, headers, insecure) - .returns(bad_response) - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate2_endpoint, headers, insecure) - .returns(bad_response) - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + compliance_endpoint, headers, insecure) - .returns(good_response) - - _(InspecPlugins::Compliance::API.determine_server_type(url, insecure)).must_equal(:compliance) - end - - it "returns `nil` if it cannot determine the server type" do - bad_response.stubs(:code).returns("404") - - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate2_endpoint, headers, insecure) - .returns(bad_response) - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + automate_endpoint, headers, insecure) - .returns(bad_response) - InspecPlugins::Compliance::HTTP.expects(:get) - .with(url + compliance_endpoint, headers, insecure) - .returns(bad_response) - - _(InspecPlugins::Compliance::API.determine_server_type(url, insecure)).must_be_nil + describe "when the config has a automate2 server_type" do + it "automate server 2 is? methods return correctly" do + config = InspecPlugins::Compliance::Configuration.new + config.clean + config["server_type"] = "automate2" + _(InspecPlugins::Compliance::API.is_automate2_server?(config)).must_equal true end end end diff --git a/lib/plugins/inspec-compliance/test/unit/target_test.rb b/lib/plugins/inspec-compliance/test/unit/target_test.rb index c8bc7d850..801a8a079 100644 --- a/lib/plugins/inspec-compliance/test/unit/target_test.rb +++ b/lib/plugins/inspec-compliance/test/unit/target_test.rb @@ -15,12 +15,11 @@ describe InspecPlugins::Compliance::Fetcher do it "returns an error when token is not set" do ex = assert_raises(Inspec::FetcherFailure) { fetcher.class.check_compliance_token("http://test.com", config) } - _(ex.message).must_include "Cannot fetch http://test.com because your compliance token has not been\nconfigured." + _(ex.message).must_include "Cannot fetch http://test.com because your automate2 token has not been\nconfigured." end end describe "when the server is an automate2 server" do - before { InspecPlugins::Compliance::API.expects(:is_automate2_server?).with(config).returns(true) } it "returns the correct owner and profile name" do config["profile"] = ["admin", "ssh-baseline", nil] @@ -29,54 +28,6 @@ describe InspecPlugins::Compliance::Fetcher do end end - describe "when the server is an automate server pre-0.8.0" do - before { InspecPlugins::Compliance::API.expects(:is_automate_server_pre_080?).with(config).returns(true) } - - it "returns the correct profile name when the url is correct" do - fetcher = InspecPlugins::Compliance::Fetcher.new("myserver/myowner/myprofile/tar", config) - _(fetcher.send(:compliance_profile_name)).must_equal "myowner/myprofile" - end - - it "raises an exception if the url is malformed" do - fetcher = InspecPlugins::Compliance::Fetcher.new("a/bad/url", config) - _(proc { fetcher.send(:compliance_profile_name) }).must_raise RuntimeError - end - end - - describe "when the server is an automate server 0.8.0-or-later" do - before do - InspecPlugins::Compliance::API.expects(:is_automate_server_pre_080?).with(config).returns(false) - InspecPlugins::Compliance::API.expects(:is_automate_server_080_and_later?).with(config).returns(true) - end - - it "returns the correct profile name when the url is correct" do - fetcher = InspecPlugins::Compliance::Fetcher.new("myserver/profiles/myowner/myprofile/tar", config) - _(fetcher.send(:compliance_profile_name)).must_equal "myowner/myprofile" - end - - it "raises an exception if the url is malformed" do - fetcher = InspecPlugins::Compliance::Fetcher.new("a/bad/url", config) - _(proc { fetcher.send(:compliance_profile_name) }).must_raise RuntimeError - end - end - - describe "when the server is not an automate server (likely a compliance server)" do - before do - InspecPlugins::Compliance::API.expects(:is_automate_server_pre_080?).with(config).returns(false) - InspecPlugins::Compliance::API.expects(:is_automate_server_080_and_later?).with(config).returns(false) - end - - it "returns the correct profile name when the url is correct" do - fetcher = InspecPlugins::Compliance::Fetcher.new("myserver/owners/myowner/compliance/myprofile/tar", config) - _(fetcher.send(:compliance_profile_name)).must_equal "myowner/myprofile" - end - - it "raises an exception if the url is malformed" do - fetcher = InspecPlugins::Compliance::Fetcher.new("a/bad/url", config) - _(proc { fetcher.send(:compliance_profile_name) }).must_raise RuntimeError - end - end - describe "when the server calls an automate profile" do let(:profiles_result) do [{ "name" => "ssh-baseline",