diff --git a/Gemfile b/Gemfile
index b55115e1d..8b50cb85b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,5 +15,5 @@ group :development do
end
group :inspec do
- gem 'inspec', '~> 2.1', '>= 2.1.78'
+ gem 'inspec', '~> 2.2', '>= 2.2.10'
end
diff --git a/docs/resources/google_compute_firewalls.md.erb b/docs/resources/google_compute_firewalls.md.erb
new file mode 100644
index 000000000..4666d3cd5
--- /dev/null
+++ b/docs/resources/google_compute_firewalls.md.erb
@@ -0,0 +1,76 @@
+---
+title: About the google_compute_firewalls Resource
+platform: gcp
+---
+
+# google\_compute\_firewalls
+
+Use the `google_compute_firewalls` InSpec audit resource to test properties of all, or a filtered group of, GCP compute firewalls for a project.
+
+
+
+## Syntax
+
+A `google_compute_firewalls` resource block collects GCP firewalls by project then tests that group.
+
+ describe google_compute_firewalls(project: 'chef-inspec-gcp') do
+ it { should exist }
+ end
+
+Use this InSpec resource to enumerate IDs then test in-depth using `google_compute_firewall`.
+
+ google_compute_firewalls(project: 'chef-inspec-gcp').firewall_names.each do |firewall_name|
+ describe google_compute_firewall(project: 'chef-inspec-gcp', name: firewall_name) do
+ it { should exist }
+ its('kind') { should eq "compute#firewall" }
+ end
+ end
+
+
+
+## Examples
+
+The following examples show how to use this InSpec audit resource.
+
+### Test that there are no more than a specified number of firewalls available for the project
+
+ describe google_compute_firewalls(project: 'chef-inspec-gcp') do
+ its('count') { should be <= 100}
+ end
+
+### Test that an expected firewall is available for the project
+
+ describe google_compute_firewalls(project: 'chef-inspec-gcp') do
+ its('firewall_names') { should include "my-app-firewall-rule" }
+ end
+
+### Test that a particular named rule does not exist
+
+ describe google_compute_firewalls(project: 'chef-inspec-gcp') do
+ its('firewall_names') { should_not include "default-allow-ssh" }
+ end
+
+### Test there are no firewalls for the "INGRESS" direction
+
+ describe google_compute_firewalls(project: 'chef-inspec-gcp').where(firewall_direction: 'INGRESS') do
+ it { should_not exist }
+ end
+
+
+
+## Filter Criteria
+
+This resource supports the following filter criteria: `firewall_id`; `firewall_name`; and `firewall_direction`. Any of these may be used with `where`, as a block or as a method.
+
+## Properties
+
+* `firewall_ids` - an array of google_compute_firewall identifier integers
+* `firewall_names` - an array of google_compute_firewall name strings
+* `firewall_directions`- an array of google_compute_firewall directions containing strings e.g. "INGRESS" or "EGRESS"
+
+
+
+
+## GCP Permissions
+
+Ensure the [Compute Engine API](https://console.cloud.google.com/apis/library/compute.googleapis.com/) is enabled for the project where the resource is located.
\ No newline at end of file
diff --git a/docs/resources/google_compute_instance.md.erb b/docs/resources/google_compute_instance.md.erb
index 479847bfa..457bdf3d4 100644
--- a/docs/resources/google_compute_instance.md.erb
+++ b/docs/resources/google_compute_instance.md.erb
@@ -75,11 +75,17 @@ The following examples show how to use this InSpec audit resource.
its('first_network_interface_type'){ should eq "one_to_one_nat" }
end
+### Test that a particular compute instance label key is present
+
+ describe google_compute_instance(project: 'chef-inspec-gcp', zone: 'us-east1-b', name: 'inspec-test-vm') do
+ its('labels_keys') { should include 'my_favourite_label' }
+ end
+
## Properties
-* `cpu_platform`, `creation_timestamp`, `deletion_protection`, `disks`, `id`, `kind`, `label_fingerprint`, `machine_type`, `metadata`, `name`, `network_interfaces`, `scheduling`, `start_restricted`, `status`, `tags`, `zone`
+* `cpu_platform`, `creation_timestamp`, `deletion_protection`, `disks`, `id`, `kind`, `label_fingerprint`, `machine_type`, `metadata`, `name`, `network_interfaces`, `scheduling`, `start_restricted`, `status`, `tags`, `zone`, `labels_keys`, `labels_values`
diff --git a/docs/resources/google_compute_instances.md.erb b/docs/resources/google_compute_instances.md.erb
index 2837f7edb..7569edbcd 100644
--- a/docs/resources/google_compute_instances.md.erb
+++ b/docs/resources/google_compute_instances.md.erb
@@ -5,7 +5,7 @@ platform: gcp
# google\_compute\_instances
-Use the `google_compute_instances` InSpec audit resource to test properties of all GCP compute instances for a project in a particular zone.
+Use the `google_compute_instances` InSpec audit resource to test properties of all, or a filtered group of, GCP compute instances for a project in a particular zone.
@@ -38,7 +38,7 @@ The following examples show how to use this InSpec audit resource.
### Test that there are no more than a specified number of instances in the project and zone
describe google_compute_instances(project: 'chef-inspec-gcp', zone: 'europe-west2-a') do
- its('entries.count') { should be <= 100}
+ its('count') { should be <= 100}
end
### Test the exact number of instances in the project and zone
@@ -57,11 +57,12 @@ The following examples show how to use this InSpec audit resource.
## Filter Criteria
-This resource currently does not support any filter criteria; it will always fetch all instances in the zone.
+This resource supports the following filter criteria: `instance_id` and `instance_name`. Either of these may be used with `where`, as a block or as a method.
## Properties
-* `instance_id`, `instance_name`
+* `instance_ids` - an array of google_compute_instance identifier integers
+* `instance_names` - an array of google_compute_instance name strings
diff --git a/docs/resources/google_compute_zone.md.erb b/docs/resources/google_compute_zone.md.erb
new file mode 100644
index 000000000..6f826445c
--- /dev/null
+++ b/docs/resources/google_compute_zone.md.erb
@@ -0,0 +1,57 @@
+---
+title: About the google_compute_zone Resource
+platform: gcp
+---
+
+# google\_compute\_zone
+
+Use the `google_compute_zone` InSpec audit resource to test properties of a single GCP compute zone.
+
+
+
+## Syntax
+
+A `google_compute_zone` resource block declares the tests for a single GCP zone by project and name.
+
+ describe google_compute_zone(project: 'chef-inspec-gcp', zone: 'us-east1-b') do
+ its('name') { should match 'us-east1-b' }
+ end
+
+
+
+## Examples
+
+The following examples show how to use this InSpec audit resource.
+
+### Test that a GCP compute zone exists
+
+ describe google_compute_zone(project: 'chef-inspec-gcp', zone: 'us-east1-b') do
+ it { should exist }
+ end
+
+### Test that a GCP compute zone is in the expected state
+
+ describe google_compute_zone(project: 'chef-inspec-gcp', zone: 'us-east1-b') do
+ its('status') { should eq 'UP' }
+ # or equivalently
+ it { should be_up }
+ end
+
+### Test that a GCP compute zone has an expected CPU platform
+
+ describe google_compute_zone(project: 'chef-inspec-gcp', zone: 'us-east1-b') do
+ its('available_cpu_platforms') { should include "Intel Skylake" }
+ end
+
+
+
+## Properties
+
+* `available_cpu_platforms`, `creation_timestamp`, `description`, `id`, `kind`, `name`, `region`, `status`, `region_name`
+
+
+
+
+## GCP Permissions
+
+Ensure the [Compute Engine API](https://console.cloud.google.com/apis/library/compute.googleapis.com/) is enabled for the project where the resource is located.
\ No newline at end of file
diff --git a/docs/resources/google_compute_zones.md.erb b/docs/resources/google_compute_zones.md.erb
new file mode 100644
index 000000000..a5c24b476
--- /dev/null
+++ b/docs/resources/google_compute_zones.md.erb
@@ -0,0 +1,77 @@
+---
+title: About the google_compute_zones Resource
+platform: gcp
+---
+
+# google\_compute\_zones
+
+Use the `google_compute_zones` InSpec audit resource to test properties of all, or a filtered group of, GCP compute zones for a project in a particular zone.
+
+
+
+## Syntax
+
+A `google_compute_zones` resource block collects GCP zones by project then tests that group.
+
+ describe google_compute_zones(project: 'chef-inspec-gcp') do
+ it { should exist }
+ end
+
+Use this InSpec resource to enumerate IDs then test in-depth using `google_compute_zone`.
+
+ google_compute_zones(project: 'chef-inspec-gcp').zone_names.each do |zone_name|
+ describe google_compute_zone(project: 'chef-inspec-gcp', zone: zone_name) do
+ it { should exist }
+ its('kind') { should eq "compute#zone" }
+ its('status') { should eq 'UP' }
+ end
+ end
+
+
+
+## Examples
+
+The following examples show how to use this InSpec audit resource.
+
+### Test that there are no more than a specified number of zones available for the project
+
+ describe google_compute_zones(project: 'chef-inspec-gcp') do
+ its('count') { should be <= 100}
+ end
+
+### Test the exact number of zones in the project
+
+ describe google_compute_zones(project: 'chef-inspec-gcp') do
+ its('zone_ids.count') { should cmp 9 }
+ end
+
+### Test that an expected zone is available for the project
+
+ describe google_compute_zones(project: 'chef-inspec-gcp') do
+ its('zone_names') { should include "us-east1-b" }
+ end
+
+### Test whether any zones are in status "DOWN"
+
+ describe google_compute_zones(project: 'chef-inspec-gcp') do
+ its('zone_statuses') { should_not include "DOWN" }
+ end
+
+
+
+## Filter Criteria
+
+This resource supports the following filter criteria: `zone_id`; `zone_name` and `zone_status`. Anyy of these may be used with `where`, as a block or as a method.
+
+## Properties
+
+* `zone_ids` - an array of google_compute_zone identifier integers
+* `zone_names` - an array of google_compute_zone name strings
+* `zone_statuses`- an array of google_compute_zone statuses
+
+
+
+
+## GCP Permissions
+
+Ensure the [Compute Engine API](https://console.cloud.google.com/apis/library/compute.googleapis.com/) is enabled for the project where the resource is located.
\ No newline at end of file
diff --git a/libraries/google_compute_firewall.rb b/libraries/google_compute_firewall.rb
index 8de5ee601..01e23b92c 100644
--- a/libraries/google_compute_firewall.rb
+++ b/libraries/google_compute_firewall.rb
@@ -8,7 +8,7 @@ class GoogleComputeFirewall < GcpResourceBase
desc 'Verifies settings for a compute firewall rule'
example "
- describe google_compute_firewall(project: 'chef-inspec-gcp', location: 'us-west2', name: 'gcp-inspec-test') do
+ describe google_compute_firewall(project: 'chef-inspec-gcp', name: 'gcp-inspec-test') do
it { should exist }
its('name') { should eq 'inspec-test' }
its('status') { should eq 'in_use' }
@@ -51,6 +51,10 @@ def ports_protocol_allowed(port_list, protocol = 'tcp', index = 0)
end
end
+ def exists?
+ !@firewall.nil?
+ end
+
def to_s
"Firewall Rule #{@display_name}"
end
diff --git a/libraries/google_compute_firewalls.rb b/libraries/google_compute_firewalls.rb
new file mode 100644
index 000000000..e2333dea8
--- /dev/null
+++ b/libraries/google_compute_firewalls.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'gcp_backend'
+
+module Inspec::Resources
+ class GoogleComputeFirewalls < GcpResourceBase
+ name 'google_compute_firewalls'
+ desc 'Verifies settings for GCP compute firewalls in bulk'
+
+ example "
+ describe google_compute_firewalls(project: 'chef-inspec-gcp') do
+ it { should exist }
+ ...
+ end
+ "
+
+ def initialize(opts = {})
+ # Call the parent class constructor
+ super(opts)
+ @display_name = opts[:name]
+ @project = opts[:project]
+ end
+
+ # FilterTable setup
+ filter_table_config = FilterTable.create
+ filter_table_config.add(:firewall_ids, field: :firewall_id)
+ filter_table_config.add(:firewall_names, field: :firewall_name)
+ filter_table_config.add(:firewall_directions, field: :firewall_direction)
+ filter_table_config.connect(self, :fetch_data)
+
+ def fetch_data
+ firewall_rows = []
+ next_page = nil
+ loop do
+ catch_gcp_errors do
+ @firewalls = @gcp.gcp_compute_client.list_firewalls(@project, page_token: next_page)
+ end
+ return [] if !@firewalls.items
+ @firewalls.items.map do |firewall|
+ firewall_rows+=[{ firewall_id: firewall.id,
+ firewall_name: firewall.name,
+ firewall_direction: firewall.direction }]
+ end
+ next_page = @firewalls.next_page_token
+ break unless next_page
+ end
+ @table = firewall_rows
+ end
+ end
+end
diff --git a/libraries/google_compute_instance.rb b/libraries/google_compute_instance.rb
index e1726577f..9e2351a4c 100644
--- a/libraries/google_compute_instance.rb
+++ b/libraries/google_compute_instance.rb
@@ -98,6 +98,18 @@ def machine_size
machine_type.split('/').last
end
+ # helper for returning label keys to perform checks
+ def labels_keys
+ return [] if !defined?(labels)
+ labels.item.keys
+ end
+
+ # helper for returning label values to perform checks
+ def labels_values
+ return [] if !defined?(labels)
+ labels.item.values
+ end
+
def exists?
!@instance.nil?
end
diff --git a/libraries/google_compute_instances.rb b/libraries/google_compute_instances.rb
index 2b2aa8da1..875255b85 100644
--- a/libraries/google_compute_instances.rb
+++ b/libraries/google_compute_instances.rb
@@ -24,23 +24,24 @@ def initialize(opts = {})
# FilterTable setup
filter_table_config = FilterTable.create
- filter_table_config.add_accessor(:where)
- filter_table_config.add_accessor(:entries)
- filter_table_config.add(:exist?) { |filter_table| !filter_table.entries.empty? }
- filter_table_config.add(:count) { |filter_table| filter_table.entries.count }
filter_table_config.add(:instance_ids, field: :instance_id)
filter_table_config.add(:instance_names, field: :instance_name)
- filter_table_config.add(:colors, field: :color, type: :simple)
filter_table_config.connect(self, :fetch_data)
def fetch_data
instance_rows = []
- catch_gcp_errors do
- @instances = @gcp.gcp_compute_client.list_instances(@project, @zone)
- end
- @instances.items.map do |instance|
- instance_rows+=[{ instance_id: instance.id,
- instance_name: instance.name }]
+ next_page = nil
+ loop do
+ catch_gcp_errors do
+ @instances = @gcp.gcp_compute_client.list_instances(@project, @zone, page_token: next_page)
+ end
+ return [] if !@instances.items
+ @instances.items.map do |instance|
+ instance_rows+=[{ instance_id: instance.id,
+ instance_name: instance.name }]
+ end
+ next_page = @instances.next_page_token
+ break unless next_page
end
@table = instance_rows
end
diff --git a/libraries/google_compute_zone.rb b/libraries/google_compute_zone.rb
new file mode 100644
index 000000000..678c10278
--- /dev/null
+++ b/libraries/google_compute_zone.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'gcp_backend'
+
+module Inspec::Resources
+ class GoogleComputeZone < GcpResourceBase
+ name 'google_compute_zone'
+ desc 'Verifies settings for a zone'
+
+ example "
+ describe google_compute_zone(project: 'chef-inspec-gcp', zone: 'us-east1-b') do
+ it { should exist }
+ its('name') { should match 'us-east1-b' }
+ end
+ "
+
+ def initialize(opts = {})
+ # Call the parent class constructor
+ super(opts)
+ @display_name = opts[:name]
+ catch_gcp_errors do
+ @zone = @gcp.gcp_compute_client.get_zone(opts[:project], opts[:name])
+ create_resource_methods(@zone)
+ end
+ end
+
+ # helper method for retrieving a region name
+ def region_name
+ return false if !defined?(region)
+ region.split('/').last
+ end
+
+ def exists?
+ !@zone.nil?
+ end
+
+ def up?
+ return false if !defined?(status)
+ status == 'UP'
+ end
+
+ def to_s
+ "Zone #{@display_name}"
+ end
+ end
+end
diff --git a/libraries/google_compute_zones.rb b/libraries/google_compute_zones.rb
new file mode 100644
index 000000000..c0a688e5d
--- /dev/null
+++ b/libraries/google_compute_zones.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'gcp_backend'
+
+module Inspec::Resources
+ class GoogleComputeZones < GcpResourceBase
+ name 'google_compute_zones'
+ desc 'Verifies settings for GCP compute zones in bulk'
+
+ example "
+ describe google_compute_zones(project: 'chef-inspec-gcp') do
+ it { should exist }
+ ...
+ end
+ "
+
+ def initialize(opts = {})
+ # Call the parent class constructor
+ super(opts)
+ @display_name = opts[:name]
+ @project = opts[:project]
+ end
+
+ # FilterTable setup
+ filter_table_config = FilterTable.create
+ filter_table_config.add(:zone_ids, field: :zone_id)
+ filter_table_config.add(:zone_names, field: :zone_name)
+ filter_table_config.add(:zone_statuses, field: :zone_status)
+ filter_table_config.connect(self, :fetch_data)
+
+ def fetch_data
+ zone_rows = []
+ catch_gcp_errors do
+ @zones = @gcp.gcp_compute_client.list_zones(@project)
+ end
+ return [] if !@zones.items
+ @zones.items.map do |zone|
+ zone_rows+=[{ zone_id: zone.id,
+ zone_name: zone.name,
+ zone_status: zone.status }]
+ end
+ @table = zone_rows
+ end
+ end
+end
diff --git a/test/integration/configuration/gcp_inspec_config.rb b/test/integration/configuration/gcp_inspec_config.rb
index 9b943cea8..f8c391b56 100644
--- a/test/integration/configuration/gcp_inspec_config.rb
+++ b/test/integration/configuration/gcp_inspec_config.rb
@@ -18,6 +18,7 @@ module GCPInspecConfig
# Determine the storage account name and the admin password
:gcp_location => "europe-west2",
:gcp_zone => "europe-west2-a",
+ :gcp_zone_id => "2290",
:gcp_int_vm_name => "gcp-inspec-int-linux-vm",
:gcp_int_vm_size => "f1-micro",
:gcp_int_vm_image => "ubuntu-os-cloud/ubuntu-1604-lts",
@@ -64,7 +65,11 @@ module GCPInspecConfig
# be disabled meaning a user needs no special GCP privileges to run the integration test pack.
#
# Note, would prefer to use boolean true or false here but will revisit for a future version of tf, see here for more detail: https://www.terraform.io/docs/configuration/variables.html
- :gcp_enable_privileged_resources => 0
+ :gcp_enable_privileged_resources => 0,
+ # Some controls make use of the gcloud command and grep to discover live data to then test against.
+ # Only test execution is affected by this flag, resource creation via terraform is unaffected.
+ # Default behaviour is for this to be disabled, enable by changing the below flag.
+ :gcp_enable_gcloud_calls => 0
}
def self.config
diff --git a/test/integration/verify/controls/generic_external_vm.rb b/test/integration/verify/controls/generic_external_vm.rb
index 48a58274f..45bc051e8 100644
--- a/test/integration/verify/controls/generic_external_vm.rb
+++ b/test/integration/verify/controls/generic_external_vm.rb
@@ -52,6 +52,6 @@
its('first_network_interface_name'){ should eq "external-nat" }
its('first_network_interface_type'){ should eq "one_to_one_nat" }
+ its('labels_keys') { should_not include 'label_does_not_exist' }
end
-
end
diff --git a/test/integration/verify/controls/generic_external_vm_data_disk.rb b/test/integration/verify/controls/generic_external_vm_data_disk.rb
index cf6cee00b..33033ddbb 100644
--- a/test/integration/verify/controls/generic_external_vm_data_disk.rb
+++ b/test/integration/verify/controls/generic_external_vm_data_disk.rb
@@ -53,6 +53,7 @@
its('first_network_interface_nat_ip_exists'){ should be true }
its('first_network_interface_name'){ should eq "external-nat" }
its('first_network_interface_type'){ should eq "one_to_one_nat" }
+ its('labels_keys') { should_not include 'non_existing_label' }
end
diff --git a/test/integration/verify/controls/google_compute_firewalls.rb b/test/integration/verify/controls/google_compute_firewalls.rb
new file mode 100644
index 000000000..134e8efcc
--- /dev/null
+++ b/test/integration/verify/controls/google_compute_firewalls.rb
@@ -0,0 +1,25 @@
+title 'Firewalls Properties'
+
+gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.')
+gcp_enable_gcloud_calls = attribute(:gcp_enable_gcloud_calls,default:0,description:'Flag to enable the use of gcloud command line to pull in live data to test against.')
+
+control 'gcp-firewalls-1.0' do
+
+ only_if { gcp_enable_gcloud_calls.to_i == 1 }
+ impact 1.0
+ title 'Ensure firewalls have the correct properties in bulk'
+
+ describe google_compute_firewalls(project: gcp_project_id) do
+ it { should exist }
+ its('count') { should be <= 100}
+ # assume this is a development setup for a moment
+ its('firewall_names') { should include "default-allow-ssh" }
+ its('firewall_names') { should include "default-allow-rdp" }
+ its('firewall_names') { should include "default-allow-internal" }
+ its('firewall_names') { should include "default-allow-icmp" }
+ # Only make the call if the configuration flag is specified and the test will run
+ gcp_firewall_id = `gcloud compute firewall-rules list --filter="name=default-allow-ssh" --format=json | grep id | grep -o '[0-9]\\+'`.chomp.to_i
+ its('firewall_ids') { should include gcp_firewall_id }
+ end
+
+end
\ No newline at end of file
diff --git a/test/integration/verify/controls/google_compute_firewalls_loop.rb b/test/integration/verify/controls/google_compute_firewalls_loop.rb
new file mode 100644
index 000000000..f34d0fffc
--- /dev/null
+++ b/test/integration/verify/controls/google_compute_firewalls_loop.rb
@@ -0,0 +1,17 @@
+title 'Loop over all GCP Firewalls'
+
+gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.')
+
+control 'gcp-firewalls-loop-1.0' do
+
+ impact 1.0
+ title 'Ensure firewalls have the correct properties in bulk using google_compute_firewall for detail.'
+
+ google_compute_firewalls(project: gcp_project_id).firewall_names.each do |firewall_name|
+ describe google_compute_firewall(project: gcp_project_id, name: firewall_name) do
+ it { should exist }
+ its('kind') { should eq "compute#firewall" }
+ its('direction') { should be_in ["INGRESS","EGRESS"] }
+ end
+ end
+end
\ No newline at end of file
diff --git a/test/integration/verify/controls/google_compute_instance_label_loop.rb b/test/integration/verify/controls/google_compute_instance_label_loop.rb
new file mode 100644
index 000000000..1ccc914ab
--- /dev/null
+++ b/test/integration/verify/controls/google_compute_instance_label_loop.rb
@@ -0,0 +1,17 @@
+title 'Loop over all GCP Zones to find all Compute Instances with a particular Label'
+
+gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.')
+
+control 'gcp-zones-compute-label-loop-1.0' do
+
+ impact 1.0
+ title 'Ensure labels for compute instances across all zones have or do not have a particular label.'
+
+ google_compute_zones(project: gcp_project_id).zone_names.each do |zone_name|
+ google_compute_instances(project: gcp_project_id, zone: zone_name).instance_names.each do |instance_name|
+ describe google_compute_instance(project: gcp_project_id, zone: zone_name, name: instance_name) do
+ its('labels_keys') { should_not include 'operations_override_do_not_kill' }
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/test/integration/verify/controls/google_compute_vms.rb b/test/integration/verify/controls/google_compute_vms.rb
index 467a74d0c..d50342792 100644
--- a/test/integration/verify/controls/google_compute_vms.rb
+++ b/test/integration/verify/controls/google_compute_vms.rb
@@ -3,17 +3,22 @@
gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.')
gcp_zone = attribute(:gcp_zone, default: '', description: 'The GCP zone being used.')
gcp_ext_vm_data_disk_name = attribute(:gcp_ext_vm_data_disk_name, default: '', description: 'A valid GCP VM name to check for.')
+gcp_enable_gcloud_calls = attribute(:gcp_enable_gcloud_calls,default:0,description:'Flag to enable the use of gcloud command line to pull in live data to test against.')
control 'gcp-vms-1.0' do
+ only_if { gcp_enable_gcloud_calls.to_i == 1 }
impact 1.0
title 'Ensure VMs have the correct properties in bulk'
describe google_compute_instances(project: gcp_project_id, zone: gcp_zone) do
it { should exist }
- its('entries.count') { should be <= 100}
+ its('count') { should be <= 100}
its('instance_ids.count') { should cmp 9 }
its('instance_names') { should include gcp_ext_vm_data_disk_name }
+ # Only make the call if the configuration flag is specified and the test will run
+ gcp_instance_id = `gcloud compute instances list --filter="name=gcp-inspec-ext-linux-vm" --format=json | grep id | grep -o '[0-9]\\+'`.chomp.to_i
+ its('instance_ids') { should include gcp_instance_id }
end
end
\ No newline at end of file
diff --git a/test/integration/verify/controls/google_compute_zones.rb b/test/integration/verify/controls/google_compute_zones.rb
new file mode 100644
index 000000000..e1f357054
--- /dev/null
+++ b/test/integration/verify/controls/google_compute_zones.rb
@@ -0,0 +1,20 @@
+title 'Zones Properties'
+
+gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.')
+gcp_zone = attribute(:gcp_zone, default: '', description: 'The GCP zone being used.')
+gcp_zone_id = attribute(:gcp_zone_id, default: '', description: 'A sample zone identifier to test for.')
+
+control 'gcp-zones-1.0' do
+
+ impact 1.0
+ title 'Ensure zones have the correct properties in bulk'
+
+ describe google_compute_zones(project: gcp_project_id) do
+ it { should exist }
+ its('count') { should be <= 100} # 46 at the time of writing
+ its('zone_names') { should include gcp_zone }
+ its('zone_statuses') { should_not include "DOWN" }
+ its('zone_ids') { should include gcp_zone_id.to_i }
+ end
+
+end
\ No newline at end of file
diff --git a/test/integration/verify/controls/google_compute_zones_loop.rb b/test/integration/verify/controls/google_compute_zones_loop.rb
new file mode 100644
index 000000000..0731b29f7
--- /dev/null
+++ b/test/integration/verify/controls/google_compute_zones_loop.rb
@@ -0,0 +1,19 @@
+title 'Loop over all GCP Zones'
+
+gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.')
+
+control 'gcp-zones-loop-1.0' do
+
+ impact 1.0
+ title 'Ensure zones have the correct properties in bulk using google_compute_zone for detail.'
+
+ google_compute_zones(project: gcp_project_id).zone_names.each do |zone_name|
+ describe google_compute_zone(project: gcp_project_id, name: zone_name) do
+ it { should exist }
+ its('kind') { should eq "compute#zone" }
+ its('status') { should eq 'UP' }
+ # or equivalently
+ it { should be_up }
+ end
+ end
+end
\ No newline at end of file
diff --git a/test/integration/verify/inspec.yml b/test/integration/verify/inspec.yml
index 21eada108..d4b55b917 100644
--- a/test/integration/verify/inspec.yml
+++ b/test/integration/verify/inspec.yml
@@ -1,6 +1,6 @@
name: inspec-gcp-integration-tests
version: 0.2.0
-inspec_version: '>= 2.1.78'
+inspec_version: '>= 2.2.10'
depends:
- name: inspec-gcp
path: ../../../