inspec-iggy 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ # helpers for working with InSpec-AWS profiles
2
+
3
+ require 'yaml'
4
+
5
+ module InspecPlugins::Iggy::Platforms
6
+ class AwsHelper
7
+ # find the additional parameters
8
+ AWS_RESOURCE_QUALIFIERS = {
9
+ }.freeze
10
+
11
+ # the iterators for the various resource types
12
+ AWS_RESOURCE_ITERATORS = {
13
+ }.freeze
14
+
15
+ AWS_REMOVED_PROPERTIES = {
16
+ }.freeze
17
+
18
+ # Terraform boilerplate controls/controls.rb content
19
+ def self.tf_controls
20
+ "\n\naws_vpc_id = attribute('aws_vpc_id', default: '', description: 'Optional AWS VPC identifier.')\n\n"
21
+ end
22
+
23
+ # readme content
24
+ def self.readme
25
+ end
26
+
27
+ # inspec.yml boilerplate content from
28
+ # inspec/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml
29
+ def self.inspec_yml
30
+ yml = {}
31
+ yml['inspec_version'] = '~> 4'
32
+ yml['depends'] = [{
33
+ 'name' => 'inspec-aws',
34
+ 'url' => 'https://github.com/inspec/inspec-aws/archive/master.tar.gz'
35
+ }]
36
+ yml['supports'] = [{
37
+ 'platform' => 'aws'
38
+ }]
39
+ yml
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ # helpers for working with InSpec-Azure profiles
2
+
3
+ require 'yaml'
4
+
5
+ module InspecPlugins::Iggy::Platforms
6
+ class AzureHelper
7
+ # find the additional parameters
8
+ AZURE_RESOURCE_QUALIFIERS = {
9
+ }.freeze
10
+
11
+ # the iterators for the various resource types
12
+ AZURE_RESOURCE_ITERATORS = {
13
+ }.freeze
14
+
15
+ AZURE_REMOVED_PROPERTIES = {
16
+ }.freeze
17
+
18
+ # readme content
19
+ def self.readme
20
+ "\n"
21
+ end
22
+
23
+ # inspec.yml boilerplate content from
24
+ # inspec/lib/plugins/inspec-init/templates/profiles/azure/inspec.yml
25
+ def self.inspec_yml
26
+ yml = {}
27
+ yml['inspec_version'] = '>= 2.2.7'
28
+ yml['depends'] = [{
29
+ 'name' => 'inspec-azure',
30
+ 'url' => 'https://github.com/inspec/inspec-azure/archive/master.tar.gz'
31
+ }]
32
+ yml['supports'] = [{
33
+ 'platform' => 'azure'
34
+ }]
35
+ yml
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,168 @@
1
+ # helpers for working with InSpec-GCP profiles
2
+
3
+ require 'yaml'
4
+
5
+ module InspecPlugins::Iggy::Platforms
6
+ class GcpHelper
7
+ # find the additional parameters for the 'describe'
8
+ GCP_RESOURCE_QUALIFIERS = {
9
+ 'google_bigquery_dataset' => [:project, :name],
10
+ 'google_bigquery_table' => [:project, :dataset, :name],
11
+ 'google_cloudfunctions_cloud_function' => [:project, :location, :name],
12
+ 'google_compute_address' => [:project, :location, :name],
13
+ 'google_compute_autoscaler' => [:project, :zone, :name],
14
+ 'google_compute_backend_bucket' => [:project, :name],
15
+ 'google_compute_backend_service' => [:project, :name],
16
+ 'google_compute_disk' => [:project, :name, :zone],
17
+ 'google_compute_firewall' => [:project, :name],
18
+ 'google_compute_forwarding_rule' => [:project, :region, :name],
19
+ 'google_compute_global_address' => [:project, :name],
20
+ 'google_compute_global_forwarding_rule' => [:project, :name],
21
+ 'google_compute_health_check' => [:project, :name],
22
+ 'google_compute_http_health_check' => [:project, :name],
23
+ 'google_compute_https_health_check' => [:project, :name],
24
+ 'google_compute_image' => [:project, :name],
25
+ 'google_compute_instance' => [:project, :zone, :name],
26
+ 'google_compute_instance_group' => [:project, :zone, :name],
27
+ 'google_compute_instance_group_manager' => [:project, :zone, :name],
28
+ 'google_compute_instance_template' => [:project, :name],
29
+ 'google_compute_network' => [:project, :name],
30
+ 'google_compute_project_info' => [:project],
31
+ 'google_compute_region' => [:project, :name],
32
+ 'google_compute_region_backend_service' => [:project, :region, :name],
33
+ 'google_compute_region_instance_group_manager' => [:project, :region, :name],
34
+ 'google_compute_route' => [:project, :name],
35
+ 'google_compute_router' => [:project, :region, :name],
36
+ 'google_compute_snapshot' => [:project, :name],
37
+ 'google_compute_ssl_certificate' => [:project, :name],
38
+ 'google_compute_ssl_policy' => [:project, :name],
39
+ 'google_compute_subnetwork' => [:project, :region, :name],
40
+ 'google_compute_subnetwork_iam_policy' => [:project, :region, :name],
41
+ 'google_compute_target_http_proxy' => [:project, :name],
42
+ 'google_compute_target_https_proxy' => [:project, :name],
43
+ 'google_compute_target_pool' => [:project, :region, :name],
44
+ 'google_compute_target_tcp_proxy' => [:project, :name],
45
+ 'google_compute_url_map' => [:project, :name],
46
+ 'google_compute_vpn_tunnel' => [:project, :region, :name],
47
+ 'google_compute_zone' => [:project, :zone],
48
+ 'google_container_cluster' => [:project, :zone, :name],
49
+ 'google_container_node_pool' => [:project, :zone, :cluster_name, :nodepool_name],
50
+ 'google_container_regional_cluster' => [:project, :location, :name],
51
+ 'google_container_regional_node_pool' => [:project, :location, :cluster, :name],
52
+ 'google_dns_managed_zone' => [:project, :zone],
53
+ 'google_dns_resource_record_set' => [:project, :name, :type, :managed_zone],
54
+ 'google_kms_crypto_key' => [:project, :location, :key_ring_name, :name],
55
+ 'google_kms_crypto_key_iam_binding' => [:crypto_key_url, :role],
56
+ 'google_kms_key_ring' => [:project, :location, :name],
57
+ 'google_kms_key_ring_iam_binding' => [:key_ring_url, :role],
58
+ 'google_logging_project_exclusion' => [:project, :exclusion],
59
+ 'google_logging_project_sink' => [:project, :sink],
60
+ 'google_organization' => [:display_name],
61
+ 'google_organization_policy' => [:name, :constraints],
62
+ 'google_project' => [:project],
63
+ 'google_project_alert_policy' => [:policy],
64
+ 'google_project_alert_policy_condition' => [:name, :filter],
65
+ 'google_project_iam_binding' => [:project, :role],
66
+ 'google_project_iam_custom_role' => [:project, :name],
67
+ 'google_project_logging_audit_config' => [:project],
68
+ 'google_project_metric' => [:project, :metric],
69
+ 'google_pubsub_subscription' => [:project, :name],
70
+ 'google_pubsub_subscription_iam_policy' => [:project, :name],
71
+ 'google_pubsub_topic' => [:project, :name],
72
+ 'google_pubsub_topic_iam_policy' => [:project, :name],
73
+ 'google_resourcemanager_organization_policy' => [:organization_name, :constraint],
74
+ 'google_service_account' => [:name],
75
+ 'google_service_account_key' => [:name],
76
+ 'google_sourcerepo_repository' => [:project, :name],
77
+ 'google_sql_database_instance' => [:project, :database],
78
+ 'google_storage_bucket' => [:name],
79
+ 'google_storage_bucket_acl' => [:bucket, :entity],
80
+ 'google_storage_bucket_iam_binding' => [:bucket, :role],
81
+ 'google_storage_bucket_object' => [:bucket, :object],
82
+ 'google_storage_default_object_acl' => [:bucket, :entity],
83
+ 'google_storage_object_acl' => [:bucket, :object, :entity],
84
+ 'google_user' => [:user_key]
85
+ }.freeze
86
+
87
+ # the iterators for the various resource types
88
+ GCP_RESOURCE_ITERATORS = {
89
+ # 'google_compute_disk' => { 'iterator' => 'google_compute_disks', 'index' => 'names', 'qualifiers' => [:project, :zone] }, # false positives because instance attached disks aren't managed by Terraform
90
+ # 'google_compute_network' => { 'iterator' => 'google_compute_networks', 'index' => 'network_names', 'qualifiers' => [:project] },
91
+ # 'google_compute_region' => { 'iterator' => 'google_compute_regions', 'index' => 'region_names', 'qualifiers' => [:project] },
92
+ # 'google_compute_region_instance_group_manager' => { 'iterator' => 'google_compute_region_instance_group_managers', 'index' => 'instance_group_names', 'qualifiers' => [:project, :region] }, verify it has 2 filter criteria
93
+ # 'google_compute_route' => { 'iterator' => 'google_compute_routes', 'index' => 'names', 'qualifiers' => [:project] },
94
+ # 'google_compute_subnetwork' => { 'iterator' => 'google_compute_subnetworks', 'index' => 'subnetwork_names', 'qualifiers' => [:project, :region] },
95
+ # 'google_compute_zone' => { 'iterator' => 'google_compute_zones', 'index' => 'zone_names', 'qualifiers' => [:project] },
96
+ # 'google_kms_crypto_key_iam_binding' => { 'iterator' => 'google_kms_crypto_key_iam_bindings', 'index' => 'iam_binding_roles', 'qualifiers' => [:crypto_key_url] },
97
+ # 'google_kms_key_ring' => { 'iterator' => 'google_kms_key_rings', 'index' => 'key_ring_names', 'qualifiers' => [:project, :location] },
98
+ # 'google_kms_key_ring_iam_binding' => { 'iterator' => 'google_kms_key_ring_iam_bindings', 'index' => 'iam_binding_roles', 'qualifiers' => [:key_ring_url] },
99
+ # 'google_organization' => { 'iterator' => 'google_organizations', 'index' => 'names', 'qualifiers' => [] }, # organizations are not managed by Terraform
100
+ # 'google_project' => { 'iterator' => 'google_projects', 'index' => 'project_names', 'qualifiers' => [] }, # projects are not managed by Terraform
101
+ # 'google_project_iam_binding' => { 'iterator' => 'google_project_iam_bindings', 'index' => 'iam_binding_roles', 'qualifiers' => [:project] },
102
+ 'google_bigquery_dataset' => { 'iterator' => 'google_bigquery_datasets', 'index' => 'names', 'qualifiers' => [:project] },
103
+ 'google_bigquery_table' => { 'iterator' => 'google_bigquery_tables', 'index' => 'table_references', 'qualifiers' => [:project, :dataset] },
104
+ 'google_cloudbuild_trigger' => { 'iterator' => 'google_cloudbuild_triggers', 'index' => 'names', 'qualifiers' => [:project] },
105
+ 'google_cloudfunctions_cloud_function' => { 'iterator' => 'google_cloudfunctions_cloud_functions', 'index' => 'names', 'qualifiers' => [:project, :location] },
106
+ 'google_compute_autoscaler' => { 'iterator' => 'google_compute_autoscalers', 'index' => 'names', 'qualifiers' => [:project, :zone] },
107
+ 'google_compute_backend_bucket' => { 'iterator' => 'google_compute_backend_buckets', 'index' => 'names', 'qualifiers' => [:project] },
108
+ 'google_compute_backend_service' => { 'iterator' => 'google_compute_backend_services', 'index' => 'names', 'qualifiers' => [:project] },
109
+ 'google_compute_firewall' => { 'iterator' => 'google_compute_firewalls', 'index' => 'firewall_names', 'qualifiers' => [:project] },
110
+ 'google_compute_forwarding_rule' => { 'iterator' => 'google_compute_forwarding_rules', 'index' => 'forwarding_rule_names', 'qualifiers' => [:project, :region] },
111
+ 'google_compute_health_check' => { 'iterator' => 'google_compute_health_checks', 'index' => 'names', 'qualifiers' => [:project] },
112
+ 'google_compute_http_health_check' => { 'iterator' => 'google_compute_http_health_checks', 'index' => 'names', 'qualifiers' => [:project] },
113
+ 'google_compute_https_health_check' => { 'iterator' => 'google_compute_https_health_checks', 'index' => 'names', 'qualifiers' => [:project] },
114
+ 'google_compute_instance' => { 'iterator' => 'google_compute_instances', 'index' => 'instance_names', 'qualifiers' => [:project, :zone] },
115
+ 'google_compute_instance_group' => { 'iterator' => 'google_compute_instance_groups', 'index' => 'instance_group_names', 'qualifiers' => [:project, :zone] },
116
+ 'google_compute_instance_group_manager' => { 'iterator' => 'google_compute_instance_group_managers', 'index' => 'base_instance_names', 'qualifiers' => [:project, :zone] },
117
+ 'google_compute_instance_template' => { 'iterator' => 'google_compute_instance_templates', 'index' => 'names', 'qualifiers' => [:project] },
118
+ 'google_compute_router' => { 'iterator' => 'google_compute_routers', 'index' => 'names', 'qualifiers' => [:project, :region] },
119
+ 'google_compute_snapshot' => { 'iterator' => 'google_compute_snapshots', 'index' => 'names', 'qualifiers' => [:project] },
120
+ 'google_compute_ssl_certificate' => { 'iterator' => 'google_compute_ssl_certificates', 'index' => 'names', 'qualifiers' => [:project] },
121
+ 'google_compute_ssl_policy' => { 'iterator' => 'google_compute_ssl_policies', 'index' => 'names', 'qualifiers' => [:project] },
122
+ 'google_compute_target_http_proxy' => { 'iterator' => 'google_compute_target_http_proxies', 'index' => 'names', 'qualifiers' => [:project] },
123
+ 'google_compute_target_https_proxy' => { 'iterator' => 'google_compute_target_https_proxies', 'index' => 'names', 'qualifiers' => [:project] },
124
+ 'google_compute_target_pool' => { 'iterator' => 'google_compute_target_pools', 'index' => 'names', 'qualifiers' => [:project, :region] },
125
+ 'google_compute_target_tcp_proxy' => { 'iterator' => 'google_compute_target_tcp_proxies', 'index' => 'names', 'qualifiers' => [:project] },
126
+ 'google_compute_url_map' => { 'iterator' => 'google_compute_url_maps', 'index' => 'names', 'qualifiers' => [:project] },
127
+ 'google_compute_vpn_tunnel' => { 'iterator' => 'google_compute_vpn_tunnels', 'index' => 'vpn_tunnel_names', 'qualifiers' => [:project, :region] },
128
+ 'google_container_cluster' => { 'iterator' => 'google_container_clusters', 'index' => 'cluster_names', 'qualifiers' => [:project, :zone] },
129
+ 'google_container_node_pool' => { 'iterator' => 'google_container_node_pools', 'index' => 'node_pool_names', 'qualifiers' => [:project, :zone, :cluster_name] },
130
+ 'google_container_regional_cluster' => { 'iterator' => 'google_container_regional_clusters', 'index' => 'names', 'qualifiers' => [:project, :location] },
131
+ 'google_dns_managed_zone' => { 'iterator' => 'google_dns_managed_zones', 'index' => 'zone_names', 'qualifiers' => [:project] },
132
+ 'google_dns_resource_record_set' => { 'iterator' => 'google_dns_resource_record_sets', 'index' => 'names', 'qualifiers' => [:project, :managed_zone] },
133
+ 'google_kms_crypto_key' => { 'iterator' => 'google_kms_crypto_keys', 'index' => 'crypto_key_names', 'qualifiers' => [:project, :location, :key_ring_name] },
134
+ 'google_logging_project_sink' => { 'iterator' => 'google_logging_project_sinks', 'index' => 'sink_names', 'qualifiers' => [:project] },
135
+ 'google_project_alert_policy' => { 'iterator' => 'google_project_alert_policies', 'index' => 'policy_names', 'qualifiers' => [:project] },
136
+ 'google_project_metric' => { 'iterator' => 'google_project_metrics', 'index' => 'metric_names', 'qualifiers' => [:project] },
137
+ 'google_pubsub_subscription' => { 'iterator' => 'google_pubsub_subscriptions', 'index' => 'names', 'qualifiers' => [:project] },
138
+ }.freeze
139
+
140
+ GCP_REMOVED_PROPERTIES = {
141
+ 'google_compute_http_health_check' => [:self_link, :id, :creation_timestamp], # id: terraform has name not id, self_link: undocumented but broken, creation_timestamp api incompatibility
142
+ 'google_compute_instance' => [:label_fingerprint, :machine_type, :min_cpu_platform, :zone], # label_fingerprint, machine_type, zone api incompatibility | min_cpu_platform undefined
143
+ 'google_compute_instance_group' => [:zone], # zone api incompatibility issue
144
+ 'google_compute_forwarding_rule' => [:backend_service, :ip_version, :network, :region, :subnetwork], # :backend_service, :ip_version, :network, :region, :subnetwork api incompatibility
145
+ 'google_compute_target_pool' => [:backup_pool, :failover_ratio, :id, :region, :self_link], # api incompatibility
146
+
147
+ }.freeze
148
+
149
+ # readme content
150
+ def self.readme
151
+ end
152
+
153
+ # inspec.yml boilerplate content from
154
+ # inspec/lib/plugins/inspec-init/templates/profiles/gcp/inspec.yml
155
+ def self.inspec_yml
156
+ yml = {}
157
+ yml['inspec_version'] = '>= 2.3.5'
158
+ yml['depends'] = [{
159
+ 'name' => 'inspec-gcp',
160
+ 'url' => 'https://github.com/inspec/inspec-gcp/archive/master.tar.gz'
161
+ }]
162
+ yml['supports'] = [{
163
+ 'platform' => 'gcp'
164
+ }]
165
+ yml
166
+ end
167
+ end
168
+ end
@@ -1,46 +1,64 @@
1
+ # -*- coding: utf-8 -*-
1
2
  # renders the profile from the parsed files
2
3
 
3
4
  require 'yaml'
4
5
 
6
+ require 'inspec-iggy/platforms/aws_helper'
7
+ require 'inspec-iggy/platforms/azure_helper'
8
+ require 'inspec-iggy/platforms/gcp_helper'
9
+
5
10
  module InspecPlugins
6
11
  module Iggy
7
12
  class ProfileHelper
8
13
  # match the output of 'inspec init profile'
9
- def self.render_profile(cli_ui, options, source_file, controls)
14
+ # inspec/lib/plugins/inspec-init/lib/inspec-init/renderer.rb
15
+ def self.render_profile(cli, options, source_file, controls, platform = nil)
10
16
  name = options[:name]
11
17
  overwrite_mode = options[:overwrite]
12
- # Create new profile at /Users/mattray/ws/inspec-iggy/foobar
13
- full_destination_root_path = Pathname.new(Dir.pwd).join(name)
14
- cli_ui.plain_text "Create new profile at #{cli_ui.mark_text(full_destination_root_path)}"
15
- if File.exist?(full_destination_root_path) && !overwrite_mode
16
- cli_ui.plain_text "#{cli_ui.mark_text(full_destination_root_path)} exists already, use --overwrite"
17
- cli_ui.exit(1)
18
+
19
+ # --------------------------- InSpec Code Generator ---------------------------
20
+ cli.headline('InSpec Iggy Code Generator')
21
+
22
+ full_destination_path = Pathname.new(Dir.pwd).join(name)
23
+
24
+ if File.exist?(full_destination_path) && !overwrite_mode
25
+ cli.plain_line "#{cli.emphasis(full_destination_path)} exists already, use --overwrite"
26
+ cli.exit(1)
18
27
  end
19
- # ensure that full_destination_root_path directory is available
20
- FileUtils.mkdir_p(full_destination_root_path)
21
- # * Create directory controls
22
- cli_ui.li "Create directory #{cli_ui.mark_text("#{name}/controls")}"
28
+
29
+ # ensure that full_destination_path directory is available
30
+ FileUtils.mkdir_p(full_destination_path)
31
+
32
+ # Creating new profile at /Users/mattray/ws/inspec-iggy/FOO
33
+ cli.plain_line "Creating new profile at #{cli.emphasis(full_destination_path)}"
34
+ # * Creating file README.md
35
+ render_readme_md(cli, name, source_file, platform)
36
+ # * Creating directory controls
37
+ cli.list_item "Creating directory #{cli.emphasis('controls')}"
23
38
  FileUtils.mkdir_p("#{name}/controls")
24
- render_readme_md(cli_ui, name, source_file)
25
- render_inspec_yml(cli_ui, name, source_file, options)
26
- render_controls_rb(cli_ui, name, controls)
39
+ # * Creating file controls/generated.rb
40
+ render_controls_rb(cli, name, controls)
41
+ # * Creating file inspec.yml
42
+ render_inspec_yml(cli, name, source_file, options, platform)
43
+ cli.plain_line
27
44
  end
28
45
 
29
- # * Create file README.md
30
- def self.render_readme_md(cli_ui, name, source_file)
31
- render_file = "#{name}/README.md"
32
- cli_ui.li "Create file #{cli_ui.mark_text(render_file)}"
33
- f = File.new(render_file, 'w')
46
+ def self.render_readme_md(cli, name, source_file, platform)
47
+ cli.list_item "Creating file #{cli.emphasis('README.md')}"
48
+ f = File.new("#{name}/README.md", 'w')
34
49
  f.puts("# #{name}")
35
50
  f.puts
36
51
  f.puts("This profile was generated by InSpec-Iggy v#{Iggy::VERSION} from the #{source_file} source file.")
52
+
53
+ f.puts(InspecPlugins::Iggy::Platforms::AwsHelper.readme) if platform.eql?('aws')
54
+ f.puts(InspecPlugins::Iggy::Platforms::AzureHelper.readme) if platform.eql?('azure')
55
+ f.puts(InspecPlugins::Iggy::Platforms::GcpHelper.readme) if platform.eql?('gcp')
56
+
37
57
  f.close
38
58
  end
39
59
 
40
- # * Create file inspec.yml
41
- def self.render_inspec_yml(cli_ui, name, source_file, options)
42
- render_file = "#{name}/inspec.yml"
43
- cli_ui.li "Create file #{cli_ui.mark_text(render_file)}"
60
+ def self.render_inspec_yml(cli, name, source_file, options, platform)
61
+ cli.list_item "Creating file #{cli.emphasis('inspec.yml')}"
44
62
  yml = {}
45
63
  yml['name'] = name
46
64
  yml['title'] = options[:title]
@@ -51,16 +69,19 @@ module InspecPlugins
51
69
  yml['summary'] = options[:summary]
52
70
  yml['version'] = options[:version]
53
71
  yml['description'] = "Generated by InSpec-Iggy v#{Iggy::VERSION} from the #{source_file} source file."
54
- f = File.new(render_file, 'w')
72
+
73
+ yml.merge!(InspecPlugins::Iggy::Platforms::AwsHelper.inspec_yml) if platform.eql?('aws')
74
+ yml.merge!(InspecPlugins::Iggy::Platforms::AzureHelper.inspec_yml) if platform.eql?('azure')
75
+ yml.merge!(InspecPlugins::Iggy::Platforms::GcpHelper.inspec_yml) if platform.eql?('gcp')
76
+
77
+ f = File.new("#{name}/inspec.yml", 'w')
55
78
  f.write(yml.to_yaml)
56
79
  f.close
57
80
  end
58
81
 
59
- # * Create file controls/controls.rb
60
- def self.render_controls_rb(cli_ui, name, controls)
61
- render_file = "#{name}/controls/controls.rb"
62
- cli_ui.li "Create file #{cli_ui.mark_text(render_file)}"
63
- f = File.new(render_file, 'w')
82
+ def self.render_controls_rb(cli, name, controls)
83
+ cli.list_item "Creating file #{cli.emphasis('controls/generated.rb')}"
84
+ f = File.new("#{name}/controls/generated.rb", 'w')
64
85
  f.write(controls)
65
86
  f.close
66
87
  end
@@ -4,7 +4,8 @@ require 'inspec/plugin/v2'
4
4
 
5
5
  require 'inspec-iggy/version'
6
6
  require 'inspec-iggy/profile_helper'
7
- require 'inspec-iggy/terraform/parser'
7
+ require 'inspec-iggy/terraform/generate'
8
+ require 'inspec-iggy/terraform/negative'
8
9
 
9
10
  module InspecPlugins::Iggy
10
11
  module Terraform
@@ -20,71 +21,95 @@ module InspecPlugins::Iggy
20
21
  say("Iggy v#{InspecPlugins::Iggy::VERSION}")
21
22
  end
22
23
 
23
- option :debug,
24
- desc: 'Verbose debugging messages',
25
- type: :boolean,
26
- default: false
24
+ class_option :debug,
25
+ desc: 'Verbose debugging messages',
26
+ type: :boolean,
27
+ default: false
27
28
 
28
- option :copyright,
29
- desc: 'Name of the copyright holder',
30
- default: 'The Authors'
29
+ class_option :copyright,
30
+ desc: 'Name of the copyright holder',
31
+ default: 'The Authors'
31
32
 
32
- option :email,
33
- desc: 'Email address of the author',
34
- default: 'you@example.com'
33
+ class_option :email,
34
+ desc: 'Email address of the author',
35
+ default: 'you@example.com'
35
36
 
36
- option :license,
37
- desc: 'License for the profile',
38
- default: 'Apache-2.0'
37
+ class_option :license,
38
+ desc: 'License for the profile',
39
+ default: 'Apache-2.0'
39
40
 
40
- option :maintainer,
41
- desc: 'Name of the copyright holder',
42
- default: 'The Authors'
41
+ class_option :maintainer,
42
+ desc: 'Name of the copyright holder',
43
+ default: 'The Authors'
43
44
 
44
- option :summary,
45
- desc: 'One line summary for the profile',
46
- default: 'An InSpec Compliance Profile'
45
+ class_option :summary,
46
+ desc: 'One line summary for the profile',
47
+ default: 'An InSpec Compliance Profile'
47
48
 
48
- option :title,
49
- desc: 'Human-readable name for the profile',
50
- default: 'InSpec Profile'
49
+ class_option :title,
50
+ desc: 'Human-readable name for the profile',
51
+ default: 'InSpec Profile'
51
52
 
52
- option :version,
53
- desc: 'Specify the profile version',
54
- default: '0.1.0'
53
+ class_option :version,
54
+ desc: 'Specify the profile version',
55
+ default: '0.1.0'
55
56
 
56
- option :overwrite,
57
- desc: 'Overwrites existing profile directory',
58
- type: :boolean,
59
- default: false
57
+ class_option :overwrite,
58
+ desc: 'Overwrites existing profile directory',
59
+ type: :boolean,
60
+ default: false
60
61
 
61
- option :name,
62
- aliases: '-n',
63
- required: true,
64
- desc: 'Name of profile to be generated'
62
+ class_option :name,
63
+ aliases: '-n',
64
+ required: true,
65
+ desc: 'Name of profile to be generated'
65
66
 
66
- option :tfstate,
67
- aliases: '-t',
68
- desc: 'Specify path to the input terraform.tfstate',
69
- default: 'terraform.tfstate'
67
+ class_option :tfstate,
68
+ aliases: '-t',
69
+ desc: 'Specify path to the input terraform.tfstate',
70
+ default: 'terraform.tfstate'
71
+
72
+ class_option :platform,
73
+ desc: 'The InSpec platform providing the necessary resources (aws, azure, or gcp)'
74
+
75
+ class_option :resourcepath,
76
+ desc: 'Specify path to the InSpec Resource Pack providing the necessary resources'
70
77
 
71
78
  desc 'generate [options]', 'Generate InSpec compliance controls from terraform.tfstate'
72
79
  def generate
73
80
  Inspec::Log.level = :debug if options[:debug]
74
- generated_controls = InspecPlugins::Iggy::Terraform::Parser.parse_generate(options[:tfstate])
75
- printable_controls = InspecPlugins::Iggy::InspecHelper.tf_controls(options[:title], generated_controls)
76
- InspecPlugins::Iggy::ProfileHelper.render_profile(self, options, options[:tfstate], printable_controls)
81
+ platform = options[:platform]
82
+ resource_path = options[:resourcepath]
83
+ # require validation that if platform or resourcepath are passed, both are available
84
+ if platform or resource_path
85
+ unless platform and resource_path
86
+ error 'You must pass both --platform and --resourcepath if using either'
87
+ exit(1)
88
+ end
89
+ end
90
+ generated_controls = InspecPlugins::Iggy::Terraform::Generate.parse_generate(options[:tfstate], resource_path, platform)
91
+ printable_controls = InspecPlugins::Iggy::InspecHelper.tf_controls(options[:title], generated_controls, platform)
92
+ InspecPlugins::Iggy::ProfileHelper.render_profile(ui, options, options[:tfstate], printable_controls, platform)
77
93
  exit 0
78
94
  end
79
95
 
80
- # disabled extract functionality
81
- # desc 'extract [options]', 'Extract tagged InSpec profiles from terraform.tfstate'
82
- # def extract
83
- # Inspec::Log.level = :debug if options[:debug]
84
- # extracted_profiles = InspecPlugins::Iggy::Terraform::Parser.parse_extract(options[:tfstate])
85
- # puts InspecPlugins::Iggy::InspecHelper.print_commands(extracted_profiles)
86
- # exit 0
87
- # end
96
+ desc 'negative [options]', 'Generate negative InSpec compliance controls from terraform.tfstate'
97
+ def negative
98
+ Inspec::Log.level = :debug if options[:debug]
99
+ platform = options[:platform]
100
+ resource_path = options[:resourcepath]
101
+ # require validation that if platform or resourcepath are passed, both are available
102
+ if platform or resource_path
103
+ unless platform and resource_path
104
+ error 'You must pass both --platform and --resourcepath if using either'
105
+ exit(1)
106
+ end
107
+ end
108
+ negative_controls = InspecPlugins::Iggy::Terraform::Negative.parse_negative(options[:tfstate], resource_path, platform)
109
+ printable_controls = InspecPlugins::Iggy::InspecHelper.tf_controls(options[:title], negative_controls, platform)
110
+ InspecPlugins::Iggy::ProfileHelper.render_profile(ui, options, options[:tfstate], printable_controls, platform)
111
+ exit 0
112
+ end
88
113
  end
89
114
  end
90
115
  end