inspec 4.22.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +63 -0
  3. data/inspec.gemspec +36 -0
  4. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/Gemfile +11 -0
  5. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/inspec-plugin-template.gemspec +43 -0
  6. data/lib/plugins/inspec-init/templates/profiles/aws/README.md +192 -0
  7. data/lib/plugins/inspec-init/templates/profiles/aws/attributes.yml +2 -0
  8. data/lib/plugins/inspec-init/templates/profiles/aws/controls/example.rb +39 -0
  9. data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +22 -0
  10. data/lib/plugins/inspec-init/templates/profiles/azure/README.md +56 -0
  11. data/lib/plugins/inspec-init/templates/profiles/azure/controls/example.rb +14 -0
  12. data/lib/plugins/inspec-init/templates/profiles/azure/inspec.yml +14 -0
  13. data/lib/plugins/inspec-init/templates/profiles/gcp/README.md +66 -0
  14. data/lib/plugins/inspec-init/templates/profiles/gcp/attributes.yml +2 -0
  15. data/lib/plugins/inspec-init/templates/profiles/gcp/controls/example.rb +27 -0
  16. data/lib/plugins/inspec-init/templates/profiles/gcp/inspec.yml +19 -0
  17. data/lib/resource_support/aws.rb +76 -0
  18. data/lib/resource_support/aws/aws_backend_base.rb +12 -0
  19. data/lib/resource_support/aws/aws_backend_factory_mixin.rb +12 -0
  20. data/lib/resource_support/aws/aws_plural_resource_mixin.rb +24 -0
  21. data/lib/resource_support/aws/aws_resource_mixin.rb +69 -0
  22. data/lib/resource_support/aws/aws_singular_resource_mixin.rb +27 -0
  23. data/lib/resources/aws/aws_billing_report.rb +107 -0
  24. data/lib/resources/aws/aws_billing_reports.rb +74 -0
  25. data/lib/resources/aws/aws_cloudtrail_trail.rb +97 -0
  26. data/lib/resources/aws/aws_cloudtrail_trails.rb +51 -0
  27. data/lib/resources/aws/aws_cloudwatch_alarm.rb +67 -0
  28. data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +105 -0
  29. data/lib/resources/aws/aws_config_delivery_channel.rb +74 -0
  30. data/lib/resources/aws/aws_config_recorder.rb +99 -0
  31. data/lib/resources/aws/aws_ebs_volume.rb +127 -0
  32. data/lib/resources/aws/aws_ebs_volumes.rb +69 -0
  33. data/lib/resources/aws/aws_ec2_instance.rb +162 -0
  34. data/lib/resources/aws/aws_ec2_instances.rb +69 -0
  35. data/lib/resources/aws/aws_ecs_cluster.rb +88 -0
  36. data/lib/resources/aws/aws_eks_cluster.rb +105 -0
  37. data/lib/resources/aws/aws_elb.rb +85 -0
  38. data/lib/resources/aws/aws_elbs.rb +84 -0
  39. data/lib/resources/aws/aws_flow_log.rb +106 -0
  40. data/lib/resources/aws/aws_iam_access_key.rb +112 -0
  41. data/lib/resources/aws/aws_iam_access_keys.rb +153 -0
  42. data/lib/resources/aws/aws_iam_group.rb +62 -0
  43. data/lib/resources/aws/aws_iam_groups.rb +56 -0
  44. data/lib/resources/aws/aws_iam_password_policy.rb +121 -0
  45. data/lib/resources/aws/aws_iam_policies.rb +57 -0
  46. data/lib/resources/aws/aws_iam_policy.rb +311 -0
  47. data/lib/resources/aws/aws_iam_role.rb +60 -0
  48. data/lib/resources/aws/aws_iam_root_user.rb +82 -0
  49. data/lib/resources/aws/aws_iam_user.rb +145 -0
  50. data/lib/resources/aws/aws_iam_users.rb +160 -0
  51. data/lib/resources/aws/aws_kms_key.rb +100 -0
  52. data/lib/resources/aws/aws_kms_keys.rb +58 -0
  53. data/lib/resources/aws/aws_rds_instance.rb +74 -0
  54. data/lib/resources/aws/aws_route_table.rb +67 -0
  55. data/lib/resources/aws/aws_route_tables.rb +64 -0
  56. data/lib/resources/aws/aws_s3_bucket.rb +142 -0
  57. data/lib/resources/aws/aws_s3_bucket_object.rb +87 -0
  58. data/lib/resources/aws/aws_s3_buckets.rb +52 -0
  59. data/lib/resources/aws/aws_security_group.rb +314 -0
  60. data/lib/resources/aws/aws_security_groups.rb +71 -0
  61. data/lib/resources/aws/aws_sns_subscription.rb +82 -0
  62. data/lib/resources/aws/aws_sns_topic.rb +57 -0
  63. data/lib/resources/aws/aws_sns_topics.rb +60 -0
  64. data/lib/resources/aws/aws_sqs_queue.rb +66 -0
  65. data/lib/resources/aws/aws_subnet.rb +92 -0
  66. data/lib/resources/aws/aws_subnets.rb +56 -0
  67. data/lib/resources/aws/aws_vpc.rb +77 -0
  68. data/lib/resources/aws/aws_vpcs.rb +55 -0
  69. data/lib/resources/azure/azure_backend.rb +379 -0
  70. data/lib/resources/azure/azure_generic_resource.rb +55 -0
  71. data/lib/resources/azure/azure_resource_group.rb +151 -0
  72. data/lib/resources/azure/azure_virtual_machine.rb +262 -0
  73. data/lib/resources/azure/azure_virtual_machine_data_disk.rb +131 -0
  74. metadata +202 -0
@@ -0,0 +1,14 @@
1
+ # copyright: 2018, The Authors
2
+
3
+ title "Sample Section"
4
+
5
+ # you add controls here
6
+ control "azure-virtual-machines-exist-check" do # A unique ID for this control.
7
+ impact 1.0 # The criticality, if this control fails.
8
+ title "Check resource groups to see if any VMs exist." # A human-readable title
9
+ azurerm_resource_groups.names.each do |resource_group_name| # Plural resources can be leveraged to loop across many resources
10
+ describe azurerm_virtual_machines(resource_group: resource_group_name) do
11
+ it { should exist } # The test itself.
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ name: <%= name %>
2
+ title: Azure InSpec Profile
3
+ maintainer: The Authors
4
+ copyright: The Authors
5
+ copyright_email: you@example.com
6
+ license: Apache-2.0
7
+ summary: An InSpec Compliance Profile For Azure
8
+ version: 0.1.0
9
+ inspec_version: '>= 2.2.7'
10
+ depends:
11
+ - name: inspec-azure
12
+ url: https://github.com/inspec/inspec-azure/archive/master.tar.gz
13
+ supports:
14
+ - platform: azure
@@ -0,0 +1,66 @@
1
+ # Example InSpec Profile For GCP
2
+
3
+ This example shows the implementation of an InSpec profile for GCP that depends on the [InSpec GCP Resource Pack](https://github.com/inspec/inspec-gcp). See the [README](https://github.com/inspec/inspec-gcp) for instructions on setting up appropriate GCP credentials.
4
+
5
+ ## Create a profile
6
+
7
+ ```
8
+ $ inspec init profile --platform gcp my-profile
9
+ Create new profile at /Users/spaterson/my-profile
10
+ * Create directory libraries
11
+ * Create file README.md
12
+ * Create directory controls
13
+ * Create file controls/example.rb
14
+ * Create file inspec.yml
15
+ * Create file attributes.yml
16
+ * Create file libraries/.gitkeep
17
+
18
+ ```
19
+
20
+ ## Update `attributes.yml` to point to your project
21
+
22
+ ```
23
+ gcp_project_id: 'my-gcp-project'
24
+ ```
25
+
26
+ ## Run the tests
27
+
28
+ ```
29
+ $ cd gcp-profile/
30
+ $ inspec exec . -t gcp:// --attrs attributes.yml
31
+
32
+ Profile: GCP InSpec Profile (my-profile)
33
+ Version: 0.1.0
34
+ Target: gcp://local-service-account@my-gcp-project.iam.gserviceaccount.com
35
+
36
+ ✔ gcp-single-region-1.0: Ensure single region has the correct properties.
37
+ ✔ Region europe-west2 zone_names should include "europe-west2-a"
38
+ ✔ gcp-regions-loop-1.0: Ensure regions have the correct properties in bulk.
39
+ ✔ Region asia-east1 should be up
40
+ ✔ Region asia-northeast1 should be up
41
+ ✔ Region asia-south1 should be up
42
+ ✔ Region asia-southeast1 should be up
43
+ ✔ Region australia-southeast1 should be up
44
+ ✔ Region europe-north1 should be up
45
+ ✔ Region europe-west1 should be up
46
+ ✔ Region europe-west2 should be up
47
+ ✔ Region europe-west3 should be up
48
+ ✔ Region europe-west4 should be up
49
+ ✔ Region northamerica-northeast1 should be up
50
+ ✔ Region southamerica-east1 should be up
51
+ ✔ Region us-central1 should be up
52
+ ✔ Region us-east1 should be up
53
+ ✔ Region us-east4 should be up
54
+ ✔ Region us-west1 should be up
55
+ ✔ Region us-west2 should be up
56
+
57
+
58
+ Profile: Google Cloud Platform Resource Pack (inspec-gcp)
59
+ Version: 0.5.0
60
+ Target: gcp://local-service-account@my-gcp-project.iam.gserviceaccount.com
61
+
62
+ No tests executed.
63
+
64
+ Profile Summary: 2 successful controls, 0 control failures, 0 controls skipped
65
+ Test Summary: 18 successful, 0 failures, 0 skipped
66
+ ```
@@ -0,0 +1,2 @@
1
+ # Below is to be uncommented and set with your GCP project ID:
2
+ # gcp_project_id: 'your-gcp-project'
@@ -0,0 +1,27 @@
1
+ # copyright: 2018, The Authors
2
+
3
+ title "Sample Section"
4
+
5
+ gcp_project_id = attribute("gcp_project_id")
6
+
7
+ # you add controls here
8
+ control "gcp-single-region-1.0" do # A unique ID for this control
9
+ impact 1.0 # The criticality, if this control fails.
10
+ title "Ensure single region has the correct properties." # A human-readable title
11
+ desc "An optional description..."
12
+ describe google_compute_region(project: gcp_project_id, name: "europe-west2") do # The actual test
13
+ its("zone_names") { should include "europe-west2-a" }
14
+ end
15
+ end
16
+
17
+ # plural resources can be leveraged to loop across many resources
18
+ control "gcp-regions-loop-1.0" do # A unique ID for this control
19
+ impact 1.0 # The criticality, if this control fails.
20
+ title "Ensure regions have the correct properties in bulk." # A human-readable title
21
+ desc "An optional description..."
22
+ google_compute_regions(project: gcp_project_id).region_names.each do |region_name| # Loop across all regions by name
23
+ describe google_compute_region(project: gcp_project_id, name: region_name) do # The test for a single region
24
+ it { should be_up }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ name: <%= name %>
2
+ title: GCP InSpec Profile
3
+ maintainer: The Authors
4
+ copyright: The Authors
5
+ copyright_email: you@example.com
6
+ license: Apache-2.0
7
+ summary: An InSpec Compliance Profile For GCP
8
+ version: 0.1.0
9
+ inspec_version: '>= 2.3.5'
10
+ attributes:
11
+ - name: gcp_project_id
12
+ required: true
13
+ description: 'The GCP project identifier.'
14
+ type: string
15
+ depends:
16
+ - name: inspec-gcp
17
+ url: https://github.com/inspec/inspec-gcp/archive/master.tar.gz
18
+ supports:
19
+ - platform: gcp
@@ -0,0 +1,76 @@
1
+ # Main AWS loader file. The intent is for this to be
2
+ # loaded only if AWS resources are needed.
3
+
4
+ require "aws-sdk-core"
5
+
6
+ require "aws-sdk-cloudtrail"
7
+ require "aws-sdk-cloudwatch"
8
+ require "aws-sdk-cloudwatchlogs"
9
+ require "aws-sdk-costandusagereportservice"
10
+ require "aws-sdk-configservice"
11
+ require "aws-sdk-ec2"
12
+ require "aws-sdk-ecs"
13
+ require "aws-sdk-eks"
14
+ require "aws-sdk-elasticloadbalancing"
15
+ require "aws-sdk-iam"
16
+ require "aws-sdk-kms"
17
+ require "aws-sdk-rds"
18
+ require "aws-sdk-s3"
19
+ require "aws-sdk-sqs"
20
+ require "aws-sdk-sns"
21
+
22
+ require "resource_support/aws/aws_backend_factory_mixin"
23
+ require "resource_support/aws/aws_resource_mixin"
24
+ require "resource_support/aws/aws_singular_resource_mixin"
25
+ require "resource_support/aws/aws_plural_resource_mixin"
26
+ require "resource_support/aws/aws_backend_base"
27
+
28
+ # Load all AWS resources
29
+ # TODO: loop over and load entire directory
30
+ # for f in ls lib/resources/aws/*; do t=$(echo $f | cut -c 5- | cut -f1 -d. ); echo "require '${t}'"; done
31
+ require "resources/aws/aws_billing_report"
32
+ require "resources/aws/aws_billing_reports"
33
+ require "resources/aws/aws_cloudtrail_trail"
34
+ require "resources/aws/aws_cloudtrail_trails"
35
+ require "resources/aws/aws_cloudwatch_alarm"
36
+ require "resources/aws/aws_cloudwatch_log_metric_filter"
37
+ require "resources/aws/aws_config_delivery_channel"
38
+ require "resources/aws/aws_config_recorder"
39
+ require "resources/aws/aws_ec2_instance"
40
+ require "resources/aws/aws_ebs_volume"
41
+ require "resources/aws/aws_ebs_volumes"
42
+ require "resources/aws/aws_flow_log"
43
+ require "resources/aws/aws_ec2_instances"
44
+ require "resources/aws/aws_ecs_cluster"
45
+ require "resources/aws/aws_eks_cluster"
46
+ require "resources/aws/aws_elb"
47
+ require "resources/aws/aws_elbs"
48
+ require "resources/aws/aws_iam_access_key"
49
+ require "resources/aws/aws_iam_access_keys"
50
+ require "resources/aws/aws_iam_group"
51
+ require "resources/aws/aws_iam_groups"
52
+ require "resources/aws/aws_iam_password_policy"
53
+ require "resources/aws/aws_iam_policies"
54
+ require "resources/aws/aws_iam_policy"
55
+ require "resources/aws/aws_iam_role"
56
+ require "resources/aws/aws_iam_root_user"
57
+ require "resources/aws/aws_iam_user"
58
+ require "resources/aws/aws_iam_users"
59
+ require "resources/aws/aws_kms_key"
60
+ require "resources/aws/aws_kms_keys"
61
+ require "resources/aws/aws_rds_instance"
62
+ require "resources/aws/aws_route_table"
63
+ require "resources/aws/aws_route_tables"
64
+ require "resources/aws/aws_s3_bucket"
65
+ require "resources/aws/aws_s3_bucket_object"
66
+ require "resources/aws/aws_s3_buckets"
67
+ require "resources/aws/aws_security_group"
68
+ require "resources/aws/aws_security_groups"
69
+ require "resources/aws/aws_sns_subscription"
70
+ require "resources/aws/aws_sns_topic"
71
+ require "resources/aws/aws_sns_topics"
72
+ require "resources/aws/aws_sqs_queue"
73
+ require "resources/aws/aws_subnet"
74
+ require "resources/aws/aws_subnets"
75
+ require "resources/aws/aws_vpc"
76
+ require "resources/aws/aws_vpcs"
@@ -0,0 +1,12 @@
1
+ class AwsBackendBase
2
+ attr_reader :aws_transport
3
+ class << self; attr_accessor :aws_client_class end
4
+
5
+ def initialize(inspec = nil)
6
+ @aws_transport = inspec ? inspec.backend : nil
7
+ end
8
+
9
+ def aws_service_client
10
+ aws_transport.aws_client(self.class.aws_client_class)
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # Intended to be pulled in via extend, not include
2
+ module AwsBackendFactoryMixin
3
+ def create(inspec)
4
+ @selected_backend.new(inspec)
5
+ end
6
+
7
+ def select(klass)
8
+ @selected_backend = klass
9
+ end
10
+
11
+ alias set_default_backend select
12
+ end
@@ -0,0 +1,24 @@
1
+ require "resource_support/aws/aws_resource_mixin"
2
+ require "resource_support/aws/aws_backend_factory_mixin"
3
+
4
+ module AwsPluralResourceMixin
5
+ include AwsResourceMixin
6
+ attr_reader :table
7
+
8
+ # This sets up a class, AwsSomeResource::BackendFactory, that
9
+ # provides a mechanism to create and use backends without
10
+ # having to know which is selected. This is mainly used for
11
+ # unit testing.
12
+ # TODO: DRY up. This code exists in both the Singular and Plural mixins.
13
+ # We'd like to put it in AwsResourceMixin, but included only sees the
14
+ # directly-including class - we can't see second-order includers.
15
+ def self.included(base)
16
+ # Create a new class, whose body is simply to extend the
17
+ # backend factory mixin
18
+ resource_backend_factory_class = Class.new(Object) do
19
+ extend AwsBackendFactoryMixin
20
+ end
21
+ # Name that class
22
+ base.const_set("BackendFactory", resource_backend_factory_class)
23
+ end
24
+ end
@@ -0,0 +1,69 @@
1
+ module AwsResourceMixin
2
+ def initialize(resource_params = {})
3
+ Inspec.deprecate(:aws_resources_in_resource_pack,
4
+ "Resource '#{@__resource_name__ ||= self.class.to_s}'")
5
+ validate_params(resource_params).each do |param, value|
6
+ instance_variable_set(:"@#{param}", value)
7
+ end
8
+ catch_aws_errors do
9
+ fetch_from_api
10
+ end
11
+ rescue ArgumentError => e
12
+ # continue with ArgumentError if testing
13
+ raise unless respond_to?(:inspec) && inspec
14
+
15
+ raise Inspec::Exceptions::ResourceFailed, e.message
16
+ end
17
+
18
+ # Default implementation of validate params accepts everything.
19
+ def validate_params(resource_params)
20
+ resource_params
21
+ end
22
+
23
+ def check_resource_param_names(raw_params: {}, allowed_params: [], allowed_scalar_name: nil, allowed_scalar_type: nil)
24
+ # Some resources allow passing in a single ID value. Check and convert to hash if so.
25
+ if allowed_scalar_name && !raw_params.is_a?(Hash)
26
+ value_seen = raw_params
27
+ if value_seen.is_a?(allowed_scalar_type)
28
+ raw_params = { allowed_scalar_name => value_seen }
29
+ else
30
+ raise ArgumentError, "If you pass a single value to the resource, it must " \
31
+ "be a #{allowed_scalar_type}, not an #{value_seen.class}."
32
+ end
33
+ end
34
+
35
+ # Remove all expected params from the raw param hash
36
+ recognized_params = {}
37
+ allowed_params.each do |expected_param|
38
+ recognized_params[expected_param] = raw_params.delete(expected_param) if raw_params.key?(expected_param)
39
+ end
40
+
41
+ # Any leftovers are unwelcome
42
+ unless raw_params.empty?
43
+ raise ArgumentError, "Unrecognized resource param '#{raw_params.keys.first}'. Expected parameters: #{allowed_params.join(", ")}"
44
+ end
45
+
46
+ recognized_params
47
+ end
48
+
49
+ def inspec_runner
50
+ # When running under inspec-cli, we have an 'inspec' method that
51
+ # returns the runner. When running under unit tests, we don't
52
+ # have that, but we still have to call this to pass something
53
+ # (nil is OK) to the backend.
54
+ # TODO: remove with https://github.com/chef/inspec-aws/issues/216
55
+ inspec if respond_to?(:inspec)
56
+ end
57
+
58
+ # Intercept AWS exceptions
59
+ def catch_aws_errors
60
+ yield
61
+ rescue Aws::Errors::MissingCredentialsError
62
+ # The AWS error here is unhelpful:
63
+ # "unable to sign request without credentials set"
64
+ 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://www.inspec.io/docs/reference/platforms for details."
65
+ fail_resource("No AWS credentials available")
66
+ rescue Aws::Errors::ServiceError => e
67
+ fail_resource e.message
68
+ end
69
+ end
@@ -0,0 +1,27 @@
1
+ require "resource_support/aws/aws_resource_mixin"
2
+ require "resource_support/aws/aws_backend_factory_mixin"
3
+
4
+ module AwsSingularResourceMixin
5
+ include AwsResourceMixin
6
+
7
+ def exists?
8
+ @exists
9
+ end
10
+
11
+ # This sets up a class, AwsSomeResource::BackendFactory, that
12
+ # provides a mechanism to create and use backends without
13
+ # having to know which is selected. This is mainly used for
14
+ # unit testing.
15
+ # TODO: DRY up. This code exists in both the Singular and Plural mixins.
16
+ # We'd like to put it in AwsResourceMixin, but included only sees the
17
+ # directly-including class - we can't see second-order includers.
18
+ def self.included(base)
19
+ # Create a new class, whose body is simply to extend the
20
+ # backend factory mixin
21
+ resource_backend_factory_class = Class.new(Object) do
22
+ extend AwsBackendFactoryMixin
23
+ end
24
+ # Name that class
25
+ base.const_set("BackendFactory", resource_backend_factory_class)
26
+ end
27
+ end
@@ -0,0 +1,107 @@
1
+ require "resource_support/aws/aws_singular_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+
4
+ require "resource_support/aws/aws_singular_resource_mixin"
5
+ require "resource_support/aws/aws_backend_base"
6
+ require "aws-sdk-costandusagereportservice.rb"
7
+
8
+ class AwsBillingReport < Inspec.resource(1)
9
+ name "aws_billing_report"
10
+ supports platform: "aws"
11
+ desc "Verifies settings for AWS Cost and Billing Reports."
12
+ example <<~EXAMPLE
13
+ describe aws_billing_report('inspec1') do
14
+ its('report_name') { should cmp 'inspec1' }
15
+ its('time_unit') { should cmp 'hourly' }
16
+ end
17
+
18
+ describe aws_billing_report(report: 'inspec1') do
19
+ it { should exist }
20
+ end
21
+ EXAMPLE
22
+
23
+ include AwsSingularResourceMixin
24
+
25
+ attr_reader :report_name, :time_unit, :format, :compression, :s3_bucket,
26
+ :s3_prefix, :s3_region
27
+
28
+ def to_s
29
+ "AWS Billing Report #{report_name}"
30
+ end
31
+
32
+ def hourly?
33
+ exists? ? time_unit.eql?("hourly") : nil
34
+ end
35
+
36
+ def daily?
37
+ exists? ? time_unit.eql?("daily") : nil
38
+ end
39
+
40
+ def zip?
41
+ exists? ? compression.eql?("zip") : nil
42
+ end
43
+
44
+ def gzip?
45
+ exists? ? compression.eql?("gzip") : nil
46
+ end
47
+
48
+ private
49
+
50
+ def validate_params(raw_params)
51
+ validated_params = check_resource_param_names(
52
+ raw_params: raw_params,
53
+ allowed_params: [:report_name],
54
+ allowed_scalar_name: :report_name,
55
+ allowed_scalar_type: String
56
+ )
57
+
58
+ if validated_params.empty?
59
+ raise ArgumentError, "You must provide the parameter 'report_name' to aws_billing_report."
60
+ end
61
+
62
+ validated_params
63
+ end
64
+
65
+ def fetch_from_api
66
+ report = find_report(report_name)
67
+ @exists = !report.nil?
68
+ if exists?
69
+ @time_unit = report.time_unit.downcase
70
+ @format = report.format.downcase
71
+ @compression = report.compression.downcase
72
+ @s3_bucket = report.s3_bucket
73
+ @s3_prefix = report.s3_prefix
74
+ @s3_region = report.s3_region
75
+ end
76
+ end
77
+
78
+ def find_report(report_name)
79
+ pagination_opts = {}
80
+ found_report_def = nil
81
+ while found_report_def.nil?
82
+ api_result = backend.describe_report_definitions(pagination_opts)
83
+ next_token = api_result.next_token
84
+ found_report_def = api_result.report_definitions.find { |report_def| report_def.report_name == report_name }
85
+ pagination_opts = { next_token: next_token }
86
+
87
+ next if found_report_def.nil? && next_token # Loop again: didn't find it, but there are more results
88
+ break if found_report_def.nil? && next_token.nil? # Give up: didn't find it, no more results
89
+ end
90
+ found_report_def
91
+ end
92
+
93
+ def backend
94
+ @backend ||= BackendFactory.create(inspec_runner)
95
+ end
96
+
97
+ class Backend
98
+ class AwsClientApi < AwsBackendBase
99
+ AwsBillingReport::BackendFactory.set_default_backend(self)
100
+ self.aws_client_class = Aws::CostandUsageReportService::Client
101
+
102
+ def describe_report_definitions(query = {})
103
+ aws_service_client.describe_report_definitions(query)
104
+ end
105
+ end
106
+ end
107
+ end