diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 30cd4c85f..92c4d5334 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by -# `rubocop --auto-gen-config` -# on 2020-04-13 17:31:41 +0300 using RuboCop version 0.74.0. +# `rubocop --auto-gen-config --exclude-limit 1000` +# on 2020-04-15 10:09:42 +0300 using RuboCop version 0.74.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -9,7 +9,87 @@ # Offense count: 80 # Configuration parameters: CustomTransform, IgnoreMethods. RSpec/FilePath: - Enabled: false + Exclude: + - 'spec/custom_facts/core/aggregate_spec.rb' + - 'spec/custom_facts/core/directed_graph_spec.rb' + - 'spec/custom_facts/core/execution/fact_manager_spec.rb' + - 'spec/custom_facts/core/execution/posix_spec.rb' + - 'spec/custom_facts/core/execution/windows_spec.rb' + - 'spec/custom_facts/core/execution_spec.rb' + - 'spec/custom_facts/core/logging_spec.rb' + - 'spec/custom_facts/core/resolvable_spec.rb' + - 'spec/custom_facts/core/suitable_spec.rb' + - 'spec/custom_facts/util/collection_spec.rb' + - 'spec/custom_facts/util/config_spec.rb' + - 'spec/custom_facts/util/confine_spec.rb' + - 'spec/custom_facts/util/directory_loader_spec.rb' + - 'spec/custom_facts/util/fact_spec.rb' + - 'spec/custom_facts/util/loader_spec.rb' + - 'spec/custom_facts/util/normalization_spec.rb' + - 'spec/custom_facts/util/parser_spec.rb' + - 'spec/custom_facts/util/resolution_spec.rb' + - 'spec/facter/facts_utils/bytes_to_human_readable_spec.rb' + - 'spec/facter/facts_utils/uptime_parser_spec.rb' + - 'spec/facter/facts_utils/windows_release_finder_spec.rb' + - 'spec/facter/model/fact_collection_spec.rb' + - 'spec/facter/model/resolved_fact_spec.rb' + - 'spec/facter/resolvers/aio_agent_version_spec.rb' + - 'spec/facter/resolvers/aix/architecture_resolver_spec.rb' + - 'spec/facter/resolvers/aix/ffi_helper_spec.rb' + - 'spec/facter/resolvers/aix/hardware_resolver_spec.rb' + - 'spec/facter/resolvers/disk_resolver_spec.rb' + - 'spec/facter/resolvers/dmi_resolver_spec.rb' + - 'spec/facter/resolvers/filesystems_resolver_spec.rb' + - 'spec/facter/resolvers/fips_enabled_resolver_spec.rb' + - 'spec/facter/resolvers/identity_resolver_spec.rb' + - 'spec/facter/resolvers/load_averages_resolver_spec.rb' + - 'spec/facter/resolvers/macosx/dmi_resolver_spec.rb' + - 'spec/facter/resolvers/memory_resolver_spec.rb' + - 'spec/facter/resolvers/mountpoints_resolver_spec.rb' + - 'spec/facter/resolvers/processors_resolver_spec.rb' + - 'spec/facter/resolvers/redhat_release_resolver_spec.rb' + - 'spec/facter/resolvers/selinux_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/current_zone_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/solaris_release_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/zone_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/zpool_resolver_spec.rb' + - 'spec/facter/resolvers/suse_relese_resolver_spec.rb' + - 'spec/facter/resolvers/system_profile_resolver_spec.rb' + - 'spec/facter/resolvers/utils/aix/odm_query_spec.rb' + - 'spec/facter/resolvers/utils/macosx/filesystem_helper_spec.rb' + - 'spec/facter/resolvers/utils/windows/win32ole_spec.rb' + - 'spec/facter/resolvers/windows/dmi_bios_resolver_spec.rb' + - 'spec/facter/resolvers/windows/dmi_computersystem_resolver_spec.rb' + - 'spec/facter/resolvers/windows/hardware_architecture_resolver_spec.rb' + - 'spec/facter/resolvers/windows/identity_resolver_spec.rb' + - 'spec/facter/resolvers/windows/kernel_resolver_spec.rb' + - 'spec/facter/resolvers/windows/memory_resolver_spec.rb' + - 'spec/facter/resolvers/windows/netkvm_resolver_spec.rb' + - 'spec/facter/resolvers/windows/networking_resolver_spec.rb' + - 'spec/facter/resolvers/windows/processors_resolver_spec.rb' + - 'spec/facter/resolvers/windows/product_release_resolver_spec.rb' + - 'spec/facter/resolvers/windows/system32_resolver_spec.rb' + - 'spec/facter/resolvers/windows/virtualization_resolver_spec.rb' + - 'spec/facter/resolvers/windows/win_os_description_resolver_spec.rb' + - 'spec/framework/config/block_list_spec.rb' + - 'spec/framework/config/config_reader_spec.rb' + - 'spec/framework/core/fact/external/external_fact_manager_spec.rb' + - 'spec/framework/core/fact/internal/internal_fact_manager_spec.rb' + - 'spec/framework/core/fact_loaders/class_discoverer_spec.rb' + - 'spec/framework/core/fact_loaders/external_fact_loader_spec.rb' + - 'spec/framework/core/fact_loaders/fact_loader_spec.rb' + - 'spec/framework/core/fact_loaders/internal_fact_loader_spec.rb' + - 'spec/framework/core/fact_manager_spec.rb' + - 'spec/framework/core/options/option_store_spec.rb' + - 'spec/framework/core/options/options_validator_spec.rb' + - 'spec/framework/core/options_spec.rb' + - 'spec/framework/core/session_cache_spec.rb' + - 'spec/framework/formatters/fact_formatter_spec.rb' + - 'spec/framework/formatters/hocon_fact_formatter_spec.rb' + - 'spec/framework/formatters/json_fact_formatter_spec.rb' + - 'spec/framework/formatters/legacy_fact_formatter_spec.rb' + - 'spec/framework/formatters/yaml_fact_formatter_spec.rb' + - 'spec/framework/utils/utils_spec.rb' # Offense count: 15 # Configuration parameters: AssignmentOnly. @@ -33,7 +113,71 @@ RSpec/LeakyConstantDeclaration: # Configuration parameters: EnforcedStyle. # SupportedStyles: have_received, receive RSpec/MessageSpies: - Enabled: false + Exclude: + - 'spec/custom_facts/core/aggregate_spec.rb' + - 'spec/custom_facts/core/execution/fact_manager_spec.rb' + - 'spec/custom_facts/core/execution/windows_spec.rb' + - 'spec/custom_facts/core/execution_spec.rb' + - 'spec/custom_facts/core/logging_spec.rb' + - 'spec/custom_facts/core/resolvable_spec.rb' + - 'spec/custom_facts/core/suitable_spec.rb' + - 'spec/custom_facts/util/collection_spec.rb' + - 'spec/custom_facts/util/confine_spec.rb' + - 'spec/custom_facts/util/directory_loader_spec.rb' + - 'spec/custom_facts/util/fact_spec.rb' + - 'spec/custom_facts/util/loader_spec.rb' + - 'spec/custom_facts/util/parser_spec.rb' + - 'spec/custom_facts/util/resolution_spec.rb' + - 'spec/facter/facter_spec.rb' + - 'spec/facter/facts/aix/os/name_spec.rb' + - 'spec/facter/facts/aix/os/release_spec.rb' + - 'spec/facter/facts/macosx/is_virtual_spec.rb' + - 'spec/facter/facts/macosx/mountpoints_spec.rb' + - 'spec/facter/facts/macosx/os/architecture_spec.rb' + - 'spec/facter/facts/macosx/os/family_spec.rb' + - 'spec/facter/facts/macosx/os/name_spec.rb' + - 'spec/facter/facts/sles/os/architecture_spec.rb' + - 'spec/facter/facts/sles/os/name_spec.rb' + - 'spec/facter/facts/sles/os/release_spec.rb' + - 'spec/facter/facts/solaris/os/architecture_spec.rb' + - 'spec/facter/facts/solaris/os/name_spec.rb' + - 'spec/facter/facts/solaris/ruby/platform_spec.rb' + - 'spec/facter/facts/solaris/ruby/sitedir_spec.rb' + - 'spec/facter/facts/windows/dmi/manufacturer_spec.rb' + - 'spec/facter/facts/windows/dmi/product/name_spec.rb' + - 'spec/facter/facts/windows/dmi/product/serial_number_spec.rb' + - 'spec/facter/facts/windows/dmi/product/uuid_spec.rb' + - 'spec/facter/facts/windows/fips_enabled_spec.rb' + - 'spec/facter/facts/windows/identity/user_spec.rb' + - 'spec/facter/facts/windows/ipaddress6_interfaces_spec.rb' + - 'spec/facter/facts/windows/ipaddress_interfaces_spec.rb' + - 'spec/facter/facts/windows/macaddress_interfaces_spec.rb' + - 'spec/facter/facts/windows/memory/system/available_bytes_spec.rb' + - 'spec/facter/facts/windows/memory/system/available_spec.rb' + - 'spec/facter/facts/windows/memory/system/total_bytes_spec.rb' + - 'spec/facter/facts/windows/memory/system/total_spec.rb' + - 'spec/facter/facts/windows/mtu_interfaces_spec.rb' + - 'spec/facter/facts/windows/netmask6_interfaces_spec.rb' + - 'spec/facter/facts/windows/netmask_interfaces_spec.rb' + - 'spec/facter/facts/windows/network6_interfaces_spec.rb' + - 'spec/facter/facts/windows/network_interfaces_spec.rb' + - 'spec/facter/facts/windows/os/architecture_spec.rb' + - 'spec/facter/facts/windows/os/family_spec.rb' + - 'spec/facter/facts/windows/os/hardware_spec.rb' + - 'spec/facter/facts/windows/os/name_spec.rb' + - 'spec/facter/facts/windows/os/windows/edition_id_spec.rb' + - 'spec/facter/facts/windows/os/windows/installation_type_spec.rb' + - 'spec/facter/facts/windows/os/windows/product_name_spec.rb' + - 'spec/facter/facts/windows/os/windows/release_id_spec.rb' + - 'spec/facter/facts/windows/os/windows/system32_spec.rb' + - 'spec/facter/facts/windows/processors/count_spec.rb' + - 'spec/facter/facts/windows/processors/isa_spec.rb' + - 'spec/facter/facts/windows/processors/physicalcount_spec.rb' + - 'spec/facter/facts/windows/ruby/platform_spec.rb' + - 'spec/facter/facts/windows/ruby/sitedir_spec.rb' + - 'spec/facter/facts/windows/scope6_interfaces_spec.rb' + - 'spec/facter/resolvers/utils/aix/odm_query_spec.rb' + - 'spec/framework/core/fact_loaders/external_fact_loader_spec.rb' # Offense count: 26 RSpec/SubjectStub: @@ -46,7 +190,70 @@ RSpec/SubjectStub: - 'spec/custom_facts/util/fact_spec.rb' - 'spec/custom_facts/util/resolution_spec.rb' -# Offense count: 185 +# Offense count: 179 # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames. RSpec/VerifiedDoubles: - Enabled: false + Exclude: + - 'spec/custom_facts/core/aggregate_spec.rb' + - 'spec/custom_facts/util/collection_spec.rb' + - 'spec/custom_facts/util/confine_spec.rb' + - 'spec/custom_facts/util/directory_loader_spec.rb' + - 'spec/custom_facts/util/fact_spec.rb' + - 'spec/custom_facts/util/resolution_spec.rb' + - 'spec/facter/facter_spec.rb' + - 'spec/facter/facts/aix/ssh_spec.rb' + - 'spec/facter/facts/macosx/memory/swap/capacity_spec.rb' + - 'spec/facter/facts/macosx/memory/swap/used_bytes_spec.rb' + - 'spec/facter/facts/macosx/memory/system/capacity_spec.rb' + - 'spec/facter/facts/macosx/memory/system/used_bytes_spec.rb' + - 'spec/facter/facts/windows/dmi/product/serial_number_spec.rb' + - 'spec/facter/facts/windows/hypervisors/hyperv_spec.rb' + - 'spec/facter/facts/windows/hypervisors/kvm_spec.rb' + - 'spec/facter/facts/windows/hypervisors/virtualbox_spec.rb' + - 'spec/facter/facts/windows/hypervisors/vmware_spec.rb' + - 'spec/facter/facts/windows/hypervisors/xen_spec.rb' + - 'spec/facter/facts/windows/identity/privileged_spec.rb' + - 'spec/facter/facts/windows/memory/system/capacity_spec.rb' + - 'spec/facter/facts/windows/memory/system/used_bytes_spec.rb' + - 'spec/facter/facts/windows/networking/dhcp_spec.rb' + - 'spec/facter/facts/windows/networking/interfaces_spec.rb' + - 'spec/facter/facts/windows/networking/mtu_spec.rb' + - 'spec/facter/facts/windows/networking/primary_spec.rb' + - 'spec/facter/facts/windows/processors/models_spec.rb' + - 'spec/facter/facts/windows/virtualization/is_virtual_spec.rb' + - 'spec/facter/facts/windows/virtualization/virtual_spec.rb' + - 'spec/facter/query_parser_spec.rb' + - 'spec/facter/resolvers/aix/architecture_resolver_spec.rb' + - 'spec/facter/resolvers/aix/ffi_helper_spec.rb' + - 'spec/facter/resolvers/aix/hardware_resolver_spec.rb' + - 'spec/facter/resolvers/macosx/mountpoints_resolver_spec.rb' + - 'spec/facter/resolvers/mountpoints_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/current_zone_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/solaris_release_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/zfs_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/zone_resolver_spec.rb' + - 'spec/facter/resolvers/solaris/zpool_resolver_spec.rb' + - 'spec/facter/resolvers/utils/windows/network_utils_spec.rb' + - 'spec/facter/resolvers/utils/windows/win32ole_spec.rb' + - 'spec/facter/resolvers/windows/dmi_bios_resolver_spec.rb' + - 'spec/facter/resolvers/windows/dmi_computersystem_resolver_spec.rb' + - 'spec/facter/resolvers/windows/hardware_architecture_resolver_spec.rb' + - 'spec/facter/resolvers/windows/identity_resolver_spec.rb' + - 'spec/facter/resolvers/windows/kernel_resolver_spec.rb' + - 'spec/facter/resolvers/windows/memory_resolver_spec.rb' + - 'spec/facter/resolvers/windows/networking_resolver_spec.rb' + - 'spec/facter/resolvers/windows/processors_resolver_spec.rb' + - 'spec/facter/resolvers/windows/system32_resolver_spec.rb' + - 'spec/facter/resolvers/windows/uptime_resolver_spec.rb' + - 'spec/facter/resolvers/windows/virtualization_resolver_spec.rb' + - 'spec/facter/resolvers/windows/win_os_description_resolver_spec.rb' + - 'spec/framework/config/block_list_spec.rb' + - 'spec/framework/core/fact_loaders/external_fact_loader_spec.rb' + - 'spec/framework/core/fact_loaders/fact_loader_spec.rb' + - 'spec/framework/core/fact_manager_spec.rb' + - 'spec/framework/core/session_cache_spec.rb' + - 'spec/framework/formatters/hocon_fact_formatter_spec.rb' + - 'spec/framework/formatters/json_fact_formatter_spec.rb' + - 'spec/framework/formatters/legacy_fact_formatter_spec.rb' + - 'spec/framework/formatters/yaml_fact_formatter_spec.rb' + - 'spec/mocks/util.rb' diff --git a/lib/facts/windows/ssh.rb b/lib/facts/windows/ssh.rb new file mode 100644 index 000000000..54f65a715 --- /dev/null +++ b/lib/facts/windows/ssh.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Facts + module Windows + class Ssh + FACT_NAME = 'ssh' + + def call_the_resolver + privileged = Facter::Resolvers::Identity.resolve(:privileged) + ssh_info = Facter::Resolvers::Windows::Ssh.resolve(:ssh) if privileged + ssh_facts = {} + ssh_info&.each { |ssh| ssh_facts.merge!(create_ssh_fact(ssh)) } + Facter::ResolvedFact.new(FACT_NAME, ssh_facts.empty? ? nil : ssh_facts) + end + + private + + def create_ssh_fact(ssh) + { ssh.name.to_sym => + { fingerprints: { sha1: ssh.fingerprint.sha1, + sha256: ssh.fingerprint.sha256 }, + key: ssh.key, + type: ssh.type } } + end + end + end +end diff --git a/lib/resolvers/ssh_resolver.rb b/lib/resolvers/ssh_resolver.rb index 1eb1e2090..82edf1bf6 100644 --- a/lib/resolvers/ssh_resolver.rb +++ b/lib/resolvers/ssh_resolver.rb @@ -1,8 +1,5 @@ # frozen_string_literal: true -require 'base64' -require 'digest/sha1' - module Facter module Resolvers class SshResolver < BaseResolver @@ -28,49 +25,12 @@ def retrieve_info(fact_name) next unless file_content key_type, key = file_content.split(' ') - key_name = determine_ssh_key_name(key_type) - ssh_list << create_ssh(key_name, key_type, key) + ssh_list << ::Resolvers::Utils::SshHelper.create_ssh(key_type, key) end end @fact_list[:ssh] = ssh_list @fact_list[fact_name] end - - def create_ssh(key_name, key_type, key) - decoded_key = Base64.decode64(key) - ssh_fa = determine_ssh_fingerprint(key_name) - sha1 = "SSHFP #{ssh_fa} 1 #{Digest::SHA1.new.update(decoded_key)}" - sha256 = "SSHFP #{ssh_fa} 2 #{Digest::SHA2.new.update(decoded_key)}" - - fingerprint = FingerPrint.new(sha1, sha256) - Ssh.new(fingerprint, key_type, key, key_name) - end - - def determine_ssh_key_name(key) - case key - when 'ssh-dss' - 'dsa' - when 'ecdsa-sha2-nistp256' - 'ecdsa' - when 'ssh-ed25519' - 'ed25519' - when 'ssh-rsa' - 'rsa' - end - end - - def determine_ssh_fingerprint(key_name) - case key_name - when 'rsa' - 1 - when 'dsa' - 2 - when 'ecdsa' - 3 - when 'ed25519' - 4 - end - end end end end diff --git a/lib/resolvers/utils/ssh_helper.rb b/lib/resolvers/utils/ssh_helper.rb new file mode 100644 index 000000000..9b327b670 --- /dev/null +++ b/lib/resolvers/utils/ssh_helper.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'base64' +require 'digest/sha1' + +module Resolvers + module Utils + class SshHelper + class << self + SSH_NAME = { 'ssh-dss' => 'dsa', 'ecdsa-sha2-nistp256' => 'ecdsa', + 'ssh-ed25519' => 'ed25519', 'ssh-rsa' => 'rsa' }.freeze + SSH_FINGERPRINT = { 'rsa' => 1, 'dsa' => 2, 'ecdsa' => 3, 'ed25519' => 4 }.freeze + + def create_ssh(key_type, key) + key_name = SSH_NAME[key] + decoded_key = Base64.decode64(key) + ssh_fp = SSH_FINGERPRINT[key_name] + sha1 = "SSHFP #{ssh_fp} 1 #{Digest::SHA1.new.update(decoded_key)}" + sha256 = "SSHFP #{ssh_fp} 2 #{Digest::SHA2.new.update(decoded_key)}" + + fingerprint = Facter::FingerPrint.new(sha1, sha256) + Facter::Ssh.new(fingerprint, key_type, key, key_name) + end + end + end + end +end diff --git a/lib/resolvers/windows/ssh.rb b/lib/resolvers/windows/ssh.rb new file mode 100644 index 000000000..4f6d723e2 --- /dev/null +++ b/lib/resolvers/windows/ssh.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Facter + module Resolvers + module Windows + class Ssh < BaseResolver + @log = Facter::Log.new(self) + @semaphore = Mutex.new + @fact_list ||= {} + FILE_NAMES = %w[ssh_host_rsa_key.pub ssh_host_dsa_key.pub + ssh_host_ecdsa_key.pub ssh_host_ed25519_key.pub].freeze + class << self + private + + def post_resolve(fact_name) + @fact_list.fetch(fact_name) { retrieve_info(fact_name) } + end + + def retrieve_info(fact_name) + ssh_dir = determine_ssh_dir + return unless ssh_dir && File.directory?(ssh_dir) + + ssh_list = [] + + FILE_NAMES.each do |file_name| + next unless File.readable?(File.join(ssh_dir, file_name)) + + key_type, key = File.read(File.join(ssh_dir, file_name)).split(' ') + ssh_list << ::Resolvers::Utils::SshHelper.create_ssh(key_type, key) + end + @fact_list[:ssh] = ssh_list.empty? ? nil : ssh_list + @fact_list[fact_name] + end + + def determine_ssh_dir + progdata_dir = ENV['programdata'] + + return if !progdata_dir || progdata_dir.empty? + + File.join(progdata_dir, 'ssh') + end + end + end + end + end +end diff --git a/spec/facter/facts/windows/ssh_spec.rb b/spec/facter/facts/windows/ssh_spec.rb new file mode 100644 index 000000000..ae1d714ad --- /dev/null +++ b/spec/facter/facts/windows/ssh_spec.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +describe Facts::Windows::Ssh do + describe '#call_the_resolver' do + subject(:fact) { Facts::Windows::Ssh.new } + + context 'when user is privileged' do + let(:ssh) do + [Facter::Ssh.new(Facter::FingerPrint.new('test', 'test'), 'ecdsa', 'test', 'ecdsa')] + end + let(:value) do + { 'ecdsa' => { 'fingerprints' => + { 'sha1' => 'test', 'sha256' => 'test' }, + 'key' => 'test', + 'type' => 'ecdsa' } } + end + + before do + allow(Facter::Resolvers::Identity).to receive(:resolve).with(:privileged).and_return(true) + allow(Facter::Resolvers::Windows::Ssh).to receive(:resolve).with(:ssh).and_return(ssh) + end + + it 'calls Facter::Resolvers::Windows::Ssh' do + fact.call_the_resolver + expect(Facter::Resolvers::Windows::Ssh).to have_received(:resolve).with(:ssh) + end + + it 'calls Facter::Resolvers::Windows::Identity' do + fact.call_the_resolver + expect(Facter::Resolvers::Identity).to have_received(:resolve).with(:privileged) + end + + it 'returns ssh fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'ssh', value: value) + end + end + + context 'when user is privileged but no ssh key found' do + let(:value) { nil } + + before do + allow(Facter::Resolvers::Identity).to receive(:resolve).with(:privileged).and_return(true) + allow(Facter::Resolvers::Windows::Ssh).to receive(:resolve).with(:ssh).and_return({}) + end + + it 'calls Facter::Resolvers::Windows::Ssh' do + fact.call_the_resolver + expect(Facter::Resolvers::Windows::Ssh).to have_received(:resolve).with(:ssh) + end + + it 'calls Facter::Resolvers::Windows::Identity' do + fact.call_the_resolver + expect(Facter::Resolvers::Identity).to have_received(:resolve).with(:privileged) + end + + it 'returns ssh fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'ssh', value: value) + end + end + + context 'when user is not privileged' do + let(:value) { nil } + + before do + allow(Facter::Resolvers::Identity).to receive(:resolve).with(:privileged).and_return(false) + allow(Facter::Resolvers::Windows::Ssh).to receive(:resolve).with(:ssh).and_return(value) + end + + it "doesn't call Facter::Resolvers::Windows::Ssh" do + fact.call_the_resolver + expect(Facter::Resolvers::Windows::Ssh).not_to have_received(:resolve).with(:ssh) + end + + it 'calls Facter::Resolvers::Windows::Identity' do + fact.call_the_resolver + expect(Facter::Resolvers::Identity).to have_received(:resolve).with(:privileged) + end + + it 'returns ssh fact' do + expect(fact.call_the_resolver).to be_an_instance_of(Facter::ResolvedFact).and \ + have_attributes(name: 'ssh', value: value) + end + end + end +end diff --git a/spec/facter/resolvers/ssh_resolver_spec.rb b/spec/facter/resolvers/ssh_resolver_spec.rb index 1d6ab8fb6..ef1931c7f 100644 --- a/spec/facter/resolvers/ssh_resolver_spec.rb +++ b/spec/facter/resolvers/ssh_resolver_spec.rb @@ -7,36 +7,29 @@ let(:ed25519_content) { load_fixture('ed25519').read.strip! } let(:ecdsa_fingerprint) do - double(Facter::FingerPrint, - sha1: 'SSHFP 3 1 fd92cf867fac0042d491eb1067e4f3cabf54039a', - sha256: 'SSHFP 3 2 a51271a67987d7bbd685fa6d7cdd2823a30373ab01420b094480523fabff2a05') + Facter::FingerPrint.new('SSHFP 3 1 fd92cf867fac0042d491eb1067e4f3cabf54039a', + 'SSHFP 3 2 a51271a67987d7bbd685fa6d7cdd2823a30373ab01420b094480523fabff2a05') end let(:rsa_fingerprint) do - double(Facter::FingerPrint, - sha1: 'SSHFP 1 1 90134f93fec6ab5e22bdd88fc4d7cd6e9dca4a07', - sha256: 'SSHFP 1 2 efaa26ff8169f5ffc372ebcad17aef886f4ccaa727169acdd0379b51c6c77e99') + Facter::FingerPrint.new('SSHFP 1 1 90134f93fec6ab5e22bdd88fc4d7cd6e9dca4a07', + 'SSHFP 1 2 efaa26ff8169f5ffc372ebcad17aef886f4ccaa727169acdd0379b51c6c77e99') end let(:ed25519_fingerprint) do - double(Facter::FingerPrint, - sha1: 'SSHFP 4 1 f5780634d4e34c6ef2411ac439b517bfdce43cf1', - sha256: 'SSHFP 4 2 c1257b3865df22f3349f9ebe19961c8a8edf5fbbe883113e728671b42d2c9723') + Facter::FingerPrint.new('SSHFP 4 1 f5780634d4e34c6ef2411ac439b517bfdce43cf1', + 'SSHFP 4 2 c1257b3865df22f3349f9ebe19961c8a8edf5fbbe883113e728671b42d2c9723') end let(:ecdsa_result) do - double(Facter::Ssh, fingerprint: ecdsa_fingerprint, type: 'ecdsa-sha2-nistp256', - key: load_fixture('ecdsa_key').read.strip!, name: 'ecdsa') + Facter::Ssh.new(ecdsa_fingerprint, 'ecdsa-sha2-nistp256', ecdsa_content, 'ecdsa') end let(:rsa_result) do - double(Facter::Ssh, fingerprint: rsa_fingerprint, type: 'ssh-rsa', - key: load_fixture('rsa_key').read.strip!, name: 'rsa') + Facter::Ssh.new(rsa_fingerprint, 'ssh-rsa', rsa_content, 'rsa') end - let(:ed25519_result) do - double(Facter::Ssh, fingerpint: ed25519_fingerprint, type: 'ssh-ed22519', - key: load_fixture('ed25519_key').read.strip!, name: 'ed25519') + Facter::Ssh.new(ed25519_fingerprint, 'ssh-ed22519', ed25519_content, 'ed25519') end let(:paths) { %w[/etc/ssh /usr/local/etc/ssh /etc /usr/local/etc /etc/opt/ssh] } @@ -55,37 +48,14 @@ allow(Facter::Util::FileHelper).to receive(:safe_read) .with('/etc/ssh_host_ed25519_key.pub', nil).and_return(ed25519_content) - allow(Facter::FingerPrint) - .to receive(:new) - .with('SSHFP 3 1 fd92cf867fac0042d491eb1067e4f3cabf54039a', - 'SSHFP 3 2 a51271a67987d7bbd685fa6d7cdd2823a30373ab01420b094480523fabff2a05') - .and_return(ecdsa_fingerprint) - - allow(Facter::FingerPrint) - .to receive(:new) - .with('SSHFP 1 1 90134f93fec6ab5e22bdd88fc4d7cd6e9dca4a07', - 'SSHFP 1 2 efaa26ff8169f5ffc372ebcad17aef886f4ccaa727169acdd0379b51c6c77e99') - .and_return(rsa_fingerprint) - - allow(Facter::FingerPrint) - .to receive(:new) - .with('SSHFP 4 1 1c02084d251368b98a3af97820d9fbf2b8dc9558', - 'SSHFP 4 2 656bd7aa3f8ad4703bd581888231f822cb8cd4a2a258584469551d2c2c9f6b62') - .and_return(ed25519_fingerprint) - - allow(Facter::Ssh) - .to receive(:new) - .with(ecdsa_fingerprint, 'ecdsa-sha2-nistp256', load_fixture('ecdsa_key').read.strip!, 'ecdsa') - .and_return(ecdsa_result) - - allow(Facter::Ssh) - .to receive(:new) - .with(rsa_fingerprint, 'ssh-rsa', load_fixture('rsa_key').read.strip!, 'rsa') + allow(Resolvers::Utils::SshHelper).to receive(:create_ssh) + .with('ssh-rsa', load_fixture('rsa_key').read.strip!) .and_return(rsa_result) - - allow(Facter::Ssh) - .to receive(:new) - .with(ed25519_fingerprint, 'ssh-ed25519', load_fixture('ed25519_key').read.strip!, 'ed25519') + allow(Resolvers::Utils::SshHelper).to receive(:create_ssh) + .with('ecdsa-sha2-nistp256', load_fixture('ecdsa_key').read.strip!) + .and_return(ecdsa_result) + allow(Resolvers::Utils::SshHelper).to receive(:create_ssh) + .with('ssh-ed25519', load_fixture('ed25519_key').read.strip!) .and_return(ed25519_result) end diff --git a/spec/facter/resolvers/utils/ssh_helper_spec.rb b/spec/facter/resolvers/utils/ssh_helper_spec.rb new file mode 100644 index 000000000..3a16e05ae --- /dev/null +++ b/spec/facter/resolvers/utils/ssh_helper_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +describe Resolvers::Utils::SshHelper do + subject(:ssh_helper) { Resolvers::Utils::SshHelper } + + describe '#create_ssh' do + let(:fingerprint) { instance_spy(Facter::FingerPrint) } + let(:key) { load_fixture('rsa_key').read.strip } + let(:ssh_object) { Facter::Ssh.new(fingerprint, 'ssh-rsa', key, 'rsa') } + + before do + allow(Facter::FingerPrint).to receive(:new).and_return(fingerprint) + allow(Facter::Ssh).to receive(:new).and_return(ssh_object) + end + + it 'returns a ssh object' do + expect(ssh_helper.create_ssh('ssh-rsa', key)).to eql(ssh_object) + end + end +end diff --git a/spec/facter/resolvers/windows/ssh_spec.rb b/spec/facter/resolvers/windows/ssh_spec.rb new file mode 100644 index 000000000..0cae2c8f6 --- /dev/null +++ b/spec/facter/resolvers/windows/ssh_spec.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +describe Facter::Resolvers::Windows::Ssh do + describe '#resolve' do + before do + allow(ENV).to receive(:[]).with('programdata').and_return(programdata_dir) + allow(File).to receive(:directory?).with("#{programdata_dir}/ssh").and_return(dir_exists) + end + + after do + Facter::Resolvers::Windows::Ssh.invalidate_cache + end + + context 'when programdata enviroment variable is set' do + let(:programdata_dir) { 'C:/ProgramData' } + let(:dir_exists) { true } + + before do + allow(File).to receive(:readable?).with("#{programdata_dir}/ssh/ssh_host_ecdsa_key.pub") + .and_return(ecdsa_exists) + allow(File).to receive(:readable?).with("#{programdata_dir}/ssh/ssh_host_rsa_key.pub").and_return(rsa_exists) + allow(File).to receive(:readable?).with("#{programdata_dir}/ssh/ssh_host_ed25519_key.pub") + .and_return(ed25519_exists) + allow(File).to receive(:readable?).with("#{programdata_dir}/ssh/ssh_host_dsa_key.pub").and_return(false) + end + + context 'when ecdsa, ed25519 and rsa files exists' do + before do + allow(File).to receive(:read).with("#{programdata_dir}/ssh/ssh_host_ecdsa_key.pub").and_return(ecdsa_content) + allow(File).to receive(:read).with("#{programdata_dir}/ssh/ssh_host_rsa_key.pub").and_return(rsa_content) + allow(File).to receive(:read).with("#{programdata_dir}/ssh/ssh_host_ed25519_key.pub") + .and_return(ed25519_content) + + allow(Resolvers::Utils::SshHelper).to receive(:create_ssh) + .with('ssh-rsa', load_fixture('rsa_key').read.strip!) + .and_return(rsa_result) + allow(Resolvers::Utils::SshHelper).to receive(:create_ssh) + .with('ecdsa-sha2-nistp256', load_fixture('ecdsa_key').read.strip!) + .and_return(ecdsa_result) + allow(Resolvers::Utils::SshHelper).to receive(:create_ssh) + .with('ssh-ed25519', load_fixture('ed25519_key').read.strip!) + .and_return(ed25519_result) + end + + let(:ecdsa_exists) { true } + let(:rsa_exists) { true } + let(:ed25519_exists) { true } + let(:ecdsa_content) { load_fixture('ecdsa').read.strip! } + let(:rsa_content) { load_fixture('rsa').read.strip! } + let(:ed25519_content) { load_fixture('ed25519').read.strip! } + + let(:ecdsa_fingerprint) do + Facter::FingerPrint.new('SSHFP 3 1 fd92cf867fac0042d491eb1067e4f3cabf54039a', + 'SSHFP 3 2 a51271a67987d7bbd685fa6d7cdd2823a30373ab01420b094480523fabff2a05') + end + + let(:rsa_fingerprint) do + Facter::FingerPrint.new('SSHFP 1 1 90134f93fec6ab5e22bdd88fc4d7cd6e9dca4a07', + 'SSHFP 1 2 efaa26ff8169f5ffc372ebcad17aef886f4ccaa727169acdd0379b51c6c77e99') + end + + let(:ed25519_fingerprint) do + Facter::FingerPrint.new('SSHFP 4 1 f5780634d4e34c6ef2411ac439b517bfdce43cf1', + 'SSHFP 4 2 c1257b3865df22f3349f9ebe19961c8a8edf5fbbe883113e728671b42d2c9723') + end + + let(:ecdsa_result) do + Facter::Ssh.new(ecdsa_fingerprint, 'ecdsa-sha2-nistp256', ecdsa_content, 'ecdsa') + end + + let(:rsa_result) do + Facter::Ssh.new(rsa_fingerprint, 'ssh-rsa', rsa_content, 'rsa') + end + + let(:ed25519_result) do + Facter::Ssh.new(ed25519_fingerprint, 'ssh-ed22519', ed25519_content, 'ed25519') + end + + it 'returns ssh fact' do + expect(Facter::Resolvers::Windows::Ssh.resolve(:ssh)).to eq([rsa_result, ecdsa_result, ed25519_result]) + end + end + + context 'when files are not readable' do + let(:ecdsa_exists) { false } + let(:rsa_exists) { false } + let(:ed25519_exists) { false } + + it 'returns nil' do + expect(Facter::Resolvers::Windows::Ssh.resolve(:ssh)).to eq(nil) + end + end + end + + context 'when programdata enviroment variable is not set' do + let(:programdata_dir) { '' } + let(:dir_exists) { false } + + it 'returns nil' do + expect(Facter::Resolvers::Windows::Ssh.resolve(:ssh)).to eq(nil) + end + end + end +end