From 9c0d645f87c0c6b7e2ecb475c208eb38e1f5c3bd Mon Sep 17 00:00:00 2001 From: Matthias Folz Date: Thu, 4 Dec 2025 12:22:25 +0100 Subject: [PATCH] add sast & lint check workflows --- .github/actions/linter_ruby.yml | 26 +++ .github/actions/sast_ruby.yml | 41 ++++ .github/workflows/linter_ruby.yml | 4 +- .rubocop.yml | 44 ++++ Gemfile | 16 +- Gemfile.lock | 48 ++++ Rakefile | 2 +- app/controllers/application_controller.rb | 9 +- app/controllers/v_hosts_controller.rb | 30 ++- app/models/api_key.rb | 13 +- app/models/v_host.rb | 128 +++++------ config.ru | 4 +- config/application.rb | 6 +- config/boot.rb | 4 +- config/environment.rb | 2 +- config/environments/development.rb | 7 +- config/environments/production.rb | 10 +- config/environments/test.rb | 6 +- config/initializers/backtrace_silencers.rb | 2 +- .../initializers/filter_parameter_logging.rb | 4 +- config/initializers/secret_token.rb | 4 +- config/routes.rb | 3 +- db/migrate/20130625072954_create_v_hosts.rb | 2 +- ..._to_active_storage_blobs.active_storage.rb | 12 +- ..._storage_variant_records.active_storage.rb | 21 +- lib/virtual_host_service/configuration.rb | 43 ++-- script/rails | 4 +- spec/controllers/v_hosts_controller_spec.rb | 94 ++++---- spec/factories/v_host.rb | 140 ++++++------ spec/models/v_host_spec.rb | 211 +++++++++--------- spec/spec_helper.rb | 9 +- 31 files changed, 543 insertions(+), 406 deletions(-) create mode 100644 .github/actions/linter_ruby.yml create mode 100644 .github/actions/sast_ruby.yml create mode 100644 .rubocop.yml mode change 100644 => 100755 Rakefile diff --git a/.github/actions/linter_ruby.yml b/.github/actions/linter_ruby.yml new file mode 100644 index 0000000..e54a283 --- /dev/null +++ b/.github/actions/linter_ruby.yml @@ -0,0 +1,26 @@ +on: + workflow_call: + secrets: + token: + required: true + +jobs: + rubocop: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Ruby versions + uses: ruby/setup-ruby@v1 + with: + bundler-cache: false + + - name: Install Rubocop + run: | + gem install rubocop-rails-omakase -N + gem install rubocop-rspec -N + + - name: Run Rubocop + run: rubocop --lint diff --git a/.github/actions/sast_ruby.yml b/.github/actions/sast_ruby.yml new file mode 100644 index 0000000..c7bb9db --- /dev/null +++ b/.github/actions/sast_ruby.yml @@ -0,0 +1,41 @@ +name: SAST + +on: + workflow_call: + secrets: + token: + required: true + +permissions: + contents: read + +jobs: + brakeman: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: false + + - name: Install Brakeman + run: gem install brakeman -N + + - name: Run brakeman + run: brakeman --force + + bearer: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby versions + uses: ruby/setup-ruby@v1 + + - name: Bearer + uses: bearer/bearer-action@v2 diff --git a/.github/workflows/linter_ruby.yml b/.github/workflows/linter_ruby.yml index 9a40306..1ac6c97 100644 --- a/.github/workflows/linter_ruby.yml +++ b/.github/workflows/linter_ruby.yml @@ -6,11 +6,11 @@ on: jobs: lint: - uses: anynines/int-gitops/.github/workflows/linter_ruby.yml@master + uses: ./.github/actions/linter_ruby.yml secrets: token: ${{ secrets.GITHUB_TOKEN }} sast: - uses: anynines/int-gitops/.github/workflows/sast_ruby.yml@master + uses: ./.github/actions/sast_ruby.yml secrets: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..6acb804 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,44 @@ +plugins: + - rubocop-performance + - rubocop-rails + - rubocop-rspec + +AllCops: + # Insert your target ruby version + TargetRubyVersion: 3.1.x + NewCops: enable + +# Overwrite or add rules to create your own house style +# +# # Use `[a, [b, c]]` not `[ a, [ b, c ] ]` +# Layout/SpaceInsideArrayLiteralBrackets: +# Enabled: false + +Layout/IndentationConsistency: + Enabled: true + +Layout/IndentationWidth: + Enabled: true + +Bundler: + Enabled: true +Gemspec: + Enabled: true +Layout: + Enabled: true +Lint: + Enabled: true +Metrics: + Enabled: true +Naming: + Enabled: true +Performance: + Enabled: true + Exclude: + - "spec/**/*" +Rails: + Enabled: true +Security: + Enabled: true +Style: + Enabled: true diff --git a/Gemfile b/Gemfile index 42867ef..9531c1a 100644 --- a/Gemfile +++ b/Gemfile @@ -4,27 +4,29 @@ ruby '3.1.3' gem 'rails', '~> 7.0.0' -gem 'eventmachine' gem 'amqp' -gem 'honeybadger' gem 'erubis' +gem 'eventmachine' +gem 'honeybadger' gem 'listen' gem 'net-smtp' -gem 'webrick', '~> 1.7' gem 'psych', '< 4' +gem 'webrick', '~> 1.7' gem 'hashie' gem 'pg' gem 'nokogiri', '~> 1.18.4' -gem "rack", "~> 2.2.13" +gem 'rack', '~> 2.2.13' group :test do gem 'byebug' - gem 'rspec-rails' - gem "factory_bot_rails", "~> 4.0" - gem 'mocha', :require => false gem 'database_cleaner' + gem 'factory_bot_rails', '~> 4.0' + gem 'mocha', require: false + gem 'rspec-rails' + gem 'rubocop-rails-omakase', require: false + gem 'rubocop-rspec' end diff --git a/Gemfile.lock b/Gemfile.lock index 2339468..24cb568 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -70,6 +70,7 @@ GEM amqp (1.8.0) amq-protocol (>= 2.2.0) eventmachine + ast (2.4.3) base64 (0.2.0) builder (3.3.0) byebug (11.1.3) @@ -98,6 +99,9 @@ GEM honeybadger (5.0.2) i18n (1.14.7) concurrent-ruby (~> 1.0) + json (2.17.1) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -129,7 +133,12 @@ GEM racc (~> 1.4) nokogiri (1.18.7-x86_64-darwin) racc (~> 1.4) + parallel (1.27.0) + parser (3.3.10.0) + ast (~> 2.4.1) + racc pg (1.4.4) + prism (1.6.0) psych (3.3.4) racc (1.8.1) rack (2.2.13) @@ -163,10 +172,12 @@ GEM rake (>= 12.2) thor (~> 1.0) zeitwerk (~> 2.5) + rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) + regexp_parser (2.11.3) rspec-core (3.12.0) rspec-support (~> 3.12.0) rspec-expectations (3.12.0) @@ -184,11 +195,46 @@ GEM rspec-mocks (~> 3.11) rspec-support (~> 3.11) rspec-support (3.12.0) + rubocop (1.81.7) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.47.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.48.0) + parser (>= 3.3.7.2) + prism (~> 1.4) + rubocop-performance (1.26.1) + lint_roller (~> 1.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.47.1, < 2.0) + rubocop-rails (2.34.2) + activesupport (>= 4.2.0) + lint_roller (~> 1.1) + rack (>= 1.1) + rubocop (>= 1.75.0, < 2.0) + rubocop-ast (>= 1.44.0, < 2.0) + rubocop-rails-omakase (1.1.0) + rubocop (>= 1.72) + rubocop-performance (>= 1.24) + rubocop-rails (>= 2.30) + rubocop-rspec (3.8.0) + lint_roller (~> 1.1) + rubocop (~> 1.81) + ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) thor (1.3.2) timeout (0.4.3) tzinfo (2.0.6) concurrent-ruby (~> 1.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.1.0) webrick (1.9.1) websocket-driver (0.7.7) base64 @@ -219,6 +265,8 @@ DEPENDENCIES rack (~> 2.2.13) rails (~> 7.0.0) rspec-rails + rubocop-rails-omakase + rubocop-rspec webrick (~> 1.7) RUBY VERSION diff --git a/Rakefile b/Rakefile old mode 100644 new mode 100755 index 3b63591..932eff4 --- a/Rakefile +++ b/Rakefile @@ -2,6 +2,6 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require File.expand_path('config/application', __dir__) VirtualHostService::Application.load_tasks diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ba52ee9..a985b2a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,15 +1,14 @@ class ApplicationController < ActionController::API - before_action :authorize! - + protected - + ## # Every Request needs an access token wich authorizes to use the api. # No action will be performed if no access token is specified in the request params. def authorize! api_key = ApiKey.find_by_access_token(params[:access_token]) head :unauthorized unless api_key - return false + false end -end \ No newline at end of file +end diff --git a/app/controllers/v_hosts_controller.rb b/app/controllers/v_hosts_controller.rb index f5e4024..adf2a67 100644 --- a/app/controllers/v_hosts_controller.rb +++ b/app/controllers/v_hosts_controller.rb @@ -1,39 +1,37 @@ class VHostsController < ApplicationController - def create vhost = VHost.new(vhost_params) if vhost.save - render :json => vhost + render json: vhost else - render :json => {:errors => vhost.errors.full_messages}, :status => 422 + render json: { errors: vhost.errors.full_messages }, status: :unprocessable_entity end - - rescue AMQP::TCPConnectionFailed => ex - render :json => {:errors => ['Could not establish TCP connection to the amqp broker']}, :status => 500 + rescue AMQP::TCPConnectionFailed => e + Rails.logger.error(e) + render json: { errors: ['Could not establish TCP connection to the amqp broker'] }, status: :internal_server_error end def destroy_by_server_name - - vhost = VHost.where(:server_name => params['server_name']).first + vhost = VHost.where(server_name: params['server_name']).first if vhost.destroy - render :json => 'ok' + render json: 'ok' else - render :json => {:errors => 'error on deleting vhost'}, :status => 422 + render json: { errors: 'error on deleting vhost' }, status: :unprocessable_entity end - - rescue AMQP::TCPConnectionFailed => ex - render :json => {:errors => ['Could not establish TCP connection to the amqp broker']}, :status => 500 + rescue AMQP::TCPConnectionFailed => e + Rails.logger.error(e) + render json: { errors: ['Could not establish TCP connection to the amqp broker'] }, status: :internal_server_error end def by_organization - render :json => VHost.where(:organization_guid => params['guid']) + render json: VHost.where(organization_guid: params['guid']) end private def vhost_params - params.require(:v_host).permit(:organization_guid, :server_name, :ssl_ca_certificate, :ssl_certificate, :ssl_key, :server_aliases) + params.require(:v_host).permit(:organization_guid, :server_name, :ssl_ca_certificate, :ssl_certificate, :ssl_key, + :server_aliases) end - end diff --git a/app/models/api_key.rb b/app/models/api_key.rb index ef67edd..ec40937 100644 --- a/app/models/api_key.rb +++ b/app/models/api_key.rb @@ -1,21 +1,18 @@ -## +## # Every client which wants to perform actions through this api needs a API key # otherwise every request will rejektet with a 401 status. API keys can be added # in the application.yml. class ApiKey - def initialize(name, access_token) @name = name @access_token = access_token end - + def self.find_by_access_token(access_token) - - APP_CONFIG['api_keys'].each do |k,v| + APP_CONFIG['api_keys'].each do |k, v| return ApiKey.new(k, v) if access_token == v end - - return nil - + + nil end end diff --git a/app/models/v_host.rb b/app/models/v_host.rb index 2bdc52f..cfbeccf 100644 --- a/app/models/v_host.rb +++ b/app/models/v_host.rb @@ -1,8 +1,6 @@ require 'openssl' require 'pp' - - ## # This class is to initialize with a SSL certificate, an unencrypted ssl key and # a optional ca certificate. @@ -17,9 +15,9 @@ # the ssl certificate working. # class VHost < ActiveRecord::Base - SERVER_NAME_REGEX = /\A(\*\.)?([a-zA-Z0-9]([a-zA-Z0-9\-])*[a-zA-Z0-9]\.)*([A-Za-z0-9]([A-Za-z0-9\-])*[A-Za-z0-9])\.([A-Za-z0-9]([A-Za-z0-9\-])*[A-Za-z0-9])\z/ + SERVER_NAME_REGEX = /\A(\*\.)?([a-zA-Z0-9]([a-zA-Z0-9-])*[a-zA-Z0-9]\.)*([A-Za-z0-9]([A-Za-z0-9-])*[A-Za-z0-9])\.([A-Za-z0-9]([A-Za-z0-9-])*[A-Za-z0-9])\z/ - validates :server_name, :uniqueness => { :case_sensitive => false }, :format => { :with => SERVER_NAME_REGEX } + validates :server_name, uniqueness: { case_sensitive: false }, format: { with: SERVER_NAME_REGEX } validate :must_have_a_valid_list_of_server_aliases, :must_have_a_unencrypted_ssl_key, @@ -31,131 +29,126 @@ class VHost < ActiveRecord::Base encrypts :ssl_certificate, :ssl_ca_certificate, :ssl_key def save - if valid? - push_to_amqp - super - end + return unless valid? + + push_to_amqp + super end - + def destroy push_destroy_to_amqp super end def server_name + self.server_name = server_name_from_ssl_certificate if super.blank? - if super.blank? - self.server_name = server_name_from_ssl_certificate - end - - return super + super end def server_aliases - if super.blank? - self.server_aliases = server_aliases_from_ssl_certificate - end + self.server_aliases = server_aliases_from_ssl_certificate if super.blank? - return super + super end - + protected - + def must_have_a_valid_list_of_server_aliases return unless server_aliases - + server_aliases.split(',').each do |server_alias| - errors.add(:server_aliases, 'is invalid') unless server_alias =~ SERVER_NAME_REGEX + errors.add(:server_aliases, 'is invalid') unless SERVER_NAME_REGEX.match?(server_alias) end end - + def must_have_a_well_formatted_ssl_ca_certificate - # The ca certificate is no longer optional raise if ssl_ca_certificate.blank? OpenSSL::X509::Certificate.new(ssl_ca_certificate) - #the certificate should start with "-----BEGIN CERTIFICATE-----" - #and end with "-----END CERTIFICATE-----" - tmp_cert = ssl_ca_certificate.gsub("\n", "") - raise unless tmp_cert.strip =~ /^-+BEGIN CERTIFICATE(.*)END CERTIFICATE-+$/ - rescue + # the certificate should start with "-----BEGIN CERTIFICATE-----" + # and end with "-----END CERTIFICATE-----" + tmp_cert = ssl_ca_certificate.delete("\n") + raise unless /^-+BEGIN CERTIFICATE(.*)END CERTIFICATE-+$/.match?(tmp_cert.strip) + rescue StandardError errors.add(:ssl_ca_certificate, 'is invalid') end - + def must_have_a_well_formatted_ssl_certificate OpenSSL::X509::Certificate.new(ssl_certificate) - #the certificate should start with "-----BEGIN CERTIFICATE-----" - #and end with "-----END CERTIFICATE-----" - tmp_cert = ssl_certificate.gsub("\n", "") - raise unless tmp_cert.strip =~ /^-+BEGIN CERTIFICATE(.*)END CERTIFICATE-+$/ - rescue + # the certificate should start with "-----BEGIN CERTIFICATE-----" + # and end with "-----END CERTIFICATE-----" + tmp_cert = ssl_certificate.delete("\n") + raise unless /^-+BEGIN CERTIFICATE(.*)END CERTIFICATE-+$/.match?(tmp_cert.strip) + rescue StandardError errors.add(:ssl_certificate, 'is invalid') end - + def must_have_a_unencrypted_ssl_key - errors.add(:ssl_key, 'must be unencrypted') if (ssl_key =~ /Proc-Type: 4,ENCRYPTED/) + errors.add(:ssl_key, 'must be unencrypted') if /Proc-Type: 4,ENCRYPTED/.match?(ssl_key) end - + def must_have_a_well_formatted_ssl_key OpenSSL::PKey.read ssl_key if errors[:ssl_key].empty? - rescue + rescue StandardError errors.add(:ssl_key, 'is invalid') end - + def private_key_must_match_ssl_certificate - if errors.empty? - cert = OpenSSL::X509::Certificate.new ssl_certificate - key = OpenSSL::PKey.read ssl_key if errors[:ssl_key].empty? + return unless errors.empty? - errors.add(:ssl_key, 'must match the ssl certificate') unless cert.check_private_key key - end + cert = OpenSSL::X509::Certificate.new ssl_certificate + key = OpenSSL::PKey.read ssl_key if errors[:ssl_key].empty? + + errors.add(:ssl_key, 'must match the ssl certificate') unless cert.check_private_key key end def server_name_from_ssl_certificate - OpenSSL::X509::Certificate.new(ssl_certificate).to_text.match(/^\s*Subject\: .*CN=(.*)/)[1].split('/').first + OpenSSL::X509::Certificate.new(ssl_certificate).to_text.match(/^\s*Subject: .*CN=(.*)/)[1].split('/').first rescue OpenSSL::X509::CertificateError nil end def server_aliases_from_ssl_certificate - results = dns_alt_names_from_ssl_certificate.delete_if { |x| x.downcase == self.server_name.downcase } + results = dns_alt_names_from_ssl_certificate.delete_if { |x| x.downcase == server_name.downcase } return nil if results.empty? + results * ',' end def dns_alt_names_from_ssl_certificate - subject_alt_names = OpenSSL::X509::Certificate.new(ssl_certificate).extensions.detect { |x| x.to_s =~ /.*subjectAltName.*/ } - subject_alt_names.value.split(",").map { |x| x.strip }.select { |x| x =~ /^DNS\:/ }.map { |x| x[4..-1] } - rescue + subject_alt_names = OpenSSL::X509::Certificate.new(ssl_certificate).extensions.detect do |x| + x.to_s =~ /.*subjectAltName.*/ + end + subject_alt_names.value.split(',').map { |x| x.strip }.select { |x| x =~ /^DNS:/ }.map { |x| x[4..-1] } + rescue StandardError [] end - - # triggers a deletion of a vhost + + # triggers a deletion of a vhost def push_destroy_to_amqp AMQP.start(APP_CONFIG.amqp) do |connection| channel = AMQP::Channel.new(connection) - exchange = channel.fanout(APP_CONFIG['amqp_channel'], :durable => true) - + exchange = channel.fanout(APP_CONFIG['amqp_channel'], durable: true) + payload = { - :action => 'delete', - :server_name => server_name + action: 'delete', + server_name: server_name } - - exchange.publish(payload.to_json, :persistent => true) do + + exchange.publish(payload.to_json, persistent: true) do connection.close { EventMachine.stop } end end - - return true + + true end - + # push a create vhost with a ssl cert to the amqp (rabbitmq) def push_to_amqp - AMQP.start(APP_CONFIG.amqp) do |connection| - channel = AMQP::Channel.new(connection) channel.on_connection_interruption do |ch| @@ -163,18 +156,17 @@ def push_to_amqp EventMachine.stop end - exchange = channel.fanout(APP_CONFIG['amqp_channel'], :durable => true) + exchange = channel.fanout(APP_CONFIG['amqp_channel'], durable: true) exchange.on_connection_interruption do |ex| puts "--> Exchange #{ex.name} detected connection interruption" EventMachine.stop - end + end - exchange.publish(attributes.to_json.gsub('\r\n', '\n'), :persistent => true) do + exchange.publish(attributes.to_json.gsub('\r\n', '\n'), persistent: true) do connection.close { EventMachine.stop } end end - return true + true end - end diff --git a/config.ru b/config.ru index 7370dc1..bf91c61 100644 --- a/config.ru +++ b/config.ru @@ -1,8 +1,8 @@ # This file is used by Rack-based servers to start the application. -require_relative "config/environment" +require_relative 'config/environment' # run Rails.application # Rails.application.load_server -run VirtualHostService::Application \ No newline at end of file +run VirtualHostService::Application diff --git a/config/application.rb b/config/application.rb index 553d826..43273ba 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,13 +1,13 @@ -require_relative "boot" +require_relative 'boot' -require "rails/all" +require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module VirtualHostService - require_relative("../lib/virtual_host_service/configuration") + require_relative('../lib/virtual_host_service/configuration') def self.config VirtualHostService::Configuration.instance diff --git a/config/boot.rb b/config/boot.rb index 2820116..30f5120 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,3 +1,3 @@ -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -require "bundler/setup" # Set up gems listed in the Gemfile. +require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/config/environment.rb b/config/environment.rb index cac5315..426333b 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,5 @@ # Load the Rails application. -require_relative "application" +require_relative 'application' # Initialize the Rails application. Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb index 8d1635e..0760077 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,4 +1,4 @@ -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -19,13 +19,13 @@ # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. - if Rails.root.join("tmp/caching-dev.txt").exist? + if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{2.days.to_i}" + 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false @@ -56,7 +56,6 @@ # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true - # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true diff --git a/config/environments/production.rb b/config/environments/production.rb index 5a9102f..64c9902 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,4 +1,4 @@ -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -22,7 +22,7 @@ # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. - config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com" @@ -47,7 +47,7 @@ config.log_level = :info # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] + config.log_tags = [:request_id] # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -70,13 +70,13 @@ config.active_support.report_deprecations = false # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new + config.log_formatter = Logger::Formatter.new # Use a different logger for distributed setups. # require "syslog/logger" # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") - if ENV["RAILS_LOG_TO_STDOUT"].present? + if ENV['RAILS_LOG_TO_STDOUT'].present? logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) diff --git a/config/environments/test.rb b/config/environments/test.rb index 6ea4d1e..5f6cef4 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,4 +1,4 @@ -require "active_support/core_ext/integer/time" +require 'active_support/core_ext/integer/time' # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that @@ -14,12 +14,12 @@ # Eager loading loads your whole application. When running a single test locally, # this probably isn't necessary. It's a good idea to do in a continuous integration # system, or in some way before deploying your code. - config.eager_load = ENV["CI"].present? + config.eager_load = ENV['CI'].present? # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{1.hour.to_i}" + 'Cache-Control' => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 33699c3..d4d9b3b 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -5,4 +5,4 @@ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". -Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] +Rails.backtrace_cleaner.remove_silencers! if ENV['BACKTRACE'] diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index adc6568..166997c 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -3,6 +3,6 @@ # Configure parameters to be filtered from the log file. Use this to limit dissemination of # sensitive information. See the ActiveSupport::ParameterFilter documentation for supported # notations and behaviors. -Rails.application.config.filter_parameters += [ - :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +Rails.application.config.filter_parameters += %i[ + passw secret token _key crypt salt certificate otp ssn ] diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb index 0ef5d70..59b1158 100644 --- a/config/initializers/secret_token.rb +++ b/config/initializers/secret_token.rb @@ -10,8 +10,8 @@ # Make sure your secret_key_base is kept private # if you're sharing your code publicly. -# Although this is not needed for an api-only application, rails4 -# requires secret_key_base or secret_toke to be defined, otherwise an +# Although this is not needed for an api-only application, rails4 +# requires secret_key_base or secret_toke to be defined, otherwise an # error is raised. # Using secret_token for rails3 compatibility. Change to secret_key_base # to avoid deprecation warning. diff --git a/config/routes.rb b/config/routes.rb index 0760544..a45b435 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,5 @@ Rails.application.routes.draw do - - resources :v_hosts, :only => [:create] do + resources :v_hosts, only: [:create] do collection do get 'by_organization' delete 'destroy_by_server_name' diff --git a/db/migrate/20130625072954_create_v_hosts.rb b/db/migrate/20130625072954_create_v_hosts.rb index 0b724db..dd08b21 100644 --- a/db/migrate/20130625072954_create_v_hosts.rb +++ b/db/migrate/20130625072954_create_v_hosts.rb @@ -6,7 +6,7 @@ def change t.string :ssl_key t.string :server_name t.string :server_aliases - + t.string :organization_guid t.timestamps diff --git a/db/migrate/20221107141444_add_service_name_to_active_storage_blobs.active_storage.rb b/db/migrate/20221107141444_add_service_name_to_active_storage_blobs.active_storage.rb index a15c6ce..5b06792 100644 --- a/db/migrate/20221107141444_add_service_name_to_active_storage_blobs.active_storage.rb +++ b/db/migrate/20221107141444_add_service_name_to_active_storage_blobs.active_storage.rb @@ -3,15 +3,15 @@ class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0] def up return unless table_exists?(:active_storage_blobs) - unless column_exists?(:active_storage_blobs, :service_name) - add_column :active_storage_blobs, :service_name, :string + return if column_exists?(:active_storage_blobs, :service_name) - if configured_service = ActiveStorage::Blob.service.name - ActiveStorage::Blob.unscoped.update_all(service_name: configured_service) - end + add_column :active_storage_blobs, :service_name, :string - change_column :active_storage_blobs, :service_name, :string, null: false + if (configured_service = ActiveStorage::Blob.service.name) + ActiveStorage::Blob.unscoped.update_all(service_name: configured_service) end + + change_column :active_storage_blobs, :service_name, :string, null: false end def down diff --git a/db/migrate/20221107141445_create_active_storage_variant_records.active_storage.rb b/db/migrate/20221107141445_create_active_storage_variant_records.active_storage.rb index 94ac83a..58cc779 100644 --- a/db/migrate/20221107141445_create_active_storage_variant_records.active_storage.rb +++ b/db/migrate/20221107141445_create_active_storage_variant_records.active_storage.rb @@ -8,20 +8,21 @@ def change t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type t.string :variation_digest, null: false - t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true + t.index %i[blob_id variation_digest], name: 'index_active_storage_variant_records_uniqueness', unique: true t.foreign_key :active_storage_blobs, column: :blob_id end end private - def primary_key_type - config = Rails.configuration.generators - config.options[config.orm][:primary_key_type] || :primary_key - end - def blobs_primary_key_type - pkey_name = connection.primary_key(:active_storage_blobs) - pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name } - pkey_column.bigint? ? :bigint : pkey_column.type - end + def primary_key_type + config = Rails.configuration.generators + config.options[config.orm][:primary_key_type] || :primary_key + end + + def blobs_primary_key_type + pkey_name = connection.primary_key(:active_storage_blobs) + pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name } + pkey_column.bigint? ? :bigint : pkey_column.type + end end diff --git a/lib/virtual_host_service/configuration.rb b/lib/virtual_host_service/configuration.rb index da2ed64..290e382 100644 --- a/lib/virtual_host_service/configuration.rb +++ b/lib/virtual_host_service/configuration.rb @@ -3,48 +3,59 @@ class VirtualHostService::Configuration < Hashie::Dash include Hashie::Extensions::IndifferentAccess include Hashie::Extensions::IgnoreUndeclared - def self.config_path Rails.root.join('config/application.yml') end def initialize - if File.exists?(self.class.config_path) + if File.exist?(self.class.config_path) yaml = YAML.load_file(self.class.config_path)[Rails.env] super(yaml) else super end - if File.exists?(Rails.root.join('config/amqp.yml')) - self.raw_amqp = YAML.load(Erubis::Eruby.new(File.read(Rails.root.join('config/amqp.yml'))).result)[Rails.env] - end + return unless File.exist?(Rails.root.join('config/amqp.yml')) + + self.raw_amqp = YAML.load(Erubis::Eruby.new(File.read(Rails.root.join('config/amqp.yml'))).result)[Rails.env] end property :secret_key_base, default: 'xxx' property( :active_record_encryption, default: { - primary_key: "xxx", - deterministic_key: "xxx", - key_derivation_salt: "xxx" - }) + primary_key: 'xxx', + deterministic_key: 'xxx', + key_derivation_salt: 'xxx' + } + ) property :honeybadger_api_key, default: '' property :amqp_channel, default: 'virtual_host_jobs' - property :api_keys, default: { customer_partal: 'FGaNYNkgvQ'} + property :api_keys, default: { customer_partal: 'FGaNYNkgvQ' } property( - :raw_amqp, + :raw_amqp, default: { - user: (JSON.parse( ENV['VCAP_SERVICES'] )['a9hcp-rabbitmq'].first['credentials']['username'] rescue ''), - pass: (JSON.parse( ENV['VCAP_SERVICES'] )['a9hcp-rabbitmq'].first['credentials']['password'] rescue ''), - host: (JSON.parse( ENV['VCAP_SERVICES'] )['a9hcp-rabbitmq'].first['credentials']['host'] rescue 'localhost'), + user: begin + JSON.parse(ENV.fetch('VCAP_SERVICES', nil))['a9hcp-rabbitmq'].first['credentials']['username'] + rescue StandardError + '' + end, + pass: begin + JSON.parse(ENV.fetch('VCAP_SERVICES', nil))['a9hcp-rabbitmq'].first['credentials']['password'] + rescue StandardError + '' + end, + host: begin + JSON.parse(ENV.fetch('VCAP_SERVICES', nil))['a9hcp-rabbitmq'].first['credentials']['host'] + rescue StandardError + 'localhost' + end, vhost: '/' } ) def amqp - self.raw_amqp.symbolize_keys + raw_amqp.symbolize_keys end - end diff --git a/script/rails b/script/rails index f8da2cf..3c234a2 100755 --- a/script/rails +++ b/script/rails @@ -1,6 +1,6 @@ #!/usr/bin/env ruby # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. -APP_PATH = File.expand_path('../../config/application', __FILE__) -require File.expand_path('../../config/boot', __FILE__) +APP_PATH = File.expand_path('../config/application', __dir__) +require File.expand_path('../config/boot', __dir__) require 'rails/commands' diff --git a/spec/controllers/v_hosts_controller_spec.rb b/spec/controllers/v_hosts_controller_spec.rb index db55818..1a94b61 100644 --- a/spec/controllers/v_hosts_controller_spec.rb +++ b/spec/controllers/v_hosts_controller_spec.rb @@ -1,118 +1,109 @@ require 'spec_helper' describe VHostsController, type: :controller do - let :invalid_api_key do 'invalid' end - + let :api_key do APP_CONFIG['api_keys'].values.first end - + describe 'POST create' do - context 'with an invalid api key' do - - it 'should respond with a unauthorized http header' do + it 'responds with a unauthorized http header' do post :create, params: { vhost: FactoryBot.attributes_for(:valid_v_host), access_token: invalid_api_key } expect(response.response_code).to be 401 end - - it 'should not create a vHost' do + + it 'does not create a vHost' do post :create, params: { vhost: FactoryBot.attributes_for(:valid_v_host), access_token: invalid_api_key } - + expect(VHost.all.count).to be 0 end - end - + context 'with a valid api key' do context 'with valid params' do - - it 'should respond with a ok http header' do + it 'responds with a ok http header' do FactoryBot.attributes_for(:valid_v_host) post :create, params: { access_token: api_key, v_host: FactoryBot.attributes_for(:valid_v_host) } expect(response.response_code).to eq 200 end - - it 'should save the vHost' do + + it 'saves the vHost' do attr = FactoryBot.attributes_for(:valid_v_host) post :create, params: { v_host: attr, access_token: api_key } expect(VHost.first.server_name).to eq attr[:server_name] end - - it 'should save the vHost and the server aliases' do - attr = FactoryBot.attributes_for(:valid_v_host, :server_aliases => "alias.de,alias.com,alias.com") + + it 'saves the vHost and the server aliases' do + attr = FactoryBot.attributes_for(:valid_v_host, server_aliases: 'alias.de,alias.com,alias.com') post :create, params: { v_host: attr, access_token: api_key } - + expect(VHost.first.server_aliases).to eq attr[:server_aliases] end end context 'with valid params and broken RabbitMQ connection' do - it 'should respond with a server error status code' do + it 'responds with a server error status code' do VHost.any_instance.stubs(:push_to_amqp).raises(AMQP::TCPConnectionFailed.new({})) post :create, params: { v_host: FactoryBot.attributes_for(:valid_v_host), access_token: api_key } expect(response.response_code).to be 500 end - - it 'should respond with a descriptive error message' do + + it 'responds with a descriptive error message' do VHost.any_instance.stubs(:push_to_amqp).raises(AMQP::TCPConnectionFailed.new({})) post :create, params: { v_host: FactoryBot.attributes_for(:valid_v_host), access_token: api_key } expect(JSON.parse(response.body)['errors']).not_to be :empty end end - + context 'wiht invalid params' do - it 'should respond with unprocessable entity http header' do - post :create, params: { v_host: FactoryBot.attributes_for(:v_host_with_invalid_ssl_key), access_token: api_key } + it 'responds with unprocessable entity http header' do + post :create, + params: { v_host: FactoryBot.attributes_for(:v_host_with_invalid_ssl_key), access_token: api_key } expect(response.response_code).to be 422 end - - it 'should respond with some descriptive error messages' do - post :create, params: { v_host: FactoryBot.attributes_for(:v_host_with_invalid_ssl_key), access_token: api_key } - + + it 'responds with some descriptive error messages' do + post :create, + params: { v_host: FactoryBot.attributes_for(:v_host_with_invalid_ssl_key), access_token: api_key } + expect(JSON.parse(response.body)['errors']).not_to be :empty end - end - end - end - + describe 'DELETE destroy_by_server_name' do context 'with a valid api key' do context 'with an existing vhost and with a working RabbitMQ connection' do - - it 'should delete the vhost' do + it 'deletes the vhost' do vhost = FactoryBot.create(:valid_v_host) delete :destroy_by_server_name, params: { access_token: api_key, server_name: vhost.server_name } expect(VHost.all.count).to be 0 end - end context 'with an existing vhost and with a broken RabbitMQ connection' do - - it 'should respond with a server error status code' do + it 'responds with a server error status code' do VHost.any_instance.stubs(:push_destroy_to_amqp).raises(AMQP::TCPConnectionFailed.new({})) vhost = FactoryBot.create(:valid_v_host) delete :destroy_by_server_name, params: { access_token: api_key, server_name: vhost.server_name } expect(response.response_code).to be 500 end - - it 'should respond with a descriptive error message' do + + it 'responds with a descriptive error message' do VHost.any_instance.stubs(:push_destroy_to_amqp).raises(AMQP::TCPConnectionFailed.new({})) vhost = FactoryBot.create(:valid_v_host) delete :destroy_by_server_name, params: { access_token: api_key, server_name: vhost.server_name } @@ -120,14 +111,13 @@ expect(JSON.parse(response.body)['errors']).not_to be :empty end - it 'should not delete the vhost' do + it 'does not delete the vhost' do VHost.any_instance.stubs(:push_destroy_to_amqp).raises(AMQP::TCPConnectionFailed.new({})) vhost = FactoryBot.create(:valid_v_host) delete :destroy_by_server_name, params: { access_token: api_key, server_name: vhost.server_name } expect(VHost.all.count).to be 1 end - end end end @@ -135,20 +125,18 @@ describe 'GET by_organization' do context 'with a valid api key' do context 'with existing v hosts for an organization' do - - it 'should list all vhosts from an organization' do - FactoryBot.create(:valid_v_host, :server_name => "example1.com", :organization_guid => "1") - FactoryBot.create(:valid_v_host, :server_name => "example2.com", :organization_guid => "1") - FactoryBot.create(:valid_v_host, :server_name => "example3.com", :organization_guid => "1") - FactoryBot.create(:valid_v_host, :server_name => "example4.com", :organization_guid => "2") - FactoryBot.create(:valid_v_host, :server_name => "example5.com", :organization_guid => "2-a-3-2") - - get :by_organization, params: { access_token: api_key, guid: "1" } + it 'lists all vhosts from an organization' do + FactoryBot.create(:valid_v_host, server_name: 'example1.com', organization_guid: '1') + FactoryBot.create(:valid_v_host, server_name: 'example2.com', organization_guid: '1') + FactoryBot.create(:valid_v_host, server_name: 'example3.com', organization_guid: '1') + FactoryBot.create(:valid_v_host, server_name: 'example4.com', organization_guid: '2') + FactoryBot.create(:valid_v_host, server_name: 'example5.com', organization_guid: '2-a-3-2') + + get :by_organization, params: { access_token: api_key, guid: '1' } expect(JSON.parse(response.body).count).to be 3 end end end end - -end \ No newline at end of file +end diff --git a/spec/factories/v_host.rb b/spec/factories/v_host.rb index ebda429..5760461 100644 --- a/spec/factories/v_host.rb +++ b/spec/factories/v_host.rb @@ -1,5 +1,5 @@ -FactoryBot.define do |f| - + # rubocop:disable Lint/ConstantDefinitionInBlock +FactoryBot.define do |_f| PLAIN_RSA_KEY = "-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQCYYrlPEKhz5ZPhxKXLvOtQR4FQ1EzpI3Kkx5lgXDmn8pIXwlKy 3uoFNTR4ANc9r4sbl/O0QhKh2/fcMFrqwhHO/cnPvSxtlWupIbgvl/MRB/f1tKrp @@ -63,8 +63,8 @@ DVyMxqPfW1XvQj5Vx2naUio7gy3zg5Y+v7+LbJY2g7Cc -----END RSA PRIVATE KEY-----" - INVALID_EC_KEY = "" - + INVALID_EC_KEY = '' + VALID_SSL_CERTIFICATE = "-----BEGIN CERTIFICATE----- MIID1DCCAbwCAQEwDQYJKoZIhvcNAQEFBQAwgYgxCzAJBgNVBAYTAkRFMREwDwYD VQQIEwhTYWFybGFuZDEVMBMGA1UEBxMMU2FhcmJydWVja2VuMQ0wCwYDVQQKEwRh @@ -89,7 +89,7 @@ 7BeVZ1Q+foNw3Yl5o46J5K5AvIulzMCP -----END CERTIFICATE-----" - VALID_EC_SSL_CERTIFICATE = "-----BEGIN CERTIFICATE----- + VALID_EC_SSL_CERTIFICATE = "-----BEGIN CERTIFICATE----- MIIB+DCCAZ4CAQEwCgYIKoZIzj0EAwIwgZMxCzAJBgNVBAYTAkRFMREwDwYDVQQI DAhTYWFybGFuZDEVMBMGA1UEBwwMU2FhcmJydWVja2VuMREwDwYDVQQKDAhhbnlu aW5lczENMAsGA1UECwwEQ05BRDENMAsGA1UEAwwEdGVzdDEpMCcGCSqGSIb3DQEJ @@ -131,7 +131,7 @@ ad adsf" -SSL_EC_CERTIFICATE_WITH_USELESS_APPENDING = "-----BEGIN CERTIFICATE----- + SSL_EC_CERTIFICATE_WITH_USELESS_APPENDING = "-----BEGIN CERTIFICATE----- MIIB+DCCAZ4CAQEwCgYIKoZIzj0EAwIwgZMxCzAJBgNVBAYTAkRFMREwDwYDVQQI DAhTYWFybGFuZDEVMBMGA1UEBwwMU2FhcmJydWVja2VuMREwDwYDVQQKDAhhbnlu aW5lczENMAsGA1UECwwEQ05BRDENMAsGA1UEAwwEdGVzdDEpMCcGCSqGSIb3DQEJ @@ -148,7 +148,7 @@ adf ad adsf" - + CORRUPT_SSL_CERTIFICATE = "-----BEGIN CERTIFICATE----- MIID1DCCAbwCAQEwDQYJKoZIhacNAQEFBQAwgYgxCzAJBgNVBAYTAkRFMREwDwYD VQQIEwhTYWFybGFuZDEVMBMGA1UEBxMMU2FhcmJydWVja2VuMQ0wCwYDVQQKEwRh @@ -172,7 +172,7 @@ nenMSGo4crCtBmTLWtqxhuizKD7OEEenXOUeGCDeDDGZOOgCcw9oVk5ZErhndTqR 7BeVZ1Q+foNw3Yl5o46J5K5AvIulzMCP -----END CERTIFICATE-----" - + INVALID_SSL_CERTIFICATE = "-----BEGIN CERTIFICATE----- MIID1DCCAbwCAQEwDQYJKoZIhvcNAQEFBQAwgYgxCzAJBgNVBAYTAkRFMREwDwYD VQQIEwhTYWFybGFuZDEVMBMGA1UEBxMMU2FhcmJydWVja2VuMQ0wCwYDVQQKEwRh @@ -192,8 +192,8 @@ 7BeVZ1Q+foNw3Yl5o46J5K5AvIulzMCP -----END CERTIFICATE-----" - INVALID_EC_SSL_CERTIFICATE = "" - + INVALID_EC_SSL_CERTIFICATE = '' + VALID_CA_CERTIFICATE = "-----BEGIN CERTIFICATE----- MIIGhjCCBG6gAwIBAgIJAKrMa3+Wsy4NMA0GCSqGSIb3DQEBBQUAMIGIMQswCQYD VQQGEwJERTERMA8GA1UECBMIU2FhcmxhbmQxFTATBgNVBAcTDFNhYXJicnVlY2tl @@ -248,7 +248,7 @@ qwaksoksZkcPg0hK0mj6ca4GTWcCIQCP0qKZiNMljeZFt19Dx7NSSFpU43H0N/jg r02BNRy8Mg== -----END CERTIFICATE-----" - + INVALID_CA_CERTIFICATE = "----RTIFICATE----- MIIGhjCCBG6gAwIBAgIJAKrMa3+Wsy4NMA0GCSqGSIb3DQEBBQUAMIGIMQswCQYD VQQGEwJERTERMA8GA1UECBMIU2FhcmxhbmQxFTATBgNVBAcTDFNhYXJicnVlY2tl @@ -394,138 +394,140 @@ JralMRfUuJ6/FGfjimDifIST+0pmvD7bnlgCnMkKoZwq66+sYoWhXwI0O3PQFuDS YGixHCwXW0s/3aHDWA== -----END CERTIFICATE-----" - - factory :valid_v_host, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + + factory :valid_v_host, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_SSL_CERTIFICATE } ssl_ca_certificate { VALID_CA_CERTIFICATE } ssl_key { PLAIN_RSA_KEY } end - factory :ec_valid_v_host, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :ec_valid_v_host, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_EC_SSL_CERTIFICATE } ssl_ca_certificate { VALID_EC_CA_CERTIFICATE } ssl_key { PLAIN_EC_KEY } end - factory :valid_v_host_without_ca_cert, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :valid_v_host_without_ca_cert, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_SSL_CERTIFICATE } - ssl_ca_certificate {""} + ssl_ca_certificate { '' } ssl_key { PLAIN_RSA_KEY } end - factory :ec_valid_v_host_without_ca_cert, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :ec_valid_v_host_without_ca_cert, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_EC_SSL_CERTIFICATE } - ssl_ca_certificate { "" } + ssl_ca_certificate { '' } ssl_key { PLAIN_EC_KEY } end - factory :v_host_with_encrypted_ssl_key, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :v_host_with_encrypted_ssl_key, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_SSL_CERTIFICATE } ssl_ca_certificate { VALID_CA_CERTIFICATE } ssl_key { ENCRYPTED_RSA_KEY } end - factory :ec_v_host_with_encrypted_ssl_key, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :ec_v_host_with_encrypted_ssl_key, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_EC_SSL_CERTIFICATE } - ssl_ca_certificate { "" } + ssl_ca_certificate { '' } ssl_key { ENCRYPTED_EC_KEY } end - factory :v_host_with_invalid_ssl_key, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :v_host_with_invalid_ssl_key, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_SSL_CERTIFICATE } ssl_ca_certificate { VALID_CA_CERTIFICATE } ssl_key { INVALID_RSA_KEY } end - factory :ec_v_host_with_invalid_ssl_key, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :ec_v_host_with_invalid_ssl_key, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_EC_SSL_CERTIFICATE } ssl_ca_certificate { VALID_CA_CERTIFICATE } ssl_key { INVALID_EC_KEY } end - factory :v_host_with_invalid_ssl_certificate, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :v_host_with_invalid_ssl_certificate, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { INVALID_SSL_CERTIFICATE } ssl_ca_certificate { VALID_CA_CERTIFICATE } ssl_key { PLAIN_RSA_KEY } end - factory :ec_v_host_with_invalid_ssl_certificate, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :ec_v_host_with_invalid_ssl_certificate, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { INVALID_EC_SSL_CERTIFICATE } ssl_ca_certificate { VALID_EC_CA_CERTIFICATE } ssl_key { PLAIN_EC_KEY } end - - factory :v_host_with_invalid_ssl_ca_certificate, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + + factory :v_host_with_invalid_ssl_ca_certificate, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_SSL_CERTIFICATE } ssl_ca_certificate { INVALID_CA_CERTIFICATE } ssl_key { PLAIN_RSA_KEY } end - factory :ec_v_host_with_invalid_ssl_ca_certificate, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :ec_v_host_with_invalid_ssl_ca_certificate, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_SSL_CERTIFICATE } ssl_ca_certificate { INVALID_EC_CA_CERTIFICATE } ssl_key { PLAIN_EC_KEY } end - - factory :v_host_with_corrupt_ssl_certificate, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + + factory :v_host_with_corrupt_ssl_certificate, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { CORRUPT_SSL_CERTIFICATE } ssl_ca_certificate { VALID_CA_CERTIFICATE } ssl_key { PLAIN_RSA_KEY } end - factory :v_host_with_ssl_certificate_containing_usless_appending, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :v_host_with_ssl_certificate_containing_usless_appending, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { SSL_CERTIFICATE_WITH_USELESS_APPENDING } ssl_ca_certificate { VALID_CA_CERTIFICATE } ssl_key { PLAIN_RSA_KEY } end - factory :ec_v_host_with_ssl_certificate_containing_usless_appending, :class => VHost do - server_name { "example.de" } - organization_guid { "a-valid-org-guid" } + factory :ec_v_host_with_ssl_certificate_containing_usless_appending, class: VHost do + server_name { 'example.de' } + organization_guid { 'a-valid-org-guid' } ssl_certificate { SSL_EC_CERTIFICATE_WITH_USELESS_APPENDING } ssl_ca_certificate { VALID_EC_CA_CERTIFICATE } ssl_key { PLAIN_EC_KEY } end - factory :v_host_with_one_subject_alt_name, :class => VHost do - organization_guid { "a-valid-org-guid" } + factory :v_host_with_one_subject_alt_name, class: VHost do + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_CERTIFICATE_WITH_ONE_SUBJECT_ALT_NAME } end - factory :v_host_with_www_alt_name, :class => VHost do - organization_guid { "a-valid-org-guid" } + factory :v_host_with_www_alt_name, class: VHost do + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_CERTIFICATE_WITH_WWW_ALT_NAME } end - factory :v_host_with_wildcard_certificate, :class => VHost do - organization_guid { "a-valid-org-guid" } + factory :v_host_with_wildcard_certificate, class: VHost do + organization_guid { 'a-valid-org-guid' } ssl_certificate { VALID_WILDCARD_CERTIFICATE } end -end \ No newline at end of file +end + +# rubocop:enable Lint/ConstantDefinitionInBlock \ No newline at end of file diff --git a/spec/models/v_host_spec.rb b/spec/models/v_host_spec.rb index bb96fd7..ee0a516 100644 --- a/spec/models/v_host_spec.rb +++ b/spec/models/v_host_spec.rb @@ -1,23 +1,21 @@ require 'spec_helper' describe VHost do - describe '#create' do - - context 'with valid attributes for a v host' do - it 'should save a valid vhost' do + context 'with valid attributes for a v host' do + it 'saves a valid vhost' do vhost = FactoryBot.build(:valid_v_host) expect(vhost.save).to be true expect(vhost.errors).to be_empty end - it 'should save a valid ECC vhost' do + it 'saves a valid ECC vhost' do vhost = FactoryBot.build(:ec_valid_v_host) expect(vhost.save).to be true expect(vhost.errors).to be_empty end - it 'should encrypt valid vhosts ssl attributes' do + it 'encrypts valid vhosts ssl attributes' do vhost = FactoryBot.build(:valid_v_host) expect(vhost.save).to be true expect(vhost.encrypted_attribute?(:ssl_certificate)).to be true @@ -25,7 +23,7 @@ expect(vhost.encrypted_attribute?(:ssl_key)).to be true end - it 'should encrypt valid ECC vhosts ssl attributes' do + it 'encrypts valid ECC vhosts ssl attributes' do vhost = FactoryBot.build(:ec_valid_v_host) expect(vhost.save).to be true expect(vhost.encrypted_attribute?(:ssl_certificate)).to be true @@ -33,28 +31,27 @@ expect(vhost.encrypted_attribute?(:ssl_key)).to be true end - it 'should push a valid vhost to RabbitMQ' do + it 'pushes a valid vhost to RabbitMQ' do # pending end - - it 'should not save the private ssl key to the local db' do + + it 'does not save the private ssl key to the local db' do # pending end - - it 'should push the private ssl key to RabbitMQ' do + + it 'pushes the private ssl key to RabbitMQ' do # pending end end - + context 'with a blank ssl ca certificate' do - - it 'should not save' do + it 'does not save' do vhost = FactoryBot.build(:valid_v_host_without_ca_cert) vhost.save expect(vhost.errors[:ssl_ca_certificate].first).to eq 'is invalid' end - - it 'should not save ECC vhost' do + + it 'does not save ECC vhost' do vhost = FactoryBot.build(:ec_valid_v_host_without_ca_cert) vhost.save expect(vhost.errors[:ssl_ca_certificate].first).to eq 'is invalid' @@ -62,13 +59,13 @@ end context 'with any invalid attribute' do - it 'should not push data to the RabbitMQ' do + it 'does not push data to the RabbitMQ' do vhost = FactoryBot.build(:v_host_with_invalid_ssl_key) vhost.expects(:push_to_amqp).never vhost.save end - it 'should not push EC data to the RabbitMQ' do + it 'does not push EC data to the RabbitMQ' do vhost = FactoryBot.build(:ec_v_host_with_invalid_ssl_key) vhost.expects(:push_to_amqp).never vhost.save @@ -76,55 +73,56 @@ end context 'with an broken RabbitMQ connection and valid attributes' do - it 'should not save the vhost to the database' do - + it 'does not save the vhost to the database' do vhost = FactoryBot.build(:valid_v_host) vhost.stubs(:push_to_amqp).raises AMQP::TCPConnectionFailed - vhost.save rescue - - expect(VHost.all.count).to be 0 + begin + vhost.save + rescue StandardError + expect(VHost.all.count).to be 0 + end end end - + context 'with an encrypted ssl key' do - it 'should trigger an error' do + it 'triggers an error' do vhost = FactoryBot.build(:v_host_with_encrypted_ssl_key) vhost.save expect(vhost.errors[:ssl_key].first).to eq 'must be unencrypted' end - it 'should trigger an error for ECC' do + it 'triggers an error for ECC' do vhost = FactoryBot.build(:ec_v_host_with_encrypted_ssl_key) vhost.save expect(vhost.errors[:ssl_key].first).to eq 'must be unencrypted' end end - + context 'with an invalid ssl key' do - it 'should trigger an error' do + it 'triggers an error' do vhost = FactoryBot.build(:v_host_with_invalid_ssl_key) vhost.save expect(vhost.errors[:ssl_key].first).to eq 'is invalid' end - it 'should trigger an error for ECC' do + it 'triggers an error for ECC' do vhost = FactoryBot.build(:ec_v_host_with_invalid_ssl_key) vhost.save expect(vhost.errors[:ssl_key].first).to eq 'is invalid' end end - + context 'with an invalid ssl certificate' do - it 'should trigger an error' do + it 'triggers an error' do vhost = FactoryBot.build(:v_host_with_invalid_ssl_certificate) vhost.save expect(vhost.errors[:ssl_certificate].first).to eq 'is invalid' end - it 'should trigger an error for ECC' do + it 'triggers an error for ECC' do vhost = FactoryBot.build(:ec_v_host_with_invalid_ssl_certificate) vhost.save expect(vhost.errors[:ssl_certificate].first).to eq 'is invalid' @@ -132,99 +130,98 @@ end context 'with an ssl certificate containing useless appending' do - it 'should trigger an error' do + it 'triggers an error' do vhost = FactoryBot.build(:v_host_with_ssl_certificate_containing_usless_appending) vhost.save expect(vhost.errors[:ssl_certificate].first).to eq 'is invalid' end - it 'should trigger an error for ECC' do + it 'triggers an error for ECC' do vhost = FactoryBot.build(:ec_v_host_with_ssl_certificate_containing_usless_appending) vhost.save expect(vhost.errors[:ssl_certificate].first).to eq 'is invalid' end end - + context 'with an invalid ssl ca certificate' do - it 'should trigger an error' do + it 'triggers an error' do vhost = FactoryBot.build(:v_host_with_invalid_ssl_ca_certificate) vhost.save expect(vhost.errors[:ssl_ca_certificate].first).to eq 'is invalid' end - it 'should trigger an error for ECC' do + it 'triggers an error for ECC' do vhost = FactoryBot.build(:ec_v_host_with_invalid_ssl_ca_certificate) vhost.save expect(vhost.errors[:ssl_ca_certificate].first).to eq 'is invalid' end end - + context 'with a different modulo in the ssl certificate and the ssl key' do - it 'should trigger an error' do + it 'triggers an error' do vhost = FactoryBot.build(:v_host_with_corrupt_ssl_certificate) vhost.save expect(vhost.errors[:ssl_key].first).to eq 'must match the ssl certificate' end - end - + context 'with an already existing server name' do - it 'should trigger an error' do + it 'triggers an error' do vhost = FactoryBot.create(:valid_v_host) vhost.server_name.capitalize! vhost.save - + other_vhost = FactoryBot.build(:valid_v_host) other_vhost.save expect(other_vhost.errors[:server_name].first).to eq 'has already been taken' end - it 'should trigger an error for ECC' do + it 'triggers an error for ECC' do vhost = FactoryBot.create(:ec_valid_v_host) vhost.server_name.capitalize! vhost.save - + other_vhost = FactoryBot.build(:valid_v_host) other_vhost.save expect(other_vhost.errors[:server_name].first).to eq 'has already been taken' end end - + context 'with an invalid host name' do - it 'should detect that "host" is a invalid host name' do - vhost = FactoryBot.build(:valid_v_host, :server_name => "host") + it 'detects that "host" is a invalid host name' do + vhost = FactoryBot.build(:valid_v_host, server_name: 'host') vhost.save expect(vhost.errors[:server_name].first).to eq 'is invalid' end - - it 'should detect that "host" is a invalid host name for ECC' do - vhost = FactoryBot.build(:ec_valid_v_host, :server_name => "host") + + it 'detects that "host" is a invalid host name for ECC' do + vhost = FactoryBot.build(:ec_valid_v_host, server_name: 'host') vhost.save expect(vhost.errors[:server_name].first).to eq 'is invalid' end - it 'should detect that "host.4" is a invalid host name' do - vhost = FactoryBot.build(:valid_v_host, :server_name => "host.4") + it 'detects that "host.4" is a invalid host name' do + vhost = FactoryBot.build(:valid_v_host, server_name: 'host.4') vhost.save expect(vhost.errors[:server_name].first).to eq 'is invalid' end - it 'should detect that "host.4" is a invalid host name for ECC' do - vhost = FactoryBot.build(:ec_valid_v_host, :server_name => "host.4") + it 'detects that "host.4" is a invalid host name for ECC' do + vhost = FactoryBot.build(:ec_valid_v_host, server_name: 'host.4') vhost.save expect(vhost.errors[:server_name].first).to eq 'is invalid' end - - it 'should detect that "-host" is a invalid host name' do - vhost = FactoryBot.build(:valid_v_host, :server_name => "host.4") + + it 'detects that "-host" is a invalid host name' do + vhost = FactoryBot.build(:valid_v_host, server_name: 'host.4') vhost.save expect(vhost.errors[:server_name].first).to eq 'is invalid' end - it 'should detect that "-host" is a invalid host name for ECC' do - vhost = FactoryBot.build(:ec_valid_v_host, :server_name => "host.4") + it 'detects that "-host" is a invalid host name for ECC' do + vhost = FactoryBot.build(:ec_valid_v_host, server_name: 'host.4') vhost.save expect(vhost.errors[:server_name].first).to eq 'is invalid' end @@ -232,135 +229,129 @@ context 'with not specified server name' do context 'with a wildcard certificate' do - it 'should set the server name from the certificate' do + it 'sets the server name from the certificate' do vhost = FactoryBot.build(:v_host_with_wildcard_certificate) expect(vhost.server_name).to eq '*.railshoster.de' end - - it 'should set a server alias to the host without a wildcard' do + + it 'sets a server alias to the host without a wildcard' do vhost = FactoryBot.build(:v_host_with_wildcard_certificate) expect(vhost.server_aliases).to eq 'railshoster.de' end end - + context 'with a simple certificate (one subject alt name)' do - it 'should detect the server name from the certificate' do + it 'detects the server name from the certificate' do vhost = FactoryBot.build(:v_host_with_one_subject_alt_name) expect(vhost.server_name).to eq 'mail.kundenportal.railshoster.de' end end - + context 'with a www certificate' do - it 'should detect the server name from the certificate' do - vhost = FactoryBot.build(:v_host_with_www_alt_name) - expect(vhost.server_name).to eq 'www.fancyerp.com' + it 'detects the server name from the certificate' do + vhost = FactoryBot.build(:v_host_with_www_alt_name) + expect(vhost.server_name).to eq 'www.fancyerp.com' end - it 'should set a server alias to the host without www prefix' do - vhost = FactoryBot.build(:v_host_with_www_alt_name) + it 'sets a server alias to the host without www prefix' do + vhost = FactoryBot.build(:v_host_with_www_alt_name) expect(vhost.server_aliases).to eq 'fancyerp.com' end end end - + context 'with valid server aliases' do - it 'should save the aliases' do - vhost = FactoryBot.build(:valid_v_host, :server_aliases => "alias.de,alias.com,alias.org") + it 'saves the aliases' do + vhost = FactoryBot.build(:valid_v_host, server_aliases: 'alias.de,alias.com,alias.org') expect(vhost.save).to be true expect(vhost.errors).to be_empty end - it 'should save the aliases for ECC' do - vhost = FactoryBot.build(:ec_valid_v_host, :server_aliases => "alias.de,alias.com,alias.org") + it 'saves the aliases for ECC' do + vhost = FactoryBot.build(:ec_valid_v_host, server_aliases: 'alias.de,alias.com,alias.org') expect(vhost.save).to be true expect(vhost.errors).to be_empty end - - it 'should save the alias' do - vhost = FactoryBot.build(:valid_v_host, :server_aliases => "alias.de") + + it 'saves the alias' do + vhost = FactoryBot.build(:valid_v_host, server_aliases: 'alias.de') expect(vhost.save).to be true expect(vhost.errors).to be_empty end - it 'should save the alias for ECC' do - vhost = FactoryBot.build(:ec_valid_v_host, :server_aliases => "alias.de") + it 'saves the alias for ECC' do + vhost = FactoryBot.build(:ec_valid_v_host, server_aliases: 'alias.de') expect(vhost.save).to be true expect(vhost.errors).to be_empty end end - + context 'with invalid server aliases' do - it 'should detect that "alias.de,a" is a invalid server aliases list' do - vhost = FactoryBot.build(:valid_v_host, :server_aliases => "alias.de,a") + it 'detects that "alias.de,a" is a invalid server aliases list' do + vhost = FactoryBot.build(:valid_v_host, server_aliases: 'alias.de,a') vhost.save expect(vhost.errors[:server_aliases].first).to eq 'is invalid' end - - it 'should detect that "alias.de,a" is a invalid server aliases list for ECC' do - vhost = FactoryBot.build(:ec_valid_v_host, :server_aliases => "alias.de,a") + + it 'detects that "alias.de,a" is a invalid server aliases list for ECC' do + vhost = FactoryBot.build(:ec_valid_v_host, server_aliases: 'alias.de,a') vhost.save expect(vhost.errors[:server_aliases].first).to eq 'is invalid' end - it 'should detect that "alias.de, " is a invalid server aliases list' do - vhost = FactoryBot.build(:valid_v_host, :server_aliases => "alias.de, ") + it 'detects that "alias.de, " is a invalid server aliases list' do + vhost = FactoryBot.build(:valid_v_host, server_aliases: 'alias.de, ') vhost.save expect(vhost.errors[:server_aliases].first).to eq 'is invalid' end - it 'should detect that "alias.de, " is a invalid server aliases list for ECC' do - vhost = FactoryBot.build(:ec_valid_v_host, :server_aliases => "alias.de, ") + it 'detects that "alias.de, " is a invalid server aliases list for ECC' do + vhost = FactoryBot.build(:ec_valid_v_host, server_aliases: 'alias.de, ') vhost.save expect(vhost.errors[:server_aliases].first).to eq 'is invalid' end - - it 'should detect that "alias.de alias.com" is a invalid server aliases list' do - vhost = FactoryBot.build(:valid_v_host, :server_aliases => "alias.de alias.com") + + it 'detects that "alias.de alias.com" is a invalid server aliases list' do + vhost = FactoryBot.build(:valid_v_host, server_aliases: 'alias.de alias.com') vhost.save expect(vhost.errors[:server_aliases].first).to eq 'is invalid' end - it 'should detect that "alias.de alias.com" is a invalid server aliases list for ECC' do - vhost = FactoryBot.build(:ec_valid_v_host, :server_aliases => "alias.de alias.com") + it 'detects that "alias.de alias.com" is a invalid server aliases list for ECC' do + vhost = FactoryBot.build(:ec_valid_v_host, server_aliases: 'alias.de alias.com') vhost.save expect(vhost.errors[:server_aliases].first).to eq 'is invalid' end end - end - + describe '#destroy' do - context 'with a existing virtual host' do - - it 'should delete the virtual host from the database' do + it 'deletes the virtual host from the database' do vhost = FactoryBot.build(:valid_v_host) vhost.save vhost.destroy expect(VHost.all.count).to be 0 end - it 'should delete the ECC virtual host from the database' do + it 'deletes the ECC virtual host from the database' do vhost = FactoryBot.build(:ec_valid_v_host) vhost.save vhost.destroy expect(VHost.all.count).to be 0 end - - it 'should push the delete command to amqp' do + + it 'pushes the delete command to amqp' do vhost = FactoryBot.build(:valid_v_host) vhost.expects(:push_destroy_to_amqp) vhost.destroy end - - it 'should push the delete command to amqp for ECC' do + + it 'pushes the delete command to amqp for ECC' do vhost = FactoryBot.build(:ec_valid_v_host) vhost.expects(:push_destroy_to_amqp) vhost.destroy end end - end - end - \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5776249..8a3f46b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,8 +1,8 @@ # This file is copied to ~/spec when you run 'ruby script/generate rspec' # from the project root directory. -ENV["RAILS_ENV"] ||= 'test' +ENV['RAILS_ENV'] ||= 'test' -require File.join( [File.dirname(__FILE__), "..", 'config/environment' ]) unless defined?(Rails) +require File.join([File.dirname(__FILE__), '..', 'config/environment']) unless defined?(Rails) require 'rspec/rails' require 'factory_bot' require 'database_cleaner' @@ -14,17 +14,16 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } RSpec.configure do |config| - config.before(:suite) do DatabaseCleaner.strategy = :transaction DatabaseCleaner.clean_with(:truncation) end - config.before(:each) do + config.before do DatabaseCleaner.start end - config.after(:each) do + config.after do DatabaseCleaner.clean end