diff --git a/Rakefile b/Rakefile index 1c42a7c38..76dd166a2 100755 --- a/Rakefile +++ b/Rakefile @@ -277,178 +277,6 @@ namespace :test do sh("sh", "-c", sh_cmd) end - - project_dir = File.dirname(__FILE__) - namespace :aws do - %w{default minimal}.each do |account| - integration_dir = File.join(project_dir, "test", "integration", "aws", account) - attribute_file = File.join(integration_dir, ".attribute.yml") - - task :"setup:#{account}", :tf_workspace do |t, args| - tf_workspace = args[:tf_workspace] || ENV["INSPEC_TERRAFORM_ENV"] - abort("You must either call the top-level test:aws:#{account} task, or set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace - puts "----> Setup" - abort("You must set the environment variable AWS_REGION") unless ENV["AWS_REGION"] - puts "----> Checking for required AWS profile..." - sh("aws configure get aws_access_key_id --profile inspec-aws-test-#{account} > /dev/null") - sh("cd #{integration_dir}/build/ && terraform init -upgrade") - sh("cd #{integration_dir}/build/ && terraform workspace new #{tf_workspace}") - sh("cd #{integration_dir}/build/ && AWS_PROFILE=inspec-aws-test-#{account} terraform plan -out inspec-aws-#{account}.plan") - sh("cd #{integration_dir}/build/ && AWS_PROFILE=inspec-aws-test-#{account} terraform apply -auto-approve inspec-aws-#{account}.plan") - Rake::Task["test:aws:dump_attrs:#{account}"].execute - end - - task :"dump_attrs:#{account}" do - sh("cd #{integration_dir}/build/ && AWS_PROFILE=inspec-aws-test-#{account} terraform output > #{attribute_file}") - raw_output = File.read(attribute_file) - yaml_output = raw_output.gsub(" = ", " : ") - File.open(attribute_file, "w") { |file| file.puts yaml_output } - end - - task :"run:#{account}" do - puts "----> Run" - sh("bundle exec inspec exec #{integration_dir}/verify -t aws://${AWS_REGION}/inspec-aws-test-#{account} --attrs #{attribute_file}") - end - - task :"cleanup:#{account}", :tf_workspace do |t, args| - tf_workspace = args[:tf_workspace] || ENV["INSPEC_TERRAFORM_ENV"] - abort("You must either call the top-level test:aws:#{account} task, or set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace - puts "----> Cleanup" - sh("cd #{integration_dir}/build/ && AWS_PROFILE=inspec-aws-test-#{account} terraform destroy -force") - sh("cd #{integration_dir}/build/ && terraform workspace select default") - sh("cd #{integration_dir}/build && terraform workspace delete #{tf_workspace}") - end - - task :"#{account}" do - tf_workspace = ENV["INSPEC_TERRAFORM_ENV"] || prompt("Please enter a workspace for your integration tests to run in: ") - begin - Rake::Task["test:aws:setup:#{account}"].execute({ tf_workspace: tf_workspace }) - Rake::Task["test:aws:run:#{account}"].execute - rescue - abort("Integration testing has failed for the #{account} account") - ensure - Rake::Task["test:aws:cleanup:#{account}"].execute({ tf_workspace: tf_workspace }) - end - end - end - end - desc "Perform AWS Integration Tests" - task aws: %i{aws:default aws:minimal} - - namespace :azure do - # Specify the directory for the integration tests - integration_dir = File.join(project_dir, "test", "integration", "azure") - tf_vars_file = File.join(integration_dir, "build", "terraform.tfvars") - attribute_file = File.join(integration_dir, ".attribute.yml") - - task :setup, :tf_workspace do |t, args| - tf_workspace = args[:tf_workspace] || ENV["INSPEC_TERRAFORM_ENV"] - abort("You must either call the top-level test:azure task, or set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace - - puts "----> Setup Terraform Workspace" - - sh("cd #{integration_dir}/build/ && terraform init -upgrade") - sh("cd #{integration_dir}/build/ && terraform workspace new #{tf_workspace}") - - Rake::Task["test:azure:vars"].execute - Rake::Task["test:azure:plan"].execute - Rake::Task["test:azure:apply"].execute - end - - desc "Generate terraform.tfvars file" - task :vars do |t, args| - - next if File.exist?(tf_vars_file) - - puts "----> Generating Vars" - - # Generate Azure crendentials - connection = Train.create("azure").connection - creds = connection.options - - # Determine the storage account name and the admin password - require "securerandom" - sa_name = ("a".."z").to_a.sample(15).join - admin_password = SecureRandom.alphanumeric 72 - - # Use the first 4 characters of the storage account to create a suffix - suffix = sa_name[0..3] - - content = <<~VARS - subscription_id = "#{creds[:subscription_id]}" - client_id = "#{creds[:client_id]}" - client_secret = "#{creds[:client_secret]}" - tenant_id = "#{creds[:tenant_id]}" - storage_account_name = "#{sa_name}" - admin_password = "#{admin_password}" - suffix = "#{suffix}" - VARS - - content << "location = \"#{ENV["AZURE_LOCATION"]}\"\n" if ENV["AZURE_LOCATION"] - - File.write(tf_vars_file, content) - end - - desc "generate plan from state using terraform.tfvars file" - task :plan, [:tf_workspace] => [:vars] do |t, args| - tf_workspace = args[:tf_workspace] || ENV["INSPEC_TERRAFORM_ENV"] - abort("You must set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace - - puts "----> Generating Plan" - - sh("cd #{integration_dir}/build/ && terraform plan -out inspec-azure.plan") - end - - desc "apply terraform plan" - task :apply, [:tf_workspace] => [:plan] do |t, args| - tf_workspace = args[:tf_workspace] || ENV["INSPEC_TERRAFORM_ENV"] - abort("You must set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace - puts "----> Applying Plan" - - sh("cd #{integration_dir}/build/ && terraform workspace select #{tf_workspace}") - - sh("cd #{integration_dir}/build/ && terraform apply inspec-azure.plan") - - Rake::Task["test:azure:dump_attrs"].execute - end - - task :dump_attrs do - sh("cd #{integration_dir}/build/ && terraform output > #{attribute_file}") - raw_output = File.read(attribute_file) - yaml_output = raw_output.gsub(" = ", " : ") - File.open(attribute_file, "w") { |file| file.puts yaml_output } - end - - task :run do - puts "----> Run" - sh("bundle exec inspec exec #{integration_dir}/verify -t azure://1e0b427a-d58b-494e-ae4f-ee558463ebbf") - end - - task :cleanup, :tf_workspace do |t, args| - tf_workspace = args[:tf_workspace] || ENV["INSPEC_TERRAFORM_ENV"] - abort("You must either call the top-level test:azure task, or set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace - puts "----> Cleanup" - - sh("cd #{integration_dir}/build/ && terraform destroy -force ") - - sh("cd #{integration_dir}/build/ && terraform workspace select default") - sh("cd #{integration_dir}/build && terraform workspace delete #{tf_workspace}") - File.delete(tf_vars_file) - end - end - - desc "Perform Azure Integration Tests" - task :azure do - tf_workspace = ENV["INSPEC_TERRAFORM_ENV"] || prompt("Please enter a workspace for your integration tests to run in: ") - begin - Rake::Task["test:azure:setup"].execute({ tf_workspace: tf_workspace }) - Rake::Task["test:azure:run"].execute - rescue - abort("Integration testing has failed") - ensure - Rake::Task["test:azure:cleanup"].execute({ tf_workspace: tf_workspace }) - end - end end # Print the current version of this gem or update it. diff --git a/lib/inspec/resources.rb b/lib/inspec/resources.rb index 18e591e1b..e90188620 100644 --- a/lib/inspec/resources.rb +++ b/lib/inspec/resources.rb @@ -9,20 +9,6 @@ require "inspec/resource" -# Detect if we are running the stripped-down inspec-core -# This relies on AWS being stripped from the inspec-core gem -inspec_core_only = ENV["NO_AWS"] || !File.exist?(File.join(File.dirname(__FILE__), "..", "resource_support", "aws.rb")) - -# Do not attempt to load cloud resources if we are in inspec-core mode -unless inspec_core_only - require "resource_support/aws" - require "resources/azure/azure_backend" - require "resources/azure/azure_generic_resource" - require "resources/azure/azure_resource_group" - require "resources/azure/azure_virtual_machine" - require "resources/azure/azure_virtual_machine_data_disk" -end - require "inspec/resources/aide_conf" require "inspec/resources/apache" require "inspec/resources/apache_conf" diff --git a/lib/resource_support/aws.rb b/lib/resource_support/aws.rb deleted file mode 100644 index 3dd303a48..000000000 --- a/lib/resource_support/aws.rb +++ /dev/null @@ -1,76 +0,0 @@ -# Main AWS loader file. The intent is for this to be -# loaded only if AWS resources are needed. - -require "aws-sdk-core" - -require "aws-sdk-cloudtrail" -require "aws-sdk-cloudwatch" -require "aws-sdk-cloudwatchlogs" -require "aws-sdk-costandusagereportservice" -require "aws-sdk-configservice" -require "aws-sdk-ec2" -require "aws-sdk-ecs" -require "aws-sdk-eks" -require "aws-sdk-elasticloadbalancing" -require "aws-sdk-iam" -require "aws-sdk-kms" -require "aws-sdk-rds" -require "aws-sdk-s3" -require "aws-sdk-sqs" -require "aws-sdk-sns" - -require "resource_support/aws/aws_backend_factory_mixin" -require "resource_support/aws/aws_resource_mixin" -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" - -# Load all AWS resources -# TODO: loop over and load entire directory -# for f in ls lib/resources/aws/*; do t=$(echo $f | cut -c 5- | cut -f1 -d. ); echo "require '${t}'"; done -require "resources/aws/aws_billing_report" -require "resources/aws/aws_billing_reports" -require "resources/aws/aws_cloudtrail_trail" -require "resources/aws/aws_cloudtrail_trails" -require "resources/aws/aws_cloudwatch_alarm" -require "resources/aws/aws_cloudwatch_log_metric_filter" -require "resources/aws/aws_config_delivery_channel" -require "resources/aws/aws_config_recorder" -require "resources/aws/aws_ec2_instance" -require "resources/aws/aws_ebs_volume" -require "resources/aws/aws_ebs_volumes" -require "resources/aws/aws_flow_log" -require "resources/aws/aws_ec2_instances" -require "resources/aws/aws_ecs_cluster" -require "resources/aws/aws_eks_cluster" -require "resources/aws/aws_elb" -require "resources/aws/aws_elbs" -require "resources/aws/aws_iam_access_key" -require "resources/aws/aws_iam_access_keys" -require "resources/aws/aws_iam_group" -require "resources/aws/aws_iam_groups" -require "resources/aws/aws_iam_password_policy" -require "resources/aws/aws_iam_policies" -require "resources/aws/aws_iam_policy" -require "resources/aws/aws_iam_role" -require "resources/aws/aws_iam_root_user" -require "resources/aws/aws_iam_user" -require "resources/aws/aws_iam_users" -require "resources/aws/aws_kms_key" -require "resources/aws/aws_kms_keys" -require "resources/aws/aws_rds_instance" -require "resources/aws/aws_route_table" -require "resources/aws/aws_route_tables" -require "resources/aws/aws_s3_bucket" -require "resources/aws/aws_s3_bucket_object" -require "resources/aws/aws_s3_buckets" -require "resources/aws/aws_security_group" -require "resources/aws/aws_security_groups" -require "resources/aws/aws_sns_subscription" -require "resources/aws/aws_sns_topic" -require "resources/aws/aws_sns_topics" -require "resources/aws/aws_sqs_queue" -require "resources/aws/aws_subnet" -require "resources/aws/aws_subnets" -require "resources/aws/aws_vpc" -require "resources/aws/aws_vpcs" diff --git a/lib/resource_support/aws/aws_backend_base.rb b/lib/resource_support/aws/aws_backend_base.rb deleted file mode 100644 index ecf5ef5b3..000000000 --- a/lib/resource_support/aws/aws_backend_base.rb +++ /dev/null @@ -1,12 +0,0 @@ -class AwsBackendBase - attr_reader :aws_transport - class << self; attr_accessor :aws_client_class end - - def initialize(inspec = nil) - @aws_transport = inspec ? inspec.backend : nil - end - - def aws_service_client - aws_transport.aws_client(self.class.aws_client_class) - end -end diff --git a/lib/resource_support/aws/aws_backend_factory_mixin.rb b/lib/resource_support/aws/aws_backend_factory_mixin.rb deleted file mode 100644 index 36b3a33f3..000000000 --- a/lib/resource_support/aws/aws_backend_factory_mixin.rb +++ /dev/null @@ -1,12 +0,0 @@ -# Intended to be pulled in via extend, not include -module AwsBackendFactoryMixin - def create(inspec) - @selected_backend.new(inspec) - end - - def select(klass) - @selected_backend = klass - end - - alias set_default_backend select -end diff --git a/lib/resource_support/aws/aws_plural_resource_mixin.rb b/lib/resource_support/aws/aws_plural_resource_mixin.rb deleted file mode 100644 index 15b2f9d4f..000000000 --- a/lib/resource_support/aws/aws_plural_resource_mixin.rb +++ /dev/null @@ -1,24 +0,0 @@ -require "resource_support/aws/aws_resource_mixin" -require "resource_support/aws/aws_backend_factory_mixin" - -module AwsPluralResourceMixin - include AwsResourceMixin - attr_reader :table - - # This sets up a class, AwsSomeResource::BackendFactory, that - # provides a mechanism to create and use backends without - # having to know which is selected. This is mainly used for - # unit testing. - # TODO: DRY up. This code exists in both the Singular and Plural mixins. - # We'd like to put it in AwsResourceMixin, but included only sees the - # directly-including class - we can't see second-order includers. - def self.included(base) - # Create a new class, whose body is simply to extend the - # backend factory mixin - resource_backend_factory_class = Class.new(Object) do - extend AwsBackendFactoryMixin - end - # Name that class - base.const_set("BackendFactory", resource_backend_factory_class) - end -end diff --git a/lib/resource_support/aws/aws_resource_mixin.rb b/lib/resource_support/aws/aws_resource_mixin.rb deleted file mode 100644 index 9d9bc7e97..000000000 --- a/lib/resource_support/aws/aws_resource_mixin.rb +++ /dev/null @@ -1,69 +0,0 @@ -module AwsResourceMixin - def initialize(resource_params = {}) - Inspec.deprecate(:aws_resources_in_resource_pack, - "Resource '#{@__resource_name__ ||= self.class.to_s}'") - validate_params(resource_params).each do |param, value| - instance_variable_set(:"@#{param}", value) - end - catch_aws_errors do - fetch_from_api - end - rescue ArgumentError => e - # continue with ArgumentError if testing - raise unless respond_to?(:inspec) && inspec - - raise Inspec::Exceptions::ResourceFailed, e.message - end - - # Default implementation of validate params accepts everything. - def validate_params(resource_params) - resource_params - end - - def check_resource_param_names(raw_params: {}, allowed_params: [], allowed_scalar_name: nil, allowed_scalar_type: nil) - # Some resources allow passing in a single ID value. Check and convert to hash if so. - if allowed_scalar_name && !raw_params.is_a?(Hash) - value_seen = raw_params - if value_seen.is_a?(allowed_scalar_type) - raw_params = { allowed_scalar_name => value_seen } - else - raise ArgumentError, "If you pass a single value to the resource, it must " \ - "be a #{allowed_scalar_type}, not an #{value_seen.class}." - end - end - - # Remove all expected params from the raw param hash - recognized_params = {} - allowed_params.each do |expected_param| - recognized_params[expected_param] = raw_params.delete(expected_param) if raw_params.key?(expected_param) - end - - # Any leftovers are unwelcome - unless raw_params.empty? - raise ArgumentError, "Unrecognized resource param '#{raw_params.keys.first}'. Expected parameters: #{allowed_params.join(", ")}" - end - - recognized_params - end - - def inspec_runner - # When running under inspec-cli, we have an 'inspec' method that - # returns the runner. When running under unit tests, we don't - # have that, but we still have to call this to pass something - # (nil is OK) to the backend. - # TODO: remove with https://github.com/chef/inspec-aws/issues/216 - inspec if respond_to?(:inspec) - end - - # Intercept AWS exceptions - def catch_aws_errors - yield - rescue Aws::Errors::MissingCredentialsError - # The AWS error here is unhelpful: - # "unable to sign request without credentials set" - Inspec::Log.error "It appears that you have not set your AWS credentials. You may set them using environment variables, or using the 'aws://region/aws_credentials_profile' target. See https://docs.chef.io/inspec/platforms/ for details." - fail_resource("No AWS credentials available") - rescue Aws::Errors::ServiceError => e - fail_resource e.message - end -end diff --git a/lib/resource_support/aws/aws_singular_resource_mixin.rb b/lib/resource_support/aws/aws_singular_resource_mixin.rb deleted file mode 100644 index 1d85ffdaa..000000000 --- a/lib/resource_support/aws/aws_singular_resource_mixin.rb +++ /dev/null @@ -1,27 +0,0 @@ -require "resource_support/aws/aws_resource_mixin" -require "resource_support/aws/aws_backend_factory_mixin" - -module AwsSingularResourceMixin - include AwsResourceMixin - - def exists? - @exists - end - - # This sets up a class, AwsSomeResource::BackendFactory, that - # provides a mechanism to create and use backends without - # having to know which is selected. This is mainly used for - # unit testing. - # TODO: DRY up. This code exists in both the Singular and Plural mixins. - # We'd like to put it in AwsResourceMixin, but included only sees the - # directly-including class - we can't see second-order includers. - def self.included(base) - # Create a new class, whose body is simply to extend the - # backend factory mixin - resource_backend_factory_class = Class.new(Object) do - extend AwsBackendFactoryMixin - end - # Name that class - base.const_set("BackendFactory", resource_backend_factory_class) - end -end diff --git a/lib/resources/aws/aws_billing_report.rb b/lib/resources/aws/aws_billing_report.rb deleted file mode 100644 index de3477947..000000000 --- a/lib/resources/aws/aws_billing_report.rb +++ /dev/null @@ -1,105 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" - -require "aws-sdk-costandusagereportservice" - -class AwsBillingReport < Inspec.resource(1) - name "aws_billing_report" - supports platform: "aws" - desc "Verifies settings for AWS Cost and Billing Reports." - example <<~EXAMPLE - describe aws_billing_report('inspec1') do - its('report_name') { should cmp 'inspec1' } - its('time_unit') { should cmp 'hourly' } - end - - describe aws_billing_report(report: 'inspec1') do - it { should exist } - end - EXAMPLE - - include AwsSingularResourceMixin - - attr_reader :report_name, :time_unit, :format, :compression, :s3_bucket, - :s3_prefix, :s3_region - - def to_s - "AWS Billing Report #{report_name}" - end - - def hourly? - exists? ? time_unit.eql?("hourly") : nil - end - - def daily? - exists? ? time_unit.eql?("daily") : nil - end - - def zip? - exists? ? compression.eql?("zip") : nil - end - - def gzip? - exists? ? compression.eql?("gzip") : nil - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:report_name], - allowed_scalar_name: :report_name, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, "You must provide the parameter 'report_name' to aws_billing_report." - end - - validated_params - end - - def fetch_from_api - report = find_report(report_name) - @exists = !report.nil? - if exists? - @time_unit = report.time_unit.downcase - @format = report.format.downcase - @compression = report.compression.downcase - @s3_bucket = report.s3_bucket - @s3_prefix = report.s3_prefix - @s3_region = report.s3_region - end - end - - def find_report(report_name) - pagination_opts = {} - found_report_def = nil - while found_report_def.nil? - api_result = backend.describe_report_definitions(pagination_opts) - next_token = api_result.next_token - found_report_def = api_result.report_definitions.find { |report_def| report_def.report_name == report_name } - pagination_opts = { next_token: next_token } - - next if found_report_def.nil? && next_token # Loop again: didn't find it, but there are more results - break if found_report_def.nil? && next_token.nil? # Give up: didn't find it, no more results - end - found_report_def - end - - def backend - @backend ||= BackendFactory.create(inspec_runner) - end - - class Backend - class AwsClientApi < AwsBackendBase - AwsBillingReport::BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::CostandUsageReportService::Client - - def describe_report_definitions(query = {}) - aws_service_client.describe_report_definitions(query) - end - end - end -end diff --git a/lib/resources/aws/aws_billing_reports.rb b/lib/resources/aws/aws_billing_reports.rb deleted file mode 100644 index c7784b10b..000000000 --- a/lib/resources/aws/aws_billing_reports.rb +++ /dev/null @@ -1,74 +0,0 @@ -require "inspec/utils/filter" -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-costandusagereportservice" - -class AwsBillingReports < Inspec.resource(1) - name "aws_billing_reports" - supports platform: "aws" - desc "Verifies settings for AWS Cost and Billing Reports." - example <<~EXAMPLE - describe aws_billing_reports do - its('report_names') { should include 'inspec1' } - its('s3_buckets') { should include 'inspec1-s3-bucket' } - end - - describe aws_billing_reports.where { report_name =~ /inspec.*/ } do - its ('report_names') { should include ['inspec1'] } - its ('time_units') { should include ['DAILY'] } - its ('s3_buckets') { should include ['inspec1-s3-bucket'] } - end - EXAMPLE - - include AwsPluralResourceMixin - - filtertable = FilterTable.create - filtertable.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - .register_column(:report_names, field: :report_name) - .register_column(:time_units, field: :time_unit, style: :simple) - .register_column(:formats, field: :format, style: :simple) - .register_column(:compressions, field: :compression, style: :simple) - .register_column(:s3_buckets, field: :s3_bucket, style: :simple) - .register_column(:s3_prefixes, field: :s3_prefix, style: :simple) - .register_column(:s3_regions, field: :s3_region, style: :simple) - filtertable.install_filter_methods_on_resource(self, :table) - - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_billing_reports does not accept resource parameters." - end - - resource_params - end - - def to_s - "AWS Billing Reports" - end - - def fetch_from_api - @table = [] - pagination_opts = {} - backend = BackendFactory.create(inspec_runner) - loop do - api_result = backend.describe_report_definitions(pagination_opts) - api_result.report_definitions.each do |raw_report| - report = raw_report.to_h - %i{time_unit compression}.each { |field| report[field].downcase! } - @table << report - end - pagination_opts = { next_token: api_result.next_token } - break unless api_result.next_token - end - end - - class Backend - class AwsClientApi < AwsBackendBase - AwsBillingReports::BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::CostandUsageReportService::Client - - def describe_report_definitions(options = {}) - aws_service_client.describe_report_definitions(options) - end - end - end -end diff --git a/lib/resources/aws/aws_cloudtrail_trail.rb b/lib/resources/aws/aws_cloudtrail_trail.rb deleted file mode 100644 index e337d8059..000000000 --- a/lib/resources/aws/aws_cloudtrail_trail.rb +++ /dev/null @@ -1,97 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-cloudtrail" - -class AwsCloudTrailTrail < Inspec.resource(1) - name "aws_cloudtrail_trail" - desc "Verifies settings for an individual AWS CloudTrail Trail" - example <<~EXAMPLE - describe aws_cloudtrail_trail('trail-name') do - it { should exist } - end - EXAMPLE - - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :cloud_watch_logs_log_group_arn, :cloud_watch_logs_role_arn, :home_region, - :kms_key_id, :s3_bucket_name, :trail_arn - - def to_s - "CloudTrail #{@trail_name}" - end - - def multi_region_trail? - @is_multi_region_trail - end - - def log_file_validation_enabled? - @log_file_validation_enabled - end - - def encrypted? - !kms_key_id.nil? - end - - def delivered_logs_days_ago - query = { name: @trail_name } - catch_aws_errors do - - resp = BackendFactory.create(inspec_runner).get_trail_status(query).to_h - ((Time.now - resp[:latest_cloud_watch_logs_delivery_time]) / (24 * 60 * 60)).to_i unless resp[:latest_cloud_watch_logs_delivery_time].nil? - rescue Aws::CloudTrail::Errors::TrailNotFoundException - nil - - end - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:trail_name], - allowed_scalar_name: :trail_name, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, "You must provide the parameter 'trail_name' to aws_cloudtrail_trail." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - query = { trail_name_list: [@trail_name] } - resp = backend.describe_trails(query) - - @trail = resp.trail_list[0].to_h - @exists = !@trail.empty? - @s3_bucket_name = @trail[:s3_bucket_name] - @is_multi_region_trail = @trail[:is_multi_region_trail] - @trail_arn = @trail[:trail_arn] - @log_file_validation_enabled = @trail[:log_file_validation_enabled] - @cloud_watch_logs_role_arn = @trail[:cloud_watch_logs_role_arn] - @cloud_watch_logs_log_group_arn = @trail[:cloud_watch_logs_log_group_arn] - @kms_key_id = @trail[:kms_key_id] - @home_region = @trail[:home_region] - end - - class Backend - class AwsClientApi < AwsBackendBase - AwsCloudTrailTrail::BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::CloudTrail::Client - - def describe_trails(query) - aws_service_client.describe_trails(query) - end - - def get_trail_status(query) - aws_service_client.get_trail_status(query) - end - end - end -end diff --git a/lib/resources/aws/aws_cloudtrail_trails.rb b/lib/resources/aws/aws_cloudtrail_trails.rb deleted file mode 100644 index 38ab771cd..000000000 --- a/lib/resources/aws/aws_cloudtrail_trails.rb +++ /dev/null @@ -1,51 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-cloudtrail" - -class AwsCloudTrailTrails < Inspec.resource(1) - name "aws_cloudtrail_trails" - desc "Verifies settings for AWS CloudTrail Trails in bulk" - example <<~EXAMPLE - describe aws_cloudtrail_trails do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_cloudtrail_trails does not accept resource parameters." - end - - resource_params - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:trail_arns, field: :trail_arn) - filter.register_column(:names, field: :name) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "CloudTrail Trails" - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = backend.describe_trails({}).to_h[:trail_list] - end - - class Backend - class AwsClientApi < AwsBackendBase - AwsCloudTrailTrails::BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::CloudTrail::Client - - def describe_trails(query) - aws_service_client.describe_trails(query) - end - end - end -end diff --git a/lib/resources/aws/aws_cloudwatch_alarm.rb b/lib/resources/aws/aws_cloudwatch_alarm.rb deleted file mode 100644 index 0cff458bc..000000000 --- a/lib/resources/aws/aws_cloudwatch_alarm.rb +++ /dev/null @@ -1,67 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-cloudwatch" - -class AwsCloudwatchAlarm < Inspec.resource(1) - name "aws_cloudwatch_alarm" - desc <<~EXAMPLE - # Look for a specific alarm - aws_cloudwatch_alarm( - metric_name: 'my-metric-name', - metric_namespace: 'my-metric-namespace', - ) do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :alarm_actions, :alarm_name, :metric_name, :metric_namespace - - private - - def validate_params(raw_params) - recognized_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: %i{metric_name metric_namespace} - ) - validated_params = {} - # Currently you must specify exactly metric_name and metric_namespace - %i{metric_name metric_namespace}.each do |param| - raise ArgumentError, "Missing resource param #{param}" unless recognized_params.key?(param) - - validated_params[param] = recognized_params.delete(param) - end - - validated_params - end - - def fetch_from_api - aws_alarms = BackendFactory.create(inspec_runner).describe_alarms_for_metric( - metric_name: @metric_name, - namespace: @metric_namespace - ) - if aws_alarms.metric_alarms.empty? - @exists = false - elsif aws_alarms.metric_alarms.count > 1 - alarms = aws_alarms.metric_alarms.map(&:alarm_name) - raise "More than one Cloudwatch Alarm was matched. Try using " \ - "more specific resource parameters. Alarms matched: #{alarms.join(", ")}" - else - @alarm_actions = aws_alarms.metric_alarms.first.alarm_actions - @alarm_name = aws_alarms.metric_alarms.first.alarm_name - @exists = true - end - end - - class Backend - class AwsClientApi < AwsBackendBase - AwsCloudwatchAlarm::BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::CloudWatch::Client - - def describe_alarms_for_metric(query) - aws_service_client.describe_alarms_for_metric(query) - end - end - end -end diff --git a/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb b/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb deleted file mode 100644 index c34e8cd68..000000000 --- a/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +++ /dev/null @@ -1,105 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-cloudwatchlogs" - -class AwsCloudwatchLogMetricFilter < Inspec.resource(1) - name "aws_cloudwatch_log_metric_filter" - desc "Verifies individual Cloudwatch Log Metric Filters" - example <<~EXAMPLE - # Look for a LMF by its filter name and log group name. This combination - # will always either find at most one LMF - no duplicates. - describe aws_cloudwatch_log_metric_filter( - filter_name: 'my-filter', - log_group_name: 'my-log-group' - ) do - it { should exist } - end - - # Search for an LMF by pattern and log group. - # This could result in an error if the results are not unique. - describe aws_cloudwatch_log_metric_filter( - log_group_name: 'my-log-group', - pattern: 'my-filter' - ) do - it { should exist } - end - EXAMPLE - supports platform: "aws" - include AwsSingularResourceMixin - attr_reader :filter_name, :log_group_name, :metric_name, :metric_namespace, :pattern - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: %i{filter_name log_group_name pattern} - ) - if validated_params.empty? - raise ArgumentError, "You must provide either filter_name, log_group, or pattern to aws_cloudwatch_log_metric_filter." - end - - validated_params - end - - def fetch_from_api - # get a backend - backend = BackendFactory.create(inspec_runner) - - # Perform query with remote filtering - aws_search_criteria = {} - aws_search_criteria[:filter_name] = filter_name if filter_name - aws_search_criteria[:log_group_name] = log_group_name if log_group_name - begin - aws_results = backend.describe_metric_filters(aws_search_criteria) - rescue Aws::CloudWatchLogs::Errors::ResourceNotFoundException - @exists = false - return - end - - # Then perform local filtering - if pattern - aws_results.select! { |lmf| lmf.filter_pattern == pattern } - end - - # Check result count. We're a singular resource and can tolerate - # 0 or 1 results, not multiple. - if aws_results.count > 1 - raise "More than one result was returned, but aws_cloudwatch_log_metric_filter "\ - "can only handle a single AWS resource. Consider passing more resource "\ - "parameters to narrow down the search." - elsif aws_results.empty? - @exists = false - else - @exists = true - # Unpack the funny-shaped object we got back from AWS into our instance vars - lmf = aws_results.first - @filter_name = lmf.filter_name - @log_group_name = lmf.log_group_name - @pattern = lmf.filter_pattern # Note inconsistent name - # AWS SDK returns an array of metric transformations - # but only allows one (mandatory) entry, let's flatten that - @metric_name = lmf.metric_transformations.first.metric_name - @metric_namespace = lmf.metric_transformations.first.metric_namespace - end - end - - class Backend - # Uses the cloudwatch API to really talk to AWS - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::CloudWatchLogs::Client - - def describe_metric_filters(criteria) - query = {} - query[:filter_name_prefix] = criteria[:filter_name] if criteria[:filter_name] - query[:log_group_name] = criteria[:log_group_name] if criteria[:log_group_name] - # 'pattern' is not available as a remote filter, - # we filter it after the fact locally - # TODO: handle pagination? Max 50/page. Maybe you want a plural resource? - aws_response = aws_service_client.describe_metric_filters(query) - aws_response.metric_filters - end - end - end -end diff --git a/lib/resources/aws/aws_config_delivery_channel.rb b/lib/resources/aws/aws_config_delivery_channel.rb deleted file mode 100644 index 6d9bec255..000000000 --- a/lib/resources/aws/aws_config_delivery_channel.rb +++ /dev/null @@ -1,74 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-configservice" - -class AwsConfigDeliveryChannel < Inspec.resource(1) - name "aws_config_delivery_channel" - desc "Verifies settings for AWS Config Delivery Channel" - example <<~EXAMPLE - describe aws_config_delivery_channel do - it { should exist } - its('s3_bucket_name') { should eq 'my_bucket' } - its('sns_topic_arn') { should eq arn:aws:sns:us-east-1:721741954427:sns_topic' } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :channel_name, :s3_bucket_name, :s3_key_prefix, :sns_topic_arn, - :delivery_frequency_in_hours - - def to_s - "Config_Delivery_Channel: #{@channel_name}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:channel_name], - allowed_scalar_name: :channel_name, - allowed_scalar_type: String - ) - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - query = @channel_name ? { delivery_channel_names: [@channel_name] } : {} - response = backend.describe_delivery_channels(query) - - @exists = !response.delivery_channels.empty? - return unless exists? - - channel = response.delivery_channels.first.to_h - @channel_name = channel[:name] - @s3_bucket_name = channel[:s3_bucket_name] - @s3_key_prefix = channel[:s3_key_prefix] - @sns_topic_arn = channel[:sns_topic_arn] - @delivery_frequency_in_hours = channel.dig(:config_snapshot_delivery_properties, :delivery_frequency) - frequencies = { - "One_Hour" => 1, - "TwentyFour_Hours" => 24, - "Three_Hours" => 3, - "Six_Hours" => 6, - "Twelve_Hours" => 12, - } - @delivery_frequency_in_hours = frequencies[@delivery_frequency_in_hours] - rescue Aws::ConfigService::Errors::NoSuchDeliveryChannelException - @exists = false - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::ConfigService::Client - - def describe_delivery_channels(query = {}) - aws_service_client.describe_delivery_channels(query) - end - end - end -end diff --git a/lib/resources/aws/aws_config_recorder.rb b/lib/resources/aws/aws_config_recorder.rb deleted file mode 100644 index 19294256c..000000000 --- a/lib/resources/aws/aws_config_recorder.rb +++ /dev/null @@ -1,99 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-configservice" - -class AwsConfigurationRecorder < Inspec.resource(1) - name "aws_config_recorder" - desc "Verifies settings for AWS Configuration Recorder" - example <<~EXAMPLE - describe aws_config_recorder('My_Recorder') do - it { should exist } - it { should be_recording } - it { should be_all_supported } - it { should have_include_global_resource_types } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :role_arn, :resource_types, :recorder_name - - def to_s - "Configuration_Recorder: #{@recorder_name}" - end - - def recording_all_resource_types? - @recording_all_resource_types - end - - def recording_all_global_types? - @recording_all_global_types - end - - def status - return {} unless @exists - - backend = BackendFactory.create(inspec_runner) - catch_aws_errors do - response = backend.describe_configuration_recorder_status(configuration_recorder_names: [@recorder_name]) - @status = response.configuration_recorders_status.first.to_h - end - end - - def recording? - return unless @exists - - status[:recording] - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:recorder_name], - allowed_scalar_name: :recorder_name, - allowed_scalar_type: String - ) - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - query = @recorder_name ? { configuration_recorder_names: [@recorder_name] } : {} - response = backend.describe_configuration_recorders(query) - - @exists = !response.configuration_recorders.empty? - return unless exists? - - if response.configuration_recorders.count > 1 - raise ArgumentError, "Internal error: unexpectedly received multiple AWS Config Recorder objects from API; expected to be singleton per-region. Please file a bug report at https://github.com/chef/inspec/issues ." - end - - recorder = response.configuration_recorders.first.to_h - @recorder_name = recorder[:name] - @role_arn = recorder[:role_arn] - @recording_all_resource_types = recorder[:recording_group][:all_supported] - @recording_all_global_types = recorder[:recording_group][:include_global_resource_types] - @resource_types = recorder[:recording_group][:resource_types] - rescue Aws::ConfigService::Errors::NoSuchConfigurationRecorderException - @exists = false - nil - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::ConfigService::Client - - def describe_configuration_recorders(query) - aws_service_client.describe_configuration_recorders(query) - end - - def describe_configuration_recorder_status(query) - aws_service_client.describe_configuration_recorder_status(query) - end - end - end -end diff --git a/lib/resources/aws/aws_ebs_volume.rb b/lib/resources/aws/aws_ebs_volume.rb deleted file mode 100644 index 8416b865e..000000000 --- a/lib/resources/aws/aws_ebs_volume.rb +++ /dev/null @@ -1,127 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsEbsVolume < Inspec.resource(1) - name "aws_ebs_volume" - desc "Verifies settings for an EBS volume" - - example <<~EXAMPLE - describe aws_ebs_volume('vol-123456') do - it { should be_encrypted } - its('size') { should cmp 8 } - end - - describe aws_ebs_volume(name: 'my-volume') do - its('encrypted') { should eq true } - its('iops') { should cmp 100 } - end - EXAMPLE - supports platform: "aws" - - # TODO: rewrite to avoid direct injection, match other resources, use AwsSingularResourceMixin - def initialize(opts, conn = nil) - @opts = opts - @display_name = opts.is_a?(Hash) ? @opts[:name] : opts - @ec2_client = conn ? conn.ec2_client : inspec_runner.backend.aws_client(Aws::EC2::Client) - @ec2_resource = conn ? conn.ec2_resource : inspec_runner.backend.aws_resource(Aws::EC2::Resource, {}) - end - - # TODO: DRY up, see https://github.com/chef/inspec/issues/2633 - # Copied from resource_support/aws/aws_resource_mixin.rb - def catch_aws_errors - yield - rescue Aws::Errors::MissingCredentialsError - # The AWS error here is unhelpful: - # "unable to sign request without credentials set" - Inspec::Log.error "It appears that you have not set your AWS credentials. You may set them using environment variables, or using the 'aws://region/aws_credentials_profile' target. See https://docs.chef.io/inspec/platforms/ for details." - fail_resource("No AWS credentials available") - rescue Aws::Errors::ServiceError => e - fail_resource(e.message) - end - - # TODO: DRY up, see https://github.com/chef/inspec/issues/2633 - # Copied from resource_support/aws/aws_singular_resource_mixin.rb - def inspec_runner - # When running under inspec-cli, we have an 'inspec' method that - # returns the runner. When running under unit tests, we don't - # have that, but we still have to call this to pass something - # (nil is OK) to the backend. - # TODO: remove with https://github.com/chef/inspec-aws/issues/216 - # TODO: remove after rewrite to include AwsSingularResource - inspec if respond_to?(:inspec) - end - - def id - return @volume_id if defined?(@volume_id) - - catch_aws_errors do - if @opts.is_a?(Hash) - first = @ec2_resource.volumes( - { - filters: [{ - name: "tag:Name", - values: [@opts[:name]], - }], - } - ).first - # catch case where the volume is not known - @volume_id = first.id unless first.nil? - else - @volume_id = @opts - end - end - end - alias volume_id id - - def exists? - !volume.nil? - end - - def encrypted? - volume.encrypted - end - - # attributes that we want to expose - %w{ - availability_zone encrypted iops kms_key_id size snapshot_id state volume_type - }.each do |attribute| - define_method attribute do - catch_aws_errors do - volume.send(attribute) if volume - end - end - end - - # Don't document this - it's a bit hard to use. Our current doctrine - # is to use dumb things, like arrays of strings - use security_group_ids instead. - def security_groups - catch_aws_errors do - @security_groups ||= volume.security_groups.map do |sg| - { id: sg.group_id, name: sg.group_name } - end - end - end - - def security_group_ids - catch_aws_errors do - @security_group_ids ||= volume.security_groups.map(&:group_id) - end - end - - def tags - catch_aws_errors do - @tags ||= volume.tags.map { |tag| { key: tag.key, value: tag.value } } - end - end - - def to_s - "EBS Volume #{@display_name}" - end - - private - - def volume - catch_aws_errors { @volume ||= @ec2_resource.volume(id) } - end -end diff --git a/lib/resources/aws/aws_ebs_volumes.rb b/lib/resources/aws/aws_ebs_volumes.rb deleted file mode 100644 index 75a3373c6..000000000 --- a/lib/resources/aws/aws_ebs_volumes.rb +++ /dev/null @@ -1,69 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsEbsVolumes < Inspec.resource(1) - name "aws_ebs_volumes" - desc "Verifies settings for AWS EBS Volumes in bulk" - example <<~EXAMPLE - describe aws_ebs_volumes do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_ebs_volumes does not accept resource parameters." - end - - resource_params - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:volume_ids, field: :volume_id) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "EBS Volumes" - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = [] - pagination_opts = {} - loop do - api_result = backend.describe_volumes(pagination_opts) - @table += unpack_describe_volumes_response(api_result.volumes) - break unless api_result.next_token - - pagination_opts = { next_token: api_result.next_token } - end - end - - def unpack_describe_volumes_response(volumes) - volume_rows = [] - volumes.each do |res| - volume_rows += res.attachments.map do |volume_struct| - { - volume_id: volume_struct.volume_id, - } - end - end - volume_rows - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::EC2::Client - - def describe_volumes(query) - aws_service_client.describe_volumes(query) - end - end - end -end diff --git a/lib/resources/aws/aws_ec2_instance.rb b/lib/resources/aws/aws_ec2_instance.rb deleted file mode 100644 index 4d67cfdb2..000000000 --- a/lib/resources/aws/aws_ec2_instance.rb +++ /dev/null @@ -1,162 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsEc2Instance < Inspec.resource(1) - name "aws_ec2_instance" - desc "Verifies settings for an EC2 instance" - - example <<~EXAMPLE - describe aws_ec2_instance('i-123456') do - it { should be_running } - it { should have_roles } - end - - describe aws_ec2_instance(name: 'my-instance') do - it { should be_running } - it { should have_roles } - end - EXAMPLE - supports platform: "aws" - - # TODO: rewrite to avoid direct injection, match other resources, use AwsSingularResourceMixin - def initialize(opts, conn = nil) - @opts = opts - @opts.is_a?(Hash) ? @display_name = @opts[:name] : @display_name = opts - @ec2_client = conn ? conn.ec2_client : inspec_runner.backend.aws_client(Aws::EC2::Client) - @ec2_resource = conn ? conn.ec2_resource : inspec_runner.backend.aws_resource(Aws::EC2::Resource, {}) - @iam_resource = conn ? conn.iam_resource : inspec_runner.backend.aws_resource(Aws::IAM::Resource, {}) - end - - # TODO: DRY up, see https://github.com/chef/inspec/issues/2633 - # Copied from resource_support/aws/aws_resource_mixin.rb - def catch_aws_errors - yield - rescue Aws::Errors::MissingCredentialsError - # The AWS error here is unhelpful: - # "unable to sign request without credentials set" - Inspec::Log.error "It appears that you have not set your AWS credentials. You may set them using environment variables, or using the 'aws://region/aws_credentials_profile' target. See https://docs.chef.io/inspec/platforms/ for details." - fail_resource("No AWS credentials available") - rescue Aws::Errors::ServiceError => e - fail_resource e.message - end - - # TODO: DRY up, see https://github.com/chef/inspec/issues/2633 - # Copied from resource_support/aws/aws_singular_resource_mixin.rb - def inspec_runner - # When running under inspec-cli, we have an 'inspec' method that - # returns the runner. When running under unit tests, we don't - # have that, but we still have to call this to pass something - # (nil is OK) to the backend. - # TODO: remove with https://github.com/chef/inspec-aws/issues/216 - # TODO: remove after rewrite to include AwsSingularResource - inspec if respond_to?(:inspec) - end - - def id - return @instance_id if defined?(@instance_id) - - catch_aws_errors do - if @opts.is_a?(Hash) - first = @ec2_resource.instances( - { - filters: [{ - name: "tag:Name", - values: [@opts[:name]], - }], - } - ).first - # catch case where the instance is not known - @instance_id = first.id unless first.nil? - else - @instance_id = @opts - end - end - end - alias instance_id id - - def exists? - return false if instance.nil? - - instance.exists? - end - - # returns the instance state - def state - catch_aws_errors do - instance&.state&.name - end - end - - # helper methods for each state - %w{ - pending running shutting-down - terminated stopping stopped unknown - }.each do |state_name| - define_method state_name.tr("-", "_") + "?" do - state == state_name - end - end - - # attributes that we want to expose - %w{ - public_ip_address private_ip_address key_name private_dns_name - public_dns_name subnet_id architecture root_device_type - root_device_name virtualization_type client_token launch_time - instance_type image_id vpc_id - }.each do |attribute| - define_method attribute do - catch_aws_errors do - instance.send(attribute) if instance - end - end - end - - # Don't document this - it's a bit hard to use. Our current doctrine - # is to use dumb things, like arrays of strings - use security_group_ids instead. - def security_groups - catch_aws_errors do - @security_groups ||= instance.security_groups.map do |sg| - { id: sg.group_id, name: sg.group_name } - end - end - end - - def security_group_ids - catch_aws_errors do - @security_group_ids ||= instance.security_groups.map(&:group_id) - end - end - - def tags - catch_aws_errors do - @tags ||= instance.tags.map { |tag| { key: tag.key, value: tag.value } } - end - end - - def to_s - "EC2 Instance #{@display_name}" - end - - def has_roles? - catch_aws_errors do - instance_profile = instance.iam_instance_profile - - if instance_profile - roles = @iam_resource.instance_profile( - instance_profile.arn.gsub(%r{^.*\/}, "") - ).roles - else - roles = nil - end - - roles && !roles.empty? - end - end - - private - - def instance - catch_aws_errors { @instance ||= @ec2_resource.instance(id) } - end -end diff --git a/lib/resources/aws/aws_ec2_instances.rb b/lib/resources/aws/aws_ec2_instances.rb deleted file mode 100644 index 77361a422..000000000 --- a/lib/resources/aws/aws_ec2_instances.rb +++ /dev/null @@ -1,69 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsEc2Instances < Inspec.resource(1) - name "aws_ec2_instances" - desc "Verifies settings for AWS EC2 Instances in bulk" - example <<~EXAMPLE - describe aws_ec2_instances do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_ec2_instances does not accept resource parameters." - end - - resource_params - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:instance_ids, field: :instance_id) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "EC2 Instances" - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = [] - pagination_opts = {} - loop do - api_result = backend.describe_instances(pagination_opts) - @table += unpack_describe_instances_response(api_result.reservations) - break unless api_result.next_token - - pagination_opts = { next_token: api_result.next_token } - end - end - - def unpack_describe_instances_response(reservations) - instance_rows = [] - reservations.each do |res| - instance_rows += res.instances.map do |instance_struct| - { - instance_id: instance_struct.instance_id, - } - end - end - instance_rows - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::EC2::Client - - def describe_instances(query) - aws_service_client.describe_instances(query) - end - end - end -end diff --git a/lib/resources/aws/aws_ecs_cluster.rb b/lib/resources/aws/aws_ecs_cluster.rb deleted file mode 100644 index 5aa0fa023..000000000 --- a/lib/resources/aws/aws_ecs_cluster.rb +++ /dev/null @@ -1,87 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ecs" - -class AwsEcsCluster < Inspec.resource(1) - name "aws_ecs_cluster" - desc "Verifies settings for an ECS cluster" - - example <<~EXAMPLE - describe aws_ecs_cluster('default') do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :cluster_arn, :cluster_name, :status, - :registered_container_instances_count, :running_tasks_count, - :pending_tasks_count, :active_services_count, :statistics - - def to_s - "AWS ECS cluster #{cluster_name}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:cluster_name], - allowed_scalar_name: :cluster_name, - allowed_scalar_type: String - ) - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - # Use default cluster if no cluster name is specified - params = cluster_name.nil? ? {} : { clusters: [cluster_name] } - clusters = backend.describe_clusters(params).clusters - - # Cluster name is unique, we either get back one cluster, or none - if clusters.length == 1 - @exists = true - unpack_describe_clusters_response(clusters.first) - else - @exists = false - populate_as_missing - end - end - - def unpack_describe_clusters_response(cluster_struct) - @cluster_arn = cluster_struct.cluster_arn - @cluster_name = cluster_struct.cluster_name - @status = cluster_struct.status - @registered_container_instances_count = cluster_struct.registered_container_instances_count - @running_tasks_count = cluster_struct.running_tasks_count - @pending_tasks_count = cluster_struct.pending_tasks_count - @active_services_count = cluster_struct.active_services_count - @statistics = cluster_struct.statistics - end - - def populate_as_missing - @cluster_arn = "" - @cluster_name = "" - @status = "" - @registered_container_instances_count = 0 - @running_tasks_count = 0 - @pending_tasks_count = 0 - @active_services_count = 0 - @statistics = [] - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::ECS::Client - - def describe_clusters(query = {}) - aws_service_client.describe_clusters(query) - end - end - end -end diff --git a/lib/resources/aws/aws_eks_cluster.rb b/lib/resources/aws/aws_eks_cluster.rb deleted file mode 100644 index edbd5d720..000000000 --- a/lib/resources/aws/aws_eks_cluster.rb +++ /dev/null @@ -1,105 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-eks" - -class AwsEksCluster < Inspec.resource(1) - name "aws_eks_cluster" - desc "Verifies settings for an EKS cluster" - - example <<~EXAMPLE - describe aws_eks_cluster('default') do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :version, :arn, :cluster_name, :certificate_authority, :name, - :status, :endpoint, :subnets_count, :subnet_ids, :security_group_ids, - :created_at, :role_arn, :vpc_id, :security_groups_count, :creating, - :active, :failed, :deleting - # Use aliases for matchers - alias active? active - alias failed? failed - alias creating? creating - alias deleting? deleting - - def to_s - "AWS EKS cluster #{cluster_name}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:cluster_name], - allowed_scalar_name: :cluster_name, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, "You must provide a cluster_name to aws_eks_cluster." - end - - validated_params - end - - def fetch_from_api # rubocop:disable Metrics/AbcSize - backend = BackendFactory.create(inspec_runner) - begin - params = { name: cluster_name } - resp = backend.describe_cluster(params) - rescue Aws::EKS::Errors::ResourceNotFoundException - @exists = false - populate_as_missing - return - end - @exists = true - cluster = resp.to_h[:cluster] - @version = cluster[:version] - @name = cluster[:name] - @arn = cluster[:arn] - @certificate_authority = cluster[:certificate_authority][:data] - @created_at = cluster[:created_at] - @endpoint = cluster[:endpoint] - @security_group_ids = cluster[:resources_vpc_config][:security_group_ids] - @subnet_ids = cluster[:resources_vpc_config][:subnet_ids] - @subnets_count = cluster[:resources_vpc_config][:subnet_ids].length - @security_groups_count = cluster[:resources_vpc_config][:security_group_ids].length - @vpc_id = cluster[:resources_vpc_config][:vpc_id] - @role_arn = cluster[:role_arn] - @status = cluster[:status] - @active = cluster[:status] == "ACTIVE" - @failed = cluster[:status] == "FAILED" - @creating = cluster[:status] == "CREATING" - @deleting = cluster[:status] == "DELETING" - end - - def populate_as_missing - @version = nil - @name = cluster_name # name is an alias for cluster_name, and it is retained on a miss - @arn = nil - @certificate_authority = nil - @created_at = nil - @endpoint = nil - @security_group_ids = [] - @subnet_ids = [] - @subnets_count = nil - @security_groups_count = nil - @vpc_id = nil - @role_arn = nil - @status = nil - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::EKS::Client - - def describe_cluster(query = {}) - aws_service_client.describe_cluster(query) - end - end - end -end diff --git a/lib/resources/aws/aws_elb.rb b/lib/resources/aws/aws_elb.rb deleted file mode 100644 index d73d4647b..000000000 --- a/lib/resources/aws/aws_elb.rb +++ /dev/null @@ -1,85 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-elasticloadbalancing" - -class AwsElb < Inspec.resource(1) - name "aws_elb" - desc "Verifies settings for AWS Elastic Load Balancer" - example <<~EXAMPLE - describe aws_elb('myelb') do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :availability_zones, :dns_name, :elb_name, :external_ports, - :instance_ids, :internal_ports, :security_group_ids, - :subnet_ids, :vpc_id - - def to_s - "AWS ELB #{elb_name}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:elb_name], - allowed_scalar_name: :elb_name, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, "You must provide a elb_name to aws_elb." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - begin - lbs = backend.describe_load_balancers(load_balancer_names: [elb_name]).load_balancer_descriptions - @exists = true - # Load balancer names are uniq; we will either have 0 or 1 result - unpack_describe_elbs_response(lbs.first) - rescue Aws::ElasticLoadBalancing::Errors::LoadBalancerNotFound - @exists = false - populate_as_missing - end - end - - def unpack_describe_elbs_response(lb_struct) - @availability_zones = lb_struct.availability_zones - @dns_name = lb_struct.dns_name - @external_ports = lb_struct.listener_descriptions.map { |ld| ld.listener.load_balancer_port } - @instance_ids = lb_struct.instances.map(&:instance_id) - @internal_ports = lb_struct.listener_descriptions.map { |ld| ld.listener.instance_port } - @elb_name = lb_struct.load_balancer_name - @security_group_ids = lb_struct.security_groups - @subnet_ids = lb_struct.subnets - @vpc_id = lb_struct.vpc_id - end - - def populate_as_missing - @availability_zones = [] - @external_ports = [] - @instance_ids = [] - @internal_ports = [] - @security_group_ids = [] - @subnet_ids = [] - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::ElasticLoadBalancing::Client - - def describe_load_balancers(query = {}) - aws_service_client.describe_load_balancers(query) - end - end - end -end diff --git a/lib/resources/aws/aws_elbs.rb b/lib/resources/aws/aws_elbs.rb deleted file mode 100644 index 847ff7f13..000000000 --- a/lib/resources/aws/aws_elbs.rb +++ /dev/null @@ -1,84 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-elasticloadbalancing" - -class AwsElbs < Inspec.resource(1) - name "aws_elbs" - desc "Verifies settings for AWS ELBs (classic Elastic Load Balancers) in bulk" - example <<~EXAMPLE - describe aws_elbs do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_elbs does not accept resource parameters." - end - - resource_params - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.add_accessor(:entries) - .add_accessor(:where) - .add(:exists?) { |table| !table.params.empty? } - .add(:count) { |table| table.params.count } - .add(:availability_zones, field: :availability_zones, style: :simple) - .add(:dns_names, field: :dns_name) - .add(:external_ports, field: :external_ports, style: :simple) - .add(:instance_ids, field: :instance_ids, style: :simple) - .add(:internal_ports, field: :internal_ports, style: :simple) - .add(:elb_names, field: :elb_name) - .add(:security_group_ids, field: :security_group_ids, style: :simple) - .add(:subnet_ids, field: :subnet_ids, style: :simple) - .add(:vpc_ids, field: :vpc_id, style: :simple) - filter.connect(self, :table) - - def to_s - "AWS ELBs" - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = [] - pagination_opts = {} - loop do - api_result = backend.describe_load_balancers(pagination_opts) - @table += unpack_describe_elbs_response(api_result.load_balancer_descriptions) - break unless api_result.next_marker - - pagination_opts = { marker: api_result.next_marker } - end - end - - def unpack_describe_elbs_response(load_balancers) - load_balancers.map do |lb_struct| - { - availability_zones: lb_struct.availability_zones, - dns_name: lb_struct.dns_name, - external_ports: lb_struct.listener_descriptions.map { |ld| ld.listener.load_balancer_port }, - instance_ids: lb_struct.instances.map(&:instance_id), - internal_ports: lb_struct.listener_descriptions.map { |ld| ld.listener.instance_port }, - elb_name: lb_struct.load_balancer_name, - security_group_ids: lb_struct.security_groups, - subnet_ids: lb_struct.subnets, - vpc_id: lb_struct.vpc_id, - } - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::ElasticLoadBalancing::Client - - def describe_load_balancers(query = {}) - aws_service_client.describe_load_balancers(query) - end - end - end -end diff --git a/lib/resources/aws/aws_flow_log.rb b/lib/resources/aws/aws_flow_log.rb deleted file mode 100644 index c833ba970..000000000 --- a/lib/resources/aws/aws_flow_log.rb +++ /dev/null @@ -1,106 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsFlowLog < Inspec.resource(1) - name "aws_flow_log" - supports platform: "aws" - desc "This resource is used to test the attributes of a Flow Log." - example <<~EXAMPLE - describe aws_flow_log('fl-9c718cf5') do - it { should exist } - end - EXAMPLE - - include AwsSingularResourceMixin - - def to_s - "AWS Flow Log #{id}" - end - - def resource_type - case @resource_id - when /^eni/ - @resource_type = "eni" - when /^subnet/ - @resource_type = "subnet" - when /^vpc/ - @resource_type = "vpc" - end - end - - def attached_to_eni? - resource_type.eql?("eni") ? true : false - end - - def attached_to_subnet? - resource_type.eql?("subnet") ? true : false - end - - def attached_to_vpc? - resource_type.eql?("vpc") ? true : false - end - - attr_reader :log_group_name, :resource_id, :flow_log_id - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: %i{flow_log_id subnet_id vpc_id}, - allowed_scalar_name: :flow_log_id, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, - "aws_flow_log requires a parameter: flow_log_id, subnet_id, or vpc_id" - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - resp = backend.describe_flow_logs(filter_args) - flow_log = resp.to_h[:flow_logs].first - @exists = !flow_log.nil? - unless flow_log.nil? - @log_group_name = flow_log[:log_group_name] - @resource_id = flow_log[:resource_id] - @flow_log_id = flow_log[:flow_log_id] - end - end - - def filter_args - if @flow_log_id - { filter: [{ name: "flow-log-id", values: [@flow_log_id] }] } - elsif @subnet_id || @vpc_id - filter = @subnet_id || @vpc_id - { filter: [{ name: "resource-id", values: [filter] }] } - end - end - - def id - return @flow_log_id if @flow_log_id - return @subnet_id if @subnet_id - return @vpc_id if @vpc_id - end - - def backend - BackendFactory.create(inspec_runner) - end - - class Backend - class AwsClientApi < AwsBackendBase - AwsFlowLog::BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::EC2::Client - - def describe_flow_logs(query) - aws_service_client.describe_flow_logs(query) - end - end - end -end diff --git a/lib/resources/aws/aws_iam_access_key.rb b/lib/resources/aws/aws_iam_access_key.rb deleted file mode 100644 index 52e810208..000000000 --- a/lib/resources/aws/aws_iam_access_key.rb +++ /dev/null @@ -1,112 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamAccessKey < Inspec.resource(1) - name "aws_iam_access_key" - desc "Verifies settings for an individual IAM access key" - example <<~EXAMPLE - describe aws_iam_access_key(username: 'username', id: 'access-key id') do - it { should exist } - it { should_not be_active } - its('create_date') { should be > Time.now - 365 * 86400 } - its('last_used_date') { should be > Time.now - 90 * 86400 } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :access_key_id, :create_date, :status, :username - alias id access_key_id - - def validate_params(raw_params) - recognized_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: %i{username id access_key_id}, - allowed_scalar_name: :access_key_id, - allowed_scalar_type: String - ) - - # id and access_key_id are aliases; standardize on access_key_id - recognized_params[:access_key_id] = recognized_params.delete(:id) if recognized_params.key?(:id) - - # Validate format of access_key_id - if recognized_params[:access_key_id] && - recognized_params[:access_key_id] !~ (/^AKIA[0-9A-Z]{16}$/) - raise ArgumentError, "Incorrect format for Access Key ID - expected AKIA followed " \ - "by 16 letters or numbers" - end - - # One of username and access_key_id is required - if recognized_params[:username].nil? && recognized_params[:access_key_id].nil? - raise ArgumentError, "You must provide at lease one of access_key_id or username to aws_iam_access_key" - end - - recognized_params - end - - def active? - return nil unless exists? - - status == "Active" - end - - def to_s - "IAM Access-Key #{access_key_id}" - end - - def last_used_date - return nil unless exists? - return @last_used_date if defined? @last_used_date - - backend = BackendFactory.create(inspec_runner) - catch_aws_errors do - @last_used_date = backend.get_access_key_last_used({ access_key_id: access_key_id }).access_key_last_used.last_used_date - end - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - query = {} - query[:user_name] = username if username - - response = backend.list_access_keys(query) - - access_keys = response.access_key_metadata.select do |key| - if access_key_id - key.access_key_id == access_key_id - else - true - end - end - - if access_keys.empty? - @exists = false - return - end - - if access_keys.count > 1 - raise "More than one access key matched for aws_iam_access_key. Use more specific parameters, such as access_key_id." - end - - @exists = true - @access_key_id = access_keys[0].access_key_id - @username = access_keys[0].user_name - @create_date = access_keys[0].create_date - @status = access_keys[0].status - # Last used date is lazily loaded, separate API call - rescue Aws::IAM::Errors::NoSuchEntity - @exists = false - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - - def list_access_keys(query) - aws_service_client.list_access_keys(query) - end - end - end -end diff --git a/lib/resources/aws/aws_iam_access_keys.rb b/lib/resources/aws/aws_iam_access_keys.rb deleted file mode 100644 index 73743d0d5..000000000 --- a/lib/resources/aws/aws_iam_access_keys.rb +++ /dev/null @@ -1,153 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamAccessKeys < Inspec.resource(1) - name "aws_iam_access_keys" - desc "Verifies settings for AWS IAM Access Keys in bulk" - example <<~EXAMPLE - describe aws_iam_access_keys do - it { should_not exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - def validate_params(raw_params) - recognized_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: %i{username id access_key_id created_date}, - allowed_scalar_name: :access_key_id, - allowed_scalar_type: String - ) - - # id and access_key_id are aliases; standardize on access_key_id - recognized_params[:access_key_id] = recognized_params.delete(:id) if recognized_params.key?(:id) - if recognized_params[:access_key_id] && - recognized_params[:access_key_id] !~ (/^AKIA[0-9A-Z]{16}$/) - raise "Incorrect format for Access Key ID - expected AKIA followed " \ - "by 16 letters or numbers" - end - - recognized_params - end - - def fetch_from_api - # TODO: this interface should be normalized to match the AWS API - criteria = {} - criteria[:username] = @username if defined? @username - @table = BackendFactory.create(inspec_runner).fetch(criteria) - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:access_key_ids, field: :access_key_id) - .register_column(:created_date, field: :create_date) - .register_column(:created_days_ago, field: :created_days_ago) - .register_column(:created_with_user, field: :created_with_user) - .register_column(:created_hours_ago, field: :created_hours_ago) - .register_column(:usernames, field: :username) - .register_column(:active, field: :active) - .register_column(:inactive, field: :inactive) - .register_column(:last_used_date, field: :last_used_date) - .register_column(:last_used_hours_ago, field: :last_used_hours_ago) - .register_column(:last_used_days_ago, field: :last_used_days_ago) - .register_column(:ever_used, field: :ever_used) - .register_column(:never_used, field: :never_used) - .register_column(:user_created_date, field: :user_created_date) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "IAM Access Keys" - end - - # Internal support class. This is used to fetch - # the users and access keys. We have an abstract - # class with a concrete AWS implementation provided here; - # a few mock implementations are also provided in the unit tests. - class Backend - # Implementation of AccessKeyProvider which operates by looping over - # all users, then fetching their access keys. - # TODO: An alternate, more scalable implementation could be made - # using the Credential Report. - class AwsUserIterator < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - - def fetch(criteria) - iam_client = aws_service_client - - user_details = {} - if criteria.key?(:username) - begin - user_details[criteria[:username]] = iam_client.get_user(user_name: criteria[:username]).user - rescue Aws::IAM::Errors::NoSuchEntity # rubocop:disable Lint/HandleExceptions - # Swallow - a miss on search results should return an empty table - end - else - pagination_opts = {} - loop do - api_result = iam_client.list_users(pagination_opts) - api_result.users.each do |info| - user_details[info.user_name] = info - end - break unless api_result.is_truncated - - pagination_opts[:marker] = api_result.marker - end - end - - access_key_data = [] - user_details.each_key do |username| - - user_keys = iam_client.list_access_keys(user_name: username) - .access_key_metadata - user_keys = user_keys.map do |metadata| - { - access_key_id: metadata.access_key_id, - username: username, - status: metadata.status, - create_date: metadata.create_date, # DateTime.parse(metadata.create_date), - } - end - - # Copy in from user data - # Synthetics - user_keys.each do |key_info| - add_synthetic_fields(key_info, user_details[username]) - end - access_key_data.concat(user_keys) - rescue Aws::IAM::Errors::NoSuchEntity # rubocop:disable Lint/HandleExceptions - # Swallow - a miss on search results should return an empty table - - end - access_key_data - end - - def add_synthetic_fields(key_info, user_details) # rubocop:disable Metrics/AbcSize - key_info[:id] = key_info[:access_key_id] - key_info[:active] = key_info[:status] == "Active" - key_info[:inactive] = key_info[:status] != "Active" - key_info[:created_hours_ago] = ((Time.now - key_info[:create_date]) / (60 * 60)).to_i - key_info[:created_days_ago] = (key_info[:created_hours_ago] / 24).to_i - key_info[:user_created_date] = user_details[:create_date] - key_info[:created_with_user] = (key_info[:create_date] - key_info[:user_created_date]).abs < 1.0 / 24.0 - - # Last used is a separate API call - iam_client = aws_service_client - last_used = - iam_client.get_access_key_last_used(access_key_id: key_info[:access_key_id]) - .access_key_last_used.last_used_date - key_info[:ever_used] = !last_used.nil? - key_info[:never_used] = last_used.nil? - key_info[:last_used_time] = last_used - return unless last_used - - key_info[:last_used_hours_ago] = ((Time.now - last_used) / (60 * 60)).to_i - key_info[:last_used_days_ago] = (key_info[:last_used_hours_ago] / 24).to_i - end - end - end -end diff --git a/lib/resources/aws/aws_iam_group.rb b/lib/resources/aws/aws_iam_group.rb deleted file mode 100644 index 363229ab0..000000000 --- a/lib/resources/aws/aws_iam_group.rb +++ /dev/null @@ -1,62 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamGroup < Inspec.resource(1) - name "aws_iam_group" - desc "Verifies settings for AWS IAM Group" - example <<~EXAMPLE - describe aws_iam_group('mygroup') do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :group_name, :users - - def to_s - "IAM Group #{group_name}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:group_name], - allowed_scalar_name: :group_name, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, "You must provide a group_name to aws_iam_group." - end - - validated_params - end - - def fetch_from_api - backend = AwsIamGroup::BackendFactory.create(inspec_runner) - - begin - resp = backend.get_group(group_name: group_name) - @exists = true - @aws_group_struct = resp[:group] - @users = resp[:users].map(&:user_name) - rescue Aws::IAM::Errors::NoSuchEntity - @exists = false - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - - def get_group(query) - aws_service_client.get_group(query) - end - end - end -end diff --git a/lib/resources/aws/aws_iam_groups.rb b/lib/resources/aws/aws_iam_groups.rb deleted file mode 100644 index 93b8444a6..000000000 --- a/lib/resources/aws/aws_iam_groups.rb +++ /dev/null @@ -1,56 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamGroups < Inspec.resource(1) - name "aws_iam_groups" - desc "Verifies settings for AWS IAM groups in bulk" - example <<~EXAMPLE - describe aws_iam_groups do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_iam_groups does not accept resource parameters." - end - - resource_params - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_column(:group_names, field: :group_name) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "IAM Groups" - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = [] - pagination_opts = {} - loop do - api_result = backend.list_groups(pagination_opts) - @table += api_result.groups.map(&:to_h) - pagination_opts = { marker: api_result.marker } - break unless api_result.is_truncated - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - - def list_groups(query = {}) - aws_service_client.list_groups(query) - end - end - end -end diff --git a/lib/resources/aws/aws_iam_password_policy.rb b/lib/resources/aws/aws_iam_password_policy.rb deleted file mode 100644 index 55a912996..000000000 --- a/lib/resources/aws/aws_iam_password_policy.rb +++ /dev/null @@ -1,121 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamPasswordPolicy < Inspec.resource(1) - name "aws_iam_password_policy" - desc "Verifies iam password policy" - - example <<~EXAMPLE - describe aws_iam_password_policy do - its('requires_lowercase_characters?') { should be true } - end - - describe aws_iam_password_policy do - its('requires_uppercase_characters?') { should be true } - end - EXAMPLE - supports platform: "aws" - - # TODO: rewrite to avoid direct injection, match other resources, use AwsSingularResourceMixin - def initialize(conn = nil) - catch_aws_errors do - - if conn - # We're in a mocked unit test. - @policy = conn.iam_resource.account_password_policy - else - # Don't use the resource approach. It's a CRUD operation - # - if the policy does not exist, you get back a blank object to populate and save. - # Using the Client will throw an exception if no policy exists. - @policy = inspec_runner.backend.aws_client(Aws::IAM::Client).get_account_password_policy.password_policy - end - rescue Aws::IAM::Errors::NoSuchEntity - @policy = nil - - end - end - - # TODO: DRY up, see https://github.com/chef/inspec/issues/2633 - # Copied from resource_support/aws/aws_resource_mixin.rb - def catch_aws_errors - yield - rescue Aws::Errors::MissingCredentialsError - # The AWS error here is unhelpful: - # "unable to sign request without credentials set" - Inspec::Log.error "It appears that you have not set your AWS credentials. You may set them using environment variables, or using the 'aws://region/aws_credentials_profile' target. See https://docs.chef.io/inspec/platforms/ for details." - fail_resource("No AWS credentials available") - rescue Aws::Errors::ServiceError => e - fail_resource e.message - end - - # TODO: DRY up, see https://github.com/chef/inspec/issues/2633 - # Copied from resource_support/aws/aws_singular_resource_mixin.rb - def inspec_runner - # When running under inspec-cli, we have an 'inspec' method that - # returns the runner. When running under unit tests, we don't - # have that, but we still have to call this to pass something - # (nil is OK) to the backend. - # TODO: remove with https://github.com/chef/inspec-aws/issues/216 - # TODO: remove after rewrite to include AwsSingularResource - inspec if respond_to?(:inspec) - end - - def to_s - "IAM Password-Policy" - end - - def exists? - !@policy.nil? - end - - #-------------------------- Properties ----------------------------# - - def minimum_password_length - @policy.minimum_password_length - end - - def max_password_age_in_days - raise "this policy does not expire passwords" unless expire_passwords? - - @policy.max_password_age - end - - def number_of_passwords_to_remember - raise "this policy does not prevent password reuse" \ - unless prevent_password_reuse? - - @policy.password_reuse_prevention - end - - #-------------------------- Matchers ----------------------------# - %i{ - require_lowercase_characters - require_uppercase_characters - require_symbols - require_numbers - expire_passwords - }.each do |matcher_stem| - # Create our predicates (for example, 'require_symbols?') - stem_with_question_mark = (matcher_stem.to_s + "?").to_sym - define_method stem_with_question_mark do - @policy.send(matcher_stem) - end - # RSpec will expose that as (for example) `be_require_symbols`. - # To undo that, we have to make a matcher alias. - stem_with_be = ("be_" + matcher_stem.to_s).to_sym - RSpec::Matchers.alias_matcher matcher_stem, stem_with_be - end - - # This one has an awkward name mapping - def allow_users_to_change_passwords? - @policy.allow_users_to_change_password - end - RSpec::Matchers.alias_matcher :allow_users_to_change_passwords, :be_allow_users_to_change_passwords - - # This one has custom logic and renaming - def prevent_password_reuse? - !@policy.password_reuse_prevention.nil? - end - RSpec::Matchers.alias_matcher :prevent_password_reuse, :be_prevent_password_reuse -end diff --git a/lib/resources/aws/aws_iam_policies.rb b/lib/resources/aws/aws_iam_policies.rb deleted file mode 100644 index f5a3ea5fc..000000000 --- a/lib/resources/aws/aws_iam_policies.rb +++ /dev/null @@ -1,57 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamPolicies < Inspec.resource(1) - name "aws_iam_policies" - desc "Verifies settings for AWS IAM Policies in bulk" - example <<~EXAMPLE - describe aws_iam_policies do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_iam_policies does not accept resource parameters." - end - - resource_params - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:policy_names, field: :policy_name) - .register_column(:arns, field: :arn) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "IAM Policies" - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = [] - pagination_opts = {} - loop do - api_result = backend.list_policies(pagination_opts) - @table += api_result.policies.map(&:to_h) - pagination_opts = { marker: api_result.marker } - break unless api_result.is_truncated - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - - def list_policies(query) - aws_service_client.list_policies(query) - end - end - end -end diff --git a/lib/resources/aws/aws_iam_policy.rb b/lib/resources/aws/aws_iam_policy.rb deleted file mode 100644 index d8b498eb8..000000000 --- a/lib/resources/aws/aws_iam_policy.rb +++ /dev/null @@ -1,311 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -require "json" unless defined?(JSON) -require "set" unless defined?(Set) -require "uri" unless defined?(URI) - -class AwsIamPolicy < Inspec.resource(1) - name "aws_iam_policy" - desc "Verifies settings for individual AWS IAM Policy" - example <<~EXAMPLE - describe aws_iam_policy('AWSSupportAccess') do - it { should be_attached } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - - attr_reader :arn, :attachment_count, :default_version_id - - # Note that we also accept downcases and symbol versions of these - EXPECTED_CRITERIA = %w{ - Action - Effect - Resource - Sid - }.freeze - - UNIMPLEMENTED_CRITERIA = %w{ - Conditional - NotAction - NotPrincipal - NotResource - Principal - }.freeze - - def to_s - "Policy #{@policy_name}" - end - - def attached? - attachment_count > 0 - end - - def attached_users - return @attached_users if defined? @attached_users - - fetch_attached_entities - @attached_users - end - - def attached_groups - return @attached_groups if defined? @attached_groups - - fetch_attached_entities - @attached_groups - end - - def attached_roles - return @attached_roles if defined? @attached_roles - - fetch_attached_entities - @attached_roles - end - - def attached_to_user?(user_name) - attached_users.include?(user_name) - end - - def attached_to_group?(group_name) - attached_groups.include?(group_name) - end - - def attached_to_role?(role_name) - attached_roles.include?(role_name) - end - - def policy - return nil unless exists? - return @policy if defined?(@policy) - - catch_aws_errors do - backend = BackendFactory.create(inspec_runner) - gpv_response = backend.get_policy_version(policy_arn: arn, version_id: default_version_id) - @policy = JSON.parse(URI.decode_www_form_component(gpv_response.policy_version.document)) - end - @policy - end - - def statement_count - return nil unless exists? - - # Typically it is an array of statements - if policy["Statement"].is_a? Array - policy["Statement"].count - else - # But if there is one statement, it is permissable to degenerate the array, - # and place the statement as a hash directly under the 'Statement' key - 1 - end - end - - def has_statement?(provided_criteria = {}) - return nil unless exists? - - raw_criteria = provided_criteria.dup # provided_criteria is used for output formatting - can't delete from it. - criteria = has_statement__validate_criteria(raw_criteria) - @normalized_statements ||= has_statement__normalize_statements - statements = has_statement__focus_on_sid(@normalized_statements, criteria) - statements.any? do |statement| - true && \ - has_statement__effect(statement, criteria) && \ - has_statement__array_criterion(:action, statement, criteria) && \ - has_statement__array_criterion(:resource, statement, criteria) - end - end - - private - - def has_statement__validate_criteria(raw_criteria) - recognized_criteria = {} - EXPECTED_CRITERIA.each do |expected_criterion| - [ - expected_criterion, - expected_criterion.downcase, - expected_criterion.to_sym, - expected_criterion.downcase.to_sym, - ].each do |variant| - if raw_criteria.key?(variant) - # Always store as downcased symbol - recognized_criteria[expected_criterion.downcase.to_sym] = raw_criteria.delete(variant) - end - end - end - - # Special message for valid, but unimplemented statement attributes - UNIMPLEMENTED_CRITERIA.each do |unimplemented_criterion| - [ - unimplemented_criterion, - unimplemented_criterion.downcase, - unimplemented_criterion.to_sym, - unimplemented_criterion.downcase.to_sym, - ].each do |variant| - if raw_criteria.key?(variant) - raise ArgumentError, "Criterion '#{unimplemented_criterion}' is not supported for performing have_statement queries." - end - end - end - - # If anything is left, it's spurious - unless raw_criteria.empty? - raise ArgumentError, "Unrecognized criteria #{raw_criteria.keys.join(", ")} to have_statement. Recognized criteria: #{EXPECTED_CRITERIA.join(", ")}" - end - - # Effect has only 2 permitted values - if recognized_criteria.key?(:effect) - unless %w{Allow Deny}.include?(recognized_criteria[:effect]) - raise ArgumentError, "Criterion 'Effect' for have_statement must be one of 'Allow' or 'Deny' - got '#{recognized_criteria[:effect]}'" - end - end - - recognized_criteria - end - - def has_statement__normalize_statements - # Some single-statement policies place their statement - # directly in policy['Statement'], rather than in an - # Array within it. See arn:aws:iam::aws:policy/AWSCertificateManagerReadOnly - # Thus, coerce to Array. - policy["Statement"] = [policy["Statement"]] if policy["Statement"].is_a? Hash - policy["Statement"].map do |statement| - # Coerce some values into arrays - %w{Action Resource}.each do |field| - if statement.key?(field) - statement[field] = Array(statement[field]) - end - end - - # Symbolize all keys - statement.keys.each do |field| - statement[field.downcase.to_sym] = statement.delete(field) - end - - statement - end - end - - def has_statement__focus_on_sid(statements, criteria) - return statements unless criteria.key?(:sid) - - sid_seek = criteria[:sid] - statements.select do |statement| - if sid_seek.is_a? Regexp - statement[:sid] =~ sid_seek - else - statement[:sid] == sid_seek - end - end - end - - def has_statement__effect(statement, criteria) - !criteria.key?(:effect) || criteria[:effect] == statement[:effect] - end - - def has_statement__array_criterion(crit_name, statement, criteria) - return true unless criteria.key?(crit_name) - - check = criteria[crit_name] - # This is an array due to normalize_statements - # If it is nil, the statement does not have an entry for that dimension; - # but since we were asked to match on it (on nothing), we - # decide to never match - values = statement[crit_name] - return false if values.nil? - - if check.is_a?(String) - # If check is a string, it only has to match one of the values - values.any? { |v| v == check } - elsif check.is_a?(Regexp) - # If check is a regex, it only has to match one of the values - values.any? { |v| v =~ check } - elsif check.is_a?(Array) && check.all? { |c| c.is_a? String } - # If check is an array of strings, perform setwise check - Set.new(values) == Set.new(check) - elsif check.is_a?(Array) && check.all? { |c| c.is_a? Regexp } - # If check is an array of regexes, all values must match all regexes - values.all? { |v| check.all? { |r| v =~ r } } - else - false - end - end - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:policy_name], - allowed_scalar_name: :policy_name, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, "You must provide the parameter 'policy_name' to aws_iam_policy." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - policy = nil - pagination_opts = { max_items: 1000 } - loop do - api_result = backend.list_policies(pagination_opts) - policy = api_result.policies.detect do |p| - p.policy_name == @policy_name - end - break if policy # Found it! - break unless api_result.is_truncated # Not found and no more results - - pagination_opts[:marker] = api_result.marker - end - - @exists = !policy.nil? - - return unless @exists - - @arn = policy[:arn] - @default_version_id = policy[:default_version_id] - @attachment_count = policy[:attachment_count] - end - - def fetch_attached_entities - unless @exists - @attached_groups = nil - @attached_users = nil - @attached_roles = nil - return - end - backend = AwsIamPolicy::BackendFactory.create(inspec_runner) - criteria = { policy_arn: arn } - resp = nil - catch_aws_errors do - resp = backend.list_entities_for_policy(criteria) - end - @attached_groups = resp.policy_groups.map(&:group_name) - @attached_users = resp.policy_users.map(&:user_name) - @attached_roles = resp.policy_roles.map(&:role_name) - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - - def get_policy_version(criteria) - aws_service_client.get_policy_version(criteria) - end - - def list_policies(criteria) - aws_service_client.list_policies(criteria) - end - - def list_entities_for_policy(criteria) - aws_service_client.list_entities_for_policy(criteria) - end - end - end -end diff --git a/lib/resources/aws/aws_iam_role.rb b/lib/resources/aws/aws_iam_role.rb deleted file mode 100644 index ce27064db..000000000 --- a/lib/resources/aws/aws_iam_role.rb +++ /dev/null @@ -1,60 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamRole < Inspec.resource(1) - name "aws_iam_role" - desc "Verifies settings for an IAM Role" - example <<~EXAMPLE - describe aws_iam_role('my-role') do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :description, :role_name - - def to_s - "IAM Role #{role_name}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:role_name], - allowed_scalar_name: :role_name, - allowed_scalar_type: String - ) - if validated_params.empty? - raise ArgumentError, "You must provide a role_name to aws_iam_role." - end - - validated_params - end - - def fetch_from_api - role_info = nil - begin - role_info = BackendFactory.create(inspec_runner).get_role(role_name: role_name) - rescue Aws::IAM::Errors::NoSuchEntity - @exists = false - return - end - @exists = true - @description = role_info.role.description - end - - # Uses the SDK API to really talk to AWS - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - def get_role(query) - aws_service_client.get_role(query) - end - end - end -end diff --git a/lib/resources/aws/aws_iam_root_user.rb b/lib/resources/aws/aws_iam_root_user.rb deleted file mode 100644 index 51c22a838..000000000 --- a/lib/resources/aws/aws_iam_root_user.rb +++ /dev/null @@ -1,82 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamRootUser < Inspec.resource(1) - name "aws_iam_root_user" - desc "Verifies settings for AWS root account" - example <<~EXAMPLE - describe aws_iam_root_user do - it { should have_access_key } - end - EXAMPLE - supports platform: "aws" - - # TODO: rewrite to avoid direct injection, match other resources, use AwsSingularResourceMixin - def initialize(conn = nil) - @client = conn ? conn.iam_client : inspec_runner.backend.aws_client(Aws::IAM::Client) - end - - # TODO: DRY up, see https://github.com/chef/inspec/issues/2633 - # Copied from resource_support/aws/aws_resource_mixin.rb - def catch_aws_errors - yield - rescue Aws::Errors::MissingCredentialsError - # The AWS error here is unhelpful: - # "unable to sign request without credentials set" - Inspec::Log.error "It appears that you have not set your AWS credentials. You may set them using environment variables, or using the 'aws://region/aws_credentials_profile' target. See https://docs.chef.io/inspec/platforms/ for details." - fail_resource("No AWS credentials available") - rescue Aws::Errors::ServiceError => e - fail_resource e.message - end - - # TODO: DRY up, see https://github.com/chef/inspec/issues/2633 - # Copied from resource_support/aws/aws_singular_resource_mixin.rb - def inspec_runner - # When running under inspec-cli, we have an 'inspec' method that - # returns the runner. When running under unit tests, we don't - # have that, but we still have to call this to pass something - # (nil is OK) to the backend. - # TODO: remove with https://github.com/chef/inspec-aws/issues/216 - # TODO: remove after rewrite to include AwsSingularResource - inspec if respond_to?(:inspec) - end - - def has_access_key? - summary_account["AccountAccessKeysPresent"] == 1 - end - - def has_mfa_enabled? - summary_account["AccountMFAEnabled"] == 1 - end - - # if the root account has a Virtual MFA device then it will have a special - # serial number ending in 'root-account-mfa-device' - def has_virtual_mfa_enabled? - mfa_device_pattern = %r{arn:aws:iam::\d{12}:mfa\/root-account-mfa-device} - - virtual_mfa_devices.any? { |d| mfa_device_pattern =~ d["serial_number"] } - end - - def has_hardware_mfa_enabled? - has_mfa_enabled? && !has_virtual_mfa_enabled? - end - - def to_s - "AWS Root-User" - end - - private - - def summary_account - catch_aws_errors do - @summary_account ||= @client.get_account_summary.summary_map - end - end - - def virtual_mfa_devices - catch_aws_errors do - @__virtual_devices ||= @client.list_virtual_mfa_devices.virtual_mfa_devices - end - end -end diff --git a/lib/resources/aws/aws_iam_user.rb b/lib/resources/aws/aws_iam_user.rb deleted file mode 100644 index 0b019fb1a..000000000 --- a/lib/resources/aws/aws_iam_user.rb +++ /dev/null @@ -1,145 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamUser < Inspec.resource(1) - name "aws_iam_user" - desc "Verifies settings for AWS IAM user" - example <<~EXAMPLE - describe aws_iam_user(username: 'test_user') do - it { should have_mfa_enabled } - it { should_not have_console_password } - it { should_not have_inline_user_policies } - it { should_not have_attached_user_policies } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :access_keys, :attached_policy_names, :attached_policy_arns, \ - :has_console_password, :has_mfa_enabled, :inline_policy_names, :username - alias has_mfa_enabled? has_mfa_enabled - alias has_console_password? has_console_password - - def name - Inspec.deprecate(:properties_aws_iam_user, "The aws_iam_user `name` property is deprecated. Please use `username` instead") - username - end - - def to_s - "IAM User #{username}" - end - - def has_attached_policies? - return nil unless exists? - - !attached_policy_names.empty? - end - - def has_inline_policies? - return nil unless exists? - - !inline_policy_names.empty? - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: %i{username aws_user_struct name user}, - allowed_scalar_name: :username, - allowed_scalar_type: String - ) - # If someone passed :name, rename it to :username - if validated_params.key?(:name) - Inspec.deprecate(:properties_aws_iam_user, "The aws_iam_users `name` property is deprecated. Please use `username` instead") - validated_params[:username] = validated_params.delete(:name) - end - - # If someone passed :user, rename it to :aws_user_struct - if validated_params.key?(:user) - Inspec.deprecate(:properties_aws_iam_user, "The aws_iam_users `user` property is deprecated. Please use `aws_user_struct` instead") - validated_params[:aws_user_struct] = validated_params.delete(:user) - end - - if validated_params.empty? - raise ArgumentError, "You must provide a username to aws_iam_user." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @aws_user_struct ||= nil # silence unitialized warning - unless @aws_user_struct - begin - @aws_user_struct = backend.get_user(user_name: username) - rescue Aws::IAM::Errors::NoSuchEntity - @exists = false - @access_keys = [] - @inline_policy_names = [] - @attached_policy_arns = [] - @attached_policy_names = [] - return - end - end - # TODO: extract properties from aws_user_struct? - - @exists = true - - begin - _login_profile = backend.get_login_profile(user_name: username) - @has_console_password = true - # Password age also available here - rescue Aws::IAM::Errors::NoSuchEntity - @has_console_password = false - end - - mfa_info = backend.list_mfa_devices(user_name: username) - @has_mfa_enabled = !mfa_info.mfa_devices.empty? - - # TODO: consider returning InSpec AwsIamAccessKey objects - @access_keys = backend.list_access_keys(user_name: username).access_key_metadata - # If the above call fails, we get nil here; but we promise access_keys will be an array. - @access_keys ||= [] - - @inline_policy_names = backend.list_user_policies(user_name: username).policy_names - - attached_policies = backend.list_attached_user_policies(user_name: username).attached_policies - @attached_policy_arns = attached_policies.map { |p| p[:policy_arn] } - @attached_policy_names = attached_policies.map { |p| p[:policy_name] } - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - - def get_user(criteria) - aws_service_client.get_user(criteria) - end - - def get_login_profile(criteria) - aws_service_client.get_login_profile(criteria) - end - - def list_mfa_devices(criteria) - aws_service_client.list_mfa_devices(criteria) - end - - def list_access_keys(criteria) - aws_service_client.list_access_keys(criteria) - end - - def list_user_policies(criteria) - aws_service_client.list_user_policies(criteria) - end - - def list_attached_user_policies(criteria) - aws_service_client.list_attached_user_policies(criteria) - end - end - end -end diff --git a/lib/resources/aws/aws_iam_users.rb b/lib/resources/aws/aws_iam_users.rb deleted file mode 100644 index 553815513..000000000 --- a/lib/resources/aws/aws_iam_users.rb +++ /dev/null @@ -1,160 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-iam" - -class AwsIamUsers < Inspec.resource(1) - name "aws_iam_users" - desc "Verifies settings for AWS IAM users" - example <<~EXAMPLE - describe aws_iam_users.where(has_mfa_enabled?: false) do - it { should_not exist } - end - describe aws_iam_users.where(has_console_password?: true) do - it { should exist } - end - describe aws_iam_users.where(has_inline_policies?: true) do - it { should_not exist } - end - describe aws_iam_users.where(has_attached_policies?: true) do - it { should_not exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - def self.lazy_get_login_profile(row, _criterion, table) - backend = BackendFactory.create(table.resource.inspec_runner) - begin - _login_profile = backend.get_login_profile(user_name: row[:user_name]) - row[:has_console_password] = true - rescue Aws::IAM::Errors::NoSuchEntity - row[:has_console_password] = false - end - row[:has_console_password?] = row[:has_console_password] - end - - def self.lazy_list_mfa_devices(row, _criterion, table) - backend = BackendFactory.create(table.resource.inspec_runner) - begin - aws_mfa_devices = backend.list_mfa_devices(user_name: row[:user_name]) - row[:has_mfa_enabled] = !aws_mfa_devices.mfa_devices.empty? - rescue Aws::IAM::Errors::NoSuchEntity - row[:has_mfa_enabled] = false - end - row[:has_mfa_enabled?] = row[:has_mfa_enabled] - end - - def self.lazy_list_user_policies(row, _criterion, table) - backend = BackendFactory.create(table.resource.inspec_runner) - row[:inline_policy_names] = backend.list_user_policies(user_name: row[:user_name]).policy_names - row[:has_inline_policies] = !row[:inline_policy_names].empty? - row[:has_inline_policies?] = row[:has_inline_policies] - end - - def self.lazy_list_attached_policies(row, _criterion, table) - backend = BackendFactory.create(table.resource.inspec_runner) - attached_policies = backend.list_attached_user_policies(user_name: row[:user_name]).attached_policies - row[:has_attached_policies] = !attached_policies.empty? - row[:has_attached_policies?] = row[:has_attached_policies] - row[:attached_policy_names] = attached_policies.map { |p| p[:policy_name] } - row[:attached_policy_arns] = attached_policies.map { |p| p[:policy_arn] } - end - - filter = FilterTable.create - - # These are included on the initial fetch - filter.register_column(:usernames, field: :user_name) - .register_column(:username) { |res| res.entries.map { |row| row[:user_name] } } # We should deprecate this; plural resources get plural properties - .register_column(:password_ever_used?, field: :password_ever_used?) - .register_column(:password_never_used?, field: :password_never_used?) - .register_column(:password_last_used_days_ago, field: :password_last_used_days_ago) - - # Remaining properties / criteria are handled lazily, grouped by fetcher - filter.register_column(:has_console_password?, field: :has_console_password?, lazy: method(:lazy_get_login_profile)) - .register_column(:has_console_password, field: :has_console_password, lazy: method(:lazy_get_login_profile)) - - filter.register_column(:has_mfa_enabled?, field: :has_mfa_enabled?, lazy: method(:lazy_list_mfa_devices)) - .register_column(:has_mfa_enabled, field: :has_mfa_enabled, lazy: method(:lazy_list_mfa_devices)) - - filter.register_column(:has_inline_policies?, field: :has_inline_policies?, lazy: method(:lazy_list_user_policies)) - .register_column(:has_inline_policies, field: :has_inline_policies, lazy: method(:lazy_list_user_policies)) - .register_column(:inline_policy_names, field: :inline_policy_names, style: :simple, lazy: method(:lazy_list_user_policies)) - - filter.register_column(:has_attached_policies?, field: :has_attached_policies?, lazy: method(:lazy_list_attached_policies)) - .register_column(:has_attached_policies, field: :has_attached_policies, lazy: method(:lazy_list_attached_policies)) - .register_column(:attached_policy_names, field: :attached_policy_names, style: :simple, lazy: method(:lazy_list_attached_policies)) - .register_column(:attached_policy_arns, field: :attached_policy_arns, style: :simple, lazy: method(:lazy_list_attached_policies)) - filter.install_filter_methods_on_resource(self, :table) - - def validate_params(raw_params) - # No params yet - unless raw_params.empty? - raise ArgumentError, "aws_iam_users does not accept resource parameters" - end - - raw_params - end - - def fetch_from_api_paginated(backend) - table = [] - page_marker = nil - loop do - api_result = backend.list_users(marker: page_marker) - table += api_result.users.map(&:to_h) - page_marker = api_result.marker - break unless api_result.is_truncated - end - table - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = fetch_from_api_paginated(backend) - - @table.each do |user| - password_last_used = user[:password_last_used] - user[:password_ever_used?] = !password_last_used.nil? - user[:password_never_used?] = password_last_used.nil? - if user[:password_ever_used?] - user[:password_last_used_days_ago] = ((Time.now - password_last_used) / (24 * 60 * 60)).to_i - end - end - @table - end - - def to_s - "IAM Users" - end - - #===========================================================================# - # Backend Implementation - #===========================================================================# - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::IAM::Client - - # TODO: delegate this out - def list_users(query = {}) - aws_service_client.list_users(query) - end - - def get_login_profile(query) - aws_service_client.get_login_profile(query) - end - - def list_mfa_devices(query) - aws_service_client.list_mfa_devices(query) - end - - def list_user_policies(query) - aws_service_client.list_user_policies(query) - end - - def list_attached_user_policies(query) - aws_service_client.list_attached_user_policies(query) - end - end - end -end diff --git a/lib/resources/aws/aws_kms_key.rb b/lib/resources/aws/aws_kms_key.rb deleted file mode 100644 index eabc0a1c6..000000000 --- a/lib/resources/aws/aws_kms_key.rb +++ /dev/null @@ -1,100 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-kms" - -class AwsKmsKey < Inspec.resource(1) - name "aws_kms_key" - desc "Verifies settings for an individual AWS KMS Key" - example <<~EXAMPLE - describe aws_kms_key('arn:aws:kms:us-east-1::key/4321dcba-21io-23de-85he-ab0987654321') do - it { should exist } - end - EXAMPLE - - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :key_id, :arn, :creation_date, :key_usage, :key_state, :description, - :deletion_date, :valid_to, :external, :has_key_expiration, :managed_by_aws, - :has_rotation_enabled, :enabled - # Use aliases for matchers - alias deletion_time deletion_date - alias invalidation_time valid_to - alias external? external - alias enabled? enabled - alias managed_by_aws? managed_by_aws - alias has_key_expiration? has_key_expiration - alias has_rotation_enabled? has_rotation_enabled - - def to_s - "KMS Key #{@key_id}" - end - - def created_days_ago - ((Time.now - creation_date) / (24 * 60 * 60)).to_i unless creation_date.nil? - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:key_id], - allowed_scalar_name: :key_id, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, "You must provide the parameter 'key_id' to aws_kms_key." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - query = { key_id: @key_id } - catch_aws_errors do - - resp = backend.describe_key(query) - - @exists = true - @key = resp.key_metadata.to_h - @key_id = @key[:key_id] - @arn = @key[:arn] - @creation_date = @key[:creation_date] - @enabled = @key[:enabled] - @description = @key[:description] - @key_usage = @key[:key_usage] - @key_state = @key[:key_state] - @deletion_date = @key[:deletion_date] - @valid_to = @key[:valid_to] - @external = @key[:origin] == "EXTERNAL" - @has_key_expiration = @key[:expiration_model] == "KEY_MATERIAL_EXPIRES" - @managed_by_aws = @key[:key_manager] == "AWS" - - resp = backend.get_key_rotation_status(query) - @has_rotation_enabled = resp.key_rotation_enabled unless resp.empty? - rescue Aws::KMS::Errors::NotFoundException - @exists = false - return - - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::KMS::Client - - def describe_key(query) - aws_service_client.describe_key(query) - end - - def get_key_rotation_status(query) - aws_service_client.get_key_rotation_status(query) - end - end - end -end diff --git a/lib/resources/aws/aws_kms_keys.rb b/lib/resources/aws/aws_kms_keys.rb deleted file mode 100644 index ffe23a2ec..000000000 --- a/lib/resources/aws/aws_kms_keys.rb +++ /dev/null @@ -1,58 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-kms" - -class AwsKmsKeys < Inspec.resource(1) - name "aws_kms_keys" - desc "Verifies settings for AWS KMS Keys in bulk" - example <<~EXAMPLE - describe aws_kms_keys do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_kms_keys does not accept resource parameters." - end - - resource_params - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:key_arns, field: :key_arn) - .register_column(:key_ids, field: :key_id) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "KMS Keys" - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = [] - pagination_opts = { limit: 1000 } - loop do - api_result = backend.list_keys(pagination_opts) - @table += api_result.keys.map(&:to_h) - break unless api_result.truncated - - pagination_opts = { marker: api_result.next_marker } - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::KMS::Client - - def list_keys(query = {}) - aws_service_client.list_keys(query) - end - end - end -end diff --git a/lib/resources/aws/aws_rds_instance.rb b/lib/resources/aws/aws_rds_instance.rb deleted file mode 100644 index be167e1d2..000000000 --- a/lib/resources/aws/aws_rds_instance.rb +++ /dev/null @@ -1,74 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-rds" - -class AwsRdsInstance < Inspec.resource(1) - name "aws_rds_instance" - desc "Verifies settings for an rds instance" - example <<~EXAMPLE - describe aws_rds_instance(db_instance_identifier: 'test-instance-id') do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :db_instance_identifier - - def to_s - "RDS Instance #{@db_instance_identifier}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:db_instance_identifier], - allowed_scalar_name: :db_instance_identifier, - allowed_scalar_type: String - ) - if validated_params.empty? || !validated_params.key?(:db_instance_identifier) - raise ArgumentError, "You must provide an id for the aws_rds_instance." - end - - if validated_params.key?(:db_instance_identifier) && validated_params[:db_instance_identifier] !~ /^[a-z]{1}[0-9a-z\-]{0,62}$/ - raise ArgumentError, "aws_rds_instance Database Instance ID must be in the format: start with a letter followed by up to 62 letters/numbers/hyphens." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - dsg_response = nil - catch_aws_errors do - - dsg_response = backend.describe_db_instances(db_instance_identifier: db_instance_identifier) - @exists = true - rescue Aws::RDS::Errors::DBInstanceNotFound - @exists = false - return - - end - - if dsg_response.db_instances.empty? - @exists = false - return - end - - @db_instance_identifier = dsg_response.db_instances[0].db_instance_identifier - end - - # Uses the SDK API to really talk to AWS - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::RDS::Client - - def describe_db_instances(query) - aws_service_client.describe_db_instances(query) - end - end - end -end diff --git a/lib/resources/aws/aws_route_table.rb b/lib/resources/aws/aws_route_table.rb deleted file mode 100644 index 51196f19b..000000000 --- a/lib/resources/aws/aws_route_table.rb +++ /dev/null @@ -1,67 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsRouteTable < Inspec.resource(1) - name "aws_route_table" - desc "Verifies settings for an AWS Route Table" - example <<~EXAMPLE - describe aws_route_table do - its('route_table_id') { should cmp 'rtb-05462d2278326a79c' } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - - def to_s - "Route Table #{@route_table_id}" - end - - attr_reader :route_table_id, :vpc_id - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:route_table_id], - allowed_scalar_name: :route_table_id, - allowed_scalar_type: String - ) - - if validated_params.key?(:route_table_id) && - validated_params[:route_table_id] !~ /^rtb\-([0-9a-f]{17})|(^rtb\-[0-9a-f]{8})$/ - raise ArgumentError, - "aws_route_table Route Table ID must be in the" \ - ' format "rtb-" followed by 8 or 17 hexadecimal characters.' - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - if @route_table_id.nil? - args = nil - else - args = { filters: [{ name: "route-table-id", values: [@route_table_id] }] } - end - - resp = backend.describe_route_tables(args) - routetable = resp.to_h[:route_tables] - @exists = !routetable.empty? - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::EC2::Client - - def describe_route_tables(query) - aws_service_client.describe_route_tables(query) - end - end - end -end diff --git a/lib/resources/aws/aws_route_tables.rb b/lib/resources/aws/aws_route_tables.rb deleted file mode 100644 index 877e4135d..000000000 --- a/lib/resources/aws/aws_route_tables.rb +++ /dev/null @@ -1,64 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsRouteTables < Inspec.resource(1) - name "aws_route_tables" - desc "Verifies settings for AWS Route Tables in bulk" - example <<~EXAMPLE - describe aws_route_tables do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:vpc_ids, field: :vpc_id) - .register_column(:route_table_ids, field: :route_table_id) - filter.install_filter_methods_on_resource(self, :routes_data) - - def routes_data - @table - end - - def to_s - "Route Tables" - end - - private - - def validate_params(raw_criteria) - unless raw_criteria.is_a? Hash - raise "Unrecognized criteria for fetching Route Tables. " \ - "Use 'criteria: value' format." - end - - # No criteria yet - unless raw_criteria.empty? - raise ArgumentError, "aws_route_tables does not currently accept resource parameters." - end - - raw_criteria - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - catch_aws_errors do - @table = backend.describe_route_tables({}).to_h[:route_tables] - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend self - self.aws_client_class = Aws::EC2::Client - - def describe_route_tables(query = {}) - aws_service_client.describe_route_tables(query) - end - end - end -end diff --git a/lib/resources/aws/aws_s3_bucket.rb b/lib/resources/aws/aws_s3_bucket.rb deleted file mode 100644 index 4e8fce251..000000000 --- a/lib/resources/aws/aws_s3_bucket.rb +++ /dev/null @@ -1,141 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-s3" - -class AwsS3Bucket < Inspec.resource(1) - name "aws_s3_bucket" - desc "Verifies settings for a s3 bucket" - example <<~EXAMPLE - describe aws_s3_bucket(bucket_name: 'test_bucket') do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :bucket_name, :has_default_encryption_enabled, :has_access_logging_enabled, :region - - def to_s - "S3 Bucket #{@bucket_name}" - end - - def bucket_acl - catch_aws_errors do - @bucket_acl ||= BackendFactory.create(inspec_runner).get_bucket_acl(bucket: bucket_name).grants - end - end - - def bucket_policy - @bucket_policy ||= fetch_bucket_policy - end - - # RSpec will alias this to be_public - def public? - # first line just for formatting - false || \ - bucket_acl.any? { |g| g.grantee.type == "Group" && g.grantee.uri =~ /AllUsers/ } || \ - bucket_acl.any? { |g| g.grantee.type == "Group" && g.grantee.uri =~ /AuthenticatedUsers/ } || \ - bucket_policy.any? { |s| s.effect == "Allow" && s.principal == "*" } - end - - def has_default_encryption_enabled? - return false unless @exists - - @has_default_encryption_enabled ||= fetch_bucket_encryption_configuration - end - - def has_access_logging_enabled? - return false unless @exists - - catch_aws_errors do - @has_access_logging_enabled ||= !BackendFactory.create(inspec_runner).get_bucket_logging(bucket: bucket_name).logging_enabled.nil? - end - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:bucket_name], - allowed_scalar_name: :bucket_name, - allowed_scalar_type: String - ) - if validated_params.empty? || !validated_params.key?(:bucket_name) - raise ArgumentError, "You must provide a bucket_name to aws_s3_bucket." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - # Since there is no basic "get_bucket" API call, use the - # region fetch as the existence check. - begin - @region = backend.get_bucket_location(bucket: bucket_name).location_constraint - rescue Aws::S3::Errors::NoSuchBucket - @exists = false - return - end - @exists = true - end - - def fetch_bucket_policy - backend = BackendFactory.create(inspec_runner) - catch_aws_errors do - - # AWS SDK returns a StringIO, we have to read() - raw_policy = backend.get_bucket_policy(bucket: bucket_name).policy - return JSON.parse(raw_policy.read)["Statement"].map do |statement| - lowercase_hash = {} - statement.each_key { |k| lowercase_hash[k.downcase] = statement[k] } - @bucket_policy = OpenStruct.new(lowercase_hash) - end - rescue Aws::S3::Errors::NoSuchBucketPolicy - @bucket_policy = [] - - end - end - - def fetch_bucket_encryption_configuration - @has_default_encryption_enabled ||= catch_aws_errors do - !BackendFactory.create(inspec_runner) - .get_bucket_encryption(bucket: bucket_name) - .server_side_encryption_configuration - .nil? - rescue Aws::S3::Errors::ServerSideEncryptionConfigurationNotFoundError - false - - end - end - - # Uses the SDK API to really talk to AWS - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::S3::Client - - def get_bucket_acl(query) - aws_service_client.get_bucket_acl(query) - end - - def get_bucket_location(query) - aws_service_client.get_bucket_location(query) - end - - def get_bucket_policy(query) - aws_service_client.get_bucket_policy(query) - end - - def get_bucket_logging(query) - aws_service_client.get_bucket_logging(query) - end - - def get_bucket_encryption(query) - aws_service_client.get_bucket_encryption(query) - end - end - end -end diff --git a/lib/resources/aws/aws_s3_bucket_object.rb b/lib/resources/aws/aws_s3_bucket_object.rb deleted file mode 100644 index ef28195bf..000000000 --- a/lib/resources/aws/aws_s3_bucket_object.rb +++ /dev/null @@ -1,87 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-s3" - -class AwsS3BucketObject < Inspec.resource(1) - name "aws_s3_bucket_object" - desc "Verifies settings for a s3 bucket object" - example <<~EXAMPLE - describe aws_s3_bucket_object(bucket_name: 'bucket_name', key: 'file_name') do - it { should exist } - it { should_not be_public } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :bucket_name, :key - - def to_s - # keep the format that aws uses. - "s3://#{@bucket_name}/#{@key}" - end - - def object_acl - return @object_acl if defined? @object_acl - - catch_aws_errors do - @object_acl = BackendFactory.create(inspec_runner).get_object_acl(bucket: bucket_name, key: key).grants - end - @object_acl - end - - # RSpec will alias this to be_public - def public? - # first line just for formatting - false || \ - object_acl.any? { |g| g.grantee.type == "Group" && g.grantee.uri =~ /AllUsers/ } || \ - object_acl.any? { |g| g.grantee.type == "Group" && g.grantee.uri =~ /AuthenticatedUsers/ } - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: %i{bucket_name key id} - ) - if validated_params.empty? || !validated_params.key?(:bucket_name) || !validated_params.key?(:key) - raise ArgumentError, "You must provide a bucket_name and key to aws_s3_bucket_object." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - catch_aws_errors do - - # Just use get_object to detect if the bucket exists - backend.get_object(bucket: bucket_name, key: key) - rescue Aws::S3::Errors::NoSuchBucket - @exists = false - return - rescue Aws::S3::Errors::NoSuchKey - @exists = false - return - - end - @exists = true - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::S3::Client - - # Used to detect if object exists - def get_object(query) - aws_service_client.get_object(query) - end - - def get_object_acl(query) - aws_service_client.get_object_acl(query) - end - end - end -end diff --git a/lib/resources/aws/aws_s3_buckets.rb b/lib/resources/aws/aws_s3_buckets.rb deleted file mode 100644 index 0d63fb8bc..000000000 --- a/lib/resources/aws/aws_s3_buckets.rb +++ /dev/null @@ -1,52 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-s3" - -class AwsS3Buckets < Inspec.resource(1) - name "aws_s3_buckets" - desc "Verifies settings for AWS S3 Buckets in bulk" - example <<~EXAMPLE - describe aws_s3_bucket do - its('bucket_names') { should eq ['my_bucket'] } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:bucket_names, field: :name) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "S3 Buckets" - end - - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_s3_buckets does not accept resource parameters." - end - - resource_params - end - - private - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = backend.list_buckets.buckets.map(&:to_h) - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend self - self.aws_client_class = Aws::S3::Client - - def list_buckets - aws_service_client.list_buckets - end - end - end -end diff --git a/lib/resources/aws/aws_security_group.rb b/lib/resources/aws/aws_security_group.rb deleted file mode 100644 index ce9b72d20..000000000 --- a/lib/resources/aws/aws_security_group.rb +++ /dev/null @@ -1,314 +0,0 @@ -require "set" unless defined?(Set) -require "ipaddr" unless defined?(IPAddr) - -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsSecurityGroup < Inspec.resource(1) - name "aws_security_group" - desc "Verifies settings for an individual AWS Security Group." - example <<~EXAMPLE - describe aws_security_group('sg-12345678') do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :description, :group_id, :group_name, :vpc_id, :inbound_rules, :outbound_rules, :inbound_rules_count, :outbound_rules_count - - def to_s - "EC2 Security Group #{@group_id}" - end - - def allow_in?(criteria = {}) - allow(inbound_rules, criteria.dup) - end - RSpec::Matchers.alias_matcher :allow_in, :be_allow_in - - def allow_out?(criteria = {}) - allow(outbound_rules, criteria.dup) - end - RSpec::Matchers.alias_matcher :allow_out, :be_allow_out - - def allow_in_only?(criteria = {}) - allow_only(inbound_rules, criteria.dup) - end - RSpec::Matchers.alias_matcher :allow_in_only, :be_allow_in_only - - def allow_out_only?(criteria = {}) - allow_only(outbound_rules, criteria.dup) - end - RSpec::Matchers.alias_matcher :allow_out_only, :be_allow_out_only - - private - - def allow_only(rules, criteria) - rules = allow__focus_on_position(rules, criteria) - # allow_{in_out}_only require either a single-rule group, or you - # to select a rule using position. - return false unless rules.count == 1 || criteria.key?(:position) - - if criteria.key?(:security_group) - if criteria.key?(:position) - pos = criteria[:position] - 1 - else - pos = 0 - end - return false unless rules[pos].key?(:user_id_group_pairs) && rules[pos][:user_id_group_pairs].count == 1 - end - criteria[:exact] = true - allow(rules, criteria) - end - - def allow(rules, criteria) - criteria = allow__check_criteria(criteria) - rules = allow__focus_on_position(rules, criteria) - - rules.any? do |rule| - matched = true - matched &&= allow__match_port(rule, criteria) - matched &&= allow__match_protocol(rule, criteria) - matched &&= allow__match_ipv4_range(rule, criteria) - matched &&= allow__match_ipv6_range(rule, criteria) - matched &&= allow__match_security_group(rule, criteria) - matched - end - end - - def allow__check_criteria(raw_criteria) - allowed_criteria = [ - :from_port, - :ipv4_range, - :ipv6_range, - :security_group, - :port, - :position, - :protocol, - :to_port, - :exact, # Internal - ] - recognized_criteria = {} - allowed_criteria.each do |expected_criterion| - if raw_criteria.key?(expected_criterion) - recognized_criteria[expected_criterion] = raw_criteria.delete(expected_criterion) - end - end - - # Any leftovers are unwelcome - unless raw_criteria.empty? - raise ArgumentError, "Unrecognized security group rule 'allow' criteria '#{raw_criteria.keys.join(",")}'. Expected criteria: #{allowed_criteria.join(", ")}" - end - - recognized_criteria - end - - def allow__focus_on_position(rules, criteria) - return rules unless criteria.key?(:position) - - idx = criteria.delete(:position) - - # Normalize to a zero-based numeric index - case # rubocop: disable Style/EmptyCaseCondition - when idx.is_a?(Symbol) && idx == :first - idx = 0 - when idx.is_a?(Symbol) && idx == :last - idx = rules.count - 1 - when idx.is_a?(String) - idx = idx.to_i - 1 # We document this as 1-based, so adjust to be zero-based. - when idx.is_a?(Numeric) - idx -= 1 # We document this as 1-based, so adjust to be zero-based. - else - raise ArgumentError, "aws_security_group 'allow' 'position' criteria must be an integer or the symbols :first or :last" - end - - unless idx < rules.count - raise ArgumentError, "aws_security_group 'allow' 'position' criteria #{idx + 1} is out of range - there are only #{rules.count} rules for security group #{group_id}." - end - - [rules[idx]] - end - - def allow__match_port(rule, criteria) # rubocop: disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize - if criteria[:exact] || criteria[:from_port] || criteria[:to_port] - # Exact match mode - # :port is shorthand for a single-valued port range. - criteria[:to_port] = criteria[:from_port] = criteria[:port] if criteria[:port] - to = criteria[:to_port] - from = criteria[:from_port] - # It's a match if neither criteria was specified - return true if to.nil? && from.nil? - - # Normalize to integers - to = to.to_i unless to.nil? - from = from.to_i unless from.nil? - # It's a match if either was specified and the other was not - return true if rule[:to_port] == to && from.nil? - return true if rule[:from_port] == from && to.nil? - - # Finally, both must match. - rule[:to_port] == to && rule[:from_port] == from - elsif !criteria[:port] - # port not specified, match anything - true - else - # Range membership mode - rule_from = rule[:from_port] || 0 - rule_to = rule[:to_port] || 65535 - (rule_from..rule_to).cover?(criteria[:port].to_i) - end - end - - def allow__match_protocol(rule, criteria) - return true unless criteria.key?(:protocol) - - prot = criteria[:protocol] - # We provide a "fluency alias" for -1 (any). - prot = "-1" if prot == "any" - - rule[:ip_protocol] == prot - end - - def match_ipv4_or_6_range(rule, criteria) - if criteria.key?(:ipv4_range) - query = criteria[:ipv4_range] - query = [query] unless query.is_a?(Array) - ranges = rule[:ip_ranges].map { |rng| rng[:cidr_ip] } - else # IPv6 - query = criteria[:ipv6_range] - query = [query] unless query.is_a?(Array) - ranges = rule[:ipv_6_ranges].map { |rng| rng[:cidr_ipv_6] } - end - - if criteria[:exact] - Set.new(query) == Set.new(ranges) - else - # CIDR subset mode - # "Each of the provided IP ranges must be a member of one of the rule's listed IP ranges" - query.all? do |candidate| - candidate = IPAddr.new(candidate) - ranges.any? do |range| - range = IPAddr.new(range) - range.include?(candidate) - end - end - end - end - - def allow__match_ipv4_range(rule, criteria) - return true unless criteria.key?(:ipv4_range) - - match_ipv4_or_6_range(rule, criteria) - end - - def allow__match_ipv6_range(rule, criteria) - return true unless criteria.key?(:ipv6_range) - - match_ipv4_or_6_range(rule, criteria) - end - - def allow__match_security_group(rule, criteria) - return true unless criteria.key?(:security_group) - - query = criteria[:security_group] - return false unless rule[:user_id_group_pairs] - - rule[:user_id_group_pairs].any? { |group| query == group[:group_id] } - end - - def validate_params(raw_params) - recognized_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: %i{id group_id group_name vpc_id}, - allowed_scalar_name: :group_id, - allowed_scalar_type: String - ) - - # id is an alias for group_id - recognized_params[:group_id] = recognized_params.delete(:id) if recognized_params.key?(:id) - - if recognized_params.key?(:group_id) && recognized_params[:group_id] !~ /^sg\-[0-9a-f]{8}/ - raise ArgumentError, 'aws_security_group security group ID must be in the format "sg-" followed by 8 hexadecimal characters.' - end - - if recognized_params.key?(:vpc_id) && recognized_params[:vpc_id] !~ /^vpc\-[0-9a-f]{8}/ - raise ArgumentError, 'aws_security_group VPC ID must be in the format "vpc-" followed by 8 hexadecimal characters.' - end - - validated_params = recognized_params - - if validated_params.empty? - raise ArgumentError, "You must provide parameters to aws_security_group, such as group_name, group_id, or vpc_id.g_group." - end - - validated_params - end - - def count_sg_rules(ip_permissions) - rule_count = 0 - ip_permissions.each do |ip_permission| - %i{ip_ranges ipv_6_ranges user_id_group_pairs}.each do |key| - if ip_permission.key? key - rule_count += ip_permission[key].length - end - end - end - rule_count - end - - def fetch_from_api # rubocop: disable Metrics/AbcSize - backend = BackendFactory.create(inspec_runner) - - # Transform into filter format expected by AWS - filters = [] - %i{ - description - group_id - group_name - vpc_id - }.each do |criterion_name| - instance_var = "@#{criterion_name}".to_sym - next unless instance_variable_defined?(instance_var) - - val = instance_variable_get(instance_var) - next if val.nil? - - filters.push( - { - name: criterion_name.to_s.tr("_", "-"), - values: [val], - } - ) - end - dsg_response = backend.describe_security_groups(filters: filters) - - if dsg_response.security_groups.empty? - @exists = false - @inbound_rules = [] - @outbound_rules = [] - return - end - - @exists = true - @description = dsg_response.security_groups[0].description - @group_id = dsg_response.security_groups[0].group_id - @group_name = dsg_response.security_groups[0].group_name - @vpc_id = dsg_response.security_groups[0].vpc_id - @inbound_rules = dsg_response.security_groups[0].ip_permissions.map(&:to_h) - @inbound_rules_count = count_sg_rules(dsg_response.security_groups[0].ip_permissions.map(&:to_h)) - @outbound_rules = dsg_response.security_groups[0].ip_permissions_egress.map(&:to_h) - @outbound_rules_count = count_sg_rules(dsg_response.security_groups[0].ip_permissions_egress.map(&:to_h)) - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend self - self.aws_client_class = Aws::EC2::Client - - def describe_security_groups(query) - aws_service_client.describe_security_groups(query) - end - end - end -end diff --git a/lib/resources/aws/aws_security_groups.rb b/lib/resources/aws/aws_security_groups.rb deleted file mode 100644 index e4d95cdaf..000000000 --- a/lib/resources/aws/aws_security_groups.rb +++ /dev/null @@ -1,71 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsSecurityGroups < Inspec.resource(1) - name "aws_security_groups" - desc "Verifies settings for AWS Security Groups in bulk" - example <<~EXAMPLE - # Verify that you have security groups defined - describe aws_security_groups do - it { should exist } - end - - # Verify you have more than the default security group - describe aws_security_groups do - its('entries.count') { should be > 1 } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:group_ids, field: :group_id) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "EC2 Security Groups" - end - - private - - def validate_params(raw_criteria) - unless raw_criteria.is_a? Hash - raise "Unrecognized criteria for fetching Security Groups. " \ - "Use 'criteria: value' format." - end - - # No criteria yet - unless raw_criteria.empty? - raise ArgumentError, "aws_ec2_security_groups does not currently accept resource parameters." - end - - raw_criteria - end - - def fetch_from_api - @table = [] - backend = BackendFactory.create(inspec_runner) - backend.describe_security_groups({}).security_groups.each do |sg_info| - @table.push({ - group_id: sg_info.group_id, - group_name: sg_info.group_name, - vpc_id: sg_info.vpc_id, - }) - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend self - self.aws_client_class = Aws::EC2::Client - - def describe_security_groups(query) - aws_service_client.describe_security_groups(query) - end - end - end -end diff --git a/lib/resources/aws/aws_sns_subscription.rb b/lib/resources/aws/aws_sns_subscription.rb deleted file mode 100644 index 34b29f0bc..000000000 --- a/lib/resources/aws/aws_sns_subscription.rb +++ /dev/null @@ -1,82 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-sns" - -class AwsSnsSubscription < Inspec.resource(1) - name "aws_sns_subscription" - desc "Verifies settings for an SNS Subscription" - example <<~EXAMPLE - describe aws_sns_subscription('arn:aws:sns:us-east-1::test-topic-01:b214aff5-a2c7-438f-a753-8494493f2ff6') do - it { should_not have_raw_message_delivery } - it { should be_confirmation_authenticated } - its('owner') { should cmp '12345678' } - its('topic_arn') { should cmp 'arn:aws:sns:us-east-1::test-topic-01' } - its('endpoint') { should cmp 'arn:aws:sqs:us-east-1::test-queue-01' } - its('protocol') { should cmp 'sqs' } - end - EXAMPLE - - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :arn, :owner, :raw_message_delivery, :topic_arn, :endpoint, :protocol, - :confirmation_was_authenticated, :aws_response - - alias confirmation_authenticated? confirmation_was_authenticated - alias raw_message_delivery? raw_message_delivery - - def has_raw_message_delivery? - raw_message_delivery - end - - def to_s - "SNS Subscription #{@arn}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:subscription_arn], - allowed_scalar_name: :subscription_arn, - allowed_scalar_type: String - ) - - if validated_params.empty? - raise ArgumentError, "You must provide a subscription_arn to aws_sns_subscription." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - catch_aws_errors do - - aws_response = backend.get_subscription_attributes(subscription_arn: @subscription_arn).attributes - @exists = true - @owner = aws_response["Owner"] - @raw_message_delivery = aws_response["RawMessageDelivery"].eql?("true") - @topic_arn = aws_response["TopicArn"] - @endpoint = aws_response["Endpoint"] - @protocol = aws_response["Protocol"] - @confirmation_was_authenticated = aws_response["ConfirmationWasAuthenticated"].eql?("true") - rescue Aws::SNS::Errors::NotFound - @exists = false - return - - end - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend self - self.aws_client_class = Aws::SNS::Client - - def get_subscription_attributes(criteria) - aws_service_client.get_subscription_attributes(criteria) - end - end - end -end diff --git a/lib/resources/aws/aws_sns_topic.rb b/lib/resources/aws/aws_sns_topic.rb deleted file mode 100644 index 561d2893f..000000000 --- a/lib/resources/aws/aws_sns_topic.rb +++ /dev/null @@ -1,57 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-sns" - -class AwsSnsTopic < Inspec.resource(1) - name "aws_sns_topic" - desc "Verifies settings for an SNS Topic" - example <<~EXAMPLE - describe aws_sns_topic('arn:aws:sns:us-east-1:123456789012:some-topic') do - it { should exist } - its('confirmed_subscription_count') { should_not be_zero } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :arn, :confirmed_subscription_count - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:arn], - allowed_scalar_name: :arn, - allowed_scalar_type: String - ) - # Validate the ARN - unless validated_params[:arn] =~ /^arn:aws:sns:[\w\-]+:\d{12}:[\S]+$/ - raise ArgumentError, "Malformed ARN for SNS topics. Expected an ARN of the form " \ - "'arn:aws:sns:REGION:ACCOUNT-ID:TOPIC-NAME'" - end - validated_params - end - - def fetch_from_api - aws_response = BackendFactory.create(inspec_runner).get_topic_attributes(topic_arn: @arn).attributes - @exists = true - - # The response has a plain hash with CamelCase plain string keys and string values - @confirmed_subscription_count = aws_response["SubscriptionsConfirmed"].to_i - rescue Aws::SNS::Errors::NotFound - @exists = false - end - - # Uses the SDK API to really talk to AWS - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::SNS::Client - - def get_topic_attributes(criteria) - aws_service_client.get_topic_attributes(criteria) - end - end - end -end diff --git a/lib/resources/aws/aws_sns_topics.rb b/lib/resources/aws/aws_sns_topics.rb deleted file mode 100644 index 5ebe99480..000000000 --- a/lib/resources/aws/aws_sns_topics.rb +++ /dev/null @@ -1,60 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-sns" - -class AwsSnsTopics < Inspec.resource(1) - name "aws_sns_topics" - desc "Verifies settings for SNS Topics in bulk" - example <<~EXAMPLE - describe aws_sns_topics do - its('topic_arns') { should include '' } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_sns_topics does not accept resource parameters." - end - - resource_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = [] - pagination_opts = nil - catch_aws_errors do - loop do - api_result = backend.list_topics(pagination_opts) - @table += api_result.topics.map(&:to_h) - break if api_result.next_token.nil? - - pagination_opts = { next_token: api_result.next_token } - end - end - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:topic_arns, field: :topic_arn) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "EC2 SNS Topics" - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend self - self.aws_client_class = Aws::SNS::Client - - def list_topics(pagination_opts) - aws_service_client.list_topics(pagination_opts) - end - end - end -end diff --git a/lib/resources/aws/aws_sqs_queue.rb b/lib/resources/aws/aws_sqs_queue.rb deleted file mode 100644 index 696b23680..000000000 --- a/lib/resources/aws/aws_sqs_queue.rb +++ /dev/null @@ -1,66 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-sqs" - -require "uri" unless defined?(URI) - -class AwsSqsQueue < Inspec.resource(1) - name "aws_sqs_queue" - desc "Verifies settings for an SQS Queue" - example <<~EXAMPLE - describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/519527725796/QueueName') do - it { should exist } - its('visiblity_timeout') { should be 300} - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :arn, :is_fifo_queue, :visibility_timeout, :maximum_message_size, :message_retention_period, :delay_seconds, :receive_message_wait_timeout_seconds, :content_based_deduplication - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:url], - allowed_scalar_name: :url, - allowed_scalar_type: String - ) - # Validate the URL - unless validated_params[:url] =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w{https})}\z/ - raise ArgumentError, "Malformed URL for SQS. Expected an ARN of the form " \ - "'https://sqs.ap-southeast-2.amazonaws.com/111212121/MyQeueue'" - end - validated_params - end - - def fetch_from_api - aws_response = BackendFactory.create(inspec_runner).get_queue_attributes(queue_url: @url, attribute_names: ["All"]).attributes - @exists = true - @visibility_timeout = aws_response["VisibilityTimeout"].to_i - @maximum_message_size = aws_response["MaximumMessageSize"].to_i - @message_retention_period = aws_response["MessageRetentionPeriod"].to_i - @delay_seconds = aws_response["DelaySeconds"].to_i - @receive_message_wait_timeout_seconds = aws_response["ReceiveMessageWaitTimeSeconds"].to_i - - # FIFO queues - these attributes only exist for FIFO queues, their presence indicates a FIFO - # queue - @is_fifo_queue = aws_response["FifoQueue"].nil? ? false : true - @content_based_deduplication = aws_response["ContentBasedDeduplication"].nil? ? false : true - rescue Aws::SQS::Errors::NonExistentQueue - @exists = false - end - - # Uses the SDK API to really talk to AWS - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::SQS::Client - - def get_queue_attributes(criteria) - aws_service_client.get_queue_attributes(criteria) - end - end - end -end diff --git a/lib/resources/aws/aws_subnet.rb b/lib/resources/aws/aws_subnet.rb deleted file mode 100644 index a8e7c3305..000000000 --- a/lib/resources/aws/aws_subnet.rb +++ /dev/null @@ -1,92 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsSubnet < Inspec.resource(1) - name "aws_subnet" - desc "This resource is used to test the attributes of a VPC subnet" - example <<~EXAMPLE - describe aws_subnet(subnet_id: 'subnet-12345678') do - it { should exist } - its('cidr_block') { should eq '10.0.1.0/24' } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - attr_reader :assigning_ipv_6_address_on_creation, :availability_zone, :available_ip_address_count, - :available, :cidr_block, :default_for_az, :ipv_6_cidr_block_association_set, - :mapping_public_ip_on_launch, :subnet_id, :vpc_id - alias available? available - alias default_for_az? default_for_az - alias mapping_public_ip_on_launch? mapping_public_ip_on_launch - alias assigning_ipv_6_address_on_creation? assigning_ipv_6_address_on_creation - - def to_s - "VPC Subnet #{@subnet_id}" - end - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:subnet_id], - allowed_scalar_name: :subnet_id, - allowed_scalar_type: String - ) - - # Make sure the subnet_id parameter was specified and in the correct form. - if validated_params.key?(:subnet_id) && validated_params[:subnet_id] !~ /^subnet\-[0-9a-f]{8}/ - raise ArgumentError, 'aws_subnet Subnet ID must be in the format "subnet-" followed by 8 hexadecimal characters.' - end - - if validated_params.empty? - raise ArgumentError, "You must provide a subnet_id to aws_subnet." - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - # Transform into filter format expected by AWS - filters = [] - filters.push({ name: "subnet-id", values: [@subnet_id] }) - ds_response = backend.describe_subnets(filters: filters) - - # If no subnets exist in the VPC, exist is false. - if ds_response.subnets.empty? - @exists = false - return - end - @exists = true - assign_properties(ds_response) - end - - def assign_properties(ds_response) - @vpc_id = ds_response.subnets[0].vpc_id - @subnet_id = ds_response.subnets[0].subnet_id - @cidr_block = ds_response.subnets[0].cidr_block - @availability_zone = ds_response.subnets[0].availability_zone - @available_ip_address_count = ds_response.subnets[0].available_ip_address_count - @default_for_az = ds_response.subnets[0].default_for_az - @mapping_public_ip_on_launch = ds_response.subnets[0].map_public_ip_on_launch - @available = ds_response.subnets[0].state == "available" - @ipv_6_cidr_block_association_set = ds_response.subnets[0].ipv_6_cidr_block_association_set - @assigning_ipv_6_address_on_creation = ds_response.subnets[0].assign_ipv_6_address_on_creation - end - - # Uses the SDK API to really talk to AWS - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::EC2::Client - - def describe_subnets(query) - aws_service_client.describe_subnets(query) - end - end - end -end diff --git a/lib/resources/aws/aws_subnets.rb b/lib/resources/aws/aws_subnets.rb deleted file mode 100644 index bc2ac4785..000000000 --- a/lib/resources/aws/aws_subnets.rb +++ /dev/null @@ -1,56 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsSubnets < Inspec.resource(1) - name "aws_subnets" - desc "Verifies settings for VPC Subnets in bulk" - example <<~EXAMPLE - # you should be able to test the cidr_block of a subnet - describe aws_subnets.where(vpc_id: 'vpc-123456789') do - its('subnet_ids') { should eq ['subnet-12345678', 'subnet-87654321'] } - its('cidr_blocks') { should eq ['172.31.96.0/20'] } - its('states') { should_not include 'pending' } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - def validate_params(resource_params) - unless resource_params.empty? - raise ArgumentError, "aws_vpc_subnets does not accept resource parameters." - end - - resource_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - @table = backend.describe_subnets.subnets.map(&:to_h) - end - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:vpc_ids, field: :vpc_id) - .register_column(:subnet_ids, field: :subnet_id) - .register_column(:cidr_blocks, field: :cidr_block) - .register_column(:states, field: :state) - filter.install_filter_methods_on_resource(self, :table) - - def to_s - "EC2 VPC Subnets" - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend self - self.aws_client_class = Aws::EC2::Client - - def describe_subnets(query = {}) - aws_service_client.describe_subnets(query) - end - end - end -end diff --git a/lib/resources/aws/aws_vpc.rb b/lib/resources/aws/aws_vpc.rb deleted file mode 100644 index 4e11fca5c..000000000 --- a/lib/resources/aws/aws_vpc.rb +++ /dev/null @@ -1,77 +0,0 @@ -require "resource_support/aws/aws_singular_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsVpc < Inspec.resource(1) - name "aws_vpc" - desc "Verifies settings for AWS VPC" - example <<~EXAMPLE - describe aws_vpc do - it { should be_default } - its('cidr_block') { should cmp '10.0.0.0/16' } - end - EXAMPLE - supports platform: "aws" - - include AwsSingularResourceMixin - - def to_s - "VPC #{vpc_id}" - end - - attr_reader :cidr_block, :dhcp_options_id, :instance_tenancy, :is_default, - :state, :vpc_id - - alias default? is_default - - private - - def validate_params(raw_params) - validated_params = check_resource_param_names( - raw_params: raw_params, - allowed_params: [:vpc_id], - allowed_scalar_name: :vpc_id, - allowed_scalar_type: String - ) - - if validated_params.key?(:vpc_id) && validated_params[:vpc_id] !~ /^vpc\-([0-9a-f]{8})|(^vpc\-[0-9a-f]{17})$/ - raise ArgumentError, 'aws_vpc VPC ID must be in the format "vpc-" followed by 8 or 17 hexadecimal characters.' - end - - validated_params - end - - def fetch_from_api - backend = BackendFactory.create(inspec_runner) - - if @vpc_id.nil? - filter = { name: "isDefault", values: ["true"] } - else - filter = { name: "vpc-id", values: [@vpc_id] } - end - - resp = backend.describe_vpcs({ filters: [filter] }) - - vpc = resp.vpcs[0].to_h - @exists = !vpc.empty? - return unless @exists - - @cidr_block = vpc[:cidr_block] - @dhcp_options_id = vpc[:dhcp_options_id] - @instance_tenancy = vpc[:instance_tenancy] - @is_default = vpc[:is_default] - @state = vpc[:state] - @vpc_id = vpc[:vpc_id] - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::EC2::Client - - def describe_vpcs(query) - aws_service_client.describe_vpcs(query) - end - end - end -end diff --git a/lib/resources/aws/aws_vpcs.rb b/lib/resources/aws/aws_vpcs.rb deleted file mode 100644 index 8865122a5..000000000 --- a/lib/resources/aws/aws_vpcs.rb +++ /dev/null @@ -1,55 +0,0 @@ -require "resource_support/aws/aws_plural_resource_mixin" -require "resource_support/aws/aws_backend_base" -require "aws-sdk-ec2" - -class AwsVpcs < Inspec.resource(1) - name "aws_vpcs" - desc "Verifies settings for AWS VPCs in bulk" - example <<~EXAMPLE - describe aws_vpcs do - it { should exist } - end - EXAMPLE - supports platform: "aws" - - include AwsPluralResourceMixin - - # Underlying FilterTable implementation. - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:cidr_blocks, field: :cidr_block) - .register_column(:vpc_ids, field: :vpc_id) - # We need a dummy here, so FilterTable will define and populate the dhcp_options_id field - filter.register_column(:dummy, field: :dhcp_options_id) - .register_column(:dhcp_options_ids) { |obj| obj.entries.map(&:dhcp_options_id).uniq } - filter.install_filter_methods_on_resource(self, :table) - - def validate_params(raw_params) - # No params yet - unless raw_params.empty? - raise ArgumentError, "aws_vpcs does not accept resource parameters" - end - - raw_params - end - - def to_s - "VPCs" - end - - def fetch_from_api - describe_vpcs_response = BackendFactory.create(inspec_runner).describe_vpcs - @table = describe_vpcs_response.to_h[:vpcs].map(&:to_h) - end - - class Backend - class AwsClientApi < AwsBackendBase - BackendFactory.set_default_backend(self) - self.aws_client_class = Aws::EC2::Client - - def describe_vpcs(query = {}) - aws_service_client.describe_vpcs(query) - end - end - end -end diff --git a/lib/resources/azure/azure_backend.rb b/lib/resources/azure/azure_backend.rb deleted file mode 100644 index 27eaf2b6b..000000000 --- a/lib/resources/azure/azure_backend.rb +++ /dev/null @@ -1,379 +0,0 @@ -# Base class for Azure Resources. This allows the generic class to work -# as well as the specific target resources for Azure Resources -# -# @author Russell Seymour -module Inspec::Resources - class AzureResourceBase < Inspec.resource(1) - attr_reader :opts, :client, :azure - - # Constructor that retrieves the specified resource - # - # The opts hash should contain the following - # :group_name - name of the resource group in which to look for items - # :type - the type of Azure resource to look for - # :apiversion - API version to use when looking for a specific resource - # :name - name of the resource to find - # - # @author Russell Seymour - # - # @param [Hash] opts Hashtable of options as highlighted above - # rubocop:disable Metrics/AbcSize - def initialize(opts) - # declare the hashtable of counts - @counts = {} - @total = 0 - @opts = opts - - # Determine if the environment variables for the options have been set - option_var_names = { - group_name: "AZURE_RESOURCE_GROUP_NAME", - name: "AZURE_RESOURCE_NAME", - type: "AZURE_RESOURCE_TYPE", - apiversion: "AZURE_RESOURCE_API_VERSION", - } - option_var_names.each do |option_name, env_var_name| - opts[option_name] = ENV[env_var_name] unless ENV[env_var_name].nil? - end - - @azure = inspec.backend - @client = azure.azure_client - @failed_resource = false - end - - def failed_resource? - @failed_resource - end - - def catch_azure_errors - yield - rescue MsRestAzure::AzureOperationError => e - # e.message is actually a massive stringified JSON, which might be useful in the future. - # You want error_message here. - fail_resource e.error_message - @failed_resource = true - nil - end - - # Return information about the resource group - def resource_group - catch_azure_errors do - resource_group = client.resource_groups.get(opts[:group_name]) - - # create the methods for the resource group object - dm = AzureResourceDynamicMethods.new - dm.create_methods(self, resource_group) - end - end - - def resources - resources = nil - catch_azure_errors do - resources = client.resources.list_by_resource_group(opts[:group_name]) - end - return if failed_resource? - - # filter the resources based on the type, and the name if they been specified - resources = filter_resources(resources, opts) - - # if there is one resource then define methods on this class - if resources.count == 1 - @total = 1 - - resource = nil - catch_azure_errors do - # get the apiversion for the resource, if one has not been specified - apiversion = azure.get_api_version(resources[0].type, opts) - - # get the resource by id so it can be interrogated - resource = client.resources.get_by_id(resources[0].id, apiversion) - end - return if failed_resource? - - dm = AzureResourceDynamicMethods.new - - dm.create_methods(self, resource) - else - - # As there are many resources, parse each one so that it can be - # interrogated by the FilterTable - # @probes = parse_resources(resources, azure) - @probes = resources.each.map do |item| - # update the total - @total += 1 - - # determine the counts for each type - namespace, type_name = item.type.split(/\./) - counts.key?(namespace) ? false : counts[namespace] = {} - counts[namespace].key?(type_name) ? counts[namespace][type_name] += 1 : counts[namespace][type_name] = 1 - - # get the detail about the resource - apiversion = azure.get_api_version(item.type, opts) - resource = client.resources.get_by_id(item.id, apiversion) - - # parse the resource - parse_resource(resource) - end.compact - - # Iterate around the counts and create the necessary classes - counts.each do |namespace, ns_counts| - define_singleton_method namespace do - AzureResourceTypeCounts.new(ns_counts) - end - end - end - end - - # Does the resource have any tags? - # - # If it is a Hashtable then it does not, because there was nothing to parse so there is not - # a nested object to work with - # - # @author Russell Seymour - def has_tags? - tags.is_a?(Hash) ? false : true - end - - # Returns how many tags have been set on the resource - # - # @author Russell Seymour - def tag_count - tags.count - end - - # It is necessary to be able to test the tags of a resource. It is possible to say of the - # resource has tags or not, and it is possible to check that the tags include a specific tag - # However the value is not accessible, this function creates methods for all the tags that - # are available. - # - # The format of the method name is '_tag' and will return the value of that tag - # - # Disabling rubopcop check. If this is set as a normal if..then..end statement there is a - # violation stating it should use a guard. When using a guard it throws this error - # - # @author Russell Seymour - def create_tag_methods - # Iterate around the items of the tags and create the necessary access methods - if defined?(tags.item) - tags.item.each do |name, value| - method_name = format("%s_tag", name) - define_singleton_method method_name do - value - end - end - end - end - - private - - # Filter the resources that are returned by the options that have been specified - # - def filter_resources(resources, opts) - if opts[:type] && opts[:name] - resources.select { |r| r.type == opts[:type] && r.name == opts[:name] } - elsif opts[:type] - resources.select { |r| r.type == opts[:type] } - elsif opts[:name] - resources.select { |r| r.name == opts[:name] } - else - resources - end - end - end -end - -# Class to create methods on the calling object at run time. -# Each of the Azure Resources have different attributes and properties, and they all need -# to be testable. To do this no methods are hardcoded, each on is craeted based on the -# information returned from Azure. -# -# The class is a helper class essentially as it creates the methods on the calling class -# rather than itself. This means that there is less duplication of code and it can be -# reused easily. -# -# @author Russell Seymour -# @since 0.2.0 -class AzureResourceDynamicMethods - # Given the calling object and its data, create the methods on the object according - # to the data that has been retrieved. Various types of data can be returned so the method - # checks the type to ensure that the necessary methods are configured correctly - # - # @param AzureResourceProbe|AzureResource object The object on which the methods should be craeted - # @param variant data The data from which the methods should be created - def create_methods(object, data) - # Check the type of data as this affects the setup of the methods - # If it is an Azure Generic Resource then setup methods for each of - # the instance variables - case data.class.to_s - when /^Azure::Resources::Mgmt::.*::Models::GenericResource$/, - /^Azure::Resources::Mgmt::.*::Models::ResourceGroup$/ - # iterate around the instance variables - data.instance_variables.each do |var| - create_method(object, var.to_s.delete("@"), data.instance_variable_get(var)) - end - # When the data is a Hash object iterate around each of the key value pairs and - # craete a method for each one. - when "Hash" - data.each do |key, value| - create_method(object, key, value) - end - end - end - - private - - # Method that is responsible for creating the method on the calling object. This is - # because some nesting maybe required. For example of the value is a Hash then it will - # need to have an AzureResourceProbe create for each key, whereas if it is a simple - # string then the value just needs to be returned - # - # @private - # - # @param AzureResourceProbe|AzureResource object Object on which the methods need to be created - # @param string name The name of the method - # @param variant value The value that needs to be returned by the method - def create_method(object, name, value) - # Create the necessary method based on the var that has been passed - # Test the value for its type so that the method can be setup correctly - case value.class.to_s - when "String", "Integer", "TrueClass", "FalseClass", "Fixnum" - object.define_singleton_method name do - value - end - when "Hash" - value.count == 0 ? return_value = value : return_value = AzureResourceProbe.new(value) - object.define_singleton_method name do - return_value - end - when /^Azure::Resources::Mgmt::.*::Models::ResourceGroupProperties$/ - # This is a special case where the properties of the resource group is not a simple JSON model - # This is because the plugin is using the Azure SDK to get this information so it is an SDK object - # that has to be interrogated in a different way. This is the only object type that behaves like this - value.instance_variables.each do |var| - create_method(object, var.to_s.delete("@"), value.instance_variable_get(var)) - end - when "Array" - # Some things are just string or integer arrays - # Check this by seeing if the first element is a string / integer / boolean or - # a hashtable - # This may not be the best methid, but short of testing all elements in the array, this is - # the quickest test - case value[0].class.to_s - when "String", "Integer", "TrueClass", "FalseClass", "Fixnum" - probes = value - else - probes = [] - value.each do |value_item| - probes << AzureResourceProbe.new(value_item) - end - end - object.define_singleton_method name do - probes - end - end - end -end - -# Class object to maintain a count of the Azure Resource types that are found -# when a less specific test is carried out. For example if all the resoures of a resource -# group are called for, there will be various types and number of those types. -# -# Each type is namespaced, so for example a virtual machine has the type 'Microsoft.Compute/virtualMachines' -# This is broken down into the 'Microsoft' class with the type 'Compute/virtualMachines' -# This has been done for two reasons: -# 1. Enable the dotted notation to work in the test -# 2. Allow third party resource types ot be catered for if they are ever enabled by Microsoft -# -# @author Russell Seymour -# @since 0.2.0 -class AzureResourceTypeCounts - # Constructor to setup a new class for a specific Azure Resource type. - # It should be passed a hashtable with information such as: - # { - # "Compute/virtualMachines" => 2, - # "Network/networkInterfaces" => 3 - # } - # This will result in two methods being created on the class: - # - Compute/virtualNetworks - # - Network/networkInterfaces - # Each of which will return the corresponding count value - # - # @param Hash counts Hash table of types and the count of each one - # - # @return AzureResourceTypeCounts - def initialize(counts) - counts.each do |type, count| - define_singleton_method type do - count - end - end - end -end - -# Class object that is created for each element that is returned by Azure. -# This is what is interrogated by InSpec. If they are nested hashes, then this results -# in nested AzureResourceProbe objects. -# -# For example, if the following was seen in an Azure Resource -# properties -> storageProfile -> imageReference -# Would result in the following nestec classes -# AzureResource -> AzureResourceProbe -> AzureResourceProbe -# -# The methods for each of the classes are dynamically defined at run time and will -# match the items that are retrieved from Azure. See the 'test/integration/verify/controls' for -# examples -# -# This class will not be called externally -# -# @author Russell Seymour -# @since 0.2.0 -# @attr_reader string name Name of the Azure resource -# @attr_reader string type Type of the Azure Resource -# @attr_reader string location Location in Azure of the resource -class AzureResourceProbe - attr_reader :name, :type, :location, :item, :count - - # Initialize method for the class. Accepts an item, be it a scalar value, hash or Azure object - # It will then create the necessary dynamic methods so that they can be called in the tests - # This is accomplished by call the AzureResourceDynamicMethods - # - # @param varaint The item from which the class will be initialized - # - # @return AzureResourceProbe - def initialize(item) - dm = AzureResourceDynamicMethods.new - dm.create_methods(self, item) - - # Set the item as a property on the class - # This is so that it is possible to interrogate what has been added to the class and isolate them from - # the standard methods that a Ruby class has. - # This used for checking Tags on a resource for example - # It also allows direct access if so required - @item = item - - # Set how many items have been set - @count = item.length - end - - # Allows resources to respond to the include test - # This means that things like tags can be checked for and then their value tested - # - # @author Russell Seymour - # - # @param [String] key Name of the item to look for in the @item property - def include?(key) - @item.key?(key) - end - - # Give a sting like `computer_name` return the camelCase version, e.g. - # computerName - # - # @param string data Data that needs to be converted from snake_case to camelCase - # - # @return string - def camel_case(data) - camel_case_data = data.split("_").inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join - - # Ensure that gb (as in gigabytes) is uppercased - camel_case_data.gsub(/[gb]/, &:upcase) - end -end diff --git a/lib/resources/azure/azure_generic_resource.rb b/lib/resources/azure/azure_generic_resource.rb deleted file mode 100644 index 0e2941b83..000000000 --- a/lib/resources/azure/azure_generic_resource.rb +++ /dev/null @@ -1,55 +0,0 @@ -require "resources/azure/azure_backend" -require "inspec/utils/filter" - -module Inspec::Resources - class AzureGenericResource < AzureResourceBase - name "azure_generic_resource" - - desc ' - InSpec Resource to interrogate any Resource type in Azure - ' - - supports platform: "azure" - - attr_accessor :filter, :total, :counts, :name, :type, :location, :probes - - def initialize(opts = {}) - Inspec.deprecate(:resource_azure_generic_resource) - - # Call the parent class constructor - super(opts) - - # Get the resource group - resource_group - - # Get the resources - resources - - # Create the tag methods - create_tag_methods - end - - # Define the filter table so that it can be interrogated - @filter = FilterTable.create - @filter.register_filter_method(:contains) - .register_column(:type, field: "type") - .register_column(:name, field: "name") - .register_column(:location, field: "location") - .register_column(:properties, field: "properties") - - @filter.install_filter_methods_on_resource(self, :probes) - - def parse_resource(resource) - # return a hash of information - parsed = { - "location" => resource.location, - "name" => resource.name, - "type" => resource.type, - "exist?" => true, - "properties" => AzureResourceProbe.new(resource.properties), - } - - parsed - end - end -end diff --git a/lib/resources/azure/azure_resource_group.rb b/lib/resources/azure/azure_resource_group.rb deleted file mode 100644 index e79a11e43..000000000 --- a/lib/resources/azure/azure_resource_group.rb +++ /dev/null @@ -1,151 +0,0 @@ -require "resources/azure/azure_backend" - -module Inspec::Resources - class AzureResourceGroup < AzureResourceBase - name "azure_resource_group" - - desc ' - InSpec Resource to get metadata about a specific Resource Group - ' - - supports platform: "azure" - - attr_reader :name, :location, :id, :total, :counts, :mapping - - # Constructor to get the resource group itself and perform some analysis on the - # resources that in the resource group. - # - # This analysis is defined by the the mapping hashtable which is used to define - # the 'has_xxx?' methods (see AzureResourceGroup#create_has_methods) and return - # the counts for each type - # - # @author Russell Seymour - def initialize(opts) - opts.key?(:name) ? opts[:group_name] = opts[:name] : false - # Ensure that the opts only have the name of the resource group set - opts.select! { |k, _v| k == :group_name } - super(opts) - - # set the mapping for the Azure Resources - @mapping = { - nic: "Microsoft.Network/networkInterfaces", - vm: "Microsoft.Compute/virtualMachines", - extension: "Microsoft.Compute/virtualMachines/extensions", - nsg: "Microsoft.Network/networkSecurityGroups", - vnet: "Microsoft.Network/virtualNetworks", - managed_disk: "Microsoft.Compute/disks", - managed_disk_image: "Microsoft.Compute/images", - sa: "Microsoft.Storage/storageAccounts", - public_ip: "Microsoft.Network/publicIPAddresses", - } - - # Get information about the resource group itself - resource_group - - # Get information about the resources in the resource group - resources - - # Call method to create the has_xxxx? methods - create_has_methods - - # Call method to allow access to the tag values - create_tag_methods - end - - # Return the provisioning state of the resource group - # - # @author Russell Seymour - def provisioning_state - properties.provisioningState - end - - # Analyze the fully qualified id of the resource group to return the subscription id - # that this resource group is part of - # - # The format of the id is - # /subscriptions//resourceGroups/ - # - # @author Russell Seymour - def subscription_id - id.split(%r{\/}).reject(&:empty?)[1] - end - - # Method to parse the resources that have been returned - # This allows the calculations of the amount of resources to be determined - # - # @author Russell Seymour - # - # @param [Hash] resource A hashtable representing the resource group - def parse_resource(resource) - # return a hash of information - parsed = { - "name" => resource.name, - "type" => resource.type, - } - - parsed - end - - # This method catches the xxx_count calls that are made on the resource. - # - # The method that is called is stripped of '_count' and then compared with the - # mappings table. If that type exists then the number of those items is returned. - # However if that type is not in the Resource Group then the method will return - # a NoMethodError exception - # - # @author Russell Seymour - # - # @param [Symbol] method_id The name of the method that was called - def method_missing(method_id) - # Determine the mapping_key based on the method_id - mapping_key = method_id.to_s.chomp("_count").to_sym - - if mapping.key?(mapping_key) - # based on the method id get the - namespace, type_name = mapping[mapping_key].split(/\./) - - # check that the type_name is defined, if not return 0 - if send(namespace).methods.include?(type_name.to_sym) - # return the count for the method id - send(namespace).send(type_name) - else - 0 - end - else - msg = format("undefined method `%s` for %s", method_id, self.class) - raise NoMethodError, msg - end - end - - private - - # For each of the mappings this method creates the has_xxx? method. This allows the use - # of the following type of test - # - # it { should have_nics } - # - # For example, it will create a has_nics? method that returns a boolean to state of the - # resource group has any nics at all. - # - # @author Russell Seymour - # @private - def create_has_methods - return if failed_resource? - - # Create the has methods for each of the mappings - # This is a quick test to show that the resource group has at least one of these things - mapping.each do |name, type| - # Determine the name of the method name - method_name = format("has_%ss?", name) - namespace, type_name = type.split(/\./) - - # use the namespace and the type_name to determine if the resource group has this type or not - result = send(namespace).methods.include?(type_name.to_sym) ? true : false - - define_singleton_method method_name do - result - end - end - end - end -end diff --git a/lib/resources/azure/azure_virtual_machine.rb b/lib/resources/azure/azure_virtual_machine.rb deleted file mode 100644 index 90ca23855..000000000 --- a/lib/resources/azure/azure_virtual_machine.rb +++ /dev/null @@ -1,262 +0,0 @@ -require "resources/azure/azure_backend" - -module Inspec::Resources - class AzureVirtualMachine < AzureResourceBase - name "azure_virtual_machine" - - desc ' - InSpec Resource to test Azure Virtual Machines - ' - - supports platform: "azure" - - # Constructor for the resource. This calls the parent constructor to - # get the generic resource for the specified machine. This will provide - # static methods that are documented - # - # @author Russell Seymour - def initialize(opts = {}) - # The generic resource needs to pass back a Microsoft.Compute/virtualMachines object so force it - opts[:type] = "Microsoft.Compute/virtualMachines" - super(opts) - - # Find the virtual machines - resources - - create_tag_methods - end - - # Method to catch calls that are not explicitly defined. - # This allows the simple attributes of the virtual machine to be read without having - # to define each one in turn. - # - # rubocop:disable Metrics/AbcSize - # - # @param symobl method_id The symbol of the method that has been called - # - # @return Value of attribute that has been called - def method_missing(method_id) - # Depending on the method that has been called, determine what value should be returned - # These are set as camel case methods to comply with rubocop - image_reference_attrs = %w{sku publisher offer} - osdisk_attrs = %w{os_type caching create_option disk_size_gb} - hardware_profile_attrs = %w{vm_size} - os_profile_attrs = %w{computer_name admin_username} - osdisk_managed_disk_attrs = %w{storage_account_type} - - # determine the method name to call by converting the snake_case to camelCase - # method_name = self.camel_case(method_id.to_s) - method_name = method_id.to_s.split("_").inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join - method_name.end_with?("Gb") ? method_name.gsub!(/Gb/, &:upcase) : false - - if image_reference_attrs.include?(method_id.to_s) - properties.storageProfile.imageReference.send(method_name) - elsif osdisk_attrs.include?(method_id.to_s) - properties.storageProfile.osDisk.send(method_name) - elsif hardware_profile_attrs.include?(method_id.to_s) - properties.hardwareProfile.send(method_name) - elsif os_profile_attrs.include?(method_id.to_s) - properties.osProfile.send(method_name) - elsif osdisk_managed_disk_attrs.include?(method_id.to_s) - properties.storageProfile.osDisk.managedDisk.send(method_name) - end - end - - # Return the name of the os disk - # - # @return string Name of the OS disk - def os_disk_name - properties.storageProfile.osDisk.name - end - - # Determine if the OS disk is a managed disk - # - # @return boolean - def has_managed_osdisk? - defined?(properties.storageProfile.osDisk.managedDisk) - end - - # Does the machine have any NICs connected - # - # @return boolean - def has_nics? - properties.networkProfile.networkInterfaces.count != 0 - end - - # How many NICs are connected to the machine - # - # @return integer - def nic_count - properties.networkProfile.networkInterfaces.count - end - - # Return an array of the connected NICs so that it can be tested to ensure - # the machine is connected properly - # - # @return array Array of NIC names connected to the machine - def connected_nics - nic_names = [] - properties.networkProfile.networkInterfaces.each do |nic| - nic_names << nic.id.split(%r{/}).last - end - nic_names - end - - # Whether the machine has data disks or not - # - # @return boolean - def has_data_disks? - properties.storageProfile.dataDisks.count != 0 - end - - # How many data disks are connected - # - # @return integer - def data_disk_count - properties.storageProfile.dataDisks.count - end - - # Does the machine allow password authentication - # - # This allows the use of - # it { should have_password_authentication } - # within the InSpec profile - # - # @return boolean - def has_password_authentication? - password_authentication? - end - - # Determine if the machine allows password authentication - # - # @return boolean - def password_authentication? - # if the osProfile property has a linuxConfiguration section then interrogate that - # otherwise it is a Windows machine and that always has password auth - if defined?(properties.osProfile.linuxConfiguration) - !properties.osProfile.linuxConfiguration.disablePasswordAuthentication - else - true - end - end - - # Has the machine been given Custom Data at creation - # - # This allows the use of - # it { should have_custom_data } - # within the InSpec Profile - # - # @return boolean - def has_custom_data? - custom_data? - end - - # Determine if custom data has been set - # - # @return boolean - def custom_data? - if defined?(properties.osProfile.CustomData) - true - else - false - end - end - - # Are any SSH Keys assigned to the machine - # - # This allows the use of - # it { should have_ssh_keys } - # within the InSpec Profile - # - # @return boolean - def has_ssh_keys? - ssh_keys? - end - - # Determine if any ssh keys have been asigned to the machine - # - # @return boolean - def ssh_keys? - if defined?(properties.osProfile.linuxConfiguration.ssh) - properties.osProfile.linuxConfiguration.ssh.publicKeys != 0 - else - false - end - end - - # Return the number of ssh keys that have been assigned to the machine - # - # @return integer - def ssh_key_count - if defined?(properties.osProfile.linuxConfiguration.ssh) - properties.osProfile.linuxConfiguration.ssh.publicKeys.count - else - 0 - end - end - - # Determine is the specified key is in the ssh_keys list - # - # @return array Array of the public keys that are assigned to allow for testing of that key - def ssh_keys - # iterate around the keys - keys = [] - properties.osProfile.linuxConfiguration.ssh.publicKeys.each do |key| - keys << key.keyData - end - keys - end - - # Does the machine have boot diagnostics enabled - # - # @return boolean - def has_boot_diagnostics? - if defined?(properties.diagnosticsProfile) - properties.diagnosticsProfile.bootDiagnostics.enabled - else - false - end - end - - # Return the URI that has been set for the boot diagnostics storage - # - # @return string - def boot_diagnostics_storage_uri - properties.diagnosticsProfile.bootDiagnostics.storageUri - end - - # If this is a windows machine, returns whether the agent was provisioned or not - # - # @return boolean - def has_provision_vmagent? - if defined?(properties.osProfile.windowsConfiguration) - properties.osProfile.windowsConfiguration.provisionVMAgent - else - false - end - end - - # If a windows machine see if automatic updates for the agent are enabled - # - # @return boolean - def has_automatic_agent_update? - if defined?(properties.osProfile.windowsConfiguration) - properties.osProfile.windowsConfiguration.enableAutomaticUpdates - else - false - end - end - - # If this is a windows machine return a boolean to state of the WinRM options - # have been set - # - # @return boolean - def has_winrm_options? - if defined?(properties.osProfile.windowsConfiguration) && defined?(properties.osProfile.windowsConfiguration.winrm) - properties.osProfile.windowsConfiguration.winrm.protocol - else - false - end - end - end -end diff --git a/lib/resources/azure/azure_virtual_machine_data_disk.rb b/lib/resources/azure/azure_virtual_machine_data_disk.rb deleted file mode 100644 index 1559c1818..000000000 --- a/lib/resources/azure/azure_virtual_machine_data_disk.rb +++ /dev/null @@ -1,131 +0,0 @@ -require "resources/azure/azure_backend" -require "uri" unless defined?(URI) - -module Inspec::Resources - class AzureVirtualMachineDataDisk < AzureResourceBase - name "azure_virtual_machine_data_disk" - - desc ' - InSpec Resource to ensure that the data disks attached to a machine are correct - ' - - supports platform: "azure" - - # Create a filter table so that tests on the disk can be performed - filter = FilterTable.create - filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? } - filter.register_column(:disk, field: :disk) - .register_column(:number, field: :number) - .register_column(:name, field: :name) - .register_column(:size, field: :size) - .register_column(:vhd_uri, field: :vhd_uri) - .register_column(:storage_account_name, field: :storage_account_name) - .register_column(:lun, field: :lun) - .register_column(:caching, field: :caching) - .register_column(:create_option, field: :create_option) - .register_column(:is_managed_disk?, field: :is_managed_disk?) - .register_column(:storage_account_type, field: :storage_account_type) - .register_column(:subscription_id, field: :subscription_id) - .register_column(:resource_group, field: :resource_group) - filter.install_filter_methods_on_resource(self, :datadisk_details) - - # Constructor for the resource. This calls the parent constructor to - # get the generic resource for the specified machine. This will provide - # static methods that are documented - # - # @author Russell Seymour - def initialize(opts = {}) - # The generic resource needs to pass back a Microsoft.Compute/virtualMachines object so force it - opts[:type] = "Microsoft.Compute/virtualMachines" - super(opts) - - # Get the data disks - resources - end - - # Return information about the disks and add to the filter table so that - # assertions can be performed - # - # @author Russell Seymour - def datadisk_details - return if failed_resource? - - # Iterate around the data disks on the machine - properties.storageProfile.dataDisks.each_with_index.map do |datadisk, index| - # Call function to parse the data disks and return an object based on the parameters - parse_datadisk(datadisk, index) - end - end - - # Return boolean to denote if the machine has data disks attached or not - def has_data_disks? - !entries.empty? - end - - # Return an integer stating how many data disks are attached to the machine - def count - entries.count - end - - # Return boolean to state if the machine is using managed disks for data disks - def has_managed_disks? - # iterate around the entries - result = entries.each.select { |e| e[:is_managed_disk?] } - result.empty? ? false : true - end - - private - - # Parse the data disk to determine if these are managed disks or in a storage account - # for example. The disk index, name and size will be returned - # - # params object disk Object containing the details of the disk - # params integer index Index denoting which disk number this is on the machine - # - # return hashtable - def parse_datadisk(disk, index) - # Configure parsed hashtable to hold the information - # Initialize this with common attributes from the different types of disk - parsed = { - disk: index, - number: index + 1, - lun: disk.lun, - name: disk.name, - size: disk.diskSizeGB, - caching: disk.caching, - create_option: disk.createOption, - } - - # Determine if the current disk is a managed disk or not - if defined?(disk.vhd) - # As this is in a storage account this is not a managed disk - parsed[:is_managed_disk?] = false - - # Set information about the disk - # Parse the uri of the disk URI so that the storage account can be retrieved - uri = URI.parse(disk.vhd.uri) - parsed[:vhd_uri] = disk.vhd.uri - parsed[:storage_account_name] = uri.host.split(".").first - - elsif defined?(disk.managedDisk) - # State that this is a managed disk - parsed[:is_managed_disk?] = true - - # Get information about the managed disk - parsed[:storage_account_type] = disk.managedDisk.storageAccountType - parsed[:id] = disk.managedDisk.id - - # Break up the ID string so that the following information can get retrieved - # - subscription_id - # - resource_group - id_parts = parsed[:id].split(%r{/}).reject(&:empty?) - - parsed[:subscription_id] = id_parts[1] - parsed[:resource_group] = id_parts[3] - end - - # return the parsed object - parsed - end - end -end diff --git a/test/fixtures/files/aws_billing_backend.rb b/test/fixtures/files/aws_billing_backend.rb deleted file mode 100644 index 22a523c5d..000000000 --- a/test/fixtures/files/aws_billing_backend.rb +++ /dev/null @@ -1,102 +0,0 @@ -require "resource_support/aws" - -module MockAwsBillingReports - class Empty < AwsBackendBase - def describe_report_definitions(_query) - Aws::CostandUsageReportService::Types::DescribeReportDefinitionsResponse.new(report_definitions: []) - end - end - - class Basic < AwsBackendBase - def describe_report_definitions(_query) - Aws::CostandUsageReportService::Types::DescribeReportDefinitionsResponse - .new(report_definitions: - [ - Aws::CostandUsageReportService::Types::ReportDefinition.new( - report_name: "inspec1", - time_unit: "HOURLY", - format: "textORcsv", - compression: "ZIP", - s3_bucket: "inspec1-s3-bucket", - s3_prefix: "inspec1/accounting", - s3_region: "us-east-1" - ), - Aws::CostandUsageReportService::Types::ReportDefinition.new( - report_name: "inspec2", - time_unit: "DAILY", - format: "textORcsv", - compression: "GZIP", - s3_bucket: "inspec2-s3-bucket", - s3_prefix: "inspec2/accounting", - s3_region: "us-west-1" - ), - ]) - end - end - - # This backend will always repond with 5 reports, as if the `max_results` option was passed to - # `#describe_report_definitions`. I chose 5 because when using `max_results` in the real world - # it seems to only accept a value of 5. - # - # == Returns: - # A Aws::CostandUsageReportService::Types::DescribeReportDefinitionsRespons object with two instance - # properties: - # `report_definitions` An Array that includes a single page of 5 Reports. - # `next_token` A String set to the start of the next page. When `next_token` is nil, there are no more pages. - # - class Paginated < AwsBackendBase - - # Generate a set of report data, and shuffle their order. - def generate_definitions - definitions = [] - - definitions << Aws::CostandUsageReportService::Types::ReportDefinition.new( - report_name: "inspec1", - time_unit: "HOURLY", - format: "textORcsv", - compression: "ZIP", - s3_bucket: "inspec1-s3-bucket", - s3_prefix: "inspec1/accounting", - s3_region: "us-east-1" - ) - definitions << Aws::CostandUsageReportService::Types::ReportDefinition.new( - report_name: "inspec2", - time_unit: "DAILY", - format: "textORcsv", - compression: "GZIP", - s3_bucket: "inspec2-s3-bucket", - s3_prefix: "inspec2/accounting", - s3_region: "us-west-1" - ) - - (3..12).each do |i| - definitions << - Aws::CostandUsageReportService::Types::ReportDefinition.new( - report_name: "inspec#{i}", - time_unit: %w{HOURLY DAILY}.sample, - format: "textORcsv", - compression: %w{ZIP GZIP}.sample, - s3_bucket: "inspec#{i}-s3-bucket", - s3_prefix: "inspec#{i}", - s3_region: "us-east-1" - ) - end - - definitions.shuffle - end - - def describe_report_definitions(options = {}) - @definitions ||= generate_definitions - - starting_position = options.fetch(:next_token, 0) - selected_definitions = @definitions.slice(starting_position, 5).compact - next_token = starting_position + 5 - next_token = @definitions.count < next_token ? nil : next_token - - response = Aws::CostandUsageReportService::Types::DescribeReportDefinitionsResponse - .new(report_definitions: selected_definitions) - response.next_token = next_token - response - end - end -end diff --git a/test/integration/aws/TESTING_AGAINST_AWS.md b/test/integration/aws/TESTING_AGAINST_AWS.md deleted file mode 100644 index 6ae65c777..000000000 --- a/test/integration/aws/TESTING_AGAINST_AWS.md +++ /dev/null @@ -1,108 +0,0 @@ -# Testing Against AWS - Integration Testing - -## Problem Statement - -We want to be able to test AWS-related InSpec resources against AWS itself. This means we need to create constructs ("test fixtures") in AWS to examine using InSpec. For cost management, we also want to be able to destroy - -## General Approach - -We use Terraform to setup test fixtures in AWS, then run a defined set of InSpec controls against these (which should all pass), and finally tear down the test fixtures with Terraform. For fixtures that cannot be managed by Terraform, we manually setup fixtures using instructions below. - -We use the AWS CLI credentials system to manage credentials. - - -### Installing Terraform - -Download [Terraform](https://www.terraform.io/downloads.html). We require at least v0.10. To install and choose from multiple Terraform versions, consider using [tfenv](https://github.com/kamatama41/tfenv). - -### Installing AWS CLI - -Install the [AWS CLI](http://docs.aws.amazon.com/cli/latest/userguide/installing.html). We will store profiles for testing in the `~/.aws/credentials` file. - -## Limitations - -There are some things that we can't (or very much shouldn't) do via Terraform - like manipulating the root account MFA settings. - -Also, there are some singleton resources (such as the default VPC, or Config status) that we should not manipulate without consequences. - -## Current Solution - -Our solution is to create two AWS accounts, each dedicated to the task of integration testing inspec-aws. - -In the "default" account, we setup all fixtures that can be handled by Terraform. For any remaining fixtures, -such as enabling MFA on the root account, we manually set one value in the "default" account, and manually set the opposing value in the "minimal" account. This allows use to perform testing on any reachable resource or property, regardless of whether or not Terraform can manage it. - -All tests (and test fixtures) that do not require special handling are placed in the "default" set. That includes both positive and negative checks. - -Note that some tests will fail for the first day or two after you set up the accounts, due to the tests checking properties such as the last usage time of an access key, for example. - -Additionally, the first time you run the tests, you will need to accept the user agreement in the AWS marketplace for the linux AMIs we use. You'll need to do it 4 times, once for each of debian and centos on the two accounts. - -### Creating the Default account - -Follow these instructions carefully. Do not perform any action not specified. - -1. Create an AWS account. Make a note of the account email and root password in a secure secret storage system. -2. Create an IAM user named `test-fixture-maker`. - * Enable programmatic access (to generate an access key) - * Direct-attach the policy AdministratorAccess - * Note the access key and secret key ID that are generated. -3. Using the aws command line tool, store the access key and secret key in a profile with a special name: - `aws configure --profile inspec-aws-test-default` - -#### Test Fixtures for the Default Account - -1. As the root user, enable a virtual MFA device. -2. Create an IAM user named 'test-user-last-key-use'. - * Enable programmatic access (to generate an access key) - * Note the access key and secret key ID that are generated. - * Direct-attach the policy AmazonEC2ReadOnlyAccess - * Using the AWS CLI and the credentials, execute the command `aws ec2 describe-instances`. - * The goal here is to have an access key that was used at one point. - -### Creating the Minimal Account - -Follow these instructions carefully. Do not perform any action not specified. - -1. Create an AWS account. Make a note of the account email and root password in a secure secret storage system. -2. Create an IAM user named `test-fixture-maker`. - * Enable programmatic access (to generate an access key) - * Direct-attach the policy AdministratorAccess - * Note the access key and secret key ID that are generated. -3. Using the aws command line tool, store the access key and secret key in a profile with a special name: - `aws configure --profile inspec-aws-test-minimal` - -#### Test Fixtures for the Minimal Account - -1. Create an Access Key for the root user. You do not have to save the access key. - -## Running the integration tests - -To run all AWS integration tests, run: - - ``` - bundle exec rake test:aws - ``` - -To run the tests against one account only: - - ``` - bundle exec rake test:aws:default - ``` - - or - - ``` - bundle exec rake test:aws:minimal - ``` - -Each account has separate tasks for setup, running the tests, and cleanup. You may run them separately: - -``` -bundle exec rake test:aws:setup:default -bundle exec rake test:aws:run:default -bundle exec rake test:aws:cleanup:default -``` - - - diff --git a/test/integration/aws/default/build/aws.tf b/test/integration/aws/default/build/aws.tf deleted file mode 100644 index 57de435d9..000000000 --- a/test/integration/aws/default/build/aws.tf +++ /dev/null @@ -1,22 +0,0 @@ -terraform { - required_version = "~> 0.11.0" -} - -provider "aws" { - # was 1.13.0 - version = "= 1.42.0" -} - -data "aws_caller_identity" "creds" {} - -output "aws_account_id" { - value = "${data.aws_caller_identity.creds.account_id}" -} - -data "aws_region" "current" {} - -output "aws_region" { - value = "${data.aws_region.current.name}" -} - -data "aws_availability_zones" "available" {} \ No newline at end of file diff --git a/test/integration/aws/default/build/cloudtrail.tf b/test/integration/aws/default/build/cloudtrail.tf deleted file mode 100644 index f4aefa352..000000000 --- a/test/integration/aws/default/build/cloudtrail.tf +++ /dev/null @@ -1,230 +0,0 @@ -resource "aws_s3_bucket" "trail_1_bucket" { - bucket = "${terraform.env}-trail-01-bucket" - force_destroy = true - - policy = < 3 } - end - - describe aws_config_delivery_channel do - its('channel_name') { should eq fixtures['delivery_channel_01_name'] } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_config_recorder.rb b/test/integration/aws/default/verify/controls/aws_config_recorder.rb deleted file mode 100644 index 85461827e..000000000 --- a/test/integration/aws/default/verify/controls/aws_config_recorder.rb +++ /dev/null @@ -1,62 +0,0 @@ -fixtures = {} -[ - 'role_for_config_recorder_arn', - 'config_recorder_name', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/config.tf', - ) -end - -#======================================================# -# aws_config_recorder - Singular -#======================================================# - -#------------------- Recall / Miss -------------------# - -control "aws_config_recorder recall" do - - # Get the singleton if you don't pass a name - describe aws_config_recorder do - it { should exist } - end - - # Test scalar param - describe aws_config_recorder(fixtures['config_recorder_name']) do - it { should exist } - end - - # Test hash parameter - describe aws_config_recorder(recorder_name: fixtures['config_recorder_name']) do - it { should exist } - end - - # Test recorder that doesnt exist - describe aws_config_recorder(recorder_name: 'NonExistentRecorder') do - it { should_not exist } - end -end - -#------------------- Properties -------------------# -control "aws_config_recorder properties" do - describe aws_config_recorder do - its('recorder_name') { should eq fixtures['config_recorder_name'] } - end - - describe aws_config_recorder(fixtures['config_recorder_name']) do - its('recorder_name') { should eq fixtures['config_recorder_name'] } - its('role_arn') { should eq fixtures['role_for_config_recorder_arn'] } - its('resource_types') { should eq [] } - end -end - -#------------------- Matchers -------------------# -control "aws_config_recorder matchers" do - describe aws_config_recorder(fixtures['config_recorder_name']) do - it { should_not be_recording } - it { should be_recording_all_resource_types } - it { should_not be_recording_all_global_types } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_ec2_instance.rb b/test/integration/aws/default/verify/controls/aws_ec2_instance.rb deleted file mode 100644 index a7296051c..000000000 --- a/test/integration/aws/default/verify/controls/aws_ec2_instance.rb +++ /dev/null @@ -1,77 +0,0 @@ -fixtures = {} -[ - 'ec2_instance_recall_hit_id', - 'ec2_instance_recall_hit_name', - 'ec2_instance_recall_miss', - 'ec2_instance_no_role_id', - 'ec2_instance_has_role_id', - 'ec2_instance_type_t2_micro_id', - 'ec2_instance_type_t2_small_id', - 'ec2_instance_centos_id', - 'ec2_ami_id_centos', - 'ec2_instance_debian_id', - 'ec2_ami_id_debian', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -#------------------- Recall / Miss -------------------# -control "aws_ec_instance - Recall" do - describe aws_ec2_instance(fixtures['ec2_instance_recall_miss']) do - it { should_not exist } - end - - # Recall by ID - describe aws_ec2_instance(fixtures['ec2_instance_recall_hit_id']) do - it { should exist } - end - - # Recall by Name tag - describe aws_ec2_instance(name: fixtures['ec2_instance_recall_hit_name']) do - it { should exist } - end -end - -# TODO: Most properties are untested. Some to consider including: -# security_groups -# state -# vpc_id -# tags - - -#----------------- has_role property ------------------# -control "aws_ec2_instance - has_role property" do - - describe aws_ec2_instance(fixtures['ec2_instance_has_role_id']) do - it { should have_roles } # TODO: this is a misnomer, you may have only one role attached - end - - describe aws_ec2_instance(fixtures['ec2_instance_no_role_id']) do - it { should_not have_roles } # TODO: this is a misnomer, you may have only one role attached - end -end - -#----------------- instance_type property ------------------# -control "aws_ec2_instance - instance_type property" do - describe aws_ec2_instance(fixtures['ec2_instance_type_t2_micro_id']) do - its('instance_type') { should eq 't2.micro' } - end - describe aws_ec2_instance(fixtures['ec2_instance_type_t2_small_id']) do - its('instance_type') { should eq 't2.small' } - end -end - -#-------------------- image_id property --------------------# -control "aws_ec2_instance - image_id property" do - describe aws_ec2_instance(fixtures['ec2_instance_centos_id']) do - its('image_id') { should eq fixtures['ec2_ami_id_centos'] } - end - - describe aws_ec2_instance(fixtures['ec2_instance_debian_id']) do - its('image_id') { should eq fixtures['ec2_ami_id_debian'] } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_ec2_instances.rb b/test/integration/aws/default/verify/controls/aws_ec2_instances.rb deleted file mode 100644 index 86ba35d47..000000000 --- a/test/integration/aws/default/verify/controls/aws_ec2_instances.rb +++ /dev/null @@ -1,30 +0,0 @@ -fixtures = {} -[ - 'ec2_instance_recall_miss', - 'ec2_instance_centos_id', - 'ec2_instance_debian_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -#------------------- Recall / Miss -------------------# -control "aws_ec_instances - Recall" do - describe aws_ec2_instances do - it { should exist } - end -end - -#------------------- Property instance_ids -------------# -control "aws_ec_instances - instance_ids property" do - describe aws_ec2_instances do - its('instance_ids') { should_not be_empty } - its('instance_ids') { should include fixtures['ec2_instance_centos_id'] } - its('instance_ids') { should include fixtures['ec2_instance_debian_id'] } - its('instance_ids') { should_not include fixtures['ec2_instance_recall_miss'] } - its('instance_ids') { should_not include nil } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_eks_cluster.rb b/test/integration/aws/default/verify/controls/aws_eks_cluster.rb deleted file mode 100644 index 3ace63eaa..000000000 --- a/test/integration/aws/default/verify/controls/aws_eks_cluster.rb +++ /dev/null @@ -1,45 +0,0 @@ -fixtures = {} -[ - 'eks_cluster_id', - 'eks_cluster_name', - 'eks_cluster_security_group_id', - 'eks_vpc_subnets', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/eks.tf', - ) -end - -control "aws_eks_cluster recall" do - - describe aws_eks_cluster(fixtures['eks_cluster_id']) do - it { should exist } - end - - describe aws_eks_cluster('i-dont-exist') do - it { should_not exist } - end - -end - -control "aws_eks_cluster properties" do - describe aws_eks_cluster(fixtures['eks_cluster_id']) do - its('name') { should eq fixtures['eks_cluster_name'] } - its('status') { should be_in %w(ACTIVE CREATING) } - its('subnets_count') { should eq 3 } - its('security_groups_count') { should eq 1 } - - fixtures['eks_vpc_subnets'].each do |subnet| - its('subnet_ids') { should include (subnet) } - end - end -end - -control "aws_eks_cluster matchers" do - describe aws_eks_cluster(fixtures['eks_cluster_id']) do - it { should exist } - it { should be_active } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_elb.rb b/test/integration/aws/default/verify/controls/aws_elb.rb deleted file mode 100644 index 56dc31a18..000000000 --- a/test/integration/aws/default/verify/controls/aws_elb.rb +++ /dev/null @@ -1,86 +0,0 @@ -fixtures = {} -[ - 'aws_region', - 'elb_subnet_a_id', - 'elb_subnet_c_id', - 'elb_alpha_name', - 'elb_alpha_dns_name', - 'elb_beta_name', - 'elb_beta_dns_name', - 'elb_beta_instance_1_id', - 'elb_beta_instance_2_id', - 'elb_security_group_to_instances_id', - 'elb_security_group_to_lb_id', - 'elb_vpc_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -#------------------- Search / Recall -------------------# -control "aws_elb - search" do - describe aws_elb(fixtures['elb_alpha_name']) do - it { should exist } - end - describe aws_elb(elb_name: fixtures['elb_beta_name']) do - it { should exist } - end - describe aws_elb('nonesuch') do - it { should_not exist } - end -end - - -# #------------------- Properties -------------# -control "aws_elb properties" do - - describe aws_elb(fixtures['elb_alpha_name']) do - its('availability_zones') { should include fixtures['aws_region'] + 'a' } - its('availability_zones.count') { should cmp 1 } - its('dns_name') { should match /elb\.amazonaws\.com$/ } - its('external_ports') { should include 80 } - its('external_ports.count') { should cmp 1 } - its('instance_ids') { should be_empty } - its('internal_ports') { should include 8080 } - its('internal_ports.count') { should cmp 1 } - its('security_group_ids') { should include fixtures['elb_security_group_to_lb_id']} - its('security_group_ids.count') { should cmp 1 } - its('subnet_ids') { should include fixtures['elb_subnet_a_id']} - its('subnet_ids.count') { should cmp 1 } - its('vpc_id') { should cmp fixtures['elb_vpc_id']} - end - - describe aws_elb(fixtures['elb_beta_name']) do - its('availability_zones') { should include fixtures['aws_region'] + 'a' } - its('availability_zones') { should include fixtures['aws_region'] + 'c' } - its('availability_zones.count') { should cmp 2 } - its('dns_name') { should match /elb\.amazonaws\.com$/ } - its('external_ports') { should include 80 } - its('external_ports.count') { should cmp 1 } - its('instance_ids') { should include fixtures['elb_beta_instance_1_id']} - its('instance_ids') { should include fixtures['elb_beta_instance_2_id']} - its('instance_ids.count') { should cmp 2 } - its('internal_ports') { should include 80 } - its('internal_ports.count') { should cmp 1 } - its('security_group_ids') { should include fixtures['elb_security_group_to_lb_id']} - its('security_group_ids.count') { should cmp 1 } - its('subnet_ids') { should include fixtures['elb_subnet_a_id']} - its('subnet_ids') { should include fixtures['elb_subnet_c_id']} - its('subnet_ids.count') { should cmp 2 } - its('vpc_id') { should cmp fixtures['elb_vpc_id']} - end - - describe aws_elb('nonesuch') do - its('availability_zones') { should be_empty } - its('dns_name') { should be_nil } - its('external_ports') { should be_empty } - its('instance_ids') { should be_empty } - its('internal_ports') { should be_empty } - its('security_group_ids') { should be_empty } - its('subnet_ids') { should be_empty } - its('vpc_id') { should be_nil } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_elbs.rb b/test/integration/aws/default/verify/controls/aws_elbs.rb deleted file mode 100644 index 298cb9e08..000000000 --- a/test/integration/aws/default/verify/controls/aws_elbs.rb +++ /dev/null @@ -1,128 +0,0 @@ -fixtures = {} -[ - 'aws_region', - 'elb_subnet_a_id', - 'elb_subnet_c_id', - 'elb_alpha_name', - 'elb_alpha_dns_name', - 'elb_beta_name', - 'elb_beta_dns_name', - 'elb_beta_instance_1_id', - 'elb_beta_instance_2_id', - 'elb_security_group_to_instances_id', - 'elb_security_group_to_lb_id', - 'elb_vpc_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -#------------------- Recall / Miss -------------------# -control "aws_elbs - Recall" do - describe aws_elbs do - it { should exist } - end - describe aws_elbs.where(elb_name: 'nonesuch') do - it { should_not exist } - end -end - -#------------------- Filtering -------------------# -control "aws_elbs - filtering" do - elbs = aws_elbs - - # Alpha is in a only - # Beta is in a and c - region = fixtures['aws_region'] - describe elbs.where { availability_zones.include? region + 'a' } do - its('elb_names') { should include fixtures['elb_alpha_name']} - its('elb_names') { should include fixtures['elb_beta_name']} - end - describe elbs.where { availability_zones.include? region + 'c' } do - its('elb_names') { should_not include fixtures['elb_alpha_name']} - its('elb_names') { should include fixtures['elb_beta_name']} - end - - describe elbs.where(dns_name: /com$/) do - its('count') { should cmp 2 } - end - - # Both listen on 80 - describe elbs.where { external_ports.include? 80 } do - its('count') { should cmp 2 } - end - - # Alpha has no instances, beta has two - describe elbs.where { instance_ids.count == 0 } do - its('count') { should cmp 1 } - its('elb_names') { should include fixtures['elb_alpha_name'] } - end - describe elbs.where { instance_ids.count == 2 } do - its('count') { should cmp 1 } - its('elb_names') { should include fixtures['elb_beta_name'] } - its('instance_ids') { should include fixtures['elb_beta_instance_1_id'] } - its('instance_ids') { should include fixtures['elb_beta_instance_2_id'] } - its('instance_ids.count') { should cmp 2 } - end - - # Alpha uses 8080, beta uses 80 - describe elbs.where { internal_ports.include? 8080 } do - its('count') { should cmp 1 } - its('elb_names') { should include fixtures['elb_alpha_name'] } - end - - # Both have the same - describe elbs.where { security_group_ids.count == 1 } do - its('count') { should cmp 2 } - its('elb_names') { should include fixtures['elb_alpha_name'] } - its('elb_names') { should include fixtures['elb_beta_name'] } - end - - # Alpha is in A only - # Beta is in A and C - describe elbs.where { subnet_ids.include? fixtures['elb_subnet_a_id']} do - its('count') { should cmp 2 } - its('elb_names') { should include fixtures['elb_alpha_name'] } - its('elb_names') { should include fixtures['elb_beta_name'] } - end - describe elbs.where { subnet_ids.include? fixtures['elb_subnet_c_id']} do - its('count') { should cmp 1 } - its('elb_names') { should_not include fixtures['elb_alpha_name'] } - its('elb_names') { should include fixtures['elb_beta_name'] } - end - - describe elbs.where(vpc_id: fixtures['elb_vpc_id']) do - its('count') { should cmp 2 } - its('elb_names') { should include fixtures['elb_alpha_name'] } - its('elb_names') { should include fixtures['elb_beta_name'] } - end -end - -# #------------------- Properties -------------# -control "aws_elbs properties" do - describe aws_elbs do - its('availability_zones') { should include fixtures['aws_region'] + 'a' } - its('availability_zones') { should include fixtures['aws_region'] + 'c' } - its('availability_zones.count') { should cmp 2 } - its('dns_names') { should include(a_string_ending_with('elb.amazonaws.com'))} - its('dns_names.count') { should cmp 2 } - its('external_ports') { should include 80 } - its('external_ports.count') { should cmp 1 } - its('instance_ids') { should include fixtures['elb_beta_instance_1_id']} - its('instance_ids') { should include fixtures['elb_beta_instance_2_id']} - its('instance_ids.count') { should cmp 2 } - its('internal_ports') { should include 80 } - its('internal_ports') { should include 8080 } - its('internal_ports.count') { should cmp 2 } - its('security_group_ids') { should include fixtures['elb_security_group_to_lb_id']} - its('security_group_ids.count') { should cmp 1 } - its('subnet_ids') { should include fixtures['elb_subnet_a_id']} - its('subnet_ids') { should include fixtures['elb_subnet_c_id']} - its('subnet_ids.count') { should cmp 2 } - its('vpc_ids') { should include fixtures['elb_vpc_id']} - its('vpc_ids.count') { should cmp 1 } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_flow_log.rb b/test/integration/aws/default/verify/controls/aws_flow_log.rb deleted file mode 100644 index a7245ed0c..000000000 --- a/test/integration/aws/default/verify/controls/aws_flow_log.rb +++ /dev/null @@ -1,49 +0,0 @@ -fixtures = {} -%w[flow_log_alpha_vpc_log_id flow_log_alpha_subnet_log_id - flow_log_alpha_subnet_id flow_log_vpc_id].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/flow_log.tf', - ) -end - -control 'aws_flow_log exists' do - describe aws_flow_log(fixtures['flow_log_alpha_vpc_log_id']) do - it { should exist} - end -end - -control 'aws_flow_log should not exist' do - describe aws_flow_log(flow_log_id: 'fl-1122aabb') do - it { should_not exist } - end -end - -control 'aws_flow_log search by flow_log_id exists' do - describe aws_flow_log(flow_log_id: fixtures['flow_log_alpha_vpc_log_id']) do - it { should exist } - it { should be_attached_to_vpc } - its('flow_log_id') { should cmp fixtures['flow_log_alpha_vpc_log_id'] } - its('log_group_name') { should cmp 'flow_log_alpha_log_group' } - its('resource_id') { should cmp fixtures['flow_log_vpc_id'] } - its('resource_type') { should cmp 'vpc' } - end -end - -control 'aws_flow_log search by subnet exists' do - describe aws_flow_log(subnet_id: fixtures['flow_log_alpha_subnet_id']) do - it { should exist } - it { should be_attached_to_subnet } - its('flow_log_id') { should cmp fixtures['flow_log_alpha_subnet_log_id'] } - its('log_group_name') { should cmp 'flow_log_alpha_log_group' } - its('resource_id') { should cmp fixtures['flow_log_alpha_subnet_id'] } - its('resource_type') { should cmp 'subnet' } - end -end - -control 'aws_flow_log search by vpc exists' do - describe aws_flow_log(vpc_id: fixtures['flow_log_vpc_id']) do - it { should exist } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_iam_access_key.rb b/test/integration/aws/default/verify/controls/aws_iam_access_key.rb deleted file mode 100644 index 5004962d2..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_access_key.rb +++ /dev/null @@ -1,43 +0,0 @@ -fixtures = {} -[ - 'iam_user_with_access_key', - 'iam_user_without_access_key', - 'iam_user_recall_miss', - 'iam_access_key_recall_hit', - 'iam_access_key_recall_miss', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -#======================================================# -# IAM Access Key - Singular -#======================================================# - -#------------------- Recall / Miss -------------------# - -control "aws_iam_access_key recall" do - # Neither user nor access key ID exist - describe aws_iam_access_key(username: fixtures['iam_user_recall_miss'], id: fixtures['iam_access_key_recall_miss']) do - it { should_not exist } - end - - # User exists but has no keys - describe aws_iam_access_key(username: fixtures['iam_user_without_access_key'], id: fixtures['iam_access_key_recall_miss']) do - it { should_not exist } - end - - # User exists and has an access key - describe aws_iam_access_key(username: fixtures['iam_user_with_access_key'], id: fixtures['iam_access_key_recall_hit']) do - it { should exist } - end -end - -#------------- Property - create_date -------------# -# TODO: create_date tests - -#------------- Property - last_used_date -------------# -# TODO: last_used_date tests diff --git a/test/integration/aws/default/verify/controls/aws_iam_access_keys.rb b/test/integration/aws/default/verify/controls/aws_iam_access_keys.rb deleted file mode 100644 index 314a39493..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_access_keys.rb +++ /dev/null @@ -1,58 +0,0 @@ -fixtures = {} -[ - 'iam_user_with_access_key', - 'iam_user_without_access_key', - 'iam_access_key_recall_hit', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -#======================================================# -# IAM Access Key - Plural -#======================================================# - -control 'IAM Access Keys - fetch all' do - describe aws_iam_access_keys do - it { should exist } - end -end - -control 'IAM Access Keys - Client-side filtering' do - all_keys = aws_iam_access_keys - describe all_keys.where(username: fixtures['iam_user_with_access_key']) do - its('entries.length') { should be 1 } - its('access_key_ids.first') { should eq fixtures['iam_access_key_recall_hit'] } - end - describe all_keys.where(created_days_ago: 0) do - it { should exist } - end - describe all_keys.where { active } do - it { should exist } - end - - # This would presumably refer to your test-user-last-key-use IAM user - # This test will fail if you have very recently setup your - # testing environment - describe all_keys.where { ever_used } - .where { last_used_days_ago > 0 } do - it { should exist } - end - describe all_keys.where { created_with_user } do - it { should exist } - end -end - -control 'IAM Access Keys - fetch-time filtering' do - describe aws_iam_access_keys(username: fixtures['iam_user_with_access_key']) do - its('entries.length') { should be 1 } - its('access_key_ids.first') { should eq fixtures['iam_access_key_recall_hit'] } - end - - describe aws_iam_access_keys(username: fixtures['iam_user_without_access_key']) do - it { should_not exist } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_iam_group.rb b/test/integration/aws/default/verify/controls/aws_iam_group.rb deleted file mode 100644 index c5c093cf0..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_group.rb +++ /dev/null @@ -1,27 +0,0 @@ -fixtures = {} -[ - 'iam_group_administrators', - 'iam_user_recall_hit' -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -control "aws_iam_group recall" do - describe aws_iam_group(fixtures['iam_group_administrators']) do - it { should exist } - end - - describe aws_iam_group('fakegroup') do - it { should_not exist } - end -end - -control "aws_iam_group properties test" do - describe aws_iam_group(fixtures['iam_group_administrators']) do - its('users') { should include fixtures['iam_user_recall_hit'] } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_iam_groups.rb b/test/integration/aws/default/verify/controls/aws_iam_groups.rb deleted file mode 100644 index 768e4a6ef..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_groups.rb +++ /dev/null @@ -1,31 +0,0 @@ -fixtures = {} -[ - 'iam_group_administrators', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -control "aws_iam_groups search" do - describe aws_iam_groups do - it { should exist } - end - - describe aws_iam_groups.where(group_name: fixtures['iam_group_administrators']) do - it { should exist } - its('count') { should cmp 1 } - end - - describe aws_iam_groups.where(group_name: /fakegroup/) do - it { should_not exist } - end -end - -control "aws_iam_groups properties test" do - describe aws_iam_groups do - its('group_names') { should include fixtures['iam_group_administrators'] } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_iam_password_policy.rb b/test/integration/aws/default/verify/controls/aws_iam_password_policy.rb deleted file mode 100644 index ef6fd46ab..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_password_policy.rb +++ /dev/null @@ -1,33 +0,0 @@ -# There are other tests in the "minimal" test account. - -#---------------------- Recall ------------------------# -# Password policy is a per-account singleton. If it's been configured, it exists. -control "aws_iam_password_policy existence" do - describe aws_iam_password_policy do - it { should exist } - end -end - -#------------- Properties -------------# - -control "aws_iam_password_policy properties" do - describe aws_iam_password_policy do - its('max_password_age_in_days') { should cmp 365 } - its('number_of_passwords_to_remember') { should cmp 7 } - end -end - -#------------- Matchers - Positive Case -------------# - -control "aws_iam_password_policy matchers" do - describe aws_iam_password_policy do - it { should require_lowercase_characters } - it { should require_uppercase_characters } - it { should require_numbers } - it { should require_symbols } - it { should allow_users_to_change_passwords } - it { should expire_passwords } - it { should prevent_password_reuse } - end -end - diff --git a/test/integration/aws/default/verify/controls/aws_iam_policies.rb b/test/integration/aws/default/verify/controls/aws_iam_policies.rb deleted file mode 100644 index 4cc3ec2f9..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_policies.rb +++ /dev/null @@ -1,5 +0,0 @@ -control "aws_iam_policies recall" do - describe aws_iam_policies do - it { should exist } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_iam_policy.rb b/test/integration/aws/default/verify/controls/aws_iam_policy.rb deleted file mode 100644 index 79ab8189d..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_policy.rb +++ /dev/null @@ -1,110 +0,0 @@ -fixtures = {} -[ - 'aws_iam_policy_alpha_name', - 'aws_iam_policy_beta_name', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -control "aws_iam_policy recall" do - describe aws_iam_policy("AWSSupportAccess") do - it { should exist } - end - - describe aws_iam_policy(policy_name: "AWSSupportAccess") do - it { should exist } - end - - describe aws_iam_policy(fixtures['aws_iam_policy_alpha_name']) do - it { should exist } - end -end - -control "aws_iam_policy properties" do - describe aws_iam_policy("AdministratorAccess") do - its('arn') { should cmp "arn:aws:iam::aws:policy/AdministratorAccess" } - its('default_version_id') { should cmp 'v1' } - its('attachment_count') { should cmp 1 } - its('attached_users') { should include "test-fixture-maker" } - its('attached_groups') { should be_empty } - its('attached_roles') { should be_empty } - end - - describe aws_iam_policy(fixtures['aws_iam_policy_alpha_name']) do - its('statement_count') { should cmp 2 } - its('policy') { should be_kind_of(Hash) } - end -end - -control "aws_iam_policy matchers" do - describe aws_iam_policy("AdministratorAccess") do - it { should be_attached } - end - describe aws_iam_policy("AdministratorAccess") do - it { should be_attached_to_user("test-fixture-maker") } - end - - describe aws_iam_policy(fixtures['aws_iam_policy_alpha_name']) do - it { should have_statement('Resource' => '*')} - it { should have_statement('Resource' => '*', 'Sid' => 'alpha01')} - it { should have_statement('Resource' => 'arn:aws:s3:::bobs-stuff', 'Sid' => 'alpha02')} - - it { should have_statement('Effect' => 'Allow', 'Sid' => 'alpha01')} - it { should have_statement('Effect' => 'Deny', 'Sid' => 'alpha02')} - - it { should have_statement('Action' => 'ec2:Describe*', 'Sid' => 'alpha01')} - it { should_not have_statement('Action' => 'ec2:Describe')} - it { should have_statement('Action' => /^ec2:Describe\*$/, 'Sid' => 'alpha01')} - it { should have_statement('Action' => /^ec2:.+$/, 'Sid' => 'alpha01')} - - it { should have_statement('Action' => 'ec2:Describe*', 'Resource' => '*', 'Effect' => 'Allow') } - it { should_not have_statement('Action' => 'ec2:Describe*', 'Resource' => 'arn:aws:s3:::bobs-stuff') } - end - - describe aws_iam_policy(fixtures['aws_iam_policy_beta_name']) do - it { should have_statement('Action' => 'ec2:DescribeSubnets')} - it { should have_statement('Action' => 'ec2:DescribeSecurityGroups')} - # Array indicates all must match - it { should_not have_statement('Action' => ['ec2:DescribeSecurityGroups'])} - it { should have_statement('Action' => ['ec2:DescribeSubnets', 'ec2:DescribeSecurityGroups'])} - it { should have_statement('Action' => ['ec2:DescribeSecurityGroups', 'ec2:DescribeSubnets'])} - - it { should have_statement('Resource' => 'arn:aws:ec2:::*')} - it { should have_statement('Resource' => '*')} - it { should_not have_statement('Resource' => ['*'])} - it { should have_statement('Resource' => ['arn:aws:ec2:::*', '*'])} - it { should have_statement('Resource' => ['*', 'arn:aws:ec2:::*'])} - end - - # AWSCertificateManagerReadOnly has an odd shape: - # its Statement list is not an array, but a hash - it's a degenerate form. - # { - # "Version": "2012-10-17", - # "Statement": { - # "Effect": "Allow", - # "Action": [ - # "acm:DescribeCertificate", - # "acm:ListCertificates", - # "acm:GetCertificate", - # "acm:ListTagsForCertificate" - # ], - # "Resource": "*" - # } - # } - describe aws_iam_policy('AWSCertificateManagerReadOnly') do - its('statement_count') { should cmp 1 } - it { should have_statement 'Effect' => 'Allow', 'Action' => 'acm:GetCertificate' } - end - - # This policy has a statment with a NotAction, and no Action - # We don't yet support NotAction - # But if you ask for action, it should not match, and also not explode - # arn:aws:iam::aws:policy/PowerUserAccess - describe aws_iam_policy('PowerUserAccess') do - it { should_not have_statement 'Action' => 'iam:*' } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_iam_role.rb b/test/integration/aws/default/verify/controls/aws_iam_role.rb deleted file mode 100644 index 7b6ca829a..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_role.rb +++ /dev/null @@ -1,6 +0,0 @@ -control 'AWS IAM Role search for default AWS role' do - # This should exist because we created an RDS - describe aws_iam_role('AWSServiceRoleForRDS') do - it { should exist } - end -end \ No newline at end of file diff --git a/test/integration/aws/default/verify/controls/aws_iam_root_user.rb b/test/integration/aws/default/verify/controls/aws_iam_root_user.rb deleted file mode 100644 index d94024198..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_root_user.rb +++ /dev/null @@ -1,35 +0,0 @@ -fixtures = {} -[ - 'aws_account_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -#------------- Property - has_mfa_enabled -------------# -# Negative test in 'minimal' test set. See TESTING_AGAINST_AWS.md -# for fixture instructions. -control "aws_iam_root_user has_mfa_enabled property" do - describe aws_iam_root_user do - it { should have_mfa_enabled } - end -end - -#---------- Property - has_virtual_mfa_enabled ----------# -# Negative test in 'minimal' test set. -control "aws_iam_root_user has_virtual_mfa_enabled property" do - describe aws_iam_root_user do - it { should have_virtual_mfa_enabled } - end -end - -#------------- Property - has_access_key -------------# -# Positive test in 'minimal' test set -control "aws_iam_root_user has_access_key property" do - describe aws_iam_root_user do - it { should_not have_access_key } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_iam_user.rb b/test/integration/aws/default/verify/controls/aws_iam_user.rb deleted file mode 100644 index ba3f582c1..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_user.rb +++ /dev/null @@ -1,111 +0,0 @@ -fixtures = {} -[ - 'iam_user_recall_hit', - 'iam_user_recall_miss', - 'iam_user_no_mfa_enabled', - 'iam_user_has_console_password', - 'iam_user_with_access_key', - - # Naming scheme: 1i_1a means one - # inline policy, one attached policy, etc - 'iam_user_for_policies_0i_0a_name', - 'iam_user_for_policies_1i_0a_name', - 'iam_user_for_policies_2i_0a_name', - 'iam_user_for_policies_1i_1a_name', - 'iam_user_for_policies_0i_2a_name', - 'iam_policy_user_attached_1i_1a_1_arn', - 'iam_policy_user_attached_1i_1a_1_name', - 'iam_policy_user_attached_0i_2a_1_arn', - 'iam_policy_user_attached_0i_2a_1_name', - 'iam_policy_user_attached_0i_2a_2_arn', - 'iam_policy_user_attached_0i_2a_2_name', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -#------------------- Recall / Miss -------------------# -control "aws_iam_user recall" do - describe aws_iam_user(username: fixtures['iam_user_recall_hit']) do - it { should exist } - end - - describe aws_iam_user(username: fixtures['iam_user_recall_miss']) do - it { should_not exist } - end -end - -control "aws_iam_user properties" do - #------------- Property - has_mfa_enabled -------------# - - # TODO: fixture and test for has_mfa_enabled - - describe aws_iam_user(username: fixtures['iam_user_no_mfa_enabled']) do - it { should_not have_mfa_enabled } - it { should_not have_console_password } # TODO: this is working by accident, we should have a dedicated fixture - end - - #---------- Property - has_console_password -----------# - - describe aws_iam_user(username: fixtures['iam_user_has_console_password']) do - it { should have_console_password } - end - - #------------- Property - access_keys -------------# - - aws_iam_user(username: fixtures['iam_user_with_access_key']).access_keys.each { |access_key| - describe access_key.access_key_id do - subject { access_key } - its('status') { should eq 'Active' } - end - } - - #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# - # Inline and Attached Policies - #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# - [ - [0,0], - [1,0], - [2,0], - [1,1], - [0,2], - ].each do |combo_as_ints| - inline_count, attached_count = *combo_as_ints - combo_as_string = "#{inline_count}i_#{attached_count}a" - describe aws_iam_user(fixtures["iam_user_for_policies_#{combo_as_string}_name"]) do - # Check inline has flag - if inline_count > 0 - it { should have_inline_policies } - else - it { should_not have_inline_policies } - end - - # Check inline count - its('inline_policy_names.count') { should eq inline_count } - - # Check for expected inline name(s) - (1..inline_count).each do |idx| - its('inline_policy_names') { should include "test_#{combo_as_string}_#{idx}"} - end - - # Check attached has flag - if attached_count > 0 - it { should have_attached_policies } - else - it { should_not have_attached_policies } - end - - # Check attached count - its('attached_policy_names.count') { should eq attached_count } - - # Check for expected attached name(s) and arn(s) - (1..attached_count).each do |idx| - its('attached_policy_arns') { should include fixtures["iam_policy_user_attached_#{combo_as_string}_#{idx}_arn"] } - its('attached_policy_names') { should include fixtures["iam_policy_user_attached_#{combo_as_string}_#{idx}_name"] } - end - end - end -end diff --git a/test/integration/aws/default/verify/controls/aws_iam_users.rb b/test/integration/aws/default/verify/controls/aws_iam_users.rb deleted file mode 100644 index d826aefb4..000000000 --- a/test/integration/aws/default/verify/controls/aws_iam_users.rb +++ /dev/null @@ -1,55 +0,0 @@ -fixtures = {} -[ - # Naming scheme: 1i_1a means one - # inline policy, one attached policy, etc - 'iam_user_for_policies_0i_0a_name', - 'iam_user_for_policies_1i_0a_name', - 'iam_user_for_policies_2i_0a_name', - 'iam_user_for_policies_1i_1a_name', - 'iam_user_for_policies_0i_2a_name', - 'iam_policy_user_attached_1i_1a_1_arn', - 'iam_policy_user_attached_1i_1a_1_name', - 'iam_policy_user_attached_0i_2a_1_arn', - 'iam_policy_user_attached_0i_2a_1_name', - 'iam_policy_user_attached_0i_2a_2_arn', - 'iam_policy_user_attached_0i_2a_2_name', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -control "aws_iam_users filtering" do - describe aws_iam_users.where(has_console_password?: true) - .where(has_mfa_enabled?: false) do - it { should exist } - end - - describe aws_iam_users.where { user_name =~ /user_for_policies/ } - .where(has_inline_policies: true) do - its('entries.count') { should eq 3 } - its('usernames') { should include fixtures['iam_user_for_policies_1i_0a_name'] } - its('usernames') { should include fixtures['iam_user_for_policies_1i_1a_name'] } - its('usernames') { should_not include fixtures['iam_user_for_policies_0i_2a_name'] } - - its('inline_policy_names.count') { should eq 4 } - its('inline_policy_names') { should include 'test_1i_0a_1' } - its('attached_policy_names.count') { should eq 1 } - end - - describe aws_iam_users.where { user_name =~ /user_for_policies/ } - .where(has_attached_policies: true) do - # We have 2 users from our fixtures - its('entries.count') { should eq 2 } - its('usernames') { should include fixtures['iam_user_for_policies_0i_2a_name'] } - its('usernames') { should include fixtures['iam_user_for_policies_1i_1a_name'] } - its('usernames') { should_not include fixtures['iam_user_for_policies_1i_0a_name'] } - - its('attached_policy_names.count') { should eq 3 } - its('attached_policy_names') { should include fixtures['iam_policy_user_attached_1i_1a_1_name'] } - its('attached_policy_arns.count') { should eq 3 } - its('attached_policy_arns') { should include fixtures['iam_policy_user_attached_1i_1a_1_arn'] } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_kms_key.rb b/test/integration/aws/default/verify/controls/aws_kms_key.rb deleted file mode 100644 index 936aab44a..000000000 --- a/test/integration/aws/default/verify/controls/aws_kms_key.rb +++ /dev/null @@ -1,51 +0,0 @@ -fixtures = {} -[ - 'kms_key_enabled_arn', - 'kms_key_enabled_key_id', - 'kms_key_disabled_key_id', - 'kms_key_enabled_key_description' -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/kms.tf', - ) -end - -control "aws_kms_key recall" do - describe aws_kms_key(fixtures['kms_key_enabled_key_id']) do - it { should exist} - end - describe aws_kms_key(key_id: fixtures['kms_key_enabled_key_id']) do - it { should exist } - end - describe aws_kms_key('non-existent-key') do - it { should_not exist } - end -end - -control "aws_kms_key properties" do - describe aws_kms_key(fixtures['kms_key_enabled_key_id']) do - its('key_id') { should eq fixtures['kms_key_enabled_key_id'] } - its('arn') { should eq fixtures['kms_key_enabled_arn'] } - its('description') { should eq fixtures['kms_key_enabled_key_description'] } - its('created_days_ago') { should eq 0 } - its('key_usage') { should eq 'ENCRYPT_DECRYPT' } - its('key_state') { should eq 'Enabled' } - end -end - -control "aws_kms_key matchers" do - describe aws_kms_key(fixtures['kms_key_enabled_key_id']) do - it { should be_enabled } - it { should_not be_external } - it { should_not be_managed_by_aws } - it { should_not have_key_expiration } - end - describe aws_kms_key(fixtures['kms_key_enabled_key_id']) do - it { should have_rotation_enabled } - end - describe aws_kms_key(fixtures['kms_key_disabled_key_id']) do - it { should_not have_rotation_enabled } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_kms_keys.rb b/test/integration/aws/default/verify/controls/aws_kms_keys.rb deleted file mode 100644 index 881d535ee..000000000 --- a/test/integration/aws/default/verify/controls/aws_kms_keys.rb +++ /dev/null @@ -1,5 +0,0 @@ -control "aws_kms_keys recall" do - describe aws_kms_keys do - it { should exist } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_rds_instance.rb b/test/integration/aws/default/verify/controls/aws_rds_instance.rb deleted file mode 100644 index e3ae3e3c6..000000000 --- a/test/integration/aws/default/verify/controls/aws_rds_instance.rb +++ /dev/null @@ -1,22 +0,0 @@ -fixtures = {} -[ - 'rds_db_instance_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/rds.tf', - ) -end - -control "aws_rds_instance recall of default Instance" do - - describe aws_rds_instance(fixtures['rds_db_instance_id']) do - it { should exist } - end - - describe aws_rds_instance('i-dont-exist') do - it { should_not exist } - end - -end diff --git a/test/integration/aws/default/verify/controls/aws_route_table.rb b/test/integration/aws/default/verify/controls/aws_route_table.rb deleted file mode 100644 index 9297ba222..000000000 --- a/test/integration/aws/default/verify/controls/aws_route_table.rb +++ /dev/null @@ -1,33 +0,0 @@ -fixtures = {} -[ - 'route_table_1_id', - 'route_table_1_vpc_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/route_table.tf', - ) -end - -control "aws_route_table exists" do - describe aws_route_table do - it { should exist } - end -end - -control "aws_route_table recall" do - describe aws_route_table(fixtures['route_table_1_id']) do - it { should exist} - end -end - -control "aws_route_tables dont exist" do - describe aws_route_table('rtb-123abcde') do - it { should_not exist } - end - - describe aws_route_table(route_table_id: 'rtb-123abcde') do - it { should_not exist } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_route_tables.rb b/test/integration/aws/default/verify/controls/aws_route_tables.rb deleted file mode 100644 index 74c60c2b3..000000000 --- a/test/integration/aws/default/verify/controls/aws_route_tables.rb +++ /dev/null @@ -1,28 +0,0 @@ -fixtures = {} -[ - 'route_table_1_id', - 'route_table_2_id', - 'route_table_1_vpc_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -control "aws_route_tables recall" do - # Check if at least one route table has been created and test a specific route table was created. - describe aws_route_tables do - it { should exist } - its('route_table_ids') { should include fixtures['route_table_1_id'], fixtures['route_table_2_id'] } - end -end - -control "aws_route_tables properties" do - # test the vpc ids and route table ids - describe aws_route_tables do - its('vpc_ids') { should include fixtures['route_table_1_vpc_id'] } - its('route_table_ids') { should include fixtures['route_table_1_id'], fixtures['route_table_2_id'] } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_s3_bucket.rb b/test/integration/aws/default/verify/controls/aws_s3_bucket.rb deleted file mode 100644 index 6d8bcb1f2..000000000 --- a/test/integration/aws/default/verify/controls/aws_s3_bucket.rb +++ /dev/null @@ -1,133 +0,0 @@ -fixtures = {} -[ - 's3_bucket_public_name', - 's3_bucket_private_name', - 's3_bucket_auth_name', - 's3_bucket_private_acl_public_policy_name', - 's3_bucket_public_region', - 's3_bucket_default_encryption_enabled_name', - 's3_bucket_default_encryption_not_enabled_name', - 's3_bucket_access_logging_enabled_name', - 's3_bucket_access_logging_not_enabled_name', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/s3.tf', - ) -end - -control 'aws_s3_bucket recall tests' do - #------------------- Exists -------------------# - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_public_name']) do - it { should exist } - end - - #------------------- Does Not Exist -------------------# - describe aws_s3_bucket(bucket_name: 'inspec-testing-NonExistentBucket.chef.io') do - it { should_not exist } - end -end - -control 'aws_s3_bucket properties tests' do - #--------------------------- Region --------------------------# - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_public_name']) do - its('region') { should eq fixtures['s3_bucket_public_region'] } - end - - #------------------- bucket_acl -------------------# - describe "Bucket ACL: Public grants on a public bucket" do - subject do - aws_s3_bucket(bucket_name: fixtures['s3_bucket_public_name']).bucket_acl.select do |g| - g.grantee.type == 'Group' && g.grantee.uri =~ /AllUsers/ - end - end - it { should_not be_empty } - end - - describe "Bucket ACL: Public grants on a private bucket" do - subject do - aws_s3_bucket(bucket_name: fixtures['s3_bucket_private_name']).bucket_acl.select do |g| - g.grantee.type == 'Group' && g.grantee.uri =~ /AllUsers/ - end - end - it { should be_empty } - end - - describe "Bucket ACL: AuthUser grants on a private bucket" do - subject do - aws_s3_bucket(bucket_name: fixtures['s3_bucket_private_name']).bucket_acl.select do |g| - g.grantee.type == 'Group' && g.grantee.uri =~ /AuthenticatedUsers/ - end - end - it { should be_empty } - end - - describe "Bucket ACL: AuthUser grants on an AuthUser bucket" do - subject do - aws_s3_bucket(bucket_name: fixtures['s3_bucket_auth_name']).bucket_acl.select do |g| - g.grantee.type == 'Group' && g.grantee.uri =~ /AuthenticatedUsers/ - end - end - it { should_not be_empty } - end - - #------------------- bucket_policy -------------------# - describe "Bucket Policy: Allow GetObject Statement For Everyone on public" do - subject do - bucket_policy = aws_s3_bucket(bucket_name: fixtures['s3_bucket_public_name']).bucket_policy - allow_all = bucket_policy.select { |s| s.effect == 'Allow' && s.principal == '*' } - allow_all.count - end - it { should == 1 } - end - - describe "Bucket Policy: Allow GetObject Statement For Everyone on private" do - subject do - bucket_policy = aws_s3_bucket(bucket_name: fixtures['s3_bucket_private_name']).bucket_policy - allow_all = bucket_policy.select { |s| s.effect == 'Allow' && s.principal == '*' } - allow_all.count - end - it { should be_zero } - end - - describe "Bucket Policy: Empty policy on auth" do - subject do - aws_s3_bucket(bucket_name: fixtures['s3_bucket_auth_name']).bucket_policy - end - it { should be_empty } - end -end - -control 'aws_s3_bucket matchers test' do - - #------------------------ be_public --------------------------# - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_public_name']) do - it { should be_public } - end - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_auth_name']) do - it { should be_public } - end - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_private_name']) do - it { should_not be_public } - end - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_private_acl_public_policy_name']) do - it { should be_public } - end - - #----------------- have_default_encryption_enabled -----------------# - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_default_encryption_enabled_name']) do - it { should have_default_encryption_enabled } - end - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_default_encryption_not_enabled_name']) do - it { should_not have_default_encryption_enabled } - end - - #----------------- have_access_logging_enabled -----------------# - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_access_logging_enabled_name']) do - it { should have_access_logging_enabled } - end - describe aws_s3_bucket(bucket_name: fixtures['s3_bucket_access_logging_not_enabled_name']) do - it { should_not have_access_logging_enabled } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_s3_buckets.rb b/test/integration/aws/default/verify/controls/aws_s3_buckets.rb deleted file mode 100644 index e2b658378..000000000 --- a/test/integration/aws/default/verify/controls/aws_s3_buckets.rb +++ /dev/null @@ -1,28 +0,0 @@ -fixtures = {} -[ - 's3_bucket_public_name', - 's3_bucket_private_name', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/s3.tf', - ) -end - -control "aws_s3_buckets recall" do - - # You should be able to test if there are any buckets - describe aws_s3_buckets do - it { should exist } - end -end - -control "aws_s3_buckets properties" do - # you should be able to test the cidr_block of a subnet - describe aws_s3_buckets do - its('bucket_names') { should include fixtures['s3_bucket_public_name'], fixtures['s3_bucket_private_name'] } - its('bucket_names') { should_not include 'i_dont_exist' } - end -end - diff --git a/test/integration/aws/default/verify/controls/aws_security_group.rb b/test/integration/aws/default/verify/controls/aws_security_group.rb deleted file mode 100644 index 0fc39b1d1..000000000 --- a/test/integration/aws/default/verify/controls/aws_security_group.rb +++ /dev/null @@ -1,86 +0,0 @@ -fixtures = {} -[ - 'ec2_security_group_default_vpc_id', - 'ec2_security_group_default_group_id', - 'ec2_security_group_alpha_group_id', - 'ec2_security_group_beta_group_id', - 'ec2_security_group_gamma_group_id', - 'ec2_security_group_alpha_group_name', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -control "aws_security_group recall of default VPC" do - - describe aws_security_group(fixtures['ec2_security_group_default_group_id']) do - it { should exist } - end - - describe aws_security_group(group_name: 'default', vpc_id: fixtures['ec2_security_group_default_vpc_id']) do - it { should exist } - end - - describe aws_security_group(group_name: 'no-such-security-group') do - it { should_not exist } - end -end - -control "aws_security_group properties" do - # You should be able to find the default security group's ID. - describe aws_security_group(fixtures['ec2_security_group_default_group_id']) do - its('group_id') { should cmp fixtures['ec2_security_group_default_group_id'] } - end - - describe aws_security_group(fixtures['ec2_security_group_alpha_group_id']) do - its('group_name') { should cmp fixtures['ec2_security_group_alpha_group_name'] } - its('vpc_id') { should cmp fixtures['ec2_security_group_default_vpc_id'] } - its('description') { should cmp 'SG alpha' } - its('inbound_rules') { should be_a_kind_of(Array)} - its('inbound_rules.first') { should be_a_kind_of(Hash)} - its('inbound_rules.count') { should cmp 3 } # 3 explicit, one implicit - its('inbound_rules_count') { should cmp 4 } - its('outbound_rules') { should be_a_kind_of(Array)} - its('outbound_rules.first') { should be_a_kind_of(Hash)} - its('outbound_rules.count') { should cmp 1 } # 1 explicit - its('outbound_rules_count') { should cmp 3 } # 3 CIDR blocks specified - end -end - -control "aws_security_group matchers" do - describe aws_security_group(fixtures['ec2_security_group_alpha_group_id']) do - it { should allow_in(port: 22) } - it { should_not allow_in(port: 631, ipv4_range: "0.0.0.0/0") } - it { should allow_in(ipv4_range: "0.0.0.0/0", port: 80)} - it { should_not allow_in(ipv4_range: "0.0.0.0/0", port: 22)} - it { should allow_in(ipv4_range: "10.1.2.0/24", port: 22)} - it { should allow_in(ipv4_range: ["10.1.2.0/24"], port: 22)} - it { should allow_in(ipv6_range: ["2001:db8::/122"], port: 22)} - - it { should allow_in({ipv4_range: "10.1.2.32/32", position: 2}) } - it { should_not allow_in_only({ipv4_range: "10.1.2.32/32", position: 2}) } - it { should allow_in_only({ipv4_range: "10.1.2.0/24", position: 2}) } - - # Fixture allows out 6000-6007, with one rule - it { should allow_out(port: 6003)} - it { should_not allow_out_only(port: 6003)} - it { should allow_out_only(from_port: 6000, to_port: 6007)} - - it { should allow_out(ipv4_range: ["10.1.2.0/24", "10.3.2.0/24"])} - it { should allow_out(ipv4_range: ["10.1.2.0/24", "10.3.2.0/24"], from_port: 6000, to_port: 6007)} - it { should allow_out(ipv4_range: ["10.1.2.0/24", "10.3.2.0/24"], from_port: 6000, to_port: 6007, position: 1)} - - it { should allow_out(ipv6_range: ["2001:db8::/122"])} - it { should allow_out(ipv6_range: ["2001:db8::/122"], from_port: 6000, to_port: 6007)} - end - describe aws_security_group(fixtures['ec2_security_group_beta_group_id']) do - it { should allow_in(port: 22, security_group: fixtures['ec2_security_group_alpha_group_id']) } - it { should allow_in(security_group: fixtures['ec2_security_group_gamma_group_id']) } - end - describe aws_security_group(fixtures['ec2_security_group_gamma_group_id']) do - it { should allow_in_only(port: 22, security_group: fixtures['ec2_security_group_alpha_group_id']) } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_security_groups.rb b/test/integration/aws/default/verify/controls/aws_security_groups.rb deleted file mode 100644 index 15fb099a2..000000000 --- a/test/integration/aws/default/verify/controls/aws_security_groups.rb +++ /dev/null @@ -1,50 +0,0 @@ -fixtures = {} -[ - 'ec2_security_group_default_vpc_id', - 'ec2_security_group_default_group_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -control "aws_security_groups client-side filtering" do - all_groups = aws_security_groups - - # You should always have at least one security group - describe all_groups do - it { should exist } - end - - # You should be able to find a security group in the default VPC - describe all_groups.where(vpc_id: fixtures['ec2_security_group_default_vpc_id']) do - it { should exist } - end - describe all_groups.where(vpc_id: 'vpc-12345678') do - it { should_not exist } - end - - # You should be able to find the security group named default - describe all_groups.where(group_name: 'default') do - it { should exist } - end - describe all_groups.where(group_name: 'no-such-security-group') do - it { should_not exist } - end -end - -control "aws_security_groups properties" do - # You should be able to find the default security group's ID. - describe aws_security_groups.where(vpc_id: fixtures['ec2_security_group_default_vpc_id']) do - its('group_ids') { should include fixtures['ec2_security_group_default_group_id'] } - end -end - -control "aws_security_groups" do - # Verify you have more than the default security group - describe aws_security_groups do - its('entries.count') { should be >= 2 } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_sns_subscription.rb b/test/integration/aws/default/verify/controls/aws_sns_subscription.rb deleted file mode 100644 index 2d37faf4e..000000000 --- a/test/integration/aws/default/verify/controls/aws_sns_subscription.rb +++ /dev/null @@ -1,44 +0,0 @@ -fixtures = {} -[ - 'sns_subscription_03_arn', - 'sns_topic_3_arn', - 'sqs_for_sub_03_arn', - 'aws_account_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/sns.tf', - ) -end - -control "aws_sns_subscription recall of default VPC" do - # Test constructor scalar hit - describe aws_sns_subscription(fixtures['sns_subscription_03_arn']) do - it { should exist } - end - # Test constructor hash hit - describe aws_sns_subscription(subscription_arn: fixtures['sns_subscription_03_arn']) do - it { should exist } - end - - describe aws_sns_subscription(subscription_arn: 'arn:aws:sns:us-east-1:721741954427:NonExistentSubscrtiption:bf007420-6-45-96-9c2bf144') do - it { should_not exist } - end -end - -control "aws_sns_subscription properties" do - describe aws_sns_subscription(fixtures['sns_subscription_03_arn']) do - its('topic_arn') { should eq fixtures['sns_topic_3_arn'] } - its('endpoint') { should eq fixtures['sqs_for_sub_03_arn'] } - its('protocol') { should eq 'sqs' } - its('owner') { should cmp fixtures['aws_account_id'] } - end -end - -control "aws_sns_subscription matchers" do - describe aws_sns_subscription(fixtures['sns_subscription_03_arn']) do - it { should_not have_raw_message_delivery } - it { should be_confirmation_authenticated } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_sns_topic.rb b/test/integration/aws/default/verify/controls/aws_sns_topic.rb deleted file mode 100644 index bb9abe8b6..000000000 --- a/test/integration/aws/default/verify/controls/aws_sns_topic.rb +++ /dev/null @@ -1,39 +0,0 @@ -fixtures = {} -[ - 'sns_topic_recall_hit_arn', - 'sns_topic_with_subscription_arn', - 'sns_topic_no_subscription_arn', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/sns.tf', - ) -end - -control 'aws_sns_topic recall' do - - # Split the ARNs so we can test various ways of missing - scheme, partition, service, region, account, topic = fixtures['sns_topic_recall_hit_arn'].split(':') - arn_prefix = [scheme, partition, service].join(':') - - # Search miss - no_such_topic_arn = [arn_prefix, region, account, 'no-such-topic-for-realz'].join(':') - describe aws_sns_topic(no_such_topic_arn) do - it { should_not exist } - end - - # Search hit - describe aws_sns_topic(fixtures['sns_topic_recall_hit_arn']) do - it { should exist } - end -end - -control "aws_sns_topic confirmed_subscription_count property" do - describe aws_sns_topic(fixtures['sns_topic_with_subscription_arn']) do - its('confirmed_subscription_count') { should_not be_zero } - end - describe aws_sns_topic(fixtures['sns_topic_no_subscription_arn']) do - its('confirmed_subscription_count') { should be_zero } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_sns_topics.rb b/test/integration/aws/default/verify/controls/aws_sns_topics.rb deleted file mode 100644 index 9e7c1022f..000000000 --- a/test/integration/aws/default/verify/controls/aws_sns_topics.rb +++ /dev/null @@ -1,24 +0,0 @@ -fixtures = {} -[ - 'sns_topic_recall_hit_arn', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/sns.tf', - ) -end - -control "aws_sns_topics recall" do - # Check if there is at least one sns topic - describe aws_sns_topics do - it { should exist } - end -end - -control "aws_sns_topics properties" do - # you should be able to get a list of all SNS Topic arns - describe aws_sns_topics do - its('topic_arns') { should include fixtures['sns_topic_recall_hit_arn'] } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_sqs_queue.rb b/test/integration/aws/default/verify/controls/aws_sqs_queue.rb deleted file mode 100644 index 5f30ca6cb..000000000 --- a/test/integration/aws/default/verify/controls/aws_sqs_queue.rb +++ /dev/null @@ -1,47 +0,0 @@ -fixtures = {} -[ - 'sqs_queue_1_url', - 'sqs_queue_2_url', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/sqs.tf', - ) -end - -control 'aws_sqs_queue lookup' do - - sqs_queue1_url = fixtures['sqs_queue_1_url'] - - # Search miss - sqs_queue_url_non_existent = sqs_queue1_url + "random" - - describe aws_sqs_queue(sqs_queue_url_non_existent) do - it { should_not exist } - end - - # Search hit - describe aws_sqs_queue(sqs_queue1_url) do - it { should exist } - end -end - -control "aws_sqs_queue properties" do - describe aws_sqs_queue(fixtures['sqs_queue_1_url']) do - its('delay_seconds') { should be 0 } - its('is_fifo_queue') { should be false } - its('visibility_timeout') { should be 300 } - its('maximum_message_size') { should be 262144 } - its('message_retention_period') { should be 345600 } - its('receive_message_wait_timeout_seconds') { should be 2 } - end -end - - -control "aws_sqs_queue fifo properties" do - describe aws_sqs_queue(fixtures['sqs_queue_2_url']) do - its('is_fifo_queue') { should be true } - its('content_based_deduplication') { should be true } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_subnet.rb b/test/integration/aws/default/verify/controls/aws_subnet.rb deleted file mode 100644 index 040ae43e0..000000000 --- a/test/integration/aws/default/verify/controls/aws_subnet.rb +++ /dev/null @@ -1,48 +0,0 @@ -fixtures = {} -[ - 'subnet_vpc_id', - 'subnet_01_id', - 'subnet_01_az', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -control "aws_subnet recall of subnet_01" do - # Test hash given subnet_id - describe aws_subnet(subnet_id: fixtures['subnet_01_id']) do - it { should exist } - end - - # Test scalar works - describe aws_subnet(fixtures['subnet_01_id']) do - it { should exist } - end - - describe aws_subnet(subnet_id: 'subnet-00000000') do - it { should_not exist } - end -end - -control "aws_subnet properties of subnet_01" do - describe aws_subnet(subnet_id: fixtures['subnet_01_id']) do - its('vpc_id') { should eq fixtures['subnet_vpc_id'] } - its('subnet_id') { should eq fixtures['subnet_01_id'] } - its('cidr_block') { should eq '172.31.48.0/28' } - its('available_ip_address_count') { should eq 11 } # AWS Reserve 5 - its('availability_zone') { should eq fixtures['subnet_01_az'] } - its('ipv_6_cidr_block_association_set') { should eq [] } - end -end - -control "aws_subnet matchers of subnet_01" do - describe aws_subnet(subnet_id: fixtures['subnet_01_id']) do - it { should be_available } - it { should_not be_mapping_public_ip_on_launch } - it { should_not be_default_for_az } - it { should_not be_assigning_ipv_6_address_on_creation } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_subnets.rb b/test/integration/aws/default/verify/controls/aws_subnets.rb deleted file mode 100644 index 6c223c6b4..000000000 --- a/test/integration/aws/default/verify/controls/aws_subnets.rb +++ /dev/null @@ -1,49 +0,0 @@ -fixtures = {} -[ - 'subnet_01_id', - 'subnet_vpc_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -control "aws_subnets recall" do - all_subnets = aws_subnets - - # You should be able to get a specific subnet given its id - describe all_subnets.where(subnet_id: fixtures['subnet_01_id']) do - it { should exist } - end - - # You should be able to get subnets given a vpc_id - describe all_subnets.where(vpc_id: fixtures['subnet_vpc_id']) do - it { should exist } - end - - describe all_subnets.where(vpc_id: 'vpc-00000000') do - it { should_not exist } - end - - describe all_subnets.where(subnet_id: 'subnet-00000000') do - it { should_not exist } - end -end - -control "aws_subnets properties by subnet id" do - # you should be able to test the cidr_block of a subnet - describe aws_subnets.where(subnet_id: fixtures['subnet_01_id']) do - its('cidr_blocks') { should include '172.31.48.0/28' } - its('states') { should_not include 'pending' } - end -end - -control "aws_subnets properties by vpc_id" do - # you should be able to test the cidr_block of a subnet - describe aws_subnets.where(vpc_id: fixtures['subnet_vpc_id']) do - its('cidr_blocks') { should include '172.31.48.0/28' } - its('states') { should include 'available' } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_vpc.rb b/test/integration/aws/default/verify/controls/aws_vpc.rb deleted file mode 100644 index d3ad69ce7..000000000 --- a/test/integration/aws/default/verify/controls/aws_vpc.rb +++ /dev/null @@ -1,62 +0,0 @@ -fixtures = {} -[ - 'vpc_default_vpc_id', - 'vpc_default_cidr_block', - 'vpc_default_dhcp_options_id', - 'vpc_non_default_vpc_id', - 'vpc_non_default_cidr_block', - 'vpc_non_default_instance_tenancy', - 'vpc_non_default_dhcp_options_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -control "aws_vpc recall" do - describe aws_vpc(fixtures['vpc_default_vpc_id']) do - it { should exist} - end - - describe aws_vpc do - it { should exist } - end - - describe aws_vpc(vpc_id: fixtures['vpc_non_default_vpc_id']) do - it { should exist } - end - - describe aws_vpc('vpc-12345678') do - it { should_not exist } - end -end - -control "aws_vpc properties" do - describe aws_vpc(fixtures['vpc_non_default_vpc_id']) do - its('vpc_id') { should eq fixtures['vpc_non_default_vpc_id'] } - its('state') { should eq 'available' } - its('cidr_block') { should eq fixtures['vpc_non_default_cidr_block']} - its('instance_tenancy') { should eq fixtures['vpc_non_default_instance_tenancy']} - its('dhcp_options_id') { should eq fixtures['vpc_non_default_dhcp_options_id']} - end - - describe aws_vpc do - its('vpc_id') { should eq fixtures['vpc_default_vpc_id'] } - end -end - -control "aws_vpc matchers" do - describe aws_vpc do - it { should be_default } - end - - describe aws_vpc(fixtures['vpc_default_vpc_id']) do - it { should be_default } - end - - describe aws_vpc(fixtures['vpc_non_default_vpc_id']) do - it { should_not be_default } - end -end diff --git a/test/integration/aws/default/verify/controls/aws_vpcs.rb b/test/integration/aws/default/verify/controls/aws_vpcs.rb deleted file mode 100644 index 0b82f2a95..000000000 --- a/test/integration/aws/default/verify/controls/aws_vpcs.rb +++ /dev/null @@ -1,46 +0,0 @@ -fixtures = {} -[ - 'vpc_default_vpc_id', - 'vpc_default_cidr_block', - 'vpc_default_dhcp_options_id', - 'vpc_non_default_vpc_id', - 'vpc_non_default_cidr_block', - 'vpc_non_default_instance_tenancy', - 'vpc_non_default_dhcp_options_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/ec2.tf', - ) -end - -control "aws_vpcs recall" do - describe aws_vpcs do - it { should exist } - its('vpc_ids') { should include fixtures['vpc_default_vpc_id'] } - its('vpc_ids') { should include fixtures['vpc_non_default_vpc_id'] } - its('entries.count') { should cmp 2 } - end -end - -control "aws_vpcs filtering" do - describe aws_vpcs.where { cidr_block.start_with? '172'} do - its('vpc_ids') { should include fixtures['vpc_non_default_vpc_id'] } - end - - describe aws_vpcs.where { dhcp_options_id == fixtures['vpc_default_dhcp_options_id']} do - its('vpc_ids') { should include fixtures['vpc_default_vpc_id']} - end -end - -control "aws_vpcs properties" do - describe aws_vpcs do - its('vpc_ids') { should include fixtures['vpc_default_vpc_id'] } - its('vpc_ids') { should include fixtures['vpc_non_default_vpc_id'] } - its('cidr_blocks') { should include fixtures['vpc_default_cidr_block']} - its('cidr_blocks') { should include fixtures['vpc_non_default_cidr_block']} - its('dhcp_options_ids') { should include fixtures['vpc_default_dhcp_options_id']} - its('dhcp_options_ids') { should include fixtures['vpc_non_default_dhcp_options_id']} - end -end diff --git a/test/integration/aws/default/verify/inspec.yml b/test/integration/aws/default/verify/inspec.yml deleted file mode 100644 index 4f41268d8..000000000 --- a/test/integration/aws/default/verify/inspec.yml +++ /dev/null @@ -1 +0,0 @@ -name: inspec-aws-integration-tests diff --git a/test/integration/aws/minimal/build/aws.tf b/test/integration/aws/minimal/build/aws.tf deleted file mode 100644 index 73041e3f3..000000000 --- a/test/integration/aws/minimal/build/aws.tf +++ /dev/null @@ -1,13 +0,0 @@ -terraform { - required_version = "~> 0.11.0" -} - -provider "aws" { - version = "= 1.13.0" -} - -data "aws_caller_identity" "creds" {} - -output "aws_account_id" { - value = "${data.aws_caller_identity.creds.account_id}" -} diff --git a/test/integration/aws/minimal/verify/controls/aws_iam_password_policy.rb b/test/integration/aws/minimal/verify/controls/aws_iam_password_policy.rb deleted file mode 100644 index 386e75890..000000000 --- a/test/integration/aws/minimal/verify/controls/aws_iam_password_policy.rb +++ /dev/null @@ -1,13 +0,0 @@ -#---------------------- Recall ------------------------# -# Password policy is a per-account singleton. If it's been configured, it exists. -control "aws_iam_password_policy properties" do - describe aws_iam_password_policy do - it { should_not exist } - end -end - -#------------- Properties - Negative Case -------------# -# No negative tests yet - we'd need a third account - -#------------- Matchers - Negative Case -------------# -# No negative tests yet - we'd need a third account \ No newline at end of file diff --git a/test/integration/aws/minimal/verify/controls/aws_iam_root_user.rb b/test/integration/aws/minimal/verify/controls/aws_iam_root_user.rb deleted file mode 100644 index ccac9e24c..000000000 --- a/test/integration/aws/minimal/verify/controls/aws_iam_root_user.rb +++ /dev/null @@ -1,42 +0,0 @@ -fixtures = {} -[ - 'aws_account_id', -].each do |fixture_name| - fixtures[fixture_name] = input( - fixture_name, - default: "default.#{fixture_name}", - description: 'See ../build/iam.tf', - ) -end - -#------------- Property - has_mfa_enabled -------------# -# Positive test in 'default' test set -control "aws_iam_root_user has_mfa_enabled property" do - describe aws_iam_root_user do - it { should_not have_mfa_enabled } - end -end - -#---------- Property - has_virtual_mfa_enabled ----------# -# Positive test in 'default' test set -control "aws_iam_root_user has_virtual_mfa_enabled property" do - describe aws_iam_root_user do - it { should_not have_virtual_mfa_enabled } - end -end - -#---------- Property - has_hardware_mfa_enabled ----------# -# Positive test in 'default' test set -control "aws_iam_root_user has_hardware_mfa_enabled property" do - describe aws_iam_root_user do - it { should_not have_hardware_mfa_enabled } - end -end - -#------------- Property - has_access_key -------------# -# Negative test in 'default' test set -control "aws_iam_root_user has_access_key property" do - describe aws_iam_root_user do - it { should have_access_key } - end -end diff --git a/test/integration/aws/minimal/verify/inspec.yml b/test/integration/aws/minimal/verify/inspec.yml deleted file mode 100644 index 666adc8bc..000000000 --- a/test/integration/aws/minimal/verify/inspec.yml +++ /dev/null @@ -1 +0,0 @@ -name: inspec-aws-integration-tests \ No newline at end of file diff --git a/test/integration/azure/TESTING_AGAINST_AZURE.md b/test/integration/azure/TESTING_AGAINST_AZURE.md deleted file mode 100644 index bd8ef868b..000000000 --- a/test/integration/azure/TESTING_AGAINST_AZURE.md +++ /dev/null @@ -1,71 +0,0 @@ -# Testing Against Azure - Integration Testing - -## Problem Statement - -We want to test Azure-related InSpec resource against Azure itself. This requires a test fixture in Azure to examine using InSpec. - -## General Approach - -We have a Terraform plan to set up and destroy test fixtures in Azure. When the environment is running we have a set of integration tests that may run against it. - -Credentials are handled via a `~/.azure/credentials` file. Create a directory in your home directory called `.azure`. Then create a file called `credentials`. An example file is below: - -``` -[subscription_id] -client_id= -client_secret= -tenant_id= -``` - -Substitute `subscription_id` for your Azure subscription ID. Client ID and client secret can be obtained when you create your application account (instructions below). - -Tenant ID can be obtained by logging into the Azure portal. Browse to the `Azure Active Directory` and click on `properties`. The `Directory ID` is your Tenant ID. - -### Installing Terraform - -Download [Terraform](https://www.terraform.io/downloads.html). We require at least v0.10. To install and choose from multiple Terraform versions, consider using [tfenv](https://github.com/kamatama41/tfenv). - -## Current Solution - -We have registered an application to use for authentication. We use Terraform to create the needed resources that we run our tests against. - -### Creating the Application account - -1. Login to the Azure portal. -2. Click on `Azure Active Directory`. -3. Click on `APP registrations`. -4. Click on `New application registration`. -5. Fill in a name and a Sign-on URL. Select `Web app / API` from the `Application Type` drop down. Save your application. -6. Note your Application ID. This is your `client_id` above. -6. Click on `Settings` -7. Click on `Keys` -8. Create a new password. This value is your `client_secret` above. -9. Go to your subscription (click on `All Services` then subscriptions). Choose your subscription from that list. -11. Note your Subscription ID can be found here. -10. Click `Access Control (IAM)` -11. Click Add -13. Select the `contributor` role. -12. Select the application you just created and save. - -## Running the integration tests -`INSPEC_TERRAFORM_ENVIRONMENT` should be set to a unique value for you to work against. See [Terraform Workspaces](https://www.terraform.io/docs/state/workspaces.html) - -`AZURE_LOCATION` may be set to the region you'd prefer to test in. The default setting is "West Europe". - -To run all Azure integration tests, run: - -`INSPEC_TERRAFORM_ENVIRONMENT=$YOUR_WORKSPACE bundle exec rake test:azure` - -If you are doing something which requires changing the Azure environment, e.g. developing a new Azure module you may want to have your environment running while you make changes. - -`INSPEC_TERRAFORM_ENVIRONMENT=$YOUR_WORKSPACE bundle exec rake test:azure:setup` - -After making any changes to Terraform. Apply your changes. - -`INSPEC_TERRAFORM_ENVIRONMENT=$YOUR_WORKSPACE bundle exec rake test:azure:apply` - -This will automatically regenerate your plan file and apply the changes. - -When you are done, and wish to destroy your environment: - -`INSPEC_TERRAFORM_ENVIRONMENT=$YOUR_WORKSPACE bundle exec rake test:azure:cleanup` diff --git a/test/integration/azure/build/azure.tf b/test/integration/azure/build/azure.tf deleted file mode 100644 index 68d8c90f9..000000000 --- a/test/integration/azure/build/azure.tf +++ /dev/null @@ -1,289 +0,0 @@ -# Configure variables -variable "storage_account_name" {} - -variable "admin_password" {} - -variable "subscription_id" {} -variable "client_id" {} -variable "client_secret" {} -variable "tenant_id" {} - -# Set a unique string which will be appended to public facing items -# to ensure there are no clashes -variable "suffix" {} - -variable "location" { - default = "West Europe" -} - -terraform { - required_version = "~> 0.11.0" -} - -# Configure the Azure RM provider -provider "azurerm" { - version = "~> 1.3" - subscription_id = "${var.subscription_id}" - client_id = "${var.client_id}" - client_secret = "${var.client_secret}" - tenant_id = "${var.tenant_id}" -} - -# Output the sub ID so the fixture system has something to chew on -output "subscription_id" { - value = "${var.subscription_id}" -} - -# Create a resource group for the machine to be created in -resource "azurerm_resource_group" "rg" { - name = "Inspec-Azure" - location = "${var.location}" - - tags { - CreatedBy = "InSpec Azure Integration Tests" - } -} - -# Create the storage account to be used -resource "azurerm_storage_account" "sa" { - name = "${var.storage_account_name}" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - account_tier = "Standard" - account_replication_type = "LRS" -} - -# Create the container in which the hard disks for the machine(s) will be stored -resource "azurerm_storage_container" "container" { - name = "vhds" - resource_group_name = "${azurerm_resource_group.rg.name}" - storage_account_name = "${azurerm_storage_account.sa.name}" - container_access_type = "private" -} - -# Create a Public IP -resource "azurerm_public_ip" "public_ip_1" { - name = "Inspec-PublicIP-1" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - public_ip_address_allocation = "dynamic" - domain_name_label = "linux-external-1-${var.suffix}" -} - -# Create a network security group so it can be tested -resource "azurerm_network_security_group" "nsg" { - name = "Inspec-NSG" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - security_rule { - name = "SSH-22" - priority = 100 - direction = "Inbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "22" - source_address_prefix = "*" - destination_address_prefix = "*" - } -} - -# Create the virtual network for the machines -resource "azurerm_virtual_network" "vnet" { - name = "Inspec-VNet" - address_space = ["10.1.1.0/24"] - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" -} - -# Create the subnet -resource "azurerm_subnet" "subnet" { - name = "Inspec-Subnet" - resource_group_name = "${azurerm_resource_group.rg.name}" - virtual_network_name = "${azurerm_virtual_network.vnet.name}" - address_prefix = "10.1.1.0/24" - - # Attach the NSG to the subnet - network_security_group_id = "${azurerm_network_security_group.nsg.id}" -} - -# Create the NIC for the internal machine -# Give the machine a static IP Address -resource "azurerm_network_interface" "nic1" { - name = "Inspec-NIC-1" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - ip_configuration { - name = "ipConfiguration1" - subnet_id = "${azurerm_subnet.subnet.id}" - private_ip_address_allocation = "static" - private_ip_address = "10.1.1.10" - } -} - -resource "azurerm_network_interface" "nic2" { - name = "Inspec-NIC-2" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - ip_configuration { - name = "ipConfiguration1" - subnet_id = "${azurerm_subnet.subnet.id}" - private_ip_address_allocation = "dynamic" - public_ip_address_id = "${azurerm_public_ip.public_ip_1.id}" - } -} - -resource "azurerm_network_interface" "nic3" { - name = "Inspec-NIC-3" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - - ip_configuration { - name = "ipConfiguration1" - subnet_id = "${azurerm_subnet.subnet.id}" - private_ip_address_allocation = "dynamic" - } -} - -# Create the machine for testing -resource "azurerm_virtual_machine" "vm_linux_internal" { - name = "Linux-Internal-VM" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - network_interface_ids = ["${azurerm_network_interface.nic1.id}"] - vm_size = "Standard_DS2_v2" - - # Configure machine with Ubuntu - storage_image_reference { - publisher = "Canonical" - offer = "UbuntuServer" - sku = "16.04.0-LTS" - version = "latest" - } - - # Create the OS disk - storage_os_disk { - name = "Linux-Internal-OSDisk-MD" - caching = "ReadWrite" - create_option = "FromImage" - managed_disk_type = "Standard_LRS" - } - - # Specify the name of the machine and the access credentials - os_profile { - computer_name = "linux-internal-1" - admin_username = "azure" - admin_password = "${var.admin_password}" - } - - os_profile_linux_config { - disable_password_authentication = false - } - - # Add boot diagnostics to the machine. These will be added to the - # created storage acccount - boot_diagnostics { - enabled = true - storage_uri = "${azurerm_storage_account.sa.primary_blob_endpoint}" - } -} - -resource "azurerm_virtual_machine" "vm_linux_external" { - name = "Linux-External-VM" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - network_interface_ids = ["${azurerm_network_interface.nic2.id}"] - vm_size = "Standard_DS2_v2" - - tags { - Description = "Externally facing Linux machine to be used as a web server" - } - - # Configure machine with Ubuntu - storage_image_reference { - publisher = "Canonical" - offer = "UbuntuServer" - sku = "16.04.0-LTS" - version = "latest" - } - - # Create the OS disk - storage_os_disk { - name = "linux-external-osdisk" - vhd_uri = "${azurerm_storage_account.sa.primary_blob_endpoint}${azurerm_storage_container.container.name}/linux-external-osdisk.vhd" - caching = "ReadWrite" - create_option = "FromImage" - } - - # Create 1 data disk to be used for testing - storage_data_disk { - name = "linux-external-datadisk-1" - vhd_uri = "${azurerm_storage_account.sa.primary_blob_endpoint}${azurerm_storage_container.container.name}/linux-internal-datadisk-1.vhd" - disk_size_gb = 15 - create_option = "empty" - lun = 0 - } - - # Specify the name of the machine and the access credentials - os_profile { - computer_name = "linux-external-1" - admin_username = "azure" - admin_password = "${var.admin_password}" - } - - os_profile_linux_config { - disable_password_authentication = true - - ssh_keys { - path = "/home/azure/.ssh/authorized_keys" - key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDOxB7GqUxppqRBG5pB2fkkhlWkWUWmFjO3ZEc+VW70erOJWfUvhzBDDQziAOVKtNF2NsY0uyRJqwaP1idL0F7GDQtQl+HhkKW1gOCoTrNptJiYfIm05jTETRWObP0kGMPoAWlkWPBluUAI74B4nkvg7SKNpe36IZhuA8/kvVjxBfWy0r/b/dh+QEIb1eE8HfELAN8SrvrydT7My7g0YFT65V00A2HVa5X3oZaBXRKbmd5gZXBJXEbgHZqA9+NnIQkZXH0vkYYOQTANB8taVwjNVftpXzf2zEupONCYOOoIAep2tXuv2YmWuHr/Y5rCv2mK28ZVcM7W9UmwM0CMHZE7 azure@inspec.local" - } - } -} - -resource "azurerm_virtual_machine" "vm_windows_internal" { - name = "Windows-Internal-VM" - location = "${var.location}" - resource_group_name = "${azurerm_resource_group.rg.name}" - network_interface_ids = ["${azurerm_network_interface.nic3.id}"] - vm_size = "Standard_DS2_v2" - - # Configure machine with Ubuntu - storage_image_reference { - publisher = "MicrosoftWindowsServer" - offer = "WindowsServer" - sku = "2016-Datacenter" - version = "latest" - } - - # Create the OS disk - storage_os_disk { - name = "Windows-Internal-OSDisk-MD" - caching = "ReadWrite" - create_option = "FromImage" - managed_disk_type = "Standard_LRS" - } - - # Create 1 data disk to be used for testing - storage_data_disk { - name = "Windows-Internal-DataDisk-1-MD" - create_option = "Empty" - managed_disk_type = "Standard_LRS" - lun = 0 - disk_size_gb = "1024" - } - - # Specify the name of the machine and the access credentials - os_profile { - computer_name = "win-internal-1" - admin_username = "azure" - admin_password = "${var.admin_password}" - } - - os_profile_windows_config { - provision_vm_agent = true - } -} diff --git a/test/integration/azure/verify/controls/generic_external_vm.rb b/test/integration/azure/verify/controls/generic_external_vm.rb deleted file mode 100644 index 8c73a20cb..000000000 --- a/test/integration/azure/verify/controls/generic_external_vm.rb +++ /dev/null @@ -1,44 +0,0 @@ -title 'External Virtual Machine Properties' - -control 'azure-generic-vm-linux-external-2.0' do - - impact 1.0 - title 'Ensure External VM was built with the correct Image and has the correct properties' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_generic_resource(group_name: 'Inspec-Azure', name: 'Linux-External-VM') do - - its('location') { should cmp 'westeurope' } - - # check the storage profile for the machine - its('properties.storageProfile.imageReference.publisher') { should cmp 'Canonical' } - its('properties.storageProfile.imageReference.offer') { should cmp 'UbuntuServer' } - its('properties.storageProfile.imageReference.sku') { should cmp '16.04.0-LTS' } - - # Check the disk for the machine - its('properties.storageProfile.osDisk.osType') { should cmp 'Linux' } - its('properties.storageProfile.osDisk.createOption') { should cmp 'FromImage' } - its('properties.storageProfile.osDisk.name') { should cmp 'linux-external-osdisk' } - its('properties.storageProfile.osDisk.caching') { should cmp 'ReadWrite' } - - # Esnure that the machine has no data disks attached - its('properties.storageProfile.dataDisks.count') { should eq 1 } - - # Check the hardwareProfile - its('properties.hardwareProfile.vmSize') { should cmp 'Standard_DS2_v2' } - - # Check the network interfaces - its('properties.networkProfile.networkInterfaces.count') { should eq 1 } - - # Determine the authentication and OS type - its('properties.osProfile.computerName') { should eq 'linux-external-1' } - its('properties.osProfile.adminUsername') { should eq 'azure' } - its('properties.osProfile.linuxConfiguration.disablePasswordAuthentication') { should be true } - - # Check that the tags have been set properly - it { should have_tags } - its('tag_count') { should be 1 } - its('tags') { should include 'Description' } - its('Description_tag') { should match 'Externally facing' } - end -end diff --git a/test/integration/azure/verify/controls/generic_external_vm_nic.rb b/test/integration/azure/verify/controls/generic_external_vm_nic.rb deleted file mode 100644 index 806ff929f..000000000 --- a/test/integration/azure/verify/controls/generic_external_vm_nic.rb +++ /dev/null @@ -1,31 +0,0 @@ -title 'External VM Network Interface Card' - -control 'azure-generic-vm-external-nic-2.0' do - - impact 1.0 - title 'Ensure that the NIC for the external VM is correctly setup' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_generic_resource(group_name: 'Inspec-Azure', name: 'Inspec-NIC-2') do - - # There should be no tags - it { should_not have_tags } - its('tags.count') { should eq 0 } - - # The resources should be a network interface - its('type') { should cmp 'Microsoft.Network/networkInterfaces' } - - # It should have only 1 ipConfiguration - its('properties.ipConfigurations.count') { should eq 1 } - - # There should be no custom dns settings - its('properties.dnsSettings.dnsServers.count') { should eq 0 } - its('properties.dnsSettings.appliedDnsServers.count') { should eq 0 } - - # This NIC should be connected to the correct machine - its('properties.virtualMachine.id') { should match 'Linux-External-VM' } - - its('properties.enableAcceleratedNetworking') { should be false } - its('properties.enableIPForwarding') { should be false } - end -end diff --git a/test/integration/azure/verify/controls/generic_internal_vm.rb b/test/integration/azure/verify/controls/generic_internal_vm.rb deleted file mode 100644 index 50bb86af9..000000000 --- a/test/integration/azure/verify/controls/generic_internal_vm.rb +++ /dev/null @@ -1,44 +0,0 @@ -title 'Internal Virtual Machine Properties' - -control 'azure-generic-vm-linux-internal-2.0' do - - impact 1.0 - title 'Ensure Internal VM was built with the correct Image and has the correct properties' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_generic_resource(group_name: 'Inspec-Azure', name: 'Linux-Internal-VM') do - - its('location') { should cmp 'westeurope' } - - # check the storage profile for the machine - its('properties.storageProfile.imageReference.publisher') { should cmp 'Canonical' } - its('properties.storageProfile.imageReference.offer') { should cmp 'UbuntuServer' } - its('properties.storageProfile.imageReference.sku') { should cmp '16.04.0-LTS' } - - # Check the disk for the machine - its('properties.storageProfile.osDisk.osType') { should cmp 'Linux' } - its('properties.storageProfile.osDisk.name') { should cmp 'Linux-Internal-OSDisk-MD' } - its('properties.storageProfile.osDisk.caching') { should cmp 'ReadWrite' } - - # This machine has been setup with a Managed Disk for the OSDisk, ensure that - # it is linked to the correct disk - its('properties.storageProfile.osDisk.managedDisk.id') { should match 'Linux-Internal-OSDisk-MD' } - - # Esnure that the machine has a data disk attached - its('properties.storageProfile.dataDisks.count') { should eq 0 } - - # Check the hardwareProfile - its('properties.hardwareProfile.vmSize') { should cmp 'Standard_DS2_v2' } - - # Check the network interfaces - its('properties.networkProfile.networkInterfaces.count') { should eq 1 } - - # Determine the authentication and OS type - its('properties.osProfile.computerName') { should eq 'linux-internal-1' } - its('properties.osProfile.adminUsername') { should eq 'azure' } - its('properties.osProfile.linuxConfiguration.disablePasswordAuthentication') { should be false } - - # There should be no tags on the machine - its('tags.count') { should eq 0 } - end -end diff --git a/test/integration/azure/verify/controls/generic_internal_vm_nic.rb b/test/integration/azure/verify/controls/generic_internal_vm_nic.rb deleted file mode 100644 index 78210942f..000000000 --- a/test/integration/azure/verify/controls/generic_internal_vm_nic.rb +++ /dev/null @@ -1,31 +0,0 @@ -title 'Internal VM Network Interface Card' - -control 'azure-generic-vm-internal-nic-2.0' do - - impact 1.0 - title 'Ensure that the NIC for the internal VM is correctly setup' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_generic_resource(group_name: 'Inspec-Azure', name: 'Inspec-NIC-1') do - - # There should be no tags - it { should_not have_tags } - its('tags.count') { should eq 0 } - - # The resources should be a network interface - its('type') { should cmp 'Microsoft.Network/networkInterfaces' } - - # It should have only 1 ipConfiguration - its('properties.ipConfigurations.count') { should eq 1 } - - # There should be no custom dns settings - its('properties.dnsSettings.dnsServers.count') { should eq 0 } - its('properties.dnsSettings.appliedDnsServers.count') { should eq 0 } - - # This NIC should be connected to the correct machine - its('properties.virtualMachine.id') { should match 'Linux-Internal-VM' } - - its('properties.enableAcceleratedNetworking') { should be false } - its('properties.enableIPForwarding') { should be false } - end -end diff --git a/test/integration/azure/verify/controls/generic_linux_vm_managed_os_disk.rb b/test/integration/azure/verify/controls/generic_linux_vm_managed_os_disk.rb deleted file mode 100644 index a4c2b6bf7..000000000 --- a/test/integration/azure/verify/controls/generic_linux_vm_managed_os_disk.rb +++ /dev/null @@ -1,31 +0,0 @@ -title 'Managed Disk' - -control 'azure-generic-managed-os-disk-1.0' do - - impact 1.0 - title 'A managed disk was created for on the of machines, ensure that it is configured correctly' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_generic_resource(group_name: 'Inspec-Azure', name: 'Linux-Internal-OSDisk-MD') do - - # Ensure that it is attached, or 'managedBy' the correct machine - its('managed_by') { should match 'Linux-Internal-VM' } - - # Check some of the properties - its('properties.osType') { should cmp 'Linux' } - - # This disk should have been created from an image - # Ensure that it is the correct one - its('properties.creationData.createOption') { should eq 'FromImage' } - - # This disk should be an ubuntu image - its('properties.creationData.imageReference.id') { should match 'Canonical' } - its('properties.creationData.imageReference.id') { should match 'UbuntuServer' } - its('properties.creationData.imageReference.id') { should match '16.04.0-LTS' } - - its('properties.diskSizeGB') { should be > 25 } - - # ensure the disk is attached - its('properties.diskState') { should cmp 'Attached' } - end -end diff --git a/test/integration/azure/verify/controls/generic_network_security_group.rb b/test/integration/azure/verify/controls/generic_network_security_group.rb deleted file mode 100644 index bd15c6d95..000000000 --- a/test/integration/azure/verify/controls/generic_network_security_group.rb +++ /dev/null @@ -1,20 +0,0 @@ -title 'Network Security Group Properties' - -control 'azure-generic-network-security-group-1.0' do - - impact 1.0 - title 'Ensure that the NSG has been setup as expected' - - describe azure_generic_resource(group_name: 'Inspec-Azure', name: 'Inspec-NSG') do - - # Check that the NSG is in the correct location - its('location') { should cmp 'westeurope' } - - # It should not have any tags - it { should_not have_tags } - - # It has been provisionned successfully - its('properties.provisioningState') { should eq 'Succeeded' } - - end -end diff --git a/test/integration/azure/verify/controls/generic_public_ip_address.rb b/test/integration/azure/verify/controls/generic_public_ip_address.rb deleted file mode 100644 index 01bc46c4e..000000000 --- a/test/integration/azure/verify/controls/generic_public_ip_address.rb +++ /dev/null @@ -1,26 +0,0 @@ -title 'Public IP Address Properties' - -control 'azure-generic-public-ip-address-1.0' do - - impact 1.0 - title 'Ensure that the Public IP Address has been configured correctly' - - describe azure_generic_resource(group_name: 'Inspec-Azure', name: 'Inspec-PublicIP-1') do - - its('type') { should cmp 'Microsoft.Network/publicIPAddresses' } - its('location') { should cmp 'westeurope' } - - # There should be no tags - it { should_not have_tags } - - its('properties.provisioningState') { should cmp 'Succeeded' } - - # The IP address should be dynamically assigned - its('properties.publicIPAllocationMethod') { should cmp 'Dynamic' } - - its('properties.dnsSettings.domainNameLabel') { should match 'linux-external-1' } - - # Ensure that this Public IP is assigned to the Nic that is assigned to the external vm - its('properties.ipConfiguration.id') { should match 'Inspec-NIC-2' } - end -end \ No newline at end of file diff --git a/test/integration/azure/verify/controls/generic_resources.rb b/test/integration/azure/verify/controls/generic_resources.rb deleted file mode 100644 index e522b8c5c..000000000 --- a/test/integration/azure/verify/controls/generic_resources.rb +++ /dev/null @@ -1,25 +0,0 @@ -title 'Check Azure Resources' - -control 'azure-generic-resource-group-resources-1.0' do - - impact 1.0 - title 'Check that the resource group has the correct resources' - - # Ensure that the expected resources have been deployed - describe azure_generic_resource(group_name: 'Inspec-Azure') do - its('total') { should eq 13 } - its('Microsoft.Compute/virtualMachines') { should eq 3 } - its('Microsoft.Network/networkInterfaces') { should eq 3 } - its('Microsoft.Network/publicIPAddresses') { should eq 1 } - its('Microsoft.Network/networkSecurityGroups') { should eq 1 } - its('Microsoft.Storage/storageAccounts') { should eq 1 } - its('Microsoft.Network/virtualNetworks') { should eq 1 } - its('Microsoft.Compute/disks') { should eq 3 } - - # Check the tags - it { should have_tags } - its('tag_count') { should be 1 } - its('tags') { should include 'CreatedBy' } - its('CreatedBy_tag') { should cmp 'InSpec Azure Integration Tests' } - end -end diff --git a/test/integration/azure/verify/controls/generic_storage_account.rb b/test/integration/azure/verify/controls/generic_storage_account.rb deleted file mode 100644 index 5860402e9..000000000 --- a/test/integration/azure/verify/controls/generic_storage_account.rb +++ /dev/null @@ -1,30 +0,0 @@ -title 'Check Azure Resources' - -control 'azure-generic-storage-account-2.0' do - - impact 1.0 - title 'Check the storage account' - - # Get the storage account by type, this is because in the tests - # the storage account name is randomly generated so it cannot be known to perform - # these inspec tests - describe azure_generic_resource(group_name: 'Inspec-Azure', type: 'Microsoft.Storage/storageAccounts') do - its('total') { should be 1 } - - # There should be no tags - it { should_not have_tags } - - # Check that the blob and file services are enabled - its('properties.encryption.services.blob.enabled') { should be true } - its('properties.encryption.services.file.enabled') { should be true } - its('properties.encryption.keySource') { should cmp 'Microsoft.Storage' } - - its('properties.provisioningState') { should cmp 'Succeeded' } - - its('properties.primaryLocation') { should cmp 'westeurope' } - its('properties.statusOfPrimary') { should cmp 'available' } - - # Determine if it only supports HTTPS traffic - its('properties.supportsHttpsTrafficOnly') { should be false } - end -end diff --git a/test/integration/azure/verify/controls/generic_virtual_network.rb b/test/integration/azure/verify/controls/generic_virtual_network.rb deleted file mode 100644 index 6024e44f4..000000000 --- a/test/integration/azure/verify/controls/generic_virtual_network.rb +++ /dev/null @@ -1,27 +0,0 @@ -title 'Virtual Network Properties' - -control 'azure-generic-virtual-network-2.0' do - - impact 1.0 - title 'Ensure that the virtual network has been created with the correct address space and subnet' - - describe azure_generic_resource(group_name: 'Inspec-Azure', - name: 'Inspec-VNet') do - - # Check that this named resource is indeed a virtual network - its('type') { should cmp 'Microsoft.Network/virtualNetworks' } - its('location') { should cmp 'westeurope' } - - # There should be no tags - it { should_not have_tags } - - # Ensure that the address prefix for the VNet is correct - # This will return an array so the `include` matcher needs to be used to - # see if the specified address prefix is present - its('properties.addressSpace.addressPrefixes') { should include '10.1.1.0/24' } - - # There should be one subnet - its('properties.subnets.count') { should eq 1 } - - end -end diff --git a/test/integration/azure/verify/controls/generic_windows_internal_vm.rb b/test/integration/azure/verify/controls/generic_windows_internal_vm.rb deleted file mode 100644 index b800cd704..000000000 --- a/test/integration/azure/verify/controls/generic_windows_internal_vm.rb +++ /dev/null @@ -1,48 +0,0 @@ -title 'Internal Virtual Machine Properties' - -control 'azure-generic-vm-windows-internal-2.0' do - - impact 1.0 - title 'Ensure Windows Internal VM was built with the correct Image and has the correct properties' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_generic_resource(group_name: 'Inspec-Azure', - name: 'Windows-Internal-VM') do - - its('location') { should cmp 'westeurope' } - - # check the storage profile for the machine - its('properties.storageProfile.imageReference.publisher') { should cmp 'MicrosoftWindowsServer' } - its('properties.storageProfile.imageReference.offer') { should cmp 'WindowsServer' } - its('properties.storageProfile.imageReference.sku') { should cmp '2016-Datacenter' } - - # Check the disk for the machine - its('properties.storageProfile.osDisk.osType') { should cmp 'Windows' } - its('properties.storageProfile.osDisk.name') { should cmp 'Windows-Internal-OSDisk-MD' } - its('properties.storageProfile.osDisk.caching') { should cmp 'ReadWrite' } - - # This machine has been setup with a Managed Disk for the OSDisk, ensure that - # it is linked to the correct disk - its('properties.storageProfile.osDisk.managedDisk.id') { should match 'Windows-Internal-OSDisk-MD' } - its('properties.storageProfile.osDisk.managedDisk.storageAccountType') { should cmp 'Standard_LRS' } - - # Esnure that the machine has a data disk attached - its('properties.storageProfile.dataDisks.count') { should eq 1 } - - # Check the hardwareProfile - its('properties.hardwareProfile.vmSize') { should cmp 'Standard_DS2_v2' } - - # Check the network interfaces - its('properties.networkProfile.networkInterfaces.count') { should eq 1 } - - # Determine the authentication and OS type - its('properties.osProfile.computerName') { should eq 'win-internal-1' } - its('properties.osProfile.adminUsername') { should eq 'azure' } - its('properties.osProfile.windowsConfiguration.provisionVMAgent') { should be true } - its('properties.osProfile.windowsConfiguration.enableAutomaticUpdates') { should be false } - - # There should be no tags - it { should_not have_tags } - end - -end diff --git a/test/integration/azure/verify/controls/generic_windows_internal_vm_nic.rb b/test/integration/azure/verify/controls/generic_windows_internal_vm_nic.rb deleted file mode 100644 index ac57bb5fd..000000000 --- a/test/integration/azure/verify/controls/generic_windows_internal_vm_nic.rb +++ /dev/null @@ -1,32 +0,0 @@ -title 'Windows Internal VM Network Interface Card' - -control 'azure-generic-vm-windows-internal-nic-1.0' do - - impact 1.0 - title 'Ensure that the NIC for the Windows internal VM is correctly setup' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_generic_resource(group_name: 'Inspec-Azure', - name: 'Inspec-NIC-3') do - - # There should be no tags - it { should_not have_tags } - its('tags.count') { should eq 0 } - - # The resources should be a network interface - its('type') { should cmp 'Microsoft.Network/networkInterfaces' } - - # It should have only 1 ipConfiguration - its('properties.ipConfigurations.count') { should eq 1 } - - # There should be no custom dns settings - its('properties.dnsSettings.dnsServers.count') { should eq 0 } - its('properties.dnsSettings.appliedDnsServers.count') { should eq 0 } - - # This NIC should be connected to the correct machine - its('properties.virtualMachine.id') { should match 'Windows-Internal-VM' } - - its('properties.enableAcceleratedNetworking') { should be false } - its('properties.enableIPForwarding') { should be false } - end -end \ No newline at end of file diff --git a/test/integration/azure/verify/controls/resource_group.rb b/test/integration/azure/verify/controls/resource_group.rb deleted file mode 100644 index ac87beea0..000000000 --- a/test/integration/azure/verify/controls/resource_group.rb +++ /dev/null @@ -1,59 +0,0 @@ -title 'Resource Group Type Counts' - -control 'azure-resource-group-1.0' do - impact 1.0 - title 'Ensure that the specified resource group has the correct number of Azure resources and metadata' - - # Obtain counts for all resources in the resource group - describe azure_resource_group(name: 'Inspec-Azure') do - # Ensure that the name is correct - this is a little superfluous as this was used to select the resource - its('name') { should cmp 'Inspec-Azure' } - - # Where in Azure is the resource group located - its('location') { should cmp 'westeurope' } - - # Was the resource group provisionned successfully? - its('provisioning_state') { should cmp 'Succeeded' } - - # Make sure that the resource group has tags on it - it { should have_tags } - its('tag_count') { should be 1 } - its('tags') { should include 'CreatedBy' } - its('CreatedBy_tag') { should cmp 'InSpec Azure Integration Tests' } - - # How many resources are in the resource group in total - its('total') { should eq 13 } - - # Does the RG have virtual machines and how many - it { should have_vms } - its('vm_count') { should eq 3 } - - # Does the RG have network cards and how many - it { should have_nics } - its('nic_count') { should eq 3 } - - # Does the RG have any public ip addresses and how many - it { should have_public_ips } - its('public_ip_count') { should eq 1 } - - # Does the RG have network security groups and how many - it { should have_nsgs } - its('nsg_count') { should eq 1 } - - # Does the RG have storage accounts and how many - it { should have_sas } - its('sa_count') { should eq 1 } - - # Does the RG have virtual networks and how many - it { should have_vnets } - its('vnet_count') { should eq 1 } - - # Does the RG have managed disks and how many - it { should have_managed_disks } - its('managed_disk_count') { should eq 3 } - - # Does the RG have managed disk images - it { should_not have_managed_disk_images } - its('managed_disk_image_count') { should eq 0 } - end -end diff --git a/test/integration/azure/verify/controls/virtual_machine_external_vm.rb b/test/integration/azure/verify/controls/virtual_machine_external_vm.rb deleted file mode 100644 index 35e29cadd..000000000 --- a/test/integration/azure/verify/controls/virtual_machine_external_vm.rb +++ /dev/null @@ -1,69 +0,0 @@ -title 'Internal Virtual Machine Properties' - -control 'azure-virtual-machine-vm-external-2.0' do - - impact 1.0 - title 'Ensure External VM was built with the correct Image and has the correct properties' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_virtual_machine(group_name: 'Inspec-Azure', - name: 'Linux-External-VM') do - - # Ensure that the location of the resource is correct - its('location') { should cmp 'westeurope' } - - # Check the type. However this should always be this type because the - # resource azure_virtual_machine has been used which forces this type - its('type') { should cmp 'Microsoft.Compute/virtualMachines' } - - # Check the name, although this has beeb specified in the options - its('name') { should cmp 'Linux-External-VM' } - - # Ensure that tags have been set - it { should have_tags } - its('tags') { should include 'Description' } - its('Description_tag') { should match 'Externally facing Linux' } - - # Ensure that the machine has been created from the correct image - its('publisher') { should cmp 'Canonical' } - its('offer') { should cmp 'UbuntuServer' } - its('sku') { should cmp '16.04.0-LTS' } - - # Check the type of the machine and the disk that it is using - its('os_type') { should cmp 'Linux' } - its('os_disk_name') { should cmp 'linux-external-osdisk' } - its('caching') { should cmp 'ReadWrite' } - its('disk_size_gb') { should be >= 25 } - its('create_option') { should cmp 'FromImage' } - - # The OS disk should be a managed disk - it { should_not have_managed_osdisk } - - # Ensure that the machine is of the correct size - its('vm_size') { should cmp 'Standard_DS2_v2'} - - # Check the admin username for the machine and the hostname - its('admin_username') { should cmp 'azure' } - its('computer_name') { should cmp 'linux-external-1' } - - # Check that the machine has a NIC and that the correct one is connected - it { should have_nics } - its('nic_count') { should eq 1 } - its('connected_nics') { should include 'Inspec-NIC-2' } - - # This machine should not have any data disks - it { should have_data_disks } - - # Password authentication should be enabled - it { should_not have_password_authentication } - its('password_authentication?') { should be false } - - # No ssh keys should be assigned to the machine - it { should have_ssh_keys } - its('ssh_keys?') { should be true } - its('ssh_keys') { should include /azure@inspec.local/ } - - # The machine should have boot diagnostics enabled - it { should_not have_boot_diagnostics } - end -end \ No newline at end of file diff --git a/test/integration/azure/verify/controls/virtual_machine_internal_vm.rb b/test/integration/azure/verify/controls/virtual_machine_internal_vm.rb deleted file mode 100644 index e3865c23b..000000000 --- a/test/integration/azure/verify/controls/virtual_machine_internal_vm.rb +++ /dev/null @@ -1,67 +0,0 @@ -title 'Internal Virtual Machine Properties' - -control 'azure-virtual-machine-vm-internal-2.0' do - - impact 1.0 - title 'Ensure Internal VM was built with the correct Image and has the correct properties' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_virtual_machine(group_name: 'Inspec-Azure', - name: 'Linux-Internal-VM') do - - # Ensure that the location of the resource is correct - its('location') { should cmp 'westeurope' } - - # Check the type. However this should always be this type because the - # resource azure_virtual_machine has been used which forces this type - its('type') { should cmp 'Microsoft.Compute/virtualMachines' } - - # Check the name, although this has beeb specified in the options - its('name') { should cmp 'Linux-Internal-VM' } - - # Make sure there are no tags on the machine - it { should_not have_tags } - - # Ensure that the machine has been created from the correct image - its('publisher') { should cmp 'Canonical' } - its('offer') { should cmp 'UbuntuServer' } - its('sku') { should cmp '16.04.0-LTS' } - - # Check the type of the machine and the disk that it is using - its('os_type') { should cmp 'Linux' } - its('os_disk_name') { should cmp 'Linux-Internal-OSDisk-MD' } - its('caching') { should cmp 'ReadWrite' } - its('disk_size_gb') { should be >= 30 } - its('create_option') { should cmp 'FromImage' } - its('storage_account_type') { should cmp 'Standard_LRS' } - - # The OS disk should be a managed disk - it { should have_managed_osdisk } - - # Ensure that the machine is of the correct size - its('vm_size') { should cmp 'Standard_DS2_v2'} - - # Check the admin username for the machine and the hostname - its('admin_username') { should cmp 'azure' } - its('computer_name') { should cmp 'linux-internal-1' } - - # Check that the machine has a NIC and that the correct one is connected - it { should have_nics } - its('nic_count') { should eq 1 } - its('connected_nics') { should include 'Inspec-NIC-1' } - - # This machine should not have any data disks - it { should_not have_data_disks } - - # Password authentication should be enabled - it { should have_password_authentication } - its('password_authentication?') { should be true } - - # No ssh keys should be assigned to the machine - it { should_not have_ssh_keys } - its('ssh_keys?') { should be false } - - # The machine should have boot diagnostics enabled - it { should have_boot_diagnostics } - end -end \ No newline at end of file diff --git a/test/integration/azure/verify/controls/virtual_machine_linux_external_vm_datadisk.rb b/test/integration/azure/verify/controls/virtual_machine_linux_external_vm_datadisk.rb deleted file mode 100644 index 1bdc0e2af..000000000 --- a/test/integration/azure/verify/controls/virtual_machine_linux_external_vm_datadisk.rb +++ /dev/null @@ -1,20 +0,0 @@ -title 'Windows Internal Machine Data Disks' - -control 'azure-virtual-machine-vm-linux-external-datadisks-1.0' do - - # Select the first data disk of the Windows Internal Machine - describe azure_virtual_machine_data_disk(group_name: 'Inspec-Azure', name: 'Linux-External-VM').where(number: 1) do - its('lun') { should cmp 0 } - - # Ensure that the the name of the managed disk is correct - its('name') { should cmp 'linux-external-datadisk-1' } - - # Ensure that its size, in GB, is correct - its('size') { should cmp >= 15 } - its('caching') { should cmp 'None' } - its('create_option') { should cmp 'Empty' } - - # This should be a managed disk - its('is_managed_disk?') { should cmp false } - end -end diff --git a/test/integration/azure/verify/controls/virtual_machine_windows_internal_vm.rb b/test/integration/azure/verify/controls/virtual_machine_windows_internal_vm.rb deleted file mode 100644 index 031f91310..000000000 --- a/test/integration/azure/verify/controls/virtual_machine_windows_internal_vm.rb +++ /dev/null @@ -1,71 +0,0 @@ -title 'Windows Internal Virtual Machine Properties' - -control 'azure-virtual-machine-vm-windows-internal-1.0' do - - impact 1.0 - title 'Ensure Internal VM was built with the correct Image and has the correct properties' - - # Ensure that the virtual machine has been created with the correct attributes - describe azure_virtual_machine(group_name: 'Inspec-Azure', - name: 'Windows-Internal-VM') do - - # Ensure that the location of the resource is correct - its('location') { should cmp 'westeurope' } - - # Check the type. However this should always be this type because the - # resource azure_virtual_machine has been used which forces this type - its('type') { should cmp 'Microsoft.Compute/virtualMachines' } - - # Check the name, although this has beeb specified in the options - its('name') { should cmp 'Windows-Internal-VM' } - - # There should be no tags - it { should_not have_tags } - - # Ensure that the machine has been created from the correct image - its('publisher') { should cmp 'MicrosoftWindowsServer' } - its('offer') { should cmp 'WindowsServer' } - its('sku') { should cmp '2016-Datacenter' } - - # Check the type of the machine and the disk that it is using - its('os_type') { should cmp 'Windows' } - its('os_disk_name') { should cmp 'Windows-Internal-OSDisk-MD' } - its('caching') { should cmp 'ReadWrite' } - its('disk_size_gb') { should be >= 30 } - its('create_option') { should cmp 'FromImage' } - its('storage_account_type') { should cmp 'Standard_LRS' } - - # The OS disk should be a managed disk - it { should have_managed_osdisk } - - # Ensure that the machine is of the correct size - its('vm_size') { should cmp 'Standard_DS2_v2'} - - # Check the admin username for the machine and the hostname - its('admin_username') { should cmp 'azure' } - its('computer_name') { should cmp 'win-internal-1' } - - # Check that the machine has a NIC and that the correct one is connected - it { should have_nics } - its('nic_count') { should eq 1 } - its('connected_nics') { should include 'Inspec-NIC-3' } - - # This machine should not have any data disks - it { should have_data_disks } - - # Password authentication should be enabled - it { should have_password_authentication } - its('password_authentication?') { should be true } - - # No ssh keys should be assigned to the machine - it { should_not have_ssh_keys } - its('ssh_keys?') { should be false } - - # The machine should have boot diagnostics enabled - it { should_not have_boot_diagnostics } - - # Ensure that the agent has been provisionned and automatic updates are disabled - it { should have_provision_vmagent } - it { should_not have_automatic_agent_update } - end -end \ No newline at end of file diff --git a/test/integration/azure/verify/controls/virtual_machine_windows_internal_vm_datadisk.rb b/test/integration/azure/verify/controls/virtual_machine_windows_internal_vm_datadisk.rb deleted file mode 100644 index ef9c11105..000000000 --- a/test/integration/azure/verify/controls/virtual_machine_windows_internal_vm_datadisk.rb +++ /dev/null @@ -1,25 +0,0 @@ -title 'Windows Internal Machine Data Disks' - -control 'azure-virtual-machine-vm-windows-internal-datadisks-1.0' do - - # Select the first data disk of the Windows Internal Machine - describe azure_virtual_machine_data_disk(group_name: 'Inspec-Azure', name: 'Windows-Internal-VM').where(number: 1) do - its('lun') { should cmp 0 } - - # Ensure that the the name of the managed disk is correct - its('name') { should cmp 'Windows-Internal-DataDisk-1-MD' } - - # Ensure that its size, in GB, is correct - its('size') { should cmp >= 15 } - its('caching') { should cmp 'None' } - its('create_option') { should cmp 'Empty' } - - # This should be a managed disk - its('is_managed_disk?') { should cmp true } - - # If the disk is a managed disk then the following values should be available - # The storage account type and the resource group that the managed disk is in - its('storage_account_type') { should cmp 'Standard_LRS' } - its('resource_group') { should cmp 'Inspec-Azure' } - end -end diff --git a/test/integration/azure/verify/inspec.yml b/test/integration/azure/verify/inspec.yml deleted file mode 100644 index 6edf1804a..000000000 --- a/test/integration/azure/verify/inspec.yml +++ /dev/null @@ -1 +0,0 @@ -name: inspec-azure-integration-tests diff --git a/test/unit/resource_supports/aws/aws_resource_mixin_test.rb b/test/unit/resource_supports/aws/aws_resource_mixin_test.rb deleted file mode 100644 index 70ae88c75..000000000 --- a/test/unit/resource_supports/aws/aws_resource_mixin_test.rb +++ /dev/null @@ -1,43 +0,0 @@ -# copyright: 2017, Chef Software Inc. - -require "helper" - -require "resource_support/aws" -require "resource_support/aws/aws_resource_mixin" - -describe "AwsResourceMixin" do - describe "initialize" do - class AwsResourceMixinError - include AwsResourceMixin - def validate_params(_resource_params) - raise ArgumentError, "this param is not right" - end - end - - # rubocop:disable Style/BlockDelimiters - - it "confirm ArgumentError is raised when testing" do - _ { - AwsResourceMixinError.new({}) - }.must_raise ArgumentError - end - - class AwsResourceMixinLive - include AwsResourceMixin - def validate_params(_resource_params) - raise ArgumentError, "this param is not right" - end - - # if inspec is defined and returns true we are a live test - def inspec - true - end - end - - it "confirm ResourceFailed is raised when live" do - _ { - AwsResourceMixinLive.new({}) - }.must_raise Inspec::Exceptions::ResourceFailed - end - end -end diff --git a/test/unit/resources/aws_billing_report_test.rb b/test/unit/resources/aws_billing_report_test.rb deleted file mode 100644 index c5bc0f0df..000000000 --- a/test/unit/resources/aws_billing_report_test.rb +++ /dev/null @@ -1,83 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_billing_report" - -require "fixtures/files/aws_billing_backend" - -require "resource_support/aws" - -class EmptyAwsBillingReportTest < Minitest::Test - def setup - AwsBillingReport::BackendFactory.select(MockAwsBillingReports::Empty) - end - - def test_empty_query - assert_raises(ArgumentError) { AwsBillingReport.new } - end -end - -class BasicAwsBillingReportTest < Minitest::Test - def setup - AwsBillingReport::BackendFactory.select(MockAwsBillingReports::Basic) - end - - def test_search_hit_via_scalar - assert AwsBillingReport.new("inspec1").exists? - end - - def test_search_miss_via_scalar - refute AwsBillingReport.new("non-existent").exists? - end - - def test_search_hit_via_hash_works - assert AwsBillingReport.new(report_name: "inspec1").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsBillingReport.new(report_name: "non-existent").exists? - end - - def test_search_hit_properties - r = AwsBillingReport.new("inspec1") - assert_equal("inspec1", r.report_name) - assert_equal("hourly", r.time_unit) - assert_equal("zip", r.compression) - assert_equal("inspec1-s3-bucket", r.s3_bucket) - assert_equal("inspec1/accounting", r.s3_prefix) - assert_equal("us-east-1", r.s3_region) - end - - def test_hourly? - assert AwsBillingReport.new("inspec1").hourly? - refute AwsBillingReport.new("inspec2").hourly? - end - - def test_daily? - assert AwsBillingReport.new("inspec2").daily? - refute AwsBillingReport.new("inspec1").daily? - end - - def test_zip? - assert AwsBillingReport.new("inspec1").zip? - refute AwsBillingReport.new("inspec2").zip? - end - - def test_gzip? - assert AwsBillingReport.new("inspec2").gzip? - refute AwsBillingReport.new("inspec1").gzip? - end -end - -class PaginatedAwsBillingReportTest < Minitest::Test - def setup - AwsBillingReport::BackendFactory.select(MockAwsBillingReports::Paginated) - end - - def test_paginated_search_hit_via_scalar - assert AwsBillingReport.new("inspec8").exists? - end - - def test_paginated_search_miss_via_scalar - refute AwsBillingReport.new("non-existent").exists? - end -end diff --git a/test/unit/resources/aws_billing_reports_test.rb b/test/unit/resources/aws_billing_reports_test.rb deleted file mode 100644 index 65810ebf9..000000000 --- a/test/unit/resources/aws_billing_reports_test.rb +++ /dev/null @@ -1,66 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_billing_reports" - -require "fixtures/files/aws_billing_backend" - -require "resource_support/aws" - -class ConstructorAwsBillingReportsTest < Minitest::Test - def setup - AwsBillingReports::BackendFactory.select(MockAwsBillingReports::Empty) - end - - def test_empty_params_ok - assert AwsBillingReports.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsBillingReports.new(unrecognized_param: 1) } - end -end - -class EmptyAwsBillingReportsTest < Minitest::Test - def setup - AwsBillingReports::BackendFactory.select(MockAwsBillingReports::Empty) - end - - def test_search_miss_reports_empty - refute AwsBillingReports.new.exists? - end -end - -class BasicAwsBillingReportsTest < Minitest::Test - def setup - AwsBillingReports::BackendFactory.select(MockAwsBillingReports::Basic) - end - - def test_search_hit_via_empty_filter - assert AwsBillingReports.new.exists? - end - - def test_search_hit_properties - assert AwsBillingReports.new.report_names.include?("inspec1") - end - - def test_where_hit - abr = AwsBillingReports.new.where { report_name =~ /inspec.*/ } - assert_includes abr.time_units, "daily" - assert_includes abr.compressions, "zip" - assert_includes abr.s3_buckets, "inspec1-s3-bucket" - end -end - -class PaginatedAwsBillingReportsTest < Minitest::Test - def setup - AwsBillingReports::BackendFactory.select(MockAwsBillingReports::Paginated) - end - - def test_paginated_search_hit_via_scalar - assert AwsBillingReports.new.report_names.include?("inspec12") - end - - def test_paginated_search_miss_via_scalar - refute AwsBillingReports.new.report_names.include?("non-existent") - end -end diff --git a/test/unit/resources/aws_cloudtrail_trail_test.rb b/test/unit/resources/aws_cloudtrail_trail_test.rb deleted file mode 100644 index 65f49f715..000000000 --- a/test/unit/resources/aws_cloudtrail_trail_test.rb +++ /dev/null @@ -1,188 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_cloudtrail_trail" - -require "resource_support/aws" - -# MACTTSB = MockAwsCloudTrailTrailSingularBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsCloudTrailTrailConstructorTest < Minitest::Test - - def setup - AwsCloudTrailTrail::BackendFactory.select(MACTTSB::Empty) - end - - def test_rejects_empty_params - assert_raises(ArgumentError) { AwsCloudTrailTrail.new } - end - - def test_accepts_trail_name_as_scalar - AwsCloudTrailTrail.new("test-trail-1") - end - - def test_accepts_trail_name_as_hash - AwsCloudTrailTrail.new(trail_name: "test-trail-1") - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsCloudTrailTrail.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsCloudTrailTrailRecallTest < Minitest::Test - - def setup - AwsCloudTrailTrail::BackendFactory.select(MACTTSB::Basic) - end - - def test_search_hit_via_scalar_works - assert AwsCloudTrailTrail.new("test-trail-1").exists? - end - - def test_search_hit_via_hash_works - assert AwsCloudTrailTrail.new(trail_name: "test-trail-1").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsCloudTrailTrail.new(trail_name: "non-existent").exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsCloudTrailTrailPropertiesTest < Minitest::Test - - def setup - AwsCloudTrailTrail::BackendFactory.select(MACTTSB::Basic) - end - - def test_property_s3_bucket_name - assert_equal("aws-s3-bucket-test-trail-1", AwsCloudTrailTrail.new("test-trail-1").s3_bucket_name) - assert_nil(AwsCloudTrailTrail.new(trail_name: "non-existent").s3_bucket_name) - end - - def test_property_trail_arn - assert_equal("arn:aws:cloudtrail:us-east-1::trail/test-trail-1", AwsCloudTrailTrail.new("test-trail-1").trail_arn) - assert_nil(AwsCloudTrailTrail.new(trail_name: "non-existent").trail_arn) - end - - def test_property_cloud_watch_logs_role_arn - assert_equal("arn:aws:iam:::role/CloudTrail_CloudWatchLogs_Role", AwsCloudTrailTrail.new("test-trail-1").cloud_watch_logs_role_arn) - assert_nil(AwsCloudTrailTrail.new(trail_name: "non-existent").cloud_watch_logs_role_arn) - end - - def test_property_cloud_watch_logs_log_group_arn - assert_equal("arn:aws:logs:us-east-1::log-group:test:*", AwsCloudTrailTrail.new("test-trail-1").cloud_watch_logs_log_group_arn) - assert_nil(AwsCloudTrailTrail.new(trail_name: "non-existent").cloud_watch_logs_log_group_arn) - end - - def test_property_kms_key_id - assert_equal("arn:aws:kms:us-east-1::key/88197884-041f-4f8e-a801-cf120e4845a8", AwsCloudTrailTrail.new("test-trail-1").kms_key_id) - assert_nil(AwsCloudTrailTrail.new(trail_name: "non-existent").kms_key_id) - end - - def test_property_home_region - assert_equal("us-east-1", AwsCloudTrailTrail.new("test-trail-1").home_region) - assert_nil(AwsCloudTrailTrail.new(trail_name: "non-existent").home_region) - end - - def test_property_delivered_logs_days_ago - assert_equal(0, AwsCloudTrailTrail.new("test-trail-1").delivered_logs_days_ago) - assert_nil(AwsCloudTrailTrail.new(trail_name: "non-existent").delivered_logs_days_ago) - end -end - -#=============================================================================# -# Matchers -#=============================================================================# -class AwsCloudTrailTrailMatchersTest < Minitest::Test - - def setup - AwsCloudTrailTrail::BackendFactory.select(MACTTSB::Basic) - end - - def test_matcher_encrypted_positive - assert AwsCloudTrailTrail.new("test-trail-1").encrypted? - end - - def test_matcher_encrypted_negative - refute AwsCloudTrailTrail.new("test-trail-2").encrypted? - end - - def test_matcher_multi_region_trail_positive - assert AwsCloudTrailTrail.new("test-trail-1").multi_region_trail? - end - - def test_matcher_multi_region_trail_negative - refute AwsCloudTrailTrail.new("test-trail-2").multi_region_trail? - end - - def test_matcher_log_file_validation_enabled_positive - assert AwsCloudTrailTrail.new("test-trail-1").log_file_validation_enabled? - end - - def test_matcher_log_file_validation_enabled_negative - refute AwsCloudTrailTrail.new("test-trail-2").log_file_validation_enabled? - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MACTTSB - class Empty < AwsBackendBase - def describe_trails(query) - OpenStruct.new(trail_list: []) - end - end - - class Basic < AwsBackendBase - def describe_trails(query) - fixtures = [ - OpenStruct.new({ - name: "test-trail-1", - s3_bucket_name: "aws-s3-bucket-test-trail-1", - is_multi_region_trail: true, - home_region: "us-east-1", - trail_arn: "arn:aws:cloudtrail:us-east-1::trail/test-trail-1", - log_file_validation_enabled: true, - cloud_watch_logs_log_group_arn: "arn:aws:logs:us-east-1::log-group:test:*", - cloud_watch_logs_role_arn: "arn:aws:iam:::role/CloudTrail_CloudWatchLogs_Role", - kms_key_id: "arn:aws:kms:us-east-1::key/88197884-041f-4f8e-a801-cf120e4845a8", - }), - OpenStruct.new({ - name: "test-trail-2", - s3_bucket_name: "aws-s3-bucket-test-trail-2", - home_region: "us-east-1", - trail_arn: "arn:aws:cloudtrail:us-east-1::trail/test-trail-2", - cloud_watch_logs_log_group_arn: "arn:aws:logs:us-east-1::log-group:test:*", - cloud_watch_logs_role_arn: "arn:aws:iam:::role/CloudTrail_CloudWatchLogs_Role", - }), - ] - - selected = fixtures.detect do |fixture| - fixture.name == query[:trail_name_list].first - end - OpenStruct.new({ trail_list: [selected] }) - end - - def get_trail_status(query) - fixtures = [ - OpenStruct.new({ - name: "test-trail-1", - latest_cloud_watch_logs_delivery_time: Time.now, - }), - ] - - fixtures.detect { |f| f.name == query[:name] } - end - end -end diff --git a/test/unit/resources/aws_cloudtrail_trails_test.rb b/test/unit/resources/aws_cloudtrail_trails_test.rb deleted file mode 100644 index 641af40bf..000000000 --- a/test/unit/resources/aws_cloudtrail_trails_test.rb +++ /dev/null @@ -1,113 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_cloudtrail_trails" - -require "resource_support/aws" - -# MACTTPB = MockAwsCloudTrailTrailsPluralBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsCloudTrailTrailsConstructorTest < Minitest::Test - - def setup - AwsCloudTrailTrails::BackendFactory.select(MACTTPB::Empty) - end - - def test_empty_params_ok - AwsCloudTrailTrails.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsCloudTrailTrails.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsCloudTrailTrailsRecallEmptyTest < Minitest::Test - - def setup - AwsCloudTrailTrails::BackendFactory.select(MACTTPB::Empty) - end - - def test_search_miss_trail_empty_trail_list - refute AwsCloudTrailTrails.new.exists? - end -end - -class AwsCloudTrailTrailsRecallBasicTest < Minitest::Test - - def setup - AwsCloudTrailTrails::BackendFactory.select(MACTTPB::Basic) - end - - def test_search_hit_via_empty_filter - assert AwsCloudTrailTrails.new.exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsCloudTrailTrailsProperties < Minitest::Test - def setup - AwsCloudTrailTrails::BackendFactory.select(MACTTPB::Basic) - end - - def test_property_names - basic = AwsCloudTrailTrails.new - assert_kind_of(Array, basic.names) - assert(basic.names.include?("test-trail-1")) - refute(basic.names.include?(nil)) - end - - def test_property_trail_arns - basic = AwsCloudTrailTrails.new - assert_kind_of(Array, basic.trail_arns) - assert(basic.trail_arns.include?("arn:aws:cloudtrail:us-east-1::trail/test-trail-1")) - refute(basic.trail_arns.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MACTTPB - class Empty < AwsBackendBase - def describe_trails(query = {}) - OpenStruct.new({ trail_list: [] }) - end - end - - class Basic < AwsBackendBase - def describe_trails(query = {}) - fixtures = [ - OpenStruct.new({ - name: "test-trail-1", - s3_bucket_name: "aws-s3-bucket-test-trail-1", - is_multi_region_trail: true, - home_region: "us-east-1", - trail_arn: "arn:aws:cloudtrail:us-east-1::trail/test-trail-1", - log_file_validation_enabled: true, - cloud_watch_logs_log_group_arn: "arn:aws:logs:us-east-1::log-group:test:*", - cloud_watch_logs_role_arn: "arn:aws:iam:::role/CloudTrail_CloudWatchLogs_Role", - kms_key_id: "arn:aws:kms:us-east-1::key/88197884-041f-4f8e-a801-cf120e4845a8", - }), - OpenStruct.new({ - name: "test-trail-2", - s3_bucket_name: "aws-s3-bucket-test-trail-2", - home_region: "us-east-1", - trail_arn: "arn:aws:cloudtrail:us-east-1::trail/test-trail-2", - cloud_watch_logs_log_group_arn: "arn:aws:logs:us-east-1::log-group:test:*", - cloud_watch_logs_role_arn: "arn:aws:iam:::role/CloudTrail_CloudWatchLogs_Role", - }), - ] - - OpenStruct.new({ trail_list: fixtures }) - end - end -end diff --git a/test/unit/resources/aws_cloudwatch_alarm_test.rb b/test/unit/resources/aws_cloudwatch_alarm_test.rb deleted file mode 100644 index d0c43db48..000000000 --- a/test/unit/resources/aws_cloudwatch_alarm_test.rb +++ /dev/null @@ -1,169 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_cloudwatch_alarm" - -require "resource_support/aws" - -# MCWAB = MockCloudwatchAlarmBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsCWAConstructor < Minitest::Test - def setup - AwsCloudwatchAlarm::BackendFactory.select(AwsMCWAB::Empty) - end - - def test_constructor_some_args_required - assert_raises(ArgumentError) { AwsCloudwatchAlarm.new } - end - - def test_constructor_accepts_known_resource_params_combos - [ - { metric_name: "some-val", metric_namespace: "some-val" }, - ].each do |combo| - AwsCloudwatchAlarm.new(combo) - end - end - - def test_constructor_rejects_bad_resource_params_combos - [ - { metric_name: "some-val" }, - { metric_namespace: "some-val" }, - ].each do |combo| - assert_raises(ArgumentError) { AwsCloudwatchAlarm.new(combo) } - end - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsCloudwatchAlarm.new(beep: "boop") } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# - -class AwsCWARecall < Minitest::Test - def setup - AwsCloudwatchAlarm::BackendFactory.select(AwsMCWAB::Basic) - end - - def test_recall_no_match_is_no_exception - alarm = AwsCloudwatchAlarm.new(metric_name: "nope", metric_namespace: "nope") - refute alarm.exists? - end - - def test_recall_match_single_result_works - alarm = AwsCloudwatchAlarm.new( - metric_name: "metric-01", - metric_namespace: "metric-namespace-01" - ) - assert alarm.exists? - end - - def test_recall_multiple_result_raises - assert_raises(RuntimeError) do - AwsCloudwatchAlarm.new( - metric_name: "metric-02", - metric_namespace: "metric-namespace-01" - ) - end - end -end - -#=============================================================================# -# Properties -#=============================================================================# - -class AwsCWAProperties < Minitest::Test - def setup - AwsCloudwatchAlarm::BackendFactory.select(AwsMCWAB::Basic) - end - - #--------------------------------------- - # alarm_actions - #--------------------------------------- - def test_prop_actions_empty - alarm = AwsCloudwatchAlarm.new( - metric_name: "metric-02", - metric_namespace: "metric-namespace-02" - ) - assert_kind_of Array, alarm.alarm_actions - assert_empty alarm.alarm_actions - end - - def test_prop_actions_hit - alarm = AwsCloudwatchAlarm.new( - metric_name: "metric-01", - metric_namespace: "metric-namespace-01" - ) - assert_kind_of Array, alarm.alarm_actions - refute_empty alarm.alarm_actions - assert_kind_of String, alarm.alarm_actions.first - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMCWAB - class Empty < AwsBackendBase - def describe_alarms_for_metric(_criteria) - OpenStruct.new({ - metric_alarms: [], - }) - end - end - - class Basic < AwsBackendBase - def describe_alarms_for_metric(criteria) - OpenStruct.new({ - metric_alarms: [ # rubocop:disable Metrics/BlockLength - # Each one here is an alarm that is subscribed to the given metric - # Each has an enormous number of properties, most omitted here - # http://docs.aws.amazon.com/sdkforruby/api/Aws/CloudWatch/Client.html#describe_alarms_for_metric-instance_method - OpenStruct.new({ - alarm_name: "alarm-01", - metric_name: "metric-01", - namespace: "metric-namespace-01", - statistic: "SampleCount", - alarm_actions: [ - "arn::::", # TODO: get SNS ARN format - ], - }), - OpenStruct.new({ - # Alarm 02 and 03 both watch metric-01, metric-namespace-01 - alarm_name: "alarm-02", - metric_name: "metric-02", - namespace: "metric-namespace-01", - statistic: "SampleCount", - alarm_actions: [], - }), - OpenStruct.new({ - # Alarm 02 and 03 both watch metric-02, metric-namespace-01 - alarm_name: "alarm-03", - metric_name: "metric-02", - namespace: "metric-namespace-01", - statistic: "SampleCount", - alarm_actions: [], - }), - OpenStruct.new({ - alarm_name: "alarm-04", - metric_name: "metric-02", - namespace: "metric-namespace-02", - statistic: "SampleCount", - alarm_actions: [], - }), - ].select do |alarm| - criteria.keys.all? do |criterion| - criterion = "namespace" if criterion == "metric_namespace" - alarm[criterion] == criteria[criterion] - end - end, - }) - end - end -end diff --git a/test/unit/resources/aws_cloudwatch_log_metric_filter_test.rb b/test/unit/resources/aws_cloudwatch_log_metric_filter_test.rb deleted file mode 100644 index 09ce10c67..000000000 --- a/test/unit/resources/aws_cloudwatch_log_metric_filter_test.rb +++ /dev/null @@ -1,157 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_cloudwatch_log_metric_filter" - -require "resource_support/aws" - -# CWLMF = CloudwatchLogMetricFilter -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsCWLMFConstructor < Minitest::Test - def setup - AwsCloudwatchLogMetricFilter::BackendFactory.select(AwsMockCWLMFBackend::Empty) - end - - def test_constructor_some_args_required - assert_raises(ArgumentError) { AwsCloudwatchLogMetricFilter.new } - end - - def test_constructor_accepts_known_resource_params - %i{ - filter_name - pattern - log_group_name - }.each do |resource_param| - AwsCloudwatchLogMetricFilter.new(resource_param => "some_val") - end - end - - def test_constructor_reject_bad_resource_params - assert_raises(ArgumentError) { AwsCloudwatchLogMetricFilter.new(i_am_a_martian: "beep") } - end -end - -#=============================================================================# -# Search Tests # -#=============================================================================# -class AwsCWLMFSearch < Minitest::Test - def setup - # Reset to the Basic kit each time - AwsCloudwatchLogMetricFilter::BackendFactory.select(AwsMockCWLMFBackend::Basic) - end - - def test_using_lg_and_lmf_name_when_exactly_one - lmf = AwsCloudwatchLogMetricFilter.new( - log_group_name: "test-log-group-01", - filter_name: "test-01" - ) - assert lmf.exists? - end - - def test_using_lg_and_lmf_name_when_not_present - lmf = AwsCloudwatchLogMetricFilter.new( - log_group_name: "test-log-group-01", - filter_name: "test-1000-nope" - ) - refute lmf.exists? - end - - def test_using_log_group_name_resulting_in_duplicates - assert_raises(RuntimeError) do - AwsCloudwatchLogMetricFilter.new( - log_group_name: "test-log-group-01" - ) - end - end - - def test_duplicate_locally_uniqued_using_pattern - lmf = AwsCloudwatchLogMetricFilter.new( - log_group_name: "test-log-group-01", - pattern: "INFO" - ) - assert lmf.exists? - end -end - -#=============================================================================# -# Property Tests # -#=============================================================================# -class AwsCWLMFProperties < Minitest::Test - def setup - # Reset to the Basic kit each time - AwsCloudwatchLogMetricFilter::BackendFactory.select(AwsMockCWLMFBackend::Basic) - end - - def test_property_values - lmf = AwsCloudwatchLogMetricFilter.new( - log_group_name: "test-log-group-01", - filter_name: "test-01" - ) - assert_equal("ERROR", lmf.pattern) - assert_equal("alpha", lmf.metric_name) - assert_equal("awesome_metrics", lmf.metric_namespace) - end -end - -#=============================================================================# -# Support Classes - Mock Data Providers # -#=============================================================================# -class AwsMockCWLMFBackend - class Empty < AwsBackendBase - def describe_metric_filters(_criteria) - [] - end - end - - class Basic < AwsBackendBase - def describe_metric_filters(criteria) # rubocop:disable Metrics/MethodLength - everything = [ - OpenStruct.new({ - filter_name: "test-01", - filter_pattern: "ERROR", - log_group_name: "test-log-group-01", - metric_transformations: [ - OpenStruct.new({ - metric_name: "alpha", - metric_namespace: "awesome_metrics", - }), - ], - }), - OpenStruct.new({ - filter_name: "test-01", # Intentional duplicate - filter_pattern: "ERROR", - log_group_name: "test-log-group-02", - metric_transformations: [ - OpenStruct.new({ - metric_name: "beta", - metric_namespace: "awesome_metrics", - }), - ], - }), - OpenStruct.new({ - filter_name: "test-03", - filter_pattern: "INFO", - log_group_name: "test-log-group-01", - metric_transformations: [ - OpenStruct.new({ - metric_name: "gamma", - metric_namespace: "awesome_metrics", - }), - ], - }), - ] - selection = everything - # Here we filter on anything the AWS SDK lets us filter on remotely - # - which notably does not include the 'pattern' criteria - %i{log_group_name filter_name}.each do |remote_filter| - next unless criteria.key?(remote_filter) - - selection.select! { |lmf| lmf[remote_filter] == criteria[remote_filter] } - end - selection - end - end -end diff --git a/test/unit/resources/aws_config_delivery_channel_test.rb b/test/unit/resources/aws_config_delivery_channel_test.rb deleted file mode 100644 index 9beb395ed..000000000 --- a/test/unit/resources/aws_config_delivery_channel_test.rb +++ /dev/null @@ -1,131 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_config_delivery_channel" - -require "resource_support/aws" - -# MDCSB = MockDeliveryChannelSingleBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsConfigDeliveryChannelConstructorTest < Minitest::Test - def setup - AwsConfigDeliveryChannel::BackendFactory.select(AwsMDCSB::Basic) - end - - def test_constructor_when_no_params_provided - AwsConfigDeliveryChannel.new - end - - def test_constructor_expected_well_formed_args_scalar - AwsConfigDeliveryChannel.new("default") - end - - def test_constructor_expected_well_formed_args_hash - AwsConfigDeliveryChannel.new(channel_name: "default") - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsConfigDeliveryChannel.new(bla: "blabla") } - end -end - -#=============================================================================# -# Recall -#=============================================================================# - -class AwsConfigDeliveryChannelRecallTest < Minitest::Test - def setup - AwsConfigDeliveryChannel::BackendFactory.select(AwsMDCSB::Basic) - end - - def test_search_hit_by_default - assert AwsConfigDeliveryChannel.new.exists? - end - - def test_search_hit_via_scalar - assert AwsConfigDeliveryChannel.new("default").exists? - end - - def test_search_hit_via_hash - assert AwsConfigDeliveryChannel.new(channel_name: "default").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsConfigDeliveryChannel.new(channel_name: "NonExistentDeliveryChannel").exists? - end -end - -#=============================================================================# -# properties -#=============================================================================# - -class AwsConfigDeliveryChannelPropertiesTest < Minitest::Test - def setup - AwsConfigDeliveryChannel::BackendFactory.select(AwsMDCSB::Basic) - end - - def test_property_channel_name - assert_equal("default", AwsConfigDeliveryChannel.new("default").channel_name) - assert_equal("default", AwsConfigDeliveryChannel.new.channel_name) - assert_equal("NonExistentDeliveryChannel", AwsConfigDeliveryChannel.new("NonExistentDeliveryChannel").channel_name) - end - - def test_property_delivery_frequency_in_hours - assert_equal(3, AwsConfigDeliveryChannel.new("default").delivery_frequency_in_hours) - assert_nil(AwsConfigDeliveryChannel.new("NonExistentDeliveryChannel").delivery_frequency_in_hours) - end - - def test_property_s3_bucket_name - assert_equal("my-bucket", AwsConfigDeliveryChannel.new("default").s3_bucket_name) - assert_nil(AwsConfigDeliveryChannel.new("NonExistentDeliveryChannel").s3_bucket_name) - end - - def test_property_s3_key_prefix - assert_equal("config-logs/", AwsConfigDeliveryChannel.new("default").s3_key_prefix) - assert_nil(AwsConfigDeliveryChannel.new("NonExistentDeliveryChannel").s3_key_prefix) - end - - def test_property_sns_topic_arn - assert_equal("arn:aws:sns:::my-topic-name", AwsConfigDeliveryChannel.new("default").sns_topic_arn) - assert_nil(AwsConfigDeliveryChannel.new("NonExistentDeliveryChannel").sns_topic_arn) - end -end - -#=============================================================================# -# Test Matchers -#=============================================================================# - -# None - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMDCSB - class Basic < AwsBackendBase - def describe_delivery_channels(query = {}) - fixtures = { - "default" => Aws::ConfigService::Types::DescribeDeliveryChannelsResponse.new( - delivery_channels: [ - { - name: "default", - s3_bucket_name: "my-bucket", - s3_key_prefix: "config-logs/", - sns_topic_arn: "arn:aws:sns:::my-topic-name", - config_snapshot_delivery_properties: { - delivery_frequency: "Three_Hours", - }, - }, - ] - ), - } - return fixtures["default"] if query.empty? - return fixtures[query[:delivery_channel_names][0]] unless fixtures[query[:delivery_channel_names][0]].nil? - - raise Aws::ConfigService::Errors::NoSuchDeliveryChannelException.new(nil, nil) - end - end -end diff --git a/test/unit/resources/aws_config_recorder_test.rb b/test/unit/resources/aws_config_recorder_test.rb deleted file mode 100644 index b8fb51e54..000000000 --- a/test/unit/resources/aws_config_recorder_test.rb +++ /dev/null @@ -1,154 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_config_recorder" - -require "resource_support/aws" - -# MCRSB = MockConfigRecorderSingleBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsConfigurationRecorderConstructorTest < Minitest::Test - def setup - AwsConfigurationRecorder::BackendFactory.select(AwsMCRSB::Basic) - end - - def test_constructor_when_no_params_provided - AwsConfigurationRecorder.new - end - - def test_constructor_expected_well_formed_args_scalar - AwsConfigurationRecorder.new("default") - end - - def test_constructor_expected_well_formed_args_hash - AwsConfigurationRecorder.new(recorder_name: "default") - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsConfigurationRecorder.new(bla: "blabla") } - end -end - -#=============================================================================# -# Recall -#=============================================================================# - -class AwsConfigurationRecorderRecallTest < Minitest::Test - def setup - AwsConfigurationRecorder::BackendFactory.select(AwsMCRSB::Basic) - end - - def test_search_hit_by_default - assert AwsConfigurationRecorder.new.exists? - end - - def test_search_hit_via_scalar - assert AwsConfigurationRecorder.new("default").exists? - end - - def test_search_hit_via_hash - assert AwsConfigurationRecorder.new(recorder_name: "default").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsConfigurationRecorder.new(recorder_name: "NonExistentRecorder").exists? - end -end - -#=============================================================================# -# properties -#=============================================================================# - -class AwsConfigurationRecorderPropertiesTest < Minitest::Test - def setup - AwsConfigurationRecorder::BackendFactory.select(AwsMCRSB::Basic) - end - - def test_property_recorder_name - assert_equal("default", AwsConfigurationRecorder.new(recorder_name: "default").recorder_name) - assert_equal("default", AwsConfigurationRecorder.new.recorder_name) - end - - def test_property_role_arn - assert_equal("arn:aws:iam::721741954427:role/default", AwsConfigurationRecorder.new(recorder_name: "default").role_arn) - assert_nil(AwsConfigurationRecorder.new(recorder_name: "NonExistentRecorder").role_arn) - end - - def test_property_resource_types - assert_equal(["AWS::EC2::CustomerGateway", "AWS::EC2::EIP"], AwsConfigurationRecorder.new(recorder_name: "default").resource_types) - assert_nil(AwsConfigurationRecorder.new(recorder_name: "NonExistentRecorder").resource_types) - end -end - -#=============================================================================# -# Test Matchers -#=============================================================================# -class AwsConfigurationRecorderPropertiesTest < Minitest::Test - def test_matcher_all_supported - assert AwsConfigurationRecorder.new(recorder_name: "default").recording_all_resource_types? - refute AwsConfigurationRecorder.new(recorder_name: "Recorder_1").recording_all_resource_types? - end - - def test_matcher_has_include_global_resource_types - assert AwsConfigurationRecorder.new(recorder_name: "default").recording_all_global_types? - refute AwsConfigurationRecorder.new(recorder_name: "Recorder_1").recording_all_global_types? - end - - def test_matcher_recording - assert AwsConfigurationRecorder.new(recorder_name: "default").recording? - refute AwsConfigurationRecorder.new(recorder_name: "Recorder_1").recording? - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMCRSB - class Basic < AwsBackendBase - def describe_configuration_recorders(query = {}) - recorders = { - "default" => OpenStruct.new({ - configuration_recorders: [ - name: "default", - role_arn: "arn:aws:iam::721741954427:role/default", - recording_group: OpenStruct.new({ - all_supported: true, - include_global_resource_types: true, - resource_types: ["AWS::EC2::CustomerGateway", "AWS::EC2::EIP"], - }), - ], - }), - } - if query.empty? - recorders["default"] - elsif recorders.key?(query[:configuration_recorder_names][0]) - recorders[query[:configuration_recorder_names][0]] - else - raise Aws::ConfigService::Errors::NoSuchConfigurationRecorderException.new(nil, nil) - end - end - - def describe_configuration_recorder_status(query = {}) - recorders = { - "default" => OpenStruct.new({ - configuration_recorders_status: [ - recording: true, - ], - }), - "Recorder_1" => OpenStruct.new({ - configuration_recorders_status: [ - recording: false, - ], - }), - "empty" => {}, - } - return recorders[query[:configuration_recorder_names][0]] unless recorders[query[:configuration_recorder_names][0]].nil? - - raise Aws::ConfigService::Errors::NoSuchConfigurationRecorderException(nil, nil) - end - end -end diff --git a/test/unit/resources/aws_ebs_volume_test.rb b/test/unit/resources/aws_ebs_volume_test.rb deleted file mode 100644 index 1b145ac77..000000000 --- a/test/unit/resources/aws_ebs_volume_test.rb +++ /dev/null @@ -1,77 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_ebs_volume" - -require "resource_support/aws" - -class TestEbs < Minitest::Test - ID = "volume-id".freeze - - def setup - @mock_conn = Minitest::Mock.new - @mock_client = Minitest::Mock.new - @mock_resource = Minitest::Mock.new - - @mock_conn.expect :ec2_client, @mock_client - @mock_conn.expect :ec2_resource, @mock_resource - end - - def test_that_id_returns_id_directly_when_constructed_with_an_id - assert_equal ID, AwsEbsVolume.new(ID, @mock_conn).id - end - - def test_that_id_returns_fetched_id_when_constructed_with_a_name - mock_volume = Minitest::Mock.new - mock_volume.expect :nil?, false - mock_volume.expect :id, ID - @mock_resource.expect :volumes, [mock_volume], [Hash] - assert_equal ID, AwsEbsVolume.new({ name: "cut" }, @mock_conn).id - end - - def test_that_volume_returns_volume_when_volume_exists - mock_volume = Object.new - - @mock_resource.expect :volume, mock_volume, [ID] - assert_same( - mock_volume, - AwsEbsVolume.new(ID, @mock_conn).send(:volume) - ) - end - - def test_that_volume_returns_nil_when_volume_does_not_exist - @mock_resource.expect :volume, nil, [ID] - assert AwsEbsVolume.new(ID, @mock_conn).send(:volume).nil? - end - - def test_that_exists_returns_true_when_volume_exists - mock_volume = Minitest::Mock.new - mock_volume.expect :nil?, false - mock_volume.expect :exists?, true - @mock_resource.expect :volume, mock_volume, [ID] - assert AwsEbsVolume.new(ID, @mock_conn).exists? - end - - def test_that_exists_returns_false_when_volume_does_not_exist - mock_volume = Minitest::Mock.new - mock_volume.expect :nil?, true - mock_volume.expect :exists?, false - @mock_resource.expect :volume, mock_volume, [ID] - refute AwsEbsVolume.new(ID, @mock_conn).exists? - end - - def test_that_encrypted_returns_true_when_volume_is_encrypted - mock_volume = Minitest::Mock.new - mock_volume.expect :nil?, false - mock_volume.expect :encrypted, true - @mock_resource.expect :volume, mock_volume, [ID] - assert AwsEbsVolume.new(ID, @mock_conn).encrypted? - end - - def test_that_encrypted_returns_false_when_volume_is_not_encrypted - mock_volume = Minitest::Mock.new - mock_volume.expect :nil?, false - mock_volume.expect :encrypted, false - @mock_resource.expect :volume, mock_volume, [ID] - refute AwsEbsVolume.new(ID, @mock_conn).encrypted? - end -end diff --git a/test/unit/resources/aws_ebs_volumes_test.rb b/test/unit/resources/aws_ebs_volumes_test.rb deleted file mode 100644 index 52952f85a..000000000 --- a/test/unit/resources/aws_ebs_volumes_test.rb +++ /dev/null @@ -1,115 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_ebs_volumes" - -require "resource_support/aws" - -# MAEIPB = MockAwsEbsVolumesPluralBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsEbsVolumesConstructorTest < Minitest::Test - - def setup - AwsEbsVolumes::BackendFactory.select(MAEIPB::Empty) - end - - def test_empty_params_ok - AwsEbsVolumes.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsEbsVolumes.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsEbsVolumesRecallEmptyTest < Minitest::Test - - def setup - AwsEbsVolumes::BackendFactory.select(MAEIPB::Empty) - end - - def test_recall_when_no_volumes_exist - refute AwsEbsVolumes.new.exists? - end -end - -class AwsEbsVolumesRecallBasicTest < Minitest::Test - - def setup - AwsEbsVolumes::BackendFactory.select(MAEIPB::Basic) - end - - def test_recall_when_some_volumes_exist - assert AwsEbsVolumes.new.exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsEbsVolumesProperties < Minitest::Test - def setup - AwsEbsVolumes::BackendFactory.select(MAEIPB::Basic) - end - - def test_property_volume_ids_when_no_volumes_exist - AwsEbsVolumes::BackendFactory.select(MAEIPB::Empty) - empty = AwsEbsVolumes.new - assert_kind_of(Array, empty.volume_ids) - assert_empty(empty.volume_ids) - end - - def test_property_volume_ids_when_volumes_exist - basic = AwsEbsVolumes.new - assert_kind_of(Array, basic.volume_ids) - assert(basic.volume_ids.include?("vol-deadbeef")) - assert_equal(3, basic.volume_ids.length) - assert(basic.volume_ids.include?("vol-11112222")) - refute(basic.volume_ids.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAEIPB - class Empty < AwsBackendBase - def describe_volumes(query = {}) - OpenStruct.new( volumes: [] ) - end - end - - class Basic < AwsBackendBase - def describe_volumes(query = {}) - Aws::EC2::Types::DescribeVolumesResult.new( - volumes: [ - Aws::EC2::Types::Volume.new( - attachments: [ - Aws::EC2::Types::VolumeAttachment.new( - # Many, many other properties available here. - # We're starting with what we support. - volume_id: "vol-0e8541d718e67e1be" - ), - Aws::EC2::Types::VolumeAttachment.new( - volume_id: "vol-deadbeef" - ), - ] - ), - Aws::EC2::Types::Volume.new( - attachments: [ - Aws::EC2::Types::VolumeAttachment.new( - volume_id: "vol-11112222" - ), - ] - ), - ] - ) - end - end -end diff --git a/test/unit/resources/aws_ec2_instance_test.rb b/test/unit/resources/aws_ec2_instance_test.rb deleted file mode 100644 index 20eccc146..000000000 --- a/test/unit/resources/aws_ec2_instance_test.rb +++ /dev/null @@ -1,121 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_ec2_instance" - -require "resource_support/aws" - -class TestEc2 < Minitest::Test - ID = "instance-id".freeze - INSTANCEPROFILE = "instance-role".freeze - ARN = "arn:aws:iam::123456789012:instance-profile/instance-role".freeze - - def setup - @mock_conn = Minitest::Mock.new - @mock_client = Minitest::Mock.new - @mock_resource = Minitest::Mock.new - @mock_iam_resource = Minitest::Mock.new - - @mock_conn.expect :ec2_client, @mock_client - @mock_conn.expect :ec2_resource, @mock_resource - @mock_conn.expect :iam_resource, @mock_iam_resource - end - - def test_that_id_returns_id_directly_when_constructed_with_an_id - assert_equal ID, AwsEc2Instance.new(ID, @mock_conn).id - end - - def test_that_id_returns_fetched_id_when_constructed_with_a_name - mock_instance = Minitest::Mock.new - mock_instance.expect :nil?, false - mock_instance.expect :id, ID - @mock_resource.expect :instances, [mock_instance], [Hash] - assert_equal ID, AwsEc2Instance.new({ name: "cut" }, @mock_conn).id - end - - def test_that_instance_returns_instance_when_instance_exists - mock_instance = Object.new - - @mock_resource.expect :instance, mock_instance, [ID] - assert_same( - mock_instance, - AwsEc2Instance.new(ID, @mock_conn).send(:instance) - ) - end - - def test_that_instance_returns_nil_when_instance_does_not_exist - @mock_resource.expect :instance, nil, [ID] - assert AwsEc2Instance.new(ID, @mock_conn).send(:instance).nil? - end - - def test_that_exists_returns_true_when_instance_exists - mock_instance = Minitest::Mock.new - mock_instance.expect :nil?, false - mock_instance.expect :exists?, true - @mock_resource.expect :instance, mock_instance, [ID] - assert AwsEc2Instance.new(ID, @mock_conn).exists? - end - - def test_that_exists_returns_false_when_instance_does_not_exist - mock_instance = Minitest::Mock.new - mock_instance.expect :nil?, false - mock_instance.expect :exists?, false - @mock_resource.expect :instance, mock_instance, [ID] - assert !AwsEc2Instance.new(ID, @mock_conn).exists? - end - - def stub_iam_instance_profile - OpenStruct.new({ arn: ARN }) - end - - def stub_instance_profile(roles) - OpenStruct.new({ roles: roles }) - end - - def test_that_has_roles_returns_false_when_roles_is_empty - mock_instance = Minitest::Mock.new - mock_instance.expect :iam_instance_profile, stub_iam_instance_profile - @mock_resource.expect :instance, mock_instance, [ID] - - mock_roles = Minitest::Mock.new - mock_roles.expect :empty?, true - - @mock_iam_resource.expect( - :instance_profile, - stub_instance_profile(mock_roles), - [INSTANCEPROFILE] - ) - - refute AwsEc2Instance.new(ID, @mock_conn).has_roles? - end - - def test_that_has_roles_returns_true_when_roles_is_not_empty - mock_instance = Minitest::Mock.new - mock_instance.expect :iam_instance_profile, stub_iam_instance_profile - @mock_resource.expect :instance, mock_instance, [ID] - - mock_roles = Minitest::Mock.new - mock_roles.expect :empty?, false - - @mock_iam_resource.expect( - :instance_profile, - stub_instance_profile(mock_roles), - [INSTANCEPROFILE] - ) - - assert AwsEc2Instance.new(ID, @mock_conn).has_roles? - end - - def test_that_has_roles_returns_false_when_roles_does_not_exist - mock_instance = Minitest::Mock.new - mock_instance.expect :iam_instance_profile, stub_iam_instance_profile - @mock_resource.expect :instance, mock_instance, [ID] - - @mock_iam_resource.expect( - :instance_profile, - stub_instance_profile(nil), - [INSTANCEPROFILE] - ) - - refute AwsEc2Instance.new(ID, @mock_conn).has_roles? - end -end diff --git a/test/unit/resources/aws_ec2_instances_test.rb b/test/unit/resources/aws_ec2_instances_test.rb deleted file mode 100644 index 85789209f..000000000 --- a/test/unit/resources/aws_ec2_instances_test.rb +++ /dev/null @@ -1,115 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_ec2_instances" - -require "resource_support/aws" - -# MAEIPB = MockAwsEC2InstancesPluralBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsEc2InstancesConstructorTest < Minitest::Test - - def setup - AwsEc2Instances::BackendFactory.select(MAEIPB::Empty) - end - - def test_empty_params_ok - AwsEc2Instances.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsEc2Instances.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsEc2InstancesRecallEmptyTest < Minitest::Test - - def setup - AwsEc2Instances::BackendFactory.select(MAEIPB::Empty) - end - - def test_recall_when_no_instances_exist - refute AwsEc2Instances.new.exists? - end -end - -class AwsEc2InstancesRecallBasicTest < Minitest::Test - - def setup - AwsEc2Instances::BackendFactory.select(MAEIPB::Basic) - end - - def test_recall_when_some_instances_exist - assert AwsEc2Instances.new.exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsEc2InstancesProperties < Minitest::Test - def setup - AwsEc2Instances::BackendFactory.select(MAEIPB::Basic) - end - - def test_property_instance_ids_when_no_instances_exist - AwsEc2Instances::BackendFactory.select(MAEIPB::Empty) - empty = AwsEc2Instances.new - assert_kind_of(Array, empty.instance_ids) - assert_empty(empty.instance_ids) - end - - def test_property_instance_ids_when_instances_exist - basic = AwsEc2Instances.new - assert_kind_of(Array, basic.instance_ids) - assert(basic.instance_ids.include?("i-deadbeef")) - assert_equal(3, basic.instance_ids.length) - assert(basic.instance_ids.include?("i-11112222")) - refute(basic.instance_ids.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAEIPB - class Empty < AwsBackendBase - def describe_instances(query = {}) - OpenStruct.new( reservations: [] ) - end - end - - class Basic < AwsBackendBase - def describe_instances(query = {}) - Aws::EC2::Types::DescribeInstancesResult.new( - reservations: [ - Aws::EC2::Types::Reservation.new( - instances: [ - Aws::EC2::Types::Instance.new( - # Many, many other properties available here. - # We're starting with what we support. - instance_id: "i-0e8541d718e67e1be" - ), - Aws::EC2::Types::Instance.new( - instance_id: "i-deadbeef" - ), - ] - ), - Aws::EC2::Types::Reservation.new( - instances: [ - Aws::EC2::Types::Instance.new( - instance_id: "i-11112222" - ), - ] - ), - ] - ) - end - end -end diff --git a/test/unit/resources/aws_ecs_cluster_test.rb b/test/unit/resources/aws_ecs_cluster_test.rb deleted file mode 100644 index b3a93beca..000000000 --- a/test/unit/resources/aws_ecs_cluster_test.rb +++ /dev/null @@ -1,188 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_ecs_cluster" - -require "resource_support/aws" - -# MAECSB = MockAwsEcsClusterSingularBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsEcsClusterConstructorTest < Minitest::Test - - def setup - AwsEcsCluster::BackendFactory.select(MAECSB::Basic) - end - - def test_empty_default_cluster - AwsEcsCluster.new - end - - def test_string_accepted - AwsEcsCluster.new "my-cluster" - end - - def test_hash_accepted - AwsEcsCluster.new cluster_name: "my-cluster" - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsEcsCluster.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsEcsClusterFilterCriteriaTest < Minitest::Test - - def setup - AwsEcsCluster::BackendFactory.select(MAECSB::Basic) - end - - def test_default - cluster = AwsEcsCluster.new - assert cluster.exists? - assert_equal("default", cluster.cluster_name) - end - - def test_search_miss - refute AwsEcsCluster.new("nonesuch").exists? - end - - def test_accepts_cluster_name_as_string - cluster = AwsEcsCluster.new "kangaroo" - assert cluster.exists? - assert_equal("kangaroo", cluster.cluster_name) - end - - def test_accepts_cluster_name_as_hash - cluster = AwsEcsCluster.new cluster_name: "kangaroo" - assert cluster.exists? - assert_equal("kangaroo", cluster.cluster_name) - end - -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsEcsClusterProperties < Minitest::Test - - def setup - AwsEcsCluster::BackendFactory.select(MAECSB::Basic) - @default = AwsEcsCluster.new - @roo = AwsEcsCluster.new("kangaroo") - @miss = AwsEcsCluster.new("nonesuch") - end - - def test_property_with_cluster_arn - assert_equal("arn:aws:ecs:ab-region-1:123456789:cluster/default", @default.cluster_arn) - assert_equal("arn:aws:ecs:ab-region-1:123456789:cluster/kangaroo", @roo.cluster_arn) - assert_empty(@miss.cluster_arn) - end - - def test_property_with_cluster_name - assert_equal("default", @default.cluster_name) - assert_equal("kangaroo", @roo.cluster_name) - assert_empty(@miss.cluster_name) - end - - def test_property_with_status - assert_equal("ACTIVE", @default.status) - assert_equal("ACTIVE", @roo.status) - assert_empty(@miss.status) - end - - def test_property_with_registered_container_instances_count - assert_equal(0, @default.registered_container_instances_count) - assert_equal(3, @roo.registered_container_instances_count) - assert_equal(0, @miss.registered_container_instances_count) - end - - def test_property_with_running_tasks_count - assert_equal(0, @default.running_tasks_count) - assert_equal(10, @roo.running_tasks_count) - assert_equal(0, @miss.running_tasks_count) - end - - def test_property_with_pending_tasks_count - assert_equal(0, @default.pending_tasks_count) - assert_equal(2, @roo.pending_tasks_count) - assert_equal(0, @miss.pending_tasks_count) - end - - def test_property_with_active_services_count - assert_equal(0, @default.active_services_count) - assert_equal(4, @roo.active_services_count) - assert_equal(0, @miss.active_services_count) - end - - def test_property_with_statistics - assert_empty(@default.statistics) - assert_empty(@roo.statistics) - assert_empty(@miss.statistics) - end - -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAECSB - class Basic < AwsBackendBase - def describe_clusters(query = {}) - clusters = { - "default" => Aws::ECS::Types::Cluster.new( - cluster_arn: "arn:aws:ecs:ab-region-1:123456789:cluster/default", - cluster_name: "default", - status: "ACTIVE", - registered_container_instances_count: 0, - running_tasks_count: 0, - pending_tasks_count: 0, - active_services_count: 0, - statistics: [] - ), - "kangaroo" => Aws::ECS::Types::Cluster.new( - cluster_arn: "arn:aws:ecs:ab-region-1:123456789:cluster/kangaroo", - cluster_name: "kangaroo", - status: "ACTIVE", - registered_container_instances_count: 3, - running_tasks_count: 10, - pending_tasks_count: 2, - active_services_count: 4, - statistics: [] - ), - } - - if query[:clusters] - clstrs = [] - failures = [] - - query[:clusters].each do |cluster_name| - if clusters.key?(cluster_name) - clstrs.push(clusters[cluster_name]) - else - failures.push(Aws::ECS::Types::Failure.new( - arn: "arn:aws:ecs:ab-region-1:123456789:cluster/#{cluster_name}", - reason: "MISSING" - )) - end - end - Aws::ECS::Types::DescribeClustersResponse.new( - clusters: clstrs, - failures: failures - ) - else - Aws::ECS::Types::DescribeClustersResponse.new( - clusters: [ - clusters["default"], - ], - failures: [] - ) - end - end - end -end diff --git a/test/unit/resources/aws_eks_cluster_test.rb b/test/unit/resources/aws_eks_cluster_test.rb deleted file mode 100644 index 8df1e994b..000000000 --- a/test/unit/resources/aws_eks_cluster_test.rb +++ /dev/null @@ -1,267 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_eks_cluster" - -require "resource_support/aws" - -# MAEKSB = MockAwsEksClusterSingularBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsEksClusterConstructorTest < Minitest::Test - - def setup - AwsEksCluster::BackendFactory.select(MAEKSB::Empty) - end - - def test_empty_params_rejected - assert_raises(ArgumentError) { AwsEksCluster.new } - end - - def test_string_accepted - AwsEksCluster.new "kangaroo" - end - - def test_hash_accepted - AwsEksCluster.new cluster_name: "polar_bear" - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsEksCluster.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsEksClusterFilterCriteriaTest < Minitest::Test - - def setup - AwsEksCluster::BackendFactory.select(MAEKSB::Basic) - end - - def test_search_miss - refute AwsEksCluster.new("nonesuch").exists? - end - - def test_recall_when_provided_a_string - cluster = AwsEksCluster.new "kangaroo" - assert cluster.exists? - assert_equal("kangaroo", cluster.cluster_name) - end - - def test_recall_when_provided_a_hash - cluster = AwsEksCluster.new cluster_name: "kang-the-alien" - assert cluster.exists? - assert_equal("kang-the-alien", cluster.name) - end - -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsEksClusterProperties < Minitest::Test - - def setup - AwsEksCluster::BackendFactory.select(MAEKSB::Basic) - @roo = AwsEksCluster.new("kangaroo") - @kang = AwsEksCluster.new("kang-the-alien") - @kodos = AwsEksCluster.new("kodos-the-alien") - @gamma = AwsEksCluster.new("gamma") - @miss = AwsEksCluster.new("nonesuch") - end - - def test_property_with_cluster_arn - assert_equal("arn:aws:eks:ab-region-1:012345678910:cluster/kangaroo", @roo.arn) - assert_equal("arn:aws:eks:ab-region-1:019876543210:cluster/kang-the-alien", @kang.arn) - assert_equal("arn:aws:eks:ab-region-1:013836573410:cluster/gamma", @gamma.arn) - assert_nil(@miss.arn) - end - - def test_property_with_name - assert_equal("kangaroo", @roo.name) - assert_equal("kang-the-alien", @kang.name) - assert_equal("gamma", @gamma.name) - assert_equal("nonesuch", @miss.name) # Even misses retain their identifier - end - - def test_property_with_status - assert_equal("ACTIVE", @roo.status) - assert_equal("CREATING", @kang.status) - assert_equal("DELETING", @gamma.status) - assert_equal("FAILED", @kodos.status) - assert_nil(@miss.status) - end - - def test_property_with_status_predicate - assert(@roo.active?) - refute(@kang.active?) - assert(@kang.creating?) - assert(@gamma.deleting?) - assert(@kodos.failed?) - assert_nil(@miss.active?) - end - - def test_property_with_subnets_count - assert_equal(4, @roo.subnets_count) - assert_equal(2, @kang.subnets_count) - assert_equal(0, @gamma.subnets_count) - assert_nil(@miss.subnets_count) - end - - def test_property_with_security_groups_count - assert_equal(0, @roo.security_groups_count) - assert_equal(1, @kang.security_groups_count) - assert_equal(2, @gamma.security_groups_count) - assert_nil(@miss.security_groups_count) - end - - def test_property_with_subnet_ids - assert_includes(@roo.subnet_ids, "subnet-e7e741bc") - assert_includes(@kang.subnet_ids, "subnet-1234e12a") - refute_includes(@gamma.subnet_ids, nil) - assert_kind_of(Array, @miss.subnet_ids) - assert_empty(@miss.subnet_ids) - end - - def test_property_with_security_group_ids - refute_includes(@roo.security_group_ids, nil) - assert_includes(@kang.security_group_ids, "sg-6979fe18") - assert_includes(@gamma.security_group_ids, "sg-6975fe18") - assert_kind_of(Array, @miss.security_group_ids) - assert_empty(@miss.security_group_ids) - end - - def test_property_with_version - assert_includes(@roo.version, "1.0") - assert_includes(@kang.version, "1.3") - assert_includes(@gamma.version, "2.3") - assert_nil(@miss.version) - end - - def test_property_with_created_at - assert_operator(@roo.created_at, :>, Time.at(1527807878)) - assert_operator(@kang.created_at, :<, Time.at(1527807979)) - assert_operator(@kang.created_at, :<, @gamma.created_at) - refute_operator(@kang.created_at, :>, @gamma.created_at) - assert_equal(@gamma.created_at, Time.at(9999999999)) - assert_nil(@miss.created_at) - end - - def test_property_with_role_arn - assert_equal(@roo.role_arn, "arn:aws:iam::012345678910:role/eks-service-role-AWSServiceRoleForAmazonEKS-J7ONKE3BQ4PI") - assert_nil(@miss.role_arn) - end - - def test_property_with_certificate_authority - assert_equal(@roo.certificate_authority, "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EVXpNVEl6TVRFek1Wb1hEVEk0TURVeU9ESXpNVEV6TVZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTZWCjVUaG4rdFcySm9Xa2hQMzRlVUZMNitaRXJOZGIvWVdrTmtDdWNGS2RaaXl2TjlMVmdvUmV2MjlFVFZlN1ZGbSsKUTJ3ZURyRXJiQyt0dVlibkFuN1ZLYmE3ay9hb1BHekZMdmVnb0t6b0M1N2NUdGVwZzRIazRlK2tIWHNaME10MApyb3NzcjhFM1ROeExETnNJTThGL1cwdjhsTGNCbWRPcjQyV2VuTjFHZXJnaDNSZ2wzR3JIazBnNTU0SjFWenJZCm9hTi8zODFUczlOTFF2QTBXb0xIcjBFRlZpTFdSZEoyZ3lXaC9ybDVyOFNDOHZaQXg1YW1BU0hVd01aTFpWRC8KTDBpOW4wRVM0MkpVdzQyQmxHOEdpd3NhTkJWV3lUTHZKclNhRXlDSHFtVVZaUTFDZkFXUjl0L3JleVVOVXM3TApWV1FqM3BFbk9RMitMSWJrc0RzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNZ3RsQ1dIQ2U2YzVHMXl2YlFTS0Q4K2hUalkKSm1NSG56L2EvRGt0WG9YUjFVQzIrZUgzT1BZWmVjRVZZZHVaSlZCckNNQ2VWR0ZkeWdBYlNLc1FxWDg0S2RXbAp1MU5QaERDSmEyRHliN2pVMUV6VThTQjFGZUZ5ZFE3a0hNS1E1blpBRVFQOTY4S01hSGUrSm0yQ2x1UFJWbEJVCjF4WlhTS1gzTVZ0K1Q0SU1EV2d6c3JRSjVuQkRjdEtLcUZtM3pKdVVubHo5ZEpVckdscEltMjVJWXJDckxYUFgKWkUwRUtRNWEzMHhkVWNrTHRGQkQrOEtBdFdqSS9yZUZPNzM1YnBMdVoyOTBaNm42QlF3elRrS0p4cnhVc3QvOAppNGsxcnlsaUdWMm5SSjBUYjNORkczNHgrYWdzYTRoSTFPbU90TFM0TmgvRXJxT3lIUXNDc2hEQUtKUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=") - assert_nil(@miss.certificate_authority) - end - - def test_property_with_vpc_id - assert_equal(@roo.vpc_id, "vpc-166723ec") - assert_equal(@kang.vpc_id, "vpc-266723ec") - assert_equal(@gamma.vpc_id, "vpc-366723ec") - assert_nil(@miss.vpc_id) - end - -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAEKSB - class Empty < AwsBackendBase - def describe_cluster(query = {}) - raise Aws::EKS::Errors::ResourceNotFoundException.new(nil, nil) - end - end - - class Basic < AwsBackendBase - def describe_cluster(query = {}) - fixtures = [ - OpenStruct.new({ - version: "1.0", - name: "kangaroo", - arn: "arn:aws:eks:ab-region-1:012345678910:cluster/kangaroo", - certificate_authority: OpenStruct.new({ - data: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EVXpNVEl6TVRFek1Wb1hEVEk0TURVeU9ESXpNVEV6TVZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTZWCjVUaG4rdFcySm9Xa2hQMzRlVUZMNitaRXJOZGIvWVdrTmtDdWNGS2RaaXl2TjlMVmdvUmV2MjlFVFZlN1ZGbSsKUTJ3ZURyRXJiQyt0dVlibkFuN1ZLYmE3ay9hb1BHekZMdmVnb0t6b0M1N2NUdGVwZzRIazRlK2tIWHNaME10MApyb3NzcjhFM1ROeExETnNJTThGL1cwdjhsTGNCbWRPcjQyV2VuTjFHZXJnaDNSZ2wzR3JIazBnNTU0SjFWenJZCm9hTi8zODFUczlOTFF2QTBXb0xIcjBFRlZpTFdSZEoyZ3lXaC9ybDVyOFNDOHZaQXg1YW1BU0hVd01aTFpWRC8KTDBpOW4wRVM0MkpVdzQyQmxHOEdpd3NhTkJWV3lUTHZKclNhRXlDSHFtVVZaUTFDZkFXUjl0L3JleVVOVXM3TApWV1FqM3BFbk9RMitMSWJrc0RzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNZ3RsQ1dIQ2U2YzVHMXl2YlFTS0Q4K2hUalkKSm1NSG56L2EvRGt0WG9YUjFVQzIrZUgzT1BZWmVjRVZZZHVaSlZCckNNQ2VWR0ZkeWdBYlNLc1FxWDg0S2RXbAp1MU5QaERDSmEyRHliN2pVMUV6VThTQjFGZUZ5ZFE3a0hNS1E1blpBRVFQOTY4S01hSGUrSm0yQ2x1UFJWbEJVCjF4WlhTS1gzTVZ0K1Q0SU1EV2d6c3JRSjVuQkRjdEtLcUZtM3pKdVVubHo5ZEpVckdscEltMjVJWXJDckxYUFgKWkUwRUtRNWEzMHhkVWNrTHRGQkQrOEtBdFdqSS9yZUZPNzM1YnBMdVoyOTBaNm42QlF3elRrS0p4cnhVc3QvOAppNGsxcnlsaUdWMm5SSjBUYjNORkczNHgrYWdzYTRoSTFPbU90TFM0TmgvRXJxT3lIUXNDc2hEQUtKUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=", - }), - created_at: Time.at(1527807879), - endpoint: "https://A0DCCD80A04F01705DD065655C30CC3D.yl4.aq-south-2.eks.amazonaws.com", - resources_vpc_config: OpenStruct.new({ - security_group_ids: [], - subnet_ids: %w{subnet-1234e12a subnet-e7e741bc subnet-e7a763ac subnet-e7b781cc}, - vpc_id: "vpc-166723ec", - }), - role_arn: "arn:aws:iam::012345678910:role/eks-service-role-AWSServiceRoleForAmazonEKS-J7ONKE3BQ4PI", - status: "ACTIVE", - }), - OpenStruct.new({ - version: "1.3", - name: "kang-the-alien", - arn: "arn:aws:eks:ab-region-1:019876543210:cluster/kang-the-alien", - certificate_authority: OpenStruct.new({ - data: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EVXpNVEl6TVRFek1Wb1hEVEk0TURVeU9ESXpNVEV6TVZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTZWCjVUaG4rdFcySm9Xa2hQMzRlVUZMNitaRXJOZGIvWVdrTmtDdWNGS2RaaXl2TjlMVmdvUmV2MjlFVFZlN1ZGbSsKUTJ3ZURyRXJiQyt0dVlibkFuN1ZLYmE3ay9hb1BHekZMdmVnb0t6b0M1N2NUdGVwZzRIazRlK2tIWHNaME10MApyb3NzcjhFM1ROeExETnNJTThGL1cwdjhsTGNCbWRPcjQyV2VuTjFHZXJnaDNSZ2wzR3JIazBnNTU0SjFWenJZCm9hTi8zODFUczlOTFF2QTBXb0xIcjBFRlZpTFdSZEoyZ3lXaC9ybDVyOFNDOHZaQXg1YW1BU0hVd01aTFpWRC8KTDBpOW4wRVM0MkpVdzQyQmxHOEdpd3NhTkJWV3lUTHZKclNhRXlDSHFtVVZaUTFDZkFXUjl0L3JleVVOVXM3TApWV1FqM3BFbk9RMitMSWJrc0RzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNZ3RsQ1dIQ2U2YzVHMXl2YlFTS0Q4K2hUalkKSm1NSG56L2EvRGt0WG9YUjFVQzIrZUgzT1BZWmVjRVZZZHVaSlZCckNNQ2VWR0ZkeWdBYlNLc1FxWDg0S2RXbAp1MU5QaERDSmEyRHliN2pVMUV6VThTQjFGZUZ5ZFE3a0hNS1E1blpBRVFQOTY4S01hSGUrSm0yQ2x1UFJWbEJVCjF4WlhTS1gzTVZ0K1Q0SU1EV2d6c3JRSjVuQkRjdEtLcUZtM3pKdVVubHo5ZEpVckdscEltMjVJWXJDckxYUFgKWkUwRUtRNWEzMHhkVWNrTHRGQkQrOEtBdFdqSS9yZUZPNzM1YnBMdVoyOTBaNm42QlF3elRrS0p4cnhVc3QvOAppNGsxcnlsaUdWMm5SSjBUYjNORkczNHgrYWdzYTRoSTFPbU90TFM0TmgvRXJxT3lIUXNDc2hEQUtKUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=", - }), - created_at: Time.at(1527807879), - endpoint: "https://A0DCCD80A04F01705DD065655C30CC3D.yl4.aq-south-1.eks.amazonaws.com", - resources_vpc_config: OpenStruct.new({ - security_group_ids: ["sg-6979fe18"], - subnet_ids: %w{subnet-1234e12a subnet-e7e741bc}, - vpc_id: "vpc-266723ec", - }), - role_arn: "arn:aws:iam::012345678910:role/eks-service-role-AWSServiceRoleForAmazonEKS-J7ONKE3BQ4PI", - status: "CREATING", - }), - OpenStruct.new({ - version: "2.3", - name: "gamma", - arn: "arn:aws:eks:ab-region-1:013836573410:cluster/gamma", - certificate_authority: OpenStruct.new({ - data: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EVXpNVEl6TVRFek1Wb1hEVEk0TURVeU9ESXpNVEV6TVZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTZWCjVUaG4rdFcySm9Xa2hQMzRlVUZMNitaRXJOZGIvWVdrTmtDdWNGS2RaaXl2TjlMVmdvUmV2MjlFVFZlN1ZGbSsKUTJ3ZURyRXJiQyt0dVlibkFuN1ZLYmE3ay9hb1BHekZMdmVnb0t6b0M1N2NUdGVwZzRIazRlK2tIWHNaME10MApyb3NzcjhFM1ROeExETnNJTThGL1cwdjhsTGNCbWRPcjQyV2VuTjFHZXJnaDNSZ2wzR3JIazBnNTU0SjFWenJZCm9hTi8zODFUczlOTFF2QTBXb0xIcjBFRlZpTFdSZEoyZ3lXaC9ybDVyOFNDOHZaQXg1YW1BU0hVd01aTFpWRC8KTDBpOW4wRVM0MkpVdzQyQmxHOEdpd3NhTkJWV3lUTHZKclNhRXlDSHFtVVZaUTFDZkFXUjl0L3JleVVOVXM3TApWV1FqM3BFbk9RMitMSWJrc0RzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNZ3RsQ1dIQ2U2YzVHMXl2YlFTS0Q4K2hUalkKSm1NSG56L2EvRGt0WG9YUjFVQzIrZUgzT1BZWmVjRVZZZHVaSlZCckNNQ2VWR0ZkeWdBYlNLc1FxWDg0S2RXbAp1MU5QaERDSmEyRHliN2pVMUV6VThTQjFGZUZ5ZFE3a0hNS1E1blpBRVFQOTY4S01hSGUrSm0yQ2x1UFJWbEJVCjF4WlhTS1gzTVZ0K1Q0SU1EV2d6c3JRSjVuQkRjdEtLcUZtM3pKdVVubHo5ZEpVckdscEltMjVJWXJDckxYUFgKWkUwRUtRNWEzMHhkVWNrTHRGQkQrOEtBdFdqSS9yZUZPNzM1YnBMdVoyOTBaNm42QlF3elRrS0p4cnhVc3QvOAppNGsxcnlsaUdWMm5SSjBUYjNORkczNHgrYWdzYTRoSTFPbU90TFM0TmgvRXJxT3lIUXNDc2hEQUtKUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=", - }), - created_at: Time.at(9999999999), - endpoint: "https://A0DCCD80A04F01705DD065655C30CC3D.yl4.aq-south-3.eks.amazonaws.com", - resources_vpc_config: OpenStruct.new({ - security_group_ids: %w{sg-6975fe18 sg-6479fe18}, - subnet_ids: [], - vpc_id: "vpc-366723ec", - }), - role_arn: "arn:aws:iam::012345678910:role/eks-service-role-AWSServiceRoleForAmazonEKS-J7ONKE3BQ4PI", - status: "DELETING", - }), - OpenStruct.new({ - version: "2.0", - name: "kodos-the-alien", - arn: "arn:aws:eks:ab-region-1:013836573410:cluster/kodos", - certificate_authority: OpenStruct.new({ - data: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNE1EVXpNVEl6TVRFek1Wb1hEVEk0TURVeU9ESXpNVEV6TVZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTZWCjVUaG4rdFcySm9Xa2hQMzRlVUZMNitaRXJOZGIvWVdrTmtDdWNGS2RaaXl2TjlMVmdvUmV2MjlFVFZlN1ZGbSsKUTJ3ZURyRXJiQyt0dVlibkFuN1ZLYmE3ay9hb1BHekZMdmVnb0t6b0M1N2NUdGVwZzRIazRlK2tIWHNaME10MApyb3NzcjhFM1ROeExETnNJTThGL1cwdjhsTGNCbWRPcjQyV2VuTjFHZXJnaDNSZ2wzR3JIazBnNTU0SjFWenJZCm9hTi8zODFUczlOTFF2QTBXb0xIcjBFRlZpTFdSZEoyZ3lXaC9ybDVyOFNDOHZaQXg1YW1BU0hVd01aTFpWRC8KTDBpOW4wRVM0MkpVdzQyQmxHOEdpd3NhTkJWV3lUTHZKclNhRXlDSHFtVVZaUTFDZkFXUjl0L3JleVVOVXM3TApWV1FqM3BFbk9RMitMSWJrc0RzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFNZ3RsQ1dIQ2U2YzVHMXl2YlFTS0Q4K2hUalkKSm1NSG56L2EvRGt0WG9YUjFVQzIrZUgzT1BZWmVjRVZZZHVaSlZCckNNQ2VWR0ZkeWdBYlNLc1FxWDg0S2RXbAp1MU5QaERDSmEyRHliN2pVMUV6VThTQjFGZUZ5ZFE3a0hNS1E1blpBRVFQOTY4S01hSGUrSm0yQ2x1UFJWbEJVCjF4WlhTS1gzTVZ0K1Q0SU1EV2d6c3JRSjVuQkRjdEtLcUZtM3pKdVVubHo5ZEpVckdscEltMjVJWXJDckxYUFgKWkUwRUtRNWEzMHhkVWNrTHRGQkQrOEtBdFdqSS9yZUZPNzM1YnBMdVoyOTBaNm42QlF3elRrS0p4cnhVc3QvOAppNGsxcnlsaUdWMm5SSjBUYjNORkczNHgrYWdzYTRoSTFPbU90TFM0TmgvRXJxT3lIUXNDc2hEQUtKUT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=", - }), - created_at: Time.at(0), - endpoint: "https://A0DCCD80A04F01705DD065655C30CC3D.yl4.aq-south-3.eks.amazonaws.com", - resources_vpc_config: OpenStruct.new({ - security_group_ids: %w{sg-6975fe18 sg-6479fe18}, - subnet_ids: [], - vpc_id: "vpc-366723ec", - }), - role_arn: "arn:aws:iam::012345678910:role/eks-service-role-AWSServiceRoleForAmazonEKS-J7ONKE3BQ4PI", - status: "FAILED", - }), - ] - if query[:name] - result = fixtures.select do |clst| - query[:name].include? clst.name - end - if result.empty? - raise Aws::EKS::Errors::ResourceNotFoundException.new(nil, nil) - else - OpenStruct.new({ cluster: result[0] }) - end - end - end - end -end diff --git a/test/unit/resources/aws_elb_test.rb b/test/unit/resources/aws_elb_test.rb deleted file mode 100644 index 1dd1960f2..000000000 --- a/test/unit/resources/aws_elb_test.rb +++ /dev/null @@ -1,267 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_elb" - -require "resource_support/aws" - -# MAESB = MockAwsElbSingularBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsElbConstructorTest < Minitest::Test - - def setup - AwsElb::BackendFactory.select(MAESB::Empty) - end - - def test_empty_params_rejected - assert_raises(ArgumentError) { AwsElb.new } - end - - def test_string_accepted - AwsElb.new "my-elb" - end - - def test_hash_accepted - AwsElb.new elb_name: "my-elb" - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsElb.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsElbFilterCriteriaTest < Minitest::Test - - def setup - AwsElb::BackendFactory.select(MAESB::Basic) - end - - def test_search_miss - refute AwsElb.new("nonesuch").exists? - end - - def test_recall_when_provided_a_string - elb = AwsElb.new "kangaroo" - assert elb.exists? - assert_equal("kangaroo", elb.elb_name) - end - - def test_recall_when_provided_a_symbol - elb = AwsElb.new elb_name: "kang-the-alien" - assert elb.exists? - assert_equal("kang-the-alien", elb.elb_name) - end - -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsElbProperties < Minitest::Test - - def setup - AwsElb::BackendFactory.select(MAESB::Basic) - @roo = AwsElb.new("kangaroo") - @kang = AwsElb.new("kang-the-alien") - @gamma = AwsElb.new("gamma") - @miss = AwsElb.new("nonesuch") - end - - def test_property_with_availability_zones - assert_includes(@roo.availability_zones, "us-east-1b") - assert_includes(@roo.availability_zones, "us-east-1c") - assert_equal(2, @roo.availability_zones.count) - refute_includes(@roo.availability_zones, nil) - assert_kind_of(Array, @miss.availability_zones) - assert_empty(@miss.availability_zones) - end - - def test_property_with_dns_name - assert_equal(@gamma.dns_name, "999999.us-east-1.aws.amazon.com") - assert_equal(@roo.dns_name, "12345678.us-east-2.aws.amazon.com") - end - - def test_property_with_external_ports - assert_includes(@kang.external_ports, 80) - assert_includes(@gamma.external_ports, 631) - assert_equal(1, @roo.external_ports.count) - refute_includes(@roo.external_ports, nil) - assert_kind_of(Array, @miss.external_ports) - assert_empty(@miss.external_ports) - end - - def test_property_with_instance_ids - assert_includes(@roo.instance_ids, "i-87654321") - assert_includes(@kang.instance_ids, "i-12345678") - assert_equal(2, @kang.instance_ids.count) - assert_equal(0, @gamma.instance_ids.count) - refute_includes(@kang.instance_ids, nil) - assert_kind_of(Array, @miss.instance_ids) - assert_empty(@miss.instance_ids) - end - - def test_property_with_internal_ports - assert_includes(@gamma.internal_ports, 80) - assert_includes(@roo.internal_ports, 1001) - assert_equal(1, @roo.internal_ports.count) - refute_includes(@roo.internal_ports, nil) - assert_kind_of(Array, @miss.internal_ports) - assert_empty(@miss.internal_ports) - end - - def test_property_with_security_group_ids - assert_includes(@kang.security_group_ids, "sg-12345678") - assert_includes(@kang.security_group_ids, "sg-99998888") - assert_equal(3, @kang.security_group_ids.count) - refute_includes(@kang.security_group_ids, nil) - assert_kind_of(Array, @miss.security_group_ids) - assert_empty(@miss.security_group_ids) - end - - def test_property_with_subnet_ids - assert_includes(@gamma.subnet_ids, "subnet-ccccdddd") - assert_includes(@kang.subnet_ids, "subnet-12345678") - assert_equal(2, @gamma.subnet_ids.count) - refute_includes(@gamma.subnet_ids, nil) - assert_kind_of(Array, @miss.subnet_ids) - assert_empty(@miss.subnet_ids) - end - - def test_property_vpc_id - assert_equal(@gamma.vpc_id, "vpc-87654321") - end - -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAESB - class Empty < AwsBackendBase - def describe_load_balancers(query = {}) - raise Aws::ElasticLoadBalancing::Errors::LoadBalancerNotFound.new(nil, nil) - end - end - - class Basic < AwsBackendBase - def describe_load_balancers(query = {}) - data = Aws::ElasticLoadBalancing::Types::DescribeAccessPointsOutput.new( - load_balancer_descriptions: [ - Aws::ElasticLoadBalancing::Types::LoadBalancerDescription.new( - availability_zones: %w{ - us-east-1a - us-east-1c - }, - dns_name: "12345678.us-east-1.aws.amazon.com", - load_balancer_name: "kang-the-alien", - listener_descriptions: [ - Aws::ElasticLoadBalancing::Types::ListenerDescription.new( - listener: Aws::ElasticLoadBalancing::Types::Listener.new( - protocol: "http", - load_balancer_port: 80, - instance_protocol: "http", - instance_port: 80 - ) - ), - ], - instances: [ - Aws::ElasticLoadBalancing::Types::Instance.new(instance_id: "i-12345678"), - Aws::ElasticLoadBalancing::Types::Instance.new(instance_id: "i-aaaabbbb"), - ], - security_groups: %w{ - sg-12345678 - sg-aaaabbbb - sg-99998888 - }, - subnets: %w{ - subnet-12345678 - subnet-aaaabbbb - }, - vpc_id: "vpc-12345678" - ), - Aws::ElasticLoadBalancing::Types::LoadBalancerDescription.new( - availability_zones: %w{ - us-east-1b - us-east-1c - }, - dns_name: "12345678.us-east-2.aws.amazon.com", - load_balancer_name: "kangaroo", - listener_descriptions: [ - Aws::ElasticLoadBalancing::Types::ListenerDescription.new( - listener: Aws::ElasticLoadBalancing::Types::Listener.new( - protocol: "tcp", - load_balancer_port: 1001, - instance_protocol: "tcp", - instance_port: 1001 - ) - ), - ], - instances: [ - Aws::ElasticLoadBalancing::Types::Instance.new(instance_id: "i-87654321"), - ], - security_groups: %w{ - sg-12345678 - sg-99998888 - }, - subnets: %w{ - subnet-12345678 - subnet-aaaabbbb - }, - vpc_id: "vpc-12345678" - ), - Aws::ElasticLoadBalancing::Types::LoadBalancerDescription.new( - availability_zones: %w{ - us-east-1a - us-east-1e - }, - dns_name: "999999.us-east-1.aws.amazon.com", - load_balancer_name: "gamma", - listener_descriptions: [ - Aws::ElasticLoadBalancing::Types::ListenerDescription.new( - listener: Aws::ElasticLoadBalancing::Types::Listener.new( - protocol: "http", - load_balancer_port: 631, - instance_protocol: "http", - instance_port: 80 - ) - ), - ], - instances: [ - ], - security_groups: %w{ - sg-12345678 - sg-99998888 - sg-01010101 - }, - subnets: %w{ - subnet-ccccdddd - subnet-aaaabbbb - }, - vpc_id: "vpc-87654321" - ), - ] - ) - - if query[:load_balancer_names] - result = data.load_balancer_descriptions.select do |lbd| - query[:load_balancer_names].include? lbd.load_balancer_name - end - if result.empty? - raise Aws::ElasticLoadBalancing::Errors::LoadBalancerNotFound.new(nil, nil) - else - Aws::ElasticLoadBalancing::Types::DescribeAccessPointsOutput.new( - load_balancer_descriptions: result - ) - end - else - data - end - end - end -end diff --git a/test/unit/resources/aws_elbs_test.rb b/test/unit/resources/aws_elbs_test.rb deleted file mode 100644 index 69526684a..000000000 --- a/test/unit/resources/aws_elbs_test.rb +++ /dev/null @@ -1,311 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_elbs" - -require "resource_support/aws" - -# MAEPB = MockAwsELBsPluralBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsElbsConstructorTest < Minitest::Test - - def setup - AwsElbs::BackendFactory.select(MAEPB::Empty) - end - - def test_empty_params_ok - AwsElbs.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsElbs.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Filter Criteria -#=============================================================================# -class AwsElbsFilterCriteriaTest < Minitest::Test - - def setup - AwsElbs::BackendFactory.select(MAEPB::Basic) - end - - def test_filter_with_no_criteria - assert AwsElbs.new.exists? - assert_equal(3, AwsElbs.new.count) - end - - def test_filter_with_availability_zones - hit = AwsElbs.new.where { availability_zones.include? "us-east-1c" } - assert(hit.exists?) - assert_equal(2, hit.count) - - miss = AwsElbs.new.where { availability_zones.include? "us-east-1g" } - refute(miss.exists?) - end - - def test_filter_with_dns_name - hit = AwsElbs.new.where(dns_name: /us-east-1\.aws/) - assert(hit.exists?) - assert_equal(2, hit.count) - - miss = AwsElbs.new.where(dns_name: "bananas") - refute(miss.exists?) - end - - def test_filter_with_elb_name - hit = AwsElbs.new.where(elb_name: /kang/) - assert(hit.exists?) - assert_equal(2, hit.count) - - miss = AwsElbs.new.where(elb_name: "kodos") - refute(miss.exists?) - end - - def test_filter_with_external_ports - hit = AwsElbs.new.where { external_ports.include? 631 } - assert(hit.exists?) - assert_equal(1, hit.count) - - miss = AwsElbs.new.where { external_ports.include? 22000 } - refute(miss.exists?) - end - - def test_filter_with_instance_ids - hit = AwsElbs.new.where { instance_ids.include? "i-12345678" } - assert(hit.exists?) - assert_equal(1, hit.count) - - miss = AwsElbs.new.where { instance_ids.include? "i-deadbeef" } - refute(miss.exists?) - end - - def test_filter_with_internal_ports - hit = AwsElbs.new.where { internal_ports.include? 80 } - assert(hit.exists?) - assert_equal(2, hit.count) - - miss = AwsElbs.new.where { internal_ports.include? 93 } - refute(miss.exists?) - end - - def test_filter_with_security_group_ids - hit = AwsElbs.new.where { security_group_ids.include? "sg-12345678" } - assert(hit.exists?) - assert_equal(3, hit.count) - - miss = AwsElbs.new.where { security_group_ids.include? "sg-99999999" } - refute(miss.exists?) - end - - def test_filter_with_subnet_ids - hit = AwsElbs.new.where { subnet_ids.include? "subnet-12345678" } - assert(hit.exists?) - assert_equal(2, hit.count) - - miss = AwsElbs.new.where { subnet_ids.include? "subnet-99999999" } - refute(miss.exists?) - end - - def test_filter_with_vpc_id - hit = AwsElbs.new.where(vpc_id: "vpc-12345678") - assert(hit.exists?) - assert_equal(2, hit.count) - - miss = AwsElbs.new.where(vpc_id: "vpc-09876543") - refute(miss.exists?) - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsElbsProperties < Minitest::Test - - def setup - AwsElbs::BackendFactory.select(MAEPB::Basic) - @elbs = AwsElbs.new - end - - def test_properties_with_availability_zones - assert_includes(@elbs.availability_zones, "us-east-1a") - assert_includes(@elbs.availability_zones, "us-east-1e") - assert_equal(4, @elbs.availability_zones.count) - refute_includes(@elbs.availability_zones, nil) - end - - def test_properties_with_dns_names - assert_includes(@elbs.dns_names, "999999.us-east-1.aws.amazon.com") - assert_includes(@elbs.dns_names, "12345678.us-east-2.aws.amazon.com") - assert_equal(3, @elbs.dns_names.count) - refute_includes(@elbs.dns_names, nil) - end - - def test_properties_with_elb_names - assert_includes(@elbs.elb_names, "kang-the-alien") - assert_includes(@elbs.elb_names, "kangaroo") - assert_equal(3, @elbs.elb_names.count) - refute_includes(@elbs.elb_names, nil) - end - - def test_properties_with_external_ports - assert_includes(@elbs.external_ports, 80) - assert_includes(@elbs.external_ports, 631) - assert_equal(3, @elbs.external_ports.count) - refute_includes(@elbs.external_ports, nil) - end - - def test_properties_with_instance_ids - assert_includes(@elbs.instance_ids, "i-87654321") - assert_includes(@elbs.instance_ids, "i-12345678") - assert_equal(3, @elbs.instance_ids.count) - refute_includes(@elbs.instance_ids, nil) - end - - def test_properties_with_internal_ports - assert_includes(@elbs.internal_ports, 80) - assert_includes(@elbs.internal_ports, 1001) - assert_equal(2, @elbs.internal_ports.count) - refute_includes(@elbs.internal_ports, nil) - end - - def test_properties_with_security_group_ids - assert_includes(@elbs.security_group_ids, "sg-12345678") - assert_includes(@elbs.security_group_ids, "sg-99998888") - assert_equal(4, @elbs.security_group_ids.count) - refute_includes(@elbs.security_group_ids, nil) - end - - def test_properties_with_subnet_ids - assert_includes(@elbs.subnet_ids, "subnet-ccccdddd") - assert_includes(@elbs.subnet_ids, "subnet-12345678") - assert_equal(3, @elbs.subnet_ids.count) - refute_includes(@elbs.subnet_ids, nil) - end - - def test_property_vpc_ids - assert_includes(@elbs.vpc_ids, "vpc-87654321") - assert_includes(@elbs.vpc_ids, "vpc-12345678") - assert_equal(2, @elbs.vpc_ids.count) - refute_includes(@elbs.vpc_ids, nil) - end - -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAEPB - class Empty < AwsBackendBase - def describe_load_balancers(query = {}) - Aws::ElasticLoadBalancing::Types::DescribeAccessPointsOutput.new( - load_balancer_descriptions: [] - ) - end - end - - class Basic < AwsBackendBase - def describe_load_balancers(query = {}) - Aws::ElasticLoadBalancing::Types::DescribeAccessPointsOutput.new( - load_balancer_descriptions: [ - Aws::ElasticLoadBalancing::Types::LoadBalancerDescription.new( - availability_zones: %w{ - us-east-1a - us-east-1c - }, - dns_name: "12345678.us-east-1.aws.amazon.com", - load_balancer_name: "kang-the-alien", - listener_descriptions: [ - Aws::ElasticLoadBalancing::Types::ListenerDescription.new( - listener: Aws::ElasticLoadBalancing::Types::Listener.new( - protocol: "http", - load_balancer_port: 80, - instance_protocol: "http", - instance_port: 80 - ) - ), - ], - instances: [ - Aws::ElasticLoadBalancing::Types::Instance.new(instance_id: "i-12345678"), - Aws::ElasticLoadBalancing::Types::Instance.new(instance_id: "i-aaaabbbb"), - ], - security_groups: %w{ - sg-12345678 - sg-aaaabbbb - sg-99998888 - }, - subnets: %w{ - subnet-12345678 - subnet-aaaabbbb - }, - vpc_id: "vpc-12345678" - ), - Aws::ElasticLoadBalancing::Types::LoadBalancerDescription.new( - availability_zones: %w{ - us-east-1b - us-east-1c - }, - dns_name: "12345678.us-east-2.aws.amazon.com", - load_balancer_name: "kangaroo", - listener_descriptions: [ - Aws::ElasticLoadBalancing::Types::ListenerDescription.new( - listener: Aws::ElasticLoadBalancing::Types::Listener.new( - protocol: "tcp", - load_balancer_port: 1001, - instance_protocol: "tcp", - instance_port: 1001 - ) - ), - ], - instances: [ - Aws::ElasticLoadBalancing::Types::Instance.new(instance_id: "i-87654321"), - ], - security_groups: %w{ - sg-12345678 - sg-99998888 - }, - subnets: %w{ - subnet-12345678 - subnet-aaaabbbb - }, - vpc_id: "vpc-12345678" - ), - Aws::ElasticLoadBalancing::Types::LoadBalancerDescription.new( - availability_zones: %w{ - us-east-1a - us-east-1e - }, - dns_name: "999999.us-east-1.aws.amazon.com", - load_balancer_name: "gamma", - listener_descriptions: [ - Aws::ElasticLoadBalancing::Types::ListenerDescription.new( - listener: Aws::ElasticLoadBalancing::Types::Listener.new( - protocol: "http", - load_balancer_port: 631, - instance_protocol: "http", - instance_port: 80 - ) - ), - ], - instances: [ - ], - security_groups: %w{ - sg-12345678 - sg-99998888 - sg-01010101 - }, - subnets: %w{ - subnet-ccccdddd - subnet-aaaabbbb - }, - vpc_id: "vpc-87654321" - ), - ] - ) - end - end -end diff --git a/test/unit/resources/aws_flow_log_test.rb b/test/unit/resources/aws_flow_log_test.rb deleted file mode 100644 index 867a39ac3..000000000 --- a/test/unit/resources/aws_flow_log_test.rb +++ /dev/null @@ -1,134 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_flow_log" - -require "resource_support/aws" - -class EmptyAwsFlowLog < Minitest::Test - def setup - AwsFlowLog::BackendFactory.select(MockAwsFlowLog::Empty) - end - - def test_rejects_empty_params - assert_raises(ArgumentError) { AwsFlowLog.new } - end - - def test_search_hit_via_scalar_fails - refute AwsFlowLog.new(flow_log_id: "fl-abcd1234").exists? - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsFlowLog.new(shoe_size: 9) } - end -end - -class BasicAwsFlowLog < Minitest::Test - def setup - AwsFlowLog::BackendFactory.select(MockAwsFlowLog::Basic) - end - - def test_search_hit - assert AwsFlowLog.new(flow_log_id: "fl-abcd1111").exists? - end - - def test_to_s - assert_equal "AWS Flow Log fl-abcd1234", - AwsFlowLog.new(flow_log_id: "fl-abcd1234").to_s - assert_equal "AWS Flow Log fl-abcd3333", - AwsFlowLog.new(subnet_id: "subnet-abcd3333").to_s - assert_equal "AWS Flow Log fl-abcd1111", - AwsFlowLog.new(vpc_id: "vpc-abcd1111").to_s - end - - def test_flow_log_id - assert_equal "fl-abcd1111", AwsFlowLog.new(flow_log_id: "fl-abcd1111").flow_log_id - end - - def test_log_group_name - assert_equal "inspec-abcd1111", AwsFlowLog.new(flow_log_id: "fl-abcd1111").log_group_name - end - - def test_resource_id - assert_equal "vpc-abcd1111", AwsFlowLog.new(flow_log_id: "fl-abcd1111").resource_id - assert_equal "eni-abcd2222", AwsFlowLog.new(flow_log_id: "fl-abcd2222").resource_id - assert_equal "subnet-abcd3333", AwsFlowLog.new(flow_log_id: "fl-abcd3333").resource_id - end - - def test_resource_type - assert_equal "vpc", AwsFlowLog.new(flow_log_id: "fl-abcd1111").resource_type - assert_equal "eni", AwsFlowLog.new(flow_log_id: "fl-abcd2222").resource_type - assert_equal "subnet", AwsFlowLog.new(flow_log_id: "fl-abcd3333").resource_type - end - - def test_search_miss - flowlog = AwsFlowLog.new(flow_log_id: "fl-12341234") - refute flowlog.exists? - assert_nil flowlog.log_group_name - assert_nil flowlog.resource_id - assert_equal "AWS Flow Log fl-12341234", flowlog.to_s - end - - def test_search_subnet_miss - flowlog = AwsFlowLog.new(subnet_id: "subnet-12341234") - refute flowlog.exists? - assert_nil flowlog.log_group_name - assert_nil flowlog.resource_id - assert_equal "AWS Flow Log subnet-12341234", flowlog.to_s - end - - def test_search_vpc_miss - flowlog = AwsFlowLog.new(vpc_id: "vpc-12341234") - refute flowlog.exists? - assert_nil flowlog.log_group_name - assert_nil flowlog.resource_id - assert_equal "AWS Flow Log vpc-12341234", flowlog.to_s - end - - def test_attached_to? - assert AwsFlowLog.new(flow_log_id: "fl-abcd1111").attached_to_vpc? - assert AwsFlowLog.new(flow_log_id: "fl-abcd2222").attached_to_eni? - assert AwsFlowLog.new(flow_log_id: "fl-abcd3333").attached_to_subnet? - end -end - -module MockAwsFlowLog - class Empty < AwsBackendBase - def describe_flow_logs(query) - Aws::EC2::Types::DescribeFlowLogsResult.new( - flow_logs: [] - ) - end - end - - class Basic < AwsBackendBase - def describe_flow_logs(query) - resp = Aws::EC2::Types::DescribeFlowLogsResult.new( - flow_logs: [ - Aws::EC2::Types::FlowLog.new( - flow_log_id: "fl-abcd1111", - log_group_name: "inspec-abcd1111", - resource_id: "vpc-abcd1111" - ), - Aws::EC2::Types::FlowLog.new( - flow_log_id: "fl-abcd2222", - log_group_name: "inspec-abcd2222", - resource_id: "eni-abcd2222" - ), - Aws::EC2::Types::FlowLog.new( - flow_log_id: "fl-abcd3333", - log_group_name: "inspec-abcd3333", - resource_id: "subnet-abcd3333" - ), - ] - ) - - selected = resp[:flow_logs].select do |fl| - query[:filter].all? do |filter| - filter[:values].include?(fl[filter[:name].tr("-", "_")]) - end - end - - OpenStruct.new({ flow_logs: selected }) - end - end -end diff --git a/test/unit/resources/aws_iam_access_key_test.rb b/test/unit/resources/aws_iam_access_key_test.rb deleted file mode 100644 index 9f3477fd3..000000000 --- a/test/unit/resources/aws_iam_access_key_test.rb +++ /dev/null @@ -1,212 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_access_key" - -require "resource_support/aws" - -class AwsIamAccessKeyConstructorTest < Minitest::Test - def setup - AwsIamAccessKey::BackendFactory.select(EmptyMAIKSB) - end - - # Username or ID are required - def test_username_sufficient - AwsIamAccessKey.new(username: "bob") - end - - def test_access_key_id_sufficient - AwsIamAccessKey.new(access_key_id: "AKIA1234567890123BOB") - end - - def test_id_is_alias_for_access_key_id - AwsIamAccessKey.new(id: "AKIA1234567890123BOB") - end - - def test_access_key_id_and_username_ok - AwsIamAccessKey.new(username: "bob", access_key_id: "AKIA1234567890123BOB") - end - - def test_access_key_id_gets_validated - assert_raises(ArgumentError) do - AwsIamAccessKey.new(access_key_id: "martians") - end - end - - def test_reject_other_params - assert_raises(ArgumentError) do - AwsIamAccessKey.new(shoe_size: 9) - end - end -end - -#==========================================================# -# Search / Recall # -#==========================================================# -class AwsIamAccessKeyRecallTest < Minitest::Test - def setup - AwsIamAccessKey::BackendFactory.select(BasicMAIKSB) - end - - def test_recall_access_key_id_hit - key = AwsIamAccessKey.new(access_key_id: "AKIA1234567890123BOB") - assert(key.exists?) - end - - def test_recall_access_key_id_miss - key = AwsIamAccessKey.new(access_key_id: "AKIA123456789012NOPE") - refute(key.exists?) - end - - def test_recall_username_hit - key = AwsIamAccessKey.new(username: "bob") - assert(key.exists?) - end - - # Recall miss by username - def test_recall_username_miss - key = AwsIamAccessKey.new(username: "nope") - refute(key.exists?) - end - - # Recall multiple hit by username - def test_recall_username_multiple - assert_raises(RuntimeError) do - AwsIamAccessKey.new(username: "sally") - end - end -end - -#==========================================================# -# Properties # -#==========================================================# -class AwsIamAccessKeyPropertiesTest < Minitest::Test - def setup - AwsIamAccessKey::BackendFactory.select(BasicMAIKSB) - end - - def test_property_access_key_id - bob = AwsIamAccessKey.new(username: "bob") - assert_equal("AKIA1234567890123BOB", bob.access_key_id) - noone = AwsIamAccessKey.new(username: "roderick") - assert_nil(noone.access_key_id) - end - - def test_property_username - sally1 = AwsIamAccessKey.new(access_key_id: "AKIA12345678901SALLY") - assert_equal("sally", sally1.username) - noone = AwsIamAccessKey.new(access_key_id: "AKIA12345678901STEVE") - assert_nil(noone.username) - end - - def test_property_status - sally1 = AwsIamAccessKey.new(access_key_id: "AKIA12345678901SALLY") - assert_equal("Active", sally1.status) - sally2 = AwsIamAccessKey.new(access_key_id: "AKIA12345678901SALL2") - assert_equal("Inactive", sally2.status) - noone = AwsIamAccessKey.new(access_key_id: "AKIA12345678901STEVE") - assert_nil(noone.status) - end - - def test_property_create_date - bob = AwsIamAccessKey.new(username: "bob") - assert_kind_of(DateTime, bob.create_date) - assert_equal(DateTime.parse("2017-10-27T17:58:00Z"), bob.create_date) - noone = AwsIamAccessKey.new(username: "roderick") - assert_nil(noone.create_date) - end - - def test_property_last_used_date - bob = AwsIamAccessKey.new(username: "bob") - assert_kind_of(DateTime, bob.last_used_date) - assert_equal(DateTime.parse("2017-11-30T17:58:00Z"), bob.last_used_date) - noone = AwsIamAccessKey.new(username: "roderick") - assert_nil(noone.last_used_date) - end - -end - -#==========================================================# -# Matchers # -#==========================================================# -class AwsIamAccessKeyMatchersTest < Minitest::Test - def setup - AwsIamAccessKey::BackendFactory.select(BasicMAIKSB) - end - - def test_matcher_be_active - sally1 = AwsIamAccessKey.new(access_key_id: "AKIA12345678901SALLY") - assert(sally1.active?) - sally2 = AwsIamAccessKey.new(access_key_id: "AKIA12345678901SALL2") - refute(sally2.active?) - noone = AwsIamAccessKey.new(access_key_id: "AKIA12345678901STEVE") - assert_nil(noone.active?) - end -end - -#==========================================================# -# Mock Support Classes # -#==========================================================# - -# MIAKSB = Mock IAM Access Key Singular Backend. Abbreviation not used -# outside this file. - -class EmptyMAIKSB < AwsBackendBase - def list_access_keys(query) - raise Aws::IAM::Errors::NoSuchEntity.new(nil, nil) - end -end - -class BasicMAIKSB < AwsBackendBase - def list_access_keys(query) - fixtures = [ - # Bob has one active key - OpenStruct.new({ - user_name: "bob", - access_key_id: "AKIA1234567890123BOB", - create_date: DateTime.parse("2017-10-27T17:58:00Z"), - status: "Active", - }), - # Sally has one active and one inactive key - OpenStruct.new({ - user_name: "sally", - access_key_id: "AKIA12345678901SALLY", - create_date: DateTime.parse("2017-10-22T17:58:00Z"), - status: "Active", - }), - OpenStruct.new({ - user_name: "sally", - access_key_id: "AKIA12345678901SALL2", - create_date: DateTime.parse("2017-10-22T17:58:00Z"), - status: "Inactive", - }), - ] - matches = [] - if query.key?(:user_name) - matches = fixtures.select { |k| k.user_name == query[:user_name] } - if matches.empty? - raise Aws::IAM::Errors::NoSuchEntity.new(nil, nil) - end - else - matches = fixtures - end - OpenStruct.new({ access_key_metadata: matches }) - end - - def get_access_key_last_used(query) - fixtures = { - "AKIA1234567890123BOB" => OpenStruct.new({ - user_name: "bob", - access_key_last_used: OpenStruct.new({ - last_used_date: DateTime.parse("2017-11-30T17:58:00Z"), - }), - }), - "AKIA12345678901SALLY" => OpenStruct.new({ - user_name: "sally", - access_key_last_used: OpenStruct.new({ - last_used_date: DateTime.parse("2017-11-25T17:58:00Z"), - }), - }), - } - fixtures[query[:access_key_id]] - end -end diff --git a/test/unit/resources/aws_iam_access_keys_test.rb b/test/unit/resources/aws_iam_access_keys_test.rb deleted file mode 100644 index 3872e976c..000000000 --- a/test/unit/resources/aws_iam_access_keys_test.rb +++ /dev/null @@ -1,360 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_access_keys" - -require "resource_support/aws" - -#==========================================================# -# Constructor Tests # -#==========================================================# - -class AwsIamAccessKeysConstructorTest < Minitest::Test - def setup - AwsIamAccessKeys::BackendFactory.select(AlwaysEmptyMAKP) - end - - def test_bare_constructor_does_not_explode - AwsIamAccessKeys.new - end -end - -#==========================================================# -# Filtering Tests # -#==========================================================# - -class AwsIamAccessKeysFilterTest < Minitest::Test - - def test_filter_methods_should_exist - AwsIamAccessKeys::BackendFactory.select(AlwaysEmptyMAKP) - resource = AwsIamAccessKeys.new - %i{where exists?}.each do |meth| - assert_respond_to(resource, meth) - end - end - - def test_filter_method_where_should_be_chainable - AwsIamAccessKeys::BackendFactory.select(AlwaysEmptyMAKP) - resource = AwsIamAccessKeys.new - assert_respond_to(resource.where, :where) - end - - def test_filter_method_exists_should_probe_empty_when_empty - AwsIamAccessKeys::BackendFactory.select(AlwaysEmptyMAKP) - resource = AwsIamAccessKeys.new - refute(resource.exists?) - end - - def test_filter_method_exists_should_probe_present_when_present - AwsIamAccessKeys::BackendFactory.select(BasicMAKP) - resource = AwsIamAccessKeys.new - assert(resource.exists?) - end -end - -#==========================================================# -# Filter Criteria Tests # -#==========================================================# - -class AwsIamAccessKeysFilterCriteriaTest < Minitest::Test - def setup - # Here we always want no results. - AwsIamAccessKeys::BackendFactory.select(AlwaysEmptyMAKP) - @valued_criteria = { - username: "bob", - id: "AKIA1234567890ABCDEF", - access_key_id: "AKIA1234567890ABCDEF", - } - end - - def test_criteria_when_used_in_constructor_with_value - @valued_criteria.each do |criterion, value| - AwsIamAccessKeys.new(criterion => value) - end - end - - def test_criteria_when_used_in_where_with_value - @valued_criteria.each do |criterion, value| - AwsIamAccessKeys.new.where(criterion => value) - end - end - - # Negative cases - def test_criteria_when_used_in_constructor_with_bad_criterion - assert_raises(ArgumentError) do - AwsIamAccessKeys.new(nope: "some_val") - end - end - - def test_criteria_when_used_in_where_with_bad_criterion - assert_raises(ArgumentError) do - AwsIamAccessKeys.new(nope: "some_val") - end - end - - # Identity criterion is allowed based on regex - def test_identity_criterion_when_used_in_constructor_positive - AwsIamAccessKeys.new("AKIA1234567890ABCDEF") - end - - # Permitted by FilterTable? - def test_identity_criterion_when_used_in_where_positive - AwsIamAccessKeys.new.where("AKIA1234567890ABCDEF") - end - - def test_identity_criterion_when_used_in_constructor_negative - assert_raises(RuntimeError) do - AwsIamAccessKeys.new("NopeAKIA1234567890ABCDEF") - end - end - - # Permitted by FilterTable? - # def test_identity_criterion_when_used_in_where_negative - # assert_raises(RuntimeError) do - # AwsIamAccessKeys.new.where('NopeAKIA1234567890ABCDEF') - # end - # end -end - -#==========================================================# -# Property Tests # -#==========================================================# -class AwsIamAccessKeysPropertiesTest < Minitest::Test - def setup - # Reset back to the basic kit each time. - AwsIamAccessKeys::BackendFactory.select(BasicMAKP) - @all_basic = AwsIamAccessKeys.new - end - - #----------------------------------------------------------# - # created_date / created_days_ago / created_hours_ago # - #----------------------------------------------------------# - def test_property_created_date - assert_kind_of(DateTime, @all_basic.entries.first.create_date) - - arg_filtered = @all_basic.where(create_date: DateTime.parse("2017-10-27T17:58:00Z")) - assert_equal(1, arg_filtered.entries.count) - assert arg_filtered.access_key_ids.first.end_with?("BOB") - - block_filtered = @all_basic.where { create_date.friday? } - assert_equal(1, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("BOB") - end - - def test_property_created_days_ago - assert_kind_of(Integer, @all_basic.entries.first.created_days_ago) - - arg_filtered = @all_basic.where(created_days_ago: 9) - assert_equal(1, arg_filtered.entries.count) - assert arg_filtered.access_key_ids.first.end_with?("SALLY") - - block_filtered = @all_basic.where { created_days_ago > 2 } - assert_equal(2, block_filtered.entries.count) - end - - def test_property_created_hours_ago - assert_kind_of(Integer, @all_basic.entries.first.created_hours_ago) - - arg_filtered = @all_basic.where(created_hours_ago: 222) - assert_equal(1, arg_filtered.entries.count) - assert arg_filtered.access_key_ids.first.end_with?("SALLY") - - block_filtered = @all_basic.where { created_hours_ago > 100 } - assert_equal(2, block_filtered.entries.count) - end - - #----------------------------------------------------------# - # created_with_user # - #----------------------------------------------------------# - def test_property_created_with_user - assert_kind_of(TrueClass, @all_basic.entries[0].created_with_user) - assert_kind_of(FalseClass, @all_basic.entries[1].created_with_user) - - arg_filtered = @all_basic.where(created_with_user: true) - assert_equal(2, arg_filtered.entries.count) - assert arg_filtered.access_key_ids.first.end_with?("BOB") - - block_filtered = @all_basic.where { created_with_user } - assert_equal(2, block_filtered.entries.count) - end - - #----------------------------------------------------------# - # active / inactive # - #----------------------------------------------------------# - def test_property_active - assert_kind_of(TrueClass, @all_basic.entries.first.active) - - arg_filtered = @all_basic.where(active: true) - assert_equal(2, arg_filtered.entries.count) - - block_filtered = @all_basic.where { active } - assert_equal(2, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("BOB") - end - - def test_property_inactive - assert_kind_of(FalseClass, @all_basic.entries.first.inactive) - - arg_filtered = @all_basic.where(inactive: true) - assert_equal(1, arg_filtered.entries.count) - - block_filtered = @all_basic.where { inactive } - assert_equal(1, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("ROBIN") - end - - #-----------------------------------------------------------# - # last_used_date / last_used_days_ago / last_used_hours_ago # - #-----------------------------------------------------------# - def test_property_last_used_date - assert_kind_of(NilClass, @all_basic.entries[0].last_used_date) - assert_kind_of(DateTime, @all_basic.entries[1].last_used_date) - - arg_filtered = @all_basic.where(last_used_date: DateTime.parse("2017-10-27T17:58:00Z")) - assert_equal(1, arg_filtered.entries.count) - assert arg_filtered.access_key_ids.first.end_with?("SALLY") - - block_filtered = @all_basic.where { last_used_date && last_used_date.friday? } - assert_equal(1, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("SALLY") - end - - def test_property_last_used_days_ago - assert_kind_of(NilClass, @all_basic.entries[0].last_used_days_ago) - assert_kind_of(Integer, @all_basic.entries[1].last_used_days_ago) - - arg_filtered = @all_basic.where(last_used_days_ago: 4) - assert_equal(1, arg_filtered.entries.count) - assert arg_filtered.access_key_ids.first.end_with?("SALLY") - - block_filtered = @all_basic.where { last_used_days_ago && (last_used_days_ago < 2) } - assert_equal(1, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("ROBIN") - end - - def test_property_last_used_hours_ago - assert_kind_of(NilClass, @all_basic.entries[0].last_used_hours_ago) - assert_kind_of(Integer, @all_basic.entries[1].last_used_hours_ago) - - arg_filtered = @all_basic.where(last_used_hours_ago: 102) - assert_equal(1, arg_filtered.entries.count) - assert arg_filtered.access_key_ids.first.end_with?("SALLY") - - block_filtered = @all_basic.where { last_used_hours_ago && (last_used_hours_ago < 10) } - assert_equal(1, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("ROBIN") - end - - #-----------------------------------------------------------# - # ever_used / never_used # - #-----------------------------------------------------------# - def test_property_ever_used - assert_kind_of(FalseClass, @all_basic.entries[0].ever_used) - assert_kind_of(TrueClass, @all_basic.entries[1].ever_used) - - arg_filtered = @all_basic.where(ever_used: true) - assert_equal(2, arg_filtered.entries.count) - - block_filtered = @all_basic.where { ever_used } - assert_equal(2, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("SALLY") - end - - def test_property_never_used - assert_kind_of(TrueClass, @all_basic.entries[0].never_used) - assert_kind_of(FalseClass, @all_basic.entries[1].never_used) - - arg_filtered = @all_basic.where(never_used: true) - assert_equal(1, arg_filtered.entries.count) - - block_filtered = @all_basic.where { never_used } - assert_equal(1, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("BOB") - end - - #----------------------------------------------------------# - # user_created_date # - #----------------------------------------------------------# - def test_property_user_created_date - assert_kind_of(DateTime, @all_basic.entries.first.user_created_date) - arg_filtered = @all_basic.where(user_created_date: DateTime.parse("2017-10-21T17:58:00Z")) - assert_equal(1, arg_filtered.entries.count) - assert arg_filtered.access_key_ids.first.end_with?("SALLY") - - block_filtered = @all_basic.where { user_created_date.saturday? } - assert_equal(1, block_filtered.entries.count) - assert block_filtered.access_key_ids.first.end_with?("SALLY") - end -end -#==========================================================# -# Mock Support Classes # -#==========================================================# - -# MAKP = MockAccessKeyProvider. Abbreviation not used -# outside this file. - -class AlwaysEmptyMAKP < AwsBackendBase - def fetch(_filter_criteria) - [] - end -end - -class BasicMAKP < AwsBackendBase - def fetch(_filter_criteria) - [ - { - username: "bob", - access_key_id: "AKIA1234567890123BOB", - id: "AKIA1234567890123BOB", - create_date: DateTime.parse("2017-10-27T17:58:00Z"), - created_days_ago: 4, - created_hours_ago: 102, - created_with_user: true, - status: "Active", - active: true, - inactive: false, - last_used_date: nil, - last_used_days_ago: nil, - last_used_hours_ago: nil, - ever_used: false, - never_used: true, - user_created_date: DateTime.parse("2017-10-27T17:58:00Z"), - }, - { - username: "sally", - access_key_id: "AKIA12345678901SALLY", - id: "AKIA12345678901SALLY", - create_date: DateTime.parse("2017-10-22T17:58:00Z"), - created_days_ago: 9, - created_hours_ago: 222, - created_with_user: false, - status: "Active", - active: true, - inactive: false, - last_used_date: DateTime.parse("2017-10-27T17:58:00Z"), - last_used_days_ago: 4, - last_used_hours_ago: 102, - ever_used: true, - never_used: false, - user_created_date: DateTime.parse("2017-10-21T17:58:00Z"), - }, - { - username: "robin", - access_key_id: "AKIA12345678901ROBIN", - id: "AKIA12345678901ROBIN", - create_date: DateTime.parse("2017-10-31T17:58:00Z"), - created_days_ago: 1, - created_hours_ago: 12, - created_with_user: true, - status: "Inactive", - active: false, - inactive: true, - last_used_date: DateTime.parse("2017-10-31T20:58:00Z"), - last_used_days_ago: 0, - last_used_hours_ago: 5, - ever_used: true, - never_used: false, - user_created_date: DateTime.parse("2017-10-31T17:58:00Z"), - }, - ] - end -end diff --git a/test/unit/resources/aws_iam_group_test.rb b/test/unit/resources/aws_iam_group_test.rb deleted file mode 100644 index e3615ea40..000000000 --- a/test/unit/resources/aws_iam_group_test.rb +++ /dev/null @@ -1,122 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_group" - -require "resource_support/aws" - -# MAIGSB = MockAwsIamGroupSingularBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsIamGroupConstructorTest < Minitest::Test - - def setup - AwsIamGroup::BackendFactory.select(MAIGSB::Empty) - end - - def test_rejects_empty_params - assert_raises(ArgumentError) { AwsIamGroup.new } - end - - def test_accepts_group_name_as_scalar - AwsIamGroup.new("Whatever") - end - - def test_accepts_group_name_as_hash - AwsIamGroup.new(group_name: "Whatever") - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsIamGroup.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsIamGroupRecallTest < Minitest::Test - - def setup - AwsIamGroup::BackendFactory.select(MAIGSB::Basic) - end - - def test_search_hit_via_scalar_works - assert AwsIamGroup.new("Administrator").exists? - end - - def test_search_hit_via_hash_works - assert AwsIamGroup.new(group_name: "Administrator").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsIamGroup.new(group_name: "Whatever").exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsIamGroupPropertiesTest < Minitest::Test - - def setup - AwsIamGroup::BackendFactory.select(MAIGSB::Basic) - end - - def test_property_users - assert_equal(%w{user1 user2}, AwsIamGroup.new("Administrator").users) - assert_nil(AwsIamGroup.new("nonexistent").users) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAIGSB - class Empty < AwsBackendBase - def get_group(query = {}) - raise Aws::IAM::Errors::NoSuchEntity.new(nil, nil) - end - end - - class Basic < AwsBackendBase - def get_group(query = {}) - fixtures = [ - OpenStruct.new({ - path: "/", - group_name: "Administrator", - group_id: "AGPAQWERQWERQWERQWERQ", - arn: "arn:aws:iam::111111111111:group/Administrator", - create_date: DateTime.parse("2017-12-14 05:29:57 UTC"), - users: [ - OpenStruct.new({ - user_name: "user1", - }), - OpenStruct.new({ - user_name: "user2", - }), - ], - }), - OpenStruct.new({ - path: "/", - group_name: "AmazonEC2ReadOnlyAccess", - group_id: "AGPAASDFASDFASDFASDFA", - arn: "arn:aws:iam::111111111111:group/AmazonEC2ReadOnlyAccess", - create_date: DateTime.parse("2017-12-15 17:37:14 UTC"), - }), - ] - - selected = fixtures.select do |group| - group[:group_name].eql? query[:group_name] - end - - if selected.empty? - raise Aws::IAM::Errors::NoSuchEntity.new(nil, nil) - end - - OpenStruct.new({ group: selected[0], users: selected[0].users }) - end - end - -end diff --git a/test/unit/resources/aws_iam_groups_test.rb b/test/unit/resources/aws_iam_groups_test.rb deleted file mode 100644 index 2cd2f73e2..000000000 --- a/test/unit/resources/aws_iam_groups_test.rb +++ /dev/null @@ -1,94 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_groups" - -require "resource_support/aws" - -# MAIGPB = MockAwsIamGroupsPluralBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsIamGroupsConstructorTest < Minitest::Test - - def setup - AwsIamGroups::BackendFactory.select(MAIGPB::Empty) - end - - def test_empty_params_ok - AwsIamGroups.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsIamGroups.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsIamGroupsRecallEmptyTest < Minitest::Test - - def setup - AwsIamGroups::BackendFactory.select(MAIGPB::Empty) - end - - def test_search_miss_via_empty_groups - refute AwsIamGroups.new.exist? - end -end - -class AwsIamGroupsRecallBasicTest < Minitest::Test - - def setup - AwsIamGroups::BackendFactory.select(MAIGPB::Basic) - end - - def test_search_hit_via_empty_query - assert AwsIamGroups.new.exist? - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAIGPB - class Empty < AwsBackendBase - def list_groups(query = {}) - OpenStruct.new({ groups: [] }) - end - end - - class Basic < AwsBackendBase - def list_groups(query = {}) - fixtures = [ - OpenStruct.new({ - path: "/", - group_name: "Administrator", - group_id: "AGPAQWERQWERQWERQWERQ", - arn: "arn:aws:iam::111111111111:group/Administrator", - create_date: DateTime.parse("2017-12-14 05:29:57 UTC"), - }), - OpenStruct.new({ - path: "/", - group_name: "AmazonEC2ReadOnlyAccess", - group_id: "AGPAASDFASDFASDFASDFA", - arn: "arn:aws:iam::111111111111:group/AmazonEC2ReadOnlyAccess", - create_date: DateTime.parse("2017-12-15 17:37:14 UTC"), - }), - ] - - if query[:path_prefix].nil? - selected = fixtures - else - selected = fixtures.select do |group| - group[:path].start_with? query[:path_prefix] - end - end - - OpenStruct.new({ groups: selected }) - end - end - -end diff --git a/test/unit/resources/aws_iam_password_policy_test.rb b/test/unit/resources/aws_iam_password_policy_test.rb deleted file mode 100644 index d6de756d3..000000000 --- a/test/unit/resources/aws_iam_password_policy_test.rb +++ /dev/null @@ -1,87 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_password_policy" - -require "resource_support/aws" - -class AwsIamPasswordPolicyTest < Minitest::Test - def setup - @mock_conn = Minitest::Mock.new - @mock_resource = Minitest::Mock.new - @mock_policy = Minitest::Mock.new - - @mock_conn.expect :iam_resource, @mock_resource - end - - def test_policy_exists_when_policy_exists - @mock_resource.expect :account_password_policy, true - - assert_equal true, AwsIamPasswordPolicy.new(@mock_conn).exists? - end - - def test_policy_does_not_exists_when_no_policy - skip "Disabled until fix for issue 2633" - @mock_resource.expect :account_password_policy, nil do - raise Aws::IAM::Errors::NoSuchEntity.new nil, nil - end - - assert_equal false, AwsIamPasswordPolicy.new(@mock_conn).exists? - end - - def test_throws_when_password_age_0 - @mock_policy.expect :expire_passwords, false - @mock_resource.expect :account_password_policy, @mock_policy - - e = assert_raises Exception do - AwsIamPasswordPolicy.new(@mock_conn).max_password_age_in_days - end - - assert_equal e.message, "this policy does not expire passwords" - end - - def test_prevents_password_reuse_returns_true_when_not_nil - configure_policy_password_reuse_prevention(value: Object.new) - - assert AwsIamPasswordPolicy.new(@mock_conn).prevent_password_reuse? - end - - def test_prevents_password_reuse_returns_false_when_nil - configure_policy_password_reuse_prevention(value: nil) - - refute AwsIamPasswordPolicy.new(@mock_conn).prevent_password_reuse? - end - - def test_number_of_passwords_to_remember_throws_when_nil - configure_policy_password_reuse_prevention(value: nil) - - e = assert_raises Exception do - AwsIamPasswordPolicy.new(@mock_conn).number_of_passwords_to_remember - end - - assert_equal e.message, "this policy does not prevent password reuse" - end - - def test_number_of_passwords_to_remember_returns_configured_value - expected_value = 5 - configure_policy_password_reuse_prevention(value: expected_value, n: 2) - - assert_equal( - expected_value, - AwsIamPasswordPolicy.new(@mock_conn).number_of_passwords_to_remember - ) - end - - def test_policy_to_s - configure_policy_password_reuse_prevention(value: Object.new) - expected_value = "IAM Password-Policy" - test = AwsIamPasswordPolicy.new(@mock_conn).to_s - assert_equal expected_value, test - end - - private - - def configure_policy_password_reuse_prevention(value: value = nil, n: 1) - n.times { @mock_policy.expect :password_reuse_prevention, value } - @mock_resource.expect :account_password_policy, @mock_policy - end -end diff --git a/test/unit/resources/aws_iam_policies_test.rb b/test/unit/resources/aws_iam_policies_test.rb deleted file mode 100644 index 37f0e4c02..000000000 --- a/test/unit/resources/aws_iam_policies_test.rb +++ /dev/null @@ -1,108 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_policies" - -require "resource_support/aws" - -# MAIPPB = MockAwsIamPoliciesPluralBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsIamPoliciesConstructorTest < Minitest::Test - - def setup - AwsIamPolicies::BackendFactory.select(MAIPPB::Empty) - end - - def test_empty_params_ok - AwsIamPolicies.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsIamPolicies.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsIamPoliciesRecallEmptyTest < Minitest::Test - - def setup - AwsIamPolicies::BackendFactory.select(MAIPPB::Empty) - end - - def test_search_miss_policy_empty_policy_list - refute AwsIamPolicies.new.exists? - end -end - -class AwsIamPoliciesRecallBasicTest < Minitest::Test - - def setup - AwsIamPolicies::BackendFactory.select(MAIPPB::Basic) - end - - def test_search_hit_via_empty_filter - assert AwsIamPolicies.new.exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsIamPoliciesProperties < Minitest::Test - def setup - AwsIamPolicies::BackendFactory.select(MAIPPB::Basic) - end - - def test_property_policy_names - basic = AwsIamPolicies.new - assert_kind_of(Array, basic.policy_names) - assert(basic.policy_names.include?("test-policy-1")) - refute(basic.policy_names.include?(nil)) - end - - def test_property_arns - basic = AwsIamPolicies.new - assert_kind_of(Array, basic.arns) - assert(basic.arns.include?("arn:aws:iam::aws:policy/test-policy-1")) - refute(basic.arns.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAIPPB - class Empty < AwsBackendBase - def list_policies(query = {}) - OpenStruct.new({ policies: [] }) - end - end - - class Basic < AwsBackendBase - def list_policies(query = {}) - fixtures = [ - OpenStruct.new({ - policy_name: "test-policy-1", - arn: "arn:aws:iam::aws:policy/test-policy-1", - default_version_id: "v1", - attachment_count: 3, - is_attachable: true, - }), - OpenStruct.new({ - policy_name: "test-policy-2", - arn: "arn:aws:iam::aws:policy/test-policy-2", - default_version_id: "v2", - attachment_count: 0, - is_attachable: false, - }), - ] - - OpenStruct.new({ policies: fixtures }) - end - end -end diff --git a/test/unit/resources/aws_iam_policy_test.rb b/test/unit/resources/aws_iam_policy_test.rb deleted file mode 100644 index 622c6bfcb..000000000 --- a/test/unit/resources/aws_iam_policy_test.rb +++ /dev/null @@ -1,455 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_policy" - -require "resource_support/aws" - -# MAIPSB = MockAwsIamPolicySingularBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsIamPolicyConstructorTest < Minitest::Test - - def setup - AwsIamPolicy::BackendFactory.select(MAIPSB::Empty) - end - - def test_rejects_empty_params - assert_raises(ArgumentError) { AwsIamPolicy.new } - end - - def test_accepts_policy_name_as_scalar - AwsIamPolicy.new("test-policy-1") - end - - def test_accepts_policy_name_as_hash - AwsIamPolicy.new(policy_name: "test-policy-1") - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsIamPolicy.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsIamPolicyRecallTest < Minitest::Test - - def setup - AwsIamPolicy::BackendFactory.select(MAIPSB::Basic) - end - - def test_search_hit_via_scalar_works - assert AwsIamPolicy.new("test-policy-1").exists? - end - - def test_search_hit_via_hash_works - assert AwsIamPolicy.new(policy_name: "test-policy-1").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsIamPolicy.new(policy_name: "non-existent").exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsIamPolicyPropertiesTest < Minitest::Test - - def setup - AwsIamPolicy::BackendFactory.select(MAIPSB::Basic) - end - - def test_property_arn - assert_equal("arn:aws:iam::aws:policy/test-policy-1", AwsIamPolicy.new("test-policy-1").arn) - assert_nil(AwsIamPolicy.new(policy_name: "non-existent").arn) - end - - def test_property_default_version_id - assert_equal("v1", AwsIamPolicy.new("test-policy-1").default_version_id) - assert_nil(AwsIamPolicy.new(policy_name: "non-existent").default_version_id) - end - - def test_property_attachment_count - assert_equal(3, AwsIamPolicy.new("test-policy-1").attachment_count) - assert_nil(AwsIamPolicy.new(policy_name: "non-existent").attachment_count) - end - - def test_property_attached_users - assert_equal(["test-user"], AwsIamPolicy.new("test-policy-1").attached_users) - assert_nil(AwsIamPolicy.new(policy_name: "non-existent").attached_users) - end - - def test_property_attached_groups - assert_equal(["test-group"], AwsIamPolicy.new("test-policy-1").attached_groups) - assert_nil(AwsIamPolicy.new(policy_name: "non-existent").attached_groups) - end - - def test_property_attached_roles - assert_equal(["test-role"], AwsIamPolicy.new("test-policy-1").attached_roles) - assert_nil(AwsIamPolicy.new(policy_name: "non-existent").attached_roles) - end - - def test_property_policy - policy = AwsIamPolicy.new("test-policy-1").policy - assert_kind_of(Hash, policy) - assert(policy.key?("Statement"), "test-policy-1 should have a Statement key when unpacked") - assert_equal(1, policy["Statement"].count, "test-policy-1 should have 1 statements when unpacked") - assert_nil(AwsIamPolicy.new("non-existent").policy) - end - - def test_property_statement_count - assert_nil(AwsIamPolicy.new("non-existent").statement_count) - assert_equal(1, AwsIamPolicy.new("test-policy-1").statement_count) - assert_equal(2, AwsIamPolicy.new("test-policy-2").statement_count) - assert_equal(1, AwsIamPolicy.new("test-policy-3").statement_count) - end -end - -#=============================================================================# -# Matchers -#=============================================================================# -class AwsIamPolicyMatchersTest < Minitest::Test - - def setup - AwsIamPolicy::BackendFactory.select(MAIPSB::Basic) - end - - def test_matcher_attached_positive - assert AwsIamPolicy.new("test-policy-1").attached? - end - - def test_matcher_attached_negative - refute AwsIamPolicy.new("test-policy-2").attached? - end - - def test_matcher_attached_to_user_positive - assert AwsIamPolicy.new("test-policy-1").attached_to_user?("test-user") - end - - def test_matcher_attached_to_user_negative - refute AwsIamPolicy.new("test-policy-2").attached_to_user?("test-user") - end - - def test_matcher_attached_to_group_positive - assert AwsIamPolicy.new("test-policy-1").attached_to_group?("test-group") - end - - def test_matcher_attached_to_group_negative - refute AwsIamPolicy.new("test-policy-2").attached_to_group?("test-group") - end - - def test_matcher_attached_to_role_positive - assert AwsIamPolicy.new("test-policy-1").attached_to_role?("test-role") - end - - def test_matcher_attached_to_role_negative - refute AwsIamPolicy.new("test-policy-2").attached_to_role?("test-role") - end - - def test_have_statement_when_policy_does_not_exist - assert_nil AwsIamPolicy.new("nonesuch").has_statement?("Effect" => "foo") - end - - def test_have_statement_when_provided_no_criteria - AwsIamPolicy.new("test-policy-1").has_statement? - end - - def test_have_statement_when_provided_acceptable_criteria - { - "Action" => "dummy", - "Effect" => "Deny", # This has restictions on the value provided - "Resource" => "dummy", - "Sid" => "dummy", - }.each do |criterion, test_value| - [ - criterion, - criterion.downcase, - criterion.to_sym, - criterion.downcase.to_sym, - ].each do |variant| - AwsIamPolicy.new("test-policy-1").has_statement?(variant => test_value) - end - end - end - - def test_have_statement_when_provided_unimplemented_criteria - %w{ - Conditional - NotAction - NotPrincipal - NotResource - Principal - }.each do |criterion| - ex = assert_raises(ArgumentError) { AwsIamPolicy.new("test-policy-1").has_statement?(criterion => "dummy") } - assert_match(/not supported/, ex.message) - end - end - - def test_have_statement_when_provided_unrecognized_criteria - ex = assert_raises(ArgumentError) { AwsIamPolicy.new("test-policy-1").has_statement?("foo" => "dummy") } - assert_match(/Unrecognized/, ex.message) - end - - def test_have_statement_when_sid_is_provided - ["Sid", "sid", :Sid, :sid].each do |variant| - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => "beta01")) - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "CloudWatchEventsFullAccess")) - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "IAMPassRoleForCloudWatchEvents")) - refute(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "beta01")) - - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => /eta/)) - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => /CloudWatch/)) - refute(AwsIamPolicy.new("test-policy-2").has_statement?(variant => /eta/)) - end - end - - def test_have_statement_when_effect_is_provided - ["Effect", "effect", :Effect, :effect].each do |variant| - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => "Deny")) - refute(AwsIamPolicy.new("test-policy-1").has_statement?(variant => "Allow")) - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "Allow")) - - assert_raises(ArgumentError) { AwsIamPolicy.new("test-policy-1").has_statement?(variant => "Disallow") } - assert_raises(ArgumentError) { AwsIamPolicy.new("test-policy-1").has_statement?(variant => "allow") } - assert_raises(ArgumentError) { AwsIamPolicy.new("test-policy-1").has_statement?(variant => :Allow) } - assert_raises(ArgumentError) { AwsIamPolicy.new("test-policy-1").has_statement?(variant => :allow) } - end - end - - def test_have_statement_when_action_is_provided - ["Action", "action", :Action, :action].each do |variant| - # Able to match a simple string action when multiple statements present - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "iam:PassRole")) - # Able to match a wildcard string action - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "events:*")) - # Do not match a wildcard when using strings - refute(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "events:EnableRule")) - # Do match when using a regex - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => /^events\:/)) - # Able to match one action when the statement has an array of actions - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => "ec2:DescribeSubnets")) - # Do not match if only one action specified as an array when the statement has an array of actions - refute(AwsIamPolicy.new("test-policy-1").has_statement?(variant => ["ec2:DescribeSubnets"])) - # Do match if two actions specified when the statement has an array of actions - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => ["ec2:DescribeSubnets", "ec2:DescribeSecurityGroups"])) - # Do match setwise if two actions specified when the statement has an array of actions - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => ["ec2:DescribeSecurityGroups", "ec2:DescribeSubnets"])) - # Do match if only one regex action specified when the statement has an array of actions - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => /^ec2\:Describe/)) - # Do match if one regex action specified in an array when the statement has an array of actions - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => [/^ec2\:Describe/])) - # Able to match a degenerate policy doc in which there is exactly one statement as a hash. - assert(AwsIamPolicy.new("test-policy-3").has_statement?(variant => "acm:GetCertificate")) - # Don't explode, and also don't match, if a policy has a statement without an Action - refute(AwsIamPolicy.new("test-policy-4").has_statement?(variant => "iam:*")) - end - end - - def test_have_statement_when_resource_is_provided - ["Resource", "resource", :Resource, :resource].each do |variant| - # Able to match a simple string resource when multiple statements present - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "arn:aws:iam::*:role/AWS_Events_Invoke_Targets")) - # Able to match a wildcard string resource - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "*")) - # Do not match a wildcard when using strings - refute(AwsIamPolicy.new("test-policy-2").has_statement?(variant => "arn:aws:events:us-east-1:123456789012:rule/my-rule")) - # Do match when using a regex - assert(AwsIamPolicy.new("test-policy-2").has_statement?(variant => /AWS_Events_Invoke_Targets$/)) - # Able to match one resource when the statement has an array of resources - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => "arn:aws:ec2:::*")) - # Do not match if only one resource specified as an array when the statement has an array of resources - refute(AwsIamPolicy.new("test-policy-1").has_statement?(variant => ["arn:aws:ec2:::*"])) - # Do match if two resources specified when the statement has an array of resources - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => ["arn:aws:ec2:::*", "*"])) - # Do match setwise if two resources specified when the statement has an array of resources - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => ["*", "arn:aws:ec2:::*"])) - # Do match if only one regex resource specified when the statement has an array of resources - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => /^arn\:aws\:ec2/)) - # Do match if one regex resource specified in an array when the statement has an array of resources - assert(AwsIamPolicy.new("test-policy-1").has_statement?(variant => [/\*/])) - # Able to match a degenerate policy doc in which there is exactly one statement as a hash. - assert(AwsIamPolicy.new("test-policy-3").has_statement?(variant => "*")) - end - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAIPSB - class Empty < AwsBackendBase - def list_policies(query) - OpenStruct.new(policies: []) - end - end - - class Basic < AwsBackendBase - def list_policies(query) - fixtures = [ - OpenStruct.new({ - policy_name: "test-policy-1", - arn: "arn:aws:iam::aws:policy/test-policy-1", - default_version_id: "v1", - attachment_count: 3, - is_attachable: true, - }), - OpenStruct.new({ - policy_name: "test-policy-2", - arn: "arn:aws:iam::aws:policy/test-policy-2", - default_version_id: "v1", - attachment_count: 0, - is_attachable: false, - }), - OpenStruct.new({ - policy_name: "test-policy-3", - arn: "arn:aws:iam::aws:policy/test-policy-3", - default_version_id: "v1", - attachment_count: 0, - is_attachable: true, - }), - OpenStruct.new({ - policy_name: "test-policy-4", - arn: "arn:aws:iam::aws:policy/test-policy-4", - default_version_id: "v1", - attachment_count: 0, - is_attachable: false, - }), - ] - OpenStruct.new({ policies: fixtures }) - end - - def list_entities_for_policy(query) - policy = {} - policy["arn:aws:iam::aws:policy/test-policy-1"] = - { - policy_groups: [ - OpenStruct.new({ - group_name: "test-group", - group_id: "AIDAIJ3FUBXLZ4VXV34LE", - }), - ], - policy_users: [ - OpenStruct.new({ - user_name: "test-user", - user_id: "AIDAIJ3FUBXLZ4VXV34LE", - }), - ], - policy_roles: [ - OpenStruct.new({ - role_name: "test-role", - role_id: "AIDAIJ3FUBXLZ4VXV34LE", - }), - ], - } - policy["arn:aws:iam::aws:policy/test-policy-2"] = - { - policy_groups: [], - policy_users: [], - policy_roles: [], - } - OpenStruct.new( policy[query[:policy_arn]] ) - end - - def get_policy_version(query) - fixtures = { - "arn:aws:iam::aws:policy/test-policy-1" => { - "v1" => OpenStruct.new( - # This is the integration test fixture "beta" - # { - # "Version"=>"2012-10-17", - # "Statement"=> [ - # { - # "Sid"=>"beta01", - # "Action"=>["ec2:DescribeSubnets", "ec2:DescribeSecurityGroups"], - # "Effect"=>"Deny", - # "Resource"=>["arn:aws:ec2:::*", "*"] - # } - # ] - # } - document: "%7B%0A%20%20%22Version%22%3A%20%222012-10-17%22%2C%0A%20%20%22Statement%22%3A%20%5B%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22Sid%22%3A%20%22beta01%22%2C%0A%20%20%20%20%20%20%22Action%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%22ec2%3ADescribeSubnets%22%2C%0A%20%20%20%20%20%20%20%20%22ec2%3ADescribeSecurityGroups%22%0A%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%22Effect%22%3A%20%22Deny%22%2C%0A%20%20%20%20%20%20%22Resource%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%22arn%3Aaws%3Aec2%3A%3A%3A%2A%22%2C%0A%20%20%20%20%20%20%20%20%22%2A%22%0A%20%20%20%20%20%20%5D%0A%20%20%20%20%7D%0A%20%20%5D%0A%7D%0A" - ), - }, - "arn:aws:iam::aws:policy/test-policy-2" => { - "v1" => OpenStruct.new( - # This is AWS-managed CloudWatchEventsFullAccess - # { - # "Version"=>"2012-10-17", - # "Statement"=> [ - # { - # "Sid"=>"CloudWatchEventsFullAccess", - # "Effect"=>"Allow", - # "Action"=>"events:*", - # "Resource"=>"*" - # }, - # { - # "Sid"=>"IAMPassRoleForCloudWatchEvents", - # "Effect"=>"Allow", - # "Action"=>"iam:PassRole", - # "Resource"=>"arn:aws:iam::*:role/AWS_Events_Invoke_Targets" - # } - # ] - # } - document: "%7B%0A%20%20%20%20%22Version%22%3A%20%222012-10-17%22%2C%0A%20%20%20%20%22Statement%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Sid%22%3A%20%22CloudWatchEventsFullAccess%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Effect%22%3A%20%22Allow%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Action%22%3A%20%22events%3A%2A%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Resource%22%3A%20%22%2A%22%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Sid%22%3A%20%22IAMPassRoleForCloudWatchEvents%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Effect%22%3A%20%22Allow%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Action%22%3A%20%22iam%3APassRole%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Resource%22%3A%20%22arn%3Aaws%3Aiam%3A%3A%2A%3Arole%2FAWS_Events_Invoke_Targets%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%5D%0A%7D" - ), - }, - "arn:aws:iam::aws:policy/test-policy-3" => { - "v1" => OpenStruct.new( - # This is AWS-managed AWSCertificateManagerReadOnly - # { - # "Version": "2012-10-17", - # "Statement": { - # "Effect": "Allow", - # "Action": [ - # "acm:DescribeCertificate", - # "acm:ListCertificates", - # "acm:GetCertificate", - # "acm:ListTagsForCertificate" - # ], - # "Resource": "*" - # } - # } - document: "%7B%0A%20%20%20%20%22Version%22%3A%20%222012-10-17%22%2C%0A%20%20%20%20%22Statement%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%22Effect%22%3A%20%22Allow%22%2C%0A%20%20%20%20%20%20%20%20%22Action%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22acm%3ADescribeCertificate%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22acm%3AListCertificates%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22acm%3AGetCertificate%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22acm%3AListTagsForCertificate%22%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%22Resource%22%3A%20%22%2A%22%0A%20%20%20%20%7D%0A%7D" - ), - }, - "arn:aws:iam::aws:policy/test-policy-4" => { - "v1" => OpenStruct.new( - # This is arn:aws:iam::aws:policy/PowerUserAccess - # { - # "Version": "2012-10-17", - # "Statement": [ - # { - # "Effect": "Allow", - # "NotAction": [ - # "iam:*", - # "organizations:*" - # ], - # "Resource": "*" - # }, - # { - # "Effect": "Allow", - # "Action": [ - # "iam:CreateServiceLinkedRole", - # "iam:DeleteServiceLinkedRole", - # "iam:ListRoles", - # "organizations:DescribeOrganization" - # ], - # "Resource": "*" - # } - # ] - # } - document: "%7B%0A%20%20%22Version%22%3A%20%222012-10-17%22%2C%0A%20%20%22Statement%22%3A%20%5B%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22Effect%22%3A%20%22Allow%22%2C%0A%20%20%20%20%20%20%22NotAction%22%3A%20%5B%22iam%3A%2A%22%2C%20%22organizations%3A%2A%22%5D%2C%0A%20%20%20%20%20%20%22Resource%22%3A%20%22%2A%22%0A%20%20%20%20%7D%2C%7B%0A%20%20%20%20%20%20%22Effect%22%3A%20%22Allow%22%2C%0A%20%20%20%20%20%20%22Action%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%22iam%3ACreateServiceLinkedRole%22%2C%0A%20%20%20%20%20%20%20%20%20%20%22iam%3ADeleteServiceLinkedRole%22%2C%0A%20%20%20%20%20%20%20%20%20%20%22iam%3AListRoles%22%2C%0A%20%20%20%20%20%20%20%20%20%20%22organizations%3ADescribeOrganization%22%0A%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%22Resource%22%3A%20%22%2A%22%0A%20%20%20%20%7D%0A%20%20%5D%0A%7D" - ), - }, - } - pv = fixtures.dig(query[:policy_arn], query[:version_id]) - return OpenStruct.new(policy_version: pv) if pv - - raise Aws::IAM::Errors::NoSuchEntity.new(nil, nil) - end - end -end diff --git a/test/unit/resources/aws_iam_role_test.rb b/test/unit/resources/aws_iam_role_test.rb deleted file mode 100644 index 7f0cea870..000000000 --- a/test/unit/resources/aws_iam_role_test.rb +++ /dev/null @@ -1,105 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_role" - -require "resource_support/aws" - -# MIRB = MockIamRoleBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsIamRoleConstructorTest < Minitest::Test - def setup - AwsIamRole::BackendFactory.select(AwsMIRB::Basic) - end - - def test_constructor_some_args_required - assert_raises(ArgumentError) { AwsIamRole.new } - end - - def test_constructor_accepts_scalar_role_name - AwsIamRole.new("alpha") - end - - def test_constructor_accepts_role_name_as_hash - AwsIamRole.new(role_name: "alpha") - end - - def test_constructor_rejects_unrecognized_resource_params - assert_raises(ArgumentError) { AwsIamRole.new(beep: "boop") } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsIamRoleRecallTest < Minitest::Test - # No setup here - each test needs to explicitly declare - # what they want from the backend. - - def test_recall_no_match_is_no_exception - AwsIamRole::BackendFactory.select(AwsMIRB::Miss) - refute AwsIamRole.new("nonesuch").exists? - end - - def test_recall_match_single_result_works - AwsIamRole::BackendFactory.select(AwsMIRB::Basic) - assert AwsIamRole.new("alpha").exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# - -class AwsIamRolePropertiesTest < Minitest::Test - def setup - AwsIamRole::BackendFactory.select(AwsMIRB::Basic) - end - - #--------------------------------------- - # description - #--------------------------------------- - def test_property_description - assert_equal("alpha role", AwsIamRole.new("alpha").description) - end - - def test_prop_conf_sub_count_zero - assert_empty(AwsIamRole.new("beta").description) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module AwsMIRB - class Miss < AwsBackendBase - def get_role(query) - raise Aws::IAM::Errors::NoSuchEntity.new("Nope", "Nope") - end - end - - class Basic < AwsBackendBase - def get_role(query) - fixtures = { - "alpha" => OpenStruct.new({ - role_name: "alpha", - description: "alpha role", - }), - "beta" => OpenStruct.new({ - role_name: "beta", - description: "", - }), - } - unless fixtures.key?(query[:role_name]) - raise Aws::IAM::Errors::NoSuchEntity.new("Nope", "Nope") - end - - OpenStruct.new({ - role: fixtures[query[:role_name]], - }) - end - end -end diff --git a/test/unit/resources/aws_iam_root_user_test.rb b/test/unit/resources/aws_iam_root_user_test.rb deleted file mode 100644 index 2a59b79e4..000000000 --- a/test/unit/resources/aws_iam_root_user_test.rb +++ /dev/null @@ -1,100 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_root_user" - -require "resource_support/aws" - -class AwsIamRootUserTest < Minitest::Test - def setup - @mock_conn = Minitest::Mock.new - @mock_client = Minitest::Mock.new - - @mock_conn.expect :iam_client, @mock_client - end - - def test_has_access_key_returns_true_from_summary_account - test_summary_map = OpenStruct.new( - summary_map: { "AccountAccessKeysPresent" => 1 } - ) - @mock_client.expect :get_account_summary, test_summary_map - - assert_equal true, AwsIamRootUser.new(@mock_conn).has_access_key? - end - - def test_has_access_key_returns_false_from_summary_account - test_summary_map = OpenStruct.new( - summary_map: { "AccountAccessKeysPresent" => 0 } - ) - @mock_client.expect :get_account_summary, test_summary_map - - assert_equal false, AwsIamRootUser.new(@mock_conn).has_access_key? - end - - def test_has_mfa_enabled_returns_true_when_account_mfa_devices_is_one - test_summary_map = OpenStruct.new( - summary_map: { "AccountMFAEnabled" => 1 } - ) - @mock_client.expect :get_account_summary, test_summary_map - - assert_equal true, AwsIamRootUser.new(@mock_conn).has_mfa_enabled? - end - - def test_has_mfa_enabled_returns_false_when_account_mfa_devices_is_zero - test_summary_map = OpenStruct.new( - summary_map: { "AccountMFAEnabled" => 0 } - ) - @mock_client.expect :get_account_summary, test_summary_map - - assert_equal false, AwsIamRootUser.new(@mock_conn).has_mfa_enabled? - end - - def test_has_virtual_mfa_enabled_returns_true_when_account_vmfa_devices_is_one - test_list_virtual_mfa_devices = OpenStruct.new( - virtual_mfa_devices: [Aws::IAM::Types::VirtualMFADevice.new( - serial_number: "arn:aws:iam::123456789011:mfa/root-account-mfa-device", - user: Aws::IAM::Types::User.new( - user_id: "123456789011", - arn: "arn:aws:iam::123456789011:root" - ) - )] - ) - @mock_client.expect :list_virtual_mfa_devices, test_list_virtual_mfa_devices - - assert_equal true, AwsIamRootUser.new(@mock_conn).has_virtual_mfa_enabled? - end - - def test_has_virtual_mfa_enabled_returns_false_when_account_vmfa_devices_is_zero - test_list_virtual_mfa_devices = OpenStruct.new( - virtual_mfa_devices: [] - ) - @mock_client.expect :list_virtual_mfa_devices, test_list_virtual_mfa_devices - - assert_equal false, AwsIamRootUser.new(@mock_conn).has_virtual_mfa_enabled? - end - - def test_has_hardware_mfa_enabled_returns_true_when_account_hardware_devices_is_one - test_list_virtual_mfa_devices = OpenStruct.new( - virtual_mfa_devices: [] - ) - test_summary_map = OpenStruct.new( - summary_map: { "AccountMFAEnabled" => 1 } - ) - @mock_client.expect :list_virtual_mfa_devices, test_list_virtual_mfa_devices - @mock_client.expect :get_account_summary, test_summary_map - - assert_equal true, AwsIamRootUser.new(@mock_conn).has_hardware_mfa_enabled? - end - - def test_has_hardware_mfa_enabled_returns_false_when_account_hardware_devices_is_zero - test_list_virtual_mfa_devices = OpenStruct.new( - virtual_mfa_devices: [] - ) - test_summary_map = OpenStruct.new( - summary_map: { "AccountMFAEnabled" => 0 } - ) - @mock_client.expect :get_account_summary, test_summary_map - @mock_client.expect :list_virtual_mfa_devices, test_list_virtual_mfa_devices - - assert_equal false, AwsIamRootUser.new(@mock_conn).has_hardware_mfa_enabled? - end -end diff --git a/test/unit/resources/aws_iam_user_test.rb b/test/unit/resources/aws_iam_user_test.rb deleted file mode 100644 index e31ce1bd0..000000000 --- a/test/unit/resources/aws_iam_user_test.rb +++ /dev/null @@ -1,370 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_user" - -require "resource_support/aws" - -# MAIUB = MockAwsIamUserBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsIamUserConstructorTest < Minitest::Test - - def setup - AwsIamUser::BackendFactory.select(MAIUB::Three) - end - - def test_empty_params_throws_exception - assert_raises(ArgumentError) { AwsIamUser.new } - end - - def test_accepts_username_as_scalar - AwsIamUser.new("erin") - end - - def test_accepts_username_as_hash - AwsIamUser.new(username: "erin") - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsIamUser.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsIamUserRecallTest < Minitest::Test - def setup - AwsIamUser::BackendFactory.select(MAIUB::Three) - end - - def test_search_miss_is_not_an_exception - user = AwsIamUser.new("tommy") - refute user.exists? - end - - def test_search_hit_via_scalar_works - user = AwsIamUser.new("erin") - assert user.exists? - assert_equal("erin", user.username) - end - - def test_search_hit_via_hash_works - user = AwsIamUser.new(username: "erin") - assert user.exists? - assert_equal("erin", user.username) - end -end - -#=============================================================================# -# Properties -#=============================================================================# - -class AwsIamUserPropertiesTest < Minitest::Test - def setup - AwsIamUser::BackendFactory.select(MAIUB::Three) - end - - def test_property_attached_policies - noone = AwsIamUser.new("nonesuch") - assert_empty(noone.attached_policy_names) - assert_empty(noone.attached_policy_arns) - - erin = AwsIamUser.new("erin") - assert_empty(erin.attached_policy_names) - assert_empty(erin.attached_policy_arns) - - leslie = AwsIamUser.new("leslie") - assert_equal(1, leslie.attached_policy_names.count) - assert_includes(leslie.attached_policy_names, "AdministratorAccess") - assert_equal(1, leslie.attached_policy_arns.count) - assert_includes(leslie.attached_policy_arns, "arn:aws:iam::aws:policy/AdministratorAccess") - - jared = AwsIamUser.new("jared") - assert_equal(2, jared.attached_policy_names.count) - assert_includes(jared.attached_policy_names, "ReadOnlyAccess") - assert_equal(2, jared.attached_policy_arns.count) - assert_includes(jared.attached_policy_arns, "arn:aws:iam::aws:policy/ReadOnlyAccess") - end - - def test_property_inline_policies - noone = AwsIamUser.new("nonesuch") - assert_empty(noone.inline_policy_names) - - erin = AwsIamUser.new("erin") - assert_empty(erin.inline_policy_names) - - leslie = AwsIamUser.new("leslie") - assert_equal(2, leslie.inline_policy_names.count) - assert_includes(leslie.inline_policy_names, "leslie-inline-01") - assert_includes(leslie.inline_policy_names, "leslie-inline-02") - - jared = AwsIamUser.new("jared") - assert_equal(1, jared.inline_policy_names.count) - assert_includes(jared.inline_policy_names, "jared-inline-01") - end - - #-----------------------------------------------------# - # username property - #-----------------------------------------------------# - def test_property_username_correct_on_hit - user = AwsIamUser.new("erin") - assert_equal("erin", user.username) - end - - def test_property_username_correct_on_miss - user = AwsIamUser.new("nonesuch") - assert_equal("nonesuch", user.username) - end - - #-----------------------------------------------------# - # access_keys property - #-----------------------------------------------------# - def test_property_access_keys_positive - keys = AwsIamUser.new("erin").access_keys - assert_kind_of(Array, keys) - assert_equal(keys.length, 2) - # We don't currently promise that the results - # will be InSpec resource objects. - # assert_kind_of(AwsIamAccessKey, keys.first) - end - - def test_property_access_keys_negative - keys = AwsIamUser.new("leslie").access_keys - assert_kind_of(Array, keys) - assert(keys.empty?) - end -end - -#=============================================================================# -# Matchers -#=============================================================================# - -class AwsIamUserMatchersTest < Minitest::Test - def setup - AwsIamUser::BackendFactory.select(MAIUB::Three) - end - - def test_matcher_mfa_positive - user = AwsIamUser.new("erin") - assert_equal(true, user.has_mfa_enabled) - assert_equal(true, user.has_mfa_enabled?) - end - - def test_matcher_mfa_negative - user = AwsIamUser.new("leslie") - assert_equal(false, user.has_mfa_enabled) - assert_equal(false, user.has_mfa_enabled?) - end - - def test_matcher_password_positive - user = AwsIamUser.new("erin") - assert_equal(true, user.has_console_password) - assert_equal(true, user.has_console_password?) - end - - def test_matcher_password_negative - user = AwsIamUser.new("leslie") - assert_equal(false, user.has_console_password) - assert_equal(false, user.has_console_password?) - end - - def test_matcher_has_attached_policies - assert_nil(AwsIamUser.new("nonesuch").has_attached_policies?) - refute(AwsIamUser.new("erin").has_attached_policies?) - assert(AwsIamUser.new("leslie").has_attached_policies?) - assert(AwsIamUser.new("jared").has_attached_policies?) - end - - def test_matcher_has_inline_policies - assert_nil(AwsIamUser.new("nonesuch").has_inline_policies?) - refute(AwsIamUser.new("erin").has_inline_policies?) - assert(AwsIamUser.new("leslie").has_inline_policies?) - assert(AwsIamUser.new("jared").has_inline_policies?) - end - -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module MAIUB - class Three < AwsBackendBase - def get_user(criteria) - people = { - "erin" => OpenStruct.new({ - user: OpenStruct.new({ - arn: "arn:aws:iam::123456789012:user/erin", - create_date: Time.parse("2016-09-21T23:03:13Z"), - path: "/", - user_id: "AKIAIOSFODNN7EXAERIN", - user_name: "erin", - }), - }), - "leslie" => OpenStruct.new({ - user: OpenStruct.new({ - arn: "arn:aws:iam::123456789012:user/leslie", - create_date: Time.parse("2017-09-21T23:03:13Z"), - path: "/", - user_id: "AKIAIOSFODNN7EXAERIN", - user_name: "leslie", - }), - }), - "jared" => OpenStruct.new({ - user: OpenStruct.new({ - arn: "arn:aws:iam::123456789012:user/jared", - create_date: Time.parse("2017-09-21T23:03:13Z"), - path: "/", - user_id: "AKIAIOSFODNN7EXAERIN", - user_name: "jared", - }), - }), - } - raise Aws::IAM::Errors::NoSuchEntity.new(nil, nil) unless people.key?(criteria[:user_name]) - - people[criteria[:user_name]] - end - - def get_login_profile(criteria) - # Leslie has no password - # Jared's is expired - people = { - "erin" => OpenStruct.new({ - login_profile: OpenStruct.new({ - user_name: "erin", - password_reset_required: false, - create_date: Time.parse("2016-09-21T23:03:13Z"), - }), - }), - "jared" => OpenStruct.new({ - login_profile: OpenStruct.new({ - user_name: "jared", - password_reset_required: true, - create_date: Time.parse("2017-09-21T23:03:13Z"), - }), - }), - } - raise Aws::IAM::Errors::NoSuchEntity.new(nil, nil) unless people.key?(criteria[:user_name]) - - people[criteria[:user_name]] - end - - def list_mfa_devices(criteria) - # Erin has 2, one soft and one hw - # Leslie has none - # Jared has one soft - people = { - "erin" => OpenStruct.new({ - mfa_devices: [ - OpenStruct.new({ - user_name: "erin", - serial_number: "arn:blahblahblah", - enable_date: Time.parse("2016-09-21T23:03:13Z"), - }), - OpenStruct.new({ - user_name: "erin", - serial_number: "1234567890", - enable_date: Time.parse("2016-09-21T23:03:13Z"), - }), - ], - }), - "leslie" => OpenStruct.new({ mfa_devices: [] }), - "jared" => OpenStruct.new({ - mfa_devices: [ - OpenStruct.new({ - user_name: "jared", - serial_number: "arn:blahblahblah", - enable_date: Time.parse("2016-09-21T23:03:13Z"), - }), - ], - }), - } - people[criteria[:user_name]] - end - - def list_access_keys(criteria) - # Erin has 2 - # Leslie has none - # Jared has one - people = { - "erin" => OpenStruct.new({ - access_key_metadata: [ - OpenStruct.new({ - user_name: "erin", - access_key_id: "AKIA111111111EXAMPLE", - create_date: Time.parse("2016-09-21T23:03:13Z"), - status: "Active", - }), - OpenStruct.new({ - user_name: "erin", - access_key_id: "AKIA222222222EXAMPLE", - create_date: Time.parse("2016-09-21T23:03:13Z"), - status: "Active", - }), - ], - }), - "leslie" => OpenStruct.new({ access_key_metadata: [] }), - "jared" => OpenStruct.new({ - access_key_metadata: [ - OpenStruct.new({ - user_name: "jared", - access_key_id: "AKIA3333333333EXAMPLE", - create_date: Time.parse("2017-10-21T23:03:13Z"), - status: "Active", - }), - ], - }), - } - people[criteria[:user_name]] - end - - def list_user_policies(query) - people = { - "erin" => Aws::IAM::Types::ListUserPoliciesResponse.new( - policy_names: [] - ), - "leslie" => Aws::IAM::Types::ListUserPoliciesResponse.new( - policy_names: %w{leslie-inline-01 leslie-inline-02} - ), - "jared" => Aws::IAM::Types::ListUserPoliciesResponse.new( - policy_names: ["jared-inline-01"] - ), - } - people[query[:user_name]] - end - - def list_attached_user_policies(query) - people = { - "erin" => Aws::IAM::Types::ListAttachedUserPoliciesResponse.new( - attached_policies: [] - ), - "leslie" => Aws::IAM::Types::ListAttachedUserPoliciesResponse.new( - attached_policies: [ - { - policy_arn: "arn:aws:iam::aws:policy/AdministratorAccess", - policy_name: "AdministratorAccess", - }, - ] - ), - "jared" => Aws::IAM::Types::ListAttachedUserPoliciesResponse.new( - attached_policies: [ - { - policy_arn: "arn:aws:iam::aws:policy/ReadOnlyAccess", - policy_name: "ReadOnlyAccess", - }, - { - policy_arn: "arn:aws:iam::123456789012:policy/some-policy", - policy_name: "some-policy", - }, - ] - ), - } - people[query[:user_name]] - end - - end -end diff --git a/test/unit/resources/aws_iam_users_test.rb b/test/unit/resources/aws_iam_users_test.rb deleted file mode 100644 index fc810755c..000000000 --- a/test/unit/resources/aws_iam_users_test.rb +++ /dev/null @@ -1,276 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_iam_users" - -require "resource_support/aws" - -# Maiusb = Mock AwsIamUsers::BackendFactory -# Abbreviation not used outside of this file - -class AwsIamUsersTestConstructor < Minitest::Test - def setup - AwsIamUsers::BackendFactory.select(Maiusb::Empty) - end - - def test_users_no_params_does_not_explode - AwsIamUsers.new - end - - def test_users_all_params_rejected - assert_raises(ArgumentError) { AwsIamUsers.new(something: "somevalue") } - end -end - -class AwsIamUsersTestFilterCriteria < Minitest::Test - def setup - # Reset to empty, that's harmless - AwsIamUsers::BackendFactory.select(Maiusb::Empty) - end - - #------------------------------------------# - # Open Filter - #------------------------------------------# - def test_users_empty_result_when_no_users_no_criteria - users = AwsIamUsers.new.where {} - assert users.entries.empty? - end - - def test_users_all_returned_when_some_users_no_criteria - AwsIamUsers::BackendFactory.select(Maiusb::Basic) - users = AwsIamUsers.new.where {} - assert(3, users.entries.count) - end - - #------------------------------------------# - # has_mfa_enabled? - #------------------------------------------# - def test_users_criteria_has_mfa_enabled - AwsIamUsers::BackendFactory.select(Maiusb::Basic) - users = AwsIamUsers.new.where { has_mfa_enabled } - assert(1, users.entries.count) - assert_includes users.usernames, "carol" - refute_includes users.usernames, "alice" - end - - #------------------------------------------# - # has_console_password? - #------------------------------------------# - def test_users_criteria_has_console_password? - AwsIamUsers::BackendFactory.select(Maiusb::Basic) - users = AwsIamUsers.new.where { has_console_password } - assert(2, users.entries.count) - assert_includes users.usernames, "carol" - refute_includes users.usernames, "alice" - end - - #------------------------------------------# - # password_ever_used? - #------------------------------------------# - def test_users_criteria_password_ever_used? - AwsIamUsers::BackendFactory.select(Maiusb::Basic) - users = AwsIamUsers.new.where { password_ever_used? } - assert(2, users.entries.count) - assert_includes users.usernames, "carol" - refute_includes users.usernames, "alice" - end - - #------------------------------------------# - # password_never_used? - #------------------------------------------# - def test_users_criteria_password_never_used? - AwsIamUsers::BackendFactory.select(Maiusb::Basic) - users = AwsIamUsers.new.where { password_never_used? } - assert(1, users.entries.count) - assert_includes users.usernames, "alice" - refute_includes users.usernames, "carol" - end - - #------------------------------------------# - # password_last_used_days_ago - #------------------------------------------# - def test_users_criteria_has_password_last_used_days_ago_10 - AwsIamUsers::BackendFactory.select(Maiusb::Basic) - users = AwsIamUsers.new.where(password_last_used_days_ago: 10) - assert(1, users.entries.count) - assert_includes users.usernames, "bob" - refute_includes users.usernames, "alice" - end - - #------------------------------------------# - # has_inline_policies - #------------------------------------------# - def test_users_have_inline_policies - AwsIamUsers::BackendFactory.select(Maiusb::Basic) - users = AwsIamUsers.new.where(has_inline_policies?: true) - assert_equal(2, users.entries.count) - assert_includes users.usernames, "bob" - assert_includes users.usernames, "carol" - refute_includes users.usernames, "alice" - - users.inline_policy_names.each do |name| - assert_kind_of(String, name) - end - assert_includes users.inline_policy_names, "bob-inline-01" - assert_includes users.inline_policy_names, "bob-inline-02" - assert_includes users.inline_policy_names, "carol-inline-01" - assert_equal(3, users.inline_policy_names.count) - end - - #------------------------------------------# - # has_attached_policies - #------------------------------------------# - def test_users_have_attached_policies - AwsIamUsers::BackendFactory.select(Maiusb::Basic) - users = AwsIamUsers.new.where(has_attached_policies: true) - assert_equal(2, users.entries.count) - assert_includes users.usernames, "bob" - assert_includes users.usernames, "carol" - refute_includes users.usernames, "alice" - - users.attached_policy_names.each do |name| - assert_kind_of(String, name) - end - assert_includes users.attached_policy_names, "AdministratorAccess" - assert_includes users.attached_policy_names, "ReadOnlyAccess" - assert_equal(2, users.attached_policy_names.count) - - users.attached_policy_arns.each do |arn| - assert_kind_of(String, arn) - end - assert_includes users.attached_policy_arns, "arn:aws:iam::aws:policy/ReadOnlyAccess" - assert_equal(3, users.attached_policy_arns.count) - end -end - -#=============================================================================# -# Test Fixture Classes -#=============================================================================# -module Maiusb - - # -------------------------------- - # Empty - No users - # -------------------------------- - class Empty < AwsBackendBase - def list_users(criteria = {}) - OpenStruct.new({ - users: [], - }) - end - - def get_login_profile(criteria) - raise Aws::IAM::Errors::NoSuchEntity.new("No login profile for #{criteria[:user_name]}", "Nope") - end - - def list_mfa_devices(_criteria) - OpenStruct.new({ - mfa_devices: [], - }) - end - end - - # -------------------------------- - # Basic - 3 Users - # -------------------------------- - # Alice has no password or MFA device - # Bob has a password but no MFA device - # Carol has a password and MFA device - class Basic < AwsBackendBase - # arn, path, user_id omitted - def list_users(criteria = {}) - OpenStruct.new({ - users: [ - OpenStruct.new({ - user_name: "alice", - create_date: DateTime.parse("2017-10-10T16:19:30Z"), - # Password last used is absent, never logged in w/ password - }), - OpenStruct.new({ - user_name: "bob", - create_date: DateTime.parse("2017-11-06T16:19:30Z"), - password_last_used: Time.now - 10 * 24 * 60 * 60, - }), - OpenStruct.new({ - user_name: "carol", - create_date: DateTime.parse("2017-10-10T16:19:30Z"), - password_last_used: Time.now - 91 * 24 * 60 * 60, - }), - ], - }) - end - - def get_login_profile(criteria) - if %w{bob carol}.include?(criteria[:user_name]) - OpenStruct.new({ - login_profile: OpenStruct.new({ - user_name: criteria[:user_name], - created_date: DateTime.parse("2017-10-10T16:19:30Z"), - }), - }) - else - raise Aws::IAM::Errors::NoSuchEntity.new("No login profile for #{criteria[:user_name]}", "Nope") - end - end - - def list_mfa_devices(criteria) - if ["carol"].include?(criteria[:user_name]) - OpenStruct.new({ - mfa_devices: [ - OpenStruct.new({ - user_name: criteria[:user_name], - serial_number: "1234567890", - enable_date: DateTime.parse("2017-10-10T16:19:30Z"), - }), - ], - }) - else - OpenStruct.new({ - mfa_devices: [], - }) - end - end - - def list_user_policies(query) - people = { - "alice" => Aws::IAM::Types::ListUserPoliciesResponse.new( - policy_names: [] - ), - "bob" => Aws::IAM::Types::ListUserPoliciesResponse.new( - policy_names: %w{bob-inline-01 bob-inline-02} - ), - "carol" => Aws::IAM::Types::ListUserPoliciesResponse.new( - policy_names: ["carol-inline-01"] - ), - } - people[query[:user_name]] - end - - def list_attached_user_policies(query) - people = { - "alice" => Aws::IAM::Types::ListAttachedUserPoliciesResponse.new( - attached_policies: [] - ), - "bob" => Aws::IAM::Types::ListAttachedUserPoliciesResponse.new( - attached_policies: [ - { - policy_arn: "arn:aws:iam::aws:policy/AdministratorAccess", - policy_name: "AdministratorAccess", - }, - ] - ), - "carol" => Aws::IAM::Types::ListAttachedUserPoliciesResponse.new( - attached_policies: [ - { - policy_arn: "arn:aws:iam::aws:policy/ReadOnlyAccess", - policy_name: "ReadOnlyAccess", - }, - { - policy_arn: "arn:aws:iam::123456789012:policy/some-policy", - policy_name: "AdministratorAccess", - }, - ] - ), - } - people[query[:user_name]] - end - end -end diff --git a/test/unit/resources/aws_kms_key_test.rb b/test/unit/resources/aws_kms_key_test.rb deleted file mode 100644 index 131589f1d..000000000 --- a/test/unit/resources/aws_kms_key_test.rb +++ /dev/null @@ -1,232 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_kms_key" - -require "resource_support/aws" - -# MAKKSB = MockAwsKmsKeyBackend -# Abbreviation not used outside this file - -TIME_NOW = Time.now -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsKmsKeyConstructorTest < Minitest::Test - - def setup - AwsKmsKey::BackendFactory.select(MAKKSB::Empty) - end - - def test_rejects_empty_params - assert_raises(ArgumentError) { AwsKmsKey.new } - end - - def test_accepts_key_arn_as_scalar - AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111") - end - - def test_accepts_key_arn_as_hash - AwsKmsKey.new(key_id: "arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111") - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsKmsKey.new(invalid: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsKmsKeyRecallTest < Minitest::Test - - def setup - AwsKmsKey::BackendFactory.select(MAKKSB::Basic) - end - - def test_search_hit_via_scalar_works - assert AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").exists? - end - - def test_search_hit_via_hash_works - assert AwsKmsKey.new(key_id: "arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsKmsKey.new(key_id: "non-existent").exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsKmsKeyPropertiesTest < Minitest::Test - - def setup - AwsKmsKey::BackendFactory.select(MAKKSB::Basic) - end - - def test_property_key_id - assert_equal("7a6950aa-c8e6-4e51-8afc-111111111111", AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").key_id) - end - - def test_property_arn - assert_equal("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111", AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").arn) - assert_nil(AwsKmsKey.new(key_id: "non-existent").arn) - end - - def test_property_creation_date - assert_equal(TIME_NOW - 10 * 24 * 3600, AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").creation_date) - assert_nil(AwsKmsKey.new(key_id: "non-existent").creation_date) - end - - def test_property_key_usage - assert_equal("ENCRYPT_DECRYPT", AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").key_usage) - assert_nil(AwsKmsKey.new(key_id: "non-existent").key_usage) - end - - def test_property_key_state - assert_equal("Enabled", AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").key_state) - assert_nil(AwsKmsKey.new(key_id: "non-existent").key_state) - end - - def test_property_description - assert_equal("test-key-1-desc", AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").description) - assert_nil(AwsKmsKey.new(key_id: "non-existent").description) - end - - def test_property_deletion_time - assert_equal(TIME_NOW + 10 * 24 * 3600, AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").deletion_time) - assert_nil(AwsKmsKey.new(key_id: "non-existent").deletion_time) - end - - def test_property_invalidation_time - assert_nil(AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").invalidation_time) - assert_nil(AwsKmsKey.new(key_id: "non-existent").invalidation_time) - end - - def test_property_created_days_ago - assert_equal(10, AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").created_days_ago) - assert_nil(AwsKmsKey.new(key_id: "non-existent").created_days_ago) - end -end - -#=============================================================================# -# Matchers -#=============================================================================# -class AwsKmsKeyMatchersTest < Minitest::Test - - def setup - AwsKmsKey::BackendFactory.select(MAKKSB::Basic) - end - - def test_matcher_enabled_positive - assert AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").enabled? - end - - def test_matcher_enabled_negative - refute AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-222222222222").enabled? - end - - def test_matcher_rotation_enabled_positive - assert AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").has_rotation_enabled? - end - - def test_matcher_rotation_enabled_negative - refute AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-222222222222").has_rotation_enabled? - end - - def test_matcher_external_positive - assert AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-222222222222").external? - end - - def test_matcher_external_negative - refute AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").external? - end - - def test_matcher_has_key_expiration_positive - assert AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").has_key_expiration? - end - - def test_matcher_has_key_expiration_negative - refute AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-222222222222").has_key_expiration? - end - - def test_matcher_has_aws_key_manager_positive - assert AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111").managed_by_aws? - end - - def test_matcher_has_aws_key_manager_negative - refute AwsKmsKey.new("arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-222222222222").managed_by_aws? - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAKKSB - class Empty < AwsBackendBase - def describe_key(query) - raise Aws::KMS::Errors::NotFoundException.new(nil, nil) - end - end - - class Basic < AwsBackendBase - def describe_key(query) - fixtures = [ - OpenStruct.new({ - key_id: "7a6950aa-c8e6-4e51-8afc-111111111111", - arn: "arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111", - creation_date: TIME_NOW - 10 * 24 * 3600, - enabled: true, - description: "test-key-1-desc", - key_usage: "ENCRYPT_DECRYPT", - key_state: "Enabled", - deletion_date: TIME_NOW + 10 * 24 * 3600, - valid_to: nil, - origin: "AWS_KMS", - expiration_model: "KEY_MATERIAL_EXPIRES", - key_manager: "AWS", - }), - OpenStruct.new({ - key_id: "7a6950aa-c8e6-4e51-8afc-222222222222", - arn: "arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-222222222222", - creation_date: TIME_NOW, - enabled: false, - description: "test-key-2-desc", - key_usage: "", - key_state: "PendingDeletion", - deletion_date: nil, - valid_to: nil, - origin: "EXTERNAL", - expiration_model: "KEY_MATERIAL_DOES_NOT_EXPIRE", - key_manager: "CUSTOMER", - }), - ] - selected = fixtures.detect do |fixture| - fixture.arn == query[:key_id] - end - return OpenStruct.new({ key_metadata: selected }) unless selected.nil? - - raise Aws::KMS::Errors::NotFoundException.new(nil, nil) - end - - def get_key_rotation_status(query) - fixtures = [ - OpenStruct.new({ - arn: "arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-111111111111", - key_rotation_enabled: true, - }), - OpenStruct.new({ - arn: "arn:aws:kms:us-east-1::key/7a6950aa-c8e6-4e51-8afc-222222222222", - key_rotation_enabled: false, - }), - ] - selected = fixtures.detect do |fixture| - fixture.arn == query[:key_id] - end - return selected unless selected.nil? - - raise Aws::KMS::Errors::NotFoundException.new(nil, nil) - end - end -end diff --git a/test/unit/resources/aws_kms_keys_test.rb b/test/unit/resources/aws_kms_keys_test.rb deleted file mode 100644 index 87e310b1c..000000000 --- a/test/unit/resources/aws_kms_keys_test.rb +++ /dev/null @@ -1,106 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_kms_keys" - -require "resource_support/aws" - -# MAKKPB = MockAwsKmsKeysPluralBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsKmsKeysConstructorTest < Minitest::Test - - def setup - AwsKmsKeys::BackendFactory.select(MAKKPB::Empty) - end - - def test_empty_params_ok - AwsKmsKeys.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsKmsKeys.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsKmsKeysRecallEmptyTest < Minitest::Test - - def setup - AwsKmsKeys::BackendFactory.select(MAKKPB::Empty) - end - - def test_search_miss_key_empty_kms_key_list - refute AwsKmsKeys.new.exists? - end -end - -class AwsKmsKeysRecallBasicTest < Minitest::Test - - def setup - AwsKmsKeys::BackendFactory.select(MAKKPB::Basic) - end - - def test_search_hit_via_empty_filter - assert AwsKmsKeys.new.exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsKmsKeysProperties < Minitest::Test - def setup - AwsKmsKeys::BackendFactory.select(MAKKPB::Basic) - end - - def test_property_key_ids - basic = AwsKmsKeys.new - assert_kind_of(Array, basic.key_ids) - assert(basic.key_ids.include?("012026a4-b657-42bf-99ae-111111111111")) - refute(basic.key_ids.include?(nil)) - end - - def test_property_key_arns - basic = AwsKmsKeys.new - assert_kind_of(Array, basic.key_arns) - assert(basic.key_arns.include?("arn:aws:kms:us-east-1::key/012026a4-b657-42bf-99ae-111111111111")) - refute(basic.key_arns.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAKKPB - class Empty < AwsBackendBase - def list_keys(query = {}) - OpenStruct.new({ keys: [] }) - end - end - - class Basic < AwsBackendBase - def list_keys(query = {}) - fixtures = [ - OpenStruct.new({ - key_id: "012026a4-b657-42bf-99ae-111111111111", - key_arn: "arn:aws:kms:us-east-1::key/012026a4-b657-42bf-99ae-111111111111", - }), - OpenStruct.new({ - key_id: "012026a4-b657-42bf-99ae-222222222222", - key_arn: "arn:aws:kms:us-east-1::key/012026a4-b657-42bf-99ae-222222222222", - }), - OpenStruct.new({ - key_id: "012026a4-b657-42bf-99ae-333333333333", - key_arn: "arn:aws:kms:us-east-1::key/012026a4-b657-42bf-99ae-333333333333", - }), - ] - - OpenStruct.new({ keys: fixtures }) - end - end -end diff --git a/test/unit/resources/aws_rds_instance_test.rb b/test/unit/resources/aws_rds_instance_test.rb deleted file mode 100644 index a10ba81a8..000000000 --- a/test/unit/resources/aws_rds_instance_test.rb +++ /dev/null @@ -1,100 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_rds_instance" - -require "resource_support/aws" - -# MRDSIB = MockRDSInstanceBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsMDBIConstructor < Minitest::Test - def setup - AwsRdsInstance::BackendFactory.select(AwsMRDSIB::Empty) - end - - def test_constructor_no_args_raises - assert_raises(ArgumentError) { AwsRdsInstance.new } - end - - def test_constructor_accept_scalar_param - AwsRdsInstance.new("test-instance-id") - end - - def test_accepts_db_instance_identifier_as_hash - AwsRdsInstance.new(db_instance_identifier: "test-instance-id") - end - - def test_constructor_reject_malformed_args - { - db_instance_identifier: "no_good", - }.each do |param, value| - assert_raises(ArgumentError) { AwsRdsInstance.new(param => value) } - end - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsRdsInstance.new(beep: "boop") } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# - -class AwsMDBIRecallTest < Minitest::Test - - def setup - AwsRdsInstance::BackendFactory.select(AwsMRDSIB::Basic) - end - - def test_search_hit_via_scalar_works - assert AwsRdsInstance.new("some-db").exists? - end - - def test_search_hit_via_hash_works - assert AwsRdsInstance.new(db_instance_identifier: "some-db").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsRdsInstance.new(db_instance_identifier: "test-instance-id").exists? - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMRDSIB - class Empty < AwsBackendBase - def describe_db_instances(_query) - raise Aws::RDS::Errors::DBInstanceNotFound.new(nil, nil) - end - end - - class Basic < AwsBackendBase - def describe_db_instances(query) - fixtures = [ - OpenStruct.new({ - db_instance_identifier: "some-db", - }), - OpenStruct.new({ - db_instance_identifier: "awesome-db", - }), - ] - - selected = fixtures.select do |db| - db[:db_instance_identifier].eql? query[:db_instance_identifier] - end - - if selected.empty? - raise Aws::RDS::Errors::DBInstanceNotFound.new(nil, nil) - end - - OpenStruct.new({ db_instances: selected }) - end - end - -end diff --git a/test/unit/resources/aws_route_table_test.rb b/test/unit/resources/aws_route_table_test.rb deleted file mode 100644 index ce917374c..000000000 --- a/test/unit/resources/aws_route_table_test.rb +++ /dev/null @@ -1,84 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_route_table" - -require "resource_support/aws" - -class EmptyAwsRouteTableTest < Minitest::Test - def setup - AwsRouteTable::BackendFactory.select(AwsMRtbB::Empty) - end - - def test_search_hit_via_scalar_works_symbol - refute AwsRouteTable.new(route_table_id: "rtb-123abcde").exists? - end - - def test_search_hit_via_scalar_works_string - refute AwsRouteTable.new("rtb-123abcde").exists? - end -end - -class BasicAwsRouteTableTest2 < Minitest::Test - def setup - AwsRouteTable::BackendFactory.select(AwsMRtbB::Basic) - end - - def test_search_hit - assert AwsRouteTable.new("rtb-05462d2278326a79c").exists? - assert AwsRouteTable.new("rtb-58508630").exists? - - # not hexadecimal - assert_raises(ArgumentError) do - AwsRouteTable.new("rtb-xyzxyzxy") - end - - # not within length constraint - assert_raises(ArgumentError) do - AwsRouteTable.new("rtb-abcdef012") - end - end -end - -# MRtbB = Mock Routetable Backend -module AwsMRtbB - class Empty < AwsBackendBase - def describe_route_tables(query) - OpenStruct.new(route_tables: []) - end - end - - class Basic < AwsBackendBase - def describe_route_tables(query) - fixtures = [ - OpenStruct.new({ associations: [], - propagating_vgws: [], - route_table_id: "rtb-05462d2278326a79c", - routes: [ - { destination_cidr_block: "172.32.1.0/24", gateway_id: "igw-4fb9e626", origin: "CreateRoute", state: "active" }, - { destination_cidr_block: "172.31.0.0/16", gateway_id: "local", origin: "CreateRouteTable", state: "active" }, - ], - tags: [{ key: "Name", value: "InSpec" }], - vpc_id: "vpc-169f777e", - }), - OpenStruct.new({ associations: [], - propagating_vgws: [], - route_table_id: "rtb-58508630", - routes: [ - { destination_cidr_block: "172.33.0.0/16", gateway_id: "local", origin: "CreateRouteTable", state: "active" }, - { destination_cidr_block: "0.0.0.0/0", gateway_id: "igw-4fb9e626", origin: "CreateRoute", state: "active" }, - ], - tags: [{ key: "Name", value: "InSpec" }], - vpc_id: "vpc-169f777e", - }), - ] - - selected = fixtures.select do |rtb| - query[:filters].all? do |filter| - filter[:values].include?(rtb[filter[:name].tr("-", "_")]) - end - end - - OpenStruct.new({ route_tables: selected }) - end - end -end diff --git a/test/unit/resources/aws_route_tables_test.rb b/test/unit/resources/aws_route_tables_test.rb deleted file mode 100644 index b7f50fab3..000000000 --- a/test/unit/resources/aws_route_tables_test.rb +++ /dev/null @@ -1,74 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_route_tables" - -require "resource_support/aws" - -class EmptyAwsRouteTablesTest < Minitest::Test - def setup - AwsRouteTables::BackendFactory.select(AwsMRtbsB::Empty) - end - - def test_constructor_no_args_ok - AwsRouteTables.new - end - - def test_search_miss - refute AwsRouteTables.new.exists? - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsRouteTables.new(bla: "blabla") } - end -end - -class BasicAwsRouteTablesTest2 < Minitest::Test - def setup - AwsRouteTables::BackendFactory.select(AwsMRtbsB::Basic) - end - - def test_search_hit - assert AwsRouteTables.new.exists? - end - - def test_property_vpc_ids - basic = AwsRouteTables.new - assert_kind_of(Array, basic.vpc_ids) - assert(basic.vpc_ids.include?("vpc-169f777e")) - assert(basic.vpc_ids.include?("vpc-169f777d")) - refute(basic.vpc_ids.include?(nil)) - end - - def test_property_route_table_ids - basic = AwsRouteTables.new - assert_kind_of(Array, basic.route_table_ids) - assert(basic.route_table_ids.include?("rtb-05462d2278326a79c")) - assert(basic.route_table_ids.include?("rtb-58508630")) - refute(basic.route_table_ids.include?(nil)) - end -end - -# MRtbB = Mock Routetable Backend -module AwsMRtbsB - class Empty < AwsBackendBase - def describe_route_tables(query) - OpenStruct.new(route_tables: []) - end - end - - class Basic < AwsBackendBase - def describe_route_tables(query) - fixtures = [ - OpenStruct.new({ - route_table_id: "rtb-05462d2278326a79c", - vpc_id: "vpc-169f777e", - }), - OpenStruct.new({ - route_table_id: "rtb-58508630", - vpc_id: "vpc-169f777d", - }), - ] - OpenStruct.new({ route_tables: fixtures }) - end - end -end diff --git a/test/unit/resources/aws_s3_bucket_object_test.rb b/test/unit/resources/aws_s3_bucket_object_test.rb deleted file mode 100644 index 188aece16..000000000 --- a/test/unit/resources/aws_s3_bucket_object_test.rb +++ /dev/null @@ -1,197 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_s3_bucket_object" - -require "resource_support/aws" - -# MSBOSB = MockS3BucketObjectSingleBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsS3BucketObjectConstructor < Minitest::Test - def setup - AwsS3BucketObject::BackendFactory.select(AwsMSBOSB::Basic) - end - - def test_constructor_no_args_raises - assert_raises(ArgumentError) { AwsS3BucketObject.new } - end - - def test_constructor_no_bucket_name_arg_raises - assert_raises(ArgumentError) { AwsS3BucketObject.new(:key, "key") } - end - - def test_constructor_no_key_arg_raises - assert_raises(ArgumentError) { AwsS3BucketObject.new(:bucket_name, "bucket") } - end - - def test_constructor_expected_well_formed_args - AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "public_file.jpg") - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsS3BucketObject.new(bla: "NonExistingBucket") } - end - - def test_constructor_reject_bucket_not_given - assert_raises(ArgumentError) { AwsS3BucketObject.new(key: "public_file.jpg") } - end - - def test_constructor_reject_key_not_given - assert_raises(ArgumentError) { AwsS3BucketObject.new(bucket_name: "Public Bucket") } - end -end - -#=============================================================================# -# Recall -#=============================================================================# - -class AwsS3BucketObjectRecallTest < Minitest::Test - def setup - AwsS3BucketObject::BackendFactory.select(AwsMSBOSB::Basic) - end - - def test_searching - assert(AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "public_file.jpg").exists?) - refute(AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "NonExistingObject").exists?) - refute(AwsS3BucketObject.new(bucket_name: "NonExistingBucket", key: "public_file.jpg").exists?) - end -end - -#=============================================================================# -# Properties -#=============================================================================# - -class AwsS3BucketTestProperties < Minitest::Test - def setup - AwsS3BucketObject::BackendFactory.select(AwsMSBOSB::Basic) - end - - #---------------------Bucket Name----------------------------# - def test_property_bucket_name - assert_equal("Public Bucket", AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "public_file.jpg").bucket_name) - end - - #--------------------- Key ----------------------------# - def test_property_key - assert_equal("public_file.jpg", AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "public_file.jpg").key) - end - - #---------------------- object_acl -------------------------------# - def test_property_object_acl_structure - object_acl = AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "public_file.jpg").object_acl - - assert_kind_of(Array, object_acl) - assert(object_acl.size > 0) - assert(object_acl.all? { |g| g.respond_to?(:permission) }) - assert(object_acl.all? { |g| g.respond_to?(:grantee) }) - assert(object_acl.all? { |g| g.grantee.respond_to?(:type) }) - end - - def test_property_object_acl_public - bucket_acl = AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "public_file.jpg").object_acl - - public_grants = bucket_acl.select do |g| - g.grantee.type == "Group" && g.grantee.uri =~ /AllUsers/ - end - refute_empty(public_grants) - end - - def test_property_object_acl_private - bucket_acl = AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "private_file.jpg").object_acl - - public_grants = bucket_acl.select do |g| - g.grantee.type == "Group" && g.grantee.uri =~ /AllUsers/ - end - assert_empty(public_grants) - - auth_users_grants = bucket_acl.select do |g| - g.grantee.type == "Group" && g.grantee.uri =~ /AuthenticatedUsers/ - end - assert_empty(auth_users_grants) - end -end - -#=============================================================================# -# Matchers -#=============================================================================# - -class AwsS3BucketMatchersTest < Minitest::Test - def setup - AwsS3BucketObject::BackendFactory.select(AwsMSBOSB::Basic) - end - - def test_matcher_public - assert_equal(true, AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "public_file.jpg").public?) - assert_equal(false, AwsS3BucketObject.new(bucket_name: "Public Bucket", key: "private_file.jpg").public?) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMSBOSB - class Basic < AwsBackendBase - def get_object_acl(query) - buckets = { - "Public Bucket" => OpenStruct.new({ - "public_file.jpg" => OpenStruct.new({ - grants: [ - OpenStruct.new({ - "grantee" => OpenStruct.new({ - type: "CanonicalUser", - }), - permission: "FULL_CONTROL", - }), - OpenStruct.new({ - "grantee" => OpenStruct.new({ - type: "AmazonCustomerByEmail", - }), - permission: "READ", - }), - OpenStruct.new({ - "grantee" => OpenStruct.new({ - type: "Group", - uri: "http://acs.amazonaws.com/groups/global/AllUsers", - }), - permission: "READ", - }), - ], - }), - "private_file.jpg" => OpenStruct.new({ - grants: [ - OpenStruct.new({ - "grantee" => OpenStruct.new({ - type: "CanonicalUser", - }), - permission: "FULL_CONTROL", - }), - ], - }), - }), - } - buckets[query[:bucket]][query[:key]] - end - - def get_object(query) - buckets = { - "Public Bucket" => OpenStruct.new({ - "public_file.jpg" => OpenStruct.new({ - }), - "private_file.jpg" => OpenStruct.new({ - }), - }), - } - bucket = buckets[query[:bucket]] - raise Aws::S3::Errors::NoSuchBucket.new(Seahorse::Client::Http::Request, "Bucket does not exist") if bucket.nil? - - object = bucket[query[:key]] - raise Aws::S3::Errors::NoSuchKey.new(Seahorse::Client::Http::Request, "Key does not exist") if object.nil? - - object - end - end -end diff --git a/test/unit/resources/aws_s3_bucket_test.rb b/test/unit/resources/aws_s3_bucket_test.rb deleted file mode 100644 index 8c13c58ef..000000000 --- a/test/unit/resources/aws_s3_bucket_test.rb +++ /dev/null @@ -1,307 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_s3_bucket" - -require "resource_support/aws" - -# MSBSB = MockS3BucketSingleBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsS3BucketConstructor < Minitest::Test - def setup - AwsS3Bucket::BackendFactory.select(AwsMSBSB::Basic) - end - - def test_constructor_no_args_raises - assert_raises(ArgumentError) { AwsS3Bucket.new } - end - - def test_constructor_accept_scalar_param - AwsS3Bucket.new("some-bucket") - end - - def test_constructor_accept_hash - AwsS3Bucket.new(bucket_name: "some-bucket") - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsS3Bucket.new(bla: "blabla") } - end -end - -class AwsS3BucketPropertiesTest < Minitest::Test - def setup - AwsS3Bucket::BackendFactory.select(AwsMSBSB::Basic) - end - - #===========================================================================# - # Search / Recall - #===========================================================================# - def test_recall_no_match_is_no_exception - refute AwsS3Bucket.new("NonExistentBucket").exists? - end - - def test_recall_match_single_result_works - assert AwsS3Bucket.new("public").exists? - end - - # No need to handle multiple hits; S3 bucket names are globally unique. - - #===========================================================================# - # Properties - #===========================================================================# - #---------------------Bucket Name----------------------------# - def test_property_bucket_name - assert_equal("public", AwsS3Bucket.new("public").bucket_name) - end - - #--------------------- Region ----------------------------# - def test_property_region - assert_equal("us-east-2", AwsS3Bucket.new("public").region) - assert_equal("EU", AwsS3Bucket.new("private").region) - end - - #---------------------- bucket_acl -------------------------------# - def test_property_bucket_acl_structure - bucket_acl = AwsS3Bucket.new("public").bucket_acl - - assert_kind_of(Array, bucket_acl) - assert(bucket_acl.size > 0) - assert(bucket_acl.all? { |g| g.respond_to?(:permission) }) - assert(bucket_acl.all? { |g| g.respond_to?(:grantee) }) - assert(bucket_acl.all? { |g| g.grantee.respond_to?(:type) }) - end - - def test_property_bucket_acl_public - bucket_acl = AwsS3Bucket.new("public").bucket_acl - - public_grants = bucket_acl.select do |g| - g.grantee.type == "Group" && g.grantee.uri =~ /AllUsers/ - end - refute_empty(public_grants) - end - - def test_property_bucket_acl_private - bucket_acl = AwsS3Bucket.new("private").bucket_acl - - public_grants = bucket_acl.select do |g| - g.grantee.type == "Group" && g.grantee.uri =~ /AllUsers/ - end - assert_empty(public_grants) - - auth_users_grants = bucket_acl.select do |g| - g.grantee.type == "Group" && g.grantee.uri =~ /AuthenticatedUsers/ - end - assert_empty(auth_users_grants) - end - - def test_property_bucket_acl_auth_users - bucket_acl = AwsS3Bucket.new("auth-users").bucket_acl - - public_grants = bucket_acl.select do |g| - g.grantee.type == "Group" && g.grantee.uri =~ /AllUsers/ - end - assert_empty(public_grants) - - auth_users_grants = bucket_acl.select do |g| - g.grantee.type == "Group" && g.grantee.uri =~ /AuthenticatedUsers/ - end - refute_empty(auth_users_grants) - end - - #---------------------- bucket_policy -------------------------------# - def test_property_bucket_policy_structure - bucket_policy = AwsS3Bucket.new("public").bucket_policy - assert_kind_of(Array, bucket_policy) - assert_kind_of(OpenStruct, bucket_policy.first) - %i{effect principal action resource}.each do |field| - assert_respond_to(bucket_policy.first, field) - end - end - - def test_property_bucket_policy_public - bucket_policy = AwsS3Bucket.new("public").bucket_policy - allow_all = bucket_policy.select { |s| s.effect == "Allow" && s.principal == "*" } - assert_equal(1, allow_all.count) - end - - def test_property_bucket_policy_private - bucket_policy = AwsS3Bucket.new("private").bucket_policy - allow_all = bucket_policy.select { |s| s.effect == "Allow" && s.principal == "*" } - assert_equal(0, allow_all.count) - end - - def test_property_bucket_policy_auth - bucket_policy = AwsS3Bucket.new("auth").bucket_policy - assert_empty(bucket_policy) - end - - #===========================================================================# - # Test Matchers - #===========================================================================# - def test_be_public_public_acl - assert(AwsS3Bucket.new("public").public?) - end - - def test_be_public_auth_acl - assert(AwsS3Bucket.new("auth-users").public?) - end - - def test_be_public_private_acl - refute(AwsS3Bucket.new("private").public?) - end - - def test_has_access_logging_enabled_positive - assert(AwsS3Bucket.new("public").has_access_logging_enabled?) - end - - def test_has_access_logging_enabled_negative - refute(AwsS3Bucket.new("private").has_access_logging_enabled?) - end - - def test_has_default_encryption_enabled_positive - assert(AwsS3Bucket.new("public").has_default_encryption_enabled?) - end - - def test_has_default_encryption_enabled_negative - refute(AwsS3Bucket.new("private").has_default_encryption_enabled?) - end - -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMSBSB - class Basic < AwsBackendBase - def get_bucket_acl(query) - owner_full_control = OpenStruct.new( - grantee: OpenStruct.new( - type: "CanonicalUser" - ), - permission: "FULL_CONTROL" - ) - - buckets = { - "public" => OpenStruct.new( - grants: [ - owner_full_control, - OpenStruct.new( - grantee: OpenStruct.new( - type: "Group", - uri: "http://acs.amazonaws.com/groups/global/AllUsers" - ), - permission: "READ" - ), - ] - ), - "auth-users" => OpenStruct.new( - grants: [ - owner_full_control, - OpenStruct.new( - grantee: OpenStruct.new( - type: "Group", - uri: "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" - ), - permission: "READ" - ), - ] - ), - "private" => OpenStruct.new(grants: [ owner_full_control ]), - "private-acl-public-policy" => OpenStruct.new(grants: [ owner_full_control ]), - } - buckets[query[:bucket]] - end - - def get_bucket_location(query) - buckets = { - "public" => OpenStruct.new(location_constraint: "us-east-2"), - "private" => OpenStruct.new(location_constraint: "EU"), - "auth-users" => OpenStruct.new(location_constraint: "ap-southeast-1"), - "private-acl-public-policy" => OpenStruct.new(location_constraint: "ap-southeast-2"), - } - - buckets.fetch(query[:bucket]) { raise Aws::S3::Errors::NoSuchBucket.new(nil, nil) } - end - - def get_bucket_policy(query) - buckets = { - "public" => OpenStruct.new( - policy: StringIO.new(<<~'EOP') - { - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "AllowGetObject", - "Effect": "Allow", - "Principal": "*", - "Action": "s3:GetObject", - "Resource": "arn:aws:s3:::public/*" - } - ] - } - EOP - ), - "private" => OpenStruct.new( - policy: StringIO.new(<<~'EOP') - { - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "DenyGetObject", - "Effect": "Deny", - "Principal": "*", - "Action": "s3:GetObject", - "Resource": "arn:aws:s3:::private/*" - } - ] - } - EOP - ), - "private-acl-public-policy" => OpenStruct.new( - policy: StringIO.new(<<~'EOP') - { - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "AllowGetObject", - "Effect": "Allow", - "Principal": "*", - "Action": "s3:GetObject", - "Resource": "arn:aws:s3:::private-acl-public-policy/*" - } - ] - } - EOP - ), - # No policies for auth bucket - } - - buckets.fetch(query[:bucket]) { raise Aws::S3::Errors::NoSuchBucketPolicy.new(nil, nil) } - end - - def get_bucket_logging(query) - buckets = { - "public" => OpenStruct.new(logging_enabled: OpenStruct.new(target_bucket: "log-bucket")), - "private" => OpenStruct.new(logging_enabled: nil ), - } - - buckets.fetch(query[:bucket]) { raise Aws::S3::Errors::NoSuchBucket.new(nil, nil) } - end - - def get_bucket_encryption(query) - buckets = { - "public" => OpenStruct.new(server_side_encryption_configuration: OpenStruct.new(rules: [])), - } - if query[:bucket].eql? "private" - raise Aws::S3::Errors::ServerSideEncryptionConfigurationNotFoundError.new(nil, nil) - end - - buckets.fetch(query[:bucket]) { raise Aws::S3::Errors::NoSuchBucket.new(nil, nil) } - end - end -end diff --git a/test/unit/resources/aws_s3_buckets_test.rb b/test/unit/resources/aws_s3_buckets_test.rb deleted file mode 100644 index a3bdba29e..000000000 --- a/test/unit/resources/aws_s3_buckets_test.rb +++ /dev/null @@ -1,92 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_s3_buckets" - -require "resource_support/aws" - -# MSBB = MockS3BucketsBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsS3BucketsConstructor < Minitest::Test - def setup - AwsS3Buckets::BackendFactory.select(AwsMSBB::Basic) - end - - def test_constructor_no_args_ok - AwsS3Buckets.new - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsS3Buckets.new(bla: "blabla") } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsS3BucketsRecallEmptyTest < Minitest::Test - - def setup - AwsS3Buckets::BackendFactory.select(AwsMSBB::Empty) - end - - def test_search_miss_via_empty_vpcs - refute AwsS3Buckets.new.exists? - end -end - -class AwsS3BucketsRecallBasicTest < Minitest::Test - - def setup - AwsS3Buckets::BackendFactory.select(AwsMSBB::Basic) - end - - def test_search_hit_via_empty_filter - assert AwsS3Buckets.new.exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsS3bucketsProperties < Minitest::Test - def setup - AwsS3Buckets::BackendFactory.select(AwsMSBB::Basic) - end - - def test_property_bucket_names - basic = AwsS3Buckets.new - assert_kind_of(Array, basic.bucket_names) - assert(basic.bucket_names.include?("bucket-01")) - assert(!basic.bucket_names.include?("NonExistentBucket")) - refute(basic.bucket_names.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module AwsMSBB - class Empty < AwsBackendBase - def list_buckets - OpenStruct.new({ buckets: [] }) - end - end - - class Basic < AwsBackendBase - def list_buckets - fixtures = [ - OpenStruct.new({ - name: "bucket-01", - }), - OpenStruct.new({ - name: "bucket-02", - }), - ] - OpenStruct.new({ buckets: fixtures }) - end - end -end diff --git a/test/unit/resources/aws_security_group_test.rb b/test/unit/resources/aws_security_group_test.rb deleted file mode 100644 index 4530ce48a..000000000 --- a/test/unit/resources/aws_security_group_test.rb +++ /dev/null @@ -1,506 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_security_group" - -require "resource_support/aws" - -# MESGSB = MockEc2SecurityGroupSingleBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsSGSConstructor < Minitest::Test - def setup - AwsSecurityGroup::BackendFactory.select(AwsMESGSB::Empty) - end - - def test_constructor_no_args_raises - assert_raises(ArgumentError) { AwsSecurityGroup.new } - end - - def test_constructor_accept_scalar_param - AwsSecurityGroup.new("sg-12345678") - end - - def test_constructor_expected_well_formed_args - { - id: "sg-1234abcd", - group_id: "sg-1234abcd", - vpc_id: "vpc-1234abcd", - group_name: "some-group", - }.each do |param, value| - AwsSecurityGroup.new(param => value) - end - end - - def test_constructor_reject_malformed_args - { - id: "sg-xyz-123", - group_id: "1234abcd", - vpc_id: "vpc_1234abcd", - }.each do |param, value| - assert_raises(ArgumentError) { AwsSecurityGroup.new(param => value) } - end - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsSecurityGroup.new(beep: "boop") } - end -end - -#=============================================================================# -# Properties -#=============================================================================# - -class AwsSGSProperties < Minitest::Test - def setup - AwsSecurityGroup::BackendFactory.select(AwsMESGSB::Basic) - end - - def test_property_group_id - assert_equal("sg-12345678", AwsSecurityGroup.new("sg-12345678").group_id) - assert_nil(AwsSecurityGroup.new(group_name: "my-group").group_id) - end - - def test_property_group_name - assert_equal("beta", AwsSecurityGroup.new("sg-12345678").group_name) - assert_nil(AwsSecurityGroup.new("sg-87654321").group_name) - end - - def test_property_vpc_id - assert_equal("vpc-aaaabbbb", AwsSecurityGroup.new("sg-aaaabbbb").vpc_id) - assert_nil(AwsSecurityGroup.new("sg-87654321").vpc_id) - end - - def test_property_description - assert_equal("Awesome Group", AwsSecurityGroup.new("sg-12345678").description) - assert_nil(AwsSecurityGroup.new("sg-87654321").description) - end - - def test_property_inbound_rules - assert_empty(AwsSecurityGroup.new("sg-87654321").inbound_rules) - rules = AwsSecurityGroup.new("sg-12345678").inbound_rules - assert_kind_of(Array, rules) - assert_kind_of(Hash, rules[0]) - end - - def test_property_outbound_rules - assert_empty(AwsSecurityGroup.new("sg-87654321").outbound_rules) - rules = AwsSecurityGroup.new("sg-12345678").outbound_rules - assert_kind_of(Array, rules) - assert_kind_of(Hash, rules[0]) - end - - def test_property_inbound_rules_count - assert_equal(0, AwsSecurityGroup.new("sg-aaaabbbb").inbound_rules_count) - count = AwsSecurityGroup.new("sg-12345678").inbound_rules_count - assert_equal(7, count) - assert_kind_of(Numeric, count) - end - - def test_property_outbound_rules_count - assert_equal(0, AwsSecurityGroup.new("sg-aaaabbbb").outbound_rules_count) - count = AwsSecurityGroup.new("sg-12345678").outbound_rules_count - assert_equal(2, count) - assert_kind_of(Numeric, count) - end -end - -#=============================================================================# -# Matchers -#=============================================================================# - -class AwsSGSMatchers < Minitest::Test - def setup - AwsSecurityGroup::BackendFactory.select(AwsMESGSB::Basic) - end - - def test_matcher_allow_criteria_validation - sg = AwsSecurityGroup.new("sg-aaaabbbb") - assert_raises(ArgumentError, "allow should reject unrecognized criteria") { sg.allow_in?(shoe_size: 9) } - %i{ - from_port - ipv4_range - port - position - protocol - to_port - security_group - }.each do |criterion| - # No errors here - sg.allow_in?(criterion => "dummy") - end - end - - def test_matcher_allow_inbound_empty - sg = AwsSecurityGroup.new("sg-aaaabbbb") - rules = sg.inbound_rules - assert_equal(0, rules.count) - refute(sg.allow_in?) # Should we test this - "open" criteria? - end - - def test_matcher_allow_inbound_complex - sg = AwsSecurityGroup.new("sg-12345678") - assert_equal(3, sg.inbound_rules.count, "count the number of rules for 3-rule group") - - # Position pinning - assert(sg.allow_in?(ipv4_range: "10.1.4.0/24", position: 2), "use numeric position") - assert(sg.allow_in?(ipv4_range: "10.1.4.0/24", position: "2"), "use string position") - assert(sg.allow_in?(ipv4_range: "10.2.0.0/16", position: :last), "use :last position") - assert(sg.allow_in?(port: 22, position: :first), "use :first position") - - # Port - assert(sg.allow_in?(port: 22), "match on a numeric port") - assert(sg.allow_in?(port: "22"), "match on a string port") - assert(sg.allow_in?(to_port: "22", from_port: "22"), "match on to/from port") - assert(sg.allow_in?(port: 9002, position: 3), "range matching on port with allow_in") - refute(sg.allow_in_only?(port: 9002, position: 3), "no range matching on port with allow_in_only") - assert(sg.allow_in_only?(from_port: 9001, to_port: 9003, position: 3), "exact range matching on port with allow_in_only") - - # Protocol - assert(sg.allow_in?(protocol: "tcp"), "match on tcp protocol, unpinned") - assert(sg.allow_in?(protocol: "tcp", position: 1), "match on tcp protocol") - assert(sg.allow_in?(protocol: "any", position: 2), "match on our 'any' alias protocol") - assert(sg.allow_in?(protocol: "-1", position: 2), "match on AWS spec '-1 for any' protocol") - - # IPv4 range testing - assert(sg.allow_in?(ipv4_range: ["10.1.4.0/24"]), "match on 1 ipv4 range as array") - assert(sg.allow_in?(ipv4_range: ["10.1.4.33/32"]), "match on 1 ipv4 range subnet membership") - assert(sg.allow_in?(ipv4_range: ["10.1.4.33/32", "10.1.4.82/32"]), "match on 2 addrs ipv4 range subnet membership") - assert(sg.allow_in?(ipv4_range: ["10.1.4.0/25", "10.1.4.128/25"]), "match on 2 subnets ipv4 range subnet membership") - assert(sg.allow_in_only?(ipv4_range: "10.1.4.0/24", position: 2), "exact match on 1 ipv4 range with _only") - refute(sg.allow_in_only?(ipv4_range: "10.1.4.33/32", position: 2), "no range membership ipv4 range with _only") - assert(sg.allow_in?(ipv4_range: "10.1.2.0/24"), "match on a list ipv4 range when providing only one value (first)") - assert(sg.allow_in?(ipv4_range: "10.1.3.0/24"), "match on a list ipv4 range when providing only one value (last)") - assert(sg.allow_in?(ipv4_range: ["10.1.2.33/32", "10.1.3.33/32"]), "match on a list of single IPs against a list of subnets") - assert(sg.allow_in?(ipv4_range: ["10.1.2.0/24", "10.1.3.0/24"])) - refute(sg.allow_in?(ipv4_range: ["10.1.22.0/24", "10.1.33.0/24"])) - assert(sg.allow_in?(ipv4_range: ["10.1.3.0/24", "10.1.2.0/24"])) # Order is ignored - assert(sg.allow_in_only?(ipv4_range: ["10.1.2.0/24", "10.1.3.0/24"], position: 1)) - refute(sg.allow_in_only?(ipv4_range: ["10.1.2.0/24"], position: 1)) - refute(sg.allow_in_only?(ipv4_range: ["10.1.3.0/24"], position: 1)) - - # IPv6 range testing - assert(sg.allow_in?(ipv6_range: ["2001:db8::/122"]), "match on 1 ipv6 range as array") - assert(sg.allow_in?(ipv6_range: ["2001:db8::20/128"]), "match on 1 ipv6 range subnet membership") - assert(sg.allow_in?(ipv6_range: ["2001:db8::20/128", "2001:db8::3f/128"]), "match on 2 addrs ipv6 range subnet membership") - assert(sg.allow_in?(ipv6_range: ["2001:db8::/128", "1968:db8::/124"]), "match on 2 subnets ipv6 range subnet membership") - assert(sg.allow_in_only?(ipv6_range: "2018:db8::/122", position: 2), "exact match on 1 ipv6 range with _only") - refute(sg.allow_in_only?(ipv6_range: "2001:db8::20/128", position: 2), "no range membership ipv6 range with _only") - - # Test _only with a 3-rule group, but omitting position - refute(sg.allow_in_only?(port: 22), "_only will fail a multi-rule SG even if it has matching criteria") - refute(sg.allow_in_only?, "_only will fail a multi-rule SG even if it has match-any criteria") - - # Test _only with a single rule group (ie, omitting position) - sg = AwsSecurityGroup.new("sg-22223333") - assert_equal(1, sg.inbound_rules.count, "count the number of rules for 1-rule group") - assert_equal(1, sg.inbound_rules_count, "Count the number of rule variants for 1-rule group") - assert(sg.allow_in_only?(ipv4_range: "0.0.0.0/0"), "Match IP range using _only on 1-rule group") - assert(sg.allow_in_only?(protocol: "any"), "Match protocol using _only on 1-rule group") - refute(sg.allow_in_only?(port: 22), "no match port using _only on 1-rule group") - - # Test _only with a single rule group for IPv6 - sg = AwsSecurityGroup.new("sg-33334444") - assert_equal(1, sg.inbound_rules.count, "count the number of rules for 1-rule ipv6 group") - assert_equal(1, sg.inbound_rules_count, "Count the number of rule variants for 1-rule ipv6 group") - assert(sg.allow_in_only?(ipv6_range: "::/0"), "Match IP range using _only on 1-rule ipv6 group") - assert(sg.allow_in_only?(protocol: "any"), "Match protocol using _only on 1-rule ipv6 group") - refute(sg.allow_in_only?(port: 22), "no match port using _only on 1-rule ipv6 group") - - # security-group - sg = AwsSecurityGroup.new("sg-55556666") - assert(sg.allow_in?(security_group: "sg-33334441"), "match on group-id") - assert(sg.allow_in?(security_group: "sg-33334441", port: 22), "match on group-id, numeric port") - assert(sg.allow_in?(security_group: "sg-33334441", port: "22"), "match on group-id, string port") - assert(sg.allow_in?(security_group: "sg-33334441", to_port: "22", from_port: "22"), "match on group-id, to/from port") - assert(sg.allow_in?(port: 9002, position: 3), "range matching on port with allow_in") - refute(sg.allow_in_only?(port: 9002, position: 3), "no range matching on port with allow_in_only") - refute(sg.allow_in_only?(security_group: "sg-33334441"), "no matching on group with allow_in_only when multiple group rules") - assert(sg.allow_in_only?(from_port: 9001, to_port: 9003, position: 3), "exact range matching on port with allow_in_only") - - # Test _only with a single rule group for security-group - sg = AwsSecurityGroup.new("sg-33334441") - assert_equal(1, sg.inbound_rules.count, "count the number of rules for 1-rule security-group") - assert_equal(1, sg.inbound_rules_count, "Count the number of rule variants for 1-rule security-group") - assert(sg.allow_in_only?(security_group: "sg-33334444"), "Match security-group using _only on 1-rule security-group") - assert(sg.allow_in_only?(protocol: "any", security_group: "sg-33334444"), "Match protocol using _only on 1-rule security-group") - refute(sg.allow_in_only?(port: 22, security_group: "sg-33334444"), "no match port using _only on 1-rule security-group") - - # Test _only with a single rule group for security-group with position pinning - sg = AwsSecurityGroup.new("sg-33334442") - assert(sg.allow_in_only?(security_group: "sg-33334444", position: 2), "Match security-group using _only with numerical position") - assert(sg.allow_in_only?(protocol: "any", security_group: "sg-33334444", position: 2), "Match protocol using _only on 1-rule security-group with numerical position") - refute(sg.allow_in_only?(port: 22, security_group: "sg-33334444", position: 2), "no match port using _only on 1-rule security-group with numerical position") - assert(sg.allow_in_only?(security_group: "sg-33334444", position: "2"), "Match security-group using _only with string position") - assert(sg.allow_in_only?(security_group: "sg-33334444", position: :last), "Match security-group using _only with last position") - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMESGSB - class Empty < AwsBackendBase - def describe_security_groups(_query) - OpenStruct.new({ - security_groups: [], - }) - end - end - - class Basic < AwsBackendBase - def describe_security_groups(query) - fixtures = [ - OpenStruct.new({ - description: "Some Group", - group_id: "sg-aaaabbbb", - group_name: "alpha", - vpc_id: "vpc-aaaabbbb", - ip_permissions: [], - ip_permissions_egress: [], - }), - OpenStruct.new({ - description: "Awesome Group", - group_id: "sg-12345678", - group_name: "beta", - vpc_id: "vpc-12345678", - ip_permissions: [ - OpenStruct.new({ - from_port: 22, - to_port: 22, - ip_protocol: "tcp", - ip_ranges: [ - # Apparently AWS returns these as plain hashes, - # nested in two levels of Structs. - { cidr_ip: "10.1.2.0/24" }, - { cidr_ip: "10.1.3.0/24" }, - ], - ipv_6_ranges: [ - { cidr_ipv_6: "2001:db8::/122" }, - { cidr_ipv_6: "1968:db8::/124" }, - ], - }), - OpenStruct.new({ - from_port: nil, - to_port: nil, - ip_protocol: "-1", - ip_ranges: [ - { cidr_ip: "10.1.4.0/24" }, - ], - ipv_6_ranges: [ - { cidr_ipv_6: "2018:db8::/122" }, - ], - }), - OpenStruct.new({ - from_port: 9001, - to_port: 9003, - ip_protocol: "udp", - ip_ranges: [ - { cidr_ip: "10.2.0.0/16" }, - ], - }), - ], - ip_permissions_egress: [ - OpenStruct.new({ - from_port: 123, - to_port: 123, - ip_protocol: "udp", - ip_ranges: [ - { cidr_ip: "128.138.140.44/32" }, - ], - ipv_6_ranges: [ - { cidr_ipv_6: "2001:db8::/122" }, - ], - }), - ], - }), - OpenStruct.new({ - description: "Open Group", - group_id: "sg-22223333", - group_name: "gamma", - vpc_id: "vpc-12345678", - ip_permissions: [ - OpenStruct.new({ - from_port: nil, - to_port: nil, - ip_protocol: "-1", - ip_ranges: [ - { cidr_ip: "0.0.0.0/0" }, - ], - }), - ], - ip_permissions_egress: [], - }), - OpenStruct.new({ - description: "Open Group", - group_id: "sg-33334444", - group_name: "delta", - vpc_id: "vpc-12345678", - ip_permissions: [ - OpenStruct.new({ - from_port: nil, - to_port: nil, - ip_protocol: "-1", - ipv_6_ranges: [ - { cidr_ipv_6: "::/0" }, - ], - }), - ], - ip_permissions_egress: [], - }), - OpenStruct.new({ - description: "Open for group one group rule second position", - group_id: "sg-33334442", - group_name: "etha", - vpc_id: "vpc-12345678", - ip_permissions: [ - OpenStruct.new({ - from_port: nil, - to_port: nil, - ip_protocol: "-1", - ipv_6_ranges: [ - { cidr_ipv_6: "::/0" }, - ], - }), - OpenStruct.new({ - from_port: nil, - to_port: nil, - ip_protocol: "-1", - user_id_group_pairs: [ - OpenStruct.new({ - description: "Open for group one rule second position", - group_id: "sg-33334444", - group_name: "delta", - peering_status: "", - user_id: "123456789012", - vpc_id: "", - vpc_peering_connection_id: "", - }), - ], - }), - ], - ip_permissions_egress: [], - }), - OpenStruct.new({ - description: "Open for group one rule", - group_id: "sg-33334441", - group_name: "zeta", - vpc_id: "vpc-12345678", - ip_permissions: [ - OpenStruct.new({ - from_port: nil, - to_port: nil, - ip_protocol: "-1", - user_id_group_pairs: [ - OpenStruct.new({ - description: "Open for group one rule", - group_id: "sg-33334444", - group_name: "delta", - peering_status: "", - user_id: "123456789012", - vpc_id: "", - vpc_peering_connection_id: "", - }), - ], - }), - ], - ip_permissions_egress: [], - }), - OpenStruct.new({ - description: "Open for group", - group_id: "sg-55556666", - group_name: "epsilon", - vpc_id: "vpc-12345678", - ip_permissions: [ - OpenStruct.new({ - from_port: 80, - to_port: 443, - ip_protocol: "-1", - ip_ranges: [ - { cidr_ip: "0.0.0.0/0" }, - ], - }), - OpenStruct.new({ - from_port: 22, - to_port: 22, - ip_protocol: "-1", - user_id_group_pairs: [ - OpenStruct.new({ - description: "Open for group rule 2", - group_id: "sg-33334441", - group_name: "zeta", - peering_status: "", - user_id: "123456789012", - vpc_id: "", - vpc_peering_connection_id: "", - }), - ], - }), - OpenStruct.new({ - from_port: 9001, - to_port: 9003, - ip_protocol: "-1", - user_id_group_pairs: [ - OpenStruct.new({ - description: "Open for group rule 3", - group_id: "sg-33334441", - group_name: "zeta", - peering_status: "", - user_id: "123456789012", - vpc_id: "", - vpc_peering_connection_id: "", - }), - ], - }), - OpenStruct.new({ - from_port: nil, - to_port: nil, - ip_protocol: "-1", - user_id_group_pairs: [ - OpenStruct.new({ - description: "allow all from multiple sg", - group_id: "sg-33334441", - group_name: "zeta", - peering_status: "", - user_id: "123456789012", - vpc_id: "", - vpc_peering_connection_id: "", - }), - OpenStruct.new({ - description: "allow all from multiple sg[2]", - group_id: "sg-33334442", - group_name: "etha", - peering_status: "", - user_id: "123456789012", - vpc_id: "", - vpc_peering_connection_id: "", - }), - OpenStruct.new({ - description: "allow all from multiple sg[3]", - group_id: "sg-11112222", - group_name: "theta", - peering_status: "", - user_id: "123456789012", - vpc_id: "", - vpc_peering_connection_id: "", - }), - ], - }), - ], - ip_permissions_egress: [], - }) ] - - selected = fixtures.select do |sg| - query[:filters].all? do |filter| - filter[:values].include?(sg[filter[:name].tr("-", "_")]) - end - end - - OpenStruct.new({ security_groups: selected }) - end - end - -end diff --git a/test/unit/resources/aws_security_groups_test.rb b/test/unit/resources/aws_security_groups_test.rb deleted file mode 100644 index 33daed37b..000000000 --- a/test/unit/resources/aws_security_groups_test.rb +++ /dev/null @@ -1,106 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_security_groups" - -require "resource_support/aws" - -# MESGB = MockSecurityGroupBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsSGConstructor < Minitest::Test - def setup - AwsSecurityGroups::BackendFactory.select(AwsMESGB::Empty) - end - - def test_constructor_no_args_ok - AwsSecurityGroups.new - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsSecurityGroups.new(beep: "boop") } - end -end - -#=============================================================================# -# Filter Criteria -#=============================================================================# -class AwsSGFilterCriteria < Minitest::Test - def setup - AwsSecurityGroups::BackendFactory.select(AwsMESGB::Basic) - end - - def test_filter_vpc_id - hit = AwsSecurityGroups.new.where(vpc_id: "vpc-12345678") - assert(hit.exists?) - - miss = AwsSecurityGroups.new.where(vpc_id: "vpc-87654321") - refute(miss.exists?) - end - - def test_filter_group_name - hit = AwsSecurityGroups.new.where(group_name: "alpha") - assert(hit.exists?) - - miss = AwsSecurityGroups.new.where(group_name: "nonesuch") - refute(miss.exists?) - end - -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsSGProperties < Minitest::Test - def setup - AwsSecurityGroups::BackendFactory.select(AwsMESGB::Basic) - end - - def test_property_group_ids - basic = AwsSecurityGroups.new - assert_kind_of(Array, basic.group_ids) - assert(basic.group_ids.include?("sg-aaaabbbb")) - refute(basic.group_ids.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMESGB - class Empty < AwsBackendBase - def describe_security_groups(_query) - OpenStruct.new({ - security_groups: [], - }) - end - end - - class Basic < AwsBackendBase - def describe_security_groups(query) - fixtures = [ - OpenStruct.new({ - group_id: "sg-aaaabbbb", - group_name: "alpha", - vpc_id: "vpc-aaaabbbb", - }), - OpenStruct.new({ - group_id: "sg-12345678", - group_name: "beta", - vpc_id: "vpc-12345678", - }), - ] - - selected = fixtures.select do |sg| - query.keys.all? do |criterion| - query[criterion] == sg[criterion] - end - end - - OpenStruct.new({ security_groups: selected }) - end - end -end diff --git a/test/unit/resources/aws_sns_subscription_test.rb b/test/unit/resources/aws_sns_subscription_test.rb deleted file mode 100644 index fc3b02571..000000000 --- a/test/unit/resources/aws_sns_subscription_test.rb +++ /dev/null @@ -1,147 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_sns_subscription" - -require "resource_support/aws" - -# MASSSB = MockAwsSNSSubscriptionSingularBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsSnsSubscriptionConstructorTest < Minitest::Test - - def setup - AwsSnsSubscription::BackendFactory.select(AwsMASSSB::Basic) - end - - def test_empty_params_not_ok - assert_raises(ArgumentError) { AwsSnsSubscription.new } - end - - def test_accepts_subscription_arn_as_scalar - AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f") - end - - def test_accepts_subscription_arn_as_hash - AwsSnsSubscription.new(subscription_arn: "arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f") - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsSnsSubscriptionRecallTest < Minitest::Test - - def setup - AwsSnsSubscription::BackendFactory.select(AwsMASSSB::Basic) - end - - def test_search_hit_via_scalar_works - assert AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f").exists? - end - - def test_search_hit_via_hash_works - assert AwsSnsSubscription.new(subscription_arn: "arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsSnsSubscription.new(subscription_arn: "arn:aws:sns:us-west-2:0123456789012:my-topic_non_existent:8a21d249-4329-4871-00000-00000000").exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsSnsSubscriptionPropertiesTest < Minitest::Test - - def setup - AwsSnsSubscription::BackendFactory.select(AwsMASSSB::Basic) - end - - def test_property_topic_arn - assert_equal("arn:aws:sns:us-west-2:0123456789012:my-topic2", AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f").topic_arn) - assert_nil(AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:00000-0000-0000-0000-000000").topic_arn) - end - - def test_property_endpoint - assert_equal("my-email2@example.com", AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f").endpoint) - assert_nil(AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:00000-0000-0000-0000-000000").endpoint) - end - - def test_property_protocol - assert_equal("https", AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f").protocol) - assert_equal("email", AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f").protocol) - assert_nil(AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:00000-0000-0000-0000-000000").protocol) - end - - def test_property_owner - assert_equal("0123456789012", AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f").owner) - assert_nil(AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:00000-0000-0000-0000-000000").owner) - end -end - -#=============================================================================# -# Matchers -#=============================================================================# -class AwsSnsSubscriptionMatchersTest < Minitest::Test - - def setup - AwsSnsSubscription::BackendFactory.select(AwsMASSSB::Basic) - end - - def test_matcher_raw_message_delivery_positive - assert AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f").raw_message_delivery? - end - - def test_matcher_raw_message_delivery_negative - refute AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f").raw_message_delivery? - end - - def test_matcher_confirmation_authenticated_positive - assert AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f").confirmation_authenticated? - end - - def test_matcher_confirmation_authenticated_negative - refute AwsSnsSubscription.new("arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f").confirmation_authenticated? - end - -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module AwsMASSSB - class Basic < AwsBackendBase - def get_subscription_attributes(query) - fixtures = OpenStruct.new({ - "arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f" => OpenStruct.new({ - "attributes" => OpenStruct.new({ - "Endpoint": "my-email@example.com", - "Protocol": "email", - "RawMessageDelivery": "false", - "ConfirmationWasAuthenticated": "false", - "Owner": "0123456789012", - "SubscriptionArn": "arn:aws:sns:us-west-2:0123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f", - "TopicArn": "arn:aws:sns:us-west-2:0123456789012:my-topic", - }), - }), - "arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f" => OpenStruct.new({ - "attributes" => OpenStruct.new({ - "Endpoint": "my-email2@example.com", - "Protocol": "https", - "RawMessageDelivery": "true", - "ConfirmationWasAuthenticated": "true", - "Owner": "0123456789012", - "SubscriptionArn": "arn:aws:sns:us-west-2:0123456789012:my-topic2:8a21d249-4329-4871-acc6-7be709c6ea7f", - "TopicArn": "arn:aws:sns:us-west-2:0123456789012:my-topic2", - }), - }), - }) - return OpenStruct.new(fixtures[query[:subscription_arn]] ) unless fixtures[query[:subscription_arn]].nil? - - raise Aws::SNS::Errors::NotFound.new(Seahorse::Client::Http::Request, "Key does not exist") - end - end -end diff --git a/test/unit/resources/aws_sns_topic_test.rb b/test/unit/resources/aws_sns_topic_test.rb deleted file mode 100644 index 5a73075c1..000000000 --- a/test/unit/resources/aws_sns_topic_test.rb +++ /dev/null @@ -1,128 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_sns_topic" - -require "resource_support/aws" - -# MSNB = MockSnsBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsSnsTopicConstructorTest < Minitest::Test - def setup - AwsSnsTopic::BackendFactory.select(AwsMSNB::NoSubscriptions) - end - - def test_constructor_some_args_required - assert_raises(ArgumentError) { AwsSnsTopic.new } - end - - def test_constructor_accepts_scalar_arn - AwsSnsTopic.new("arn:aws:sns:us-east-1:123456789012:some-topic") - end - - def test_constructor_accepts_arn_as_hash - AwsSnsTopic.new(arn: "arn:aws:sns:us-east-1:123456789012:some-topic") - end - - def test_constructor_rejects_unrecognized_resource_params - assert_raises(ArgumentError) { AwsSnsTopic.new(beep: "boop") } - end - - def test_constructor_rejects_non_arn_formats - [ - "not-even-like-an-arn", - "arn:::::", # Empty - "arn::::::", # Too many colons - "arn:aws::us-east-1:123456789012:some-topic", # Omits SNS service - "arn::sns:us-east-1:123456789012:some-topic", # Omits partition - "arn:aws:sns:*:123456789012:some-topic", # All-region - not permitted for lookup - "arn:aws:sns:us-east-1::some-topic", # Default account - not permitted for lookup - ].each do |example| - assert_raises(ArgumentError) { AwsSnsTopic.new(arn: example) } - end - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsSnsTopicRecallTest < Minitest::Test - # No setup here - each test needs to explicitly declare - # what they want from the backend. - - def test_recall_no_match_is_no_exception - AwsSnsTopic::BackendFactory.select(AwsMSNB::Miss) - topic = AwsSnsTopic.new("arn:aws:sns:us-east-1:123456789012:nope") - refute topic.exists? - end - - def test_recall_match_single_result_works - AwsSnsTopic::BackendFactory.select(AwsMSNB::NoSubscriptions) - topic = AwsSnsTopic.new("arn:aws:sns:us-east-1:123456789012:does-not-matter") - assert topic.exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# - -class AwsSnsTopicPropertiesTest < Minitest::Test - # No setup here - each test needs to explicitly declare - # what they want from the backend. - - #--------------------------------------- - # confirmed_subscription_count - #--------------------------------------- - def test_prop_conf_sub_count_zero - AwsSnsTopic::BackendFactory.select(AwsMSNB::NoSubscriptions) - topic = AwsSnsTopic.new("arn:aws:sns:us-east-1:123456789012:does-not-matter") - assert_equal(0, topic.confirmed_subscription_count) - end - - def test_prop_conf_sub_count_one - AwsSnsTopic::BackendFactory.select(AwsMSNB::OneSubscription) - topic = AwsSnsTopic.new("arn:aws:sns:us-east-1:123456789012:does-not-matter") - assert_equal(1, topic.confirmed_subscription_count) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMSNB - - class Miss < AwsBackendBase - def get_topic_attributes(criteria) - raise Aws::SNS::Errors::NotFound.new("No SNS topic for #{criteria[:topic_arn]}", "Nope") - end - end - - class NoSubscriptions < AwsBackendBase - def get_topic_attributes(_criteria) - OpenStruct.new({ - attributes: { # Note that this is a plain hash, odd for AWS SDK - # Many other attributes available, see - # http://docs.aws.amazon.com/sdkforruby/api/Aws/SNS/Types/GetTopicAttributesResponse.html - "SubscriptionsConfirmed" => 0, - }, - }) - end - end - - class OneSubscription < AwsBackendBase - def get_topic_attributes(_criteria) - OpenStruct.new({ - attributes: { # Note that this is a plain hash, odd for AWS SDK - # Many other attributes available, see - # http://docs.aws.amazon.com/sdkforruby/api/Aws/SNS/Types/GetTopicAttributesResponse.html - "SubscriptionsConfirmed" => 1, - }, - }) - end - end -end diff --git a/test/unit/resources/aws_sns_topics_test.rb b/test/unit/resources/aws_sns_topics_test.rb deleted file mode 100644 index bdbdfb0dd..000000000 --- a/test/unit/resources/aws_sns_topics_test.rb +++ /dev/null @@ -1,58 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_sns_topics" - -require "resource_support/aws" - -# MSTB = MockSnsTopicsBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsSnsTopicsConstructor < Minitest::Test - def setup - AwsSnsTopics::BackendFactory.select(AwsMSTB::Basic) - end - - def test_constructor_no_args_ok - AwsSnsTopics.new - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsSnsTopics.new(bla: "blabla") } - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsSnsTopicsProperties < Minitest::Test - def setup - AwsSnsTopics::BackendFactory.select(AwsMSTB::Basic) - end - - def test_property_topics_arns - basic = AwsSnsTopics.new - assert_kind_of(Array, basic.topic_arns) - assert(basic.topic_arns.include?("arn:aws:sns:us-east-1:212312313:test-topic-01")) - assert(basic.topic_arns.include?("arn:aws:sns:us-east-1:123123129:test-topic-02")) - refute(basic.topic_arns.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module AwsMSTB - class Basic < AwsBackendBase - def list_topics(query = {}) - OpenStruct.new({ - topics: [ - OpenStruct.new({ topic_arn: "arn:aws:sns:us-east-1:212312313:test-topic-01" }), - OpenStruct.new({ topic_arn: "arn:aws:sns:us-east-1:123123129:test-topic-02" }), - ], - }) - end - end -end diff --git a/test/unit/resources/aws_sqs_queue_test.rb b/test/unit/resources/aws_sqs_queue_test.rb deleted file mode 100644 index 477368d43..000000000 --- a/test/unit/resources/aws_sqs_queue_test.rb +++ /dev/null @@ -1,130 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_sqs_queue" - -require "resource_support/aws" - -# MSQB = MockSQsBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsSqsQueueConstructorTest < Minitest::Test - def setup - AwsSqsQueue::BackendFactory.select(AwsMSQB::Hit) - end - - def test_constructor_some_args_required - assert_raises(ArgumentError) { AwsSqsQueue.new } - end - - def test_constructor_accepts_scalar_url - AwsSqsQueue.new("https://sqs.ap-southeast-2.amazonaws.com/5195277125796/MyQueue") - end - - def test_constructor_accepts_url_as_hash - AwsSqsQueue.new(url: "https://sqs.ap-southeast-2.amazonaws.com/5195277125796/MyQueue") - end - - def test_constructor_rejects_unrecognized_resource_params - assert_raises(ArgumentError) { AwsSqsQueue.new(beep: "boop") } - end - - def test_constructor_rejects_non_https_url - [ - "not-even-a-url", - "http://example.com", # http - ].each do |example| - assert_raises(ArgumentError) { AwsSqsQueue.new(url: example) } - end - end -end - -#=============================================================================# -# Search/Recall -#=============================================================================# -class AwsSqsQueueRecallTest < Minitest::Test - # No setup here - each test needs to explicitly declare - # what they want from the backend. - - def test_recall_no_match_is_no_exception - AwsSqsQueue::BackendFactory.select(AwsMSQB::Miss) - queue = AwsSqsQueue.new("https://sqs.ap-southeast-2.amazonaws.com/12121/idontexist") - refute queue.exists? - end - - def test_recall_match_single_result_works - AwsSqsQueue::BackendFactory.select(AwsMSQB::Hit) - queue = AwsSqsQueue.new("https://sqs.ap-southeast-2.amazonaws.com/12121/iexist") - assert queue.exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# - -class AwsSqsQueuePropertiesTest < Minitest::Test - # No setup here - each test needs to explicitly declare - # what they want from the backend. - - #--------------------------------------- - # confirmed_subscription_count - #--------------------------------------- - def test_visibility_timeout - AwsSqsQueue::BackendFactory.select(AwsMSQB::Hit) - queue = AwsSqsQueue.new("https://sqs.ap-southeast-2.amazonaws.com/12121/iexist") - assert_equal(300, queue.visibility_timeout) - end - - def test_not_fifo_queue - AwsSqsQueue::BackendFactory.select(AwsMSQB::Hit) - queue = AwsSqsQueue.new("https://sqs.ap-southeast-2.amazonaws.com/12121/iexist") - refute queue.is_fifo_queue - end - - def test_fifo_queue - AwsSqsQueue::BackendFactory.select(AwsMSQB::FifoQueue) - queue = AwsSqsQueue.new("https://sqs.ap-southeast-2.amazonaws.com/12121/iexist") - assert queue.is_fifo_queue - assert queue.content_based_deduplication - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMSQB - - class Miss < AwsBackendBase - def get_queue_attributes(criteria) - raise Aws::SQS::Errors::NonExistentQueue.new("No SQS queue with URL #{criteria[:url]}", "Nope") - end - end - - class Hit < AwsBackendBase - def get_queue_attributes(_criteria) - OpenStruct.new({ - attributes: { - "QueueArn" => "arn:aws:sqs:ap-southeast-2:519527721296:MyQueue", - "VisibilityTimeout" => 300, - }, - }) - end - end - - class FifoQueue < AwsBackendBase - def get_queue_attributes(_criteria) - OpenStruct.new({ - attributes: { - "QueueArn" => "arn:aws:sqs:ap-southeast-2:519527721296:MyQueue.fifo", - "VisibilityTimeout" => 300, - "FifoQueue" => true, - "ContentBasedDeduplication" => true, - }, - }) - end - end -end diff --git a/test/unit/resources/aws_subnet_test.rb b/test/unit/resources/aws_subnet_test.rb deleted file mode 100644 index 6e571c1ce..000000000 --- a/test/unit/resources/aws_subnet_test.rb +++ /dev/null @@ -1,162 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_subnet" - -require "resource_support/aws" - -# MVSSB = MockVpcSubnetSingleBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsSubnetConstructorTest < Minitest::Test - def setup - AwsSubnet::BackendFactory.select(AwsMVSSB::Basic) - end - - def test_constructor_no_args_raises - assert_raises(ArgumentError) { AwsSubnet.new } - end - - def test_constructor_expected_well_formed_args - AwsSubnet.new(subnet_id: "subnet-12345678") - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsSubnet.new(bla: "blabla") } - end -end - -#=============================================================================# -# Recall -#=============================================================================# - -class AwsSubnetRecallTest < Minitest::Test - def setup - AwsSubnet::BackendFactory.select(AwsMVSSB::Basic) - end - - def test_search_hit_via_hash_with_vpc_id_and_subnet_id_works - assert AwsSubnet.new(subnet_id: "subnet-12345678").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsSubnet.new(subnet_id: "subnet-00000000").exists? - end -end - -#=============================================================================# -# properties -#=============================================================================# - -class AwsSubnetPropertiesTest < Minitest::Test - def setup - AwsSubnet::BackendFactory.select(AwsMVSSB::Basic) - end - - def test_property_subnet_id - assert_equal("subnet-12345678", AwsSubnet.new(subnet_id: "subnet-12345678").subnet_id) - end - - def test_property_vpc_id - assert_equal("vpc-12345678", AwsSubnet.new(subnet_id: "subnet-12345678").vpc_id) - end - - def test_property_cidr_block - assert_equal("10.0.1.0/24", AwsSubnet.new(subnet_id: "subnet-12345678").cidr_block) - assert_nil(AwsSubnet.new(subnet_id: "subnet-00000000").cidr_block) - end - - def test_property_availability_zone - assert_equal("us-east-1", AwsSubnet.new(subnet_id: "subnet-12345678").availability_zone) - assert_nil(AwsSubnet.new(subnet_id: "subnet-00000000").availability_zone) - end - - def test_property_available_ip_address_count - assert_equal(251, AwsSubnet.new(subnet_id: "subnet-12345678").available_ip_address_count) - assert_nil(AwsSubnet.new(subnet_id: "subnet-00000000").available_ip_address_count) - end - - def test_property_ipv_6_cidr_block_association_set - assert_equal([], AwsSubnet.new(subnet_id: "subnet-12345678").ipv_6_cidr_block_association_set) - assert_nil(AwsSubnet.new(subnet_id: "subnet-00000000").ipv_6_cidr_block_association_set) - end -end - -#=============================================================================# -# Test Matchers -#=============================================================================# -class AwsSubnetPropertiesTest < Minitest::Test - def test_matcher_assign_ipv_6_address_on_creation - assert AwsSubnet.new(subnet_id: "subnet-12345678").assigning_ipv_6_address_on_creation - refute AwsSubnet.new(subnet_id: "subnet-87654321").assigning_ipv_6_address_on_creation - end - - def test_matcher_available - assert AwsSubnet.new(subnet_id: "subnet-12345678").available? - refute AwsSubnet.new(subnet_id: "subnet-87654321").available? - end - - def test_matcher_default_for_az - assert AwsSubnet.new(subnet_id: "subnet-12345678").default_for_az? - refute AwsSubnet.new(subnet_id: "subnet-87654321").default_for_az? - end - - def test_matcher_map_public_ip_on_launch - assert AwsSubnet.new(subnet_id: "subnet-12345678").mapping_public_ip_on_launch - refute AwsSubnet.new(subnet_id: "subnet-87654321").mapping_public_ip_on_launch - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# - -module AwsMVSSB - class Basic < AwsBackendBase - def describe_subnets(query) - subnets = { - "subnet-12345678" => OpenStruct.new({ - subnets: [ - OpenStruct.new({ - availability_zone: "us-east-1", - available_ip_address_count: 251, - cidr_block: "10.0.1.0/24", - default_for_az: true, - map_public_ip_on_launch: true, - state: "available", - subnet_id: "subnet-12345678", - vpc_id: "vpc-12345678", - ipv_6_cidr_block_association_set: [], - assign_ipv_6_address_on_creation: true, - }), - ], - }), - "subnet-87654321" => OpenStruct.new({ - subnets: [ - OpenStruct.new({ - availability_zone: "us-east-1", - available_ip_address_count: 251, - cidr_block: "10.0.1.0/24", - default_for_az: false, - map_public_ip_on_launch: false, - state: "pending", - subnet_id: "subnet-87654321", - vpc_id: "vpc-87654321", - ipv_6_cidr_block_association_set: [], - assign_ipv_6_address_on_creation: false, - }), - ], - }), - "empty" => OpenStruct.new({ - subnets: [], - }), - } - - return subnets[query[:filters][0][:values][0]] unless subnets[query[:filters][0][:values][0]].nil? - - subnets["empty"] - end - end -end diff --git a/test/unit/resources/aws_subnets_test.rb b/test/unit/resources/aws_subnets_test.rb deleted file mode 100644 index 92b4b5cd8..000000000 --- a/test/unit/resources/aws_subnets_test.rb +++ /dev/null @@ -1,121 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_subnets" - -require "resource_support/aws" - -# MVSB = MockVpcSubnetsBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsSubnetsConstructor < Minitest::Test - def setup - AwsSubnets::BackendFactory.select(AwsMVSB::Basic) - end - - def test_constructor_no_args_ok - AwsSubnets.new - end - - def test_constructor_reject_unknown_resource_params - assert_raises(ArgumentError) { AwsSubnets.new(bla: "blabla") } - end -end - -#=============================================================================# -# Filter Criteria -#=============================================================================# -class AwsSubnetsFilterCriteria < Minitest::Test - def setup - AwsSubnets::BackendFactory.select(AwsMVSB::Basic) - end - - def test_filter_vpc_id - hit = AwsSubnets.new.where(vpc_id: "vpc-01234567") - assert(hit.exists?) - - miss = AwsSubnets.new.where(vpc_id: "vpc-87654321") - refute(miss.exists?) - end - - def test_filter_subnet_id - hit = AwsSubnets.new.where(subnet_id: "subnet-01234567") - assert(hit.exists?) - - miss = AwsSubnets.new.where(subnet_id: "subnet-98765432") - refute(miss.exists?) - end - -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsSubnetProperties < Minitest::Test - def setup - AwsSubnets::BackendFactory.select(AwsMVSB::Basic) - end - - def test_property_vpc_ids - basic = AwsSubnets.new - assert_kind_of(Array, basic.vpc_ids) - assert(basic.vpc_ids.include?("vpc-01234567")) - refute(basic.vpc_ids.include?(nil)) - end - - def test_property_subnet_ids - basic = AwsSubnets.new - assert_kind_of(Array, basic.subnet_ids) - assert(basic.subnet_ids.include?("subnet-01234567")) - refute(basic.subnet_ids.include?(nil)) - end - - def test_property_cidr_blocks - basic = AwsSubnets.new - assert_kind_of(Array, basic.cidr_blocks) - assert(basic.cidr_blocks.include?("10.0.1.0/24")) - refute(basic.cidr_blocks.include?(nil)) - end - - def test_property_states - basic = AwsSubnets.new - assert_kind_of(Array, basic.states) - assert(basic.states.include?("available")) - refute(basic.states.include?(nil)) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module AwsMVSB - class Basic < AwsBackendBase - def describe_subnets - fixtures = [ - OpenStruct.new({ - availability_zone: "us-east-1c", - available_ip_address_count: 251, - cidr_block: "10.0.1.0/24", - default_for_az: false, - map_public_ip_on_launch: false, - state: "available", - subnet_id: "subnet-01234567", - vpc_id: "vpc-01234567", - }), - OpenStruct.new({ - availability_zone: "us-east-1b", - available_ip_address_count: 251, - cidr_block: "10.0.2.0/24", - default_for_az: false, - map_public_ip_on_launch: false, - state: "available", - subnet_id: "subnet-00112233", - vpc_id: "vpc-00112233", - }), - ] - OpenStruct.new({ subnets: fixtures }) - end - end -end diff --git a/test/unit/resources/aws_vpc_test.rb b/test/unit/resources/aws_vpc_test.rb deleted file mode 100644 index ff458a57e..000000000 --- a/test/unit/resources/aws_vpc_test.rb +++ /dev/null @@ -1,177 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_vpc" - -require "resource_support/aws" - -# MAVSB = MockAwsVpcSingularBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsVpcConstructorTest < Minitest::Test - - def setup - AwsVpc::BackendFactory.select(MAVSB::Empty) - end - - def test_empty_params_ok - AwsVpc.new - end - - def test_accepts_vpc_id_as_scalar_eight_sign - AwsVpc.new("vpc-12345678") - end - - def test_accepts_vpc_id_as_scalar - AwsVpc.new("vpc-12345678987654321") - end - - def test_accepts_vpc_id_as_hash_eight_sign - AwsVpc.new(vpc_id: "vpc-1234abcd") - end - - def test_accepts_vpc_id_as_hash - AwsVpc.new(vpc_id: "vpc-abcd123454321dcba") - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsVpc.new(shoe_size: 9) } - end - - def test_rejects_invalid_vpc_id - assert_raises(ArgumentError) { AwsVpc.new("vpc-rofl") } - end -end - -#=============================================================================# -# Search / Recall -#=============================================================================# -class AwsVpcRecallTest < Minitest::Test - - def setup - AwsVpc::BackendFactory.select(MAVSB::Basic) - end - - def test_search_hit_via_default_works - assert AwsVpc.new.exists? - end - - def test_search_hit_via_scalar_works - assert AwsVpc.new("vpc-12344321").exists? - end - - def test_search_hit_via_hash_works - assert AwsVpc.new(vpc_id: "vpc-12344321").exists? - end - - def test_search_miss_is_not_an_exception_eight_sign - refute AwsVpc.new(vpc_id: "vpc-00000000").exists? - end - - def test_search_miss_is_not_an_exception - refute AwsVpc.new(vpc_id: "vpc-00000000000000000").exists? - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsVpcPropertiesTest < Minitest::Test - - def setup - AwsVpc::BackendFactory.select(MAVSB::Basic) - end - - def test_property_vpc_id - assert_equal("vpc-aaaabbbb", AwsVpc.new("vpc-aaaabbbb").vpc_id) - # Even on a miss, identifiers should be preserved - assert_equal("vpc-00000000", AwsVpc.new(vpc_id: "vpc-00000000").vpc_id) - end - - def test_property_cidr_block - assert_equal("10.0.0.0/16", AwsVpc.new("vpc-aaaabbbb").cidr_block) - assert_nil(AwsVpc.new("vpc-00000000").cidr_block) - end - - def test_property_dhcp_options_id - assert_equal("dopt-aaaabbbb", AwsVpc.new("vpc-aaaabbbb").dhcp_options_id) - assert_nil(AwsVpc.new("vpc-00000000").dhcp_options_id) - end - - def test_property_state - assert_equal("available", AwsVpc.new("vpc-12344321").state) - assert_nil(AwsVpc.new("vpc-00000000").state) - end - - def test_property_instance_tenancy - assert_equal("default", AwsVpc.new("vpc-12344321").instance_tenancy) - assert_nil(AwsVpc.new("vpc-00000000").instance_tenancy) - end -end - -#=============================================================================# -# Matchers -#=============================================================================# -class AwsVpcMatchersTest < Minitest::Test - - def setup - AwsVpc::BackendFactory.select(MAVSB::Basic) - end - - def test_matcher_default_positive - assert AwsVpc.new("vpc-aaaabbbb").default? - end - - def test_matcher_default_negative - refute AwsVpc.new("vpc-12344321").default? - end - -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAVSB - class Empty < AwsBackendBase - def describe_vpcs(query) - OpenStruct.new(vpcs: []) - end - end - - class Basic < AwsBackendBase - def describe_vpcs(query) - fixtures = [ - OpenStruct.new({ - cidr_block: "10.0.0.0/16", - dhcp_options_id: "dopt-aaaabbbb", - state: "available", - vpc_id: "vpc-aaaabbbb", - instance_tenancy: "default", - is_default: true, - }), - OpenStruct.new({ - cidr_block: "10.1.0.0/16", - dhcp_options_id: "dopt-43211234", - state: "available", - vpc_id: "vpc-12344321", - instance_tenancy: "default", - is_default: false, - }), - ] - - selected = fixtures.select do |vpc| - query[:filters].all? do |filter| - if filter[:name].eql? "isDefault" - filter[:name] = "is_default" - end - filter[:values].include?(vpc[filter[:name].tr("-", "_")].to_s) - end - end - - OpenStruct.new({ vpcs: selected }) - end - end - -end diff --git a/test/unit/resources/aws_vpcs_test.rb b/test/unit/resources/aws_vpcs_test.rb deleted file mode 100644 index 24adfae96..000000000 --- a/test/unit/resources/aws_vpcs_test.rb +++ /dev/null @@ -1,147 +0,0 @@ -require "helper" -require "inspec/resource" -require "resources/aws/aws_vpcs" -require "ipaddr" - -require "resource_support/aws" - -# MAVPB = MockAwsVpcsPluralBackend -# Abbreviation not used outside this file - -#=============================================================================# -# Constructor Tests -#=============================================================================# -class AwsVpcsConstructorTest < Minitest::Test - - def setup - AwsVpcs::BackendFactory.select(MAVPB::Empty) - end - - def test_empty_params_ok - AwsVpcs.new - end - - def test_rejects_unrecognized_params - assert_raises(ArgumentError) { AwsVpcs.new(shoe_size: 9) } - end -end - -#=============================================================================# -# Filter Criteria -#=============================================================================# -class AwsVpcsFilterCriteriaTest < Minitest::Test - - def setup - AwsVpcs::BackendFactory.select(MAVPB::Basic) - end - - def test_filter_with_no_criteria - assert AwsVpcs.new.exists? - end - - def test_filter_with_vpc_id - hit = AwsVpcs.new.where(vpc_id: "vpc-aaaabbbb") - assert(hit.exists?) - - miss = AwsVpcs.new.where(vpc_id: "vpc-09876543") - refute(miss.exists?) - end - - def test_filter_with_cidr_block - hit = AwsVpcs.new.where(cidr_block: "10.0.0.0/16") - assert(hit.exists?) - - # This triggers a bug/misfeature in FilterTable - see https://github.com/chef/inspec/issues/2929 - # hit = AwsVpcs.new.where { IPAddr.new('10.0.0.0/8').include? cidr_block } - hit = AwsVpcs.new.where { cidr_block.start_with? "10" } - assert(hit.exists?) - assert_equal(2, hit.entries.count) - - miss = AwsVpcs.new.where(cidr_block: "11.0.0.0/16") - refute(miss.exists?) - end - - def test_filter_with_dhcp_options_id - hit = AwsVpcs.new.where(dhcp_options_id: "dopt-aaaabbbb") - assert(hit.exists?) - - miss = AwsVpcs.new.where(dhcp_options_id: "dopt-12345678") - refute(miss.exists?) - end -end - -#=============================================================================# -# Properties -#=============================================================================# -class AwsVpcsProperties < Minitest::Test - - def setup - AwsVpcs::BackendFactory.select(MAVPB::Basic) - @vpcs = AwsVpcs.new - end - - def test_property_vpc_ids - assert_includes(@vpcs.vpc_ids, "vpc-aaaabbbb") - assert_includes(@vpcs.vpc_ids, "vpc-12344321") - refute_includes(@vpcs.vpc_ids, nil) - end - - def test_property_cidr_blocks - assert_includes(@vpcs.cidr_blocks, "10.0.0.0/16") - assert_includes(@vpcs.cidr_blocks, "10.1.0.0/16") - refute_includes(@vpcs.cidr_blocks, nil) - end - - def test_property_dhcp_options_ids - assert_includes(@vpcs.dhcp_options_ids, "dopt-aaaabbbb") - # Should be de-duplicated - assert_equal(1, @vpcs.dhcp_options_ids.count) - end -end - -#=============================================================================# -# Test Fixtures -#=============================================================================# -module MAVPB - class Empty < AwsBackendBase - def describe_vpcs(query = {}) - OpenStruct.new({ vpcs: [] }) - end - end - - class Basic < AwsBackendBase - def describe_vpcs(query = {}) - fixtures = [ - OpenStruct.new({ - cidr_block: "10.0.0.0/16", - dhcp_options_id: "dopt-aaaabbbb", - state: "available", - vpc_id: "vpc-aaaabbbb", - instance_tenancy: "default", - is_default: true, - }), - OpenStruct.new({ - cidr_block: "10.1.0.0/16", - dhcp_options_id: "dopt-aaaabbbb", # Same as vpc-aaaabbbb - state: "available", - vpc_id: "vpc-12344321", - instance_tenancy: "default", - is_default: false, - }), - ] - - query[:filters] = [] if query[:filters].nil? - - selected = fixtures.select do |vpc| - query[:filters].all? do |filter| - if filter[:name].eql? "isDefault" - filter[:name] = "is_default" - end - filter[:values].include?(vpc[filter[:name].tr("-", "_")].to_s) - end - end - - OpenStruct.new({ vpcs: selected }) - end - end -end