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,57 @@
1
+ require "resource_support/aws/aws_singular_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-sns"
4
+
5
+ class AwsSnsTopic < Inspec.resource(1)
6
+ name "aws_sns_topic"
7
+ desc "Verifies settings for an SNS Topic"
8
+ example <<~EXAMPLE
9
+ describe aws_sns_topic('arn:aws:sns:us-east-1:123456789012:some-topic') do
10
+ it { should exist }
11
+ its('confirmed_subscription_count') { should_not be_zero }
12
+ end
13
+ EXAMPLE
14
+ supports platform: "aws"
15
+
16
+ include AwsSingularResourceMixin
17
+ attr_reader :arn, :confirmed_subscription_count
18
+
19
+ private
20
+
21
+ def validate_params(raw_params)
22
+ validated_params = check_resource_param_names(
23
+ raw_params: raw_params,
24
+ allowed_params: [:arn],
25
+ allowed_scalar_name: :arn,
26
+ allowed_scalar_type: String
27
+ )
28
+ # Validate the ARN
29
+ unless validated_params[:arn] =~ /^arn:aws:sns:[\w\-]+:\d{12}:[\S]+$/
30
+ raise ArgumentError, "Malformed ARN for SNS topics. Expected an ARN of the form " \
31
+ "'arn:aws:sns:REGION:ACCOUNT-ID:TOPIC-NAME'"
32
+ end
33
+ validated_params
34
+ end
35
+
36
+ def fetch_from_api
37
+ aws_response = BackendFactory.create(inspec_runner).get_topic_attributes(topic_arn: @arn).attributes
38
+ @exists = true
39
+
40
+ # The response has a plain hash with CamelCase plain string keys and string values
41
+ @confirmed_subscription_count = aws_response["SubscriptionsConfirmed"].to_i
42
+ rescue Aws::SNS::Errors::NotFound
43
+ @exists = false
44
+ end
45
+
46
+ # Uses the SDK API to really talk to AWS
47
+ class Backend
48
+ class AwsClientApi < AwsBackendBase
49
+ BackendFactory.set_default_backend(self)
50
+ self.aws_client_class = Aws::SNS::Client
51
+
52
+ def get_topic_attributes(criteria)
53
+ aws_service_client.get_topic_attributes(criteria)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,60 @@
1
+ require "resource_support/aws/aws_plural_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-sns"
4
+
5
+ class AwsSnsTopics < Inspec.resource(1)
6
+ name "aws_sns_topics"
7
+ desc "Verifies settings for SNS Topics in bulk"
8
+ example <<~EXAMPLE
9
+ describe aws_sns_topics do
10
+ its('topic_arns') { should include '' }
11
+ end
12
+ EXAMPLE
13
+ supports platform: "aws"
14
+
15
+ include AwsPluralResourceMixin
16
+
17
+ def validate_params(resource_params)
18
+ unless resource_params.empty?
19
+ raise ArgumentError, "aws_sns_topics does not accept resource parameters."
20
+ end
21
+
22
+ resource_params
23
+ end
24
+
25
+ def fetch_from_api
26
+ backend = BackendFactory.create(inspec_runner)
27
+ @table = []
28
+ pagination_opts = nil
29
+ catch_aws_errors do
30
+ loop do
31
+ api_result = backend.list_topics(pagination_opts)
32
+ @table += api_result.topics.map(&:to_h)
33
+ break if api_result.next_token.nil?
34
+
35
+ pagination_opts = { next_token: api_result.next_token }
36
+ end
37
+ end
38
+ end
39
+
40
+ # Underlying FilterTable implementation.
41
+ filter = FilterTable.create
42
+ filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
43
+ filter.register_column(:topic_arns, field: :topic_arn)
44
+ filter.install_filter_methods_on_resource(self, :table)
45
+
46
+ def to_s
47
+ "EC2 SNS Topics"
48
+ end
49
+
50
+ class Backend
51
+ class AwsClientApi < AwsBackendBase
52
+ BackendFactory.set_default_backend self
53
+ self.aws_client_class = Aws::SNS::Client
54
+
55
+ def list_topics(pagination_opts)
56
+ aws_service_client.list_topics(pagination_opts)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,66 @@
1
+ require "resource_support/aws/aws_singular_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-sqs"
4
+
5
+ require "uri"
6
+
7
+ class AwsSqsQueue < Inspec.resource(1)
8
+ name "aws_sqs_queue"
9
+ desc "Verifies settings for an SQS Queue"
10
+ example <<~EXAMPLE
11
+ describe aws_sqs_queue('https://sqs.ap-southeast-2.amazonaws.com/519527725796/QueueName') do
12
+ it { should exist }
13
+ its('visiblity_timeout') { should be 300}
14
+ end
15
+ EXAMPLE
16
+ supports platform: "aws"
17
+
18
+ include AwsSingularResourceMixin
19
+ attr_reader :arn, :is_fifo_queue, :visibility_timeout, :maximum_message_size, :message_retention_period, :delay_seconds, :receive_message_wait_timeout_seconds, :content_based_deduplication
20
+
21
+ private
22
+
23
+ def validate_params(raw_params)
24
+ validated_params = check_resource_param_names(
25
+ raw_params: raw_params,
26
+ allowed_params: [:url],
27
+ allowed_scalar_name: :url,
28
+ allowed_scalar_type: String
29
+ )
30
+ # Validate the URL
31
+ unless validated_params[:url] =~ /\A#{URI::DEFAULT_PARSER.make_regexp(%w{https})}\z/
32
+ raise ArgumentError, "Malformed URL for SQS. Expected an ARN of the form " \
33
+ "'https://sqs.ap-southeast-2.amazonaws.com/111212121/MyQeueue'"
34
+ end
35
+ validated_params
36
+ end
37
+
38
+ def fetch_from_api
39
+ aws_response = BackendFactory.create(inspec_runner).get_queue_attributes(queue_url: @url, attribute_names: ["All"]).attributes
40
+ @exists = true
41
+ @visibility_timeout = aws_response["VisibilityTimeout"].to_i
42
+ @maximum_message_size = aws_response["MaximumMessageSize"].to_i
43
+ @message_retention_period = aws_response["MessageRetentionPeriod"].to_i
44
+ @delay_seconds = aws_response["DelaySeconds"].to_i
45
+ @receive_message_wait_timeout_seconds = aws_response["ReceiveMessageWaitTimeSeconds"].to_i
46
+
47
+ # FIFO queues - these attributes only exist for FIFO queues, their presence indicates a FIFO
48
+ # queue
49
+ @is_fifo_queue = aws_response["FifoQueue"].nil? ? false : true
50
+ @content_based_deduplication = aws_response["ContentBasedDeduplication"].nil? ? false : true
51
+ rescue Aws::SQS::Errors::NonExistentQueue
52
+ @exists = false
53
+ end
54
+
55
+ # Uses the SDK API to really talk to AWS
56
+ class Backend
57
+ class AwsClientApi < AwsBackendBase
58
+ BackendFactory.set_default_backend(self)
59
+ self.aws_client_class = Aws::SQS::Client
60
+
61
+ def get_queue_attributes(criteria)
62
+ aws_service_client.get_queue_attributes(criteria)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,92 @@
1
+ require "resource_support/aws/aws_singular_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-ec2"
4
+
5
+ class AwsSubnet < Inspec.resource(1)
6
+ name "aws_subnet"
7
+ desc "This resource is used to test the attributes of a VPC subnet"
8
+ example <<~EXAMPLE
9
+ describe aws_subnet(subnet_id: 'subnet-12345678') do
10
+ it { should exist }
11
+ its('cidr_block') { should eq '10.0.1.0/24' }
12
+ end
13
+ EXAMPLE
14
+ supports platform: "aws"
15
+
16
+ include AwsSingularResourceMixin
17
+ attr_reader :assigning_ipv_6_address_on_creation, :availability_zone, :available_ip_address_count,
18
+ :available, :cidr_block, :default_for_az, :ipv_6_cidr_block_association_set,
19
+ :mapping_public_ip_on_launch, :subnet_id, :vpc_id
20
+ alias available? available
21
+ alias default_for_az? default_for_az
22
+ alias mapping_public_ip_on_launch? mapping_public_ip_on_launch
23
+ alias assigning_ipv_6_address_on_creation? assigning_ipv_6_address_on_creation
24
+
25
+ def to_s
26
+ "VPC Subnet #{@subnet_id}"
27
+ end
28
+
29
+ private
30
+
31
+ def validate_params(raw_params)
32
+ validated_params = check_resource_param_names(
33
+ raw_params: raw_params,
34
+ allowed_params: [:subnet_id],
35
+ allowed_scalar_name: :subnet_id,
36
+ allowed_scalar_type: String
37
+ )
38
+
39
+ # Make sure the subnet_id parameter was specified and in the correct form.
40
+ if validated_params.key?(:subnet_id) && validated_params[:subnet_id] !~ /^subnet\-[0-9a-f]{8}/
41
+ raise ArgumentError, 'aws_subnet Subnet ID must be in the format "subnet-" followed by 8 hexadecimal characters.'
42
+ end
43
+
44
+ if validated_params.empty?
45
+ raise ArgumentError, "You must provide a subnet_id to aws_subnet."
46
+ end
47
+
48
+ validated_params
49
+ end
50
+
51
+ def fetch_from_api
52
+ backend = BackendFactory.create(inspec_runner)
53
+
54
+ # Transform into filter format expected by AWS
55
+ filters = []
56
+ filters.push({ name: "subnet-id", values: [@subnet_id] })
57
+ ds_response = backend.describe_subnets(filters: filters)
58
+
59
+ # If no subnets exist in the VPC, exist is false.
60
+ if ds_response.subnets.empty?
61
+ @exists = false
62
+ return
63
+ end
64
+ @exists = true
65
+ assign_properties(ds_response)
66
+ end
67
+
68
+ def assign_properties(ds_response)
69
+ @vpc_id = ds_response.subnets[0].vpc_id
70
+ @subnet_id = ds_response.subnets[0].subnet_id
71
+ @cidr_block = ds_response.subnets[0].cidr_block
72
+ @availability_zone = ds_response.subnets[0].availability_zone
73
+ @available_ip_address_count = ds_response.subnets[0].available_ip_address_count
74
+ @default_for_az = ds_response.subnets[0].default_for_az
75
+ @mapping_public_ip_on_launch = ds_response.subnets[0].map_public_ip_on_launch
76
+ @available = ds_response.subnets[0].state == "available"
77
+ @ipv_6_cidr_block_association_set = ds_response.subnets[0].ipv_6_cidr_block_association_set
78
+ @assigning_ipv_6_address_on_creation = ds_response.subnets[0].assign_ipv_6_address_on_creation
79
+ end
80
+
81
+ # Uses the SDK API to really talk to AWS
82
+ class Backend
83
+ class AwsClientApi < AwsBackendBase
84
+ BackendFactory.set_default_backend(self)
85
+ self.aws_client_class = Aws::EC2::Client
86
+
87
+ def describe_subnets(query)
88
+ aws_service_client.describe_subnets(query)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,56 @@
1
+ require "resource_support/aws/aws_plural_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-ec2"
4
+
5
+ class AwsSubnets < Inspec.resource(1)
6
+ name "aws_subnets"
7
+ desc "Verifies settings for VPC Subnets in bulk"
8
+ example <<~EXAMPLE
9
+ # you should be able to test the cidr_block of a subnet
10
+ describe aws_subnets.where(vpc_id: 'vpc-123456789') do
11
+ its('subnet_ids') { should eq ['subnet-12345678', 'subnet-87654321'] }
12
+ its('cidr_blocks') { should eq ['172.31.96.0/20'] }
13
+ its('states') { should_not include 'pending' }
14
+ end
15
+ EXAMPLE
16
+ supports platform: "aws"
17
+
18
+ include AwsPluralResourceMixin
19
+
20
+ def validate_params(resource_params)
21
+ unless resource_params.empty?
22
+ raise ArgumentError, "aws_vpc_subnets does not accept resource parameters."
23
+ end
24
+
25
+ resource_params
26
+ end
27
+
28
+ def fetch_from_api
29
+ backend = BackendFactory.create(inspec_runner)
30
+ @table = backend.describe_subnets.subnets.map(&:to_h)
31
+ end
32
+
33
+ # Underlying FilterTable implementation.
34
+ filter = FilterTable.create
35
+ filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
36
+ filter.register_column(:vpc_ids, field: :vpc_id)
37
+ .register_column(:subnet_ids, field: :subnet_id)
38
+ .register_column(:cidr_blocks, field: :cidr_block)
39
+ .register_column(:states, field: :state)
40
+ filter.install_filter_methods_on_resource(self, :table)
41
+
42
+ def to_s
43
+ "EC2 VPC Subnets"
44
+ end
45
+
46
+ class Backend
47
+ class AwsClientApi < AwsBackendBase
48
+ BackendFactory.set_default_backend self
49
+ self.aws_client_class = Aws::EC2::Client
50
+
51
+ def describe_subnets(query = {})
52
+ aws_service_client.describe_subnets(query)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,77 @@
1
+ require "resource_support/aws/aws_singular_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-ec2"
4
+
5
+ class AwsVpc < Inspec.resource(1)
6
+ name "aws_vpc"
7
+ desc "Verifies settings for AWS VPC"
8
+ example <<~EXAMPLE
9
+ describe aws_vpc do
10
+ it { should be_default }
11
+ its('cidr_block') { should cmp '10.0.0.0/16' }
12
+ end
13
+ EXAMPLE
14
+ supports platform: "aws"
15
+
16
+ include AwsSingularResourceMixin
17
+
18
+ def to_s
19
+ "VPC #{vpc_id}"
20
+ end
21
+
22
+ attr_reader :cidr_block, :dhcp_options_id, :instance_tenancy, :is_default,
23
+ :state, :vpc_id
24
+
25
+ alias default? is_default
26
+
27
+ private
28
+
29
+ def validate_params(raw_params)
30
+ validated_params = check_resource_param_names(
31
+ raw_params: raw_params,
32
+ allowed_params: [:vpc_id],
33
+ allowed_scalar_name: :vpc_id,
34
+ allowed_scalar_type: String
35
+ )
36
+
37
+ if validated_params.key?(:vpc_id) && validated_params[:vpc_id] !~ /^vpc\-([0-9a-f]{8})|(^vpc\-[0-9a-f]{17})$/
38
+ raise ArgumentError, 'aws_vpc VPC ID must be in the format "vpc-" followed by 8 or 17 hexadecimal characters.'
39
+ end
40
+
41
+ validated_params
42
+ end
43
+
44
+ def fetch_from_api
45
+ backend = BackendFactory.create(inspec_runner)
46
+
47
+ if @vpc_id.nil?
48
+ filter = { name: "isDefault", values: ["true"] }
49
+ else
50
+ filter = { name: "vpc-id", values: [@vpc_id] }
51
+ end
52
+
53
+ resp = backend.describe_vpcs({ filters: [filter] })
54
+
55
+ vpc = resp.vpcs[0].to_h
56
+ @exists = !vpc.empty?
57
+ return unless @exists
58
+
59
+ @cidr_block = vpc[:cidr_block]
60
+ @dhcp_options_id = vpc[:dhcp_options_id]
61
+ @instance_tenancy = vpc[:instance_tenancy]
62
+ @is_default = vpc[:is_default]
63
+ @state = vpc[:state]
64
+ @vpc_id = vpc[:vpc_id]
65
+ end
66
+
67
+ class Backend
68
+ class AwsClientApi < AwsBackendBase
69
+ BackendFactory.set_default_backend(self)
70
+ self.aws_client_class = Aws::EC2::Client
71
+
72
+ def describe_vpcs(query)
73
+ aws_service_client.describe_vpcs(query)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,55 @@
1
+ require "resource_support/aws/aws_plural_resource_mixin"
2
+ require "resource_support/aws/aws_backend_base"
3
+ require "aws-sdk-ec2"
4
+
5
+ class AwsVpcs < Inspec.resource(1)
6
+ name "aws_vpcs"
7
+ desc "Verifies settings for AWS VPCs in bulk"
8
+ example <<~EXAMPLE
9
+ describe aws_vpcs do
10
+ it { should exist }
11
+ end
12
+ EXAMPLE
13
+ supports platform: "aws"
14
+
15
+ include AwsPluralResourceMixin
16
+
17
+ # Underlying FilterTable implementation.
18
+ filter = FilterTable.create
19
+ filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
20
+ filter.register_column(:cidr_blocks, field: :cidr_block)
21
+ .register_column(:vpc_ids, field: :vpc_id)
22
+ # We need a dummy here, so FilterTable will define and populate the dhcp_options_id field
23
+ filter.register_column(:dummy, field: :dhcp_options_id)
24
+ .register_column(:dhcp_options_ids) { |obj| obj.entries.map(&:dhcp_options_id).uniq }
25
+ filter.install_filter_methods_on_resource(self, :table)
26
+
27
+ def validate_params(raw_params)
28
+ # No params yet
29
+ unless raw_params.empty?
30
+ raise ArgumentError, "aws_vpcs does not accept resource parameters"
31
+ end
32
+
33
+ raw_params
34
+ end
35
+
36
+ def to_s
37
+ "VPCs"
38
+ end
39
+
40
+ def fetch_from_api
41
+ describe_vpcs_response = BackendFactory.create(inspec_runner).describe_vpcs
42
+ @table = describe_vpcs_response.to_h[:vpcs].map(&:to_h)
43
+ end
44
+
45
+ class Backend
46
+ class AwsClientApi < AwsBackendBase
47
+ BackendFactory.set_default_backend(self)
48
+ self.aws_client_class = Aws::EC2::Client
49
+
50
+ def describe_vpcs(query = {})
51
+ aws_service_client.describe_vpcs(query)
52
+ end
53
+ end
54
+ end
55
+ end