From ad2eee9fd393859835d3bf90c6591bae87367cdd Mon Sep 17 00:00:00 2001 From: jnahelou Date: Wed, 2 Jan 2019 16:26:07 +0100 Subject: [PATCH 1/5] Add pubsub support using Magic Module --- docs/resources/google_pubsub_subscription.md | 29 +++ docs/resources/google_pubsub_subscriptions.md | 37 +++ docs/resources/google_pubsub_topic.md | 21 ++ docs/resources/google_pubsub_topics.md | 34 +++ libraries/gcp_backend.rb | 213 ++++++++++++++++++ .../property/subscription_push_config.rb | 30 +++ libraries/google_pubsub_subscription.rb | 53 +++++ libraries/google_pubsub_subscriptions.rb | 65 ++++++ libraries/google_pubsub_topic.rb | 46 ++++ libraries/google_pubsub_topics.rb | 62 +++++ 10 files changed, 590 insertions(+) create mode 100644 docs/resources/google_pubsub_subscription.md create mode 100644 docs/resources/google_pubsub_subscriptions.md create mode 100644 docs/resources/google_pubsub_topic.md create mode 100644 docs/resources/google_pubsub_topics.md create mode 100644 libraries/google/pubsub/property/subscription_push_config.rb create mode 100644 libraries/google_pubsub_subscription.rb create mode 100644 libraries/google_pubsub_subscriptions.rb create mode 100644 libraries/google_pubsub_topic.rb create mode 100644 libraries/google_pubsub_topics.rb diff --git a/docs/resources/google_pubsub_subscription.md b/docs/resources/google_pubsub_subscription.md new file mode 100644 index 000000000..3156d5ced --- /dev/null +++ b/docs/resources/google_pubsub_subscription.md @@ -0,0 +1,29 @@ +--- +title: About the Subscription resource +platform: gcp +--- + + +## Syntax +A `google_pubsub_subscription` is used to test a Google Subscription resource + +## Examples +``` +describe google_pubsub_subscription({project: 'inspec-gcp-project', name: 'inspec-gcp-subscription'}) do + it { should exist } +end + +``` + +## Properties +Properties that can be accessed from the `google_pubsub_subscription` resource: + + * `name`: Name of the subscription. + + * `topic`: A reference to a Topic resource. + + * `push_config`: If push delivery is used with this subscription, this field is used to configure it. An empty pushConfig signifies that the subscriber will pull and ack messages using API methods. + + * `pushEndpoint`: A URL locating the endpoint to which messages should be pushed. For example, a Webhook endpoint might use "https://example.com/push". + + * `ack_deadline_seconds`: This value is the maximum time after a subscriber receives a message before the subscriber should acknowledge the message. After message delivery but before the ack deadline expires and before the message is acknowledged, it is an outstanding message and will not be delivered again during that time (on a best-effort basis). For pull subscriptions, this value is used as the initial value for the ack deadline. To override this value for a given message, call subscriptions.modifyAckDeadline with the corresponding ackId if using pull. The minimum custom deadline you can specify is 10 seconds. The maximum custom deadline you can specify is 600 seconds (10 minutes). If this parameter is 0, a default value of 10 seconds is used. For push delivery, this value is also used to set the request timeout for the call to the push endpoint. If the subscriber never acknowledges the message, the Pub/Sub system will eventually redeliver the message. diff --git a/docs/resources/google_pubsub_subscriptions.md b/docs/resources/google_pubsub_subscriptions.md new file mode 100644 index 000000000..c81a8bb51 --- /dev/null +++ b/docs/resources/google_pubsub_subscriptions.md @@ -0,0 +1,37 @@ +--- +title: About the Subscription resource +platform: gcp +--- + + +## Syntax +A `google_pubsub_subscriptions` is used to test a Google Subscription resource + +## Examples +``` +describe google_pubsub_subscriptions({project: 'inspec-gcp-project'}) do + it { should exist } + its('names') { should include 'inspec-gcp-topic' } + its('count') { should eq 1 } +end + +google_pubsub_subscriptions({project: 'inspec-gcp-project'}).names.each do |policy_name| + describe google_pubsub_topic({project: 'inspec-gcp-project', name: policy_name}) do + its('name') { should eq 'inspec-gcp-topic' } + end +end + +``` + +## Properties +Properties that can be accessed from the `google_pubsub_subscriptions` resource: + +See [google_pubsub_subscription.md](google_pubsub_subscription.md) for more detailed information + * `names`: an array of `google_pubsub_subscription` name + * `topics`: an array of `google_pubsub_subscription` topic + * `push_configs`: an array of `google_pubsub_subscription` push_config + * `ack_deadline_seconds`: an array of `google_pubsub_subscription` ack_deadline_seconds + +## Filter Criteria +This resource supports all of the above properties as filter criteria, which can be used +with `where` as a block or a method. diff --git a/docs/resources/google_pubsub_topic.md b/docs/resources/google_pubsub_topic.md new file mode 100644 index 000000000..016556f95 --- /dev/null +++ b/docs/resources/google_pubsub_topic.md @@ -0,0 +1,21 @@ +--- +title: About the Topic resource +platform: gcp +--- + + +## Syntax +A `google_pubsub_topic` is used to test a Google Topic resource + +## Examples +``` +describe google_pubsub_topic({project: 'inspec-gcp-project', name: 'inspec-gcp-topic'}) do + it { should exist } +end + +``` + +## Properties +Properties that can be accessed from the `google_pubsub_topic` resource: + + * `name`: Name of the topic. diff --git a/docs/resources/google_pubsub_topics.md b/docs/resources/google_pubsub_topics.md new file mode 100644 index 000000000..1a36d4c77 --- /dev/null +++ b/docs/resources/google_pubsub_topics.md @@ -0,0 +1,34 @@ +--- +title: About the Topic resource +platform: gcp +--- + + +## Syntax +A `google_pubsub_topics` is used to test a Google Topic resource + +## Examples +``` +describe google_pubsub_topics({project: 'inspec-gcp-project'}) do + it { should exist } + its('names') { should include 'inspec-gcp-topic' } + its('count') { should eq 1 } +end + +google_pubsub_topics({project: 'inspec-gcp-project'}).names.each do |policy_name| + describe google_pubsub_topic({project: 'inspec-gcp-project', name: policy_name}) do + its('name') { should eq 'inspec-gcp-topic' } + end +end + +``` + +## Properties +Properties that can be accessed from the `google_pubsub_topics` resource: + +See [google_pubsub_topic.md](google_pubsub_topic.md) for more detailed information + * `names`: an array of `google_pubsub_topic` name + +## Filter Criteria +This resource supports all of the above properties as filter criteria, which can be used +with `where` as a block or a method. diff --git a/libraries/gcp_backend.rb b/libraries/gcp_backend.rb index 41e9c7e99..492d95ad6 100644 --- a/libraries/gcp_backend.rb +++ b/libraries/gcp_backend.rb @@ -6,6 +6,8 @@ # require 'json' +require 'net/http' +require 'googleauth' # Base class for GCP resources - depends on train GCP transport for connection # @@ -17,6 +19,10 @@ def initialize(opts) @opts = opts # ensure we have a GCP connection, resources can choose which of the clients to instantiate @gcp = inspec.backend + + # Magic Modules generated resources use an alternate transport method + # In the future this will be moved into the train-gcp plugin itself + @connection = GcpApiConnection.new if opts[:use_http_transport] end def failed_resource? @@ -178,3 +184,210 @@ def camel_case(data) camel_case_data.gsub(/[gb]/, &:upcase) end end + +class GcpApiConnection + def initialize + @service_account_file = ENV['GOOGLE_APPLICATION_CREDENTIALS'] + end + + def fetch_auth + unless @service_account_file.nil? + return Network::Authorization.new.for!( + ['https://www.googleapis.com/auth/compute.readonly'], + ).from_service_account_json!( + @service_account_file, + ) + end + Network::Authorization.new.from_application_default! + end + + def fetch(base_url, template, var_data) + get_request = Network::Base.new( + build_uri(base_url, template, var_data), + fetch_auth, + ) + return_if_object get_request.send + end + + def fetch_all(base_url, template, var_data) + next_page(build_uri(base_url, template, var_data)) + end + + def next_page(uri, token = nil) + next_hash = {} + next_hash['pageToken'] = token unless token.nil? + current_params = Hash[URI.decode_www_form(uri.query || '')].merge(next_hash) + uri.query = URI.encode_www_form(current_params) + get_request = Network::Base.new( + uri, + fetch_auth, + ) + result = JSON.parse(get_request.send.body) + next_page_token = result['nextPageToken'] + return [result] if next_page_token.nil? + + [result] + next_page(uri, next_page_token) + end + + def return_if_object(response) + raise "Bad response: #{response.body}" \ + if response.is_a?(Net::HTTPBadRequest) + raise "Bad response: #{response}" \ + unless response.is_a?(Net::HTTPResponse) + return if response.is_a?(Net::HTTPNotFound) + return if response.is_a?(Net::HTTPNoContent) + result = JSON.parse(response.body) + raise_if_errors result, %w{error errors}, 'message' + raise "Bad response: #{response}" unless response.is_a?(Net::HTTPOK) + result + end + + def raise_if_errors(response, err_path, msg_field) + errors = self.class.navigate(response, err_path) + raise_error(errors, msg_field) unless errors.nil? + end + + def raise_error(errors, msg_field) + raise IOError, ['Operation failed:', + errors.map { |e| e[msg_field] }.join(', ')].join(' ') + end + + def build_uri(base_url, template, var_data) + URI.join( + base_url, + expand_variables(template, var_data), + ) + end + + # Allows fetching objects within a tree path. + def self.navigate(source, path, default = nil) + key = path.take(1)[0] + path = path.drop(1) + return default unless source.key?(key) + result = source.fetch(key) + return navigate(result, path, default) unless path.empty? + return result if path.empty? + end + + def extract_variables(template) + template.scan(/{{[^}]*}}/).map { |v| v.gsub(/{{([^}]*)}}/, '\1') } + .map(&:to_sym) + end + + def expand_variables(template, var_data) + extract_variables(template).each do |v| + unless var_data.key?(v) + raise "Missing variable :#{v} in #{var_data} on #{caller.join("\n")}}" + end + template.gsub!(/{{#{v}}}/, CGI.escape(var_data[v].to_s)) + end + template + end +end + +# A handler for authenticated network request +module Network + class Base + def initialize(link, cred) + @link = link + @cred = cred + end + + def builder + Net::HTTP.const_get('Get') + end + + def send + request = @cred.authorize(builder.new(@link)) + request['User-Agent'] = generate_user_agent + response = transport(request).request(request) + unless ENV['GOOGLE_HTTP_VERBOSE'].nil? + puts ["network(#{request}: [#{response.code}]", + response.body.split("\n").map(&:strip).join(' ')].join(' ') + end + response + end + + def transport(request) + uri = request.uri + puts "network(#{request}: #{uri})" \ + unless ENV['GOOGLE_HTTP_VERBOSE'].nil? + transport = Net::HTTP.new(uri.host, uri.port) + transport.use_ssl = uri.is_a?(URI::HTTPS) + transport.verify_mode = OpenSSL::SSL::VERIFY_PEER + transport.set_debug_output $stderr \ + unless ENV['GOOGLE_HTTP_DEBUG'].nil? + transport + end + + private + + def generate_user_agent + 'inspec-google/1.0.0' + end + end + + # A class to aquire credentials and authorize Google API calls. + class Authorization + def initialize + @authorization = nil + @scopes = [] + end + + def authorize(obj) + raise ArgumentError, 'A from_* method needs to be called before' \ + unless @authorization + + if obj.class <= URI::HTTPS || obj.class <= URI::HTTP + authorize_uri obj + elsif obj.class < Net::HTTPRequest + authorize_http obj + else + obj.authorization = @authorization + obj + end + end + + def for!(*scopes) + @scopes = scopes + self + end + + def from_service_account_json!(service_account_file) + raise 'Missing argument for scopes' if @scopes.empty? + @authorization = ::Google::Auth::ServiceAccountCredentials.make_creds( + json_key_io: File.open(service_account_file), + scope: @scopes, + ) + self + end + + def from_application_default! + @authorization = ::Google::Auth.get_application_default + self + end + + private + + def authorize_uri(obj) + http = Net::HTTP.new(obj.host, obj.port) + http.use_ssl = obj.instance_of?(URI::HTTPS) + http.verify_mode = OpenSSL::SSL::VERIFY_PEER + [http, authorize_http(Net::HTTP::Get.new(obj.request_uri))] + end + + def authorize_http(req) + req.extend TokenProperty + auth = {} + @authorization.apply!(auth) + req['Authorization'] = auth[:authorization] + req.token = auth[:authorization].split(' ')[1] + req + end + end + # Extension methods to enable retrieving the authentication token. + module TokenProperty + attr_reader :token + attr_writer :token + end +end diff --git a/libraries/google/pubsub/property/subscription_push_config.rb b/libraries/google/pubsub/property/subscription_push_config.rb new file mode 100644 index 000000000..53daf2fef --- /dev/null +++ b/libraries/google/pubsub/property/subscription_push_config.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: false + +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- +module GoogleInSpec + module Pubsub + module Property + class SubscriptionPushconfig + attr_reader :push_endpoint + + def initialize(args = nil) + return if args.nil? + @push_endpoint = args['pushEndpoint'] + end + end + + end + end +end diff --git a/libraries/google_pubsub_subscription.rb b/libraries/google_pubsub_subscription.rb new file mode 100644 index 000000000..373971c1f --- /dev/null +++ b/libraries/google_pubsub_subscription.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: false + +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- +require 'gcp_backend' +require 'google/pubsub/property/subscription_push_config' + +# A provider to manage Google Cloud Pub/Sub resources. +class Subscription < GcpResourceBase + name 'google_pubsub_subscription' + desc 'Subscription' + supports platform: 'gcp' + + attr_reader :name + attr_reader :topic + attr_reader :push_config + attr_reader :ack_deadline_seconds + def base + 'https://pubsub.googleapis.com/v1/' + end + + def url + 'projects/{{project}}/subscriptions/{{name}}' + end + + def initialize(params) + super(params.merge({ use_http_transport: true })) + @fetched = @connection.fetch(base, url, params) + parse unless @fetched.nil? + end + + def parse + @name = @fetched['name'] + @topic = @fetched['topic'] + @push_config = GoogleInSpec::Pubsub::Property::SubscriptionPushconfig.new(@fetched['pushConfig']) + @ack_deadline_seconds = @fetched['ackDeadlineSeconds'] + end + + def exists? + !@fetched.nil? + end +end diff --git a/libraries/google_pubsub_subscriptions.rb b/libraries/google_pubsub_subscriptions.rb new file mode 100644 index 000000000..b1afd96e2 --- /dev/null +++ b/libraries/google_pubsub_subscriptions.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: false + +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- +require 'gcp_backend' +class Subscriptions < GcpResourceBase + name 'google_pubsub_subscriptions' + desc 'Subscription plural resource' + supports platform: 'gcp' + + attr_reader :table + + filter_table_config = FilterTable.create + + filter_table_config.add(:names, field: :name) + filter_table_config.add(:topics, field: :topic) + filter_table_config.add(:push_configs, field: :pushConfig) + filter_table_config.add(:ack_deadline_seconds, field: :ackDeadlineSeconds) + + filter_table_config.connect(self, :table) + + def base + 'https://pubsub.googleapis.com/v1/' + end + + def url + 'projects/{{project}}/subscriptions' + end + + def initialize(params = {}) + super(params.merge({ use_http_transport: true })) + @params = params + @table = fetch_wrapped_resource('subscriptions') + end + + def fetch_wrapped_resource(wrap_path) + # fetch_resource returns an array of responses (to handle pagination) + result = @connection.fetch_all(base, url, @params) + return if result.nil? + + # Conversion of string -> object hash to symbol -> object hash that InSpec needs + converted = [] + result.each do |response| + next if response.nil? || !response.key?(wrap_path) + response[wrap_path].each do |hash| + hash_with_symbols = {} + hash.each_pair { |k, v| hash_with_symbols[k.to_sym] = v } + converted.push(hash_with_symbols) + end + end + + converted + end +end diff --git a/libraries/google_pubsub_topic.rb b/libraries/google_pubsub_topic.rb new file mode 100644 index 000000000..66f66c9c4 --- /dev/null +++ b/libraries/google_pubsub_topic.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: false + +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- +require 'gcp_backend' + +# A provider to manage Google Cloud Pub/Sub resources. +class Topic < GcpResourceBase + name 'google_pubsub_topic' + desc 'Topic' + supports platform: 'gcp' + + attr_reader :name + def base + 'https://pubsub.googleapis.com/v1/' + end + + def url + 'projects/{{project}}/topics/{{name}}' + end + + def initialize(params) + super(params.merge({ use_http_transport: true })) + @fetched = @connection.fetch(base, url, params) + parse unless @fetched.nil? + end + + def parse + @name = @fetched['name'] + end + + def exists? + !@fetched.nil? + end +end diff --git a/libraries/google_pubsub_topics.rb b/libraries/google_pubsub_topics.rb new file mode 100644 index 000000000..4240fb497 --- /dev/null +++ b/libraries/google_pubsub_topics.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: false + +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- +require 'gcp_backend' +class Topics < GcpResourceBase + name 'google_pubsub_topics' + desc 'Topic plural resource' + supports platform: 'gcp' + + attr_reader :table + + filter_table_config = FilterTable.create + + filter_table_config.add(:names, field: :name) + + filter_table_config.connect(self, :table) + + def base + 'https://pubsub.googleapis.com/v1/' + end + + def url + 'projects/{{project}}/topics' + end + + def initialize(params = {}) + super(params.merge({ use_http_transport: true })) + @params = params + @table = fetch_wrapped_resource('topics') + end + + def fetch_wrapped_resource(wrap_path) + # fetch_resource returns an array of responses (to handle pagination) + result = @connection.fetch_all(base, url, @params) + return if result.nil? + + # Conversion of string -> object hash to symbol -> object hash that InSpec needs + converted = [] + result.each do |response| + next if response.nil? || !response.key?(wrap_path) + response[wrap_path].each do |hash| + hash_with_symbols = {} + hash.each_pair { |k, v| hash_with_symbols[k.to_sym] = v } + converted.push(hash_with_symbols) + end + end + + converted + end +end From 558f1f9cf72eddd1c28cba46c436d3d8043902af Mon Sep 17 00:00:00 2001 From: jnahelou Date: Thu, 3 Jan 2019 17:34:47 +0100 Subject: [PATCH 2/5] Add pubsub scope --- libraries/gcp_backend.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gcp_backend.rb b/libraries/gcp_backend.rb index 492d95ad6..05a14be23 100644 --- a/libraries/gcp_backend.rb +++ b/libraries/gcp_backend.rb @@ -193,7 +193,7 @@ def initialize def fetch_auth unless @service_account_file.nil? return Network::Authorization.new.for!( - ['https://www.googleapis.com/auth/compute.readonly'], + ['https://www.googleapis.com/auth/compute.readonly', 'https://www.googleapis.com/auth/pubsub'], ).from_service_account_json!( @service_account_file, ) From 30d25c8f6afef897c9f5b1bde04c99d472d1bb7f Mon Sep 17 00:00:00 2001 From: jnahelou Date: Fri, 4 Jan 2019 16:48:32 +0100 Subject: [PATCH 3/5] Add pubsub tests --- test/integration/build/gcp-mm.tf | 31 ++++++++++++++++ .../configuration/mm-attributes.yml | 10 ++++++ .../controls/google_pubsub_subscription.rb | 27 ++++++++++++++ .../controls/google_pubsub_subscriptions.rb | 35 +++++++++++++++++++ .../verify/controls/google_pubsub_topic.rb | 27 ++++++++++++++ .../verify/controls/google_pubsub_topics.rb | 35 +++++++++++++++++++ 6 files changed, 165 insertions(+) create mode 100644 test/integration/build/gcp-mm.tf create mode 100644 test/integration/configuration/mm-attributes.yml create mode 100644 test/integration/verify/controls/google_pubsub_subscription.rb create mode 100644 test/integration/verify/controls/google_pubsub_subscriptions.rb create mode 100644 test/integration/verify/controls/google_pubsub_topic.rb create mode 100644 test/integration/verify/controls/google_pubsub_topics.rb diff --git a/test/integration/build/gcp-mm.tf b/test/integration/build/gcp-mm.tf new file mode 100644 index 000000000..e2ff015c5 --- /dev/null +++ b/test/integration/build/gcp-mm.tf @@ -0,0 +1,31 @@ +variable "ssl_policy" { + type = "map" +} + +variable "topic" { + type = "map" +} + +variable "subscription" { + type = "map" +} + +resource "google_compute_ssl_policy" "custom-ssl-policy" { + name = "${var.ssl_policy["name"]}" + min_tls_version = "${var.ssl_policy["min_tls_version"]}" + profile = "${var.ssl_policy["profile"]}" + custom_features = ["${var.ssl_policy["custom_feature"]}", "${var.ssl_policy["custom_feature2"]}"] + project = "${var.gcp_project_id}" +} + +resource "google_pubsub_topic" "topic" { + project = "${var.gcp_project_id}" + name = "${var.topic["name"]}" +} + +resource "google_pubsub_subscription" "default" { + project = "${var.gcp_project_id}" + name = "${var.subscription["name"]}" + topic = "${google_pubsub_topic.topic.name}" + ack_deadline_seconds = 20 +} diff --git a/test/integration/configuration/mm-attributes.yml b/test/integration/configuration/mm-attributes.yml new file mode 100644 index 000000000..9dd1c1011 --- /dev/null +++ b/test/integration/configuration/mm-attributes.yml @@ -0,0 +1,10 @@ +ssl_policy: + name: 'inspec-gcp-ssl-policy' + min_tls_version: 'TLS_1_2' + profile: 'CUSTOM' + custom_feature: 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384' + custom_feature2: 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384' +topic: + name: 'inspec-gcp-topic' +subscription: + name: 'inspec-gcp-subscription' diff --git a/test/integration/verify/controls/google_pubsub_subscription.rb b/test/integration/verify/controls/google_pubsub_subscription.rb new file mode 100644 index 000000000..23b646a2c --- /dev/null +++ b/test/integration/verify/controls/google_pubsub_subscription.rb @@ -0,0 +1,27 @@ +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- + +title 'Test GCP google_pubsub_subscription resource.' + +gcp_project_id = attribute(:gcp_gcp_project_id, default: '', description: 'The GCP project identifier.') +subscription = attribute('subscription', default: {"name"=>"inspec-gcp-subscription"}) + +control 'google_pubsub_subscription-1.0' do + impact 1.0 + title 'google_pubsub_subscription resource test' + + describe google_pubsub_subscription(project: gcp_project_id, name: subscription['name']) do + it { should exist } + end +end diff --git a/test/integration/verify/controls/google_pubsub_subscriptions.rb b/test/integration/verify/controls/google_pubsub_subscriptions.rb new file mode 100644 index 000000000..1fe7837d3 --- /dev/null +++ b/test/integration/verify/controls/google_pubsub_subscriptions.rb @@ -0,0 +1,35 @@ +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- + +title 'Test GCP google_pubsub_subscriptions resource.' + +gcp_project_id = attribute(:gcp_gcp_project_id, default: '', description: 'The GCP project identifier.') +subscription = attribute('subscription', default: {"name"=>"inspec-gcp-subscription"}) + +control 'google_pubsub_subscriptions-1.0' do + impact 1.0 + title 'google_pubsub_subscriptions resource test' + + describe google_pubsub_subscriptions(project: gcp_project_id) do + it { should exist } + its('names') { should include topic['name'] } + its('count') { should eq 1 } + end + + google_pubsub_subscriptions(project: gcp_project_id).names.each do |subscription_name| + describe google_pubsub_topic(project: gcp_project_id, name: subscription_name) do + its('name') { should eq topic['name'] } + end + end +end diff --git a/test/integration/verify/controls/google_pubsub_topic.rb b/test/integration/verify/controls/google_pubsub_topic.rb new file mode 100644 index 000000000..6faaf40a4 --- /dev/null +++ b/test/integration/verify/controls/google_pubsub_topic.rb @@ -0,0 +1,27 @@ +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- + +title 'Test GCP google_pubsub_topic resource.' + +gcp_project_id = attribute(:gcp_gcp_project_id, default: '', description: 'The GCP project identifier.') +topic = attribute('topic', default: {"name"=>"inspec-gcp-topic"}) + +control 'google_pubsub_topic-1.0' do + impact 1.0 + title 'google_pubsub_topic resource test' + + describe google_pubsub_topic(project: gcp_project_id, name: topic['name']) do + it { should exist } + end +end diff --git a/test/integration/verify/controls/google_pubsub_topics.rb b/test/integration/verify/controls/google_pubsub_topics.rb new file mode 100644 index 000000000..af308bde8 --- /dev/null +++ b/test/integration/verify/controls/google_pubsub_topics.rb @@ -0,0 +1,35 @@ +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** AUTO GENERATED CODE *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in README.md and +# CONTRIBUTING.md located at the root of this package. +# +# ---------------------------------------------------------------------------- + +title 'Test GCP google_pubsub_topics resource.' + +gcp_project_id = attribute(:gcp_gcp_project_id, default: '', description: 'The GCP project identifier.') +topic = attribute('topic', default: {"name"=>"inspec-gcp-topic"}) + +control 'google_pubsub_topics-1.0' do + impact 1.0 + title 'google_pubsub_topics resource test' + + describe google_pubsub_topics(project: gcp_project_id) do + it { should exist } + its('names') { should include topic['name'] } + its('count') { should eq 1 } + end + + google_pubsub_topics(project: gcp_project_id).names.each do |topic_name| + describe google_pubsub_topic(project: gcp_project_id, name: topic_name) do + its('name') { should eq topic['name'] } + end + end +end From 5b3b46b00241552feac877741d1598d3fab83c53 Mon Sep 17 00:00:00 2001 From: jnahelou Date: Sat, 5 Jan 2019 17:49:08 +0100 Subject: [PATCH 4/5] Convert name from self link to name Signed-off-by: jnahelou --- libraries/gcp_backend.rb | 4 ++++ .../google/pubsub/property/subscription_push_config.rb | 1 - libraries/google_pubsub_subscription.rb | 7 ++++++- libraries/google_pubsub_subscriptions.rb | 1 + libraries/google_pubsub_topic.rb | 7 ++++++- libraries/google_pubsub_topics.rb | 1 + 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/libraries/gcp_backend.rb b/libraries/gcp_backend.rb index 05a14be23..bd0c2926f 100644 --- a/libraries/gcp_backend.rb +++ b/libraries/gcp_backend.rb @@ -44,6 +44,10 @@ def create_resource_methods(object) dm = GcpResourceDynamicMethods.new dm.create_methods(self, object) end + + def name_from_self_link(property) + property.split('/').last if !property.nil? + end end # end diff --git a/libraries/google/pubsub/property/subscription_push_config.rb b/libraries/google/pubsub/property/subscription_push_config.rb index 53daf2fef..234cf0bfd 100644 --- a/libraries/google/pubsub/property/subscription_push_config.rb +++ b/libraries/google/pubsub/property/subscription_push_config.rb @@ -24,7 +24,6 @@ def initialize(args = nil) @push_endpoint = args['pushEndpoint'] end end - end end end diff --git a/libraries/google_pubsub_subscription.rb b/libraries/google_pubsub_subscription.rb index 373971c1f..4138c7b22 100644 --- a/libraries/google_pubsub_subscription.rb +++ b/libraries/google_pubsub_subscription.rb @@ -41,12 +41,17 @@ def initialize(params) end def parse - @name = @fetched['name'] + @name = name_from_self_link(@fetched['name']) @topic = @fetched['topic'] @push_config = GoogleInSpec::Pubsub::Property::SubscriptionPushconfig.new(@fetched['pushConfig']) @ack_deadline_seconds = @fetched['ackDeadlineSeconds'] end + # Handles parsing RFC3339 time string + def parse_time_string(time_string) + time_string ? Time.parse(time_string) : nil + end + def exists? !@fetched.nil? end diff --git a/libraries/google_pubsub_subscriptions.rb b/libraries/google_pubsub_subscriptions.rb index b1afd96e2..902c6ff61 100644 --- a/libraries/google_pubsub_subscriptions.rb +++ b/libraries/google_pubsub_subscriptions.rb @@ -56,6 +56,7 @@ def fetch_wrapped_resource(wrap_path) response[wrap_path].each do |hash| hash_with_symbols = {} hash.each_pair { |k, v| hash_with_symbols[k.to_sym] = v } + hash_with_symbols[:name] = name_from_self_link(hash_with_symbols[:name]) converted.push(hash_with_symbols) end end diff --git a/libraries/google_pubsub_topic.rb b/libraries/google_pubsub_topic.rb index 66f66c9c4..163cddfcf 100644 --- a/libraries/google_pubsub_topic.rb +++ b/libraries/google_pubsub_topic.rb @@ -37,7 +37,12 @@ def initialize(params) end def parse - @name = @fetched['name'] + @name = name_from_self_link(@fetched['name']) + end + + # Handles parsing RFC3339 time string + def parse_time_string(time_string) + time_string ? Time.parse(time_string) : nil end def exists? diff --git a/libraries/google_pubsub_topics.rb b/libraries/google_pubsub_topics.rb index 4240fb497..236f933e5 100644 --- a/libraries/google_pubsub_topics.rb +++ b/libraries/google_pubsub_topics.rb @@ -53,6 +53,7 @@ def fetch_wrapped_resource(wrap_path) response[wrap_path].each do |hash| hash_with_symbols = {} hash.each_pair { |k, v| hash_with_symbols[k.to_sym] = v } + hash_with_symbols[:name] = name_from_self_link(hash_with_symbols[:name]) converted.push(hash_with_symbols) end end From 3fd41e6a410efdebdf9951a5a6805005b079e92c Mon Sep 17 00:00:00 2001 From: jnahelou Date: Tue, 8 Jan 2019 09:29:14 +0100 Subject: [PATCH 5/5] Updates pubsub tests Signed-off-by: jnahelou --- test/integration/build/gcp-mm.tf | 2 +- test/integration/configuration/mm-attributes.yml | 2 ++ .../verify/controls/google_pubsub_subscription.rb | 4 ++-- .../verify/controls/google_pubsub_subscriptions.rb | 9 ++++----- test/integration/verify/controls/google_pubsub_topic.rb | 2 +- test/integration/verify/controls/google_pubsub_topics.rb | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/test/integration/build/gcp-mm.tf b/test/integration/build/gcp-mm.tf index e2ff015c5..9b7853230 100644 --- a/test/integration/build/gcp-mm.tf +++ b/test/integration/build/gcp-mm.tf @@ -27,5 +27,5 @@ resource "google_pubsub_subscription" "default" { project = "${var.gcp_project_id}" name = "${var.subscription["name"]}" topic = "${google_pubsub_topic.topic.name}" - ack_deadline_seconds = 20 + ack_deadline_seconds = "${var.subscription["ack_deadline_seconds"]}" } diff --git a/test/integration/configuration/mm-attributes.yml b/test/integration/configuration/mm-attributes.yml index 9dd1c1011..64fa7bf6f 100644 --- a/test/integration/configuration/mm-attributes.yml +++ b/test/integration/configuration/mm-attributes.yml @@ -8,3 +8,5 @@ topic: name: 'inspec-gcp-topic' subscription: name: 'inspec-gcp-subscription' + ack_deadline_seconds: 20 + diff --git a/test/integration/verify/controls/google_pubsub_subscription.rb b/test/integration/verify/controls/google_pubsub_subscription.rb index 23b646a2c..bde2c6cd8 100644 --- a/test/integration/verify/controls/google_pubsub_subscription.rb +++ b/test/integration/verify/controls/google_pubsub_subscription.rb @@ -14,8 +14,8 @@ title 'Test GCP google_pubsub_subscription resource.' -gcp_project_id = attribute(:gcp_gcp_project_id, default: '', description: 'The GCP project identifier.') -subscription = attribute('subscription', default: {"name"=>"inspec-gcp-subscription"}) +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +subscription = attribute('subscription', default: {"name"=>"inspec-gcp-subscription", "ack_deadline_seconds"=>20}) control 'google_pubsub_subscription-1.0' do impact 1.0 diff --git a/test/integration/verify/controls/google_pubsub_subscriptions.rb b/test/integration/verify/controls/google_pubsub_subscriptions.rb index 1fe7837d3..f90f2f59b 100644 --- a/test/integration/verify/controls/google_pubsub_subscriptions.rb +++ b/test/integration/verify/controls/google_pubsub_subscriptions.rb @@ -14,8 +14,8 @@ title 'Test GCP google_pubsub_subscriptions resource.' -gcp_project_id = attribute(:gcp_gcp_project_id, default: '', description: 'The GCP project identifier.') -subscription = attribute('subscription', default: {"name"=>"inspec-gcp-subscription"}) +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') +subscription = attribute('subscription', default: {"name"=>"inspec-gcp-subscription", "ack_deadline_seconds"=>20}) control 'google_pubsub_subscriptions-1.0' do impact 1.0 @@ -23,13 +23,12 @@ describe google_pubsub_subscriptions(project: gcp_project_id) do it { should exist } - its('names') { should include topic['name'] } its('count') { should eq 1 } end google_pubsub_subscriptions(project: gcp_project_id).names.each do |subscription_name| - describe google_pubsub_topic(project: gcp_project_id, name: subscription_name) do - its('name') { should eq topic['name'] } + describe google_pubsub_subscription(project: gcp_project_id, name: subscription_name) do + its('name') { should match /#{subscription['name']}/ } end end end diff --git a/test/integration/verify/controls/google_pubsub_topic.rb b/test/integration/verify/controls/google_pubsub_topic.rb index 6faaf40a4..c4e1c895b 100644 --- a/test/integration/verify/controls/google_pubsub_topic.rb +++ b/test/integration/verify/controls/google_pubsub_topic.rb @@ -14,7 +14,7 @@ title 'Test GCP google_pubsub_topic resource.' -gcp_project_id = attribute(:gcp_gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') topic = attribute('topic', default: {"name"=>"inspec-gcp-topic"}) control 'google_pubsub_topic-1.0' do diff --git a/test/integration/verify/controls/google_pubsub_topics.rb b/test/integration/verify/controls/google_pubsub_topics.rb index af308bde8..cb1b6c9ad 100644 --- a/test/integration/verify/controls/google_pubsub_topics.rb +++ b/test/integration/verify/controls/google_pubsub_topics.rb @@ -14,7 +14,7 @@ title 'Test GCP google_pubsub_topics resource.' -gcp_project_id = attribute(:gcp_gcp_project_id, default: '', description: 'The GCP project identifier.') +gcp_project_id = attribute(:gcp_project_id, default: '', description: 'The GCP project identifier.') topic = attribute('topic', default: {"name"=>"inspec-gcp-topic"}) control 'google_pubsub_topics-1.0' do